From f9315603b65b18f4f3ce1b44be7f1f4960d926f4 Mon Sep 17 00:00:00 2001 From: infactum Date: Thu, 4 Oct 2018 12:03:20 +0500 Subject: [PATCH] pjaudio and spdlog support --- libtgvoip/CMakeLists.txt | 205 ++++++++++++++++++++++ libtgvoip/VoIPController.cpp | 125 +++++++++---- libtgvoip/VoIPController.h | 14 ++ libtgvoip/audio/AudioIO.cpp | 4 + libtgvoip/audio/AudioInput.cpp | 4 + libtgvoip/audio/AudioOutput.cpp | 4 + libtgvoip/audio/SoftwareAudioInput.cpp | 66 +++++++ libtgvoip/audio/SoftwareAudioInput.h | 33 ++++ libtgvoip/audio/SoftwareAudioOutput.cpp | 81 +++++++++ libtgvoip/audio/SoftwareAudioOutput.h | 38 ++++ libtgvoip/logging.cpp | 41 +++++ libtgvoip/logging.h | 12 ++ libtgvoip/os/posix/NetworkSocketPosix.cpp | 5 + 13 files changed, 595 insertions(+), 37 deletions(-) create mode 100644 libtgvoip/CMakeLists.txt mode change 100644 => 100755 libtgvoip/VoIPController.cpp mode change 100644 => 100755 libtgvoip/VoIPController.h create mode 100644 libtgvoip/audio/SoftwareAudioInput.cpp create mode 100644 libtgvoip/audio/SoftwareAudioInput.h create mode 100644 libtgvoip/audio/SoftwareAudioOutput.cpp create mode 100644 libtgvoip/audio/SoftwareAudioOutput.h diff --git a/libtgvoip/CMakeLists.txt b/libtgvoip/CMakeLists.txt new file mode 100644 index 0000000..14ffa93 --- /dev/null +++ b/libtgvoip/CMakeLists.txt @@ -0,0 +1,205 @@ +cmake_minimum_required(VERSION 3.9) + +find_package(PkgConfig REQUIRED) +pkg_check_modules(OPUS opus REQUIRED) +pkg_check_modules(OPENSSL openssl REQUIRED) +pkg_check_modules(PJSIP libpjproject>=2.8 REQUIRED) +find_package(spdlog 0.17) + +add_library(libtgvoip STATIC + BlockingQueue.cpp + BlockingQueue.h + Buffers.cpp + Buffers.h + CongestionControl.cpp + CongestionControl.h + EchoCanceller.cpp + EchoCanceller.h + JitterBuffer.cpp + JitterBuffer.h + logging.cpp + logging.h + MediaStreamItf.cpp + MediaStreamItf.h + OpusDecoder.cpp + OpusDecoder.h + OpusEncoder.cpp + OpusEncoder.h + threading.h + VoIPController.cpp + VoIPGroupController.cpp + VoIPController.h + PrivateDefines.h + VoIPServerConfig.cpp + VoIPServerConfig.h + audio/AudioInput.cpp + audio/AudioInput.h + audio/AudioOutput.cpp + audio/AudioOutput.h + audio/Resampler.cpp + audio/Resampler.h + NetworkSocket.cpp + NetworkSocket.h + PacketReassembler.cpp + PacketReassembler.h + MessageThread.cpp + MessageThread.h + audio/AudioIO.cpp + audio/AudioIO.h + + # POSIX + os/posix/NetworkSocketPosix.cpp + os/posix/NetworkSocketPosix.h + + webrtc_dsp/webrtc/base/array_view.h + webrtc_dsp/webrtc/base/atomicops.h + webrtc_dsp/webrtc/base/basictypes.h + webrtc_dsp/webrtc/base/checks.cc + webrtc_dsp/webrtc/base/checks.h + webrtc_dsp/webrtc/base/constructormagic.h + webrtc_dsp/webrtc/base/safe_compare.h + webrtc_dsp/webrtc/base/safe_conversions.h + webrtc_dsp/webrtc/base/safe_conversions_impl.h + webrtc_dsp/webrtc/base/sanitizer.h + webrtc_dsp/webrtc/base/stringutils.cc + webrtc_dsp/webrtc/base/stringutils.h + webrtc_dsp/webrtc/base/type_traits.h + webrtc_dsp/webrtc/common_audio/audio_util.cc + webrtc_dsp/webrtc/common_audio/channel_buffer.cc + webrtc_dsp/webrtc/common_audio/channel_buffer.h + webrtc_dsp/webrtc/common_audio/fft4g.c + webrtc_dsp/webrtc/common_audio/fft4g.h + webrtc_dsp/webrtc/common_audio/include/audio_util.h + webrtc_dsp/webrtc/common_audio/ring_buffer.c + webrtc_dsp/webrtc/common_audio/ring_buffer.h + webrtc_dsp/webrtc/common_audio/signal_processing/auto_corr_to_refl_coef.c + webrtc_dsp/webrtc/common_audio/signal_processing/auto_correlation.c + webrtc_dsp/webrtc/common_audio/signal_processing/complex_bit_reverse.c + webrtc_dsp/webrtc/common_audio/signal_processing/complex_fft.c + webrtc_dsp/webrtc/common_audio/signal_processing/complex_fft_tables.h + webrtc_dsp/webrtc/common_audio/signal_processing/copy_set_operations.c + webrtc_dsp/webrtc/common_audio/signal_processing/cross_correlation.c + webrtc_dsp/webrtc/common_audio/signal_processing/division_operations.c + webrtc_dsp/webrtc/common_audio/signal_processing/dot_product_with_scale.c + webrtc_dsp/webrtc/common_audio/signal_processing/downsample_fast.c + webrtc_dsp/webrtc/common_audio/signal_processing/energy.c + webrtc_dsp/webrtc/common_audio/signal_processing/filter_ar.c + webrtc_dsp/webrtc/common_audio/signal_processing/filter_ar_fast_q12.c + webrtc_dsp/webrtc/common_audio/signal_processing/filter_ma_fast_q12.c + webrtc_dsp/webrtc/common_audio/signal_processing/get_hanning_window.c + webrtc_dsp/webrtc/common_audio/signal_processing/get_scaling_square.c + webrtc_dsp/webrtc/common_audio/signal_processing/ilbc_specific_functions.c + webrtc_dsp/webrtc/common_audio/signal_processing/include/real_fft.h + webrtc_dsp/webrtc/common_audio/signal_processing/include/signal_processing_library.h + webrtc_dsp/webrtc/common_audio/signal_processing/include/spl_inl.h + webrtc_dsp/webrtc/common_audio/signal_processing/include/spl_inl_mips.h + webrtc_dsp/webrtc/common_audio/signal_processing/levinson_durbin.c + webrtc_dsp/webrtc/common_audio/signal_processing/lpc_to_refl_coef.c + webrtc_dsp/webrtc/common_audio/signal_processing/min_max_operations.c + webrtc_dsp/webrtc/common_audio/signal_processing/randomization_functions.c + webrtc_dsp/webrtc/common_audio/signal_processing/real_fft.c + webrtc_dsp/webrtc/common_audio/signal_processing/refl_coef_to_lpc.c + webrtc_dsp/webrtc/common_audio/signal_processing/resample.c + webrtc_dsp/webrtc/common_audio/signal_processing/resample_48khz.c + webrtc_dsp/webrtc/common_audio/signal_processing/resample_by_2.c + webrtc_dsp/webrtc/common_audio/signal_processing/resample_by_2_internal.c + webrtc_dsp/webrtc/common_audio/signal_processing/resample_by_2_internal.h + webrtc_dsp/webrtc/common_audio/signal_processing/resample_fractional.c + webrtc_dsp/webrtc/common_audio/signal_processing/spl_init.c + webrtc_dsp/webrtc/common_audio/signal_processing/spl_inl.c + webrtc_dsp/webrtc/common_audio/signal_processing/spl_sqrt.c + webrtc_dsp/webrtc/common_audio/signal_processing/spl_sqrt_floor.c + webrtc_dsp/webrtc/common_audio/signal_processing/splitting_filter_impl.c + webrtc_dsp/webrtc/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c + webrtc_dsp/webrtc/common_audio/signal_processing/vector_scaling_operations.c + webrtc_dsp/webrtc/common_audio/sparse_fir_filter.cc + webrtc_dsp/webrtc/common_audio/sparse_fir_filter.h + webrtc_dsp/webrtc/common_audio/wav_file.cc + webrtc_dsp/webrtc/common_audio/wav_file.h + webrtc_dsp/webrtc/common_audio/wav_header.cc + webrtc_dsp/webrtc/common_audio/wav_header.h + webrtc_dsp/webrtc/modules/audio_processing/aec/aec_common.h + webrtc_dsp/webrtc/modules/audio_processing/aec/aec_core.cc + webrtc_dsp/webrtc/modules/audio_processing/aec/aec_core.h + webrtc_dsp/webrtc/modules/audio_processing/aec/aec_core_optimized_methods.h + webrtc_dsp/webrtc/modules/audio_processing/aec/aec_core_sse2.cc + webrtc_dsp/webrtc/modules/audio_processing/aec/aec_resampler.cc + webrtc_dsp/webrtc/modules/audio_processing/aec/aec_resampler.h + webrtc_dsp/webrtc/modules/audio_processing/aec/echo_cancellation.cc + webrtc_dsp/webrtc/modules/audio_processing/aec/echo_cancellation.h + webrtc_dsp/webrtc/modules/audio_processing/aecm/aecm_core.cc + webrtc_dsp/webrtc/modules/audio_processing/aecm/aecm_core.h + webrtc_dsp/webrtc/modules/audio_processing/aecm/aecm_core_c.cc + webrtc_dsp/webrtc/modules/audio_processing/aecm/aecm_defines.h + webrtc_dsp/webrtc/modules/audio_processing/aecm/echo_control_mobile.cc + webrtc_dsp/webrtc/modules/audio_processing/aecm/echo_control_mobile.h + webrtc_dsp/webrtc/modules/audio_processing/agc/legacy/analog_agc.c + webrtc_dsp/webrtc/modules/audio_processing/agc/legacy/analog_agc.h + webrtc_dsp/webrtc/modules/audio_processing/agc/legacy/digital_agc.c + webrtc_dsp/webrtc/modules/audio_processing/agc/legacy/digital_agc.h + webrtc_dsp/webrtc/modules/audio_processing/agc/legacy/gain_control.h + webrtc_dsp/webrtc/modules/audio_processing/logging/apm_data_dumper.cc + webrtc_dsp/webrtc/modules/audio_processing/logging/apm_data_dumper.h + webrtc_dsp/webrtc/modules/audio_processing/ns/defines.h + webrtc_dsp/webrtc/modules/audio_processing/ns/noise_suppression.c + webrtc_dsp/webrtc/modules/audio_processing/ns/noise_suppression.h + webrtc_dsp/webrtc/modules/audio_processing/ns/noise_suppression_x.c + webrtc_dsp/webrtc/modules/audio_processing/ns/noise_suppression_x.h + webrtc_dsp/webrtc/modules/audio_processing/ns/ns_core.c + webrtc_dsp/webrtc/modules/audio_processing/ns/ns_core.h + webrtc_dsp/webrtc/modules/audio_processing/ns/nsx_core.c + webrtc_dsp/webrtc/modules/audio_processing/ns/nsx_core.h + webrtc_dsp/webrtc/modules/audio_processing/ns/nsx_core_c.c + webrtc_dsp/webrtc/modules/audio_processing/ns/nsx_defines.h + webrtc_dsp/webrtc/modules/audio_processing/ns/windows_private.h + webrtc_dsp/webrtc/modules/audio_processing/splitting_filter.cc + webrtc_dsp/webrtc/modules/audio_processing/splitting_filter.h + webrtc_dsp/webrtc/modules/audio_processing/three_band_filter_bank.cc + webrtc_dsp/webrtc/modules/audio_processing/three_band_filter_bank.h + webrtc_dsp/webrtc/modules/audio_processing/utility/block_mean_calculator.cc + webrtc_dsp/webrtc/modules/audio_processing/utility/block_mean_calculator.h + webrtc_dsp/webrtc/modules/audio_processing/utility/delay_estimator.cc + webrtc_dsp/webrtc/modules/audio_processing/utility/delay_estimator.h + webrtc_dsp/webrtc/modules/audio_processing/utility/delay_estimator_internal.h + webrtc_dsp/webrtc/modules/audio_processing/utility/delay_estimator_wrapper.cc + webrtc_dsp/webrtc/modules/audio_processing/utility/delay_estimator_wrapper.h + webrtc_dsp/webrtc/modules/audio_processing/utility/ooura_fft.cc + webrtc_dsp/webrtc/modules/audio_processing/utility/ooura_fft.h + webrtc_dsp/webrtc/modules/audio_processing/utility/ooura_fft_sse2.cc + webrtc_dsp/webrtc/modules/audio_processing/utility/ooura_fft_tables_common.h + webrtc_dsp/webrtc/system_wrappers/include/asm_defines.h + webrtc_dsp/webrtc/system_wrappers/include/compile_assert_c.h + webrtc_dsp/webrtc/system_wrappers/include/cpu_features_wrapper.h + webrtc_dsp/webrtc/system_wrappers/include/metrics.h + webrtc_dsp/webrtc/system_wrappers/source/cpu_features.cc + webrtc_dsp/webrtc/typedefs.h + + #SOFTWARE AUDIO + audio/SoftwareAudioInput.h + audio/SoftwareAudioInput.cpp + audio/SoftwareAudioOutput.h + audio/SoftwareAudioOutput.cpp) + +set_property(TARGET libtgvoip PROPERTY CXX_STANDARD 11) + +target_include_directories(libtgvoip PRIVATE + webrtc_dsp + ${OPUS_INCLUDE_DIRS} + ${OPENSSL_INCLUDE_DIRS} + ${PJSIP_INCLUDE_DIRS}) + +target_compile_definitions(libtgvoip PRIVATE + WEBRTC_APM_DEBUG_DUMP=0 + WEBRTC_POSIX + DEFAULT_THREAD_PRIORITY) + +target_compile_definitions(libtgvoip PUBLIC + TGVOIP_USE_DESKTOP_DSP + TGVOIP_USE_SOFTWARE_AUDIO) + +if (${spdlog_FOUND}) + target_compile_definitions(libtgvoip PUBLIC + TGVOIP_USE_SPDLOG) +else () + message(STATUS "Could NOT find spdlog") +endif () \ No newline at end of file diff --git a/libtgvoip/VoIPController.cpp b/libtgvoip/VoIPController.cpp old mode 100644 new mode 100755 index 84098b3..61b7fbf --- a/libtgvoip/VoIPController.cpp +++ b/libtgvoip/VoIPController.cpp @@ -123,6 +123,9 @@ CryptoFunctions VoIPController::crypto; // set it yourself upon initialization extern FILE* tgvoipLogFile; +#ifdef TGVOIP_USE_SPDLOG +extern std::shared_ptr _voip_logger; +#endif VoIPController::VoIPController() : activeNetItfName(""), currentAudioInput("default"), @@ -130,7 +133,10 @@ VoIPController::VoIPController() : activeNetItfName(""), proxyAddress(""), proxyUsername(""), proxyPassword(""){ - seq=1; +#ifdef TGVOIP_USE_SPDLOG + _voip_logger = spdlog::get("tgvoip"); +#endif + seq=1; lastRemoteSeq=0; state=STATE_WAIT_INIT; audioInput=NULL; @@ -245,10 +251,42 @@ VoIPController::VoIPController() : activeNetItfName(""), vstm.codec=CODEC_AVC; vstm.enabled=1; outgoingStreams.push_back(vstm);*/ + +#if defined(TGVOIP_USE_SOFTWARE_AUDIO) + pj_thread_t *tmp_thread = nullptr; + pj_thread_desc tmp_thread_desc; + if (!pj_thread_is_registered()) { + pj_bzero(&tmp_thread_desc, sizeof(tmp_thread_desc)); + pj_status_t status; + status = pj_thread_register("tmp", tmp_thread_desc, &tmp_thread); + if (status != PJ_SUCCESS) { + LOGE("Temp constructor thread PJ register failed"); + } + } + + softwareMediaInput = new tgvoip::audio::SoftwareAudioInput(); + softwareMediaOutput = new tgvoip::audio::SoftwareAudioOutput(); + + if (tmp_thread) { + pj_thread_destroy(tmp_thread); + } +#endif } VoIPController::~VoIPController(){ LOGD("Entered VoIPController::~VoIPController"); +#if defined(TGVOIP_USE_SOFTWARE_AUDIO) + pj_thread_t *tmp_thread = nullptr; + pj_thread_desc tmp_thread_desc; + if (!pj_thread_is_registered()) { + pj_bzero(&tmp_thread_desc, sizeof(tmp_thread_desc)); + pj_status_t status; + status = pj_thread_register("tmp", tmp_thread_desc, &tmp_thread); + if (status != PJ_SUCCESS) { + LOGE("Temp destructor thread PJ register failed"); + } + } +#endif if(!stopping){ LOGE("!!!!!!!!!!!!!!!!!!!! CALL controller->Stop() BEFORE DELETING THE CONTROLLER OBJECT !!!!!!!!!!!!!!!!!!!!!!!1"); abort(); @@ -289,6 +327,14 @@ VoIPController::~VoIPController(){ delete (*stm)->decoder; } }*/ +#if defined(TGVOIP_USE_SOFTWARE_AUDIO) + delete softwareMediaInput; + delete softwareMediaOutput; + + if(tmp_thread) { + pj_thread_destroy(tmp_thread); + } +#endif LOGD("before delete echo canceller"); if(echoCanceller){ echoCanceller->Stop(); @@ -1346,45 +1392,45 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA peerCapabilities|=TGVOIP_PEER_CAP_GROUP_CALLS; } - unsigned int i; - unsigned int numSupportedAudioCodecs=in.ReadByte(); - for(i=0; i>::iterator s=outgoingStreams.begin(); s!=outgoingStreams.end(); ++s){ - out.WriteByte((*s)->id); - out.WriteByte((*s)->type); - if(peerVersion<5) - out.WriteByte((unsigned char) ((*s)->codec==CODEC_OPUS ? CODEC_OPUS_OLD : 0)); - else - out.WriteInt32((*s)->codec); - out.WriteInt16((*s)->frameDuration); - out.WriteByte((unsigned char) ((*s)->enabled ? 1 : 0)); - } - sendQueue->Put(PendingOutgoingPacket{ - /*.seq=*/GenerateOutSeq(), - /*.type=*/PKT_INIT_ACK, - /*.len=*/out.GetLength(), - /*.data=*/Buffer(move(out)), - /*.endpoint=*/0 - }); + out.WriteByte((unsigned char) outgoingStreams.size()); + for(vector>::iterator s=outgoingStreams.begin(); s!=outgoingStreams.end(); ++s){ + out.WriteByte((*s)->id); + out.WriteByte((*s)->type); + if(peerVersion<5) + out.WriteByte((unsigned char) ((*s)->codec==CODEC_OPUS ? CODEC_OPUS_OLD : 0)); + else + out.WriteInt32((*s)->codec); + out.WriteInt16((*s)->frameDuration); + out.WriteByte((unsigned char) ((*s)->enabled ? 1 : 0)); + } + sendQueue->Put(PendingOutgoingPacket{ + /*.seq=*/GenerateOutSeq(), + /*.type=*/PKT_INIT_ACK, + /*.len=*/out.GetLength(), + /*.data=*/Buffer(move(out)), + /*.endpoint=*/0 + }); } } if(type==PKT_INIT_ACK){ @@ -2648,9 +2694,14 @@ void VoIPController::SendUdpPing(shared_ptr endpoint){ void VoIPController::StartAudio(){ shared_ptr& outgoingAudioStream=outgoingStreams[0]; LOGI("before create audio io"); +#if defined(TGVOIP_USE_SOFTWARE_AUDIO) + audioInput = softwareMediaInput; + audioOutput = softwareMediaOutput; +#else audioIO=audio::AudioIO::Create(); audioInput=audioIO->GetInput(); audioOutput=audioIO->GetOutput(); +#endif LOGI("AEC: %d NS: %d AGC: %d", config.enableAEC, config.enableNS, config.enableAGC); echoCanceller=new EchoCanceller(config.enableAEC, config.enableNS, config.enableAGC); encoder=new OpusEncoder(audioInput, peerVersion>=6); diff --git a/libtgvoip/VoIPController.h b/libtgvoip/VoIPController.h old mode 100644 new mode 100755 index 12849d7..cba0c3e --- a/libtgvoip/VoIPController.h +++ b/libtgvoip/VoIPController.h @@ -21,6 +21,11 @@ #include #include #include +#if defined(TGVOIP_USE_SOFTWARE_AUDIO) +#include +#include "audio/SoftwareAudioInput.h" +#include "audio/SoftwareAudioOutput.h" +#endif #include "audio/AudioInput.h" #include "BlockingQueue.h" #include "audio/AudioOutput.h" @@ -381,6 +386,11 @@ namespace tgvoip{ return 0.0f; }; +#if defined(TGVOIP_USE_SOFTWARE_AUDIO) + pj::AudioMedia * AudioMediaInput() {return softwareMediaInput;}; + pj::AudioMedia * AudioMediaOutput() {return softwareMediaOutput;}; +#endif + private: struct Stream; struct UnacknowledgedExtraData; @@ -631,6 +641,10 @@ namespace tgvoip{ double p2pToRelaySwitchThreshold; double relayToP2pSwitchThreshold; double reconnectingTimeout; +#if defined(TGVOIP_USE_SOFTWARE_AUDIO) + tgvoip::audio::SoftwareAudioInput* softwareMediaInput; + tgvoip::audio::SoftwareAudioOutput* softwareMediaOutput; +#endif public: #ifdef __APPLE__ diff --git a/libtgvoip/audio/AudioIO.cpp b/libtgvoip/audio/AudioIO.cpp index 45767c7..96fe5f2 100644 --- a/libtgvoip/audio/AudioIO.cpp +++ b/libtgvoip/audio/AudioIO.cpp @@ -12,6 +12,7 @@ #include "config.h" #endif +#if !defined(TGVOIP_USE_SOFTWARE_AUDIO) #if defined(TGVOIP_USE_CALLBACK_AUDIO_IO) #include "AudioIOCallback.h" #elif defined(__ANDROID__) @@ -42,12 +43,14 @@ #else #error "Unsupported operating system" #endif +#endif using namespace tgvoip; using namespace tgvoip::audio; using namespace std; shared_ptr AudioIO::Create(){ +#if !defined(TGVOIP_USE_SOFTWARE_AUDIO) std::string inputDevice="default", outputDevice="default"; #if defined(TGVOIP_USE_CALLBACK_AUDIO_IO) return std::make_shared(); @@ -81,6 +84,7 @@ shared_ptr AudioIO::Create(){ return std::make_shared(inputDevice, outputDevice); #endif #endif +#endif } bool AudioIO::Failed(){ diff --git a/libtgvoip/audio/AudioInput.cpp b/libtgvoip/audio/AudioInput.cpp index dae647a..21fc7d2 100644 --- a/libtgvoip/audio/AudioInput.cpp +++ b/libtgvoip/audio/AudioInput.cpp @@ -11,6 +11,7 @@ #include "config.h" #endif +#if !defined(TGVOIP_USE_SOFTWARE_AUDIO) #if defined(TGVOIP_USE_CALLBACK_AUDIO_IO) // nothing #elif defined(__ANDROID__) @@ -36,6 +37,7 @@ #else #error "Unsupported operating system" #endif +#endif using namespace tgvoip; using namespace tgvoip::audio; @@ -60,6 +62,7 @@ bool AudioInput::IsInitialized(){ } void AudioInput::EnumerateDevices(std::vector& devs){ +#if !defined(TGVOIP_USE_SOFTWARE_AUDIO) #if defined(TGVOIP_USE_CALLBACK_AUDIO_IO) // not supported #elif defined(__APPLE__) && TARGET_OS_OSX @@ -82,6 +85,7 @@ void AudioInput::EnumerateDevices(std::vector& devs){ AudioInputPulse::EnumerateDevices(devs) #endif #endif +#endif } std::string AudioInput::GetCurrentDevice(){ diff --git a/libtgvoip/audio/AudioOutput.cpp b/libtgvoip/audio/AudioOutput.cpp index 458e8a5..d7d0b14 100644 --- a/libtgvoip/audio/AudioOutput.cpp +++ b/libtgvoip/audio/AudioOutput.cpp @@ -12,6 +12,7 @@ #include "config.h" #endif +#if !defined(TGVOIP_USE_SOFTWARE_AUDIO) #if defined(TGVOIP_USE_CALLBACK_AUDIO_IO) // nothing #elif defined(__ANDROID__) @@ -40,6 +41,7 @@ #else #error "Unsupported operating system" #endif +#endif using namespace tgvoip; using namespace tgvoip::audio; @@ -71,6 +73,7 @@ int32_t AudioOutput::GetEstimatedDelay(){ void AudioOutput::EnumerateDevices(std::vector& devs){ +#if !defined(TGVOIP_USE_SOFTWARE_AUDIO) #if defined(TGVOIP_USE_CALLBACK_AUDIO_IO) // not supported #elif defined(__APPLE__) && TARGET_OS_OSX @@ -93,6 +96,7 @@ void AudioOutput::EnumerateDevices(std::vector& devs){ AudioOutputPulse::EnumerateDevices(devs) #endif #endif +#endif } diff --git a/libtgvoip/audio/SoftwareAudioInput.cpp b/libtgvoip/audio/SoftwareAudioInput.cpp new file mode 100644 index 0000000..613691e --- /dev/null +++ b/libtgvoip/audio/SoftwareAudioInput.cpp @@ -0,0 +1,66 @@ +#include +#include "SoftwareAudioInput.h" + +using namespace tgvoip::audio; + +SoftwareAudioInput::SoftwareAudioInput() { + isActive = false; + + pj_pool = pjsua_pool_create("input%p", 2048, 512); + media_port = PJ_POOL_ZALLOC_T(pj_pool, pjmedia_port); + + pj_status_t status; + pj_str_t name = pj_str((char *) "input"); + + status = pjmedia_port_info_init(&media_port->info, + &name, + PJMEDIA_SIG_CLASS_PORT_AUD('S', 'I'), // Software Input SIG + 48000, 1, 16, 960); + assert(status == PJ_SUCCESS); + + media_port->port_data.pdata = this; + media_port->put_frame = &PutFrameCallback; + media_port->get_frame = &GetFrameCallback; + + registerMediaPort(media_port); +} + +SoftwareAudioInput::~SoftwareAudioInput() { + unregisterMediaPort(); + pjmedia_port_destroy(media_port); + pj_pool_release(pj_pool); +} + +void SoftwareAudioInput::Start() { + isActive = true; +} + +void SoftwareAudioInput::Stop() { + isActive = false; +} + +pj_status_t SoftwareAudioInput::PutFrameCallback(pjmedia_port *port, pjmedia_frame *frame) { + + // skip heartbeat frame + if (frame->type != PJMEDIA_FRAME_TYPE_AUDIO) { + return PJ_SUCCESS; + } + + assert(frame->size == 960 * 2); + + auto input = (SoftwareAudioInput *) port->port_data.pdata; + + if (!input->isActive) { + return PJ_SUCCESS; + } + + input->InvokeCallback((unsigned char *) frame->buf, frame->size); + + return PJ_SUCCESS; +} + +pj_status_t SoftwareAudioInput::GetFrameCallback(pjmedia_port *port, pjmedia_frame *frame) { + frame->size = 0; + frame->type = PJMEDIA_FRAME_TYPE_NONE; + return PJ_SUCCESS; +} \ No newline at end of file diff --git a/libtgvoip/audio/SoftwareAudioInput.h b/libtgvoip/audio/SoftwareAudioInput.h new file mode 100644 index 0000000..55631af --- /dev/null +++ b/libtgvoip/audio/SoftwareAudioInput.h @@ -0,0 +1,33 @@ +#ifndef TG2SIP_SOFTWAREAUDIOINPUT_H +#define TG2SIP_SOFTWAREAUDIOINPUT_H + +#include +#include "AudioInput.h" +#include "../threading.h" + +namespace tgvoip { + namespace audio { + class SoftwareAudioInput : public AudioInput, public pj::AudioMedia { + public: + explicit SoftwareAudioInput(); + + virtual ~SoftwareAudioInput(); + + void Start() override; + + void Stop() override; + + private: + static pj_status_t PutFrameCallback(pjmedia_port *port, pjmedia_frame *frame); + + static pj_status_t GetFrameCallback(pjmedia_port *port, pjmedia_frame *frame); + + bool isActive; + + pj_pool_t *pj_pool; + pjmedia_port *media_port; + }; + } +} + +#endif //TG2SIP_SOFTWAREAUDIOINPUT_H \ No newline at end of file diff --git a/libtgvoip/audio/SoftwareAudioOutput.cpp b/libtgvoip/audio/SoftwareAudioOutput.cpp new file mode 100644 index 0000000..f0b3059 --- /dev/null +++ b/libtgvoip/audio/SoftwareAudioOutput.cpp @@ -0,0 +1,81 @@ +#include +#include "SoftwareAudioOutput.h" + +using namespace tgvoip::audio; + +SoftwareAudioOutput::SoftwareAudioOutput() { + isActive = false; + + pj_pool = pjsua_pool_create("output%p", 2048, 512); + media_port = PJ_POOL_ZALLOC_T(pj_pool, pjmedia_port); + + pj_status_t status; + pj_str_t name = pj_str((char *) "output"); + + // ptime = 10ms -> 480 samples per frame + status = pjmedia_port_info_init(&media_port->info, + &name, + PJMEDIA_SIG_CLASS_PORT_AUD('S', 'O'), // Software Output SIG + 48000, 1, 16, 480); + assert(status == PJ_SUCCESS); + + media_port->port_data.pdata = this; + media_port->put_frame = &PutFrameCallback; + media_port->get_frame = &GetFrameCallback; + + registerMediaPort(media_port); + + // 48kHz * 20 ms * 16 bits per sample + buffer = new unsigned char[1920]; +} + +SoftwareAudioOutput::~SoftwareAudioOutput() { + unregisterMediaPort(); + pjmedia_port_destroy(media_port); + pj_pool_release(pj_pool); + if (buffer) { + delete buffer; + } +} + +void SoftwareAudioOutput::Start() { + isActive = true; +} + +void SoftwareAudioOutput::Stop() { + isActive = false; +} + +bool SoftwareAudioOutput::IsPlaying() { + return isActive; +} + +pj_status_t SoftwareAudioOutput::PutFrameCallback(pjmedia_port *port, pjmedia_frame *frame) { + + frame->size = 0; + frame->type = PJMEDIA_FRAME_TYPE_NONE; + return PJ_SUCCESS; +} + +pj_status_t SoftwareAudioOutput::GetFrameCallback(pjmedia_port *port, pjmedia_frame *frame) { + + auto output = (SoftwareAudioOutput *) port->port_data.pdata; + + if (!output->isActive) { + frame->type = PJMEDIA_FRAME_TYPE_NONE; + frame->size = 0; + return PJ_SUCCESS; + } + + // libtgvoip ptime = 20ms + if (output->read_buffer) { + output->InvokeCallback(output->buffer, 1920); + memcpy(frame->buf, output->buffer, 960); + } else { + memcpy(frame->buf, output->buffer + 960, 960); + } + + output->read_buffer = !output->read_buffer; + + return PJ_SUCCESS; +} diff --git a/libtgvoip/audio/SoftwareAudioOutput.h b/libtgvoip/audio/SoftwareAudioOutput.h new file mode 100644 index 0000000..c894446 --- /dev/null +++ b/libtgvoip/audio/SoftwareAudioOutput.h @@ -0,0 +1,38 @@ +#ifndef TG2SIP_SOFTWAREAUDIOOUTPUT_H +#define TG2SIP_SOFTWAREAUDIOOUTPUT_H + +#include +#include "AudioOutput.h" +#include "../threading.h" + +namespace tgvoip { + namespace audio { + class SoftwareAudioOutput : public AudioOutput, public pj::AudioMedia { + public: + explicit SoftwareAudioOutput(); + + virtual ~SoftwareAudioOutput(); + + void Start() override; + + void Stop() override; + + virtual bool IsPlaying(); + + private: + static pj_status_t PutFrameCallback(pjmedia_port *port, pjmedia_frame *frame); + + static pj_status_t GetFrameCallback(pjmedia_port *port, pjmedia_frame *frame); + + bool isActive; + + pj_pool_t *pj_pool; + pjmedia_port *media_port; + + bool read_buffer{true}; + unsigned char *buffer; + }; + } +} + +#endif //TG2SIP_SOFTWAREAUDIOOUTPUT_H \ No newline at end of file diff --git a/libtgvoip/logging.cpp b/libtgvoip/logging.cpp index 78724ee..0a7ec41 100644 --- a/libtgvoip/logging.cpp +++ b/libtgvoip/logging.cpp @@ -22,7 +22,48 @@ #include "os/darwin/DarwinSpecific.h" #endif +#ifdef TGVOIP_USE_SPDLOG +#include +#include "spdlog/spdlog.h" +#endif + FILE* tgvoipLogFile=NULL; +#ifdef TGVOIP_USE_SPDLOG +std::shared_ptr _voip_logger; + +void tgvoip_log_spdlog(char level, const char* msg, ...) { + if (_voip_logger) { + spdlog::level::level_enum lvl; + switch (level) { + case 'V': + lvl = spdlog::level::level_enum::trace; + break; + case 'D': + lvl = spdlog::level::level_enum::debug; + break; + case 'I': + lvl = spdlog::level::level_enum::info; + break; + case 'W': + lvl = spdlog::level::level_enum::warn; + break; + case 'E': + lvl = spdlog::level::level_enum::err; + break; + default: + return; + } + + va_list argptr; + va_start(argptr, msg); + + char buf[1024]; + vsprintf(buf, msg, argptr); + _voip_logger->log(lvl, buf); + } +} + +#endif void tgvoip_log_file_printf(char level, const char* msg, ...){ if(tgvoipLogFile){ diff --git a/libtgvoip/logging.h b/libtgvoip/logging.h index 2ddae18..fb2f46b 100644 --- a/libtgvoip/logging.h +++ b/libtgvoip/logging.h @@ -13,11 +13,19 @@ #include #endif +#ifdef TGVOIP_USE_SPDLOG +#include "spdlog/spdlog.h" +#endif + #include void tgvoip_log_file_printf(char level, const char* msg, ...); void tgvoip_log_file_write_header(FILE* file); +#ifdef TGVOIP_USE_SPDLOG +void tgvoip_log_spdlog(char level, const char* msg, ...); +#endif + #if defined(__ANDROID__) #include @@ -58,7 +66,11 @@ void tgvoip_log_file_write_header(FILE* file); #include +#ifdef TGVOIP_USE_SPDLOG +#define _TGVOIP_LOG_PRINT(verb, msg, ...) {tgvoip_log_spdlog(verb, msg, ##__VA_ARGS__);} +#else #define _TGVOIP_LOG_PRINT(verb, msg, ...) {printf("%c/tgvoip: " msg "\n", verb, ##__VA_ARGS__); tgvoip_log_file_printf(verb, msg, ##__VA_ARGS__);} +#endif #define LOGV(msg, ...) _TGVOIP_LOG_PRINT('V', msg, ##__VA_ARGS__) #define LOGD(msg, ...) _TGVOIP_LOG_PRINT('D', msg, ##__VA_ARGS__) diff --git a/libtgvoip/os/posix/NetworkSocketPosix.cpp b/libtgvoip/os/posix/NetworkSocketPosix.cpp index ef8d2cb..78e48a4 100644 --- a/libtgvoip/os/posix/NetworkSocketPosix.cpp +++ b/libtgvoip/os/posix/NetworkSocketPosix.cpp @@ -26,6 +26,11 @@ extern jclass jniUtilitiesClass; #include #endif +// fix of undef in pjsip +#if defined(TGVOIP_USE_SOFTWARE_AUDIO) +#define s6_addr __in6_u.__u6_addr8 +#endif + using namespace tgvoip;