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
This commit is contained in:
Grishka 2017-04-17 21:57:07 +03:00
parent 88d22e82cf
commit bfde1a4be3
36 changed files with 2550 additions and 618 deletions

View File

@ -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)
include $(CLEAR_VARS)

View File

@ -8,6 +8,7 @@
#define LIBTGVOIP_BUFFEROUTPUTSTREAM_H
#include <stdlib.h>
#include <stdint.h>
class CBufferOutputStream{

View File

@ -11,6 +11,8 @@
#include <math.h>
#include <assert.h>
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(inflightAvg<min){
lastActionTime=CVoIPController::GetCurrentTime();
lastActionTime=VoIPController::GetCurrentTime();
return TGVOIP_CONCTL_ACT_INCREASE;
}
if(inflightAvg>max){
lastActionTime=CVoIPController::GetCurrentTime();
lastActionTime=VoIPController::GetCurrentTime();
return TGVOIP_CONCTL_ACT_DECREASE;
}
return TGVOIP_CONCTL_ACT_NONE;

View File

@ -8,6 +8,7 @@
#define LIBTGVOIP_CONGESTIONCONTROL_H
#include <stdlib.h>
#include <stdint.h>
#include "threading.h"
#define TGVOIP_CONCTL_STARTUP 0

View File

@ -10,12 +10,17 @@
#include <string.h>
#include <stdio.h>
#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) (x<max ? (x>min ? 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);
}

View File

@ -10,6 +10,8 @@
#include "VoIPServerConfig.h"
#include <math.h>
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);

142
NetworkSocket.cpp Normal file
View File

@ -0,0 +1,142 @@
//
// Created by Grishka on 29.03.17.
//
#include "NetworkSocket.h"
#include <stdexcept>
#include <stdlib.h>
#include <string.h>
#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<IPv4Address*>(this);
IPv4Address* other4=dynamic_cast<IPv4Address*>((NetworkAddress*)&other);
if(self4 && other4){
return self4->GetAddress()==other4->GetAddress();
}
IPv6Address* self6=dynamic_cast<IPv6Address*>(this);
IPv6Address* other6=dynamic_cast<IPv6Address*>((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;
}
}

76
NetworkSocket.h Normal file
View File

@ -0,0 +1,76 @@
//
// Created by Grishka on 29.03.17.
//
#ifndef LIBTGVOIP_NETWORKSOCKET_H
#define LIBTGVOIP_NETWORKSOCKET_H
#include <stdint.h>
#include <string>
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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -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 <arpa/inet.h>
#include <netinet/in.h>
#endif
#ifdef __APPLE__
#include <TargetConditionals.h>
#endif
#include <stdint.h>
#include <vector>
#include <string>
@ -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)) || ((s1<s2) && (s2-s1>SEQ_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<Endpoint> 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<voip_endpoint_t*> endpoints;
voip_endpoint_t* currentEndpoint;
voip_endpoint_t* preferredRelay;
voip_endpoint_t* peerPreferredRelay;
std::vector<Endpoint*> endpoints;
Endpoint* currentEndpoint;
Endpoint* preferredRelay;
Endpoint* peerPreferredRelay;
bool runReceiver;
uint32_t seq;
uint32_t lastRemoteSeq;
@ -265,6 +292,7 @@ private:
CEchoCanceller* echoCanceller;
std::vector<CBufferOutputStream*> 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<voip_stream_t*> outgoingStreams;
std::vector<voip_stream_t*> 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<voip_queued_packet_t*> queuedPackets;
tgvoip_mutex_t queuedPacketsMutex;
@ -314,13 +337,8 @@ private:
bool receivedInitAck;
std::vector<std::string> 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

View File

@ -8,23 +8,25 @@
#include <stdlib.h>
#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<std::string, std::string> newValues){
void ServerConfig::Update(std::map<std::string, std::string> newValues){
CMutexGuard sync(mutex);
LOGD("=== Updating voip config ===");
config.clear();
@ -83,7 +85,7 @@ void CVoIPServerConfig::Update(std::map<std::string, std::string> newValues){
}
}
void CVoIPServerConfig::Update(const char **values, int count) {
void ServerConfig::Update(const char **values, int count) {
std::map<std::string, std::string> 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();
}

View File

@ -11,12 +11,13 @@
#include <string>
#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<std::string, std::string> config;
tgvoip_mutex_t mutex;
};
}
#endif //TGVOIP_VOIPSERVERCONFIG_H

View File

@ -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
}

View File

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

View File

@ -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;
};

View File

@ -9,6 +9,7 @@
#include <wchar.h>
#include <map>
#include <string>
#include <vector>
#include <libtgvoip/VoIPServerConfig.h>
#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<Endpoint> 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());
}

333
libtgvoip.gyp Normal file
View File

@ -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': [
],
},
},
],
],
},
],
}

View File

@ -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 = "<group>"; };
69015D891E9D846F00AC9763 /* NetworkSocketPosix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkSocketPosix.h; sourceTree = "<group>"; };
69015D921E9D848700AC9763 /* NetworkSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkSocket.cpp; sourceTree = "<group>"; };
69015D931E9D848700AC9763 /* NetworkSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkSocket.h; sourceTree = "<group>"; };
6915307A1E6B5BAB004F643F /* logging.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = logging.cpp; sourceTree = "<group>"; };
692AB8881E6759DD00706ACC /* AudioInput.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AudioInput.cpp; sourceTree = "<group>"; };
692AB8891E6759DD00706ACC /* AudioInput.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioInput.h; sourceTree = "<group>"; };
@ -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 = "<group>";
};
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";

View File

@ -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 <windows.h>
#include <stdio.h>
#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 <stdio.h>

View File

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

View File

@ -1,6 +1,6 @@
#import <Foundation/Foundation.h>
#import "ASCommon.h"
#import <ASCommon.h>
void __tgvoip_call_tglog(char* format, ...){
va_list args;

View File

@ -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 <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <dlfcn.h>
#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));
}
}

46
os/linux/AudioInputALSA.h Normal file
View File

@ -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 <alsa/asoundlib.h>
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

View File

@ -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 <assert.h>
#include <dlfcn.h>
#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;
}
}
}

View File

@ -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 <alsa/asoundlib.h>
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

View File

@ -0,0 +1,282 @@
//
// Created by Grishka on 10.04.17.
//
#include "NetworkSocketPosix.h"
#include <sys/socket.h>
#include <errno.h>
#include <assert.h>
#include <netdb.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <unistd.h>
#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<IPv4Address*>(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<IPv6Address*>(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()<switchToV6at){
switchToV6at=VoIPController::GetCurrentTime();
LOGI("Network unreachable, trying NAT64");
}
}
}
void NetworkSocketPosix::Receive(NetworkPacket *packet){
int addrLen=sizeof(sockaddr_in6);
sockaddr_in6 srcAddr;
ssize_t len=recvfrom(fd, packet->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;i<ifc.ifc_len;){
#ifndef __linux__
len=IFNAMSIZ + ifr->ifr_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);
}

View File

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

View File

@ -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 <stdlib.h>
#include <stdio.h>
#include <assert.h>
#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");
}

View File

@ -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 <windows.h>
#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

View File

@ -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 <assert.h>
#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));
}

View File

@ -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 <windows.h>
#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

View File

@ -0,0 +1,375 @@
//
// Created by Grishka on 10.04.17.
//
#include "NetworkSocketWinsock.h"
#include <winsock2.h>
#include <ws2tcpip.h>
#include <IPHlpApi.h>
#include <assert.h>
#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<IPv4Address*>(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<IPv6Address*>(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()<switchToV6at){
switchToV6at=VoIPController::GetCurrentTime();
LOGI("Network unreachable, trying NAT64");
}
}
}
void NetworkSocketWinsock::Receive(NetworkPacket *packet){
sockaddr_in6 srcAddr;
sockaddr_in srcAddr4;
sockaddr* addr;
int addrLen;
if(isAtLeastVista){
addr=(sockaddr*)&srcAddr;
addrLen=sizeof(srcAddr);
}else{
addr=(sockaddr*)&srcAddr4;
addrLen=sizeof(srcAddr4);
}
//DWORD len;
//WSABUF buf;
//buf.buf=(char*) packet->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);
}

View File

@ -0,0 +1,46 @@
//
// Created by Grishka on 10.04.17.
//
#ifndef LIBTGVOIP_NETWORKSOCKETWINSOCK_H
#define LIBTGVOIP_NETWORKSOCKETWINSOCK_H
#include "../../NetworkSocket.h"
#include <stdint.h>
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

View File

@ -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 <Windows.h>
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

View File

@ -11,7 +11,6 @@
/*
* The core AEC algorithm, SSE2 version of speed-critical functions.
*/
#if defined(WEBRTC_ARCH_X86_FAMILY)
#include <emmintrin.h>
#include <math.h>
#include <string.h> // 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) {