From bfde1a4be3168341a5c1f9d43578efb83c4013dc Mon Sep 17 00:00:00 2001 From: Grishka Date: Mon, 17 Apr 2017 21:57:07 +0300 Subject: [PATCH] Update to v0.4 Moved public API classes into namespace tgvoip (CVoIPController -> tgvoip::VoIPController, CVoIPServerConfig -> tgvoip::ServerConfig) Endpoint is now a class instead of a struct; also, IP addresses are now wrapped into objects instead of relying on in_addr and in6_addr Full Windows port (Win32 threading + Winsock + WaveOut/WaveIn) Added support for ALSA audio I/O on Linux (closes #2) Abstracted away low-level networking to make it more portable Minor bugfixes --- Android.mk | 68 +- BufferOutputStream.h | 1 + CongestionControl.cpp | 16 +- CongestionControl.h | 1 + EchoCanceller.cpp | 117 ++- JitterBuffer.cpp | 26 +- NetworkSocket.cpp | 142 ++++ NetworkSocket.h | 76 ++ OpusEncoder.cpp | 10 +- VoIPController.cpp | 748 ++++++++---------- VoIPController.h | 137 ++-- VoIPServerConfig.cpp | 26 +- VoIPServerConfig.h | 13 +- audio/AudioInput.cpp | 8 + audio/AudioOutput.cpp | 13 +- audio/AudioOutput.h | 4 + client/android/tg_voip_jni.cpp | 56 +- libtgvoip.gyp | 333 ++++++++ libtgvoip.xcodeproj/project.pbxproj | 49 +- logging.h | 13 + os/darwin/AudioUnitIO.cpp | 6 +- os/darwin/TGLogWrapper.m | 2 +- os/linux/AudioInputALSA.cpp | 88 +++ os/linux/AudioInputALSA.h | 46 ++ os/linux/AudioOutputALSA.cpp | 91 +++ os/linux/AudioOutputALSA.h | 46 ++ os/posix/NetworkSocketPosix.cpp | 282 +++++++ os/posix/NetworkSocketPosix.h | 44 ++ os/windows/AudioInputWave.cpp | 91 +++ os/windows/AudioInputWave.h | 37 + os/windows/AudioOutputWave.cpp | 90 +++ os/windows/AudioOutputWave.h | 37 + os/windows/NetworkSocketWinsock.cpp | 375 +++++++++ os/windows/NetworkSocketWinsock.h | 46 ++ threading.h | 27 + .../audio_processing/aec/aec_core_sse2.cc | 3 +- 36 files changed, 2550 insertions(+), 618 deletions(-) create mode 100644 NetworkSocket.cpp create mode 100644 NetworkSocket.h create mode 100644 libtgvoip.gyp create mode 100644 os/linux/AudioInputALSA.cpp create mode 100644 os/linux/AudioInputALSA.h create mode 100644 os/linux/AudioOutputALSA.cpp create mode 100644 os/linux/AudioOutputALSA.h create mode 100644 os/posix/NetworkSocketPosix.cpp create mode 100644 os/posix/NetworkSocketPosix.h create mode 100644 os/windows/AudioInputWave.cpp create mode 100644 os/windows/AudioInputWave.h create mode 100644 os/windows/AudioOutputWave.cpp create mode 100644 os/windows/AudioOutputWave.h create mode 100644 os/windows/NetworkSocketWinsock.cpp create mode 100644 os/windows/NetworkSocketWinsock.h diff --git a/Android.mk b/Android.mk index 189c3f6de4..23ef1c6ec4 100644 --- a/Android.mk +++ b/Android.mk @@ -1,16 +1,24 @@ +LOCAL_MODULE := WebRtcAec + +LOCAL_SRC_FILES := ./libtgvoip/external/libWebRtcAec_android_$(TARGET_ARCH_ABI).a + +include $(PREBUILT_STATIC_LIBRARY) + include $(CLEAR_VARS) LOCAL_MODULE := voip LOCAL_CPPFLAGS := -Wall -std=c++11 -DANDROID -finline-functions -ffast-math -Os -fno-strict-aliasing -O3 -LOCAL_CFLAGS := -O3 -DUSE_KISS_FFT -DFIXED_POINT +LOCAL_CFLAGS := -O3 -DUSE_KISS_FFT -fexceptions ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) - LOCAL_CPPFLAGS += -mfloat-abi=softfp -mfpu=neon - LOCAL_CFLAGS += -mfloat-abi=softfp -mfpu=neon +# LOCAL_CPPFLAGS += -mfloat-abi=softfp -mfpu=neon +# LOCAL_CFLAGS += -mfloat-abi=softfp -mfpu=neon -DFLOATING_POINT +# LOCAL_ARM_NEON := true else + LOCAL_CFLAGS += -DFIXED_POINT ifeq ($(TARGET_ARCH_ABI),armeabi) - LOCAL_CPPFLAGS += -mfloat-abi=softfp -mfpu=neon - LOCAL_CFLAGS += -mfloat-abi=softfp -mfpu=neon +# LOCAL_CPPFLAGS += -mfloat-abi=softfp -mfpu=neon +# LOCAL_CFLAGS += -mfloat-abi=softfp -mfpu=neon else ifeq ($(TARGET_ARCH_ABI),x86) @@ -23,32 +31,28 @@ MY_DIR := libtgvoip LOCAL_C_INCLUDES := jni/opus/include jni/boringssl/include/ LOCAL_SRC_FILES := \ -$(MY_DIR)/external/speex_dsp/buffer.c \ -$(MY_DIR)/external/speex_dsp/fftwrap.c \ -$(MY_DIR)/external/speex_dsp/filterbank.c \ -$(MY_DIR)/external/speex_dsp/kiss_fft.c \ -$(MY_DIR)/external/speex_dsp/kiss_fftr.c \ -$(MY_DIR)/external/speex_dsp/mdf.c \ -$(MY_DIR)/external/speex_dsp/preprocess.c \ -$(MY_DIR)/external/speex_dsp/resample.c \ -$(MY_DIR)/external/speex_dsp/scal.c \ -$(MY_DIR)/external/speex_dsp/smallft.c \ -$(MY_DIR)/VoIPController.cpp \ -$(MY_DIR)/BufferInputStream.cpp \ -$(MY_DIR)/BufferOutputStream.cpp \ -$(MY_DIR)/BlockingQueue.cpp \ -$(MY_DIR)/audio/AudioInput.cpp \ -$(MY_DIR)/os/android/AudioInputOpenSLES.cpp \ -$(MY_DIR)/MediaStreamItf.cpp \ -$(MY_DIR)/audio/AudioOutput.cpp \ -$(MY_DIR)/OpusEncoder.cpp \ -$(MY_DIR)/os/android/AudioOutputOpenSLES.cpp \ -$(MY_DIR)/JitterBuffer.cpp \ -$(MY_DIR)/OpusDecoder.cpp \ -$(MY_DIR)/BufferPool.cpp \ -$(MY_DIR)/os/android/OpenSLEngineWrapper.cpp \ -$(MY_DIR)/os/android/AudioInputAndroid.cpp \ -$(MY_DIR)/EchoCanceller.cpp \ +./libtgvoip/logging.cpp \ +./libtgvoip/VoIPController.cpp \ +./libtgvoip/BufferInputStream.cpp \ +./libtgvoip/BufferOutputStream.cpp \ +./libtgvoip/BlockingQueue.cpp \ +./libtgvoip/audio/AudioInput.cpp \ +./libtgvoip/os/android/AudioInputOpenSLES.cpp \ +./libtgvoip/MediaStreamItf.cpp \ +./libtgvoip/audio/AudioOutput.cpp \ +./libtgvoip/OpusEncoder.cpp \ +./libtgvoip/os/android/AudioOutputOpenSLES.cpp \ +./libtgvoip/JitterBuffer.cpp \ +./libtgvoip/OpusDecoder.cpp \ +./libtgvoip/BufferPool.cpp \ +./libtgvoip/os/android/OpenSLEngineWrapper.cpp \ +./libtgvoip/os/android/AudioInputAndroid.cpp \ +./libtgvoip/os/android/AudioOutputAndroid.cpp \ +./libtgvoip/EchoCanceller.cpp \ +./libtgvoip/CongestionControl.cpp \ +./libtgvoip/VoIPServerConfig.cpp \ +./libtgvoip/NetworkSocket.cpp +include $(BUILD_STATIC_LIBRARY) -include $(BUILD_STATIC_LIBRARY) \ No newline at end of file +include $(CLEAR_VARS) diff --git a/BufferOutputStream.h b/BufferOutputStream.h index 0420355646..ed58dbf38a 100644 --- a/BufferOutputStream.h +++ b/BufferOutputStream.h @@ -8,6 +8,7 @@ #define LIBTGVOIP_BUFFEROUTPUTSTREAM_H #include +#include class CBufferOutputStream{ diff --git a/CongestionControl.cpp b/CongestionControl.cpp index 71f4c58085..5f8f666729 100644 --- a/CongestionControl.cpp +++ b/CongestionControl.cpp @@ -11,6 +11,8 @@ #include #include +using namespace tgvoip; + CCongestionControl::CCongestionControl(){ memset(rttHistory, 0, 100*sizeof(double)); memset(inflightPackets, 0, 100*sizeof(tgvoip_congestionctl_packet_t)); @@ -27,7 +29,7 @@ CCongestionControl::CCongestionControl(){ stateTransitionTime=0; inflightDataSize=0; lossCount=0; - cwnd=(size_t) CVoIPServerConfig::GetSharedInstance()->GetInt("audio_congestion_window", 1024); + cwnd=(size_t) ServerConfig::GetSharedInstance()->GetInt("audio_congestion_window", 1024); init_mutex(mutex); } @@ -81,7 +83,7 @@ void CCongestionControl::PacketAcknowledged(uint32_t seq){ int i; for(i=0;i<100;i++){ if(inflightPackets[i].seq==seq && inflightPackets[i].sendTime>0){ - tmpRtt+=(CVoIPController::GetCurrentTime()-inflightPackets[i].sendTime); + tmpRtt+=(VoIPController::GetCurrentTime()-inflightPackets[i].sendTime); tmpRttCount++; inflightPackets[i].sendTime=0; inflightDataSize-=inflightPackets[i].size; @@ -119,7 +121,7 @@ void CCongestionControl::PacketSent(uint32_t seq, size_t size){ } slot->seq=seq; slot->size=size; - slot->sendTime=CVoIPController::GetCurrentTime(); + slot->sendTime=VoIPController::GetCurrentTime(); inflightDataSize+=size; unlock_mutex(mutex); } @@ -138,7 +140,7 @@ void CCongestionControl::Tick(){ } int i; for(i=0;i<100;i++){ - if(inflightPackets[i].sendTime!=0 && CVoIPController::GetCurrentTime()-inflightPackets[i].sendTime>2){ + if(inflightPackets[i].sendTime!=0 && VoIPController::GetCurrentTime()-inflightPackets[i].sendTime>2){ inflightPackets[i].sendTime=0; inflightDataSize-=inflightPackets[i].size; lossCount++; @@ -152,17 +154,17 @@ void CCongestionControl::Tick(){ int CCongestionControl::GetBandwidthControlAction(){ - if(CVoIPController::GetCurrentTime()-lastActionTime<1) + if(VoIPController::GetCurrentTime()-lastActionTime<1) return TGVOIP_CONCTL_ACT_NONE; size_t inflightAvg=GetInflightDataSize(); size_t max=cwnd+cwnd/10; size_t min=cwnd-cwnd/10; if(inflightAvgmax){ - lastActionTime=CVoIPController::GetCurrentTime(); + lastActionTime=VoIPController::GetCurrentTime(); return TGVOIP_CONCTL_ACT_DECREASE; } return TGVOIP_CONCTL_ACT_NONE; diff --git a/CongestionControl.h b/CongestionControl.h index 2838f19c8e..c659268cad 100644 --- a/CongestionControl.h +++ b/CongestionControl.h @@ -8,6 +8,7 @@ #define LIBTGVOIP_CONGESTIONCONTROL_H #include +#include #include "threading.h" #define TGVOIP_CONCTL_STARTUP 0 diff --git a/EchoCanceller.cpp b/EchoCanceller.cpp index 4ee159f6c5..62ee5856fb 100644 --- a/EchoCanceller.cpp +++ b/EchoCanceller.cpp @@ -10,12 +10,17 @@ #include #include -#ifndef TGVOIP_NO_AEC +#ifndef TGVOIP_NO_DSP +#ifndef TGVOIP_USE_DESKTOP_DSP #include "webrtc/modules/audio_processing/aecm/echo_control_mobile.h" -//#include "external/include/webrtc/echo_cancellation.h" +#include "webrtc/modules/audio_processing/ns/noise_suppression_x.h" +#else +#include "webrtc/modules/audio_processing/aec/echo_cancellation.h" +//#include "webrtc/modules/audio_processing/ns/noise_suppression.h" +#include "webrtc/modules/audio_processing/ns/noise_suppression_x.h" +#endif #include "webrtc/modules/audio_processing/splitting_filter.h" #include "webrtc/common_audio/channel_buffer.h" -#include "webrtc/modules/audio_processing/ns/noise_suppression_x.h" #include "webrtc/modules/audio_processing/agc/legacy/gain_control.h" #endif @@ -25,9 +30,11 @@ //#define CLAMP(x, min, max) (xmin ? x : min) : max) #define CLAMP(x, min, max) x -/*namespace webrtc{ +#ifdef TGVOIP_USE_DESKTOP_DSP +namespace webrtc{ void WebRtcAec_enable_delay_agnostic(AecCore* self, int enable); -}*/ +} +#endif CEchoCanceller::CEchoCanceller(bool enableAEC, bool enableNS, bool enableAGC){ this->enableAEC=enableAEC; @@ -46,12 +53,24 @@ CEchoCanceller::CEchoCanceller(bool enableAEC, bool enableNS, bool enableAGC){ if(enableAEC){ init_mutex(aecMutex); +#ifndef TGVOIP_USE_DESKTOP_DSP aec=WebRtcAecm_Create(); WebRtcAecm_Init(aec, 16000); AecmConfig cfg; cfg.cngMode=AecmFalse; cfg.echoMode=1; WebRtcAecm_set_config(aec, cfg); +#else + aec=webrtc::WebRtcAec_Create(); + webrtc::WebRtcAec_Init(aec, 48000, 48000); + webrtc::WebRtcAec_enable_delay_agnostic(webrtc::WebRtcAec_aec_core(aec), 1); + webrtc::AecConfig config; + config.metricsMode=webrtc::kAecFalse; + config.nlpMode=webrtc::kAecNlpAggressive; + config.skewMode=webrtc::kAecFalse; + config.delay_logging=webrtc::kAecFalse; + webrtc::WebRtcAec_set_config(aec, config); +#endif farendQueue=new CBlockingQueue(11); farendBufferPool=new CBufferPool(960*2, 10); @@ -61,9 +80,15 @@ CEchoCanceller::CEchoCanceller(bool enableAEC, bool enableNS, bool enableAGC){ } if(enableNS){ +//#ifndef TGVOIP_USE_DESKTOP_DSP ns=WebRtcNsx_Create(); WebRtcNsx_Init((NsxHandle*)ns, 48000); WebRtcNsx_set_policy((NsxHandle*)ns, 2); +/*#else + ns=WebRtcNs_Create(); + WebRtcNs_Init((NsHandle*)ns, 48000); + WebRtcNs_set_policy((NsHandle*)ns, 1); +#endif*/ } if(enableAGC){ @@ -90,10 +115,18 @@ CEchoCanceller::~CEchoCanceller(){ join_thread(bufferFarendThread); delete farendQueue; delete farendBufferPool; +#ifndef TGVOIP_USE_DESKTOP_DSP WebRtcAecm_Free(aec); +#else + webrtc::WebRtcAec_Free(aec); +#endif } if(enableNS){ +//#ifndef TGVOIP_USE_DESKTOP_DSP WebRtcNsx_Free((NsxHandle*)ns); +/*#else + WebRtcNs_Free((NsHandle*)ns); +#endif*/ } if(enableAGC){ WebRtcAgc_Free(agc); @@ -152,10 +185,13 @@ void CEchoCanceller::RunBufferFarendThread(){ farendBufferPool->Reuse((unsigned char *) samplesIn); ((webrtc::SplittingFilter*)splittingFilterFarend)->Analysis(bufIn, bufOut); lock_mutex(aecMutex); - //webrtc::WebRtcAec_BufferFarend(state, splittingFilterFarend->bufferOut[0], 160); - //webrtc::WebRtcAec_BufferFarend(state, &splittingFilterFarend->bufferOut[0][160], 160); +#ifndef TGVOIP_USE_DESKTOP_DSP WebRtcAecm_BufferFarend(aec, bufOut->ibuf_const()->bands(0)[0], 160); WebRtcAecm_BufferFarend(aec, bufOut->ibuf_const()->bands(0)[0]+160, 160); +#else + webrtc::WebRtcAec_BufferFarend(aec, bufOut->fbuf_const()->bands(0)[0], 160); + webrtc::WebRtcAec_BufferFarend(aec, bufOut->fbuf_const()->bands(0)[0]+160, 160); +#endif unlock_mutex(aecMutex); didBufferFarend=true; } @@ -175,8 +211,8 @@ void CEchoCanceller::ProcessInput(unsigned char* data, unsigned char* out, size_ int16_t* samplesIn=(int16_t*)data; int16_t* samplesOut=(int16_t*)out; - webrtc::IFChannelBuffer* bufIn=(webrtc::IFChannelBuffer*) splittingFilterFarendIn; - webrtc::IFChannelBuffer* bufOut=(webrtc::IFChannelBuffer*) splittingFilterFarendOut; + webrtc::IFChannelBuffer* bufIn=(webrtc::IFChannelBuffer*) splittingFilterIn; + webrtc::IFChannelBuffer* bufOut=(webrtc::IFChannelBuffer*) splittingFilterOut; memcpy(bufIn->ibuf()->bands(0)[0], samplesIn, 960*2); @@ -205,6 +241,7 @@ void CEchoCanceller::ProcessInput(unsigned char* data, unsigned char* out, size_ memcpy(bufOut->ibuf()->bands(0)[2], _agcOut[2], 320*2); } +#ifndef TGVOIP_USE_DESKTOP_DSP if(enableAEC && enableNS){ int16_t _nsOut[3][320]; int16_t* nsIn[3]; @@ -252,9 +289,69 @@ void CEchoCanceller::ProcessInput(unsigned char* data, unsigned char* out, size_ memcpy(bufOut->ibuf()->bands(0)[1], _nsOut[1], 320*2); memcpy(bufOut->ibuf()->bands(0)[2], _nsOut[2], 320*2); } +#else + /*if(enableNS){ + float _nsOut[3][320]; + const float* nsIn[3]; + float* nsOut[3]; + for(i=0;i<3;i++){ + nsIn[i]=bufOut->fbuf_const()->bands(0)[i]; + nsOut[i]=_nsOut[i]; + } + WebRtcNs_Process((NsHandle*)ns, nsIn, 3, nsOut); + for(i=0;i<3;i++){ + nsOut[i]+=160; + nsIn[i]+=160; + } + WebRtcNs_Process((NsHandle*)ns, nsIn, 3, nsOut); + + memcpy(bufOut->fbuf()->bands(0)[0], _nsOut[0], 320*4); + memcpy(bufOut->fbuf()->bands(0)[1], _nsOut[1], 320*4); + memcpy(bufOut->fbuf()->bands(0)[2], _nsOut[2], 320*4); + }*/ + if(enableNS){ + int16_t _nsOut[3][320]; + int16_t* nsIn[3]; + int16_t* nsOut[3]; + for(i=0;i<3;i++){ + nsIn[i]=(int16_t*)bufOut->ibuf_const()->bands(0)[i]; + nsOut[i]=_nsOut[i]; + } + WebRtcNsx_Process((NsxHandle*)ns, (const short *const *)nsIn, 3, nsOut); + for(i=0;i<3;i++){ + nsOut[i]+=160; + nsIn[i]+=160; + } + WebRtcNsx_Process((NsxHandle*)ns, (const short *const *)nsIn, 3, nsOut); + + memcpy(bufOut->ibuf()->bands(0)[0], _nsOut[0], 320*2); + memcpy(bufOut->ibuf()->bands(0)[1], _nsOut[1], 320*2); + memcpy(bufOut->ibuf()->bands(0)[2], _nsOut[2], 320*2); + } + + if(enableAEC){ + const float* aecIn[3]; + float* aecOut[3]; + float _aecOut[3][320]; + for(i=0;i<3;i++){ + aecIn[i]=bufOut->fbuf_const()->bands(0)[i]; + aecOut[i]=_aecOut[i]; + } + webrtc::WebRtcAec_Process(aec, aecIn, 3, aecOut, AEC_FRAME_SIZE, CAudioOutput::GetEstimatedDelay(), 0); + for(i=0;i<3;i++){ + aecOut[i]+=160; + aecIn[i]+=160; + } + webrtc::WebRtcAec_Process(aec, aecIn, 3, aecOut, AEC_FRAME_SIZE, CAudioOutput::GetEstimatedDelay(), 0); + + memcpy(bufOut->fbuf()->bands(0)[0], _aecOut[0], 320*4); + memcpy(bufOut->fbuf()->bands(0)[1], _aecOut[1], 320*4); + memcpy(bufOut->fbuf()->bands(0)[2], _aecOut[2], 320*4); + } +#endif ((webrtc::SplittingFilter*)splittingFilter)->Synthesis(bufOut, bufIn); - memcpy(samplesOut, bufIn->ibuf()->bands(0)[0], 960*2); + memcpy(samplesOut, bufIn->ibuf_const()->bands(0)[0], 960*2); } diff --git a/JitterBuffer.cpp b/JitterBuffer.cpp index 0942045b33..83de340417 100644 --- a/JitterBuffer.cpp +++ b/JitterBuffer.cpp @@ -10,6 +10,8 @@ #include "VoIPServerConfig.h" #include +using namespace tgvoip; + CJitterBuffer::CJitterBuffer(CMediaStreamItf *out, uint32_t step):bufferPool(JITTER_SLOT_SIZE, JITTER_SLOT_COUNT){ if(out) out->SetCallback(CJitterBuffer::CallbackOut, this); @@ -23,20 +25,20 @@ CJitterBuffer::CJitterBuffer(CMediaStreamItf *out, uint32_t step):bufferPool(JIT dontDecMinDelay=0; lostPackets=0; if(step<30){ - minMinDelay=(uint32_t) CVoIPServerConfig::GetSharedInstance()->GetInt("jitter_min_delay_20", 6); - maxMinDelay=(uint32_t) CVoIPServerConfig::GetSharedInstance()->GetInt("jitter_max_delay_20", 25); - maxUsedSlots=(uint32_t) CVoIPServerConfig::GetSharedInstance()->GetInt("jitter_max_slots_20", 50); + minMinDelay=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_min_delay_20", 6); + maxMinDelay=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_max_delay_20", 25); + maxUsedSlots=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_max_slots_20", 50); }else if(step<50){ - minMinDelay=(uint32_t) CVoIPServerConfig::GetSharedInstance()->GetInt("jitter_min_delay_40", 4); - maxMinDelay=(uint32_t) CVoIPServerConfig::GetSharedInstance()->GetInt("jitter_max_delay_40", 15); - maxUsedSlots=(uint32_t) CVoIPServerConfig::GetSharedInstance()->GetInt("jitter_max_slots_40", 30); + minMinDelay=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_min_delay_40", 4); + maxMinDelay=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_max_delay_40", 15); + maxUsedSlots=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_max_slots_40", 30); }else{ - minMinDelay=(uint32_t) CVoIPServerConfig::GetSharedInstance()->GetInt("jitter_min_delay_60", 1); - maxMinDelay=(uint32_t) CVoIPServerConfig::GetSharedInstance()->GetInt("jitter_max_delay_60", 10); - maxUsedSlots=(uint32_t) CVoIPServerConfig::GetSharedInstance()->GetInt("jitter_max_slots_60", 20); + minMinDelay=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_min_delay_60", 1); + maxMinDelay=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_max_delay_60", 10); + maxUsedSlots=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_max_slots_60", 20); } - lossesToReset=(uint32_t) CVoIPServerConfig::GetSharedInstance()->GetInt("jitter_losses_to_reset", 20); - resyncThreshold=CVoIPServerConfig::GetSharedInstance()->GetDouble("jitter_resync_threshold", 1.0); + lossesToReset=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_losses_to_reset", 20); + resyncThreshold=ServerConfig::GetSharedInstance()->GetDouble("jitter_resync_threshold", 1.0); Reset(); init_mutex(mutex); } @@ -208,7 +210,7 @@ void CJitterBuffer::PutInternal(jitter_packet_t* pkt){ prevTime=slots[i].recvTime; } }*/ - double time=CVoIPController::GetCurrentTime(); + double time=VoIPController::GetCurrentTime(); if(expectNextAtTime!=0){ double dev=expectNextAtTime-time; //LOGV("packet dev %f", dev); diff --git a/NetworkSocket.cpp b/NetworkSocket.cpp new file mode 100644 index 0000000000..53c313e8d5 --- /dev/null +++ b/NetworkSocket.cpp @@ -0,0 +1,142 @@ +// +// Created by Grishka on 29.03.17. +// + +#include "NetworkSocket.h" +#include +#include +#include +#if defined(_WIN32) +#include "os/windows/NetworkSocketWinsock.h" +#else +#include "os/posix/NetworkSocketPosix.h" +#endif +#include "logging.h" +#include "VoIPServerConfig.h" + +#define MIN_UDP_PORT 16384 +#define MAX_UDP_PORT 32768 + +namespace tgvoip { + +#pragma mark - NetworkSocket + + NetworkSocket::NetworkSocket(){ + ipv6Timeout=ServerConfig::GetSharedInstance()->GetDouble("nat64_fallback_timeout", 3); + failed=false; + } + + NetworkSocket::~NetworkSocket(){ + + } + + std::string NetworkSocket::GetLocalInterfaceInfo(IPv4Address *inet4addr, IPv6Address *inet6addr){ + std::string r="not implemented"; + return r; + } + + uint16_t NetworkSocket::GenerateLocalPort(){ + return (uint16_t) ((rand()%(MAX_UDP_PORT-MIN_UDP_PORT))+MIN_UDP_PORT); + } + + void NetworkSocket::SetMaxPriority(){ + } + + bool NetworkSocket::IsFailed(){ + return failed; + } + + NetworkSocket *NetworkSocket::Create(){ +#ifndef _WIN32 + return new NetworkSocketPosix(); +#else + return new NetworkSocketWinsock(); +#endif + } + +#pragma mark - NetworkAddress + + bool NetworkAddress::operator==(const NetworkAddress &other){ + IPv4Address* self4=dynamic_cast(this); + IPv4Address* other4=dynamic_cast((NetworkAddress*)&other); + if(self4 && other4){ + return self4->GetAddress()==other4->GetAddress(); + } + IPv6Address* self6=dynamic_cast(this); + IPv6Address* other6=dynamic_cast((NetworkAddress*)&other); + if(self6 && other6){ + return memcmp(self6->GetAddress(), other6->GetAddress(), 16)==0; + } + return false; + } + + bool NetworkAddress::operator!=(const NetworkAddress &other){ + return !(*this == other); + } + +#pragma mark - IPv4Address + + IPv4Address::IPv4Address(std::string addr){ +#ifndef _WIN32 + this->address=NetworkSocketPosix::StringToV4Address(addr); +#else + this->address=NetworkSocketWinsock::StringToV4Address(addr); +#endif + } + + IPv4Address::IPv4Address(uint32_t addr){ + this->address=addr; + } + + + std::string IPv4Address::ToString(){ +#ifndef _WIN32 + return NetworkSocketPosix::V4AddressToString(address); +#else + return NetworkSocketWinsock::V4AddressToString(address); +#endif + } + + /*sockaddr &IPv4Address::ToSockAddr(uint16_t port){ + sockaddr_in sa; + sa.sin_family=AF_INET; + sa.sin_addr=addr; + sa.sin_port=port; + return *((sockaddr *) &sa); + }*/ + + uint32_t IPv4Address::GetAddress(){ + return address; + } + +#pragma mark - IPv6Address + + IPv6Address::IPv6Address(std::string addr){ +#ifndef _WIN32 + NetworkSocketPosix::StringToV6Address(addr, this->address); +#else + NetworkSocketWinsock::StringToV6Address(addr, this->address); +#endif + } + + IPv6Address::IPv6Address(uint8_t addr[16]){ + memcpy(address, addr, 16); + } + + std::string IPv6Address::ToString(){ + return ""; + } + + /*sockaddr &IPv6Address::ToSockAddr(uint16_t port){ + sockaddr_in6 sa; + sa.sin6_family=AF_INET6; + sa.sin6_addr=addr; + sa.sin6_port=port; + return *((sockaddr *) &sa); + }*/ + + const uint8_t *IPv6Address::GetAddress(){ + return address; + } + +} diff --git a/NetworkSocket.h b/NetworkSocket.h new file mode 100644 index 0000000000..c9680bbb4b --- /dev/null +++ b/NetworkSocket.h @@ -0,0 +1,76 @@ +// +// Created by Grishka on 29.03.17. +// + +#ifndef LIBTGVOIP_NETWORKSOCKET_H +#define LIBTGVOIP_NETWORKSOCKET_H + +#include +#include + +namespace tgvoip { + class NetworkAddress{ + public: + virtual std::string ToString()=0; + //virtual sockaddr& ToSockAddr(uint16_t port)=0; + bool operator==(const NetworkAddress& other); + bool operator!=(const NetworkAddress& other); + }; + + class IPv4Address : public NetworkAddress{ + public: + IPv4Address(std::string addr); + IPv4Address(uint32_t addr); + virtual std::string ToString(); + //virtual sockaddr& ToSockAddr(uint16_t port); + uint32_t GetAddress(); + + private: + uint32_t address; + }; + + class IPv6Address : public NetworkAddress{ + public: + IPv6Address(std::string addr); + IPv6Address(uint8_t addr[16]); + virtual std::string ToString(); + //virtual sockaddr& ToSockAddr(uint16_t port); + const uint8_t* GetAddress(); + private: + uint8_t address[16]; + }; + + struct NetworkPacket{ + unsigned char* data; + size_t length; + NetworkAddress* address; + uint16_t port; + }; + typedef struct NetworkPacket NetworkPacket; + + class NetworkSocket{ + public: + NetworkSocket(); + virtual ~NetworkSocket(); + virtual void Send(NetworkPacket* packet)=0; + virtual void Receive(NetworkPacket* packet)=0; + virtual void Open()=0; + virtual void Close()=0; + virtual uint16_t GetLocalPort()=0; + virtual std::string GetLocalInterfaceInfo(IPv4Address* inet4addr, IPv6Address* inet6addr); + virtual void OnActiveInterfaceChanged()=0; + bool IsFailed(); + + static NetworkSocket* Create(); + + protected: + virtual uint16_t GenerateLocalPort(); + virtual void SetMaxPriority(); + double ipv6Timeout; + unsigned char nat64Prefix[12]; + bool failed; + }; + +} + +#endif //LIBTGVOIP_NETWORKSOCKET_H diff --git a/OpusEncoder.cpp b/OpusEncoder.cpp index f19e1b7cb9..eb12328ae5 100644 --- a/OpusEncoder.cpp +++ b/OpusEncoder.cpp @@ -9,6 +9,8 @@ #include "logging.h" #include "VoIPServerConfig.h" +using namespace tgvoip; + COpusEncoder::COpusEncoder(CMediaStreamItf *source):queue(11), bufferPool(960*2, 10){ this->source=source; source->SetCallback(COpusEncoder::Callback, this); @@ -24,10 +26,10 @@ COpusEncoder::COpusEncoder(CMediaStreamItf *source):queue(11), bufferPool(960*2, echoCanceller=NULL; complexity=10; frameDuration=20; - mediumCorrectionBitrate=CVoIPServerConfig::GetSharedInstance()->GetInt("audio_medium_fec_bitrate", 10000); - strongCorrectionBitrate=CVoIPServerConfig::GetSharedInstance()->GetInt("audio_strong_fec_bitrate", 8000); - mediumCorrectionMultiplier=CVoIPServerConfig::GetSharedInstance()->GetDouble("audio_medium_fec_multiplier", 1.5); - strongCorrectionMultiplier=CVoIPServerConfig::GetSharedInstance()->GetDouble("audio_strong_fec_multiplier", 2.0); + mediumCorrectionBitrate=ServerConfig::GetSharedInstance()->GetInt("audio_medium_fec_bitrate", 10000); + strongCorrectionBitrate=ServerConfig::GetSharedInstance()->GetInt("audio_strong_fec_bitrate", 8000); + mediumCorrectionMultiplier=ServerConfig::GetSharedInstance()->GetDouble("audio_medium_fec_multiplier", 1.5); + strongCorrectionMultiplier=ServerConfig::GetSharedInstance()->GetDouble("audio_strong_fec_multiplier", 2.0); } COpusEncoder::~COpusEncoder(){ diff --git a/VoIPController.cpp b/VoIPController.cpp index 4b2bd4b07f..743e374f29 100644 --- a/VoIPController.cpp +++ b/VoIPController.cpp @@ -1,4 +1,13 @@ -#include +// +// 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 _WIN32 +#include +#include +#endif #include #include #include @@ -11,22 +20,23 @@ #include "OpusDecoder.h" #include "VoIPServerConfig.h" #include -#include #include -#include #include -#include -#include -#include #include #include -#include + +using namespace tgvoip; #ifdef __APPLE__ #include "os/darwin/AudioUnitIO.h" #include -double CVoIPController::machTimebase=0; -uint64_t CVoIPController::machTimestart=0; +double VoIPController::machTimebase=0; +uint64_t VoIPController::machTimestart=0; +#endif + +#ifdef _WIN32 +int64_t VoIPController::win32TimeScale = 0; +bool VoIPController::didInitWin32TimeScale = false; #endif #define SHA1_LENGTH 20 @@ -61,7 +71,7 @@ void tgvoip_openssl_sha256(uint8_t* msg, size_t len, uint8_t* output){ SHA256(msg, len, output); } -voip_crypto_functions_t CVoIPController::crypto={ +voip_crypto_functions_t VoIPController::crypto={ tgvoip_openssl_rand_bytes, tgvoip_openssl_sha1, tgvoip_openssl_sha256, @@ -70,12 +80,18 @@ voip_crypto_functions_t CVoIPController::crypto={ }; #else -voip_crypto_functions_t CVoIPController::crypto; // set it yourself upon initialization +voip_crypto_functions_t VoIPController::crypto; // set it yourself upon initialization +#endif + +#ifdef _MSC_VER +#define MSC_STACK_FALLBACK(a, b) (b) +#else +#define MSC_STACK_FALLBACK(a, b) (a) #endif extern FILE* tgvoipLogFile; -CVoIPController::CVoIPController(){ +VoIPController::VoIPController() : activeNetItfName(""){ seq=1; lastRemoteSeq=0; state=STATE_WAIT_INIT; @@ -114,15 +130,12 @@ CVoIPController::CVoIPController(){ dontSendPackets=0; micMuted=false; currentEndpoint=NULL; - needSendP2pPing=false; waitingForRelayPeerInfo=false; - lastP2pPingTime=0; - p2pPingCount=0; allowP2p=true; dataSavingMode=false; - memset(activeNetItfName, 0, 32); publicEndpointsReqTime=0; init_mutex(queuedPacketsMutex); + init_mutex(endpointsMutex); connectionInitTime=0; lastRecvPacketTime=0; dataSavingRequestedByPeer=false; @@ -132,27 +145,23 @@ CVoIPController::CVoIPController(){ receivedInit=false; receivedInitAck=false; peerPreferredRelay=NULL; - - needUpdateNat64Prefix=true; - nat64Present=false; - switchToV6at=0; - isV4Available=false; - maxAudioBitrate=(uint32_t) CVoIPServerConfig::GetSharedInstance()->GetInt("audio_max_bitrate", 20000); - maxAudioBitrateGPRS=(uint32_t) CVoIPServerConfig::GetSharedInstance()->GetInt("audio_max_bitrate_gprs", 8000); - maxAudioBitrateEDGE=(uint32_t) CVoIPServerConfig::GetSharedInstance()->GetInt("audio_max_bitrate_edge", 16000); - maxAudioBitrateSaving=(uint32_t) CVoIPServerConfig::GetSharedInstance()->GetInt("audio_max_bitrate_saving", 8000); - initAudioBitrate=(uint32_t) CVoIPServerConfig::GetSharedInstance()->GetInt("audio_init_bitrate", 16000); - initAudioBitrateGPRS=(uint32_t) CVoIPServerConfig::GetSharedInstance()->GetInt("audio_init_bitrate_gprs", 8000); - initAudioBitrateEDGE=(uint32_t) CVoIPServerConfig::GetSharedInstance()->GetInt("audio_init_bitrate_edge", 8000); - initAudioBitrateSaving=(uint32_t) CVoIPServerConfig::GetSharedInstance()->GetInt("audio_init_bitrate_saving", 8000); - audioBitrateStepIncr=(uint32_t) CVoIPServerConfig::GetSharedInstance()->GetInt("audio_bitrate_step_incr", 1000); - audioBitrateStepDecr=(uint32_t) CVoIPServerConfig::GetSharedInstance()->GetInt("audio_bitrate_step_decr", 1000); - minAudioBitrate=(uint32_t) CVoIPServerConfig::GetSharedInstance()->GetInt("audio_min_bitrate", 8000); - relaySwitchThreshold=CVoIPServerConfig::GetSharedInstance()->GetDouble("relay_switch_threshold", 0.8); - p2pToRelaySwitchThreshold=CVoIPServerConfig::GetSharedInstance()->GetDouble("p2p_to_relay_switch_threshold", 0.6); - relayToP2pSwitchThreshold=CVoIPServerConfig::GetSharedInstance()->GetDouble("relay_to_p2p_switch_threshold", 0.8); - ipv6Timeout=CVoIPServerConfig::GetSharedInstance()->GetDouble("nat64_fallback_timeout", 3); + socket=NetworkSocket::Create(); + + maxAudioBitrate=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_max_bitrate", 20000); + maxAudioBitrateGPRS=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_max_bitrate_gprs", 8000); + maxAudioBitrateEDGE=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_max_bitrate_edge", 16000); + maxAudioBitrateSaving=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_max_bitrate_saving", 8000); + initAudioBitrate=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_init_bitrate", 16000); + initAudioBitrateGPRS=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_init_bitrate_gprs", 8000); + initAudioBitrateEDGE=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_init_bitrate_edge", 8000); + initAudioBitrateSaving=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_init_bitrate_saving", 8000); + audioBitrateStepIncr=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_bitrate_step_incr", 1000); + audioBitrateStepDecr=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_bitrate_step_decr", 1000); + minAudioBitrate=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_min_bitrate", 8000); + relaySwitchThreshold=ServerConfig::GetSharedInstance()->GetDouble("relay_switch_threshold", 0.8); + p2pToRelaySwitchThreshold=ServerConfig::GetSharedInstance()->GetDouble("p2p_to_relay_switch_threshold", 0.6); + relayToP2pSwitchThreshold=ServerConfig::GetSharedInstance()->GetDouble("relay_to_p2p_switch_threshold", 0.8); #ifdef __APPLE__ machTimestart=0; @@ -170,8 +179,8 @@ CVoIPController::CVoIPController(){ outgoingStreams.push_back(stm); } -CVoIPController::~CVoIPController(){ - LOGD("Entered CVoIPController::~CVoIPController"); +VoIPController::~VoIPController(){ + LOGD("Entered VoIPController::~VoIPController"); if(audioInput) audioInput->Stop(); if(audioOutput) @@ -179,9 +188,9 @@ CVoIPController::~CVoIPController(){ stopping=true; runReceiver=false; LOGD("before shutdown socket"); - shutdown(udpSocket, SHUT_RDWR); + if(socket) + socket->Close(); sendQueue->Put(NULL); - close(udpSocket); LOGD("before join sendThread"); join_thread(sendThread); LOGD("before join recvThread"); @@ -190,6 +199,8 @@ CVoIPController::~CVoIPController(){ join_thread(tickThread); free_mutex(sendBufferMutex); LOGD("before close socket"); + if(socket) + delete socket; LOGD("before free send buffers"); while(emptySendBuffers.size()>0){ delete emptySendBuffers[emptySendBuffers.size()-1]; @@ -240,17 +251,17 @@ CVoIPController::~CVoIPController(){ free(outgoingStreams[i]); } outgoingStreams.clear(); - for(i=0;idata) free(queuedPackets[i]->data); free(queuedPackets[i]); } delete conctl; - LOGD("Left CVoIPController::~CVoIPController"); + for(std::vector::iterator itr=endpoints.begin();itr!=endpoints.end();++itr) + delete *itr; + LOGD("Left VoIPController::~VoIPController"); if(tgvoipLogFile){ FILE* log=tgvoipLogFile; tgvoipLogFile=NULL; @@ -258,108 +269,46 @@ CVoIPController::~CVoIPController(){ } } -void CVoIPController::SetRemoteEndpoints(voip_endpoint_t* endpoints, size_t count, bool allowP2p){ +void VoIPController::SetRemoteEndpoints(std::vector endpoints, bool allowP2p){ LOGW("Set remote endpoints"); - assert(count>0); preferredRelay=NULL; size_t i; - for(i=0;i_averageRtt=0; - ep->_lastPingTime=0; - memset(ep->_rtts, 0, sizeof(double)*6); - this->endpoints.push_back(ep); - if(ep->type==EP_TYPE_UDP_RELAY && !preferredRelay) - preferredRelay=ep; + lock_mutex(endpointsMutex); + this->endpoints.clear(); + for(std::vector::iterator itrtr=endpoints.begin();itrtr!=endpoints.end();++itrtr){ + this->endpoints.push_back(new Endpoint(*itrtr)); } + unlock_mutex(endpointsMutex); currentEndpoint=this->endpoints[0]; + preferredRelay=currentEndpoint; this->allowP2p=allowP2p; } -void* CVoIPController::StartRecvThread(void* controller){ - ((CVoIPController*)controller)->RunRecvThread(); +void* VoIPController::StartRecvThread(void* controller){ + ((VoIPController*)controller)->RunRecvThread(); return NULL; } -void* CVoIPController::StartSendThread(void* controller){ - ((CVoIPController*)controller)->RunSendThread(); +void* VoIPController::StartSendThread(void* controller){ + ((VoIPController*)controller)->RunSendThread(); return NULL; } -void* CVoIPController::StartTickThread(void* controller){ - ((CVoIPController*) controller)->RunTickThread(); +void* VoIPController::StartTickThread(void* controller){ + ((VoIPController*) controller)->RunTickThread(); return NULL; } -void CVoIPController::Start(){ +void VoIPController::Start(){ int res; LOGW("Starting voip controller"); - int32_t cfgFrameSize=CVoIPServerConfig::GetSharedInstance()->GetInt("audio_frame_size", 60); + int32_t cfgFrameSize=ServerConfig::GetSharedInstance()->GetInt("audio_frame_size", 60); if(cfgFrameSize==20 || cfgFrameSize==40 || cfgFrameSize==60) outgoingStreams[0]->frameDuration=(uint16_t) cfgFrameSize; - udpSocket=socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); - if(udpSocket<0){ - LOGE("error creating socket: %d / %s", errno, strerror(errno)); - } - int flag=0; - res=setsockopt(udpSocket, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)); - if(res<0){ - LOGE("error enabling dual stack socket: %d / %s", errno, strerror(errno)); - } -#ifdef __APPLE__ - int prio=NET_SERVICE_TYPE_VO; - res=setsockopt(udpSocket, SOL_SOCKET, SO_NET_SERVICE_TYPE, &prio, sizeof(prio)); - if(res<0){ - LOGE("error setting darwin-specific net priority: %d / %s", errno, strerror(errno)); - } -#else - int prio=5; - res=setsockopt(udpSocket, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio)); - if(res<0){ - LOGE("error setting priority: %d / %s", errno, strerror(errno)); - } - prio=6 << 5; - res=setsockopt(udpSocket, SOL_IP, IP_TOS, &prio, sizeof(prio)); - if(res<0){ - LOGE("error setting ip tos: %d / %s", errno, strerror(errno)); - } -#endif - int tries=0; - sockaddr_in6 addr; - //addr.sin6_addr.s_addr=0; - memset(&addr, 0, sizeof(sockaddr_in6)); - //addr.sin6_len=sizeof(sa_family_t); - addr.sin6_family=AF_INET6; - for(tries=0;tries<10;tries++){ - addr.sin6_port=htons(GenerateLocalUDPPort()); - res=::bind(udpSocket, (sockaddr *) &addr, sizeof(sockaddr_in6)); - LOGV("trying bind to port %u", ntohs(addr.sin6_port)); - if(res<0){ - LOGE("error binding to port %u: %d / %s", ntohs(addr.sin6_port), errno, strerror(errno)); - }else{ - break; - } - } - if(tries==10){ - addr.sin6_port=0; - res=::bind(udpSocket, (sockaddr *) &addr, sizeof(sockaddr_in6)); - if(res<0){ - LOGE("error binding to port %u: %d / %s", ntohs(addr.sin6_port), errno, strerror(errno)); - SetState(STATE_FAILED); - return; - } - } - size_t addrLen=sizeof(sockaddr_in6); - getsockname(udpSocket, (sockaddr*)&addr, (socklen_t*) &addrLen); - localUdpPort=ntohs(addr.sin6_port); - LOGD("Bound to local UDP port %u", ntohs(addr.sin6_port)); + socket->Open(); - needUpdateNat64Prefix=true; - isV4Available=false; - switchToV6at=GetCurrentTime()+ipv6Timeout; SendPacket(NULL, 0, currentEndpoint); @@ -375,12 +324,12 @@ void CVoIPController::Start(){ set_thread_name(tickThread, "voip-tick"); } -size_t CVoIPController::AudioInputCallback(unsigned char* data, size_t length, void* param){ - ((CVoIPController*)param)->HandleAudioInput(data, length); +size_t VoIPController::AudioInputCallback(unsigned char* data, size_t length, void* param){ + ((VoIPController*)param)->HandleAudioInput(data, length); return 0; } -void CVoIPController::HandleAudioInput(unsigned char *data, size_t len){ +void VoIPController::HandleAudioInput(unsigned char *data, size_t len){ if(stopping) return; if(waitingForAcks || dontSendPackets>0){ @@ -410,7 +359,7 @@ void CVoIPController::HandleAudioInput(unsigned char *data, size_t len){ audioPacketsWritten++; if(audioPacketsWritten>=audioPacketGrouping){ uint32_t pl=pkt->GetLength(); - unsigned char tmp[pl]; + unsigned char tmp[MSC_STACK_FALLBACK(pl, 1024)]; memcpy(tmp, pkt->GetBuffer(), pl); pkt->Reset(); unsigned char type; @@ -438,14 +387,14 @@ void CVoIPController::HandleAudioInput(unsigned char *data, size_t len){ audioTimestampOut+=outgoingStreams[0]->frameDuration; } -void CVoIPController::Connect(){ +void VoIPController::Connect(){ assert(state!=STATE_WAIT_INIT_ACK); connectionInitTime=GetCurrentTime(); SendInit(); } -void CVoIPController::SetEncryptionKey(char *key, bool isOutgoing){ +void VoIPController::SetEncryptionKey(char *key, bool isOutgoing){ memcpy(encryptionKey, key, 256); uint8_t sha1[SHA1_LENGTH]; crypto.sha1((uint8_t*) encryptionKey, 256, sha1); @@ -456,7 +405,7 @@ void CVoIPController::SetEncryptionKey(char *key, bool isOutgoing){ this->isOutgoing=isOutgoing; } -uint32_t CVoIPController::WritePacketHeader(CBufferOutputStream *s, unsigned char type, uint32_t length){ +uint32_t VoIPController::WritePacketHeader(CBufferOutputStream *s, unsigned char type, uint32_t length){ uint32_t acks=0; int i; for(i=0;i<32;i++){ @@ -543,7 +492,7 @@ uint32_t CVoIPController::WritePacketHeader(CBufferOutputStream *s, unsigned cha } -void CVoIPController::UpdateAudioBitrate(){ +void VoIPController::UpdateAudioBitrate(){ if(encoder){ if(dataSavingMode || dataSavingRequestedByPeer){ maxBitrate=maxAudioBitrateSaving; @@ -562,7 +511,7 @@ void CVoIPController::UpdateAudioBitrate(){ } -void CVoIPController::SendInit(){ +void VoIPController::SendInit(){ CBufferOutputStream* out=new CBufferOutputStream(1024); WritePacketHeader(out, PKT_INIT, 15); out->WriteInt32(PROTOCOL_VERSION); @@ -574,49 +523,55 @@ void CVoIPController::SendInit(){ out->WriteByte(1); // audio codecs count out->WriteByte(CODEC_OPUS); out->WriteByte(0); // video codecs count - for(std::vector::const_iterator itr=endpoints.begin();itr!=endpoints.end();++itr){ + lock_mutex(endpointsMutex); + for(std::vector::iterator itr=endpoints.begin();itr!=endpoints.end();++itr){ SendPacket(out->GetBuffer(), out->GetLength(), *itr); } + unlock_mutex(endpointsMutex); SetState(STATE_WAIT_INIT_ACK); delete out; } -void CVoIPController::SendInitAck(){ +void VoIPController::SendInitAck(){ } -void CVoIPController::RunRecvThread(){ +void VoIPController::RunRecvThread(){ LOGI("Receive thread starting"); unsigned char buffer[1024]; - sockaddr_in6 srcAddr; - int addrLen; + NetworkPacket packet; while(runReceiver){ //LOGI("Before recv"); - addrLen=sizeof(sockaddr_in6); - ssize_t len=recvfrom(udpSocket, buffer, 1024, 0, (sockaddr *) &srcAddr, (socklen_t *) &addrLen); - //LOGV("Received %d bytes from %s:%d at %.5lf", len, inet_ntoa(srcAddr.sin_addr), ntohs(srcAddr.sin_port), GetCurrentTime()); - voip_endpoint_t* srcEndpoint=NULL; - if(!isV4Available && IN6_IS_ADDR_V4MAPPED(&srcAddr.sin6_addr)){ - isV4Available=true; - LOGI("Detected IPv4 connectivity, will not try IPv6"); + packet.data=buffer; + packet.length=1024; + socket->Receive(&packet); + if(!packet.address){ + LOGE("Packet has null address. This shouldn't happen."); + continue; } - if(IN6_IS_ADDR_V4MAPPED(&srcAddr.sin6_addr) || (nat64Present && memcmp(nat64Prefix, srcAddr.sin6_addr.s6_addr, 12)==0)){ - in_addr v4addr=*((in_addr*)&srcAddr.sin6_addr.s6_addr[12]); - int _i; - for(_i=0;_iaddress.s_addr==v4addr.s_addr && endpoints[_i]->port==ntohs(srcAddr.sin6_port)){ - srcEndpoint=endpoints[_i]; + size_t len=packet.length; + + //LOGV("Received %d bytes from %s:%d at %.5lf", len, inet_ntoa(srcAddr.sin_addr), ntohs(srcAddr.sin_port), GetCurrentTime()); + Endpoint* srcEndpoint=NULL; + + IPv4Address* src4=dynamic_cast(packet.address); + if(src4){ + lock_mutex(endpointsMutex); + for(std::vector::iterator itrtr=endpoints.begin();itrtr!=endpoints.end();++itrtr){ + if((*itrtr)->address==*src4){ + srcEndpoint=*itrtr; break; } } + unlock_mutex(endpointsMutex); } + if(!srcEndpoint){ - char abuf[INET6_ADDRSTRLEN]; - LOGW("Received a packet from unknown source %s:%u", inet_ntop(AF_INET6, &srcAddr.sin6_addr, abuf, INET6_ADDRSTRLEN), ntohs(srcAddr.sin6_port)); + LOGW("Received a packet from unknown source %s:%u", packet.address->ToString().c_str(), packet.port); continue; } if(len<=0){ - LOGW("error receiving: %d / %s", errno, strerror(errno)); + //LOGW("error receiving: %d / %s", errno, strerror(errno)); continue; } if(IS_MOBILE_NETWORK(networkType)) @@ -646,47 +601,41 @@ void CVoIPController::RunRecvThread(){ in->Seek(in->GetOffset()+12); uint32_t tlid=(uint32_t) in->ReadInt32(); if(tlid==TLID_UDP_REFLECTOR_PEER_INFO){ + lock_mutex(endpointsMutex); uint32_t myAddr=(uint32_t) in->ReadInt32(); uint32_t myPort=(uint32_t) in->ReadInt32(); uint32_t peerAddr=(uint32_t) in->ReadInt32(); uint32_t peerPort=(uint32_t) in->ReadInt32(); - voip_endpoint_t* p2pEndpoint=NULL; - for(i=0;itype==EP_TYPE_UDP_P2P_INET){ - p2pEndpoint=endpoints[i]; + for(std::vector::iterator itrtr=endpoints.begin();itrtr!=endpoints.end();++itrtr){ + if((*itrtr)->type==EP_TYPE_UDP_P2P_INET){ + delete *itrtr; + endpoints.erase(itrtr); break; } } - if(!p2pEndpoint){ - p2pEndpoint=(voip_endpoint_t *) malloc(sizeof(voip_endpoint_t)); - endpoints.push_back(p2pEndpoint); + for(std::vector::iterator itrtr=endpoints.begin();itrtr!=endpoints.end();++itrtr){ + if((*itrtr)->type==EP_TYPE_UDP_P2P_LAN){ + delete *itrtr; + endpoints.erase(itrtr); + break; + } } - memset(p2pEndpoint, 0, sizeof(voip_endpoint_t)); - p2pEndpoint->type=EP_TYPE_UDP_P2P_INET; - p2pEndpoint->port=peerPort; - p2pEndpoint->address.s_addr=peerAddr;//ntohl(peerAddr); + IPv4Address _peerAddr(peerAddr); + IPv6Address emptyV6("::0"); + unsigned char peerTag[16]; + endpoints.push_back(new Endpoint(0, (uint16_t) peerPort, _peerAddr, emptyV6, EP_TYPE_UDP_P2P_INET, peerTag)); LOGW("Received reflector peer info, my=%08X:%u, peer=%08X:%u", myAddr, myPort, peerAddr, peerPort); if(myAddr==peerAddr){ LOGW("Detected LAN"); - in_addr lanAddr; - GetLocalNetworkItfInfo(&lanAddr, NULL); + IPv4Address lanAddr(0); + socket->GetLocalInterfaceInfo(&lanAddr, NULL); CBufferOutputStream pkt(8); - pkt.WriteInt32(lanAddr.s_addr); - pkt.WriteInt32(localUdpPort); + pkt.WriteInt32(lanAddr.GetAddress()); + pkt.WriteInt32(socket->GetLocalPort()); SendPacketReliably(PKT_LAN_ENDPOINT, pkt.GetBuffer(), pkt.GetLength(), 0.5, 10); - }else{ - for(i=0;itype==EP_TYPE_UDP_P2P_LAN){ - free(endpoints[i]); - endpoints.erase(endpoints.begin()+i); - break; - } - } } - p2pPingCount=0; - lastP2pPingTime=0; - needSendP2pPing=true; + unlock_mutex(endpointsMutex); }else{ LOGE("It looks like a reflector response but tlid is %08X, expected %08X", tlid, TLID_UDP_REFLECTOR_PEER_INFO); } @@ -709,7 +658,7 @@ void CVoIPController::RunRecvThread(){ } unsigned char key[32], iv[32]; KDF(msgHash, isOutgoing ? 8 : 0, key, iv); - unsigned char aesOut[in->Remaining()]; + unsigned char aesOut[MSC_STACK_FALLBACK(in->Remaining(), 1024)]; crypto.aes_ige_decrypt((unsigned char *) buffer+in->GetOffset(), aesOut, in->Remaining(), key, iv); memcpy(buffer+in->GetOffset(), aesOut, in->Remaining()); unsigned char sha[SHA1_LENGTH]; @@ -751,7 +700,7 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA if(memcmp(pktCallID, callID, 16)!=0){ LOGW("Received packet has wrong call id"); delete in; - lastError=ERROR_UNKNOWN; + lastError=TGVOIP_ERROR_UNKNOWN; SetState(STATE_FAILED); return; } @@ -764,7 +713,7 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA if(proto!=PROTOCOL_NAME){ LOGW("Received packet uses wrong protocol"); delete in; - lastError=ERROR_INCOMPATIBLE; + lastError=TGVOIP_ERROR_INCOMPATIBLE; SetState(STATE_FAILED); return; } @@ -897,7 +846,7 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA LOGI("Peer version is %d", peerVersion); uint32_t minVer=(uint32_t) in->ReadInt32(); if(minVer>PROTOCOL_VERSION || peerVersionReadInt32(); uint32_t minVer=(uint32_t) in->ReadInt32(); if(minVer>PROTOCOL_VERSION || peerVersionStart(); if(!audioInput->IsInitialized()){ - lastError=ERROR_AUDIO_IO; + lastError=TGVOIP_ERROR_AUDIO_IO; delete in; SetState(STATE_FAILED); return; @@ -1015,11 +964,11 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA decoder->SetFrameDuration(incomingAudioStream->frameDuration); decoder->Start(); if(incomingAudioStream->frameDuration>50) - jitterBuffer->SetMinPacketCount(CVoIPServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_60", 3)); + jitterBuffer->SetMinPacketCount(ServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_60", 3)); else if(incomingAudioStream->frameDuration>30) - jitterBuffer->SetMinPacketCount(CVoIPServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_40", 4)); + jitterBuffer->SetMinPacketCount(ServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_40", 4)); else - jitterBuffer->SetMinPacketCount(CVoIPServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_20", 6)); + jitterBuffer->SetMinPacketCount(ServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_20", 6)); //audioOutput->Start(); #ifdef TGVOIP_USE_AUDIO_SESSION #ifdef __APPLE__ @@ -1075,7 +1024,7 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA } } if(type==PKT_PING){ - LOGD("Received ping from %s:%d", inet_ntoa(srcEndpoint->address), srcEndpoint->port); + LOGD("Received ping from %s:%d", packet.address->ToString().c_str(), srcEndpoint->port); if(srcEndpoint->type!=EP_TYPE_UDP_RELAY && !allowP2p){ LOGW("Received p2p ping but p2p is disabled by manual override"); delete in; @@ -1101,18 +1050,18 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA if(type==PKT_PONG){ if(packetInnerLen>=4){ uint32_t pingSeq=(uint32_t) in->ReadInt32(); - if(pingSeq==srcEndpoint->_lastPingSeq){ - memmove(&srcEndpoint->_rtts[1], srcEndpoint->_rtts, sizeof(double)*5); - srcEndpoint->_rtts[0]=GetCurrentTime()-srcEndpoint->_lastPingTime; + if(pingSeq==srcEndpoint->lastPingSeq){ + memmove(&srcEndpoint->rtts[1], srcEndpoint->rtts, sizeof(double)*5); + srcEndpoint->rtts[0]=GetCurrentTime()-srcEndpoint->lastPingTime; int i; - srcEndpoint->_averageRtt=0; + srcEndpoint->averageRTT=0; for(i=0;i<6;i++){ - if(srcEndpoint->_rtts[i]==0) + if(srcEndpoint->rtts[i]==0) break; - srcEndpoint->_averageRtt+=srcEndpoint->_rtts[i]; + srcEndpoint->averageRTT+=srcEndpoint->rtts[i]; } - srcEndpoint->_averageRtt/=i; - LOGD("Current RTT via %s: %.3llf, average: %.3llf", inet_ntoa(srcEndpoint->address), srcEndpoint->_rtts[0], srcEndpoint->_averageRtt); + srcEndpoint->averageRTT/=i; + LOGD("Current RTT via %s: %.3f, average: %.3f", packet.address->ToString().c_str(), srcEndpoint->rtts[0], srcEndpoint->averageRTT); } } /*if(currentEndpoint!=srcEndpoint && (srcEndpoint->type==EP_TYPE_UDP_P2P_INET || srcEndpoint->type==EP_TYPE_UDP_P2P_LAN)){ @@ -1134,17 +1083,22 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA } } if(type==PKT_LAN_ENDPOINT){ + LOGV("received lan endpoint"); uint32_t peerAddr=(uint32_t) in->ReadInt32(); uint16_t peerPort=(uint16_t) in->ReadInt32(); - voip_endpoint_t* p2pEndpoint=GetEndpointByType(EP_TYPE_UDP_P2P_LAN); - if(!p2pEndpoint){ - p2pEndpoint=(voip_endpoint_t *) malloc(sizeof(voip_endpoint_t)); - endpoints.push_back(p2pEndpoint); + lock_mutex(endpointsMutex); + for(std::vector::iterator itrtr=endpoints.begin();itrtr!=endpoints.end();++itrtr){ + if((*itrtr)->type==EP_TYPE_UDP_P2P_LAN){ + delete *itrtr; + endpoints.erase(itrtr); + break; + } } - memset(p2pEndpoint, 0, sizeof(voip_endpoint_t)); - p2pEndpoint->type=EP_TYPE_UDP_P2P_LAN; - p2pEndpoint->port=peerPort; - p2pEndpoint->address.s_addr=peerAddr;//ntohl(peerAddr); + IPv4Address v4addr(peerAddr); + IPv6Address v6addr("::0"); + unsigned char peerTag[16]; + endpoints.push_back(new Endpoint(0, peerPort, v4addr, v6addr, EP_TYPE_UDP_P2P_LAN, peerTag)); + unlock_mutex(endpointsMutex); } if(type==PKT_NETWORK_CHANGED){ currentEndpoint=preferredRelay; @@ -1157,7 +1111,7 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA UpdateAudioBitrate(); } } - if(type==PKT_SWITCH_PREF_RELAY){ + /*if(type==PKT_SWITCH_PREF_RELAY){ uint64_t relayId=(uint64_t) in->ReadInt64(); int i; for(i=0;itype==EP_TYPE_UDP_RELAY) currentEndpoint=preferredRelay; - } + }*/ /*if(type==PKT_SWITCH_TO_P2P && allowP2p){ voip_endpoint_t* p2p=GetEndpointByType(EP_TYPE_UDP_P2P_INET); if(p2p){ @@ -1198,7 +1152,7 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA LOGI("=== recv thread exiting ==="); } -void CVoIPController::RunSendThread(){ +void VoIPController::RunSendThread(){ while(runReceiver){ CBufferOutputStream* pkt=(CBufferOutputStream *) sendQueue->GetBlocking(); if(pkt){ @@ -1213,11 +1167,15 @@ void CVoIPController::RunSendThread(){ } -void CVoIPController::RunTickThread(){ +void VoIPController::RunTickThread(){ uint32_t tickCount=0; bool wasWaitingForAcks=false; while(runReceiver){ +#ifndef _WIN32 usleep(100000); +#else + Sleep(100); +#endif tickCount++; if(tickCount%5==0 && state==STATE_ESTABLISHED){ memmove(&rttHistory[1], rttHistory, 31*sizeof(double)); @@ -1369,27 +1327,29 @@ void CVoIPController::RunTickThread(){ jitterBuffer->Tick(); if(state==STATE_ESTABLISHED){ - voip_endpoint_t* minPingRelay=preferredRelay; - double minPing=preferredRelay->_averageRtt; - for(i=0;i_lastPingTime>=10){ - LOGV("Sending ping to %s", inet_ntoa(e->address)); + lock_mutex(endpointsMutex); + Endpoint* minPingRelay=preferredRelay; + double minPing=preferredRelay->averageRTT; + for(std::vector::iterator e=endpoints.begin();e!=endpoints.end();++e){ + Endpoint* endpoint=*e; + if(GetCurrentTime()-endpoint->lastPingTime>=10){ + LOGV("Sending ping to %s", endpoint->address.ToString().c_str()); CBufferOutputStream pkt(32); uint32_t seq=WritePacketHeader(&pkt, PKT_PING, 0); - e->_lastPingTime=GetCurrentTime(); - e->_lastPingSeq=seq; - SendPacket(pkt.GetBuffer(), pkt.GetLength(), e); + endpoint->lastPingTime=GetCurrentTime(); + endpoint->lastPingSeq=seq; + SendPacket(pkt.GetBuffer(), pkt.GetLength(), endpoint); } - if(e->type==EP_TYPE_UDP_RELAY){ - if(e->_averageRtt>0 && e->_averageRtt_averageRtt; - minPingRelay=e; + if(endpoint->type==EP_TYPE_UDP_RELAY){ + if(endpoint->averageRTT>0 && endpoint->averageRTTaverageRTT; + minPingRelay=endpoint; } } } if(minPingRelay!=preferredRelay){ preferredRelay=minPingRelay; + LOGV("set preferred relay to %s", preferredRelay->address.ToString().c_str()); if(currentEndpoint->type==EP_TYPE_UDP_RELAY) currentEndpoint=preferredRelay; LogDebugInfo(); @@ -1398,16 +1358,16 @@ void CVoIPController::RunTickThread(){ SendPacketReliably(PKT_SWITCH_PREF_RELAY, pkt.GetBuffer(), pkt.GetLength(), 1, 9);*/ } if(currentEndpoint->type==EP_TYPE_UDP_RELAY){ - voip_endpoint_t *p2p=GetEndpointByType(EP_TYPE_UDP_P2P_INET); + Endpoint* p2p=GetEndpointByType(EP_TYPE_UDP_P2P_INET); if(p2p){ - voip_endpoint_t *lan=GetEndpointByType(EP_TYPE_UDP_P2P_LAN); - if(lan && lan->_averageRtt>0 && lan->_averageRttaverageRTT>0 && lan->averageRTT_averageRtt>0 && p2p->_averageRttaverageRTT>0 && p2p->averageRTT0 && minPing_averageRtt*p2pToRelaySwitchThreshold){ + if(minPing>0 && minPingaverageRTT*p2pToRelaySwitchThreshold){ LOGI("Switching to relay"); currentEndpoint=preferredRelay; LogDebugInfo(); } } + unlock_mutex(endpointsMutex); } if(state==STATE_ESTABLISHED){ @@ -1429,10 +1390,11 @@ void CVoIPController::RunTickThread(){ if(currentEndpoint && currentEndpoint->type!=EP_TYPE_UDP_RELAY){ LOGW("Packet receive timeout, switching to relay"); currentEndpoint=preferredRelay; - for(i=0;itype==EP_TYPE_UDP_P2P_INET || endpoints[i]->type==EP_TYPE_UDP_P2P_LAN){ - endpoints[i]->_averageRtt=0; - memset(endpoints[i]->_rtts, 0, sizeof(endpoints[i]->_rtts)); + for(std::vector::iterator itrtr=endpoints.begin();itrtr!=endpoints.end();++itrtr){ + Endpoint* e=*itrtr; + if(e->type==EP_TYPE_UDP_P2P_INET || e->type==EP_TYPE_UDP_P2P_LAN){ + e->averageRTT=0; + memset(e->rtts, 0, sizeof(e->rtts)); } } if(allowP2p){ @@ -1446,14 +1408,14 @@ void CVoIPController::RunTickThread(){ lastRecvPacketTime=GetCurrentTime(); }else{ LOGW("Packet receive timeout, disconnecting"); - lastError=ERROR_TIMEOUT; + lastError=TGVOIP_ERROR_TIMEOUT; SetState(STATE_FAILED); } } }else if(state==STATE_WAIT_INIT){ if(GetCurrentTime()-connectionInitTime>=config.init_timeout){ LOGW("Init timeout, disconnecting"); - lastError=ERROR_TIMEOUT; + lastError=TGVOIP_ERROR_TIMEOUT; SetState(STATE_FAILED); } } @@ -1469,22 +1431,21 @@ void CVoIPController::RunTickThread(){ } -voip_endpoint_t *CVoIPController::GetRemoteEndpoint(){ +Endpoint& VoIPController::GetRemoteEndpoint(){ //return useLan ? &remoteLanEp : &remotePublicEp; - return currentEndpoint; + return *currentEndpoint; } -void CVoIPController::SendPacket(unsigned char *data, size_t len, voip_endpoint_t* ep){ +void VoIPController::SendPacket(unsigned char *data, size_t len, Endpoint* ep){ if(stopping) return; - sockaddr_in6 dst(MakeInetAddress(ep->address, ep->port)); //dst.sin_addr=ep->address; //dst.sin_port=htons(ep->port); //dst.sin_family=AF_INET; CBufferOutputStream out(len+128); if(ep->type==EP_TYPE_UDP_RELAY) - out.WriteBytes(ep->peerTag, 16); + out.WriteBytes((unsigned char*)ep->peerTag, 16); else out.WriteBytes(callID, 16); if(len>0){ @@ -1493,7 +1454,7 @@ void CVoIPController::SendPacket(unsigned char *data, size_t len, voip_endpoint_ inner.WriteBytes(data, len); if(inner.GetLength()%16!=0){ size_t padLen=16-inner.GetLength()%16; - unsigned char padding[padLen]; + unsigned char padding[16]; crypto.rand_bytes((uint8_t *) padding, padLen); inner.WriteBytes(padding, padLen); } @@ -1503,50 +1464,47 @@ void CVoIPController::SendPacket(unsigned char *data, size_t len, voip_endpoint_ out.WriteBytes(keyFingerprint, 8); out.WriteBytes((msgHash+(SHA1_LENGTH-16)), 16); KDF(msgHash+(SHA1_LENGTH-16), isOutgoing ? 0 : 8, key, iv); - unsigned char aesOut[inner.GetLength()]; + unsigned char aesOut[MSC_STACK_FALLBACK(inner.GetLength(), 1024)]; crypto.aes_ige_encrypt(inner.GetBuffer(), aesOut, inner.GetLength(), key, iv); out.WriteBytes(aesOut, inner.GetLength()); } - //LOGV("Sending %d bytes to %s:%d", out.GetLength(), inet_ntoa(ep->address), ep->port); + //LOGV("Sending %d bytes to %s:%d", out.GetLength(), ep->address.ToString().c_str(), ep->port); if(IS_MOBILE_NETWORK(networkType)) stats.bytesSentMobile+=(uint64_t)out.GetLength(); else stats.bytesSentWifi+=(uint64_t)out.GetLength(); - int res=sendto(udpSocket, out.GetBuffer(), out.GetLength(), 0, (const sockaddr *) &dst, sizeof(dst)); - if(res<0){ - LOGE("error sending: %d / %s", errno, strerror(errno)); - if(errno==ENETUNREACH && !isV4Available && GetCurrentTime()address; + pkt.port=ep->port; + pkt.length=out.GetLength(); + pkt.data=out.GetBuffer(); + socket->Send(&pkt); } -void CVoIPController::SetNetworkType(int type){ +void VoIPController::SetNetworkType(int type){ networkType=type; UpdateDataSavingState(); UpdateAudioBitrate(); - char itfName[32]; - GetLocalNetworkItfInfo(NULL, itfName); - if(strcmp(itfName, activeNetItfName)!=0){ - needUpdateNat64Prefix=true; - isV4Available=false; - switchToV6at=GetCurrentTime()+ipv6Timeout; - LOGI("Active network interface changed: %s -> %s", activeNetItfName, itfName); - bool isFirstChange=strlen(activeNetItfName)==0; - strcpy(activeNetItfName, itfName); + std::string itfName=socket->GetLocalInterfaceInfo(NULL, NULL); + if(itfName!=activeNetItfName){ + socket->OnActiveInterfaceChanged(); + LOGI("Active network interface changed: %s -> %s", activeNetItfName.c_str(), itfName.c_str()); + bool isFirstChange=activeNetItfName.length()==0; + activeNetItfName=itfName; if(isFirstChange) return; if(currentEndpoint && currentEndpoint->type!=EP_TYPE_UDP_RELAY){ currentEndpoint=preferredRelay; - for(std::vector::iterator itr=endpoints.begin();itr!=endpoints.end();){ - if((*itr)->type==EP_TYPE_UDP_P2P_INET){ - (*itr)->_averageRtt=0; - memset((*itr)->_rtts, 0, sizeof((*itr)->_rtts)); + for(std::vector::iterator itr=endpoints.begin();itr!=endpoints.end();){ + Endpoint* endpoint=*itr; + if(endpoint->type==EP_TYPE_UDP_P2P_INET){ + endpoint->averageRTT=0; + memset(endpoint->rtts, 0, sizeof(endpoint->rtts)); } - if((*itr)->type==EP_TYPE_UDP_P2P_LAN){ - free((*itr)); + if(endpoint->type==EP_TYPE_UDP_P2P_LAN){ + delete endpoint; itr=endpoints.erase(itr); }else{ ++itr; @@ -1560,7 +1518,7 @@ void CVoIPController::SetNetworkType(int type){ s.WriteInt32(dataSavingMode ? INIT_FLAG_DATA_SAVING_ENABLED : 0); SendPacketReliably(PKT_NETWORK_CHANGED, s.GetBuffer(), s.GetLength(), 1, 20); } - LOGI("set network type: %d, active interface %s", type, activeNetItfName); + LOGI("set network type: %d, active interface %s", type, activeNetItfName.c_str()); /*if(type==NET_TYPE_GPRS || type==NET_TYPE_EDGE) audioPacketGrouping=2; else @@ -1568,7 +1526,7 @@ void CVoIPController::SetNetworkType(int type){ } -double CVoIPController::GetAverageRTT(){ +double VoIPController::GetAverageRTT(){ if(lastSentSeq>=lastRemoteAckSeq){ uint32_t diff=lastSentSeq-lastRemoteAckSeq; //LOGV("rtt diff=%u", diff); @@ -1594,13 +1552,13 @@ double CVoIPController::GetAverageRTT(){ static void initMachTimestart() { mach_timebase_info_data_t tb = { 0, 0 }; mach_timebase_info(&tb); - CVoIPController::machTimebase = tb.numer; - CVoIPController::machTimebase /= tb.denom; - CVoIPController::machTimestart = mach_absolute_time(); + VoIPController::machTimebase = tb.numer; + VoIPController::machTimebase /= tb.denom; + VoIPController::machTimestart = mach_absolute_time(); } #endif -double CVoIPController::GetCurrentTime(){ +double VoIPController::GetCurrentTime(){ #if defined(__linux__) struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); @@ -1609,10 +1567,20 @@ double CVoIPController::GetCurrentTime(){ static pthread_once_t token = PTHREAD_ONCE_INIT; pthread_once(&token, &initMachTimestart); return (mach_absolute_time() - machTimestart) * machTimebase / 1000000000.0f; +#elif defined(_WIN32) + if(!didInitWin32TimeScale){ + LARGE_INTEGER scale; + QueryPerformanceFrequency(&scale); + win32TimeScale=scale.QuadPart; + didInitWin32TimeScale=true; + } + LARGE_INTEGER t; + QueryPerformanceCounter(&t); + return (double)t.QuadPart/(double)win32TimeScale; #endif } -void CVoIPController::SetStateCallback(void (* f)(CVoIPController*, int)){ +void VoIPController::SetStateCallback(void (* f)(VoIPController*, int)){ stateCallback=f; if(stateCallback){ stateCallback(this, state); @@ -1620,7 +1588,7 @@ void CVoIPController::SetStateCallback(void (* f)(CVoIPController*, int)){ } -void CVoIPController::SetState(int state){ +void VoIPController::SetState(int state){ this->state=state; stateChangeTime=GetCurrentTime(); if(stateCallback){ @@ -1629,7 +1597,7 @@ void CVoIPController::SetState(int state){ } -void CVoIPController::SetMicMute(bool mute){ +void VoIPController::SetMicMute(bool mute){ micMuted=mute; if(audioInput){ if(mute) @@ -1637,7 +1605,7 @@ void CVoIPController::SetMicMute(bool mute){ else audioInput->Start(); if(!audioInput->IsInitialized()){ - lastError=ERROR_AUDIO_IO; + lastError=TGVOIP_ERROR_AUDIO_IO; SetState(STATE_FAILED); return; } @@ -1657,7 +1625,7 @@ void CVoIPController::SetMicMute(bool mute){ } -void CVoIPController::UpdateAudioOutputState(){ +void VoIPController::UpdateAudioOutputState(){ bool areAnyAudioStreamsEnabled=false; int i; for(i=0;i0){ @@ -1693,7 +1661,7 @@ CBufferOutputStream *CVoIPController::GetOutgoingPacketBuffer(){ } -void CVoIPController::KDF(unsigned char* msgKey, size_t x, unsigned char* aesKey, unsigned char* aesIv){ +void VoIPController::KDF(unsigned char* msgKey, size_t x, unsigned char* aesKey, unsigned char* aesIv){ uint8_t sA[SHA1_LENGTH], sB[SHA1_LENGTH], sC[SHA1_LENGTH], sD[SHA1_LENGTH]; CBufferOutputStream buf(128); buf.WriteBytes(msgKey, 16); @@ -1727,13 +1695,14 @@ void CVoIPController::KDF(unsigned char* msgKey, size_t x, unsigned char* aesKey memcpy(aesIv, buf.GetBuffer(), 32); } -void CVoIPController::GetDebugString(char *buffer, size_t len){ +void VoIPController::GetDebugString(char *buffer, size_t len){ char endpointsBuf[10240]; memset(endpointsBuf, 0, 10240); int i; - for(i=0;i::iterator itrtr=endpoints.begin();itrtr!=endpoints.end();++itrtr){ const char* type; - switch(endpoints[i]->type){ + Endpoint* endpoint=*itrtr; + switch(endpoint->type){ case EP_TYPE_UDP_P2P_INET: type="UDP_P2P_INET"; break; @@ -1752,7 +1721,7 @@ void CVoIPController::GetDebugString(char *buffer, size_t len){ } if(strlen(endpointsBuf)>10240-1024) break; - sprintf(endpointsBuf+strlen(endpointsBuf), "%s:%u %dms [%s%s]\n", inet_ntoa(endpoints[i]->address), endpoints[i]->port, (int)(endpoints[i]->_averageRtt*1000), type, currentEndpoint==endpoints[i] ? ", IN_USE" : ""); + sprintf(endpointsBuf+strlen(endpointsBuf), "%s:%u %dms [%s%s]\n", endpoint->address.ToString().c_str(), endpoint->port, (int)(endpoint->averageRTT*1000), type, currentEndpoint==endpoint ? ", IN_USE" : ""); } double avgLate[3]; if(jitterBuffer) @@ -1787,99 +1756,43 @@ void CVoIPController::GetDebugString(char *buffer, size_t len){ } -void CVoIPController::SendPublicEndpointsRequest(){ +void VoIPController::SendPublicEndpointsRequest(){ LOGI("Sending public endpoints request"); if(preferredRelay){ - SendPublicEndpointsRequest(preferredRelay); + SendPublicEndpointsRequest(*preferredRelay); } if(peerPreferredRelay && peerPreferredRelay!=preferredRelay){ - SendPublicEndpointsRequest(peerPreferredRelay); + SendPublicEndpointsRequest(*peerPreferredRelay); } } -void CVoIPController::SendPublicEndpointsRequest(voip_endpoint_t *relay){ +void VoIPController::SendPublicEndpointsRequest(Endpoint& relay){ + LOGD("Sending public endpoints request to %s:%d", relay.address.ToString().c_str(), relay.port); publicEndpointsReqTime=GetCurrentTime(); waitingForRelayPeerInfo=true; - char buf[32]; - memcpy(buf, relay->peerTag, 16); + unsigned char buf[32]; + memcpy(buf, relay.peerTag, 16); memset(buf+16, 0xFF, 16); - sockaddr_in6 dst(MakeInetAddress(relay->address, relay->port)); - int res=sendto(udpSocket, buf, 32, 0, (const sockaddr *) &dst, sizeof(dst)); - if(res<0){ - LOGE("error sending: %d / %s", errno, strerror(errno)); - } + NetworkPacket pkt; + pkt.data=buf; + pkt.length=32; + pkt.address=(NetworkAddress*)&relay.address; + pkt.port=relay.port; + socket->Send(&pkt); } - -void CVoIPController::SendP2pPing(int endpointType){ - LOGD("Sending ping for p2p, endpoint type %d", endpointType); - voip_endpoint_t* endpoint=GetEndpointByType(endpointType); - if(!endpoint) - return; - lastP2pPingTime=GetCurrentTime(); - CBufferOutputStream pkt(32); - uint32_t seq=WritePacketHeader(&pkt, PKT_PING, 0); - SendPacket(pkt.GetBuffer(), pkt.GetLength(), endpoint); -} - - -void CVoIPController::GetLocalNetworkItfInfo(in_addr *outAddr, char *outName){ - struct ifconf ifc; - struct ifreq* ifr; - char buf[16384]; - int sd; - sd=socket(PF_INET, SOCK_DGRAM, 0); - if(sd>0){ - ifc.ifc_len=sizeof(buf); - ifc.ifc_ifcu.ifcu_buf=buf; - if(ioctl(sd, SIOCGIFCONF, &ifc)==0){ - ifr=ifc.ifc_req; - int len; - int i; - for(i=0;iifr_addr.sa_len; -#else - len=sizeof(*ifr); -#endif - if(ifr->ifr_addr.sa_family==AF_INET){ - if(ioctl(sd, SIOCGIFADDR, ifr)==0){ - struct sockaddr_in* addr=(struct sockaddr_in *)(&ifr->ifr_addr); - LOGI("Interface %s, address %s\n", ifr->ifr_name, inet_ntoa(addr->sin_addr)); - if(strcmp(ifr->ifr_name, "lo0")!=0 && strcmp(ifr->ifr_name, "lo")!=0 && addr->sin_addr.s_addr!=inet_addr("127.0.0.1")){ - if(outAddr) - memcpy(outAddr, &addr->sin_addr, sizeof(in_addr)); - if(outName) - strcpy(outName, ifr->ifr_name); - } - }else{ - LOGE("Error getting address for %s: %d\n", ifr->ifr_name, errno); - } - } - ifr=(struct ifreq*)((char*)ifr+len); - i+=len; - } - }else{ - LOGE("Error getting LAN address: %d", errno); - } - } - close(sd); -} - - -voip_endpoint_t *CVoIPController::GetEndpointByType(int type){ +Endpoint* VoIPController::GetEndpointByType(int type){ if(type==EP_TYPE_UDP_RELAY && preferredRelay) return preferredRelay; - int i; - for(i=0;itype==type) - return endpoints[i]; + for(std::vector::iterator itrtr=endpoints.begin();itrtr!=endpoints.end();++itrtr){ + if((*itrtr)->type==type) + return *itrtr; } return NULL; } -float CVoIPController::GetOutputLevel(){ +float VoIPController::GetOutputLevel(){ if(!audioOutput || !audioOutStarted){ return 0.0; } @@ -1887,8 +1800,8 @@ float CVoIPController::GetOutputLevel(){ } -void CVoIPController::SendPacketReliably(unsigned char type, unsigned char *data, size_t len, double retryInterval, double timeout){ - LOGD("Send reliably, type=%u, len=%u, retry=%.3llf, timeout=%.3llf", type, len, retryInterval, timeout); +void VoIPController::SendPacketReliably(unsigned char type, unsigned char *data, size_t len, double retryInterval, double timeout){ + LOGD("Send reliably, type=%u, len=%u, retry=%.3f, timeout=%.3f", type, len, retryInterval, timeout); voip_queued_packet_t* pkt=(voip_queued_packet_t *) malloc(sizeof(voip_queued_packet_t)); memset(pkt, 0, sizeof(voip_queued_packet_t)); pkt->type=type; @@ -1907,7 +1820,7 @@ void CVoIPController::SendPacketReliably(unsigned char type, unsigned char *data } -void CVoIPController::SetConfig(voip_config_t *cfg){ +void VoIPController::SetConfig(voip_config_t *cfg){ memcpy(&config, cfg, sizeof(voip_config_t)); if(tgvoipLogFile){ fclose(tgvoipLogFile); @@ -1919,7 +1832,7 @@ void CVoIPController::SetConfig(voip_config_t *cfg){ } -void CVoIPController::UpdateDataSavingState(){ +void VoIPController::UpdateDataSavingState(){ if(config.data_saving==DATA_SAVING_ALWAYS){ dataSavingMode=true; }else if(config.data_saving==DATA_SAVING_MOBILE){ @@ -1932,7 +1845,7 @@ void CVoIPController::UpdateDataSavingState(){ } -void CVoIPController::DebugCtl(int request, int param){ +void VoIPController::DebugCtl(int request, int param){ if(request==1){ // set bitrate maxBitrate=param; if(encoder){ @@ -1946,7 +1859,6 @@ void CVoIPController::DebugCtl(int request, int param){ allowP2p=param==1; if(!allowP2p && currentEndpoint && currentEndpoint->type!=EP_TYPE_UDP_RELAY){ currentEndpoint=preferredRelay; - needSendP2pPing=false; }else if(allowP2p){ SendPublicEndpointsRequest(); } @@ -1960,48 +1872,41 @@ void CVoIPController::DebugCtl(int request, int param){ } -const char* CVoIPController::GetVersion(){ +const char* VoIPController::GetVersion(){ return LIBTGVOIP_VERSION; } -int64_t CVoIPController::GetPreferredRelayID(){ +int64_t VoIPController::GetPreferredRelayID(){ if(preferredRelay) return preferredRelay->id; return 0; } -int CVoIPController::GetLastError(){ +int VoIPController::GetLastError(){ return lastError; } -void CVoIPController::GetStats(voip_stats_t *stats){ +void VoIPController::GetStats(voip_stats_t *stats){ memcpy(stats, &this->stats, sizeof(voip_stats_t)); } - -uint16_t CVoIPController::GenerateLocalUDPPort(){ - uint16_t rnd; - crypto.rand_bytes((uint8_t *) &rnd, 2); - return (uint16_t) ((rnd%(MAX_UDP_PORT-MIN_UDP_PORT))+MIN_UDP_PORT); -} - #ifdef TGVOIP_USE_AUDIO_SESSION -void CVoIPController::SetAcquireAudioSession(void (^completion)(void (^)())) { +void VoIPController::SetAcquireAudioSession(void (^completion)(void (^)())) { this->acquireAudioSession = [completion copy]; } -void CVoIPController::ReleaseAudioSession(void (^completion)()) { +void VoIPController::ReleaseAudioSession(void (^completion)()) { completion(); } #endif -void CVoIPController::LogDebugInfo(){ +void VoIPController::LogDebugInfo(){ std::string json="{\"endpoints\":["; - for(std::vector::iterator itr=endpoints.begin();itr!=endpoints.end();++itr){ - voip_endpoint_t* e=*itr; + for(std::vector::iterator itr=endpoints.begin();itr!=endpoints.end();++itr){ + Endpoint* e=*itr; char buffer[1024]; const char* typeStr="unknown"; switch(e->type){ @@ -2015,9 +1920,9 @@ void CVoIPController::LogDebugInfo(){ typeStr="udp_p2p_lan"; break; } - snprintf(buffer, 1024, "{\"address\":\"%s\",\"port\":%u,\"type\":\"%s\",\"rtt\":%u%s%s}", inet_ntoa(e->address), e->port, typeStr, (unsigned int)round(e->_averageRtt*1000), currentEndpoint==e ? ",\"in_use\":true" : "", preferredRelay==e ? ",\"preferred\":true" : ""); + snprintf(buffer, 1024, "{\"address\":\"%s\",\"port\":%u,\"type\":\"%s\",\"rtt\":%u%s%s}", e->address.ToString().c_str(), e->port, typeStr, (unsigned int)round(e->averageRTT*1000), currentEndpoint==&*e ? ",\"in_use\":true" : "", preferredRelay==&*e ? ",\"preferred\":true" : ""); json+=buffer; - if(std::next(itr)!=endpoints.end()) + if(itr!=endpoints.end()-1) json+=","; } json+="],"; @@ -2066,23 +1971,23 @@ void CVoIPController::LogDebugInfo(){ debugLogs.push_back(json); } -std::string CVoIPController::GetDebugLog(){ +std::string VoIPController::GetDebugLog(){ std::string log="{\"events\":["; for(std::vector::iterator itr=debugLogs.begin();itr!=debugLogs.end();++itr){ log+=(*itr); - if(std::next(itr)!=debugLogs.end()) + if((itr+1)!=debugLogs.end()) log+=","; } log+="],\"libtgvoip_version\":\"" LIBTGVOIP_VERSION "\"}"; return log; } -void CVoIPController::GetDebugLog(char *buffer){ +void VoIPController::GetDebugLog(char *buffer){ strcpy(buffer, GetDebugLog().c_str()); } -size_t CVoIPController::GetDebugLogLength(){ +size_t VoIPController::GetDebugLogLength(){ size_t len=128; for(std::vector::iterator itr=debugLogs.begin();itr!=debugLogs.end();++itr){ len+=(*itr).length()+1; @@ -2090,55 +1995,32 @@ size_t CVoIPController::GetDebugLogLength(){ return len; } +Endpoint::Endpoint(int64_t id, uint16_t port, IPv4Address& _address, IPv6Address& _v6address, char type, unsigned char peerTag[16]) : address(_address), v6address(_v6address){ + this->id=id; + this->port=port; + this->type=type; + memcpy(this->peerTag, peerTag, 16); + LOGV("new endpoint %lld: %s:%u", id, address.ToString().c_str(), port); -sockaddr_in6 CVoIPController::MakeInetAddress(in_addr addr, uint16_t port){ - // TODO: refactor the hell out of this by at least moving sockets to a separate class - if(needUpdateNat64Prefix && !isV4Available && GetCurrentTime()>switchToV6at && switchToV6at!=0){ - LOGV("Updating NAT64 prefix"); - nat64Present=false; - addrinfo* addr0; - int res=getaddrinfo("ipv4only.arpa", NULL, NULL, &addr0); - if(res!=0){ - LOGW("Error updating NAT64 prefix: %d / %s", res, gai_strerror(res)); - }else{ - addrinfo* addrPtr; - unsigned char* addr170=NULL; - unsigned char* addr171=NULL; - for(addrPtr=addr0;addrPtr;addrPtr=addrPtr->ai_next){ - if(addrPtr->ai_family==AF_INET6){ - sockaddr_in6* translatedAddr=(sockaddr_in6*)addrPtr->ai_addr; - uint32_t v4part=*((uint32_t*)&translatedAddr->sin6_addr.s6_addr[12]); - if(v4part==0xAA0000C0 && !addr170){ - addr170=translatedAddr->sin6_addr.s6_addr; - } - if(v4part==0xAB0000C0 && !addr171){ - addr171=translatedAddr->sin6_addr.s6_addr; - } - char buf[INET6_ADDRSTRLEN]; - LOGV("Got translated address: %s", inet_ntop(AF_INET6, &translatedAddr->sin6_addr, buf, sizeof(buf))); - } - } - if(addr170 && addr171 && memcmp(addr170, addr171, 12)==0){ - nat64Present=true; - memcpy(nat64Prefix, addr170, 12); - char buf[INET6_ADDRSTRLEN]; - LOGV("Found nat64 prefix from %s", inet_ntop(AF_INET6, addr170, buf, sizeof(buf))); - }else{ - LOGV("Didn't find nat64"); - } - freeaddrinfo(addr0); - } - needUpdateNat64Prefix=false; - } - sockaddr_in6 r; - memset(&r, 0, sizeof(sockaddr_in6)); - r.sin6_port=htons(port); - r.sin6_family=AF_INET6; - *((in_addr*)&r.sin6_addr.s6_addr[12])=addr; - if(nat64Present) - memcpy(r.sin6_addr.s6_addr, nat64Prefix, 12); - else - r.sin6_addr.s6_addr[11]=r.sin6_addr.s6_addr[10]=0xFF; - //r.sin6_len=sizeof(sa_family_t); - return r; + lastPingSeq=0; + lastPingTime=0; + averageRTT=0; + memset(rtts, 0, sizeof(rtts)); } + +Endpoint::Endpoint() : address(0), v6address("::0") { + +} + +#if defined(__APPLE__) && TARGET_OS_IPHONE +void VoIPController::SetRemoteEndpoints(voip_legacy_endpoint_t* buffer, size_t count, bool allowP2P){ + std::vector endpoints; + for(size_t i=0;iSetRemoteEndpoints(endpoints, allowP2P); +} +#endif diff --git a/VoIPController.h b/VoIPController.h index 5ed255c4d3..910eaaef17 100644 --- a/VoIPController.h +++ b/VoIPController.h @@ -1,8 +1,19 @@ +// +// 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 __VOIPCONTROLLER_H #define __VOIPCONTROLLER_H +#ifndef _WIN32 #include #include +#endif +#ifdef __APPLE__ +#include +#endif #include #include #include @@ -16,8 +27,9 @@ #include "OpusEncoder.h" #include "EchoCanceller.h" #include "CongestionControl.h" +#include "NetworkSocket.h" -#define LIBTGVOIP_VERSION "0.3.2" +#define LIBTGVOIP_VERSION "0.4" #define PKT_INIT 1 #define PKT_INIT_ACK 2 @@ -39,10 +51,10 @@ #define STATE_ESTABLISHED 3 #define STATE_FAILED 4 -#define ERROR_UNKNOWN 0 -#define ERROR_INCOMPATIBLE 1 -#define ERROR_TIMEOUT 2 -#define ERROR_AUDIO_IO 3 +#define TGVOIP_ERROR_UNKNOWN 0 +#define TGVOIP_ERROR_INCOMPATIBLE 1 +#define TGVOIP_ERROR_TIMEOUT 2 +#define TGVOIP_ERROR_AUDIO_IO 3 #define NET_TYPE_UNKNOWN 0 #define NET_TYPE_GPRS 1 @@ -62,8 +74,6 @@ #define PROTOCOL_NAME 0x50567247 // "GrVP" in little endian (reversed here) #define PROTOCOL_VERSION 3 #define MIN_PROTOCOL_VERSION 3 -#define MIN_UDP_PORT 16384 -#define MAX_UDP_PORT 32768 #define STREAM_DATA_FLAG_LEN16 0x40 #define STREAM_DATA_FLAG_HAS_MORE_FLAGS 0x80 @@ -98,6 +108,10 @@ #define TLID_UDP_REFLECTOR_PEER_INFO 0x27D9371C #define PAD4(x) (4-(x+(x<=253 ? 1 : 0))%4) +#ifdef _WIN32 +#undef GetCurrentTime +#endif + inline int pad4(int x){ int r=PAD4(x); if(r==4) @@ -105,21 +119,6 @@ inline int pad4(int x){ return r; } -struct voip_endpoint_t{ // make this a class maybe? - int64_t id; - uint32_t port; - in_addr address; - in6_addr address6; - char type; - unsigned char peerTag[16]; - - double _lastPingTime; - uint32_t _lastPingSeq; - double _rtts[6]; - double _averageRtt; -}; -typedef struct voip_endpoint_t voip_endpoint_t; - struct voip_stream_t{ int32_t userID; unsigned char id; @@ -154,6 +153,18 @@ struct voip_config_t{ }; typedef struct voip_config_t voip_config_t; +#if defined(__APPLE__) && TARGET_OS_IPHONE +// temporary fix for nasty linking errors +struct voip_legacy_endpoint_t{ + const char* address; + const char* address6; + uint16_t port; + int64_t id; + unsigned char peerTag[16]; +}; +typedef struct voip_legacy_endpoint_t voip_legacy_endpoint_t; +#endif + struct voip_stats_t{ uint64_t bytesSentWifi; uint64_t bytesRecvdWifi; @@ -177,20 +188,41 @@ inline bool seqgt(uint32_t s1, uint32_t s2){ return ((s1>s2) && (s1-s2<=SEQ_MAX/2)) || ((s1SEQ_MAX/2)); } -class CVoIPController +namespace tgvoip{ + +class Endpoint{ + friend class VoIPController; +public: + Endpoint(int64_t id, uint16_t port, IPv4Address& address, IPv6Address& v6address, char type, unsigned char* peerTag); + Endpoint(); + int64_t id; + uint16_t port; + IPv4Address address; + IPv6Address v6address; + char type; + unsigned char peerTag[16]; + +private: + double lastPingTime; + uint32_t lastPingSeq; + double rtts[6]; + double averageRTT; +}; + +class VoIPController { public: - CVoIPController(); - ~CVoIPController(); + VoIPController(); + ~VoIPController(); - void SetRemoteEndpoints(voip_endpoint_t* endpoints, size_t count, bool allowP2p); + void SetRemoteEndpoints(std::vector endpoints, bool allowP2p); void Start(); void Connect(); - voip_endpoint_t* GetRemoteEndpoint(); + Endpoint& GetRemoteEndpoint(); void GetDebugString(char* buffer, size_t len); void SetNetworkType(int type); double GetAverageRTT(); - void SetStateCallback(void (*f)(CVoIPController*, int)); + void SetStateCallback(void (*f)(VoIPController*, int)); static double GetCurrentTime(); void* implData; void SetMicMute(bool mute); @@ -218,7 +250,7 @@ private: void RunRecvThread(); void RunSendThread(); void RunTickThread(); - void SendPacket(unsigned char* data, size_t len, voip_endpoint_t* ep); + void SendPacket(unsigned char* data, size_t len, Endpoint* ep); void HandleAudioInput(unsigned char* data, size_t len); void UpdateAudioBitrate(); void SetState(int state); @@ -226,25 +258,20 @@ private: void SendInit(); void SendInitAck(); void UpdateDataSavingState(); - void SendP2pPing(int endpointType); void KDF(unsigned char* msgKey, size_t x, unsigned char* aesKey, unsigned char* aesIv); - void GetLocalNetworkItfInfo(in_addr *addr, char *outName); - uint16_t GenerateLocalUDPPort(); CBufferOutputStream* GetOutgoingPacketBuffer(); uint32_t WritePacketHeader(CBufferOutputStream* s, unsigned char type, uint32_t length); static size_t AudioInputCallback(unsigned char* data, size_t length, void* param); void SendPublicEndpointsRequest(); - void SendPublicEndpointsRequest(voip_endpoint_t* relay); - voip_endpoint_t* GetEndpointByType(int type); + void SendPublicEndpointsRequest(Endpoint& relay); + Endpoint* GetEndpointByType(int type); void SendPacketReliably(unsigned char type, unsigned char* data, size_t len, double retryInterval, double timeout); void LogDebugInfo(); - sockaddr_in6 MakeInetAddress(in_addr addr, uint16_t port); int state; - int udpSocket; - std::vector endpoints; - voip_endpoint_t* currentEndpoint; - voip_endpoint_t* preferredRelay; - voip_endpoint_t* peerPreferredRelay; + std::vector endpoints; + Endpoint* currentEndpoint; + Endpoint* preferredRelay; + Endpoint* peerPreferredRelay; bool runReceiver; uint32_t seq; uint32_t lastRemoteSeq; @@ -265,6 +292,7 @@ private: CEchoCanceller* echoCanceller; std::vector emptySendBuffers; tgvoip_mutex_t sendBufferMutex; + tgvoip_mutex_t endpointsMutex; bool stopping; bool audioOutStarted; tgvoip_thread_t recvThread; @@ -284,23 +312,18 @@ private: bool micMuted; uint32_t maxBitrate; CBufferOutputStream* currentAudioPacket; - void (*stateCallback)(CVoIPController*, int); + void (*stateCallback)(VoIPController*, int); std::vector outgoingStreams; std::vector incomingStreams; unsigned char encryptionKey[256]; unsigned char keyFingerprint[8]; unsigned char callID[16]; double stateChangeTime; - bool needSendP2pPing; bool waitingForRelayPeerInfo; - double relayPeerInfoReqTime; - double lastP2pPingTime; - int p2pPingCount; - uint16_t localUdpPort; bool allowP2p; bool dataSavingMode; bool dataSavingRequestedByPeer; - char activeNetItfName[32]; + std::string activeNetItfName; double publicEndpointsReqTime; std::vector queuedPackets; tgvoip_mutex_t queuedPacketsMutex; @@ -314,13 +337,8 @@ private: bool receivedInitAck; std::vector debugLogs; bool isOutgoing; + tgvoip::NetworkSocket* socket; - unsigned char nat64Prefix[12]; - bool needUpdateNat64Prefix; - bool nat64Present; - double switchToV6at; - bool isV4Available; - /*** server config values ***/ uint32_t maxAudioBitrate; uint32_t maxAudioBitrateEDGE; @@ -336,18 +354,27 @@ private: double relaySwitchThreshold; double p2pToRelaySwitchThreshold; double relayToP2pSwitchThreshold; - double ipv6Timeout; #ifdef TGVOIP_USE_AUDIO_SESSION void (^acquireAudioSession)(void (^)()); bool needNotifyAcquiredAudioSession; #endif -#ifdef __APPLE__ public: +#ifdef __APPLE__ static double machTimebase; static uint64_t machTimestart; +#if TARGET_OS_IPHONE + // temporary fix for nasty linking errors + void SetRemoteEndpoints(voip_legacy_endpoint_t* buffer, size_t count, bool allowP2P); +#endif +#endif +#ifdef _WIN32 + static int64_t win32TimeScale; + static bool didInitWin32TimeScale; #endif }; +} + #endif diff --git a/VoIPServerConfig.cpp b/VoIPServerConfig.cpp index 9002d6b2c3..057f5c273c 100644 --- a/VoIPServerConfig.cpp +++ b/VoIPServerConfig.cpp @@ -8,23 +8,25 @@ #include #include "logging.h" -CVoIPServerConfig* CVoIPServerConfig::sharedInstance=NULL; +using namespace tgvoip; -CVoIPServerConfig::CVoIPServerConfig(){ +ServerConfig* ServerConfig::sharedInstance=NULL; + +ServerConfig::ServerConfig(){ init_mutex(mutex); } -CVoIPServerConfig::~CVoIPServerConfig(){ +ServerConfig::~ServerConfig(){ free_mutex(mutex); } -CVoIPServerConfig *CVoIPServerConfig::GetSharedInstance(){ +ServerConfig *ServerConfig::GetSharedInstance(){ if(!sharedInstance) - sharedInstance=new CVoIPServerConfig(); + sharedInstance=new ServerConfig(); return sharedInstance; } -bool CVoIPServerConfig::GetBoolean(std::string name, bool fallback){ +bool ServerConfig::GetBoolean(std::string name, bool fallback){ CMutexGuard sync(mutex); if(ContainsKey(name)){ std::string val=config[name]; @@ -36,7 +38,7 @@ bool CVoIPServerConfig::GetBoolean(std::string name, bool fallback){ return fallback; } -double CVoIPServerConfig::GetDouble(std::string name, double fallback){ +double ServerConfig::GetDouble(std::string name, double fallback){ CMutexGuard sync(mutex); if(ContainsKey(name)){ std::string val=config[name]; @@ -50,7 +52,7 @@ double CVoIPServerConfig::GetDouble(std::string name, double fallback){ return fallback; } -int32_t CVoIPServerConfig::GetInt(std::string name, int32_t fallback){ +int32_t ServerConfig::GetInt(std::string name, int32_t fallback){ CMutexGuard sync(mutex); if(ContainsKey(name)){ std::string val=config[name]; @@ -64,14 +66,14 @@ int32_t CVoIPServerConfig::GetInt(std::string name, int32_t fallback){ return fallback; } -std::string CVoIPServerConfig::GetString(std::string name, std::string fallback){ +std::string ServerConfig::GetString(std::string name, std::string fallback){ CMutexGuard sync(mutex); if(ContainsKey(name)) return config[name]; return fallback; } -void CVoIPServerConfig::Update(std::map newValues){ +void ServerConfig::Update(std::map newValues){ CMutexGuard sync(mutex); LOGD("=== Updating voip config ==="); config.clear(); @@ -83,7 +85,7 @@ void CVoIPServerConfig::Update(std::map newValues){ } } -void CVoIPServerConfig::Update(const char **values, int count) { +void ServerConfig::Update(const char **values, int count) { std::map result; for (int i = 0; i < count / 2; i++) { result[values[i * 2 + 0]] = std::string(values[i * 2 + 1]); @@ -92,7 +94,7 @@ void CVoIPServerConfig::Update(const char **values, int count) { } -bool CVoIPServerConfig::ContainsKey(std::string key){ +bool ServerConfig::ContainsKey(std::string key){ return config.find(key)!=config.end(); } diff --git a/VoIPServerConfig.h b/VoIPServerConfig.h index 9477e9f272..93bb1b8008 100644 --- a/VoIPServerConfig.h +++ b/VoIPServerConfig.h @@ -11,12 +11,13 @@ #include #include "threading.h" +namespace tgvoip{ -class CVoIPServerConfig{ +class ServerConfig{ public: - CVoIPServerConfig(); - ~CVoIPServerConfig(); - static CVoIPServerConfig* GetSharedInstance(); + ServerConfig(); + ~ServerConfig(); + static ServerConfig* GetSharedInstance(); int32_t GetInt(std::string name, int32_t fallback); double GetDouble(std::string name, double fallback); std::string GetString(std::string name, std::string fallback); @@ -25,11 +26,11 @@ public: void Update(const char **values, int count); private: - static CVoIPServerConfig* sharedInstance; + static ServerConfig* sharedInstance; bool ContainsKey(std::string key); std::map config; tgvoip_mutex_t mutex; }; - +} #endif //TGVOIP_VOIPSERVERCONFIG_H diff --git a/audio/AudioInput.cpp b/audio/AudioInput.cpp index d3fc22f733..6989c4fc22 100644 --- a/audio/AudioInput.cpp +++ b/audio/AudioInput.cpp @@ -14,6 +14,10 @@ #else #include "../os/darwin/AudioInputAudioUnitOSX.h" #endif +#elif defined(_WIN32) +#include "../os/windows/AudioInputWave.h" +#elif defined(__linux__) +#include "../os/linux/AudioInputALSA.h" #else #error "Unsupported operating system" #endif @@ -27,6 +31,10 @@ CAudioInput *CAudioInput::Create(){ return new CAudioInputAndroid(); #elif defined(__APPLE__) return new CAudioInputAudioUnit(); +#elif defined(_WIN32) + return new tgvoip::audio::AudioInputWave(); +#elif defined(__linux__) + return new tgvoip::audio::AudioInputALSA(); #endif } diff --git a/audio/AudioOutput.cpp b/audio/AudioOutput.cpp index 5250e838af..b13abb59d0 100644 --- a/audio/AudioOutput.cpp +++ b/audio/AudioOutput.cpp @@ -15,6 +15,10 @@ #else #include "../os/darwin/AudioOutputAudioUnitOSX.h" #endif +#elif defined(_WIN32) +#include "../os/windows/AudioOutputWave.h" +#elif defined(__linux__) +#include "../os/linux/AudioOutputALSA.h" #else #error "Unsupported operating system" #endif @@ -30,9 +34,16 @@ CAudioOutput *CAudioOutput::Create(){ return new CAudioOutputOpenSLES(); #elif defined(__APPLE__) return new CAudioOutputAudioUnit(); +#elif defined(_WIN32) + return new tgvoip::audio::AudioOutputWave(); +#elif defined(__linux__) + return new tgvoip::audio::AudioOutputALSA(); #endif } +CAudioOutput::CAudioOutput(){ + failed=false; +} CAudioOutput::~CAudioOutput(){ @@ -43,7 +54,7 @@ int32_t CAudioOutput::GetEstimatedDelay(){ #if defined(__ANDROID__) return systemVersion<21 ? 150 : 50; #endif - return 0; + return 60; } float CAudioOutput::GetLevel(){ diff --git a/audio/AudioOutput.h b/audio/AudioOutput.h index ec24ba7822..83b542ee9d 100644 --- a/audio/AudioOutput.h +++ b/audio/AudioOutput.h @@ -12,6 +12,7 @@ class CAudioOutput : public CMediaStreamItf{ public: + CAudioOutput(); virtual ~CAudioOutput(); virtual void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels)=0; virtual bool IsPlaying()=0; @@ -22,6 +23,9 @@ public: #if defined(__ANDROID__) static int systemVersion; #endif + +protected: + bool failed; }; diff --git a/client/android/tg_voip_jni.cpp b/client/android/tg_voip_jni.cpp index d24596c2e9..82321fc960 100644 --- a/client/android/tg_voip_jni.cpp +++ b/client/android/tg_voip_jni.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "../../VoIPController.h" #include "../../os/android/AudioOutputOpenSLES.h" @@ -26,7 +27,9 @@ struct impl_data_android_t{ jobject javaObject; }; -void updateConnectionState(CVoIPController* cntrlr, int state){ +using namespace tgvoip; + +void updateConnectionState(VoIPController* cntrlr, int state){ impl_data_android_t* impl=(impl_data_android_t*) cntrlr->implData; if(!impl->javaObject) return; @@ -70,29 +73,30 @@ extern "C" JNIEXPORT jlong Java_org_telegram_messenger_voip_VoIPController_nativ impl_data_android_t* impl=(impl_data_android_t*) malloc(sizeof(impl_data_android_t)); impl->javaObject=env->NewGlobalRef(thiz); - CVoIPController* cntrlr=new CVoIPController(); + VoIPController* cntrlr=new VoIPController(); cntrlr->implData=impl; cntrlr->SetStateCallback(updateConnectionState); return (jlong)(intptr_t)cntrlr; } extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_nativeStart(JNIEnv* env, jobject thiz, jlong inst){ - ((CVoIPController*)(intptr_t)inst)->Start(); + ((VoIPController*)(intptr_t)inst)->Start(); } extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_nativeConnect(JNIEnv* env, jobject thiz, jlong inst){ - ((CVoIPController*)(intptr_t)inst)->Connect(); + ((VoIPController*)(intptr_t)inst)->Connect(); } extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_nativeSetEncryptionKey(JNIEnv* env, jobject thiz, jlong inst, jbyteArray key, jboolean isOutgoing){ jbyte* akey=env->GetByteArrayElements(key, NULL); - ((CVoIPController*)(intptr_t)inst)->SetEncryptionKey((char *) akey, isOutgoing); + ((VoIPController*)(intptr_t)inst)->SetEncryptionKey((char *) akey, isOutgoing); env->ReleaseByteArrayElements(key, akey, JNI_ABORT); } extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_nativeSetRemoteEndpoints(JNIEnv* env, jobject thiz, jlong inst, jobjectArray endpoints, jboolean allowP2p){ size_t len=(size_t) env->GetArrayLength(endpoints); - voip_endpoint_t* eps=(voip_endpoint_t *) malloc(sizeof(voip_endpoint_t)*len); +// voip_endpoint_t* eps=(voip_endpoint_t *) malloc(sizeof(voip_endpoint_t)*len); + std::vector eps; /*public String ip; public String ipv6; public int port; @@ -111,25 +115,25 @@ extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_native jint port=env->GetIntField(endpoint, portFld); jlong id=env->GetLongField(endpoint, idFld); jbyteArray peerTag=(jbyteArray) env->GetObjectField(endpoint, peerTagFld); - eps[i].id=id; - eps[i].port=(uint32_t) port; const char* ipChars=env->GetStringUTFChars(ip, NULL); - inet_aton(ipChars, &eps[i].address); + std::string ipLiteral(ipChars); + IPv4Address v4addr(ipLiteral); + IPv6Address v6addr("::0"); env->ReleaseStringUTFChars(ip, ipChars); if(ipv6 && env->GetStringLength(ipv6)){ const char* ipv6Chars=env->GetStringUTFChars(ipv6, NULL); - inet_pton(AF_INET6, ipv6Chars, &eps[i].address6); + v6addr=IPv6Address(ipv6Chars); env->ReleaseStringUTFChars(ipv6, ipv6Chars); } + unsigned char pTag[16]; if(peerTag && env->GetArrayLength(peerTag)){ jbyte* peerTagBytes=env->GetByteArrayElements(peerTag, NULL); - memcpy(eps[i].peerTag, peerTagBytes, 16); + memcpy(pTag, peerTagBytes, 16); env->ReleaseByteArrayElements(peerTag, peerTagBytes, JNI_ABORT); } - eps[i].type=EP_TYPE_UDP_RELAY; + eps.push_back(Endpoint((int64_t)id, (uint16_t)port, v4addr, v6addr, EP_TYPE_UDP_RELAY, pTag)); } - ((CVoIPController*)(intptr_t)inst)->SetRemoteEndpoints(eps, len, allowP2p); - free(eps); + ((VoIPController*)(intptr_t)inst)->SetRemoteEndpoints(eps, allowP2p); } extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_nativeSetNativeBufferSize(JNIEnv* env, jclass thiz, jint size){ @@ -140,7 +144,7 @@ extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_native extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_nativeRelease(JNIEnv* env, jobject thiz, jlong inst){ //env->DeleteGlobalRef(CAudioInputAndroid::jniClass); - CVoIPController* ctlr=((CVoIPController*)(intptr_t)inst); + VoIPController* ctlr=((VoIPController*)(intptr_t)inst); impl_data_android_t* impl=(impl_data_android_t*)ctlr->implData; delete ctlr; env->DeleteGlobalRef(impl->javaObject); @@ -169,16 +173,16 @@ extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_AudioTrackJNI_nativeC extern "C" JNIEXPORT jstring Java_org_telegram_messenger_voip_VoIPController_nativeGetDebugString(JNIEnv* env, jobject thiz, jlong inst){ char buf[10240]; - ((CVoIPController*)(intptr_t)inst)->GetDebugString(buf, 10240); + ((VoIPController*)(intptr_t)inst)->GetDebugString(buf, 10240); return env->NewStringUTF(buf); } extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_nativeSetNetworkType(JNIEnv* env, jobject thiz, jlong inst, jint type){ - ((CVoIPController*)(intptr_t)inst)->SetNetworkType(type); + ((VoIPController*)(intptr_t)inst)->SetNetworkType(type); } extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_nativeSetMicMute(JNIEnv* env, jobject thiz, jlong inst, jboolean mute){ - ((CVoIPController*)(intptr_t)inst)->SetMicMute(mute); + ((VoIPController*)(intptr_t)inst)->SetMicMute(mute); } extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_nativeSetConfig(JNIEnv* env, jobject thiz, jlong inst, jdouble recvTimeout, jdouble initTimeout, jint dataSavingMode, jboolean enableAEC, jboolean enableNS, jboolean enableAGC, jstring logFilePath){ @@ -197,28 +201,28 @@ extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_native }else{ memset(cfg.logFilePath, 0, sizeof(cfg.logFilePath)); } - ((CVoIPController*)(intptr_t)inst)->SetConfig(&cfg); + ((VoIPController*)(intptr_t)inst)->SetConfig(&cfg); } extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_nativeDebugCtl(JNIEnv* env, jobject thiz, jlong inst, jint request, jint param){ - ((CVoIPController*)(intptr_t)inst)->DebugCtl(request, param); + ((VoIPController*)(intptr_t)inst)->DebugCtl(request, param); } extern "C" JNIEXPORT jstring Java_org_telegram_messenger_voip_VoIPController_nativeGetVersion(JNIEnv* env, jclass clasz){ - return env->NewStringUTF(CVoIPController::GetVersion()); + return env->NewStringUTF(VoIPController::GetVersion()); } extern "C" JNIEXPORT jlong Java_org_telegram_messenger_voip_VoIPController_nativeGetPreferredRelayID(JNIEnv* env, jclass clasz, jlong inst){ - return ((CVoIPController*)(intptr_t)inst)->GetPreferredRelayID(); + return ((VoIPController*)(intptr_t)inst)->GetPreferredRelayID(); } extern "C" JNIEXPORT jint Java_org_telegram_messenger_voip_VoIPController_nativeGetLastError(JNIEnv* env, jclass clasz, jlong inst){ - return ((CVoIPController*)(intptr_t)inst)->GetLastError(); + return ((VoIPController*)(intptr_t)inst)->GetLastError(); } extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_nativeGetStats(JNIEnv* env, jclass clasz, jlong inst, jobject stats){ voip_stats_t _stats; - ((CVoIPController*)(intptr_t)inst)->GetStats(&_stats); + ((VoIPController*)(intptr_t)inst)->GetStats(&_stats); jclass cls=env->GetObjectClass(stats); env->SetLongField(stats, env->GetFieldID(cls, "bytesSentWifi", "J"), _stats.bytesSentWifi); env->SetLongField(stats, env->GetFieldID(cls, "bytesSentMobile", "J"), _stats.bytesSentMobile); @@ -243,11 +247,11 @@ extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPServerConfig_nati env->ReleaseStringUTFChars(jval, cval); config[key]=val; } - CVoIPServerConfig::GetSharedInstance()->Update(config); + ServerConfig::GetSharedInstance()->Update(config); } extern "C" JNIEXPORT jstring Java_org_telegram_messenger_voip_VoIPController_nativeGetDebugLog(JNIEnv* env, jobject thiz, jlong inst){ - CVoIPController* ctlr=((CVoIPController*)(intptr_t)inst); + VoIPController* ctlr=((VoIPController*)(intptr_t)inst); std::string log=ctlr->GetDebugLog(); return env->NewStringUTF(log.c_str()); } diff --git a/libtgvoip.gyp b/libtgvoip.gyp new file mode 100644 index 0000000000..2c38aac265 --- /dev/null +++ b/libtgvoip.gyp @@ -0,0 +1,333 @@ +# GYP project file for TDesktop + +{ + 'targets': [ + { + 'target_name': 'libtgvoip', + 'type': 'static_library', + 'dependencies': [], + 'defines': [ + 'WEBRTC_APM_DEBUG_DUMP=0', + 'TGVOIP_USE_DESKTOP_DSP' + ], + 'variables': { + 'tgvoip_src_loc': '../../third_party/libtgvoip', + }, + 'include_dirs': [ + '<(tgvoip_src_loc)/webrtc_dsp', + '../../../Libraries/opus/include', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + '<(tgvoip_src_loc)', + ], + }, + 'export_dependent_settings': [], + 'sources': [ + '<(tgvoip_src_loc)/BlockingQueue.cpp', + '<(tgvoip_src_loc)/BlockingQueue.h', + '<(tgvoip_src_loc)/BufferInputStream.cpp', + '<(tgvoip_src_loc)/BufferInputStream.h', + '<(tgvoip_src_loc)/BufferOutputStream.cpp', + '<(tgvoip_src_loc)/BufferOutputStream.h', + '<(tgvoip_src_loc)/BufferPool.cpp', + '<(tgvoip_src_loc)/BufferPool.h', + '<(tgvoip_src_loc)/CongestionControl.cpp', + '<(tgvoip_src_loc)/CongestionControl.h', + '<(tgvoip_src_loc)/EchoCanceller.cpp', + '<(tgvoip_src_loc)/EchoCanceller.h', + '<(tgvoip_src_loc)/JitterBuffer.cpp', + '<(tgvoip_src_loc)/JitterBuffer.h', + '<(tgvoip_src_loc)/logging.cpp', + '<(tgvoip_src_loc)/logging.h', + '<(tgvoip_src_loc)/MediaStreamItf.cpp', + '<(tgvoip_src_loc)/MediaStreamItf.h', + '<(tgvoip_src_loc)/OpusDecoder.cpp', + '<(tgvoip_src_loc)/OpusDecoder.h', + '<(tgvoip_src_loc)/OpusEncoder.cpp', + '<(tgvoip_src_loc)/OpusEncoder.h', + '<(tgvoip_src_loc)/threading.h', + '<(tgvoip_src_loc)/VoIPController.cpp', + '<(tgvoip_src_loc)/VoIPController.h', + '<(tgvoip_src_loc)/VoIPServerConfig.cpp', + '<(tgvoip_src_loc)/VoIPServerConfig.h', + '<(tgvoip_src_loc)/audio/AudioInput.cpp', + '<(tgvoip_src_loc)/audio/AudioInput.h', + '<(tgvoip_src_loc)/audio/AudioOutput.cpp', + '<(tgvoip_src_loc)/audio/AudioOutput.h', + '<(tgvoip_src_loc)/audio/Resampler.cpp', + '<(tgvoip_src_loc)/audio/Resampler.h', + '<(tgvoip_src_loc)/NetworkSocket.cpp', + '<(tgvoip_src_loc)/NetworkSocket.h', + + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/base/array_view.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/base/atomicops.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/base/basictypes.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/base/checks.cc', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/base/checks.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/base/constructormagic.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/base/safe_compare.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/base/safe_conversions.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/base/safe_conversions_impl.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/base/sanitizer.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/base/stringutils.cc', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/base/stringutils.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/base/type_traits.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/audio_util.cc', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/channel_buffer.cc', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/channel_buffer.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/fft4g.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/fft4g.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/include/audio_util.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/ring_buffer.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/ring_buffer.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/auto_corr_to_refl_coef.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/auto_correlation.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/complex_bit_reverse.c', +# 'webrtc_dsp/webrtc/common_audio/signal_processing/complex_bit_reverse_arm.S', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/complex_fft.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/complex_fft_tables.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/copy_set_operations.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/cross_correlation.c', +# '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/cross_correlation_neon.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/division_operations.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/dot_product_with_scale.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/downsample_fast.c', +# '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/downsample_fast_neon.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/energy.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/filter_ar.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/filter_ar_fast_q12.c', +# 'webrtc_dsp/webrtc/common_audio/signal_processing/filter_ar_fast_q12_armv7.S', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/filter_ma_fast_q12.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/get_hanning_window.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/get_scaling_square.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/ilbc_specific_functions.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/include/real_fft.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/include/signal_processing_library.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/include/spl_inl.h', +# '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/include/spl_inl_armv7.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/include/spl_inl_mips.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/levinson_durbin.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/lpc_to_refl_coef.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/min_max_operations.c', +# '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/min_max_operations_neon.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/randomization_functions.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/real_fft.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/refl_coef_to_lpc.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/resample.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/resample_48khz.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/resample_by_2.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/resample_by_2_internal.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/resample_by_2_internal.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/resample_fractional.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/spl_init.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/spl_inl.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/spl_sqrt.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/spl_sqrt_floor.c', + #'webrtc_dsp/webrtc/common_audio/signal_processing/spl_sqrt_floor_arm.S', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/splitting_filter_impl.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/signal_processing/vector_scaling_operations.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/sparse_fir_filter.cc', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/sparse_fir_filter.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/wav_file.cc', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/wav_file.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/wav_header.cc', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/common_audio/wav_header.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/aec/aec_common.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/aec/aec_core.cc', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/aec/aec_core.h', +# '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/aec/aec_core_neon.cc', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/aec/aec_core_optimized_methods.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/aec/aec_core_sse2.cc', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/aec/aec_resampler.cc', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/aec/aec_resampler.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/aec/echo_cancellation.cc', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/aec/echo_cancellation.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/aecm/aecm_core.cc', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/aecm/aecm_core.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/aecm/aecm_core_c.cc', +# '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/aecm/aecm_core_neon.cc', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/aecm/aecm_defines.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/aecm/echo_control_mobile.cc', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/aecm/echo_control_mobile.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/agc/legacy/analog_agc.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/agc/legacy/analog_agc.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/agc/legacy/digital_agc.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/agc/legacy/digital_agc.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/agc/legacy/gain_control.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/logging/apm_data_dumper.cc', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/logging/apm_data_dumper.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/ns/defines.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/ns/noise_suppression.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/ns/noise_suppression.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/ns/noise_suppression_x.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/ns/noise_suppression_x.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/ns/ns_core.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/ns/ns_core.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/ns/nsx_core.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/ns/nsx_core.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/ns/nsx_core_c.c', +# '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/ns/nsx_core_neon.c', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/ns/nsx_defines.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/ns/windows_private.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/splitting_filter.cc', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/splitting_filter.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/three_band_filter_bank.cc', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/three_band_filter_bank.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/utility/block_mean_calculator.cc', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/utility/block_mean_calculator.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/utility/delay_estimator.cc', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/utility/delay_estimator.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/utility/delay_estimator_internal.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/utility/delay_estimator_wrapper.cc', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/utility/delay_estimator_wrapper.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/utility/ooura_fft.cc', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/utility/ooura_fft.h', +# '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/utility/ooura_fft_neon.cc', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/utility/ooura_fft_sse2.cc', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/utility/ooura_fft_tables_common.h', +# '<(tgvoip_src_loc)/webrtc_dsp/webrtc/modules/audio_processing/utility/ooura_fft_tables_neon_sse2.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/system_wrappers/include/asm_defines.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/system_wrappers/include/compile_assert_c.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/system_wrappers/include/cpu_features_wrapper.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/system_wrappers/include/metrics.h', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/system_wrappers/source/cpu_features.cc', + '<(tgvoip_src_loc)/webrtc_dsp/webrtc/typedefs.h', + + ], + 'libraries': [], + 'configurations': { + 'Debug': {}, + 'Release': {}, + }, + 'conditions': [ + [ + '"<(OS)" == "mac"', { + 'sources': [ + '<(tgvoip_src_loc)/os/darwin/AudioInputAudioUnitOSX.cpp', + '<(tgvoip_src_loc)/os/darwin/AudioInputAudioUnitOSX.h', + '<(tgvoip_src_loc)/os/darwin/AudioOutputAudioUnitOSX.cpp', + '<(tgvoip_src_loc)/os/darwin/AudioOutputAudioUnitOSX.h', + '<(tgvoip_src_loc)/os/posix/NetworkSocketPosix.cpp', + '<(tgvoip_src_loc)/os/posix/NetworkSocketPosix.h', + ], + 'include_dirs': [ + '../../../Libraries/openssl-xcode/include', + ], + 'xcode_settings': { + 'CLANG_CXX_LANGUAGE_STANDARD': 'c++1z', + }, + 'defines': [ + 'WEBRTC_POSIX', + ], + }, + ], + [ + '"<(OS)" == "win"', { + 'msbuild_toolset': 'v140', + 'defines': [ + 'NOMINMAX', + '_USING_V110_SDK71_', + ], + 'sources': [ + '<(tgvoip_src_loc)/os/windows/NetworkSocketWinsock.cpp', + '<(tgvoip_src_loc)/os/windows/NetworkSocketWinsock.h', + '<(tgvoip_src_loc)/os/windows/AudioInputWave.cpp', + '<(tgvoip_src_loc)/os/windows/AudioInputWave.h', + '<(tgvoip_src_loc)/os/windows/AudioOutputWave.cpp', + '<(tgvoip_src_loc)/os/windows/AudioOutputWave.h', + ], + 'libraries': [ + 'winmm', + 'ws2_32', + 'kernel32', + 'user32', + ], + 'msvs_cygwin_shell': 0, + 'msvs_settings': { + 'VCCLCompilerTool': { + 'ProgramDataBaseFileName': '$(OutDir)\\$(ProjectName).pdb', + 'DebugInformationFormat': '3', # Program Database (/Zi) + 'AdditionalOptions': [ + '/MP', # Enable multi process build. + '/EHsc', # Catch C++ exceptions only, extern C functions never throw a C++ exception. + ], + 'TreatWChar_tAsBuiltInType': 'false', + }, + }, + 'msvs_external_builder_build_cmd': [ + 'ninja.exe', + '-C', + '$(OutDir)', + '-k0', + '$(ProjectName)', + ], + 'configurations': { + 'Debug': { + 'defines': [ + '_DEBUG', + ], + 'include_dirs': [ + '../../../Libraries/openssl_debug/Debug/include', + ], + 'msvs_settings': { + 'VCCLCompilerTool': { + 'Optimization': '0', # Disabled (/Od) + 'RuntimeLibrary': '1', # Multi-threaded Debug (/MTd) + 'RuntimeTypeInfo': 'true', + }, + 'VCLibrarianTool': { + 'AdditionalOptions': [ + '/NODEFAULTLIB:LIBCMT' + ] + } + }, + }, + 'Release': { + 'defines': [ + 'NDEBUG', + ], + 'include_dirs': [ + '../../../Libraries/openssl/Release/include', + ], + 'msvs_settings': { + 'VCCLCompilerTool': { + 'Optimization': '2', # Maximize Speed (/O2) + 'InlineFunctionExpansion': '2', # Any suitable (/Ob2) + 'EnableIntrinsicFunctions': 'true', # Yes (/Oi) + 'FavorSizeOrSpeed': '1', # Favor fast code (/Ot) + 'RuntimeLibrary': '0', # Multi-threaded (/MT) + 'EnableEnhancedInstructionSet': '2', # Streaming SIMD Extensions 2 (/arch:SSE2) + 'WholeProgramOptimization': 'true', # /GL + }, + }, + }, + }, + }, + ], + [ + '"<(OS)" == "linux"', { + 'sources': [ + '<(tgvoip_src_loc)/os/posix/NetworkSocketPosix.cpp', + '<(tgvoip_src_loc)/os/posix/NetworkSocketPosix.h', + + '<(tgvoip_src_loc)/os/linux/AudioInputALSA.cpp', + '<(tgvoip_src_loc)/os/linux/AudioInputALSA.h', + '<(tgvoip_src_loc)/os/linux/AudioOutputALSA.cpp', + '<(tgvoip_src_loc)/os/linux/AudioOutputALSA.h', + ], + 'defines': [ + 'WEBRTC_POSIX', + ], + 'direct_dependent_settings': { + 'libraries': [ + + ], + }, + }, + ], + ], + }, + ], + } \ No newline at end of file diff --git a/libtgvoip.xcodeproj/project.pbxproj b/libtgvoip.xcodeproj/project.pbxproj index abdc63797a..3e4f20d05f 100644 --- a/libtgvoip.xcodeproj/project.pbxproj +++ b/libtgvoip.xcodeproj/project.pbxproj @@ -7,6 +7,10 @@ objects = { /* Begin PBXBuildFile section */ + 69015D8A1E9D846F00AC9763 /* NetworkSocketPosix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 69015D881E9D846F00AC9763 /* NetworkSocketPosix.cpp */; }; + 69015D8B1E9D846F00AC9763 /* NetworkSocketPosix.h in Headers */ = {isa = PBXBuildFile; fileRef = 69015D891E9D846F00AC9763 /* NetworkSocketPosix.h */; }; + 69015D941E9D848700AC9763 /* NetworkSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 69015D921E9D848700AC9763 /* NetworkSocket.cpp */; }; + 69015D951E9D848700AC9763 /* NetworkSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 69015D931E9D848700AC9763 /* NetworkSocket.h */; }; 6915307B1E6B5BAB004F643F /* logging.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6915307A1E6B5BAB004F643F /* logging.cpp */; }; 692AB8CB1E6759DD00706ACC /* AudioInput.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 692AB8881E6759DD00706ACC /* AudioInput.cpp */; }; 692AB8CC1E6759DD00706ACC /* AudioInput.h in Headers */ = {isa = PBXBuildFile; fileRef = 692AB8891E6759DD00706ACC /* AudioInput.h */; }; @@ -232,6 +236,10 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 69015D881E9D846F00AC9763 /* NetworkSocketPosix.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkSocketPosix.cpp; sourceTree = ""; }; + 69015D891E9D846F00AC9763 /* NetworkSocketPosix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkSocketPosix.h; sourceTree = ""; }; + 69015D921E9D848700AC9763 /* NetworkSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkSocket.cpp; sourceTree = ""; }; + 69015D931E9D848700AC9763 /* NetworkSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkSocket.h; sourceTree = ""; }; 6915307A1E6B5BAB004F643F /* logging.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = logging.cpp; sourceTree = ""; }; 692AB8881E6759DD00706ACC /* AudioInput.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AudioInput.cpp; sourceTree = ""; }; 692AB8891E6759DD00706ACC /* AudioInput.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioInput.h; sourceTree = ""; }; @@ -427,6 +435,16 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 69015D871E9D846F00AC9763 /* posix */ = { + isa = PBXGroup; + children = ( + 69015D881E9D846F00AC9763 /* NetworkSocketPosix.cpp */, + 69015D891E9D846F00AC9763 /* NetworkSocketPosix.h */, + ); + name = posix; + path = ../../../../TDesktop/TBuild/tdesktop/third_party/libtgvoip/os/posix; + sourceTree = ""; + }; 692AB8861E6759BF00706ACC /* libtgvoip */ = { isa = PBXGroup; children = ( @@ -450,6 +468,8 @@ 692AB8AA1E6759DD00706ACC /* logging.h */, 692AB8AB1E6759DD00706ACC /* MediaStreamItf.cpp */, 692AB8AC1E6759DD00706ACC /* MediaStreamItf.h */, + 69015D921E9D848700AC9763 /* NetworkSocket.cpp */, + 69015D931E9D848700AC9763 /* NetworkSocket.h */, 692AB8AD1E6759DD00706ACC /* OpusDecoder.cpp */, 692AB8AE1E6759DD00706ACC /* OpusDecoder.h */, 692AB8AF1E6759DD00706ACC /* OpusEncoder.cpp */, @@ -479,6 +499,7 @@ 692AB8B11E6759DD00706ACC /* os */ = { isa = PBXGroup; children = ( + 69015D871E9D846F00AC9763 /* posix */, 692AB8BD1E6759DD00706ACC /* darwin */, ); path = os; @@ -875,6 +896,7 @@ 69A6DDDB1E95EC7700000E69 /* aec_common.h in Headers */, 69A6DDDD1E95EC7700000E69 /* aec_core.h in Headers */, 69A6DE051E95EC7800000E69 /* block_mean_calculator.h in Headers */, + 69015D8B1E9D846F00AC9763 /* NetworkSocketPosix.h in Headers */, 69A6DD951E95EC7700000E69 /* atomicops.h in Headers */, 69A6DD991E95EC7700000E69 /* constructormagic.h in Headers */, 69A6DDA01E95EC7700000E69 /* type_traits.h in Headers */, @@ -887,6 +909,7 @@ 69A6DE0A1E95EC7800000E69 /* delay_estimator_wrapper.h in Headers */, 69A6DE141E95EC7800000E69 /* metrics.h in Headers */, 692AB8FE1E6759DD00706ACC /* AudioUnitIO.h in Headers */, + 69015D951E9D848700AC9763 /* NetworkSocket.h in Headers */, 69A6DE131E95EC7800000E69 /* cpu_features_wrapper.h in Headers */, 69A6DDDF1E95EC7700000E69 /* aec_core_optimized_methods.h in Headers */, 69A6DE101E95EC7800000E69 /* ooura_fft_tables_neon_sse2.h in Headers */, @@ -1055,6 +1078,7 @@ 69A6DDE81E95EC7700000E69 /* aecm_core_neon.cc in Sources */, 69A6DDBB1E95EC7700000E69 /* get_hanning_window.c in Sources */, 69A6DDB51E95EC7700000E69 /* downsample_fast_neon.c in Sources */, + 69015D941E9D848700AC9763 /* NetworkSocket.cpp in Sources */, 69A6DDC41E95EC7700000E69 /* lpc_to_refl_coef.c in Sources */, 69A6DDEC1E95EC7700000E69 /* analog_agc.c in Sources */, 69A6DDA71E95EC7700000E69 /* ring_buffer.c in Sources */, @@ -1110,6 +1134,7 @@ 692AB8CB1E6759DD00706ACC /* AudioInput.cpp in Sources */, 69A6DDCC1E95EC7700000E69 /* resample_48khz.c in Sources */, 69A6DDAC1E95EC7700000E69 /* complex_bit_reverse_arm.S in Sources */, + 69015D8A1E9D846F00AC9763 /* NetworkSocketPosix.cpp in Sources */, 69A6DDD81E95EC7700000E69 /* vector_scaling_operations.c in Sources */, 69A6DE0D1E95EC7800000E69 /* ooura_fft_neon.cc in Sources */, 692AB8FD1E6759DD00706ACC /* AudioUnitIO.cpp in Sources */, @@ -1241,12 +1266,10 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; HEADER_SEARCH_PATHS = ( - ../../Telegraph/thirdparty/opus/include/opus, + "$(PROJECT_DIR)/../../Telegraph/thirdparty/opus/include/opus", "$(inherited)", - ../../Telegraph, + "$(PROJECT_DIR)/../../Telegraph", webrtc_dsp, - "../Telegram-iOS/Telegraph/thirdparty/opus/include/opus", - "../Telegram-iOS/Telegraph", ); INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1278,12 +1301,10 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; HEADER_SEARCH_PATHS = ( - ../../Telegraph/thirdparty/opus/include/opus, + "$(PROJECT_DIR)/../../Telegraph/thirdparty/opus/include/opus", "$(inherited)", - ../../Telegraph, + "$(PROJECT_DIR)/../../Telegraph", webrtc_dsp, - "../Telegram-iOS/Telegraph/thirdparty/opus/include/opus", - "../Telegram-iOS/Telegraph", ); INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1366,12 +1387,10 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; HEADER_SEARCH_PATHS = ( - ../../Telegraph/thirdparty/opus/include/opus, + "$(PROJECT_DIR)/../../Telegraph/thirdparty/opus/include/opus", "$(inherited)", - ../../Telegraph, + "$(PROJECT_DIR)/../../Telegraph", webrtc_dsp, - "../Telegram-iOS/Telegraph/thirdparty/opus/include/opus", - "../Telegram-iOS/Telegraph", ); INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1448,12 +1467,10 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; HEADER_SEARCH_PATHS = ( - ../../Telegraph/thirdparty/opus/include/opus, + "$(PROJECT_DIR)/../../Telegraph/thirdparty/opus/include/opus", "$(inherited)", - ../../Telegraph, + "$(PROJECT_DIR)/../../Telegraph", webrtc_dsp, - "../Telegram-iOS/Telegraph/thirdparty/opus/include/opus", - "../Telegram-iOS/Telegraph", ); INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; diff --git a/logging.h b/logging.h index 2ccb0c4b48..ae16cab88a 100644 --- a/logging.h +++ b/logging.h @@ -38,6 +38,19 @@ void tgvoip_log_file_printf(char level, const char* msg, ...); #define LOGW(msg, ...) __tgvoip_call_tglog("W/tgvoip: " msg, ##__VA_ARGS__) #define LOGE(msg, ...) __tgvoip_call_tglog("E/tgvoip: " msg, ##__VA_ARGS__) +#elif defined(_WIN32) && defined(_DEBUG) + +#include +#include + +#define _TGVOIP_W32_LOG_PRINT(msg, ...){ char __log_buf[1024]; snprintf(__log_buf, 1024, msg, ##__VA_ARGS__); OutputDebugStringA(__log_buf); } + +#define LOGV(msg, ...) _TGVOIP_W32_LOG_PRINT("V/tgvoip: " msg "\n", ##__VA_ARGS__) +#define LOGD(msg, ...) _TGVOIP_W32_LOG_PRINT("D/tgvoip: " msg "\n", ##__VA_ARGS__) +#define LOGI(msg, ...) _TGVOIP_W32_LOG_PRINT("I/tgvoip: " msg "\n", ##__VA_ARGS__) +#define LOGW(msg, ...) _TGVOIP_W32_LOG_PRINT("W/tgvoip: " msg "\n", ##__VA_ARGS__) +#define LOGE(msg, ...) _TGVOIP_W32_LOG_PRINT("E/tgvoip: " msg "\n", ##__VA_ARGS__) + #else #include diff --git a/os/darwin/AudioUnitIO.cpp b/os/darwin/AudioUnitIO.cpp index 9060e7bfe9..c461fa783e 100644 --- a/os/darwin/AudioUnitIO.cpp +++ b/os/darwin/AudioUnitIO.cpp @@ -17,6 +17,8 @@ #define kOutputBus 0 #define kInputBus 1 +using namespace tgvoip; + int CAudioUnitIO::refCount=0; CAudioUnitIO* CAudioUnitIO::sharedInstance=NULL; bool CAudioUnitIO::haveAudioSession=false; @@ -210,9 +212,9 @@ void* CAudioUnitIO::StartFakeIOThread(void *arg){ void CAudioUnitIO::RunFakeIOThread(){ double neededDataDuration=0; - double prevTime=CVoIPController::GetCurrentTime(); + double prevTime=VoIPController::GetCurrentTime(); while(runFakeIO){ - double t=CVoIPController::GetCurrentTime(); + double t=VoIPController::GetCurrentTime(); neededDataDuration+=t-prevTime; prevTime=t; while(neededDataDuration>=0.020){ diff --git a/os/darwin/TGLogWrapper.m b/os/darwin/TGLogWrapper.m index 4dbf5d1bfd..9cf316bf75 100644 --- a/os/darwin/TGLogWrapper.m +++ b/os/darwin/TGLogWrapper.m @@ -1,6 +1,6 @@ #import -#import "ASCommon.h" +#import void __tgvoip_call_tglog(char* format, ...){ va_list args; diff --git a/os/linux/AudioInputALSA.cpp b/os/linux/AudioInputALSA.cpp new file mode 100644 index 0000000000..3d3c2fd18c --- /dev/null +++ b/os/linux/AudioInputALSA.cpp @@ -0,0 +1,88 @@ +// +// 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 +#include +#include +#include +#include "AudioInputALSA.h" +#include "../../logging.h" + +using namespace tgvoip::audio; + +#define BUFFER_SIZE 960 +#define CHECK_ERROR(res, msg) if(res<0){LOGE(msg ": %s", _snd_strerror(res));} +#define CHECK_DL_ERROR(res, msg) if(!res){LOGE(msg ": %s", dlerror()); failed=true; return;} +#define LOAD_FUNCTION(lib, name, ref) {ref=(typeof(ref))dlsym(lib, name); CHECK_DL_ERROR(ref, "Error getting entry point for " name);} + +AudioInputALSA::AudioInputALSA(){ + isRecording=false; + + lib=dlopen("libasound.so", RTLD_LAZY); + if(!lib){ + LOGE("Error loading libasound: %s", dlerror()); + failed=true; + return; + } + + LOAD_FUNCTION(lib, "snd_pcm_open", _snd_pcm_open); + LOAD_FUNCTION(lib, "snd_pcm_set_params", _snd_pcm_set_params); + LOAD_FUNCTION(lib, "snd_pcm_close", _snd_pcm_close); + LOAD_FUNCTION(lib, "snd_pcm_readi", _snd_pcm_readi); + LOAD_FUNCTION(lib, "snd_pcm_recover", _snd_pcm_recover); + LOAD_FUNCTION(lib, "snd_strerror", _snd_strerror); + + int res=_snd_pcm_open(&handle, "default", SND_PCM_STREAM_CAPTURE, 0); + CHECK_ERROR(res, "snd_pcm_open failed"); + + res=_snd_pcm_set_params(handle, SND_PCM_FORMAT_S16, SND_PCM_ACCESS_RW_INTERLEAVED, 1, 48000, 1, 100000); + CHECK_ERROR(res, "snd_pcm_set_params failed"); +} + +AudioInputALSA::~AudioInputALSA(){ + _snd_pcm_close(handle); + dlclose(lib); +} + +void AudioInputALSA::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ + +} + +void AudioInputALSA::Start(){ + if(failed || isRecording) + return; + + isRecording=true; + start_thread(thread, AudioInputALSA::StartThread, this); +} + +void AudioInputALSA::Stop(){ + if(!isRecording) + return; + + isRecording=false; + join_thread(thread); +} + +void* AudioInputALSA::StartThread(void* arg){ + ((AudioInputALSA*)arg)->RunThread(); +} + +void AudioInputALSA::RunThread(){ + unsigned char buffer[BUFFER_SIZE*2]; + snd_pcm_sframes_t frames; + while(isRecording){ + frames=_snd_pcm_readi(handle, buffer, BUFFER_SIZE); + if (frames < 0){ + frames = _snd_pcm_recover(handle, frames, 0); + } + if (frames < 0) { + LOGE("snd_pcm_readi failed: %s\n", _snd_strerror(frames)); + break; + } + InvokeCallback(buffer, sizeof(buffer)); + } +} \ No newline at end of file diff --git a/os/linux/AudioInputALSA.h b/os/linux/AudioInputALSA.h new file mode 100644 index 0000000000..6d1904cf59 --- /dev/null +++ b/os/linux/AudioInputALSA.h @@ -0,0 +1,46 @@ +// +// 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_AUDIOINPUTALSA_H +#define LIBTGVOIP_AUDIOINPUTALSA_H + +#include "../../audio/AudioInput.h" +#include "../../threading.h" +#include + +namespace tgvoip{ +namespace audio{ + +class AudioInputALSA : public CAudioInput{ + +public: + AudioInputALSA(); + virtual ~AudioInputALSA(); + virtual void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels); + virtual void Start(); + virtual void Stop(); + +private: + static void* StartThread(void* arg); + void RunThread(); + + int (*_snd_pcm_open)(snd_pcm_t** pcm, const char* name, snd_pcm_stream_t stream, int mode); + int (*_snd_pcm_set_params)(snd_pcm_t* pcm, snd_pcm_format_t format, snd_pcm_access_t access, unsigned int channels, unsigned int rate, int soft_resample, unsigned int latency); + int (*_snd_pcm_close)(snd_pcm_t* pcm); + snd_pcm_sframes_t (*_snd_pcm_readi)(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size); + int (*_snd_pcm_recover)(snd_pcm_t* pcm, int err, int silent); + const char* (*_snd_strerror)(int errnum); + void* lib; + + snd_pcm_t* handle; + tgvoip_thread_t thread; + bool isRecording; +}; + +} +} + +#endif //LIBTGVOIP_AUDIOINPUTALSA_H diff --git a/os/linux/AudioOutputALSA.cpp b/os/linux/AudioOutputALSA.cpp new file mode 100644 index 0000000000..19decded99 --- /dev/null +++ b/os/linux/AudioOutputALSA.cpp @@ -0,0 +1,91 @@ +// +// 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 +#include +#include "AudioOutputALSA.h" +#include "../../logging.h" + +#define BUFFER_SIZE 960 +#define CHECK_ERROR(res, msg) if(res<0){LOGE(msg ": %s", _snd_strerror(res));} +#define CHECK_DL_ERROR(res, msg) if(!res){LOGE(msg ": %s", dlerror()); failed=true; return;} +#define LOAD_FUNCTION(lib, name, ref) {ref=(typeof(ref))dlsym(lib, name); CHECK_DL_ERROR(ref, "Error getting entry point for " name);} + +using namespace tgvoip::audio; + +AudioOutputALSA::AudioOutputALSA(){ + isPlaying=false; + + lib=dlopen("libasound.so", RTLD_LAZY); + if(!lib){ + LOGE("Error loading libasound: %s", dlerror()); + failed=true; + return; + } + + LOAD_FUNCTION(lib, "snd_pcm_open", _snd_pcm_open); + LOAD_FUNCTION(lib, "snd_pcm_set_params", _snd_pcm_set_params); + LOAD_FUNCTION(lib, "snd_pcm_close", _snd_pcm_close); + LOAD_FUNCTION(lib, "snd_pcm_writei", _snd_pcm_writei); + LOAD_FUNCTION(lib, "snd_pcm_recover", _snd_pcm_recover); + LOAD_FUNCTION(lib, "snd_strerror", _snd_strerror); + + int res=_snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0); + CHECK_ERROR(res, "snd_pcm_open failed"); + + res=_snd_pcm_set_params(handle, SND_PCM_FORMAT_S16, SND_PCM_ACCESS_RW_INTERLEAVED, 1, 48000, 1, 100000); + CHECK_ERROR(res, "snd_pcm_set_params failed"); +} + +AudioOutputALSA::~AudioOutputALSA(){ + _snd_pcm_close(handle); + dlclose(lib); +} + +void AudioOutputALSA::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ + +} + +void AudioOutputALSA::Start(){ + if(failed || isPlaying) + return; + + isPlaying=true; + start_thread(thread, AudioOutputALSA::StartThread, this); +} + +void AudioOutputALSA::Stop(){ + if(!isPlaying) + return; + + isPlaying=false; + join_thread(thread); +} + +bool AudioOutputALSA::IsPlaying(){ + return isPlaying; +} + +void* AudioOutputALSA::StartThread(void* arg){ + ((AudioOutputALSA*)arg)->RunThread(); +} + +void AudioOutputALSA::RunThread(){ + unsigned char buffer[BUFFER_SIZE*2]; + snd_pcm_sframes_t frames; + while(isPlaying){ + InvokeCallback(buffer, sizeof(buffer)); + frames=_snd_pcm_writei(handle, buffer, BUFFER_SIZE); + if (frames < 0){ + frames = _snd_pcm_recover(handle, frames, 0); + } + if (frames < 0) { + LOGE("snd_pcm_writei failed: %s\n", _snd_strerror(frames)); + break; + } + } +} \ No newline at end of file diff --git a/os/linux/AudioOutputALSA.h b/os/linux/AudioOutputALSA.h new file mode 100644 index 0000000000..2462e6a207 --- /dev/null +++ b/os/linux/AudioOutputALSA.h @@ -0,0 +1,46 @@ +// +// 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_AUDIOOUTPUTALSA_H +#define LIBTGVOIP_AUDIOOUTPUTALSA_H + +#include "../../audio/AudioOutput.h" +#include "../../threading.h" +#include + +namespace tgvoip{ +namespace audio{ + +class AudioOutputALSA : public CAudioOutput{ +public: + AudioOutputALSA(); + virtual ~AudioOutputALSA(); + virtual void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels); + virtual void Start(); + virtual void Stop(); + virtual bool IsPlaying(); + +private: + static void* StartThread(void* arg); + void RunThread(); + + int (*_snd_pcm_open)(snd_pcm_t** pcm, const char* name, snd_pcm_stream_t stream, int mode); + int (*_snd_pcm_set_params)(snd_pcm_t* pcm, snd_pcm_format_t format, snd_pcm_access_t access, unsigned int channels, unsigned int rate, int soft_resample, unsigned int latency); + int (*_snd_pcm_close)(snd_pcm_t* pcm); + snd_pcm_sframes_t (*_snd_pcm_writei)(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size); + int (*_snd_pcm_recover)(snd_pcm_t* pcm, int err, int silent); + const char* (*_snd_strerror)(int errnum); + void* lib; + + snd_pcm_t* handle; + tgvoip_thread_t thread; + bool isPlaying; +}; + +} +} + +#endif //LIBTGVOIP_AUDIOOUTPUTALSA_H diff --git a/os/posix/NetworkSocketPosix.cpp b/os/posix/NetworkSocketPosix.cpp new file mode 100644 index 0000000000..5b0ff3d697 --- /dev/null +++ b/os/posix/NetworkSocketPosix.cpp @@ -0,0 +1,282 @@ +// +// Created by Grishka on 10.04.17. +// + +#include "NetworkSocketPosix.h" +#include +#include +#include +#include +#include +#include +#include +#include "../../logging.h" +#include "../../VoIPController.h" + +using namespace tgvoip; + +NetworkSocketPosix::NetworkSocketPosix() : lastRecvdV4(0){ + needUpdateNat64Prefix=true; + nat64Present=false; + switchToV6at=0; + isV4Available=false; +} + +NetworkSocketPosix::~NetworkSocketPosix(){ + +} + +void NetworkSocketPosix::SetMaxPriority(){ +#ifdef __APPLE__ + int prio=NET_SERVICE_TYPE_VO; + int res=setsockopt(fd, SOL_SOCKET, SO_NET_SERVICE_TYPE, &prio, sizeof(prio)); + if(res<0){ + LOGE("error setting darwin-specific net priority: %d / %s", errno, strerror(errno)); + } +#else + int prio=5; + int res=setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio)); + if(res<0){ + LOGE("error setting priority: %d / %s", errno, strerror(errno)); + } + prio=6 << 5; + res=setsockopt(fd, SOL_IP, IP_TOS, &prio, sizeof(prio)); + if(res<0){ + LOGE("error setting ip tos: %d / %s", errno, strerror(errno)); + } +#endif +} + +void NetworkSocketPosix::Send(NetworkPacket *packet){ + sockaddr_in6 addr; + IPv4Address* v4addr=dynamic_cast(packet->address); + if(v4addr){ + if(needUpdateNat64Prefix && !isV4Available && VoIPController::GetCurrentTime()>switchToV6at && switchToV6at!=0){ + LOGV("Updating NAT64 prefix"); + nat64Present=false; + addrinfo* addr0; + int res=getaddrinfo("ipv4only.arpa", NULL, NULL, &addr0); + if(res!=0){ + LOGW("Error updating NAT64 prefix: %d / %s", res, gai_strerror(res)); + }else{ + addrinfo* addrPtr; + unsigned char* addr170=NULL; + unsigned char* addr171=NULL; + for(addrPtr=addr0;addrPtr;addrPtr=addrPtr->ai_next){ + if(addrPtr->ai_family==AF_INET6){ + sockaddr_in6* translatedAddr=(sockaddr_in6*)addrPtr->ai_addr; + uint32_t v4part=*((uint32_t*)&translatedAddr->sin6_addr.s6_addr[12]); + if(v4part==0xAA0000C0 && !addr170){ + addr170=translatedAddr->sin6_addr.s6_addr; + } + if(v4part==0xAB0000C0 && !addr171){ + addr171=translatedAddr->sin6_addr.s6_addr; + } + char buf[INET6_ADDRSTRLEN]; + LOGV("Got translated address: %s", inet_ntop(AF_INET6, &translatedAddr->sin6_addr, buf, sizeof(buf))); + } + } + if(addr170 && addr171 && memcmp(addr170, addr171, 12)==0){ + nat64Present=true; + memcpy(nat64Prefix, addr170, 12); + char buf[INET6_ADDRSTRLEN]; + LOGV("Found nat64 prefix from %s", inet_ntop(AF_INET6, addr170, buf, sizeof(buf))); + }else{ + LOGV("Didn't find nat64"); + } + freeaddrinfo(addr0); + } + needUpdateNat64Prefix=false; + } + memset(&addr, 0, sizeof(sockaddr_in6)); + addr.sin6_family=AF_INET6; + *((uint32_t*)&addr.sin6_addr.s6_addr[12])=v4addr->GetAddress(); + if(nat64Present) + memcpy(addr.sin6_addr.s6_addr, nat64Prefix, 12); + else + addr.sin6_addr.s6_addr[11]=addr.sin6_addr.s6_addr[10]=0xFF; + + }else{ + IPv6Address* v6addr=dynamic_cast(packet->address); + assert(v6addr!=NULL); + } + addr.sin6_port=htons(packet->port); + char buf[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &addr.sin6_addr, buf, sizeof(buf)); + int res=sendto(fd, packet->data, packet->length, 0, (const sockaddr *) &addr, sizeof(addr)); + if(res<0){ + LOGE("error sending: %d / %s", errno, strerror(errno)); + if(errno==ENETUNREACH && !isV4Available && VoIPController::GetCurrentTime()data, packet->length, 0, (sockaddr *) &srcAddr, (socklen_t *) &addrLen); + if(len>0) + packet->length=(size_t) len; + else{ + packet->length=0; + return; + } + //LOGV("Received %d bytes from %s:%d at %.5lf", len, inet_ntoa(srcAddr.sin_addr), ntohs(srcAddr.sin_port), GetCurrentTime()); + if(!isV4Available && IN6_IS_ADDR_V4MAPPED(&srcAddr.sin6_addr)){ + isV4Available=true; + LOGI("Detected IPv4 connectivity, will not try IPv6"); + } + if(IN6_IS_ADDR_V4MAPPED(&srcAddr.sin6_addr) || (nat64Present && memcmp(nat64Prefix, srcAddr.sin6_addr.s6_addr, 12)==0)){ + in_addr v4addr=*((in_addr *) &srcAddr.sin6_addr.s6_addr[12]); + lastRecvdV4=IPv4Address(v4addr.s_addr); + packet->address=&lastRecvdV4; + } +} + +void NetworkSocketPosix::Open(){ + fd=socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if(fd<0){ + LOGE("error creating socket: %d / %s", errno, strerror(errno)); + } + int flag=0; + int res=setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)); + if(res<0){ + LOGE("error enabling dual stack socket: %d / %s", errno, strerror(errno)); + } + + SetMaxPriority(); + + int tries=0; + sockaddr_in6 addr; + //addr.sin6_addr.s_addr=0; + memset(&addr, 0, sizeof(sockaddr_in6)); + //addr.sin6_len=sizeof(sa_family_t); + addr.sin6_family=AF_INET6; + for(tries=0;tries<10;tries++){ + addr.sin6_port=htons(GenerateLocalPort()); + res=::bind(fd, (sockaddr *) &addr, sizeof(sockaddr_in6)); + LOGV("trying bind to port %u", ntohs(addr.sin6_port)); + if(res<0){ + LOGE("error binding to port %u: %d / %s", ntohs(addr.sin6_port), errno, strerror(errno)); + }else{ + break; + } + } + if(tries==10){ + addr.sin6_port=0; + res=::bind(fd, (sockaddr *) &addr, sizeof(sockaddr_in6)); + if(res<0){ + LOGE("error binding to port %u: %d / %s", ntohs(addr.sin6_port), errno, strerror(errno)); + //SetState(STATE_FAILED); + return; + } + } + size_t addrLen=sizeof(sockaddr_in6); + getsockname(fd, (sockaddr*)&addr, (socklen_t*) &addrLen); + uint16_t localUdpPort=ntohs(addr.sin6_port); + LOGD("Bound to local UDP port %u", ntohs(addr.sin6_port)); + + needUpdateNat64Prefix=true; + isV4Available=false; + switchToV6at=VoIPController::GetCurrentTime()+ipv6Timeout; +} + +void NetworkSocketPosix::Close(){ + shutdown(fd, SHUT_RDWR); + close(fd); +} + +void NetworkSocketPosix::OnActiveInterfaceChanged(){ + needUpdateNat64Prefix=true; + isV4Available=false; + switchToV6at=VoIPController::GetCurrentTime()+ipv6Timeout; +} + +std::string NetworkSocketPosix::GetLocalInterfaceInfo(IPv4Address *v4addr, IPv6Address *v6addr){ + struct ifconf ifc; + struct ifreq* ifr; + char buf[16384]; + int sd; + std::string name=""; + sd=socket(PF_INET, SOCK_DGRAM, 0); + if(sd>0){ + ifc.ifc_len=sizeof(buf); + ifc.ifc_ifcu.ifcu_buf=buf; + if(ioctl(sd, SIOCGIFCONF, &ifc)==0){ + ifr=ifc.ifc_req; + int len; + int i; + for(i=0;iifr_addr.sa_len; +#else + len=sizeof(*ifr); +#endif + if(ifr->ifr_addr.sa_family==AF_INET){ + if(ioctl(sd, SIOCGIFADDR, ifr)==0){ + struct sockaddr_in* addr=(struct sockaddr_in *)(&ifr->ifr_addr); + LOGI("Interface %s, address %s\n", ifr->ifr_name, inet_ntoa(addr->sin_addr)); + if(ioctl(sd, SIOCGIFFLAGS, ifr)==0){ + if(!(ifr->ifr_flags & IFF_LOOPBACK) && (ifr->ifr_flags & IFF_UP) && (ifr->ifr_flags & IFF_RUNNING)){ + //LOGV("flags = %08X", ifr->ifr_flags); + if((ntohl(addr->sin_addr.s_addr) & 0xFFFF0000)==0xA9FE0000){ + LOGV("skipping link-local"); + continue; + } + if(v4addr){ + *v4addr=IPv4Address(addr->sin_addr.s_addr); + } + name=ifr->ifr_name; + } + } + }else{ + LOGE("Error getting address for %s: %d\n", ifr->ifr_name, errno); + } + } + ifr=(struct ifreq*)((char*)ifr+len); + i+=len; + } + }else{ + LOGE("Error getting LAN address: %d", errno); + } + } + close(sd); + return name; +} + +uint16_t NetworkSocketPosix::GetLocalPort(){ + sockaddr_in6 addr; + size_t addrLen=sizeof(sockaddr_in6); + getsockname(fd, (sockaddr*)&addr, (socklen_t*) &addrLen); + return ntohs(addr.sin6_port); +} + +std::string NetworkSocketPosix::V4AddressToString(uint32_t address){ + char buf[INET_ADDRSTRLEN]; + in_addr addr; + addr.s_addr=address; + inet_ntop(AF_INET, &addr, buf, sizeof(buf)); + return std::string(buf); +} + +std::string NetworkSocketPosix::V6AddressToString(unsigned char *address){ + char buf[INET6_ADDRSTRLEN]; + in6_addr addr; + memcpy(addr.s6_addr, address, 16); + inet_ntop(AF_INET6, &addr, buf, sizeof(buf)); + return std::string(buf); +} + +uint32_t NetworkSocketPosix::StringToV4Address(std::string address){ + in_addr addr; + inet_pton(AF_INET, address.c_str(), &addr); + return addr.s_addr; +} + +void NetworkSocketPosix::StringToV6Address(std::string address, unsigned char *out){ + in6_addr addr; + inet_pton(AF_INET6, address.c_str(), &addr); + memcpy(out, addr.s6_addr, 16); +} diff --git a/os/posix/NetworkSocketPosix.h b/os/posix/NetworkSocketPosix.h new file mode 100644 index 0000000000..ec39feff47 --- /dev/null +++ b/os/posix/NetworkSocketPosix.h @@ -0,0 +1,44 @@ +// +// Created by Grishka on 10.04.17. +// + +#ifndef LIBTGVOIP_NETWORKSOCKETPOSIX_H +#define LIBTGVOIP_NETWORKSOCKETPOSIX_H + +#include "../../NetworkSocket.h" + +namespace tgvoip { + +class NetworkSocketPosix : public NetworkSocket{ +public: + NetworkSocketPosix(); + virtual ~NetworkSocketPosix(); + virtual void Send(NetworkPacket* packet); + virtual void Receive(NetworkPacket* packet); + virtual void Open(); + virtual void Close(); + virtual std::string GetLocalInterfaceInfo(IPv4Address* v4addr, IPv6Address* v6addr); + virtual void OnActiveInterfaceChanged(); + virtual uint16_t GetLocalPort(); + + static std::string V4AddressToString(uint32_t address); + static std::string V6AddressToString(unsigned char address[16]); + static uint32_t StringToV4Address(std::string address); + static void StringToV6Address(std::string address, unsigned char* out); + +protected: + virtual void SetMaxPriority(); + +private: + int fd; + bool needUpdateNat64Prefix; + bool nat64Present; + double switchToV6at; + bool isV4Available; + IPv4Address lastRecvdV4; + +}; + +} + +#endif //LIBTGVOIP_NETWORKSOCKETPOSIX_H diff --git a/os/windows/AudioInputWave.cpp b/os/windows/AudioInputWave.cpp new file mode 100644 index 0000000000..48a3a26735 --- /dev/null +++ b/os/windows/AudioInputWave.cpp @@ -0,0 +1,91 @@ +// +// 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 +#include +#include +#include "AudioInputWave.h" +#include "../../logging.h" + +using namespace tgvoip::audio; + +#define BUFFER_SIZE 960 +#define CHECK_ERROR(res, msg) if(res!=MMSYSERR_NOERROR){wchar_t _buf[1024]; waveInGetErrorTextW(res, _buf, 1024); LOGE(msg ": %ws (MMRESULT=0x08X)", _buf, res); failed=true;} + +AudioInputWave::AudioInputWave(){ + isRecording=false; + + for(int i=0;i<4;i++){ + ZeroMemory(&buffers[i], sizeof(WAVEHDR)); + buffers[i].dwBufferLength=960*2; + buffers[i].lpData=(char*)malloc(960*2); + } + + ZeroMemory(&format, sizeof(format)); + format.cbSize=0; + format.wFormatTag=WAVE_FORMAT_PCM; + format.nSamplesPerSec=48000; + format.wBitsPerSample=16; + format.nChannels=1; + format.nBlockAlign=2; + + MMRESULT res=waveInOpen(&hWaveIn, WAVE_MAPPER, &format, (DWORD_PTR)AudioInputWave::WaveInProc, (DWORD_PTR)this, CALLBACK_FUNCTION); + CHECK_ERROR(res, "waveInOpen failed"); +} + +AudioInputWave::~AudioInputWave(){ + for(int i=0;i<4;i++){ + free(buffers[i].lpData); + } + waveInClose(hWaveIn); +} + +void AudioInputWave::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ + +} + +void AudioInputWave::Start(){ + isRecording=true; + + MMRESULT res; + for(int i=0;i<4;i++){ + res=waveInPrepareHeader(hWaveIn, &buffers[i], sizeof(WAVEHDR)); + CHECK_ERROR(res, "waveInPrepareHeader failed"); + res=waveInAddBuffer(hWaveIn, &buffers[i], sizeof(WAVEHDR)); + CHECK_ERROR(res, "waveInAddBuffer failed"); + } + res=waveInStart(hWaveIn); + CHECK_ERROR(res, "waveInStart failed"); +} + +void AudioInputWave::Stop(){ + isRecording=false; + + MMRESULT res=waveInStop(hWaveIn); + CHECK_ERROR(res, "waveInStop failed"); + res=waveInReset(hWaveIn); + CHECK_ERROR(res, "waveInReset failed"); + for(int i=0;i<4;i++){ + res=waveInUnprepareHeader(hWaveIn, &buffers[i], sizeof(WAVEHDR)); + CHECK_ERROR(res, "waveInUnprepareHeader failed"); + } +} + +void AudioInputWave::WaveInProc(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2){ + if(uMsg==WIM_DATA){ + ((AudioInputWave*)dwInstance)->OnData((WAVEHDR*)dwParam1); + } +} + +void AudioInputWave::OnData(WAVEHDR* hdr){ + if(!isRecording) + return; + + InvokeCallback((unsigned char*)hdr->lpData, hdr->dwBufferLength); + hdr->dwFlags&= ~WHDR_DONE; + MMRESULT res=waveInAddBuffer(hWaveIn, hdr, sizeof(WAVEHDR)); + CHECK_ERROR(res, "waveInAddBuffer failed"); +} \ No newline at end of file diff --git a/os/windows/AudioInputWave.h b/os/windows/AudioInputWave.h new file mode 100644 index 0000000000..d9d56aeca6 --- /dev/null +++ b/os/windows/AudioInputWave.h @@ -0,0 +1,37 @@ +// +// libtgvoip is free and unencumbered public domain software. +// For more information, see http://unlicense.org or the UNLICENSE file +// you should have received with this source code distribution. +// + +#ifndef LIBTGVOIP_AUDIOINPUTWAVE_H +#define LIBTGVOIP_AUDIOINPUTWAVE_H + +#include +#include "../../audio/AudioInput.h" + +namespace tgvoip{ +namespace audio{ + +class AudioInputWave : public CAudioInput{ + +public: + AudioInputWave(); + virtual ~AudioInputWave(); + virtual void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels); + virtual void Start(); + virtual void Stop(); + +private: + static void CALLBACK WaveInProc(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2); + void OnData(WAVEHDR* hdr); + HWAVEIN hWaveIn; + WAVEFORMATEX format; + WAVEHDR buffers[4]; + bool isRecording; +}; + +} +} + +#endif //LIBTGVOIP_AUDIOINPUTWAVE_H diff --git a/os/windows/AudioOutputWave.cpp b/os/windows/AudioOutputWave.cpp new file mode 100644 index 0000000000..fc969eb9dd --- /dev/null +++ b/os/windows/AudioOutputWave.cpp @@ -0,0 +1,90 @@ +// +// 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 +#include "AudioOutputWave.h" +#include "../../logging.h" + +#define BUFFER_SIZE 960 +#define CHECK_ERROR(res, msg) if(res!=MMSYSERR_NOERROR){wchar_t _buf[1024]; waveOutGetErrorTextW(res, _buf, 1024); LOGE(msg ": %ws (MMRESULT=0x08X)", _buf, res); failed=true;} + +using namespace tgvoip::audio; + +AudioOutputWave::AudioOutputWave(){ + isPlaying=false; + + for(int i=0;i<4;i++){ + ZeroMemory(&buffers[i], sizeof(WAVEHDR)); + buffers[i].dwBufferLength=960*2; + buffers[i].lpData=(char*)malloc(960*2); + } + + ZeroMemory(&format, sizeof(format)); + format.cbSize=0; + format.wFormatTag=WAVE_FORMAT_PCM; + format.nSamplesPerSec=48000; + format.wBitsPerSample=16; + format.nChannels=1; + format.nBlockAlign=2; + + MMRESULT res=waveOutOpen(&hWaveOut, WAVE_MAPPER, &format, (DWORD_PTR)AudioOutputWave::WaveOutProc, (DWORD_PTR)this, CALLBACK_FUNCTION); + CHECK_ERROR(res, "waveOutOpen failed"); +} + +AudioOutputWave::~AudioOutputWave(){ + for(int i=0;i<4;i++){ + free(buffers[i].lpData); + } + waveOutClose(hWaveOut); +} + +void AudioOutputWave::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ + +} + +void AudioOutputWave::Start(){ + isPlaying=true; + + for(int i=0;i<4;i++){ + MMRESULT res=waveOutPrepareHeader(hWaveOut, &buffers[i], sizeof(WAVEHDR)); + CHECK_ERROR(res, "waveOutPrepareHeader failed"); + //InvokeCallback((unsigned char*)buffers[i].lpData, buffers[i].dwBufferLength); + ZeroMemory(buffers[i].lpData, buffers[i].dwBufferLength); + res=waveOutWrite(hWaveOut, &buffers[i], sizeof(WAVEHDR)); + CHECK_ERROR(res, "waveOutWrite failed"); + } +} + +void AudioOutputWave::Stop(){ + isPlaying=false; + + MMRESULT res=waveOutReset(hWaveOut); + CHECK_ERROR(res, "waveOutReset failed"); + for(int i=0;i<4;i++){ + res=waveOutUnprepareHeader(hWaveOut, &buffers[i], sizeof(WAVEHDR)); + CHECK_ERROR(res, "waveOutUnprepareHeader failed"); + } +} + +bool AudioOutputWave::IsPlaying(){ + return isPlaying; +} + +void AudioOutputWave::WaveOutProc(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { + if(uMsg==WOM_DONE){ + ((AudioOutputWave*)dwInstance)->OnBufferDone((WAVEHDR*)dwParam1); + } +} + +void AudioOutputWave::OnBufferDone(WAVEHDR* hdr){ + if(!isPlaying) + return; + + InvokeCallback((unsigned char*)hdr->lpData, hdr->dwBufferLength); + hdr->dwFlags&= ~WHDR_DONE; + MMRESULT res=waveOutWrite(hWaveOut, hdr, sizeof(WAVEHDR)); +} diff --git a/os/windows/AudioOutputWave.h b/os/windows/AudioOutputWave.h new file mode 100644 index 0000000000..b9aabfb4a2 --- /dev/null +++ b/os/windows/AudioOutputWave.h @@ -0,0 +1,37 @@ +// +// libtgvoip is free and unencumbered public domain software. +// For more information, see http://unlicense.org or the UNLICENSE file +// you should have received with this source code distribution. +// + +#ifndef LIBTGVOIP_AUDIOOUTPUTWAVE_H +#define LIBTGVOIP_AUDIOOUTPUTWAVE_H + +#include +#include "../../audio/AudioOutput.h" + +namespace tgvoip{ +namespace audio{ + +class AudioOutputWave : public CAudioOutput{ +public: + AudioOutputWave(); + virtual ~AudioOutputWave(); + virtual void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels); + virtual void Start(); + virtual void Stop(); + virtual bool IsPlaying(); + +private: + HWAVEOUT hWaveOut; + WAVEFORMATEX format; + WAVEHDR buffers[4]; + static void CALLBACK WaveOutProc(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2); + void OnBufferDone(WAVEHDR* hdr); + bool isPlaying; +}; + +} +} + +#endif //LIBTGVOIP_AUDIOOUTPUTWAVE_H diff --git a/os/windows/NetworkSocketWinsock.cpp b/os/windows/NetworkSocketWinsock.cpp new file mode 100644 index 0000000000..13f9b21f4d --- /dev/null +++ b/os/windows/NetworkSocketWinsock.cpp @@ -0,0 +1,375 @@ +// +// Created by Grishka on 10.04.17. +// + +#include "NetworkSocketWinsock.h" +#include +#include +#include +#include +#include "../../logging.h" +#include "../../VoIPController.h" + +using namespace tgvoip; + +NetworkSocketWinsock::NetworkSocketWinsock() : lastRecvdV4(0){ + needUpdateNat64Prefix=true; + nat64Present=false; + switchToV6at=0; + isV4Available=false; + + DWORD version=GetVersion(); + isAtLeastVista=LOBYTE(LOWORD(version))>=6; // Vista is 6.0, XP is 5.1 and 5.2 + + WSADATA wsaData; + WSAStartup(MAKEWORD(2, 2), &wsaData); + LOGD("Initialized winsock, version %d.%d", wsaData.wHighVersion, wsaData.wVersion); +} + +NetworkSocketWinsock::~NetworkSocketWinsock(){ + +} + +void NetworkSocketWinsock::SetMaxPriority(){ + +} + +void NetworkSocketWinsock::Send(NetworkPacket *packet){ + sockaddr_in6 addr; + IPv4Address* v4addr=dynamic_cast(packet->address); + if(v4addr){ + if(!isAtLeastVista){ + sockaddr_in _addr; + _addr.sin_family=AF_INET; + _addr.sin_addr.s_addr=v4addr->GetAddress(); + _addr.sin_port=htons(packet->port); + int res=sendto(fd, (char*)packet->data, packet->length, 0, (sockaddr*)&_addr, sizeof(_addr)); + if(res==SOCKET_ERROR){ + int error=WSAGetLastError(); + LOGE("error sending: %d", error); + } + return; + } + if(needUpdateNat64Prefix && !isV4Available && VoIPController::GetCurrentTime()>switchToV6at && switchToV6at!=0){ + LOGV("Updating NAT64 prefix"); + nat64Present=false; + addrinfo* addr0; + int res=getaddrinfo("ipv4only.arpa", NULL, NULL, &addr0); + if(res!=0){ + LOGW("Error updating NAT64 prefix: %d / %s", res, gai_strerror(res)); + }else{ + addrinfo* addrPtr; + unsigned char* addr170=NULL; + unsigned char* addr171=NULL; + for(addrPtr=addr0;addrPtr;addrPtr=addrPtr->ai_next){ + if(addrPtr->ai_family==AF_INET6){ + sockaddr_in6* translatedAddr=(sockaddr_in6*)addrPtr->ai_addr; + uint32_t v4part=*((uint32_t*)&translatedAddr->sin6_addr.s6_addr[12]); + if(v4part==0xAA0000C0 && !addr170){ + addr170=translatedAddr->sin6_addr.s6_addr; + } + if(v4part==0xAB0000C0 && !addr171){ + addr171=translatedAddr->sin6_addr.s6_addr; + } + char buf[INET6_ADDRSTRLEN]; + //LOGV("Got translated address: %s", inet_ntop(AF_INET6, &translatedAddr->sin6_addr, buf, sizeof(buf))); + } + } + if(addr170 && addr171 && memcmp(addr170, addr171, 12)==0){ + nat64Present=true; + memcpy(nat64Prefix, addr170, 12); + char buf[INET6_ADDRSTRLEN]; + //LOGV("Found nat64 prefix from %s", inet_ntop(AF_INET6, addr170, buf, sizeof(buf))); + }else{ + LOGV("Didn't find nat64"); + } + freeaddrinfo(addr0); + } + needUpdateNat64Prefix=false; + } + memset(&addr, 0, sizeof(sockaddr_in6)); + addr.sin6_family=AF_INET6; + *((uint32_t*)&addr.sin6_addr.s6_addr[12])=v4addr->GetAddress(); + if(nat64Present) + memcpy(addr.sin6_addr.s6_addr, nat64Prefix, 12); + else + addr.sin6_addr.s6_addr[11]=addr.sin6_addr.s6_addr[10]=0xFF; + + }else{ + IPv6Address* v6addr=dynamic_cast(packet->address); + assert(v6addr!=NULL); + if(!isAtLeastVista){ + return; + } + } + addr.sin6_port=htons(packet->port); + + //WSABUF wsaBuf; + //wsaBuf.buf=(char*) packet->data; + //wsaBuf.len=packet->length; + //int res=WSASendTo(fd, &wsaBuf, 1, NULL, 0, (const sockaddr*)&addr, sizeof(addr), NULL, NULL); + int res=sendto(fd, (char*)packet->data, packet->length, 0, (sockaddr*)&addr, sizeof(addr)); + if(res==SOCKET_ERROR){ + int error=WSAGetLastError(); + LOGE("error sending: %d", error); + if(error==WSAENETUNREACH && !isV4Available && VoIPController::GetCurrentTime()data; + //buf.len=packet->length; + //int res=WSARecvFrom(fd, &buf, 1, &len, 0, (sockaddr*) &srcAddr, &addrLen, NULL, NULL); + int res=recvfrom(fd, (char*)packet->data, packet->length, 0, addr, &addrLen); + if(res!=SOCKET_ERROR) + packet->length=(size_t) res; + else{ + packet->length=0; + int error=WSAGetLastError(); + LOGE("error receiving: %d", error); + return; + } + //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; + lastRecvdV4=IPv4Address(srcAddr4.sin_addr.s_addr); + packet->address=&lastRecvdV4; + }else{ + packet->port=srcAddr.sin6_port; + if(!isV4Available && IN6_IS_ADDR_V4MAPPED(&srcAddr.sin6_addr)){ + isV4Available=true; + LOGI("Detected IPv4 connectivity, will not try IPv6"); + } + if(IN6_IS_ADDR_V4MAPPED(&srcAddr.sin6_addr) || (nat64Present && memcmp(nat64Prefix, srcAddr.sin6_addr.s6_addr, 12)==0)){ + in_addr v4addr=*((in_addr *)&srcAddr.sin6_addr.s6_addr[12]); + lastRecvdV4=IPv4Address(v4addr.s_addr); + packet->address=&lastRecvdV4; + } + } +} + +void NetworkSocketWinsock::Open(){ + fd=socket(isAtLeastVista ? AF_INET6 : AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if(fd==INVALID_SOCKET){ + int error=WSAGetLastError(); + LOGE("error creating socket: %d", error); + failed=true; + return; + } + + int res; + if(isAtLeastVista){ + DWORD flag=0; + res=setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&flag, sizeof(flag)); + if(res==SOCKET_ERROR){ + LOGE("error enabling dual stack socket: %d", WSAGetLastError()); + failed=true; + return; + } + } + + SetMaxPriority(); + + int tries=0; + sockaddr* addr; + sockaddr_in addr4; + sockaddr_in6 addr6; + int addrLen; + if(isAtLeastVista){ + //addr.sin6_addr.s_addr=0; + memset(&addr6, 0, sizeof(sockaddr_in6)); + //addr.sin6_len=sizeof(sa_family_t); + addr6.sin6_family=AF_INET6; + addr=(sockaddr*)&addr6; + addrLen=sizeof(addr6); + }else{ + sockaddr_in addr4; + addr4.sin_addr.s_addr=0; + addr4.sin_family=AF_INET; + addr=(sockaddr*)&addr4; + addrLen=sizeof(addr4); + } + for(tries=0;tries<10;tries++){ + uint16_t port=htons(GenerateLocalPort()); + if(isAtLeastVista) + ((sockaddr_in6*)addr)->sin6_port=port; + else + ((sockaddr_in*)addr)->sin_port=port; + res=::bind(fd, addr, addrLen); + LOGV("trying bind to port %u", ntohs(port)); + if(res<0){ + LOGE("error binding to port %u: %d / %s", ntohs(port), errno, strerror(errno)); + }else{ + break; + } + } + if(tries==10){ + if(isAtLeastVista) + ((sockaddr_in6*)addr)->sin6_port=0; + else + ((sockaddr_in*)addr)->sin_port=0; + res=::bind(fd, addr, addrLen); + if(res<0){ + LOGE("error binding to port %u: %d / %s", 0, errno, strerror(errno)); + //SetState(STATE_FAILED); + return; + } + } + getsockname(fd, addr, (socklen_t*) &addrLen); + uint16_t localUdpPort; + if(isAtLeastVista) + localUdpPort=ntohs(((sockaddr_in6*)addr)->sin6_port); + else + localUdpPort=ntohs(((sockaddr_in*)addr)->sin_port); + LOGD("Bound to local UDP port %u", ntohs(localUdpPort)); + + needUpdateNat64Prefix=true; + isV4Available=false; + switchToV6at=VoIPController::GetCurrentTime()+ipv6Timeout; +} + +void NetworkSocketWinsock::Close(){ + closesocket(fd); +} + +void NetworkSocketWinsock::OnActiveInterfaceChanged(){ + needUpdateNat64Prefix=true; + isV4Available=false; + switchToV6at=VoIPController::GetCurrentTime()+ipv6Timeout; +} + +std::string NetworkSocketWinsock::GetLocalInterfaceInfo(IPv4Address *v4addr, IPv6Address *v6addr){ + IP_ADAPTER_ADDRESSES* addrs=(IP_ADAPTER_ADDRESSES*)malloc(15*1024); + ULONG size=15*1024; + ULONG flags=GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME; + + ULONG res=GetAdaptersAddresses(AF_UNSPEC, flags, NULL, addrs, &size); + if(res==ERROR_BUFFER_OVERFLOW){ + addrs=(IP_ADAPTER_ADDRESSES*)realloc(addrs, size); + res=GetAdaptersAddresses(AF_UNSPEC, flags, NULL, addrs, &size); + } + + ULONG bestMetric=0; + std::string bestName(""); + + if(res==ERROR_SUCCESS){ + IP_ADAPTER_ADDRESSES* current=addrs; + while(current){ + char* name=current->AdapterName; + LOGV("Adapter '%s':", name); + IP_ADAPTER_UNICAST_ADDRESS* curAddr=current->FirstUnicastAddress; + if(current->OperStatus!=IfOperStatusUp){ + LOGV("-> (down)"); + current=current->Next; + continue; + } + if(current->IfType==IF_TYPE_SOFTWARE_LOOPBACK){ + LOGV("-> (loopback)"); + current=current->Next; + continue; + } + if(isAtLeastVista) + LOGV("v4 metric: %u, v6 metric: %u", current->Ipv4Metric, current->Ipv6Metric); + while(curAddr){ + sockaddr* addr=curAddr->Address.lpSockaddr; + if(addr->sa_family==AF_INET && v4addr){ + sockaddr_in* ipv4=(sockaddr_in*)addr; + LOGV("-> V4: %s", V4AddressToString(ipv4->sin_addr.s_addr).c_str()); + uint32_t ip=ntohl(ipv4->sin_addr.s_addr); + if((ip & 0xFFFF0000)!=0xA9FE0000){ + if(isAtLeastVista){ + if(current->Ipv4Metric>bestMetric){ + bestMetric=current->Ipv4Metric; + bestName=std::string(current->AdapterName); + *v4addr=IPv4Address(ipv4->sin_addr.s_addr); + } + }else{ + bestName=std::string(current->AdapterName); + *v4addr=IPv4Address(ipv4->sin_addr.s_addr); + } + } + }else if(addr->sa_family==AF_INET6 && v6addr){ + sockaddr_in6* ipv6=(sockaddr_in6*)addr; + LOGV("-> V6: %s", V6AddressToString(ipv6->sin6_addr.s6_addr).c_str()); + if(!IN6_IS_ADDR_LINKLOCAL(&ipv6->sin6_addr)){ + *v6addr=IPv6Address(ipv6->sin6_addr.s6_addr); + } + } + curAddr=curAddr->Next; + } + current=current->Next; + } + } + + free(addrs); + return bestName; +} + +uint16_t NetworkSocketWinsock::GetLocalPort(){ + if(!isAtLeastVista){ + sockaddr_in addr; + size_t addrLen=sizeof(sockaddr_in); + getsockname(fd, (sockaddr*)&addr, (socklen_t*)&addrLen); + return ntohs(addr.sin_port); + } + sockaddr_in6 addr; + size_t addrLen=sizeof(sockaddr_in6); + getsockname(fd, (sockaddr*)&addr, (socklen_t*) &addrLen); + return ntohs(addr.sin6_port); +} + +std::string NetworkSocketWinsock::V4AddressToString(uint32_t address){ + char buf[INET_ADDRSTRLEN]; + sockaddr_in addr; + ZeroMemory(&addr, sizeof(addr)); + addr.sin_family=AF_INET; + addr.sin_addr.s_addr=address; + DWORD len=sizeof(buf); + WSAAddressToStringA((sockaddr*)&addr, sizeof(addr), NULL, buf, &len); + return std::string(buf); +} + +std::string NetworkSocketWinsock::V6AddressToString(unsigned char *address){ + char buf[INET6_ADDRSTRLEN]; + sockaddr_in6 addr; + ZeroMemory(&addr, sizeof(addr)); + addr.sin6_family=AF_INET6; + memcpy(addr.sin6_addr.s6_addr, address, 16); + DWORD len=sizeof(buf); + WSAAddressToStringA((sockaddr*)&addr, sizeof(addr), NULL, buf, &len); + return std::string(buf); +} + +uint32_t NetworkSocketWinsock::StringToV4Address(std::string address){ + sockaddr_in addr; + ZeroMemory(&addr, sizeof(addr)); + addr.sin_family=AF_INET; + int size=sizeof(addr); + WSAStringToAddressA((char*)address.c_str(), AF_INET, NULL, (sockaddr*)&addr, &size); + return addr.sin_addr.s_addr; +} + +void NetworkSocketWinsock::StringToV6Address(std::string address, unsigned char *out){ + sockaddr_in6 addr; + ZeroMemory(&addr, sizeof(addr)); + addr.sin6_family=AF_INET6; + int size=sizeof(addr); + WSAStringToAddressA((char*)address.c_str(), AF_INET6, NULL, (sockaddr*)&addr, &size); + memcpy(out, addr.sin6_addr.s6_addr, 16); +} diff --git a/os/windows/NetworkSocketWinsock.h b/os/windows/NetworkSocketWinsock.h new file mode 100644 index 0000000000..25369bc44f --- /dev/null +++ b/os/windows/NetworkSocketWinsock.h @@ -0,0 +1,46 @@ +// +// Created by Grishka on 10.04.17. +// + +#ifndef LIBTGVOIP_NETWORKSOCKETWINSOCK_H +#define LIBTGVOIP_NETWORKSOCKETWINSOCK_H + +#include "../../NetworkSocket.h" +#include + +namespace tgvoip { + +class NetworkSocketWinsock : public NetworkSocket{ +public: + NetworkSocketWinsock(); + virtual ~NetworkSocketWinsock(); + virtual void Send(NetworkPacket* packet); + virtual void Receive(NetworkPacket* packet); + virtual void Open(); + virtual void Close(); + virtual std::string GetLocalInterfaceInfo(IPv4Address* v4addr, IPv6Address* v6addr); + virtual void OnActiveInterfaceChanged(); + virtual uint16_t GetLocalPort(); + + static std::string V4AddressToString(uint32_t address); + static std::string V6AddressToString(unsigned char address[16]); + static uint32_t StringToV4Address(std::string address); + static void StringToV6Address(std::string address, unsigned char* out); + +protected: + virtual void SetMaxPriority(); + +private: + uintptr_t fd; + bool needUpdateNat64Prefix; + bool nat64Present; + double switchToV6at; + bool isV4Available; + IPv4Address lastRecvdV4; + bool isAtLeastVista; + +}; + +} + +#endif //LIBTGVOIP_NETWORKSOCKETWINSOCK_H diff --git a/threading.h b/threading.h index b568ced908..29e9a68a7a 100644 --- a/threading.h +++ b/threading.h @@ -35,6 +35,33 @@ typedef pthread_cond_t tgvoip_lock_t; #define wait_lock(lock, mutex) pthread_cond_wait(&lock, &mutex) #define notify_lock(lock) pthread_cond_broadcast(&lock) +#elif defined(_WIN32) + +#include +typedef HANDLE tgvoip_thread_t; +typedef CRITICAL_SECTION tgvoip_mutex_t; +typedef HANDLE tgvoip_lock_t; // uncomment for XP compatibility +//typedef CONDITION_VARIABLE tgvoip_lock_t; + +#define start_thread(ref, entry, arg) (ref=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)entry, arg, 0, NULL)) +#define join_thread(thread) {WaitForSingleObject(thread, INFINITE); CloseHandle(thread);} +#define set_thread_name(thread, name) // threads in Windows don't have names +#define set_thread_priority(thread, priority) SetThreadPriority(thread, priority) +#define get_thread_max_priority() THREAD_PRIORITY_HIGHEST +#define get_thread_min_priority() THREAD_PRIORITY_LOWEST +#define init_mutex(mutex) InitializeCriticalSection(&mutex) +#define free_mutex(mutex) DeleteCriticalSection(&mutex) +#define lock_mutex(mutex) EnterCriticalSection(&mutex) +#define unlock_mutex(mutex) LeaveCriticalSection(&mutex) +#define init_lock(lock) (lock=CreateEvent(NULL, false, false, NULL)) +#define free_lock(lock) CloseHandle(lock) +#define wait_lock(lock, mutex) {LeaveCriticalSection(&mutex); WaitForSingleObject(lock, INFINITE); EnterCriticalSection(&mutex);} +#define notify_lock(lock) PulseEvent(lock) +//#define init_lock(lock) InitializeConditionVariable(&lock) +//#define free_lock(lock) // ? +//#define wait_lock(lock, mutex) SleepConditionVariableCS(&lock, &mutex, INFINITE) +//#define notify_lock(lock) WakeAllConditionVariable(&lock) + #else #error "No threading implementation for your operating system" #endif diff --git a/webrtc_dsp/webrtc/modules/audio_processing/aec/aec_core_sse2.cc b/webrtc_dsp/webrtc/modules/audio_processing/aec/aec_core_sse2.cc index e58b9e0618..d7144f7888 100644 --- a/webrtc_dsp/webrtc/modules/audio_processing/aec/aec_core_sse2.cc +++ b/webrtc_dsp/webrtc/modules/audio_processing/aec/aec_core_sse2.cc @@ -11,7 +11,6 @@ /* * The core AEC algorithm, SSE2 version of speed-critical functions. */ -#if defined(WEBRTC_ARCH_X86_FAMILY) #include #include #include // memset @@ -23,6 +22,8 @@ extern "C" { #include "webrtc/modules/audio_processing/aec/aec_core_optimized_methods.h" #include "webrtc/modules/audio_processing/utility/ooura_fft.h" +#if defined(WEBRTC_ARCH_X86_FAMILY) + namespace webrtc { __inline static float MulRe(float aRe, float aIm, float bRe, float bIm) {