diff --git a/EchoCanceller.cpp b/EchoCanceller.cpp index a62ea057e3..6027cc87ce 100644 --- a/EchoCanceller.cpp +++ b/EchoCanceller.cpp @@ -99,7 +99,11 @@ EchoCanceller::EchoCanceller(bool enableAEC, bool enableNS, bool enableAGC){ WebRtcAgcConfig agcConfig; agcConfig.compressionGaindB = 9; agcConfig.limiterEnable = 1; +#ifndef TGVOIP_USE_DESKTOP_DSP + agcConfig.targetLevelDbfs = 3; +#else agcConfig.targetLevelDbfs = 9; +#endif WebRtcAgc_Init(agc, 0, 255, kAgcModeAdaptiveAnalog, 48000); WebRtcAgc_set_config(agc, agcConfig); agcMicLevel=128; @@ -264,13 +268,13 @@ void EchoCanceller::ProcessInput(unsigned char* data, unsigned char* out, size_t lock_mutex(aecMutex); WebRtcAecm_Process(aec, bufOut->ibuf()->bands(0)[0], _nsOut[0], samplesOut, AEC_FRAME_SIZE, (int16_t) tgvoip::audio::AudioOutput::GetEstimatedDelay()); - WebRtcAecm_Process(aec, bufOut->ibuf()->bands(0)[0]+160, _nsOut[0]+160, samplesOut+160, AEC_FRAME_SIZE, (int16_t) tgvoip::audio::AudioOutput::GetEstimatedDelay()+audio::AudioInput::GetEstimatedDelay()); + WebRtcAecm_Process(aec, bufOut->ibuf()->bands(0)[0]+160, _nsOut[0]+160, samplesOut+160, AEC_FRAME_SIZE, (int16_t) (tgvoip::audio::AudioOutput::GetEstimatedDelay()+audio::AudioInput::GetEstimatedDelay())); unlock_mutex(aecMutex); memcpy(bufOut->ibuf()->bands(0)[0], samplesOut, 320*2); }else if(enableAEC){ lock_mutex(aecMutex); WebRtcAecm_Process(aec, bufOut->ibuf()->bands(0)[0], NULL, samplesOut, AEC_FRAME_SIZE, (int16_t) tgvoip::audio::AudioOutput::GetEstimatedDelay()); - WebRtcAecm_Process(aec, bufOut->ibuf()->bands(0)[0]+160, NULL, samplesOut+160, AEC_FRAME_SIZE, (int16_t) tgvoip::audio::AudioOutput::GetEstimatedDelay()+audio::AudioInput::GetEstimatedDelay()); + WebRtcAecm_Process(aec, bufOut->ibuf()->bands(0)[0]+160, NULL, samplesOut+160, AEC_FRAME_SIZE, (int16_t) (tgvoip::audio::AudioOutput::GetEstimatedDelay()+audio::AudioInput::GetEstimatedDelay())); unlock_mutex(aecMutex); memcpy(bufOut->ibuf()->bands(0)[0], samplesOut, 320*2); }else if(enableNS){ diff --git a/JitterBuffer.cpp b/JitterBuffer.cpp index 88739f4296..e589389d78 100644 --- a/JitterBuffer.cpp +++ b/JitterBuffer.cpp @@ -411,7 +411,7 @@ void JitterBuffer::Tick(){ //LOGV("stddev=%.3f, avg=%.3f, ndelay=%d, dontDec=%u", stddev, avgdev, stddevDelay, dontDecMinDelay); if(dontChangeDelay==0){ if(avgDelay>minDelay+0.5){ - outstandingDelayChange-=20; + outstandingDelayChange-=avgDelay>minDelay+2 ? 60 : 20; dontChangeDelay+=10; }else if(avgDelayenabled=1; stm->frameDuration=60; outgoingStreams.push_back(stm); + + std::vector odevs=EnumerateAudioOutputs(); + for(int i=0;i idevs=EnumerateAudioInputs(); + for(int i=0;i::iterator itrtr=endpoints.begin();itrtr!=endpoints.end();++itrtr){ - if((*itrtr)->address==*src4){ + if((*itrtr)->address==*src4 && (*itrtr)->port==packet.port){ srcEndpoint=*itrtr; break; } diff --git a/audio/AudioInput.cpp b/audio/AudioInput.cpp index 86f6e1986a..674b955119 100644 --- a/audio/AudioInput.cpp +++ b/audio/AudioInput.cpp @@ -89,9 +89,7 @@ void AudioInput::EnumerateDevices(std::vector& devs){ #endif AudioInputWASAPI::EnumerateDevices(devs); #elif defined(__linux__) && !defined(__ANDROID__) - if(AudioInputPulse::IsAvailable()) - AudioInputPulse::EnumerateDevices(devs); - else + if(!AudioInputPulse::IsAvailable() || !AudioInputPulse::EnumerateDevices(devs)) AudioInputALSA::EnumerateDevices(devs); #endif } diff --git a/audio/AudioOutput.cpp b/audio/AudioOutput.cpp index 2a9d6f3820..4f5fdfa15e 100644 --- a/audio/AudioOutput.cpp +++ b/audio/AudioOutput.cpp @@ -103,9 +103,7 @@ void AudioOutput::EnumerateDevices(std::vector& devs){ #endif AudioOutputWASAPI::EnumerateDevices(devs); #elif defined(__linux__) && !defined(__ANDROID__) - if(AudioOutputPulse::IsAvailable()) - AudioOutputPulse::EnumerateDevices(devs); - else + if(!AudioOutputPulse::IsAvailable() || !AudioOutputPulse::EnumerateDevices(devs)) AudioOutputALSA::EnumerateDevices(devs); #endif } diff --git a/libtgvoip.gyp b/libtgvoip.gyp index 2623f3023d..52fbea1db6 100644 --- a/libtgvoip.gyp +++ b/libtgvoip.gyp @@ -91,6 +91,8 @@ '<(tgvoip_src_loc)/os/linux/AudioOutputPulse.h', '<(tgvoip_src_loc)/os/linux/AudioInputPulse.cpp', '<(tgvoip_src_loc)/os/linux/AudioInputPulse.h', + '<(tgvoip_src_loc)/os/linux/PulseAudioLoader.cpp', + '<(tgvoip_src_loc)/os/linux/PulseAudioLoader.h', # POSIX '<(tgvoip_src_loc)/os/posix/NetworkSocketPosix.cpp', diff --git a/os/linux/AudioInputPulse.cpp b/os/linux/AudioInputPulse.cpp index 787528977a..01952cfd70 100644 --- a/os/linux/AudioInputPulse.cpp +++ b/os/linux/AudioInputPulse.cpp @@ -11,39 +11,12 @@ #include "AudioInputPulse.h" #include "../../logging.h" #include "../../VoIPController.h" +#define TGVOIP_IN_AUDIO_IO +#include "PulseAudioLoader.h" +#undef TGVOIP_IN_AUDIO_IO #define BUFFER_SIZE 960 #define CHECK_ERROR(res, msg) if(res!=0){LOGE(msg " failed: %s", pa_strerror(res)); failed=true; return;} -#define CHECK_DL_ERROR(res, msg) if(!res){LOGE(msg ": %s", dlerror()); failed=true; return;} -#define LOAD_DL_FUNCTION(name) {_import_##name=(typeof(_import_##name))dlsym(lib, #name); CHECK_DL_ERROR(_import_##name, "Error getting entry point for " #name);} - -#define pa_threaded_mainloop_new _import_pa_threaded_mainloop_new -#define pa_threaded_mainloop_get_api _import_pa_threaded_mainloop_get_api -#define pa_context_new _import_pa_context_new -#define pa_context_set_state_callback _import_pa_context_set_state_callback -#define pa_threaded_mainloop_lock _import_pa_threaded_mainloop_lock -#define pa_threaded_mainloop_unlock _import_pa_threaded_mainloop_unlock -#define pa_threaded_mainloop_start _import_pa_threaded_mainloop_start -#define pa_context_connect _import_pa_context_connect -#define pa_context_get_state _import_pa_context_get_state -#define pa_threaded_mainloop_wait _import_pa_threaded_mainloop_wait -#define pa_stream_new _import_pa_stream_new -#define pa_stream_set_state_callback _import_pa_stream_set_state_callback -#define pa_stream_set_read_callback _import_pa_stream_set_read_callback -#define pa_stream_connect_record _import_pa_stream_connect_record -#define pa_operation_unref _import_pa_operation_unref -#define pa_stream_cork _import_pa_stream_cork -#define pa_threaded_mainloop_stop _import_pa_threaded_mainloop_stop -#define pa_stream_disconnect _import_pa_stream_disconnect -#define pa_stream_unref _import_pa_stream_unref -#define pa_context_disconnect _import_pa_context_disconnect -#define pa_context_unref _import_pa_context_unref -#define pa_threaded_mainloop_free _import_pa_threaded_mainloop_free -#define pa_threaded_mainloop_signal _import_pa_threaded_mainloop_signal -#define pa_stream_peek _import_pa_stream_peek -#define pa_stream_drop _import_pa_stream_drop -#define pa_strerror _import_pa_strerror -#define pa_stream_get_state _import_pa_stream_get_state using namespace tgvoip::audio; @@ -58,43 +31,11 @@ AudioInputPulse::AudioInputPulse(std::string devID){ stream=NULL; remainingDataSize=0; - lib=dlopen("libpulse.so.0", RTLD_LAZY); - if(!lib) - lib=dlopen("libpulse.so", RTLD_LAZY); - if(!lib){ - LOGE("Error loading libpulse: %s", dlerror()); + if(!PulseAudioLoader::IncRef()){ failed=true; return; } - LOAD_DL_FUNCTION(pa_threaded_mainloop_new); - LOAD_DL_FUNCTION(pa_threaded_mainloop_get_api); - LOAD_DL_FUNCTION(pa_context_new); - LOAD_DL_FUNCTION(pa_context_set_state_callback); - LOAD_DL_FUNCTION(pa_threaded_mainloop_lock); - LOAD_DL_FUNCTION(pa_threaded_mainloop_unlock); - LOAD_DL_FUNCTION(pa_threaded_mainloop_start); - LOAD_DL_FUNCTION(pa_context_connect); - LOAD_DL_FUNCTION(pa_context_get_state); - LOAD_DL_FUNCTION(pa_threaded_mainloop_wait); - LOAD_DL_FUNCTION(pa_stream_new); - LOAD_DL_FUNCTION(pa_stream_set_state_callback); - LOAD_DL_FUNCTION(pa_stream_set_read_callback); - LOAD_DL_FUNCTION(pa_stream_connect_record); - LOAD_DL_FUNCTION(pa_operation_unref); - LOAD_DL_FUNCTION(pa_stream_cork); - LOAD_DL_FUNCTION(pa_threaded_mainloop_stop); - LOAD_DL_FUNCTION(pa_stream_disconnect); - LOAD_DL_FUNCTION(pa_stream_unref); - LOAD_DL_FUNCTION(pa_context_disconnect); - LOAD_DL_FUNCTION(pa_context_unref); - LOAD_DL_FUNCTION(pa_threaded_mainloop_free); - LOAD_DL_FUNCTION(pa_threaded_mainloop_signal); - LOAD_DL_FUNCTION(pa_stream_peek); - LOAD_DL_FUNCTION(pa_stream_drop); - LOAD_DL_FUNCTION(pa_stream_get_state); - LOAD_DL_FUNCTION(pa_strerror); - mainloop=pa_threaded_mainloop_new(); if(!mainloop){ LOGE("Error initializing PulseAudio (pa_threaded_mainloop_new)"); @@ -181,8 +122,7 @@ AudioInputPulse::~AudioInputPulse(){ if(mainloop) pa_threaded_mainloop_free(mainloop); - if(lib) - dlclose(lib); + PulseAudioLoader::DecRef(); } bool AudioInputPulse::IsAvailable(){ @@ -264,18 +204,60 @@ void AudioInputPulse::SetCurrentDevice(std::string devID){ } } -void AudioInputPulse::EnumerateDevices(std::vector& devs){ - +bool AudioInputPulse::EnumerateDevices(std::vector& devs){ + if(!PulseAudioLoader::IncRef()) + return false; + + pa_mainloop* ml; + pa_mainloop_api* mlAPI; + pa_context* ctx; + pa_operation* op=NULL; + int state=0; + int paReady=0; + + ml=pa_mainloop_new(); + mlAPI=pa_mainloop_get_api(ml); + ctx=pa_context_new(mlAPI, "libtgvoip"); + + pa_context_connect(ctx, NULL, PA_CONTEXT_NOFLAGS, NULL); + pa_context_set_state_callback(ctx, AudioInputPulse::ContextStateCallbackEnum, &paReady); + + while(true){ + if(paReady==0){ + pa_mainloop_iterate(ml, 1, NULL); + continue; + } + if(paReady==2){ + pa_context_disconnect(ctx); + pa_context_unref(ctx); + pa_mainloop_free(ml); + PulseAudioLoader::DecRef(); + return false; + } + if(!op){ + op=pa_context_get_source_info_list(ctx, AudioInputPulse::DeviceEnumCallback, &devs); + continue; + } + if(pa_operation_get_state(op)==PA_OPERATION_DONE){ + pa_operation_unref(op); + pa_context_disconnect(ctx); + pa_context_unref(ctx); + pa_mainloop_free(ml); + PulseAudioLoader::DecRef(); + return true; + } + pa_mainloop_iterate(ml, 1, NULL); + } } void AudioInputPulse::ContextStateCallback(pa_context* context, void* arg) { AudioInputPulse* self=(AudioInputPulse*) arg; - self->pa_threaded_mainloop_signal(self->mainloop, 0); + pa_threaded_mainloop_signal(self->mainloop, 0); } void AudioInputPulse::StreamStateCallback(pa_stream *s, void* arg) { AudioInputPulse* self=(AudioInputPulse*) arg; - self->pa_threaded_mainloop_signal(self->mainloop, 0); + pa_threaded_mainloop_signal(self->mainloop, 0); } void AudioInputPulse::StreamReadCallback(pa_stream *stream, size_t requestedBytes, void *userdata){ @@ -316,4 +298,36 @@ void AudioInputPulse::StreamReadCallback(pa_stream *stream, size_t requestedByte void AudioInputPulse::StreamSuccessCallback(pa_stream *stream, int success, void *userdata) { return; -} \ No newline at end of file +} + +void AudioInputPulse::ContextStateCallbackEnum(pa_context* context, void* arg){ + pa_context_state_t state; + int* pa_ready=(int*)arg; + + state=pa_context_get_state(context); + switch(state){ + case PA_CONTEXT_UNCONNECTED: + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + default: + break; + case PA_CONTEXT_FAILED: + case PA_CONTEXT_TERMINATED: + *pa_ready=2; + break; + case PA_CONTEXT_READY: + *pa_ready=1; + break; + } +} + +void AudioInputPulse::DeviceEnumCallback(pa_context* ctx, const pa_source_info* info, int eol, void* userdata){ + if(eol>0) + return; + std::vector* devs=(std::vector*)userdata; + AudioInputDevice dev; + dev.id=std::string(info->name); + dev.displayName=std::string(info->description); + devs->push_back(dev); +} diff --git a/os/linux/AudioInputPulse.h b/os/linux/AudioInputPulse.h index 33bde41acd..e37fdc6da3 100644 --- a/os/linux/AudioInputPulse.h +++ b/os/linux/AudioInputPulse.h @@ -25,49 +25,22 @@ public: virtual void Stop(); virtual bool IsRecording(); virtual void SetCurrentDevice(std::string devID); - static void EnumerateDevices(std::vector& devs); + static bool EnumerateDevices(std::vector& devs); static bool IsAvailable(); private: static void ContextStateCallback(pa_context* context, void* arg); + static void ContextStateCallbackEnum(pa_context* context, void* arg); static void StreamStateCallback(pa_stream* s, void* arg); static void StreamSuccessCallback(pa_stream* stream, int success, void* userdata); static void StreamReadCallback(pa_stream* stream, size_t requested_bytes, void* userdata); + static void DeviceEnumCallback(pa_context* ctx, const pa_source_info* info, int eol, void* userdata); void StreamReadCallback(pa_stream* stream, size_t requestedBytes); pa_threaded_mainloop* mainloop; pa_mainloop_api* mainloopApi; pa_context* context; pa_stream* stream; - void* lib; - - DECLARE_DL_FUNCTION(pa_threaded_mainloop_new); - DECLARE_DL_FUNCTION(pa_threaded_mainloop_get_api); - DECLARE_DL_FUNCTION(pa_context_new); - DECLARE_DL_FUNCTION(pa_context_set_state_callback); - DECLARE_DL_FUNCTION(pa_threaded_mainloop_lock); - DECLARE_DL_FUNCTION(pa_threaded_mainloop_unlock); - DECLARE_DL_FUNCTION(pa_threaded_mainloop_start); - DECLARE_DL_FUNCTION(pa_context_connect); - DECLARE_DL_FUNCTION(pa_context_get_state); - DECLARE_DL_FUNCTION(pa_threaded_mainloop_wait); - DECLARE_DL_FUNCTION(pa_stream_new); - DECLARE_DL_FUNCTION(pa_stream_set_state_callback); - DECLARE_DL_FUNCTION(pa_stream_set_read_callback); - DECLARE_DL_FUNCTION(pa_stream_connect_record); - DECLARE_DL_FUNCTION(pa_operation_unref); - DECLARE_DL_FUNCTION(pa_stream_cork); - DECLARE_DL_FUNCTION(pa_threaded_mainloop_stop); - DECLARE_DL_FUNCTION(pa_stream_disconnect); - DECLARE_DL_FUNCTION(pa_stream_unref); - DECLARE_DL_FUNCTION(pa_context_disconnect); - DECLARE_DL_FUNCTION(pa_context_unref); - DECLARE_DL_FUNCTION(pa_threaded_mainloop_free); - DECLARE_DL_FUNCTION(pa_threaded_mainloop_signal); - DECLARE_DL_FUNCTION(pa_stream_peek); - DECLARE_DL_FUNCTION(pa_stream_drop); - DECLARE_DL_FUNCTION(pa_stream_get_state); - DECLARE_DL_FUNCTION(pa_strerror); bool isRecording; bool isConnected; diff --git a/os/linux/AudioOutputPulse.cpp b/os/linux/AudioOutputPulse.cpp index e72bd67170..cd9c67c879 100644 --- a/os/linux/AudioOutputPulse.cpp +++ b/os/linux/AudioOutputPulse.cpp @@ -11,42 +11,18 @@ #include "AudioOutputPulse.h" #include "../../logging.h" #include "../../VoIPController.h" +#define TGVOIP_IN_AUDIO_IO +#include "PulseAudioLoader.h" +#undef TGVOIP_IN_AUDIO_IO #define BUFFER_SIZE 960 #define CHECK_ERROR(res, msg) if(res!=0){LOGE(msg " failed: %s", pa_strerror(res)); failed=true; return;} -#define CHECK_DL_ERROR(res, msg) if(!res){LOGE(msg ": %s", dlerror()); failed=true; return;} -#define LOAD_DL_FUNCTION(name) {_import_##name=(typeof(_import_##name))dlsym(lib, #name); CHECK_DL_ERROR(_import_##name, "Error getting entry point for " #name);} - -#define pa_threaded_mainloop_new _import_pa_threaded_mainloop_new -#define pa_threaded_mainloop_get_api _import_pa_threaded_mainloop_get_api -#define pa_context_new _import_pa_context_new -#define pa_context_set_state_callback _import_pa_context_set_state_callback -#define pa_threaded_mainloop_lock _import_pa_threaded_mainloop_lock -#define pa_threaded_mainloop_unlock _import_pa_threaded_mainloop_unlock -#define pa_threaded_mainloop_start _import_pa_threaded_mainloop_start -#define pa_context_connect _import_pa_context_connect -#define pa_context_get_state _import_pa_context_get_state -#define pa_threaded_mainloop_wait _import_pa_threaded_mainloop_wait -#define pa_stream_new _import_pa_stream_new -#define pa_stream_set_state_callback _import_pa_stream_set_state_callback -#define pa_stream_set_write_callback _import_pa_stream_set_write_callback -#define pa_stream_connect_playback _import_pa_stream_connect_playback -#define pa_operation_unref _import_pa_operation_unref -#define pa_stream_cork _import_pa_stream_cork -#define pa_threaded_mainloop_stop _import_pa_threaded_mainloop_stop -#define pa_stream_disconnect _import_pa_stream_disconnect -#define pa_stream_unref _import_pa_stream_unref -#define pa_context_disconnect _import_pa_context_disconnect -#define pa_context_unref _import_pa_context_unref -#define pa_threaded_mainloop_free _import_pa_threaded_mainloop_free -#define pa_threaded_mainloop_signal _import_pa_threaded_mainloop_signal -#define pa_stream_begin_write _import_pa_stream_begin_write -#define pa_stream_write _import_pa_stream_write -#define pa_strerror _import_pa_strerror -#define pa_stream_get_state _import_pa_stream_get_state +using namespace tgvoip; using namespace tgvoip::audio; +using tgvoip::PulseAudioLoader; + AudioOutputPulse::AudioOutputPulse(std::string devID){ isPlaying=false; isConnected=false; @@ -59,43 +35,11 @@ AudioOutputPulse::AudioOutputPulse(std::string devID){ stream=NULL; remainingDataSize=0; - lib=dlopen("libpulse.so.0", RTLD_LAZY); - if(!lib) - lib=dlopen("libpulse.so", RTLD_LAZY); - if(!lib){ - LOGE("Error loading libpulse: %s", dlerror()); + if(!PulseAudioLoader::IncRef()){ failed=true; return; } - LOAD_DL_FUNCTION(pa_threaded_mainloop_new); - LOAD_DL_FUNCTION(pa_threaded_mainloop_get_api); - LOAD_DL_FUNCTION(pa_context_new); - LOAD_DL_FUNCTION(pa_context_set_state_callback); - LOAD_DL_FUNCTION(pa_threaded_mainloop_lock); - LOAD_DL_FUNCTION(pa_threaded_mainloop_unlock); - LOAD_DL_FUNCTION(pa_threaded_mainloop_start); - LOAD_DL_FUNCTION(pa_context_connect); - LOAD_DL_FUNCTION(pa_context_get_state); - LOAD_DL_FUNCTION(pa_threaded_mainloop_wait); - LOAD_DL_FUNCTION(pa_stream_new); - LOAD_DL_FUNCTION(pa_stream_set_state_callback); - LOAD_DL_FUNCTION(pa_stream_set_write_callback); - LOAD_DL_FUNCTION(pa_stream_connect_playback); - LOAD_DL_FUNCTION(pa_operation_unref); - LOAD_DL_FUNCTION(pa_stream_cork); - LOAD_DL_FUNCTION(pa_threaded_mainloop_stop); - LOAD_DL_FUNCTION(pa_stream_disconnect); - LOAD_DL_FUNCTION(pa_stream_unref); - LOAD_DL_FUNCTION(pa_context_disconnect); - LOAD_DL_FUNCTION(pa_context_unref); - LOAD_DL_FUNCTION(pa_threaded_mainloop_free); - LOAD_DL_FUNCTION(pa_threaded_mainloop_signal); - LOAD_DL_FUNCTION(pa_stream_begin_write); - LOAD_DL_FUNCTION(pa_stream_write); - LOAD_DL_FUNCTION(pa_stream_get_state); - LOAD_DL_FUNCTION(pa_strerror); - mainloop=pa_threaded_mainloop_new(); if(!mainloop){ LOGE("Error initializing PulseAudio (pa_threaded_mainloop_new)"); @@ -180,8 +124,7 @@ AudioOutputPulse::~AudioOutputPulse(){ if(mainloop) pa_threaded_mainloop_free(mainloop); - if(lib) - dlclose(lib); + PulseAudioLoader::DecRef(); } bool AudioOutputPulse::IsAvailable(){ @@ -263,18 +206,60 @@ void AudioOutputPulse::SetCurrentDevice(std::string devID){ } } -void AudioOutputPulse::EnumerateDevices(std::vector& devs){ - +bool AudioOutputPulse::EnumerateDevices(std::vector& devs){ + if(!PulseAudioLoader::IncRef()) + return false; + + pa_mainloop* ml; + pa_mainloop_api* mlAPI; + pa_context* ctx; + pa_operation* op=NULL; + int state=0; + int paReady=0; + + ml=pa_mainloop_new(); + mlAPI=pa_mainloop_get_api(ml); + ctx=pa_context_new(mlAPI, "libtgvoip"); + + pa_context_connect(ctx, NULL, PA_CONTEXT_NOFLAGS, NULL); + pa_context_set_state_callback(ctx, AudioOutputPulse::ContextStateCallbackEnum, &paReady); + + while(true){ + if(paReady==0){ + pa_mainloop_iterate(ml, 1, NULL); + continue; + } + if(paReady==2){ + pa_context_disconnect(ctx); + pa_context_unref(ctx); + pa_mainloop_free(ml); + PulseAudioLoader::DecRef(); + return false; + } + if(!op){ + op=pa_context_get_sink_info_list(ctx, AudioOutputPulse::DeviceEnumCallback, &devs); + continue; + } + if(pa_operation_get_state(op)==PA_OPERATION_DONE){ + pa_operation_unref(op); + pa_context_disconnect(ctx); + pa_context_unref(ctx); + pa_mainloop_free(ml); + PulseAudioLoader::DecRef(); + return true; + } + pa_mainloop_iterate(ml, 1, NULL); + } } void AudioOutputPulse::ContextStateCallback(pa_context* context, void* arg) { AudioOutputPulse* self=(AudioOutputPulse*) arg; - self->pa_threaded_mainloop_signal(self->mainloop, 0); + pa_threaded_mainloop_signal(self->mainloop, 0); } void AudioOutputPulse::StreamStateCallback(pa_stream *s, void* arg) { AudioOutputPulse* self=(AudioOutputPulse*) arg; - self->pa_threaded_mainloop_signal(self->mainloop, 0); + pa_threaded_mainloop_signal(self->mainloop, 0); } void AudioOutputPulse::StreamWriteCallback(pa_stream *stream, size_t requestedBytes, void *userdata){ @@ -319,4 +304,36 @@ void AudioOutputPulse::StreamWriteCallback(pa_stream *stream, size_t requestedBy void AudioOutputPulse::StreamSuccessCallback(pa_stream *stream, int success, void *userdata) { return; -} \ No newline at end of file +} + +void AudioOutputPulse::ContextStateCallbackEnum(pa_context* context, void* arg){ + pa_context_state_t state; + int* pa_ready=(int*)arg; + + state=pa_context_get_state(context); + switch(state){ + case PA_CONTEXT_UNCONNECTED: + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + default: + break; + case PA_CONTEXT_FAILED: + case PA_CONTEXT_TERMINATED: + *pa_ready=2; + break; + case PA_CONTEXT_READY: + *pa_ready=1; + break; + } +} + +void AudioOutputPulse::DeviceEnumCallback(pa_context* ctx, const pa_sink_info* info, int eol, void* userdata){ + if(eol>0) + return; + std::vector* devs=(std::vector*)userdata; + AudioOutputDevice dev; + dev.id=std::string(info->name); + dev.displayName=std::string(info->description); + devs->push_back(dev); +} diff --git a/os/linux/AudioOutputPulse.h b/os/linux/AudioOutputPulse.h index 0cefd25f07..bff80087ab 100644 --- a/os/linux/AudioOutputPulse.h +++ b/os/linux/AudioOutputPulse.h @@ -11,8 +11,6 @@ #include "../../threading.h" #include -#define DECLARE_DL_FUNCTION(name) typeof(name)* _import_##name - namespace tgvoip{ namespace audio{ @@ -25,49 +23,22 @@ public: virtual void Stop(); virtual bool IsPlaying(); virtual void SetCurrentDevice(std::string devID); - static void EnumerateDevices(std::vector& devs); + static bool EnumerateDevices(std::vector& devs); static bool IsAvailable(); private: static void ContextStateCallback(pa_context* context, void* arg); + static void ContextStateCallbackEnum(pa_context* context, void* arg); static void StreamStateCallback(pa_stream* s, void* arg); static void StreamSuccessCallback(pa_stream* stream, int success, void* userdata); static void StreamWriteCallback(pa_stream* stream, size_t requested_bytes, void* userdata); + static void DeviceEnumCallback(pa_context* ctx, const pa_sink_info* info, int eol, void* userdata); void StreamWriteCallback(pa_stream* stream, size_t requestedBytes); pa_threaded_mainloop* mainloop; pa_mainloop_api* mainloopApi; pa_context* context; pa_stream* stream; - void* lib; - - DECLARE_DL_FUNCTION(pa_threaded_mainloop_new); - DECLARE_DL_FUNCTION(pa_threaded_mainloop_get_api); - DECLARE_DL_FUNCTION(pa_context_new); - DECLARE_DL_FUNCTION(pa_context_set_state_callback); - DECLARE_DL_FUNCTION(pa_threaded_mainloop_lock); - DECLARE_DL_FUNCTION(pa_threaded_mainloop_unlock); - DECLARE_DL_FUNCTION(pa_threaded_mainloop_start); - DECLARE_DL_FUNCTION(pa_context_connect); - DECLARE_DL_FUNCTION(pa_context_get_state); - DECLARE_DL_FUNCTION(pa_threaded_mainloop_wait); - DECLARE_DL_FUNCTION(pa_stream_new); - DECLARE_DL_FUNCTION(pa_stream_set_state_callback); - DECLARE_DL_FUNCTION(pa_stream_set_write_callback); - DECLARE_DL_FUNCTION(pa_stream_connect_playback); - DECLARE_DL_FUNCTION(pa_operation_unref); - DECLARE_DL_FUNCTION(pa_stream_cork); - DECLARE_DL_FUNCTION(pa_threaded_mainloop_stop); - DECLARE_DL_FUNCTION(pa_stream_disconnect); - DECLARE_DL_FUNCTION(pa_stream_unref); - DECLARE_DL_FUNCTION(pa_context_disconnect); - DECLARE_DL_FUNCTION(pa_context_unref); - DECLARE_DL_FUNCTION(pa_threaded_mainloop_free); - DECLARE_DL_FUNCTION(pa_threaded_mainloop_signal); - DECLARE_DL_FUNCTION(pa_stream_begin_write); - DECLARE_DL_FUNCTION(pa_stream_write); - DECLARE_DL_FUNCTION(pa_stream_get_state); - DECLARE_DL_FUNCTION(pa_strerror); bool isPlaying; bool isConnected; @@ -80,6 +51,4 @@ private: } } -#undef DECLARE_DL_FUNCTION - #endif //LIBTGVOIP_AUDIOOUTPUTPULSE_H diff --git a/os/linux/PulseAudioLoader.cpp b/os/linux/PulseAudioLoader.cpp new file mode 100644 index 0000000000..d1008e967f --- /dev/null +++ b/os/linux/PulseAudioLoader.cpp @@ -0,0 +1,120 @@ +// +// 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 "PulseAudioLoader.h" +#include +#include "../../logging.h" + +#define DECLARE_DL_FUNCTION(name) typeof(name)* PulseAudioLoader::_import_##name=NULL +#define CHECK_DL_ERROR(res, msg) if(!res){LOGE(msg ": %s", dlerror()); dlclose(lib); return false;} +#define LOAD_DL_FUNCTION(name) {_import_##name=(typeof(_import_##name))dlsym(lib, #name); CHECK_DL_ERROR(_import_##name, "Error getting entry point for " #name);} + +using namespace tgvoip; + +int PulseAudioLoader::refCount=0; +void* PulseAudioLoader::lib=NULL; + +DECLARE_DL_FUNCTION(pa_threaded_mainloop_new); +DECLARE_DL_FUNCTION(pa_threaded_mainloop_get_api); +DECLARE_DL_FUNCTION(pa_context_new); +DECLARE_DL_FUNCTION(pa_context_set_state_callback); +DECLARE_DL_FUNCTION(pa_threaded_mainloop_lock); +DECLARE_DL_FUNCTION(pa_threaded_mainloop_unlock); +DECLARE_DL_FUNCTION(pa_threaded_mainloop_start); +DECLARE_DL_FUNCTION(pa_context_connect); +DECLARE_DL_FUNCTION(pa_context_get_state); +DECLARE_DL_FUNCTION(pa_threaded_mainloop_wait); +DECLARE_DL_FUNCTION(pa_stream_new); +DECLARE_DL_FUNCTION(pa_stream_set_state_callback); +DECLARE_DL_FUNCTION(pa_stream_set_write_callback); +DECLARE_DL_FUNCTION(pa_stream_connect_playback); +DECLARE_DL_FUNCTION(pa_operation_unref); +DECLARE_DL_FUNCTION(pa_stream_cork); +DECLARE_DL_FUNCTION(pa_threaded_mainloop_stop); +DECLARE_DL_FUNCTION(pa_stream_disconnect); +DECLARE_DL_FUNCTION(pa_stream_unref); +DECLARE_DL_FUNCTION(pa_context_disconnect); +DECLARE_DL_FUNCTION(pa_context_unref); +DECLARE_DL_FUNCTION(pa_threaded_mainloop_free); +DECLARE_DL_FUNCTION(pa_threaded_mainloop_signal); +DECLARE_DL_FUNCTION(pa_stream_begin_write); +DECLARE_DL_FUNCTION(pa_stream_write); +DECLARE_DL_FUNCTION(pa_stream_get_state); +DECLARE_DL_FUNCTION(pa_strerror); +DECLARE_DL_FUNCTION(pa_stream_set_read_callback); +DECLARE_DL_FUNCTION(pa_stream_connect_record); +DECLARE_DL_FUNCTION(pa_stream_peek); +DECLARE_DL_FUNCTION(pa_stream_drop); +DECLARE_DL_FUNCTION(pa_mainloop_new); +DECLARE_DL_FUNCTION(pa_mainloop_get_api); +DECLARE_DL_FUNCTION(pa_mainloop_iterate); +DECLARE_DL_FUNCTION(pa_mainloop_free); +DECLARE_DL_FUNCTION(pa_context_get_sink_info_list); +DECLARE_DL_FUNCTION(pa_context_get_source_info_list); +DECLARE_DL_FUNCTION(pa_operation_get_state); + +bool PulseAudioLoader::IncRef(){ + if(refCount==0){ + lib=dlopen("libpulse.so.0", RTLD_LAZY); + if(!lib) + lib=dlopen("libpulse.so", RTLD_LAZY); + if(!lib){ + LOGE("Error loading libpulse: %s", dlerror()); + return false; + } + } + + LOAD_DL_FUNCTION(pa_threaded_mainloop_new); + LOAD_DL_FUNCTION(pa_threaded_mainloop_get_api); + LOAD_DL_FUNCTION(pa_context_new); + LOAD_DL_FUNCTION(pa_context_set_state_callback); + LOAD_DL_FUNCTION(pa_threaded_mainloop_lock); + LOAD_DL_FUNCTION(pa_threaded_mainloop_unlock); + LOAD_DL_FUNCTION(pa_threaded_mainloop_start); + LOAD_DL_FUNCTION(pa_context_connect); + LOAD_DL_FUNCTION(pa_context_get_state); + LOAD_DL_FUNCTION(pa_threaded_mainloop_wait); + LOAD_DL_FUNCTION(pa_stream_new); + LOAD_DL_FUNCTION(pa_stream_set_state_callback); + LOAD_DL_FUNCTION(pa_stream_set_write_callback); + LOAD_DL_FUNCTION(pa_stream_connect_playback); + LOAD_DL_FUNCTION(pa_operation_unref); + LOAD_DL_FUNCTION(pa_stream_cork); + LOAD_DL_FUNCTION(pa_threaded_mainloop_stop); + LOAD_DL_FUNCTION(pa_stream_disconnect); + LOAD_DL_FUNCTION(pa_stream_unref); + LOAD_DL_FUNCTION(pa_context_disconnect); + LOAD_DL_FUNCTION(pa_context_unref); + LOAD_DL_FUNCTION(pa_threaded_mainloop_free); + LOAD_DL_FUNCTION(pa_threaded_mainloop_signal); + LOAD_DL_FUNCTION(pa_stream_begin_write); + LOAD_DL_FUNCTION(pa_stream_write); + LOAD_DL_FUNCTION(pa_stream_get_state); + LOAD_DL_FUNCTION(pa_strerror); + LOAD_DL_FUNCTION(pa_stream_set_read_callback); + LOAD_DL_FUNCTION(pa_stream_connect_record); + LOAD_DL_FUNCTION(pa_stream_peek); + LOAD_DL_FUNCTION(pa_stream_drop); + LOAD_DL_FUNCTION(pa_mainloop_new); + LOAD_DL_FUNCTION(pa_mainloop_get_api); + LOAD_DL_FUNCTION(pa_mainloop_iterate); + LOAD_DL_FUNCTION(pa_mainloop_free); + LOAD_DL_FUNCTION(pa_context_get_sink_info_list); + LOAD_DL_FUNCTION(pa_context_get_source_info_list); + LOAD_DL_FUNCTION(pa_operation_get_state); + + refCount++; + return true; +} + +void PulseAudioLoader::DecRef(){ + if(refCount>0) + refCount--; + if(refCount==0){ + dlclose(lib); + lib=NULL; + } +} \ No newline at end of file diff --git a/os/linux/PulseAudioLoader.h b/os/linux/PulseAudioLoader.h new file mode 100644 index 0000000000..aa34f092c9 --- /dev/null +++ b/os/linux/PulseAudioLoader.h @@ -0,0 +1,109 @@ +// +// 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_PULSEAUDIOLOADER_H +#define LIBTGVOIP_PULSEAUDIOLOADER_H + +#include + +#define DECLARE_DL_FUNCTION(name) static typeof(name)* _import_##name + +namespace tgvoip{ +class PulseAudioLoader{ +public: + static bool IncRef(); + static void DecRef(); + + DECLARE_DL_FUNCTION(pa_threaded_mainloop_new); + DECLARE_DL_FUNCTION(pa_threaded_mainloop_get_api); + DECLARE_DL_FUNCTION(pa_context_new); + DECLARE_DL_FUNCTION(pa_context_set_state_callback); + DECLARE_DL_FUNCTION(pa_threaded_mainloop_lock); + DECLARE_DL_FUNCTION(pa_threaded_mainloop_unlock); + DECLARE_DL_FUNCTION(pa_threaded_mainloop_start); + DECLARE_DL_FUNCTION(pa_context_connect); + DECLARE_DL_FUNCTION(pa_context_get_state); + DECLARE_DL_FUNCTION(pa_threaded_mainloop_wait); + DECLARE_DL_FUNCTION(pa_stream_new); + DECLARE_DL_FUNCTION(pa_stream_set_state_callback); + DECLARE_DL_FUNCTION(pa_stream_set_write_callback); + DECLARE_DL_FUNCTION(pa_stream_connect_playback); + DECLARE_DL_FUNCTION(pa_operation_unref); + DECLARE_DL_FUNCTION(pa_stream_cork); + DECLARE_DL_FUNCTION(pa_threaded_mainloop_stop); + DECLARE_DL_FUNCTION(pa_stream_disconnect); + DECLARE_DL_FUNCTION(pa_stream_unref); + DECLARE_DL_FUNCTION(pa_context_disconnect); + DECLARE_DL_FUNCTION(pa_context_unref); + DECLARE_DL_FUNCTION(pa_threaded_mainloop_free); + DECLARE_DL_FUNCTION(pa_threaded_mainloop_signal); + DECLARE_DL_FUNCTION(pa_stream_begin_write); + DECLARE_DL_FUNCTION(pa_stream_write); + DECLARE_DL_FUNCTION(pa_stream_get_state); + DECLARE_DL_FUNCTION(pa_strerror); + DECLARE_DL_FUNCTION(pa_stream_set_read_callback); + DECLARE_DL_FUNCTION(pa_stream_connect_record); + DECLARE_DL_FUNCTION(pa_stream_peek); + DECLARE_DL_FUNCTION(pa_stream_drop); + + DECLARE_DL_FUNCTION(pa_mainloop_new); + DECLARE_DL_FUNCTION(pa_mainloop_get_api); + DECLARE_DL_FUNCTION(pa_mainloop_iterate); + DECLARE_DL_FUNCTION(pa_mainloop_free); + DECLARE_DL_FUNCTION(pa_context_get_sink_info_list); + DECLARE_DL_FUNCTION(pa_context_get_source_info_list); + DECLARE_DL_FUNCTION(pa_operation_get_state); + +private: + static void* lib; + static int refCount; +}; +} + +#undef DECLARE_DL_FUNCTION + +#ifdef TGVOIP_IN_AUDIO_IO +#define pa_threaded_mainloop_new PulseAudioLoader::_import_pa_threaded_mainloop_new +#define pa_threaded_mainloop_get_api PulseAudioLoader::_import_pa_threaded_mainloop_get_api +#define pa_context_new PulseAudioLoader::_import_pa_context_new +#define pa_context_set_state_callback PulseAudioLoader::_import_pa_context_set_state_callback +#define pa_threaded_mainloop_lock PulseAudioLoader::_import_pa_threaded_mainloop_lock +#define pa_threaded_mainloop_unlock PulseAudioLoader::_import_pa_threaded_mainloop_unlock +#define pa_threaded_mainloop_start PulseAudioLoader::_import_pa_threaded_mainloop_start +#define pa_context_connect PulseAudioLoader::_import_pa_context_connect +#define pa_context_get_state PulseAudioLoader::_import_pa_context_get_state +#define pa_threaded_mainloop_wait PulseAudioLoader::_import_pa_threaded_mainloop_wait +#define pa_stream_new PulseAudioLoader::_import_pa_stream_new +#define pa_stream_set_state_callback PulseAudioLoader::_import_pa_stream_set_state_callback +#define pa_stream_set_write_callback PulseAudioLoader::_import_pa_stream_set_write_callback +#define pa_stream_connect_playback PulseAudioLoader::_import_pa_stream_connect_playback +#define pa_operation_unref PulseAudioLoader::_import_pa_operation_unref +#define pa_stream_cork PulseAudioLoader::_import_pa_stream_cork +#define pa_threaded_mainloop_stop PulseAudioLoader::_import_pa_threaded_mainloop_stop +#define pa_stream_disconnect PulseAudioLoader::_import_pa_stream_disconnect +#define pa_stream_unref PulseAudioLoader::_import_pa_stream_unref +#define pa_context_disconnect PulseAudioLoader::_import_pa_context_disconnect +#define pa_context_unref PulseAudioLoader::_import_pa_context_unref +#define pa_threaded_mainloop_free PulseAudioLoader::_import_pa_threaded_mainloop_free +#define pa_threaded_mainloop_signal PulseAudioLoader::_import_pa_threaded_mainloop_signal +#define pa_stream_begin_write PulseAudioLoader::_import_pa_stream_begin_write +#define pa_stream_write PulseAudioLoader::_import_pa_stream_write +#define pa_strerror PulseAudioLoader::_import_pa_strerror +#define pa_stream_get_state PulseAudioLoader::_import_pa_stream_get_state +#define pa_stream_set_read_callback PulseAudioLoader::_import_pa_stream_set_read_callback +#define pa_stream_connect_record PulseAudioLoader::_import_pa_stream_connect_record +#define pa_stream_peek PulseAudioLoader::_import_pa_stream_peek +#define pa_stream_drop PulseAudioLoader::_import_pa_stream_drop +#define pa_mainloop_new PulseAudioLoader::_import_pa_mainloop_new +#define pa_mainloop_get_api PulseAudioLoader::_import_pa_mainloop_get_api +#define pa_mainloop_iterate PulseAudioLoader::_import_pa_mainloop_iterate +#define pa_mainloop_free PulseAudioLoader::_import_pa_mainloop_free +#define pa_context_get_sink_info_list PulseAudioLoader::_import_pa_context_get_sink_info_list +#define pa_context_get_source_info_list PulseAudioLoader::_import_pa_context_get_source_info_list +#define pa_operation_get_state PulseAudioLoader::_import_pa_operation_get_state +#endif + +#endif // LIBTGVOIP_PULSEAUDIOLOADER_H \ No newline at end of file diff --git a/os/posix/NetworkSocketPosix.cpp b/os/posix/NetworkSocketPosix.cpp index ca1bb602ad..2f91af480e 100644 --- a/os/posix/NetworkSocketPosix.cpp +++ b/os/posix/NetworkSocketPosix.cpp @@ -141,6 +141,7 @@ void NetworkSocketPosix::Receive(NetworkPacket *packet){ lastRecvdV6=IPv6Address(srcAddr.sin6_addr.s6_addr); packet->address=&lastRecvdV6; } + packet->port=ntohs(srcAddr.sin6_port); } void NetworkSocketPosix::Open(){ diff --git a/os/windows/NetworkSocketWinsock.cpp b/os/windows/NetworkSocketWinsock.cpp index 018355cdbc..906a84fc4f 100644 --- a/os/windows/NetworkSocketWinsock.cpp +++ b/os/windows/NetworkSocketWinsock.cpp @@ -157,11 +157,11 @@ void NetworkSocketWinsock::Receive(NetworkPacket *packet){ } //LOGV("Received %d bytes from %s:%d at %.5lf", len, inet_ntoa(srcAddr.sin_addr), ntohs(srcAddr.sin_port), GetCurrentTime()); if(addr->sa_family==AF_INET){ - packet->port=srcAddr4.sin_port; + packet->port=ntohs(srcAddr4.sin_port); lastRecvdV4=IPv4Address(srcAddr4.sin_addr.s_addr); packet->address=&lastRecvdV4; }else{ - packet->port=srcAddr.sin6_port; + packet->port=ntohs(srcAddr.sin6_port); if(!isV4Available && IN6_IS_ADDR_V4MAPPED(&srcAddr.sin6_addr)){ isV4Available=true; LOGI("Detected IPv4 connectivity, will not try IPv6"); @@ -382,7 +382,7 @@ std::string NetworkSocketWinsock::V4AddressToString(uint32_t address){ addr.sin_addr.s_addr=address; DWORD len=sizeof(buf); #if WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP - wchar_t wbuf[INET6_ADDRSTRLEN]; + wchar_t wbuf[INET_ADDRSTRLEN]; ZeroMemory(wbuf, sizeof(wbuf)); WSAAddressToStringW((sockaddr*)&addr, sizeof(addr), NULL, wbuf, &len); WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, buf, sizeof(buf), NULL, NULL); @@ -415,7 +415,13 @@ uint32_t NetworkSocketWinsock::StringToV4Address(std::string address){ ZeroMemory(&addr, sizeof(addr)); addr.sin_family=AF_INET; int size=sizeof(addr); +#if WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP + wchar_t buf[INET_ADDRSTRLEN]; + MultiByteToWideChar(CP_UTF8, 0, address.c_str(), -1, buf, INET_ADDRSTRLEN); + WSAStringToAddressW(buf, AF_INET, NULL, (sockaddr*)&addr, &size); +#else WSAStringToAddressA((char*)address.c_str(), AF_INET, NULL, (sockaddr*)&addr, &size); +#endif return addr.sin_addr.s_addr; } @@ -424,6 +430,12 @@ void NetworkSocketWinsock::StringToV6Address(std::string address, unsigned char ZeroMemory(&addr, sizeof(addr)); addr.sin6_family=AF_INET6; int size=sizeof(addr); - WSAStringToAddressA((char*)address.c_str(), AF_INET6, NULL, (sockaddr*)&addr, &size); +#if WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP + wchar_t buf[INET6_ADDRSTRLEN]; + MultiByteToWideChar(CP_UTF8, 0, address.c_str(), -1, buf, INET6_ADDRSTRLEN); + WSAStringToAddressW(buf, AF_INET, NULL, (sockaddr*)&addr, &size); +#else + WSAStringToAddressA((char*)address.c_str(), AF_INET, NULL, (sockaddr*)&addr, &size); +#endif memcpy(out, addr.sin6_addr.s6_addr, 16); }