pjaudio and spdlog support

This commit is contained in:
infactum 2018-10-04 12:03:20 +05:00
parent 58fa05e5a8
commit f9315603b6
13 changed files with 595 additions and 37 deletions

205
libtgvoip/CMakeLists.txt Normal file
View File

@ -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 ()

125
libtgvoip/VoIPController.cpp Normal file → Executable file
View File

@ -123,6 +123,9 @@ CryptoFunctions VoIPController::crypto; // set it yourself upon initialization
extern FILE* tgvoipLogFile; extern FILE* tgvoipLogFile;
#ifdef TGVOIP_USE_SPDLOG
extern std::shared_ptr<spdlog::logger> _voip_logger;
#endif
VoIPController::VoIPController() : activeNetItfName(""), VoIPController::VoIPController() : activeNetItfName(""),
currentAudioInput("default"), currentAudioInput("default"),
@ -130,7 +133,10 @@ VoIPController::VoIPController() : activeNetItfName(""),
proxyAddress(""), proxyAddress(""),
proxyUsername(""), proxyUsername(""),
proxyPassword(""){ proxyPassword(""){
seq=1; #ifdef TGVOIP_USE_SPDLOG
_voip_logger = spdlog::get("tgvoip");
#endif
seq=1;
lastRemoteSeq=0; lastRemoteSeq=0;
state=STATE_WAIT_INIT; state=STATE_WAIT_INIT;
audioInput=NULL; audioInput=NULL;
@ -245,10 +251,42 @@ VoIPController::VoIPController() : activeNetItfName(""),
vstm.codec=CODEC_AVC; vstm.codec=CODEC_AVC;
vstm.enabled=1; vstm.enabled=1;
outgoingStreams.push_back(vstm);*/ 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(){ VoIPController::~VoIPController(){
LOGD("Entered 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){ if(!stopping){
LOGE("!!!!!!!!!!!!!!!!!!!! CALL controller->Stop() BEFORE DELETING THE CONTROLLER OBJECT !!!!!!!!!!!!!!!!!!!!!!!1"); LOGE("!!!!!!!!!!!!!!!!!!!! CALL controller->Stop() BEFORE DELETING THE CONTROLLER OBJECT !!!!!!!!!!!!!!!!!!!!!!!1");
abort(); abort();
@ -289,6 +327,14 @@ VoIPController::~VoIPController(){
delete (*stm)->decoder; 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"); LOGD("before delete echo canceller");
if(echoCanceller){ if(echoCanceller){
echoCanceller->Stop(); echoCanceller->Stop();
@ -1346,45 +1392,45 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA
peerCapabilities|=TGVOIP_PEER_CAP_GROUP_CALLS; peerCapabilities|=TGVOIP_PEER_CAP_GROUP_CALLS;
} }
unsigned int i; unsigned int i;
unsigned int numSupportedAudioCodecs=in.ReadByte(); unsigned int numSupportedAudioCodecs=in.ReadByte();
for(i=0; i<numSupportedAudioCodecs; i++){ for(i=0; i<numSupportedAudioCodecs; i++){
if(peerVersion<5) if(peerVersion<5)
in.ReadByte(); // ignore for now in.ReadByte(); // ignore for now
else else
in.ReadInt32(); in.ReadInt32();
} }
unsigned int numSupportedVideoCodecs=in.ReadByte(); unsigned int numSupportedVideoCodecs=in.ReadByte();
for(i=0; i<numSupportedVideoCodecs; i++){ for(i=0; i<numSupportedVideoCodecs; i++){
if(peerVersion<5) if(peerVersion<5)
in.ReadByte(); // ignore for now in.ReadByte(); // ignore for now
else else
in.ReadInt32(); in.ReadInt32();
} }
BufferOutputStream out(1024); BufferOutputStream out(1024);
out.WriteInt32(PROTOCOL_VERSION); out.WriteInt32(PROTOCOL_VERSION);
out.WriteInt32(MIN_PROTOCOL_VERSION); out.WriteInt32(MIN_PROTOCOL_VERSION);
out.WriteByte((unsigned char) outgoingStreams.size()); out.WriteByte((unsigned char) outgoingStreams.size());
for(vector<shared_ptr<Stream>>::iterator s=outgoingStreams.begin(); s!=outgoingStreams.end(); ++s){ for(vector<shared_ptr<Stream>>::iterator s=outgoingStreams.begin(); s!=outgoingStreams.end(); ++s){
out.WriteByte((*s)->id); out.WriteByte((*s)->id);
out.WriteByte((*s)->type); out.WriteByte((*s)->type);
if(peerVersion<5) if(peerVersion<5)
out.WriteByte((unsigned char) ((*s)->codec==CODEC_OPUS ? CODEC_OPUS_OLD : 0)); out.WriteByte((unsigned char) ((*s)->codec==CODEC_OPUS ? CODEC_OPUS_OLD : 0));
else else
out.WriteInt32((*s)->codec); out.WriteInt32((*s)->codec);
out.WriteInt16((*s)->frameDuration); out.WriteInt16((*s)->frameDuration);
out.WriteByte((unsigned char) ((*s)->enabled ? 1 : 0)); out.WriteByte((unsigned char) ((*s)->enabled ? 1 : 0));
} }
sendQueue->Put(PendingOutgoingPacket{ sendQueue->Put(PendingOutgoingPacket{
/*.seq=*/GenerateOutSeq(), /*.seq=*/GenerateOutSeq(),
/*.type=*/PKT_INIT_ACK, /*.type=*/PKT_INIT_ACK,
/*.len=*/out.GetLength(), /*.len=*/out.GetLength(),
/*.data=*/Buffer(move(out)), /*.data=*/Buffer(move(out)),
/*.endpoint=*/0 /*.endpoint=*/0
}); });
} }
} }
if(type==PKT_INIT_ACK){ if(type==PKT_INIT_ACK){
@ -2648,9 +2694,14 @@ void VoIPController::SendUdpPing(shared_ptr<Endpoint> endpoint){
void VoIPController::StartAudio(){ void VoIPController::StartAudio(){
shared_ptr<Stream>& outgoingAudioStream=outgoingStreams[0]; shared_ptr<Stream>& outgoingAudioStream=outgoingStreams[0];
LOGI("before create audio io"); LOGI("before create audio io");
#if defined(TGVOIP_USE_SOFTWARE_AUDIO)
audioInput = softwareMediaInput;
audioOutput = softwareMediaOutput;
#else
audioIO=audio::AudioIO::Create(); audioIO=audio::AudioIO::Create();
audioInput=audioIO->GetInput(); audioInput=audioIO->GetInput();
audioOutput=audioIO->GetOutput(); audioOutput=audioIO->GetOutput();
#endif
LOGI("AEC: %d NS: %d AGC: %d", config.enableAEC, config.enableNS, config.enableAGC); LOGI("AEC: %d NS: %d AGC: %d", config.enableAEC, config.enableNS, config.enableAGC);
echoCanceller=new EchoCanceller(config.enableAEC, config.enableNS, config.enableAGC); echoCanceller=new EchoCanceller(config.enableAEC, config.enableNS, config.enableAGC);
encoder=new OpusEncoder(audioInput, peerVersion>=6); encoder=new OpusEncoder(audioInput, peerVersion>=6);

14
libtgvoip/VoIPController.h Normal file → Executable file
View File

@ -21,6 +21,11 @@
#include <unordered_map> #include <unordered_map>
#include <memory> #include <memory>
#include <atomic> #include <atomic>
#if defined(TGVOIP_USE_SOFTWARE_AUDIO)
#include <pjsua2.hpp>
#include "audio/SoftwareAudioInput.h"
#include "audio/SoftwareAudioOutput.h"
#endif
#include "audio/AudioInput.h" #include "audio/AudioInput.h"
#include "BlockingQueue.h" #include "BlockingQueue.h"
#include "audio/AudioOutput.h" #include "audio/AudioOutput.h"
@ -381,6 +386,11 @@ namespace tgvoip{
return 0.0f; return 0.0f;
}; };
#if defined(TGVOIP_USE_SOFTWARE_AUDIO)
pj::AudioMedia * AudioMediaInput() {return softwareMediaInput;};
pj::AudioMedia * AudioMediaOutput() {return softwareMediaOutput;};
#endif
private: private:
struct Stream; struct Stream;
struct UnacknowledgedExtraData; struct UnacknowledgedExtraData;
@ -631,6 +641,10 @@ namespace tgvoip{
double p2pToRelaySwitchThreshold; double p2pToRelaySwitchThreshold;
double relayToP2pSwitchThreshold; double relayToP2pSwitchThreshold;
double reconnectingTimeout; double reconnectingTimeout;
#if defined(TGVOIP_USE_SOFTWARE_AUDIO)
tgvoip::audio::SoftwareAudioInput* softwareMediaInput;
tgvoip::audio::SoftwareAudioOutput* softwareMediaOutput;
#endif
public: public:
#ifdef __APPLE__ #ifdef __APPLE__

View File

@ -12,6 +12,7 @@
#include "config.h" #include "config.h"
#endif #endif
#if !defined(TGVOIP_USE_SOFTWARE_AUDIO)
#if defined(TGVOIP_USE_CALLBACK_AUDIO_IO) #if defined(TGVOIP_USE_CALLBACK_AUDIO_IO)
#include "AudioIOCallback.h" #include "AudioIOCallback.h"
#elif defined(__ANDROID__) #elif defined(__ANDROID__)
@ -42,12 +43,14 @@
#else #else
#error "Unsupported operating system" #error "Unsupported operating system"
#endif #endif
#endif
using namespace tgvoip; using namespace tgvoip;
using namespace tgvoip::audio; using namespace tgvoip::audio;
using namespace std; using namespace std;
shared_ptr<AudioIO> AudioIO::Create(){ shared_ptr<AudioIO> AudioIO::Create(){
#if !defined(TGVOIP_USE_SOFTWARE_AUDIO)
std::string inputDevice="default", outputDevice="default"; std::string inputDevice="default", outputDevice="default";
#if defined(TGVOIP_USE_CALLBACK_AUDIO_IO) #if defined(TGVOIP_USE_CALLBACK_AUDIO_IO)
return std::make_shared<AudioIOCallback>(); return std::make_shared<AudioIOCallback>();
@ -81,6 +84,7 @@ shared_ptr<AudioIO> AudioIO::Create(){
return std::make_shared<AudioPulse>(inputDevice, outputDevice); return std::make_shared<AudioPulse>(inputDevice, outputDevice);
#endif #endif
#endif #endif
#endif
} }
bool AudioIO::Failed(){ bool AudioIO::Failed(){

View File

@ -11,6 +11,7 @@
#include "config.h" #include "config.h"
#endif #endif
#if !defined(TGVOIP_USE_SOFTWARE_AUDIO)
#if defined(TGVOIP_USE_CALLBACK_AUDIO_IO) #if defined(TGVOIP_USE_CALLBACK_AUDIO_IO)
// nothing // nothing
#elif defined(__ANDROID__) #elif defined(__ANDROID__)
@ -36,6 +37,7 @@
#else #else
#error "Unsupported operating system" #error "Unsupported operating system"
#endif #endif
#endif
using namespace tgvoip; using namespace tgvoip;
using namespace tgvoip::audio; using namespace tgvoip::audio;
@ -60,6 +62,7 @@ bool AudioInput::IsInitialized(){
} }
void AudioInput::EnumerateDevices(std::vector<AudioInputDevice>& devs){ void AudioInput::EnumerateDevices(std::vector<AudioInputDevice>& devs){
#if !defined(TGVOIP_USE_SOFTWARE_AUDIO)
#if defined(TGVOIP_USE_CALLBACK_AUDIO_IO) #if defined(TGVOIP_USE_CALLBACK_AUDIO_IO)
// not supported // not supported
#elif defined(__APPLE__) && TARGET_OS_OSX #elif defined(__APPLE__) && TARGET_OS_OSX
@ -82,6 +85,7 @@ void AudioInput::EnumerateDevices(std::vector<AudioInputDevice>& devs){
AudioInputPulse::EnumerateDevices(devs) AudioInputPulse::EnumerateDevices(devs)
#endif #endif
#endif #endif
#endif
} }
std::string AudioInput::GetCurrentDevice(){ std::string AudioInput::GetCurrentDevice(){

View File

@ -12,6 +12,7 @@
#include "config.h" #include "config.h"
#endif #endif
#if !defined(TGVOIP_USE_SOFTWARE_AUDIO)
#if defined(TGVOIP_USE_CALLBACK_AUDIO_IO) #if defined(TGVOIP_USE_CALLBACK_AUDIO_IO)
// nothing // nothing
#elif defined(__ANDROID__) #elif defined(__ANDROID__)
@ -40,6 +41,7 @@
#else #else
#error "Unsupported operating system" #error "Unsupported operating system"
#endif #endif
#endif
using namespace tgvoip; using namespace tgvoip;
using namespace tgvoip::audio; using namespace tgvoip::audio;
@ -71,6 +73,7 @@ int32_t AudioOutput::GetEstimatedDelay(){
void AudioOutput::EnumerateDevices(std::vector<AudioOutputDevice>& devs){ void AudioOutput::EnumerateDevices(std::vector<AudioOutputDevice>& devs){
#if !defined(TGVOIP_USE_SOFTWARE_AUDIO)
#if defined(TGVOIP_USE_CALLBACK_AUDIO_IO) #if defined(TGVOIP_USE_CALLBACK_AUDIO_IO)
// not supported // not supported
#elif defined(__APPLE__) && TARGET_OS_OSX #elif defined(__APPLE__) && TARGET_OS_OSX
@ -93,6 +96,7 @@ void AudioOutput::EnumerateDevices(std::vector<AudioOutputDevice>& devs){
AudioOutputPulse::EnumerateDevices(devs) AudioOutputPulse::EnumerateDevices(devs)
#endif #endif
#endif #endif
#endif
} }

View File

@ -0,0 +1,66 @@
#include <cassert>
#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;
}

View File

@ -0,0 +1,33 @@
#ifndef TG2SIP_SOFTWAREAUDIOINPUT_H
#define TG2SIP_SOFTWAREAUDIOINPUT_H
#include <pjsua2.hpp>
#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

View File

@ -0,0 +1,81 @@
#include <cassert>
#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;
}

View File

@ -0,0 +1,38 @@
#ifndef TG2SIP_SOFTWAREAUDIOOUTPUT_H
#define TG2SIP_SOFTWAREAUDIOOUTPUT_H
#include <pjsua2.hpp>
#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

View File

@ -22,7 +22,48 @@
#include "os/darwin/DarwinSpecific.h" #include "os/darwin/DarwinSpecific.h"
#endif #endif
#ifdef TGVOIP_USE_SPDLOG
#include <memory>
#include "spdlog/spdlog.h"
#endif
FILE* tgvoipLogFile=NULL; FILE* tgvoipLogFile=NULL;
#ifdef TGVOIP_USE_SPDLOG
std::shared_ptr<spdlog::logger> _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, ...){ void tgvoip_log_file_printf(char level, const char* msg, ...){
if(tgvoipLogFile){ if(tgvoipLogFile){

View File

@ -13,11 +13,19 @@
#include <TargetConditionals.h> #include <TargetConditionals.h>
#endif #endif
#ifdef TGVOIP_USE_SPDLOG
#include "spdlog/spdlog.h"
#endif
#include <stdio.h> #include <stdio.h>
void tgvoip_log_file_printf(char level, const char* msg, ...); void tgvoip_log_file_printf(char level, const char* msg, ...);
void tgvoip_log_file_write_header(FILE* file); 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__) #if defined(__ANDROID__)
#include <android/log.h> #include <android/log.h>
@ -58,7 +66,11 @@ void tgvoip_log_file_write_header(FILE* file);
#include <stdio.h> #include <stdio.h>
#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__);} #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 LOGV(msg, ...) _TGVOIP_LOG_PRINT('V', msg, ##__VA_ARGS__)
#define LOGD(msg, ...) _TGVOIP_LOG_PRINT('D', msg, ##__VA_ARGS__) #define LOGD(msg, ...) _TGVOIP_LOG_PRINT('D', msg, ##__VA_ARGS__)

View File

@ -26,6 +26,11 @@ extern jclass jniUtilitiesClass;
#include <ifaddrs.h> #include <ifaddrs.h>
#endif #endif
// fix of undef in pjsip
#if defined(TGVOIP_USE_SOFTWARE_AUDIO)
#define s6_addr __in6_u.__u6_addr8
#endif
using namespace tgvoip; using namespace tgvoip;