From 4f7ea110350dfac0ff954cd4249bf109a529928d Mon Sep 17 00:00:00 2001
From: Gerasim Troeglazov <3dEyes@gmail.com>
Date: Sat, 5 Feb 2022 21:04:18 +1000
Subject: Add Haiku support


diff --git a/Telegram/ThirdParty/libtgvoip/VoIPController.cpp b/Telegram/ThirdParty/libtgvoip/VoIPController.cpp
index 0ae7625..7900169 100644
--- a/Telegram/ThirdParty/libtgvoip/VoIPController.cpp
+++ b/Telegram/ThirdParty/libtgvoip/VoIPController.cpp
@@ -8,6 +8,9 @@
 #include <unistd.h>
 #include <sys/time.h>
 #endif
+#ifdef __HAIKU__
+#include <OS.h>
+#endif
 #include <errno.h>
 #include <string.h>
 #include <wchar.h>
@@ -3013,6 +3016,10 @@ double VoIPController::GetCurrentTime(){
 	struct timespec ts;
 	clock_gettime(CLOCK_MONOTONIC, &ts);
 	return ts.tv_sec+(double)ts.tv_nsec/1000000000.0;
+#elif defined(__HAIKU__)
+	struct timeval tm;
+	gettimeofday(&tm, NULL);
+	return tm.tv_sec+(double)tm.tv_usec/1000000.0;
 #elif defined(__APPLE__)
 	static pthread_once_t token = PTHREAD_ONCE_INIT;
 	pthread_once(&token, &initMachTimestart);
diff --git a/Telegram/ThirdParty/libtgvoip/audio/AudioIO.cpp b/Telegram/ThirdParty/libtgvoip/audio/AudioIO.cpp
index 29d5ad9..994d938 100644
--- a/Telegram/ThirdParty/libtgvoip/audio/AudioIO.cpp
+++ b/Telegram/ThirdParty/libtgvoip/audio/AudioIO.cpp
@@ -39,6 +39,9 @@
 #ifndef WITHOUT_PULSE
 #include "../os/linux/AudioPulse.h"
 #endif
+#elif defined(__HAIKU__)
+#include "../os/haiku/AudioInputHaiku.h"
+#include "../os/haiku/AudioOutputHaiku.h"
 #else
 #error "Unsupported operating system"
 #endif
@@ -65,6 +68,8 @@ AudioIO* AudioIO::Create(std::string inputDevice, std::string outputDevice){
 		return new ContextlessAudioIO<AudioInputWave, AudioOutputWave>(inputDevice, outputDevice);
 #endif
 	return new ContextlessAudioIO<AudioInputWASAPI, AudioOutputWASAPI>(inputDevice, outputDevice);
+#elif defined(__HAIKU__)
+	return new ContextlessAudioIO<AudioInputHaiku, AudioOutputHaiku>();
 #elif defined(__linux__) || defined(__FreeBSD__)
 #ifndef WITHOUT_ALSA
 #ifndef WITHOUT_PULSE
diff --git a/Telegram/ThirdParty/libtgvoip/audio/AudioInput.cpp b/Telegram/ThirdParty/libtgvoip/audio/AudioInput.cpp
index efdc535..12fbc5a 100644
--- a/Telegram/ThirdParty/libtgvoip/audio/AudioInput.cpp
+++ b/Telegram/ThirdParty/libtgvoip/audio/AudioInput.cpp
@@ -33,6 +33,8 @@
 #ifndef WITHOUT_PULSE
 #include "../os/linux/AudioPulse.h"
 #endif
+#elif defined(__HAIKU__)
+#include "../os/haiku/AudioInputHaiku.h"
 #else
 #error "Unsupported operating system"
 #endif
diff --git a/Telegram/ThirdParty/libtgvoip/audio/AudioOutput.cpp b/Telegram/ThirdParty/libtgvoip/audio/AudioOutput.cpp
index 3f88799..97820b6 100644
--- a/Telegram/ThirdParty/libtgvoip/audio/AudioOutput.cpp
+++ b/Telegram/ThirdParty/libtgvoip/audio/AudioOutput.cpp
@@ -37,6 +37,8 @@
 #include "../os/linux/AudioOutputPulse.h"
 #include "../os/linux/AudioPulse.h"
 #endif
+#elif defined(__HAIKU__)
+#include "../os/haiku/AudioOutputHaiku.h"
 #else
 #error "Unsupported operating system"
 #endif
diff --git a/Telegram/ThirdParty/libtgvoip/os/haiku/AudioInputHaiku.cpp b/Telegram/ThirdParty/libtgvoip/os/haiku/AudioInputHaiku.cpp
new file mode 100644
index 0000000..7cce3e3
--- /dev/null
+++ b/Telegram/ThirdParty/libtgvoip/os/haiku/AudioInputHaiku.cpp
@@ -0,0 +1,276 @@
+//
+// libtgvoip is free and unencumbered public domain software.
+// For more information, see http://unlicense.org or the UNLICENSE file
+// you should have received with this source code distribution.
+//
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <dlfcn.h>
+#include "AudioInputHaiku.h"
+#include "../../logging.h"
+#include "../../audio/Resampler.h"
+#include "../../VoIPController.h"
+
+#include "RingBuffer.h"
+
+using namespace tgvoip::audio;
+
+void RecordData(void* cookie, bigtime_t timestamp, void* data, size_t size, const media_format &format)
+{
+	AudioInputHaiku *audioInput = (AudioInputHaiku*)cookie;
+	if (!audioInput->IsRecording())
+		return;
+
+	if (format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_SHORT &&
+		format.u.raw_audio.channel_count == 1) {
+		audioInput->fRingBuffer->Write((unsigned char*)data, size);
+		return;
+	}
+
+	uint32 bytesPerSample = 2;
+	switch (format.u.raw_audio.format) {
+	    case media_raw_audio_format::B_AUDIO_CHAR:
+			bytesPerSample = 1;
+			break;
+	    case media_raw_audio_format::B_AUDIO_SHORT:
+			bytesPerSample = 2;
+			break;
+	    case media_raw_audio_format::B_AUDIO_INT:
+			bytesPerSample = 4;
+	        break;
+	    case media_raw_audio_format::B_AUDIO_FLOAT:
+			bytesPerSample = 4;
+	        break;
+	    default:
+	        break;
+    }
+
+	int frames = size / (format.u.raw_audio.channel_count * bytesPerSample);
+	int16_t *dst = audioInput->workBuffer;
+
+	if (format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_CHAR) {
+		unsigned char* src=reinterpret_cast<unsigned char*>(data);
+		for (int n=0; n < frames; n++) {
+			int32_t value = 0;
+			for (int j=0; j < format.u.raw_audio.channel_count; j++, src++) {
+				value += ((int32_t)(*src) - INT8_MAX) * UINT8_MAX;
+			}
+			value /= format.u.raw_audio.channel_count;
+			dst[n] = (int16_t)value;
+		}
+	} else if (format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_SHORT) {
+		int16_t* src=reinterpret_cast<int16_t*>(data);
+		for (int n=0; n < frames; n++) {
+			int32_t value = 0;
+			for (int j=0; j < format.u.raw_audio.channel_count; j++, src++) {
+				value += *src;
+			}
+			value /= format.u.raw_audio.channel_count;
+			dst[n] = (int16_t)value;
+		}
+	} else if (format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_INT) {
+		int32_t* src=reinterpret_cast<int32_t*>(data);
+		for (int n=0; n < frames; n++) {
+			int64_t value = 0;
+			for (int j=0; j < format.u.raw_audio.channel_count; j++, src++) {
+				value += (int64_t)(*src);
+			}
+			value /= format.u.raw_audio.channel_count;
+			dst[n] = (int16_t)(value / (UINT16_MAX + 1));
+		}
+	} else if (format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_FLOAT) {
+		float* src=reinterpret_cast<float*>(data);
+		for (int n=0; n < frames; n++) {
+			float value = 0;
+			for (int j=0; j < format.u.raw_audio.channel_count; j++, src++) {
+				value += *src;
+			}
+			value /= format.u.raw_audio.channel_count;
+			dst[n] = (int16_t)(value*INT16_MAX);
+		}
+	}
+
+	if(format.u.raw_audio.frame_rate != audioInput->tgFrameRate) {
+		size_t len = tgvoip::audio::Resampler::Convert(dst, audioInput->convertBuffer,
+			frames, frames, audioInput->tgFrameRate, format.u.raw_audio.frame_rate) * audioInput->tgBytesPerSample;
+		audioInput->fRingBuffer->Write((unsigned char*)audioInput->convertBuffer, len);
+	} else {
+		audioInput->fRingBuffer->Write((unsigned char*)dst, frames * audioInput->tgBytesPerSample);
+	}
+}
+
+void NotifyRecordData(void * cookie, BMediaRecorder::notification code, ...)
+{
+	AudioInputHaiku *audioInput = (AudioInputHaiku*)cookie;
+	if (code == BMediaRecorder::B_WILL_STOP) {
+		if (audioInput->IsRecording()) {
+			audioInput->Stop();
+		}
+	}
+}
+
+AudioInputHaiku::AudioInputHaiku()
+{
+	fRecorder = NULL;
+	fRingBuffer = NULL;
+	isRecording = false;
+
+	tgFrameRate = 48000;
+	tgChannelsCount = 1;
+	tgBytesPerSample = 2;
+
+	status_t error;
+
+	fRoster = BMediaRoster::Roster(&error);
+	if (!fRoster) {
+		failed=true;		
+		return;
+	}
+	error = fRoster->GetAudioInput(&fAudioInputNode);
+	if (error < B_OK) {
+		failed=true;
+		return;
+	}
+	error = fRoster->GetAudioMixer(&fAudioMixerNode);
+	if (error < B_OK) {
+		failed=true;
+		return;
+	}
+	fRecorder = new BMediaRecorder("Telegram", B_MEDIA_RAW_AUDIO);
+	if (fRecorder->InitCheck() < B_OK) {
+		failed=true;
+		return;
+	}	
+	media_format output_format;
+	output_format.type = B_MEDIA_RAW_AUDIO;
+	output_format.u.raw_audio = media_raw_audio_format::wildcard;
+    output_format.u.raw_audio.channel_count = 1;
+	fRecorder->SetAcceptedFormat(output_format);
+	
+	const int maxInputCount = 64;
+	dormant_node_info dni[maxInputCount];
+
+	int32 real_count = maxInputCount;
+
+	error = fRoster->GetDormantNodes(dni, &real_count, 0, &output_format, 0, B_BUFFER_PRODUCER | B_PHYSICAL_INPUT);
+	if (real_count > maxInputCount)
+			real_count = maxInputCount;
+	char selected_name[B_MEDIA_NAME_LENGTH] = "Default input";
+	
+	for (int i = 0; i < real_count; i++) {
+		media_node_id ni[12];
+		int32 ni_count = 12;
+		error = fRoster->GetInstancesFor(dni[i].addon, dni[i].flavor_id, ni, &ni_count);
+		if (error == B_OK) {
+			for (int j = 0; j < ni_count; j++) {
+				if (ni[j] == fAudioInputNode.node) {
+					strcpy(selected_name, dni[i].name);
+					break;
+				}
+			}
+		}
+	}
+
+	media_output audioOutput;
+	if (!fRecorder->IsConnected()) {
+		int32 count = 0;
+		error = fRoster->GetFreeOutputsFor(fAudioInputNode, &audioOutput, 1, &count, B_MEDIA_RAW_AUDIO);
+		if (error < B_OK) {
+			failed=true;
+			return;
+		}
+
+		if (count < 1) {
+			failed=true;
+			return;
+		}
+		fRecordFormat.u.raw_audio = audioOutput.format.u.raw_audio;
+	} else {
+		fRecordFormat.u.raw_audio = fRecorder->AcceptedFormat().u.raw_audio;
+	}
+	fRecordFormat.type = B_MEDIA_RAW_AUDIO;
+
+	error = fRecorder->SetHooks(RecordData, NotifyRecordData, this);
+	if (error < B_OK) {
+		failed=true;
+		return;
+	}
+	
+	if (!fRecorder->IsConnected()) {
+		error = fRecorder->Connect(fAudioInputNode, &audioOutput, &fRecordFormat);
+		if (error < B_OK) {
+			fRecorder->SetHooks(NULL, NULL, NULL);
+			failed=true;
+			return;
+		}
+	}
+	
+	fRingBuffer = new RingBuffer(BUFFER_SIZE * 2 * 3);
+	if (fRingBuffer->InitCheck() != B_OK) {
+		failed=true;
+		return;
+	}	
+}
+
+AudioInputHaiku::~AudioInputHaiku(){
+	if (fRecorder != NULL) {
+		if (fRecorder->InitCheck() == B_OK) {
+			if (fRecorder->IsConnected())
+				fRecorder->Disconnect();
+		}
+		delete fRecorder;
+	}
+	if (fRingBuffer != NULL)
+		delete fRingBuffer;
+}
+
+void AudioInputHaiku::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){
+	tgFrameRate = sampleRate;
+	tgChannelsCount = channels;
+	tgBytesPerSample = bitsPerSample / 8;
+}
+
+bool AudioInputHaiku::IsRecording(){
+	return isRecording;
+}
+
+void AudioInputHaiku::Start(){
+	if(failed || isRecording)
+		return;
+
+	isRecording=true;
+
+	thread = new Thread(std::bind(&AudioInputHaiku::RunThread, this));
+	thread->SetName("AudioInputHaiku");
+	thread->Start();
+
+	fRecorder->Start();
+}
+
+void AudioInputHaiku::Stop(){
+	if(!isRecording)
+		return;
+
+	isRecording=false;
+
+	fRecorder->Stop();
+
+	thread->Join();
+	delete thread;
+	thread=NULL;
+}
+
+void AudioInputHaiku::RunThread(){
+	unsigned char buffer[BUFFER_SIZE*2];
+	while (isRecording){
+		if (fRingBuffer->GetReadAvailable() >= sizeof(buffer)) {
+			int readed = fRingBuffer->Read(buffer, sizeof(buffer));
+			if (readed < sizeof(buffer))
+				memset(buffer + readed, 0, sizeof(buffer) - readed);		
+			InvokeCallback(buffer, sizeof(buffer));
+		} else
+			snooze(100);
+	}
+}
diff --git a/Telegram/ThirdParty/libtgvoip/os/haiku/AudioInputHaiku.h b/Telegram/ThirdParty/libtgvoip/os/haiku/AudioInputHaiku.h
new file mode 100644
index 0000000..1c63afe
--- /dev/null
+++ b/Telegram/ThirdParty/libtgvoip/os/haiku/AudioInputHaiku.h
@@ -0,0 +1,66 @@
+//
+// libtgvoip is free and unencumbered public domain software.
+// For more information, see http://unlicense.org or the UNLICENSE file
+// you should have received with this source code distribution.
+//
+
+#ifndef LIBTGVOIP_AUDIOINPUTHAIKU_H
+#define LIBTGVOIP_AUDIOINPUTHAIKU_H
+
+#include "../../audio/AudioInput.h"
+#include "../../threading.h"
+
+#include <OS.h>
+#include <MediaFile.h>
+#include <MediaNode.h>
+#include <MediaRecorder.h>
+#include <MediaTrack.h>
+#include <MediaRoster.h>
+#include <TimeSource.h>
+#include <NodeInfo.h>
+#include <MediaAddOn.h>
+
+#include "RingBuffer.h"
+
+#define BUFFER_SIZE 960
+
+namespace tgvoip{
+namespace audio{
+
+class AudioInputHaiku : public AudioInput{
+
+public:
+	AudioInputHaiku();
+	virtual ~AudioInputHaiku();
+	virtual void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels);
+	virtual void Start();
+	virtual void Stop();
+	virtual bool IsRecording();
+
+	RingBuffer *fRingBuffer;
+	int16_t workBuffer[BUFFER_SIZE * 64];
+	int16_t convertBuffer[BUFFER_SIZE * 64];
+
+	uint32 tgFrameRate;
+	uint32 tgChannelsCount;
+	uint32 tgBytesPerSample;
+
+private:
+	void RunThread();
+
+	bool isConfigured;
+	bool isRecording;
+	
+	BMediaRoster * fRoster;
+	BMediaRecorder * fRecorder;
+	media_format fRecordFormat;
+	media_node fAudioInputNode;
+	media_node fAudioMixerNode;
+
+	Thread* thread;
+};
+
+}
+}
+
+#endif //LIBTGVOIP_AUDIOINPUTHAIKU_H
diff --git a/Telegram/ThirdParty/libtgvoip/os/haiku/AudioOutputHaiku.cpp b/Telegram/ThirdParty/libtgvoip/os/haiku/AudioOutputHaiku.cpp
new file mode 100644
index 0000000..2fca8a1
--- /dev/null
+++ b/Telegram/ThirdParty/libtgvoip/os/haiku/AudioOutputHaiku.cpp
@@ -0,0 +1,99 @@
+//
+// libtgvoip is free and unencumbered public domain software.
+// For more information, see http://unlicense.org or the UNLICENSE file
+// you should have received with this source code distribution.
+//
+
+
+#include <assert.h>
+#include <dlfcn.h>
+#include "AudioOutputHaiku.h"
+#include "../../logging.h"
+#include "../../VoIPController.h"
+
+#define BUFFER_SIZE 960
+
+using namespace tgvoip::audio;
+
+static void playerProc(void *cookie, void *buffer, size_t len, const media_raw_audio_format &format)
+{
+	AudioOutputHaiku *obj = (AudioOutputHaiku*)cookie;
+	obj->InvokeCallback((unsigned char*)buffer, len);
+}
+
+
+AudioOutputHaiku::AudioOutputHaiku(){
+	soundPlayer = NULL;
+	isPlaying = false;
+	isConfigured = false;
+	Configure(48000, 16, 1);
+	return;
+}
+
+AudioOutputHaiku::~AudioOutputHaiku(){
+	if (isConfigured) {
+		if (soundPlayer != NULL) {
+			soundPlayer->Stop();
+			delete soundPlayer;
+		}
+	}
+}
+
+void AudioOutputHaiku::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){
+	media_raw_audio_format mediaKitFormat = {
+		(float)sampleRate,
+		(uint32)channels,
+		media_raw_audio_format::B_AUDIO_SHORT,
+		B_MEDIA_LITTLE_ENDIAN,
+		(uint32)BUFFER_SIZE * (bitsPerSample / 8) * channels
+	};
+
+	switch (bitsPerSample) {
+	    case 8:
+	        mediaKitFormat.format = media_raw_audio_format::B_AUDIO_CHAR;
+	        break;
+	    case 16:
+	    	mediaKitFormat.format = media_raw_audio_format::B_AUDIO_SHORT;
+	        break;
+	    case 32:
+	        mediaKitFormat.format = media_raw_audio_format::B_AUDIO_INT;
+	        break;
+	    default:
+	    	mediaKitFormat.format = media_raw_audio_format::B_AUDIO_SHORT;
+	        break;
+    }
+
+	soundPlayer = new BSoundPlayer(&mediaKitFormat, "Telegram", playerProc, NULL, (void*)this);
+
+	if(soundPlayer->InitCheck() != B_OK) {
+		delete soundPlayer;
+		soundPlayer = NULL;
+		isPlaying = false;
+		failed = true;
+		return;
+	}
+
+	isConfigured = true;
+}
+
+void AudioOutputHaiku::Start(){
+	if(soundPlayer == NULL || isPlaying)
+		return;
+
+	soundPlayer->Start();
+	soundPlayer->SetHasData(true);
+
+	isPlaying=true;
+}
+
+void AudioOutputHaiku::Stop(){
+	if(!isPlaying)
+		return;
+	
+	soundPlayer->Stop();
+	isPlaying=false;
+}
+
+bool AudioOutputHaiku::IsPlaying(){
+	return isPlaying;
+}
diff --git a/Telegram/ThirdParty/libtgvoip/os/haiku/AudioOutputHaiku.h b/Telegram/ThirdParty/libtgvoip/os/haiku/AudioOutputHaiku.h
new file mode 100644
index 0000000..91f2521
--- /dev/null
+++ b/Telegram/ThirdParty/libtgvoip/os/haiku/AudioOutputHaiku.h
@@ -0,0 +1,35 @@
+//
+// libtgvoip is free and unencumbered public domain software.
+// For more information, see http://unlicense.org or the UNLICENSE file
+// you should have received with this source code distribution.
+//
+
+#ifndef LIBTGVOIP_AUDIOOUTPUTHAIKU_H
+#define LIBTGVOIP_AUDIOOUTPUTHAIKU_H
+
+#include "../../audio/AudioOutput.h"
+#include "../../threading.h"
+
+#include <SoundPlayer.h>
+
+namespace tgvoip{
+namespace audio{
+
+class AudioOutputHaiku : public AudioOutput{
+public:
+	AudioOutputHaiku();
+	virtual ~AudioOutputHaiku();
+	virtual void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels);
+	virtual void Start();
+	virtual void Stop();
+	virtual bool IsPlaying() override;
+private:
+	bool isPlaying;
+	bool isConfigured;
+	BSoundPlayer *soundPlayer;
+};
+
+}
+}
+
+#endif //LIBTGVOIP_AUDIOOUTPUTHAIKU_H
diff --git a/Telegram/ThirdParty/libtgvoip/os/haiku/RingBuffer.cpp b/Telegram/ThirdParty/libtgvoip/os/haiku/RingBuffer.cpp
new file mode 100644
index 0000000..6c94933
--- /dev/null
+++ b/Telegram/ThirdParty/libtgvoip/os/haiku/RingBuffer.cpp
@@ -0,0 +1,136 @@
+//
+// libtgvoip is free and unencumbered public domain software.
+// For more information, see http://unlicense.org or the UNLICENSE file
+// you should have received with this source code distribution.
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <OS.h>
+
+#include "RingBuffer.h"
+
+RingBuffer::RingBuffer( int size )
+{
+	 initialized = false;
+     Buffer = new unsigned char[size];
+     if(Buffer!=NULL) {
+     	memset( Buffer, 0, size );
+	    BufferSize = size;     	
+     } else {
+     	BufferSize = 0;
+     }
+     reader = 0;
+     writer = 0;
+     writeBytesAvailable = size;
+     if((locker=create_sem(1,"locker")) >= B_OK) {
+     	initialized = true;
+     } else {
+     	if(Buffer!=NULL) {
+     		delete[] Buffer;     		
+     	}
+     }
+}
+
+RingBuffer::~RingBuffer( )
+{
+	 if(initialized) {
+     	delete[] Buffer;
+     	delete_sem(locker);
+	 }
+}
+
+bool 
+RingBuffer::Empty( void )
+{
+     memset( Buffer, 0, BufferSize );
+     reader = 0;
+     writer = 0;
+     writeBytesAvailable = BufferSize;
+     return true;
+}
+
+int 
+RingBuffer::Read( unsigned char *data, int size )
+{	
+	 acquire_sem(locker);
+	 
+     if( data == 0 || size <= 0 || writeBytesAvailable == BufferSize ) {
+     	 release_sem(locker);
+         return 0;
+     }
+
+     int readBytesAvailable = BufferSize - writeBytesAvailable;
+
+     if( size > readBytesAvailable ) {
+         size = readBytesAvailable;
+     }
+
+     if(size > BufferSize - reader) {
+         int len = BufferSize - reader;
+         memcpy(data, Buffer + reader, len);
+         memcpy(data + len, Buffer, size-len);
+     } else {
+         memcpy(data, Buffer + reader, size);
+     }
+
+     reader = (reader + size) % BufferSize;
+     writeBytesAvailable += size;
+	 
+	 release_sem(locker);
+     return size;
+}
+
+int 
+RingBuffer::Write( unsigned char *data, int size )
+{
+	 acquire_sem(locker);
+	 
+     if( data == 0 || size <= 0 || writeBytesAvailable == 0 ) {
+     	 release_sem(locker);
+         return 0;
+     }
+
+     if( size > writeBytesAvailable ) {
+         size = writeBytesAvailable;
+     }
+
+     if(size > BufferSize - writer) {
+         int len = BufferSize - writer;
+         memcpy(Buffer + writer, data, len);
+         memcpy(Buffer, data+len, size-len);
+     } else {
+         memcpy(Buffer + writer, data, size);
+     }
+
+     writer = (writer + size) % BufferSize;
+     writeBytesAvailable -= size;
+
+	 release_sem(locker);	 
+     return size;
+}
+
+int 
+RingBuffer::GetSize( void )
+{
+     return BufferSize;
+}
+
+int 
+RingBuffer::GetWriteAvailable( void )
+{
+     return writeBytesAvailable;
+}
+
+int 
+RingBuffer::GetReadAvailable( void )
+{
+     return BufferSize - writeBytesAvailable;
+}
+
+status_t 
+RingBuffer::InitCheck( void )
+{
+	return initialized?B_OK:B_ERROR;
+}
diff --git a/Telegram/ThirdParty/libtgvoip/os/haiku/RingBuffer.h b/Telegram/ThirdParty/libtgvoip/os/haiku/RingBuffer.h
new file mode 100644
index 0000000..01f6096
--- /dev/null
+++ b/Telegram/ThirdParty/libtgvoip/os/haiku/RingBuffer.h
@@ -0,0 +1,37 @@
+//
+// libtgvoip is free and unencumbered public domain software.
+// For more information, see http://unlicense.org or the UNLICENSE file
+// you should have received with this source code distribution.
+//
+
+#ifndef __RING_BUFFER_H__
+#define __RING_BUFFER_H__
+
+#include <OS.h>
+
+class RingBuffer {
+
+public:
+     RingBuffer(int size);
+     ~RingBuffer();
+     int Read( unsigned char* dataPtr, int numBytes );
+     int Write( unsigned char *dataPtr, int numBytes );
+     
+     bool Empty( void );
+     int GetSize( );
+     int GetWriteAvailable( );
+     int GetReadAvailable( );
+     status_t InitCheck( );
+private:
+     unsigned char *Buffer;
+     int BufferSize;
+     int reader;
+     int writer;
+     int writeBytesAvailable;
+     
+     sem_id locker;
+     
+     bool 	initialized;
+};
+
+#endif
diff --git a/Telegram/ThirdParty/libtgvoip/os/posix/NetworkSocketPosix.cpp b/Telegram/ThirdParty/libtgvoip/os/posix/NetworkSocketPosix.cpp
index 78e0583..81bf9fc 100644
--- a/Telegram/ThirdParty/libtgvoip/os/posix/NetworkSocketPosix.cpp
+++ b/Telegram/ThirdParty/libtgvoip/os/posix/NetworkSocketPosix.cpp
@@ -248,12 +248,13 @@ void NetworkSocketPosix::Open(){
 	}
 	int flag=0;
 	int res=setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag));
+#ifndef __HAIKU__
 	if(res<0){
 		LOGE("error enabling dual stack socket: %d / %s", errno, strerror(errno));
 		failed=true;
 		return;
 	}
-
+#endif
 	SetMaxPriority();
 	fcntl(fd, F_SETFL, O_NONBLOCK);
 
@@ -403,6 +404,8 @@ std::string NetworkSocketPosix::GetLocalInterfaceInfo(IPv4Address *v4addr, IPv6A
 	if(didAttach){
 		sharedJVM->DetachCurrentThread();
 	}
+#elif defined(__HAIKU__)
+	return name;
 #else
 	struct ifaddrs* interfaces;
 	if(!getifaddrs(&interfaces)){
diff --git a/Telegram/ThirdParty/libtgvoip/threading.h b/Telegram/ThirdParty/libtgvoip/threading.h
old mode 100755
new mode 100644
index 37de500..2017b83
--- a/Telegram/ThirdParty/libtgvoip/threading.h
+++ b/Telegram/ThirdParty/libtgvoip/threading.h
@@ -9,7 +9,7 @@
 
 #include <functional>
 
-#if defined(_POSIX_THREADS) || defined(_POSIX_VERSION) || defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))
+#if defined(_POSIX_THREADS) || defined(_POSIX_VERSION) || defined(__unix__) || defined(__unix) || defined(__HAIKU__) || (defined(__APPLE__) && defined(__MACH__))
 
 #include <pthread.h>
 #include <semaphore.h>
@@ -95,6 +95,7 @@ namespace tgvoip{
 		static void* ActualEntryPoint(void* arg){
 			Thread* self=reinterpret_cast<Thread*>(arg);
 			if(self->name){
+#ifndef __HAIKU__
 #if defined(__linux__) || defined(__FreeBSD__)
 				pthread_setname_np(self->thread, self->name);
 #elif defined(__APPLE__)
@@ -103,6 +104,7 @@ namespace tgvoip{
 					DarwinSpecific::SetCurrentThreadPriority(DarwinSpecific::THREAD_PRIO_USER_INTERACTIVE);
 				}
 #endif
+#endif //__HAIKU__
 			}
 			self->entry();
 			return NULL;
diff --git a/Telegram/ThirdParty/libtgvoip/webrtc_dsp/rtc_base/logging_webrtc.cc b/Telegram/ThirdParty/libtgvoip/webrtc_dsp/rtc_base/logging_webrtc.cc
old mode 100755
new mode 100644
index a8d1522..991241b
--- a/Telegram/ThirdParty/libtgvoip/webrtc_dsp/rtc_base/logging_webrtc.cc
+++ b/Telegram/ThirdParty/libtgvoip/webrtc_dsp/rtc_base/logging_webrtc.cc
@@ -28,6 +28,10 @@
 static const int kMaxLogLineSize = 1024 - 60;
 #endif  // WEBRTC_MAC && !defined(WEBRTC_IOS) || WEBRTC_ANDROID
 
+#if defined(WEBRTC_HAIKU)
+#include <OS.h>
+#endif
+
 #include <stdio.h>
 #include <string.h>
 #include <time.h>
@@ -120,7 +124,12 @@ LogMessage::LogMessage(const char* file,
 
   if (thread_) {
     PlatformThreadId id = CurrentThreadId();
+#if defined(WEBRTC_HAIKU)
+	thread_id tid = get_pthread_thread_id(id);
+	print_stream_ << "[" << tid << "] ";
+#else
     print_stream_ << "[" << id << "] ";
+#endif
   }
 
   if (file != nullptr) {
diff --git a/Telegram/ThirdParty/libtgvoip/webrtc_dsp/rtc_base/platform_file.h b/Telegram/ThirdParty/libtgvoip/webrtc_dsp/rtc_base/platform_file.h
old mode 100755
new mode 100644
diff --git a/Telegram/ThirdParty/libtgvoip/webrtc_dsp/rtc_base/platform_thread_types.cc b/Telegram/ThirdParty/libtgvoip/webrtc_dsp/rtc_base/platform_thread_types.cc
index cf7d478..f27b9a1 100644
--- a/Telegram/ThirdParty/libtgvoip/webrtc_dsp/rtc_base/platform_thread_types.cc
+++ b/Telegram/ThirdParty/libtgvoip/webrtc_dsp/rtc_base/platform_thread_types.cc
@@ -20,6 +20,8 @@ namespace rtc {
 PlatformThreadId CurrentThreadId() {
 #if defined(WEBRTC_WIN)
   return GetCurrentThreadId();
+#elif defined(WEBRTC_HAIKU)
+	return pthread_self();
 #elif defined(WEBRTC_POSIX)
 #if defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
   return pthread_mach_thread_np(pthread_self());
diff --git a/Telegram/ThirdParty/libtgvoip/webrtc_dsp/rtc_base/platform_thread_types.h b/Telegram/ThirdParty/libtgvoip/webrtc_dsp/rtc_base/platform_thread_types.h
index 0bc42eb..c87cde9 100644
--- a/Telegram/ThirdParty/libtgvoip/webrtc_dsp/rtc_base/platform_thread_types.h
+++ b/Telegram/ThirdParty/libtgvoip/webrtc_dsp/rtc_base/platform_thread_types.h
@@ -35,6 +35,9 @@ typedef DWORD PlatformThreadRef;
 #elif defined(WEBRTC_FUCHSIA)
 typedef zx_handle_t PlatformThreadId;
 typedef zx_handle_t PlatformThreadRef;
+#elif defined(WEBRTC_HAIKU)
+typedef pthread_t PlatformThreadId;
+typedef pthread_t PlatformThreadRef;
 #elif defined(WEBRTC_POSIX)
 typedef pid_t PlatformThreadId;
 typedef pthread_t PlatformThreadRef;
diff --git a/Telegram/cmake/lib_tgvoip.cmake b/Telegram/cmake/lib_tgvoip.cmake
index 9b8ec54..7ffb710 100644
--- a/Telegram/cmake/lib_tgvoip.cmake
+++ b/Telegram/cmake/lib_tgvoip.cmake
@@ -116,6 +116,14 @@ PRIVATE
     os/linux/AudioPulse.cpp
     os/linux/AudioPulse.h
 
+    # Haiku
+    os/haiku/AudioInputHaiku.cpp
+    os/haiku/AudioInputHaiku.h
+    os/haiku/AudioOutputHaiku.cpp
+    os/haiku/AudioOutputHaiku.h
+    os/haiku/RingBuffer.cpp
+    os/haiku/RingBuffer.h
+
     # POSIX
     os/posix/NetworkSocketPosix.cpp
     os/posix/NetworkSocketPosix.h
@@ -153,6 +161,25 @@ elseif (APPLE)
             TGVOIP_NO_OSX_PRIVATE_API
         )
     endif()
+elseif (HAIKU)
+    target_compile_definitions(lib_tgvoip_bundled
+    PUBLIC
+       WEBRTC_POSIX
+       WEBRTC_HAIKU
+    )
+    target_compile_options(lib_tgvoip_bundled
+    PRIVATE
+        -Wno-unknown-pragmas
+        -Wno-error=sequence-point
+        -Wno-error=unused-result
+        -mmmx
+        -msse2
+    )
+    target_link_libraries(lib_tgvoip_bundled
+    PRIVATE
+       network
+       media
+    )
 else()
     add_library(lib_tgvoip_bundled_options INTERFACE)
     target_compile_options(lib_tgvoip_bundled_options
-- 
2.30.2

