diff --git a/BlockingQueue.cpp b/BlockingQueue.cpp index 70c8a8ece7..f307f3a2b7 100644 --- a/BlockingQueue.cpp +++ b/BlockingQueue.cpp @@ -6,30 +6,25 @@ #include "BlockingQueue.h" -CBlockingQueue::CBlockingQueue(size_t capacity){ +using namespace tgvoip; + +BlockingQueue::BlockingQueue(size_t capacity) : semaphore(capacity, 0){ this->capacity=capacity; overflowCallback=NULL; - init_lock(lock); init_mutex(mutex); } -CBlockingQueue::~CBlockingQueue(){ - lock_mutex(mutex); - notify_lock(lock); - unlock_mutex(mutex); - lock_mutex(mutex); - unlock_mutex(mutex); - free_lock(lock); +BlockingQueue::~BlockingQueue(){ + semaphore.Release(); free_mutex(mutex); } -void CBlockingQueue::Put(void *thing){ - lock_mutex(mutex); - if(queue.empty()){ - notify_lock(lock); - } +void BlockingQueue::Put(void *thing){ + MutexGuard sync(mutex); queue.push_back(thing); + bool didOverflow=false; while(queue.size()>capacity){ + didOverflow=true; if(overflowCallback){ overflowCallback(queue.front()); queue.pop_front(); @@ -37,28 +32,27 @@ void CBlockingQueue::Put(void *thing){ abort(); } } - unlock_mutex(mutex); + if(!didOverflow) + semaphore.Release(); } -void *CBlockingQueue::GetBlocking(){ - lock_mutex(mutex); - while(queue.empty()){ - wait_lock(lock, mutex); - } +void *BlockingQueue::GetBlocking(){ + semaphore.Acquire(); + MutexGuard sync(mutex); void* r=GetInternal(); - unlock_mutex(mutex); return r; } -void *CBlockingQueue::Get(){ - lock_mutex(mutex); +void *BlockingQueue::Get(){ + MutexGuard sync(mutex); + if(queue.size()>0) + semaphore.Acquire(); void* r=GetInternal(); - unlock_mutex(mutex); return r; } -void *CBlockingQueue::GetInternal(){ +void *BlockingQueue::GetInternal(){ if(queue.size()==0) return NULL; void* r=queue.front(); @@ -67,18 +61,16 @@ void *CBlockingQueue::GetInternal(){ } -unsigned int CBlockingQueue::Size(){ +unsigned int BlockingQueue::Size(){ return queue.size(); } -void CBlockingQueue::PrepareDealloc(){ - lock_mutex(mutex); - notify_lock(lock); - unlock_mutex(mutex); +void BlockingQueue::PrepareDealloc(){ + } -void CBlockingQueue::SetOverflowCallback(void (*overflowCallback)(void *)){ +void BlockingQueue::SetOverflowCallback(void (*overflowCallback)(void *)){ this->overflowCallback=overflowCallback; } diff --git a/BlockingQueue.h b/BlockingQueue.h index 3ed40fed83..df3fb8b8e4 100644 --- a/BlockingQueue.h +++ b/BlockingQueue.h @@ -13,10 +13,11 @@ using namespace std; -class CBlockingQueue{ +namespace tgvoip{ +class BlockingQueue{ public: - CBlockingQueue(size_t capacity); - ~CBlockingQueue(); + BlockingQueue(size_t capacity); + ~BlockingQueue(); void Put(void* thing); void* GetBlocking(); void* Get(); @@ -28,10 +29,11 @@ private: void* GetInternal(); list queue; size_t capacity; - tgvoip_lock_t lock; + //tgvoip_lock_t lock; + Semaphore semaphore; tgvoip_mutex_t mutex; void (*overflowCallback)(void*); }; - +} #endif //LIBTGVOIP_BLOCKINGQUEUE_H diff --git a/BufferInputStream.cpp b/BufferInputStream.cpp index ce2ef5bb89..f4858bf450 100644 --- a/BufferInputStream.cpp +++ b/BufferInputStream.cpp @@ -10,42 +10,44 @@ #include #include -CBufferInputStream::CBufferInputStream(unsigned char* data, size_t length){ +using namespace tgvoip; + +BufferInputStream::BufferInputStream(unsigned char* data, size_t length){ this->buffer=data; this->length=length; offset=0; } -CBufferInputStream::~CBufferInputStream(){ +BufferInputStream::~BufferInputStream(){ } -void CBufferInputStream::Seek(size_t offset){ +void BufferInputStream::Seek(size_t offset){ if(offset>length){ throw std::out_of_range("Not enough bytes in buffer"); } this->offset=offset; } -size_t CBufferInputStream::GetLength(){ +size_t BufferInputStream::GetLength(){ return length; } -size_t CBufferInputStream::GetOffset(){ +size_t BufferInputStream::GetOffset(){ return offset; } -size_t CBufferInputStream::Remaining(){ +size_t BufferInputStream::Remaining(){ return length-offset; } -unsigned char CBufferInputStream::ReadByte(){ +unsigned char BufferInputStream::ReadByte(){ EnsureEnoughRemaining(1); return (unsigned char)buffer[offset++]; } -int32_t CBufferInputStream::ReadInt32(){ +int32_t BufferInputStream::ReadInt32(){ EnsureEnoughRemaining(4); int32_t res=((int32_t)buffer[offset] & 0xFF) | (((int32_t)buffer[offset+1] & 0xFF) << 8) | @@ -55,7 +57,7 @@ int32_t CBufferInputStream::ReadInt32(){ return res; } -int64_t CBufferInputStream::ReadInt64(){ +int64_t BufferInputStream::ReadInt64(){ EnsureEnoughRemaining(8); int64_t res=((int64_t)buffer[offset] & 0xFF) | (((int64_t)buffer[offset+1] & 0xFF) << 8) | @@ -69,7 +71,7 @@ int64_t CBufferInputStream::ReadInt64(){ return res; } -int16_t CBufferInputStream::ReadInt16(){ +int16_t BufferInputStream::ReadInt16(){ EnsureEnoughRemaining(2); int16_t res=(uint16_t)buffer[offset] | ((uint16_t)buffer[offset+1] << 8); offset+=2; @@ -77,7 +79,7 @@ int16_t CBufferInputStream::ReadInt16(){ } -int32_t CBufferInputStream::ReadTlLength(){ +int32_t BufferInputStream::ReadTlLength(){ unsigned char l=ReadByte(); if(l<254) return l; @@ -90,14 +92,14 @@ int32_t CBufferInputStream::ReadTlLength(){ return res; } -void CBufferInputStream::ReadBytes(unsigned char *to, size_t count){ +void BufferInputStream::ReadBytes(unsigned char *to, size_t count){ EnsureEnoughRemaining(count); memcpy(to, buffer+offset, count); offset+=count; } -void CBufferInputStream::EnsureEnoughRemaining(size_t need){ +void BufferInputStream::EnsureEnoughRemaining(size_t need){ if(length-offset #include -class CBufferInputStream{ +namespace tgvoip{ +class BufferInputStream{ public: - CBufferInputStream(unsigned char* data, size_t length); - ~CBufferInputStream(); + BufferInputStream(unsigned char* data, size_t length); + ~BufferInputStream(); void Seek(size_t offset); size_t GetLength(); size_t GetOffset(); @@ -32,6 +33,6 @@ private: size_t length; size_t offset; }; - +} #endif //LIBTGVOIP_BUFFERINPUTSTREAM_H diff --git a/BufferOutputStream.cpp b/BufferOutputStream.cpp index 035d03c705..e6a7ebf629 100644 --- a/BufferOutputStream.cpp +++ b/BufferOutputStream.cpp @@ -7,22 +7,24 @@ #include "BufferOutputStream.h" #include -CBufferOutputStream::CBufferOutputStream(size_t size){ +using namespace tgvoip; + +BufferOutputStream::BufferOutputStream(size_t size){ buffer=(unsigned char*) malloc(size); offset=0; this->size=size; } -CBufferOutputStream::~CBufferOutputStream(){ +BufferOutputStream::~BufferOutputStream(){ free(buffer); } -void CBufferOutputStream::WriteByte(unsigned char byte){ +void BufferOutputStream::WriteByte(unsigned char byte){ this->ExpandBufferIfNeeded(1); buffer[offset++]=byte; } -void CBufferOutputStream::WriteInt32(int32_t i){ +void BufferOutputStream::WriteInt32(int32_t i){ this->ExpandBufferIfNeeded(4); buffer[offset+3]=(unsigned char)((i >> 24) & 0xFF); buffer[offset+2]=(unsigned char)((i >> 16) & 0xFF); @@ -31,7 +33,7 @@ void CBufferOutputStream::WriteInt32(int32_t i){ offset+=4; } -void CBufferOutputStream::WriteInt64(int64_t i){ +void BufferOutputStream::WriteInt64(int64_t i){ this->ExpandBufferIfNeeded(8); buffer[offset+7]=(unsigned char)((i >> 56) & 0xFF); buffer[offset+6]=(unsigned char)((i >> 48) & 0xFF); @@ -44,28 +46,28 @@ void CBufferOutputStream::WriteInt64(int64_t i){ offset+=8; } -void CBufferOutputStream::WriteInt16(int16_t i){ +void BufferOutputStream::WriteInt16(int16_t i){ this->ExpandBufferIfNeeded(2); buffer[offset+1]=(unsigned char)((i >> 8) & 0xFF); buffer[offset]=(unsigned char)(i & 0xFF); offset+=2; } -void CBufferOutputStream::WriteBytes(unsigned char *bytes, size_t count){ +void BufferOutputStream::WriteBytes(unsigned char *bytes, size_t count){ this->ExpandBufferIfNeeded(count); memcpy(buffer+offset, bytes, count); offset+=count; } -unsigned char *CBufferOutputStream::GetBuffer(){ +unsigned char *BufferOutputStream::GetBuffer(){ return buffer; } -size_t CBufferOutputStream::GetLength(){ +size_t BufferOutputStream::GetLength(){ return offset; } -void CBufferOutputStream::ExpandBufferIfNeeded(size_t need){ +void BufferOutputStream::ExpandBufferIfNeeded(size_t need){ if(offset+need>size){ if(need<1024){ buffer=(unsigned char *) realloc(buffer, size+1024); @@ -78,7 +80,7 @@ void CBufferOutputStream::ExpandBufferIfNeeded(size_t need){ } -void CBufferOutputStream::Reset(){ +void BufferOutputStream::Reset(){ offset=0; } diff --git a/BufferOutputStream.h b/BufferOutputStream.h index ed58dbf38a..a93195ddc4 100644 --- a/BufferOutputStream.h +++ b/BufferOutputStream.h @@ -10,11 +10,12 @@ #include #include -class CBufferOutputStream{ +namespace tgvoip{ +class BufferOutputStream{ public: - CBufferOutputStream(size_t size); - ~CBufferOutputStream(); + BufferOutputStream(size_t size); + ~BufferOutputStream(); void WriteByte(unsigned char byte); void WriteInt64(int64_t i); void WriteInt32(int32_t i); @@ -30,6 +31,6 @@ private: size_t size; size_t offset; }; - +} #endif //LIBTGVOIP_BUFFEROUTPUTSTREAM_H diff --git a/BufferPool.cpp b/BufferPool.cpp index 9e48140e23..b9c5080aba 100644 --- a/BufferPool.cpp +++ b/BufferPool.cpp @@ -9,7 +9,9 @@ #include #include -CBufferPool::CBufferPool(unsigned int size, unsigned int count){ +using namespace tgvoip; + +BufferPool::BufferPool(unsigned int size, unsigned int count){ assert(count<=64); init_mutex(mutex); buffers[0]=(unsigned char*) malloc(size*count); @@ -21,12 +23,12 @@ CBufferPool::CBufferPool(unsigned int size, unsigned int count){ usedBuffers=0; } -CBufferPool::~CBufferPool(){ +BufferPool::~BufferPool(){ free_mutex(mutex); free(buffers[0]); } -unsigned char* CBufferPool::Get(){ +unsigned char* BufferPool::Get(){ lock_mutex(mutex); int i; for(i=0;i #include "threading.h" -class CBufferPool{ +namespace tgvoip{ +class BufferPool{ public: - CBufferPool(unsigned int size, unsigned int count); - ~CBufferPool(); + BufferPool(unsigned int size, unsigned int count); + ~BufferPool(); unsigned char* Get(); void Reuse(unsigned char* buffer); @@ -23,6 +24,6 @@ private: unsigned char* buffers[64]; tgvoip_mutex_t mutex; }; - +} #endif //LIBTGVOIP_BUFFERPOOL_H diff --git a/CongestionControl.cpp b/CongestionControl.cpp index 5f8f666729..0bed069d31 100644 --- a/CongestionControl.cpp +++ b/CongestionControl.cpp @@ -13,10 +13,10 @@ using namespace tgvoip; -CCongestionControl::CCongestionControl(){ - memset(rttHistory, 0, 100*sizeof(double)); - memset(inflightPackets, 0, 100*sizeof(tgvoip_congestionctl_packet_t)); - memset(inflightHistory, 0, 30*sizeof(size_t)); +CongestionControl::CongestionControl(){ + memset(rttHistory, 0, sizeof(rttHistory)); + memset(inflightPackets, 0, sizeof(inflightPackets)); + memset(inflightHistory, 0, sizeof(inflightHistory)); tmpRtt=0; tmpRttCount=0; rttHistorySize=0; @@ -33,15 +33,15 @@ CCongestionControl::CCongestionControl(){ init_mutex(mutex); } -CCongestionControl::~CCongestionControl(){ +CongestionControl::~CongestionControl(){ free_mutex(mutex); } -size_t CCongestionControl::GetAcknowledgedDataSize(){ +size_t CongestionControl::GetAcknowledgedDataSize(){ return 0; } -double CCongestionControl::GetAverageRTT(){ +double CongestionControl::GetAverageRTT(){ if(rttHistorySize==0) return 0; double avg=0; @@ -54,7 +54,7 @@ double CCongestionControl::GetAverageRTT(){ return avg/i; } -size_t CCongestionControl::GetInflightDataSize(){ +size_t CongestionControl::GetInflightDataSize(){ size_t avg=0; int i; for(i=0;i<30;i++){ @@ -64,11 +64,11 @@ size_t CCongestionControl::GetInflightDataSize(){ } -size_t CCongestionControl::GetCongestionWindow(){ +size_t CongestionControl::GetCongestionWindow(){ return cwnd; } -double CCongestionControl::GetMinimumRTT(){ +double CongestionControl::GetMinimumRTT(){ int i; double min=INFINITY; for(i=0;i<100;i++){ @@ -78,8 +78,8 @@ double CCongestionControl::GetMinimumRTT(){ return min; } -void CCongestionControl::PacketAcknowledged(uint32_t seq){ - lock_mutex(mutex); +void CongestionControl::PacketAcknowledged(uint32_t seq){ + MutexGuard sync(mutex); int i; for(i=0;i<100;i++){ if(inflightPackets[i].seq==seq && inflightPackets[i].sendTime>0){ @@ -90,16 +90,15 @@ void CCongestionControl::PacketAcknowledged(uint32_t seq){ break; } } - unlock_mutex(mutex); } -void CCongestionControl::PacketSent(uint32_t seq, size_t size){ +void CongestionControl::PacketSent(uint32_t seq, size_t size){ if(!seqgt(seq, lastSentSeq) || seq==lastSentSeq){ LOGW("Duplicate outgoing seq %u", seq); return; } lastSentSeq=seq; - lock_mutex(mutex); + MutexGuard sync(mutex); double smallestSendTime=INFINITY; tgvoip_congestionctl_packet_t* slot=NULL; int i; @@ -123,13 +122,12 @@ void CCongestionControl::PacketSent(uint32_t seq, size_t size){ slot->size=size; slot->sendTime=VoIPController::GetCurrentTime(); inflightDataSize+=size; - unlock_mutex(mutex); } -void CCongestionControl::Tick(){ +void CongestionControl::Tick(){ tickCount++; - lock_mutex(mutex); + MutexGuard sync(mutex); if(tmpRttCount>0){ rttHistory[rttHistoryTop]=tmpRtt/tmpRttCount; rttHistoryTop=(rttHistoryTop+1)%100; @@ -149,11 +147,10 @@ void CCongestionControl::Tick(){ } inflightHistory[inflightHistoryTop]=inflightDataSize; inflightHistoryTop=(inflightHistoryTop+1)%30; - unlock_mutex(mutex); } -int CCongestionControl::GetBandwidthControlAction(){ +int CongestionControl::GetBandwidthControlAction(){ if(VoIPController::GetCurrentTime()-lastActionTime<1) return TGVOIP_CONCTL_ACT_NONE; size_t inflightAvg=GetInflightDataSize(); @@ -171,6 +168,6 @@ int CCongestionControl::GetBandwidthControlAction(){ } -uint32_t CCongestionControl::GetSendLossCount(){ +uint32_t CongestionControl::GetSendLossCount(){ return lossCount; } diff --git a/CongestionControl.h b/CongestionControl.h index c659268cad..2890f0a654 100644 --- a/CongestionControl.h +++ b/CongestionControl.h @@ -20,6 +20,8 @@ #define TGVOIP_CONCTL_ACT_DECREASE 2 #define TGVOIP_CONCTL_ACT_NONE 0 +namespace tgvoip{ + struct tgvoip_congestionctl_packet_t{ uint32_t seq; double sendTime; @@ -27,10 +29,10 @@ struct tgvoip_congestionctl_packet_t{ }; typedef struct tgvoip_congestionctl_packet_t tgvoip_congestionctl_packet_t; -class CCongestionControl{ +class CongestionControl{ public: - CCongestionControl(); - ~CCongestionControl(); + CongestionControl(); + ~CongestionControl(); void PacketSent(uint32_t seq, size_t size); void PacketAcknowledged(uint32_t seq); @@ -64,6 +66,6 @@ private: size_t cwnd; tgvoip_mutex_t mutex; }; - +} #endif //LIBTGVOIP_CONGESTIONCONTROL_H diff --git a/EchoCanceller.cpp b/EchoCanceller.cpp index 62ee5856fb..d224ee6f17 100644 --- a/EchoCanceller.cpp +++ b/EchoCanceller.cpp @@ -30,13 +30,15 @@ //#define CLAMP(x, min, max) (xmin ? x : min) : max) #define CLAMP(x, min, max) x +using namespace tgvoip; + #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){ +EchoCanceller::EchoCanceller(bool enableAEC, bool enableNS, bool enableAGC){ this->enableAEC=enableAEC; this->enableAGC=enableAGC; this->enableNS=enableNS; @@ -72,11 +74,11 @@ CEchoCanceller::CEchoCanceller(bool enableAEC, bool enableNS, bool enableAGC){ webrtc::WebRtcAec_set_config(aec, config); #endif - farendQueue=new CBlockingQueue(11); - farendBufferPool=new CBufferPool(960*2, 10); + farendQueue=new BlockingQueue(11); + farendBufferPool=new BufferPool(960*2, 10); running=true; - start_thread(bufferFarendThread, CEchoCanceller::StartBufferFarendThread, this); + start_thread(bufferFarendThread, EchoCanceller::StartBufferFarendThread, this); } if(enableNS){ @@ -108,7 +110,7 @@ CEchoCanceller::CEchoCanceller(bool enableAEC, bool enableNS, bool enableAGC){ #endif } -CEchoCanceller::~CEchoCanceller(){ +EchoCanceller::~EchoCanceller(){ if(enableAEC){ running=false; farendQueue->Put(NULL); @@ -146,16 +148,16 @@ CEchoCanceller::~CEchoCanceller(){ } } -void CEchoCanceller::Start(){ +void EchoCanceller::Start(){ } -void CEchoCanceller::Stop(){ +void EchoCanceller::Stop(){ } -void CEchoCanceller::SpeakerOutCallback(unsigned char* data, size_t len){ +void EchoCanceller::SpeakerOutCallback(unsigned char* data, size_t len){ if(len!=960*2 || !enableAEC) return; /*size_t offset=0; @@ -170,12 +172,12 @@ void CEchoCanceller::SpeakerOutCallback(unsigned char* data, size_t len){ } } -void *CEchoCanceller::StartBufferFarendThread(void *arg){ - ((CEchoCanceller*)arg)->RunBufferFarendThread(); +void *EchoCanceller::StartBufferFarendThread(void *arg){ + ((EchoCanceller*)arg)->RunBufferFarendThread(); return NULL; } -void CEchoCanceller::RunBufferFarendThread(){ +void EchoCanceller::RunBufferFarendThread(){ while(running){ int16_t* samplesIn=(int16_t *) farendQueue->GetBlocking(); if(samplesIn){ @@ -198,11 +200,11 @@ void CEchoCanceller::RunBufferFarendThread(){ } } -void CEchoCanceller::Enable(bool enabled){ +void EchoCanceller::Enable(bool enabled){ //isOn=enabled; } -void CEchoCanceller::ProcessInput(unsigned char* data, unsigned char* out, size_t len){ +void EchoCanceller::ProcessInput(unsigned char* data, unsigned char* out, size_t len){ int i; if(!enableAEC && !enableAGC && !enableNS){ memcpy(out, data, len); @@ -260,14 +262,14 @@ void CEchoCanceller::ProcessInput(unsigned char* data, unsigned char* out, size_ memcpy(bufOut->ibuf()->bands(0)[1], _nsOut[1], 320*2*2); lock_mutex(aecMutex); - WebRtcAecm_Process(aec, bufOut->ibuf()->bands(0)[0], _nsOut[0], samplesOut, AEC_FRAME_SIZE, (int16_t) CAudioOutput::GetEstimatedDelay()); - WebRtcAecm_Process(aec, bufOut->ibuf()->bands(0)[0]+160, _nsOut[0]+160, samplesOut+160, AEC_FRAME_SIZE, (int16_t) CAudioOutput::GetEstimatedDelay()); + WebRtcAecm_Process(aec, bufOut->ibuf()->bands(0)[0], _nsOut[0], samplesOut, AEC_FRAME_SIZE, (int16_t) tgvoip::audio::AudioOutput::GetEstimatedDelay()); + WebRtcAecm_Process(aec, bufOut->ibuf()->bands(0)[0]+160, _nsOut[0]+160, samplesOut+160, AEC_FRAME_SIZE, (int16_t) tgvoip::audio::AudioOutput::GetEstimatedDelay()); unlock_mutex(aecMutex); memcpy(bufOut->ibuf()->bands(0)[0], samplesOut, 320*2); }else if(enableAEC){ lock_mutex(aecMutex); - WebRtcAecm_Process(aec, bufOut->ibuf()->bands(0)[0], NULL, samplesOut, AEC_FRAME_SIZE, (int16_t) CAudioOutput::GetEstimatedDelay()); - WebRtcAecm_Process(aec, bufOut->ibuf()->bands(0)[0]+160, NULL, samplesOut+160, AEC_FRAME_SIZE, (int16_t) CAudioOutput::GetEstimatedDelay()); + WebRtcAecm_Process(aec, bufOut->ibuf()->bands(0)[0], NULL, samplesOut, AEC_FRAME_SIZE, (int16_t) tgvoip::audio::AudioOutput::GetEstimatedDelay()); + WebRtcAecm_Process(aec, bufOut->ibuf()->bands(0)[0]+160, NULL, samplesOut+160, AEC_FRAME_SIZE, (int16_t) tgvoip::audio::AudioOutput::GetEstimatedDelay()); unlock_mutex(aecMutex); memcpy(bufOut->ibuf()->bands(0)[0], samplesOut, 320*2); }else if(enableNS){ @@ -337,12 +339,12 @@ void CEchoCanceller::ProcessInput(unsigned char* data, unsigned char* out, size_ 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); + webrtc::WebRtcAec_Process(aec, aecIn, 3, aecOut, AEC_FRAME_SIZE, audio::AudioOutput::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); + webrtc::WebRtcAec_Process(aec, aecIn, 3, aecOut, AEC_FRAME_SIZE, audio::AudioOutput::GetEstimatedDelay(), 0); memcpy(bufOut->fbuf()->bands(0)[0], _aecOut[0], 320*4); memcpy(bufOut->fbuf()->bands(0)[1], _aecOut[1], 320*4); diff --git a/EchoCanceller.h b/EchoCanceller.h index 46c636f58e..601aafa265 100644 --- a/EchoCanceller.h +++ b/EchoCanceller.h @@ -11,11 +11,12 @@ #include "BufferPool.h" #include "BlockingQueue.h" -class CEchoCanceller{ +namespace tgvoip{ +class EchoCanceller{ public: - CEchoCanceller(bool enableAEC, bool enableNS, bool enableAGC); - virtual ~CEchoCanceller(); + EchoCanceller(bool enableAEC, bool enableNS, bool enableAGC); + virtual ~EchoCanceller(); virtual void Start(); virtual void Stop(); void SpeakerOutCallback(unsigned char* data, size_t len); @@ -39,14 +40,14 @@ private: void* splittingFilterFarendIn; // webrtc::IFChannelBuffer void* splittingFilterFarendOut; // webrtc::IFChannelBuffer tgvoip_thread_t bufferFarendThread; - CBlockingQueue* farendQueue; - CBufferPool* farendBufferPool; + BlockingQueue* farendQueue; + BufferPool* farendBufferPool; bool running; void* ns; // NsxHandle void* agc; int32_t agcMicLevel; #endif }; - +} #endif //LIBTGVOIP_ECHOCANCELLER_H diff --git a/JitterBuffer.cpp b/JitterBuffer.cpp index 83de340417..ba6afa31b2 100644 --- a/JitterBuffer.cpp +++ b/JitterBuffer.cpp @@ -12,9 +12,9 @@ using namespace tgvoip; -CJitterBuffer::CJitterBuffer(CMediaStreamItf *out, uint32_t step):bufferPool(JITTER_SLOT_SIZE, JITTER_SLOT_COUNT){ +JitterBuffer::JitterBuffer(MediaStreamItf *out, uint32_t step):bufferPool(JITTER_SLOT_SIZE, JITTER_SLOT_COUNT){ if(out) - out->SetCallback(CJitterBuffer::CallbackOut, this); + out->SetCallback(JitterBuffer::CallbackOut, this); this->step=step; memset(slots, 0, sizeof(jitter_packet_t)*JITTER_SLOT_COUNT); minDelay=6; @@ -43,32 +43,32 @@ CJitterBuffer::CJitterBuffer(CMediaStreamItf *out, uint32_t step):bufferPool(JIT init_mutex(mutex); } -CJitterBuffer::~CJitterBuffer(){ +JitterBuffer::~JitterBuffer(){ Reset(); free_mutex(mutex); } -void CJitterBuffer::SetMinPacketCount(uint32_t count){ +void JitterBuffer::SetMinPacketCount(uint32_t count){ if(minDelay==count) return; minDelay=count; Reset(); } -int CJitterBuffer::GetMinPacketCount(){ +int JitterBuffer::GetMinPacketCount(){ return minDelay; } -size_t CJitterBuffer::CallbackIn(unsigned char *data, size_t len, void *param){ - //((CJitterBuffer*)param)->HandleInput(data, len); +size_t JitterBuffer::CallbackIn(unsigned char *data, size_t len, void *param){ + //((JitterBuffer*)param)->HandleInput(data, len); return 0; } -size_t CJitterBuffer::CallbackOut(unsigned char *data, size_t len, void *param){ - return ((CJitterBuffer*)param)->HandleOutput(data, len, 0); +size_t JitterBuffer::CallbackOut(unsigned char *data, size_t len, void *param){ + return ((JitterBuffer*)param)->HandleOutput(data, len, 0); } -void CJitterBuffer::HandleInput(unsigned char *data, size_t len, uint32_t timestamp){ +void JitterBuffer::HandleInput(unsigned char *data, size_t len, uint32_t timestamp){ jitter_packet_t pkt; pkt.size=len; pkt.buffer=data; @@ -79,7 +79,7 @@ void CJitterBuffer::HandleInput(unsigned char *data, size_t len, uint32_t timest //LOGV("in, ts=%d", timestamp); } -void CJitterBuffer::Reset(){ +void JitterBuffer::Reset(){ wasReset=true; needBuffering=true; lastPutTimestamp=0; @@ -101,7 +101,7 @@ void CJitterBuffer::Reset(){ } -size_t CJitterBuffer::HandleOutput(unsigned char *buffer, size_t len, int offsetInSteps){ +size_t JitterBuffer::HandleOutput(unsigned char *buffer, size_t len, int offsetInSteps){ jitter_packet_t pkt; pkt.buffer=buffer; pkt.size=len; @@ -116,7 +116,7 @@ size_t CJitterBuffer::HandleOutput(unsigned char *buffer, size_t len, int offset } -int CJitterBuffer::GetInternal(jitter_packet_t* pkt, int offset){ +int JitterBuffer::GetInternal(jitter_packet_t* pkt, int offset){ /*if(needBuffering && lastPutTimestampsize>JITTER_SLOT_SIZE){ LOGE("The packet is too big to fit into the jitter buffer"); return; @@ -264,12 +264,12 @@ void CJitterBuffer::PutInternal(jitter_packet_t* pkt){ } -void CJitterBuffer::Advance(){ +void JitterBuffer::Advance(){ nextTimestamp+=step; } -int CJitterBuffer::GetCurrentDelay(){ +int JitterBuffer::GetCurrentDelay(){ int delay=0; int i; for(i=0;i -class CMediaStreamItf{ +namespace tgvoip{ +class MediaStreamItf{ public: virtual void Start()=0; virtual void Stop()=0; @@ -22,6 +23,7 @@ private: size_t (*callback)(unsigned char*, size_t, void*); void* callbackParam; }; +} #endif //LIBTGVOIP_MEDIASTREAMINPUT_H diff --git a/OpusDecoder.cpp b/OpusDecoder.cpp index 56bdb42c58..36d8de36bf 100644 --- a/OpusDecoder.cpp +++ b/OpusDecoder.cpp @@ -10,9 +10,11 @@ #define PACKET_SIZE (960*2) -COpusDecoder::COpusDecoder(CMediaStreamItf *dst){ +using namespace tgvoip; + +tgvoip::OpusDecoder::OpusDecoder(MediaStreamItf *dst) : semaphore(32, 0){ //this->source=source; - dst->SetCallback(COpusDecoder::Callback, this); + dst->SetCallback(OpusDecoder::Callback, this); dec=opus_decoder_create(48000, 1, NULL); //test=fopen("/sdcard/test.raw", "wb"); buffer=(unsigned char *) malloc(4096); @@ -20,15 +22,14 @@ COpusDecoder::COpusDecoder(CMediaStreamItf *dst){ lastDecoded=NULL; lastDecodedLen=0; outputBufferSize=0; - packetsNeeded=0; lastDecodedOffset=0; - decodedQueue=new CBlockingQueue(33); - bufferPool=new CBufferPool(PACKET_SIZE, 32); + decodedQueue=new BlockingQueue(33); + bufferPool=new BufferPool(PACKET_SIZE, 32); echoCanceller=NULL; frameDuration=20; } -COpusDecoder::~COpusDecoder(){ +tgvoip::OpusDecoder::~OpusDecoder(){ opus_decoder_destroy(dec); free(buffer); delete bufferPool; @@ -36,30 +37,29 @@ COpusDecoder::~COpusDecoder(){ } -void COpusDecoder::SetEchoCanceller(CEchoCanceller* canceller){ +void tgvoip::OpusDecoder::SetEchoCanceller(EchoCanceller* canceller){ echoCanceller=canceller; } -size_t COpusDecoder::Callback(unsigned char *data, size_t len, void *param){ - ((COpusDecoder*)param)->HandleCallback(data, len); +size_t tgvoip::OpusDecoder::Callback(unsigned char *data, size_t len, void *param){ + ((OpusDecoder*)param)->HandleCallback(data, len); return 0; } -void COpusDecoder::HandleCallback(unsigned char *data, size_t len){ +void tgvoip::OpusDecoder::HandleCallback(unsigned char *data, size_t len){ if(!running){ memset(data, 0, len); return; } if(outputBufferSize==0){ outputBufferSize=len; + int packetsNeeded; if(len>PACKET_SIZE) packetsNeeded=len/PACKET_SIZE; else packetsNeeded=1; packetsNeeded*=2; - lock_mutex(mutex); - notify_lock(lock); - unlock_mutex(mutex); + semaphore.Release(packetsNeeded); } assert(outputBufferSize==len && "output buffer size is supposed to be the same throughout callbacks"); if(len>PACKET_SIZE){ @@ -72,19 +72,13 @@ void COpusDecoder::HandleCallback(unsigned char *data, size_t len){ echoCanceller->SpeakerOutCallback(data, PACKET_SIZE); bufferPool->Reuse(lastDecoded); } - lock_mutex(mutex); - packetsNeeded+=count; - if(packetsNeeded>0) - notify_lock(lock); - unlock_mutex(mutex); + semaphore.Release(count); }else if(len==PACKET_SIZE){ lastDecoded=(unsigned char*) decodedQueue->GetBlocking(); memcpy(data, lastDecoded, PACKET_SIZE); bufferPool->Reuse(lastDecoded); + semaphore.Release(); lock_mutex(mutex); - packetsNeeded+=1; - if(packetsNeeded>0) - notify_lock(lock); if(echoCanceller) echoCanceller->SpeakerOutCallback(data, PACKET_SIZE); unlock_mutex(mutex); @@ -102,14 +96,10 @@ void COpusDecoder::HandleCallback(unsigned char *data, size_t len){ lastDecodedOffset=0; bufferPool->Reuse(lastDecoded); //LOGV("before req packet, qsize=%d", decodedQueue->Size()); - lock_mutex(mutex); if(decodedQueue->Size()==0) - packetsNeeded+=2; + semaphore.Release(2); else - packetsNeeded+=1; - if(packetsNeeded>0) - notify_lock(lock); - unlock_mutex(mutex); + semaphore.Release(); } } /*if(lastDecodedLen){ @@ -144,35 +134,30 @@ void COpusDecoder::HandleCallback(unsigned char *data, size_t len){ } -void COpusDecoder::Start(){ - init_lock(lock); +void tgvoip::OpusDecoder::Start(){ init_mutex(mutex); running=true; - start_thread(thread, COpusDecoder::StartThread, this); + start_thread(thread, OpusDecoder::StartThread, this); set_thread_priority(thread, get_thread_max_priority()); set_thread_name(thread, "opus_decoder"); } -void COpusDecoder::Stop(){ +void tgvoip::OpusDecoder::Stop(){ if(!running) return; running=false; - lock_mutex(mutex); - notify_lock(lock); - unlock_mutex(mutex); + semaphore.Release(); join_thread(thread); - free_lock(lock); free_mutex(mutex); } -void* COpusDecoder::StartThread(void *param){ - ((COpusDecoder*)param)->RunThread(); +void* tgvoip::OpusDecoder::StartThread(void *param){ + ((tgvoip::OpusDecoder*)param)->RunThread(); return NULL; } -void COpusDecoder::RunThread(){ - //FILE* test=fopen("/sdcard/test.raw", "w"); +void tgvoip::OpusDecoder::RunThread(){ unsigned char nextBuffer[8192]; unsigned char decodeBuffer[8192]; int i; @@ -181,14 +166,8 @@ void COpusDecoder::RunThread(){ LOGI("decoder: packets per frame %d", packetsPerFrame); size_t nextLen=0; while(running){ - lock_mutex(mutex); - if(packetsNeeded<=0) - wait_lock(lock, mutex); - unlock_mutex(mutex); //LOGV("after wait, running=%d", running); if(!running){ - //fclose(test); - //unlock_mutex(mutex); LOGI("==== decoder exiting ===="); return; } @@ -220,6 +199,7 @@ void COpusDecoder::RunThread(){ LOGW("decoder: opus_decode error %d", size); //LOGV("After decode, size=%d", size); for(i=0;iGet(); if(buf){ if(size>0){ @@ -232,21 +212,18 @@ void COpusDecoder::RunThread(){ }else{ LOGW("decoder: no buffers left!"); } - lock_mutex(mutex); - packetsNeeded--; - unlock_mutex(mutex); //LOGD("packets needed: %d", packetsNeeded); } } } -void COpusDecoder::SetFrameDuration(uint32_t duration){ +void tgvoip::OpusDecoder::SetFrameDuration(uint32_t duration){ frameDuration=duration; } -void COpusDecoder::ResetQueue(){ +void tgvoip::OpusDecoder::ResetQueue(){ /*lock_mutex(mutex); packetsNeeded=0; unlock_mutex(mutex); @@ -256,6 +233,6 @@ void COpusDecoder::ResetQueue(){ } -void COpusDecoder::SetJitterBuffer(CJitterBuffer* jitterBuffer){ +void tgvoip::OpusDecoder::SetJitterBuffer(JitterBuffer* jitterBuffer){ this->jitterBuffer=jitterBuffer; } diff --git a/OpusDecoder.h b/OpusDecoder.h index ce92452f9f..6e12933dcc 100644 --- a/OpusDecoder.h +++ b/OpusDecoder.h @@ -17,40 +17,40 @@ #include "JitterBuffer.h" #include -class COpusDecoder { +namespace tgvoip{ +class OpusDecoder { public: virtual void Start(); virtual void Stop(); - COpusDecoder(CMediaStreamItf* dst); - virtual ~COpusDecoder(); + OpusDecoder(MediaStreamItf* dst); + virtual ~OpusDecoder(); void HandleCallback(unsigned char* data, size_t len); - void SetEchoCanceller(CEchoCanceller* canceller); + void SetEchoCanceller(EchoCanceller* canceller); void SetFrameDuration(uint32_t duration); void ResetQueue(); - void SetJitterBuffer(CJitterBuffer* jitterBuffer); + void SetJitterBuffer(JitterBuffer* jitterBuffer); private: static size_t Callback(unsigned char* data, size_t len, void* param); static void* StartThread(void* param); void RunThread(); - OpusDecoder* dec; - CBlockingQueue* decodedQueue; - CBufferPool* bufferPool; + ::OpusDecoder* dec; + BlockingQueue* decodedQueue; + BufferPool* bufferPool; unsigned char* buffer; unsigned char* lastDecoded; size_t lastDecodedLen, lastDecodedOffset; - int packetsNeeded; size_t outputBufferSize; bool running; tgvoip_thread_t thread; - tgvoip_lock_t lock; + Semaphore semaphore; tgvoip_mutex_t mutex; uint32_t frameDuration; - CEchoCanceller* echoCanceller; - CJitterBuffer* jitterBuffer; + EchoCanceller* echoCanceller; + JitterBuffer* jitterBuffer; }; - +} #endif //LIBTGVOIP_OPUSDECODER_H diff --git a/OpusEncoder.cpp b/OpusEncoder.cpp index eb12328ae5..0939b42bd8 100644 --- a/OpusEncoder.cpp +++ b/OpusEncoder.cpp @@ -9,11 +9,9 @@ #include "logging.h" #include "VoIPServerConfig.h" -using namespace tgvoip; - -COpusEncoder::COpusEncoder(CMediaStreamItf *source):queue(11), bufferPool(960*2, 10){ +tgvoip::OpusEncoder::OpusEncoder(MediaStreamItf *source):queue(11), bufferPool(960*2, 10){ this->source=source; - source->SetCallback(COpusEncoder::Callback, this); + source->SetCallback(tgvoip::OpusEncoder::Callback, this); enc=opus_encoder_create(48000, 1, OPUS_APPLICATION_VOIP, NULL); opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(10)); opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(15)); @@ -32,11 +30,11 @@ COpusEncoder::COpusEncoder(CMediaStreamItf *source):queue(11), bufferPool(960*2, strongCorrectionMultiplier=ServerConfig::GetSharedInstance()->GetDouble("audio_strong_fec_multiplier", 2.0); } -COpusEncoder::~COpusEncoder(){ +tgvoip::OpusEncoder::~OpusEncoder(){ opus_encoder_destroy(enc); } -void COpusEncoder::Start(){ +void tgvoip::OpusEncoder::Start(){ if(running) return; running=true; @@ -45,7 +43,7 @@ void COpusEncoder::Start(){ set_thread_name(thread, "opus_encoder"); } -void COpusEncoder::Stop(){ +void tgvoip::OpusEncoder::Stop(){ if(!running) return; running=false; @@ -54,11 +52,11 @@ void COpusEncoder::Stop(){ } -void COpusEncoder::SetBitrate(uint32_t bitrate){ +void tgvoip::OpusEncoder::SetBitrate(uint32_t bitrate){ requestedBitrate=bitrate; } -void COpusEncoder::Encode(unsigned char *data, size_t len){ +void tgvoip::OpusEncoder::Encode(unsigned char *data, size_t len){ if(requestedBitrate!=currentBitrate){ opus_encoder_ctl(enc, OPUS_SET_BITRATE(requestedBitrate)); currentBitrate=requestedBitrate; @@ -75,8 +73,8 @@ void COpusEncoder::Encode(unsigned char *data, size_t len){ } } -size_t COpusEncoder::Callback(unsigned char *data, size_t len, void* param){ - COpusEncoder* e=(COpusEncoder*)param; +size_t tgvoip::OpusEncoder::Callback(unsigned char *data, size_t len, void* param){ + OpusEncoder* e=(OpusEncoder*)param; unsigned char* buf=e->bufferPool.Get(); if(buf){ assert(len==960*2); @@ -93,20 +91,20 @@ size_t COpusEncoder::Callback(unsigned char *data, size_t len, void* param){ } -uint32_t COpusEncoder::GetBitrate(){ +uint32_t tgvoip::OpusEncoder::GetBitrate(){ return requestedBitrate; } -void COpusEncoder::SetEchoCanceller(CEchoCanceller* aec){ +void tgvoip::OpusEncoder::SetEchoCanceller(EchoCanceller* aec){ echoCanceller=aec; } -void* COpusEncoder::StartThread(void* arg){ - ((COpusEncoder*)arg)->RunThread(); +void* tgvoip::OpusEncoder::StartThread(void* arg){ + ((OpusEncoder*)arg)->RunThread(); return NULL; } -void COpusEncoder::RunThread(){ +void tgvoip::OpusEncoder::RunThread(){ unsigned char buf[960*2]; uint32_t bufferedCount=0; uint32_t packetsPerFrame=frameDuration/20; @@ -141,12 +139,12 @@ void COpusEncoder::RunThread(){ } -void COpusEncoder::SetOutputFrameDuration(uint32_t duration){ +void tgvoip::OpusEncoder::SetOutputFrameDuration(uint32_t duration){ frameDuration=duration; } -void COpusEncoder::SetPacketLoss(int percent){ +void tgvoip::OpusEncoder::SetPacketLoss(int percent){ packetLossPercent=percent; double multiplier=1; if(currentBitrate<=strongCorrectionBitrate) @@ -157,6 +155,6 @@ void COpusEncoder::SetPacketLoss(int percent){ opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(percent>17 ? OPUS_AUTO : OPUS_BANDWIDTH_FULLBAND)); } -int COpusEncoder::GetPacketLoss(){ +int tgvoip::OpusEncoder::GetPacketLoss(){ return packetLossPercent; } diff --git a/OpusEncoder.h b/OpusEncoder.h index 0e1fb17ce2..09e9be77fe 100644 --- a/OpusEncoder.h +++ b/OpusEncoder.h @@ -17,14 +17,15 @@ #include -class COpusEncoder : public CMediaStreamItf{ +namespace tgvoip{ +class OpusEncoder : public MediaStreamItf{ public: - COpusEncoder(CMediaStreamItf* source); - virtual ~COpusEncoder(); + OpusEncoder(MediaStreamItf* source); + virtual ~OpusEncoder(); virtual void Start(); virtual void Stop(); void SetBitrate(uint32_t bitrate); - void SetEchoCanceller(CEchoCanceller* aec); + void SetEchoCanceller(EchoCanceller* aec); void SetOutputFrameDuration(uint32_t duration); void SetPacketLoss(int percent); int GetPacketLoss(); @@ -35,15 +36,15 @@ private: static void* StartThread(void* arg); void RunThread(); void Encode(unsigned char* data, size_t len); - CMediaStreamItf* source; - OpusEncoder* enc; + MediaStreamItf* source; + ::OpusEncoder* enc; unsigned char buffer[4096]; uint32_t requestedBitrate; uint32_t currentBitrate; tgvoip_thread_t thread; - CBlockingQueue queue; - CBufferPool bufferPool; - CEchoCanceller* echoCanceller; + BlockingQueue queue; + BufferPool bufferPool; + EchoCanceller* echoCanceller; int complexity; bool running; uint32_t frameDuration; @@ -53,6 +54,6 @@ private: double mediumCorrectionMultiplier; double strongCorrectionMultiplier; }; - +} #endif //LIBTGVOIP_OPUSENCODER_H diff --git a/VoIPController.cpp b/VoIPController.cpp index 743e374f29..abc5761afa 100644 --- a/VoIPController.cpp +++ b/VoIPController.cpp @@ -91,7 +91,7 @@ voip_crypto_functions_t VoIPController::crypto; // set it yourself upon initiali extern FILE* tgvoipLogFile; -VoIPController::VoIPController() : activeNetItfName(""){ +VoIPController::VoIPController() : activeNetItfName(""), currentAudioInput("default"), currentAudioOutput("default"){ seq=1; lastRemoteSeq=0; state=STATE_WAIT_INIT; @@ -106,9 +106,9 @@ VoIPController::VoIPController() : activeNetItfName(""){ stopping=false; int i; for(i=0;i<20;i++){ - emptySendBuffers.push_back(new CBufferOutputStream(1024)); + emptySendBuffers.push_back(new BufferOutputStream(1024)); } - sendQueue=new CBlockingQueue(21); + sendQueue=new BlockingQueue(21); init_mutex(sendBufferMutex); memset(remoteAcks, 0, sizeof(double)*32); memset(sentPacketTimes, 0, sizeof(double)*32); @@ -140,11 +140,12 @@ VoIPController::VoIPController() : activeNetItfName(""){ lastRecvPacketTime=0; dataSavingRequestedByPeer=false; peerVersion=0; - conctl=new CCongestionControl(); + conctl=new CongestionControl(); prevSendLossCount=0; receivedInit=false; receivedInitAck=false; peerPreferredRelay=NULL; + statsDump=NULL; socket=NetworkSocket::Create(); @@ -209,7 +210,7 @@ VoIPController::~VoIPController(){ while(sendQueue->Size()>0){ void* p=sendQueue->Get(); if(p) - delete (CBufferOutputStream*)p; + delete (BufferOutputStream*)p; } LOGD("before delete jitter buffer"); if(jitterBuffer){ @@ -267,6 +268,8 @@ VoIPController::~VoIPController(){ tgvoipLogFile=NULL; fclose(log); } + if(statsDump) + fclose(statsDump); } void VoIPController::SetRemoteEndpoints(std::vector endpoints, bool allowP2p){ @@ -337,7 +340,7 @@ void VoIPController::HandleAudioInput(unsigned char *data, size_t len){ return; } int audioPacketGrouping=1; - CBufferOutputStream* pkt=NULL; + BufferOutputStream* pkt=NULL; if(audioPacketsWritten==0){ pkt=GetOutgoingPacketBuffer(); if(!pkt){ @@ -405,7 +408,7 @@ void VoIPController::SetEncryptionKey(char *key, bool isOutgoing){ this->isOutgoing=isOutgoing; } -uint32_t VoIPController::WritePacketHeader(CBufferOutputStream *s, unsigned char type, uint32_t length){ +uint32_t VoIPController::WritePacketHeader(BufferOutputStream *s, unsigned char type, uint32_t length){ uint32_t acks=0; int i; for(i=0;i<32;i++){ @@ -512,7 +515,7 @@ void VoIPController::UpdateAudioBitrate(){ void VoIPController::SendInit(){ - CBufferOutputStream* out=new CBufferOutputStream(1024); + BufferOutputStream* out=new BufferOutputStream(1024); WritePacketHeader(out, PKT_INIT, 15); out->WriteInt32(PROTOCOL_VERSION); out->WriteInt32(MIN_PROTOCOL_VERSION); @@ -578,19 +581,19 @@ void VoIPController::RunRecvThread(){ stats.bytesRecvdMobile+=(uint64_t)len; else stats.bytesRecvdWifi+=(uint64_t)len; - CBufferInputStream* in=new CBufferInputStream(buffer, (size_t)len); + BufferInputStream in(buffer, (size_t)len); try{ if(memcmp(buffer, srcEndpoint->type==EP_TYPE_UDP_RELAY ? srcEndpoint->peerTag : callID, 16)!=0){ LOGW("Received packet has wrong peerTag"); - delete in; + continue; } - in->Seek(16); - if(waitingForRelayPeerInfo && in->Remaining()>=32){ + in.Seek(16); + if(waitingForRelayPeerInfo && in.Remaining()>=32){ bool isPublicIpResponse=true; int i; for(i=0;i<12;i++){ - if((unsigned char)buffer[in->GetOffset()+i]!=0xFF){ + if((unsigned char)buffer[in.GetOffset()+i]!=0xFF){ isPublicIpResponse=false; break; } @@ -598,14 +601,14 @@ void VoIPController::RunRecvThread(){ if(isPublicIpResponse){ waitingForRelayPeerInfo=false; - in->Seek(in->GetOffset()+12); - uint32_t tlid=(uint32_t) in->ReadInt32(); + in.Seek(in.GetOffset()+12); + uint32_t tlid=(uint32_t) in.ReadInt32(); if(tlid==TLID_UDP_REFLECTOR_PEER_INFO){ lock_mutex(endpointsMutex); - uint32_t myAddr=(uint32_t) in->ReadInt32(); - uint32_t myPort=(uint32_t) in->ReadInt32(); - uint32_t peerAddr=(uint32_t) in->ReadInt32(); - uint32_t peerPort=(uint32_t) in->ReadInt32(); + uint32_t myAddr=(uint32_t) in.ReadInt32(); + uint32_t myPort=(uint32_t) in.ReadInt32(); + uint32_t peerAddr=(uint32_t) in.ReadInt32(); + uint32_t peerPort=(uint32_t) in.ReadInt32(); for(std::vector::iterator itrtr=endpoints.begin();itrtr!=endpoints.end();++itrtr){ if((*itrtr)->type==EP_TYPE_UDP_P2P_INET){ delete *itrtr; @@ -630,7 +633,7 @@ void VoIPController::RunRecvThread(){ IPv4Address lanAddr(0); socket->GetLocalInterfaceInfo(&lanAddr, NULL); - CBufferOutputStream pkt(8); + BufferOutputStream pkt(8); pkt.WriteInt32(lanAddr.GetAddress()); pkt.WriteInt32(socket->GetLocalPort()); SendPacketReliably(PKT_LAN_ENDPOINT, pkt.GetBuffer(), pkt.GetLength(), 0.5, 10); @@ -639,36 +642,36 @@ void VoIPController::RunRecvThread(){ }else{ LOGE("It looks like a reflector response but tlid is %08X, expected %08X", tlid, TLID_UDP_REFLECTOR_PEER_INFO); } - delete in; + continue; } } - if(in->Remaining()<40){ - delete in; + if(in.Remaining()<40){ + continue; } unsigned char fingerprint[8], msgHash[16]; - in->ReadBytes(fingerprint, 8); - in->ReadBytes(msgHash, 16); + in.ReadBytes(fingerprint, 8); + in.ReadBytes(msgHash, 16); if(memcmp(fingerprint, keyFingerprint, 8)!=0){ LOGW("Received packet has wrong key fingerprint"); - delete in; + continue; } unsigned char key[32], iv[32]; KDF(msgHash, isOutgoing ? 8 : 0, key, iv); - unsigned char aesOut[MSC_STACK_FALLBACK(in->Remaining(), 1024)]; - crypto.aes_ige_decrypt((unsigned char *) buffer+in->GetOffset(), aesOut, in->Remaining(), key, iv); - memcpy(buffer+in->GetOffset(), aesOut, in->Remaining()); + unsigned char aesOut[MSC_STACK_FALLBACK(in.Remaining(), 1024)]; + crypto.aes_ige_decrypt((unsigned char *) buffer+in.GetOffset(), aesOut, in.Remaining(), key, iv); + memcpy(buffer+in.GetOffset(), aesOut, in.Remaining()); unsigned char sha[SHA1_LENGTH]; - uint32_t _len=(uint32_t) in->ReadInt32(); - if(_len>in->Remaining()) - _len=in->Remaining(); - crypto.sha1((uint8_t *) (buffer+in->GetOffset()-4), (size_t) (_len+4), sha); + uint32_t _len=(uint32_t) in.ReadInt32(); + if(_len>in.Remaining()) + _len=in.Remaining(); + crypto.sha1((uint8_t *) (buffer+in.GetOffset()-4), (size_t) (_len+4), sha); if(memcmp(msgHash, sha+(SHA1_LENGTH-16), 16)!=0){ LOGW("Received packet has wrong hash after decryption"); - delete in; + continue; } @@ -681,62 +684,62 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA */ uint32_t ackId, pseq, acks; unsigned char type; - uint32_t tlid=(uint32_t) in->ReadInt32(); + uint32_t tlid=(uint32_t) in.ReadInt32(); uint32_t packetInnerLen; if(tlid==TLID_DECRYPTED_AUDIO_BLOCK){ - in->ReadInt64(); // random id - uint32_t randLen=(uint32_t) in->ReadTlLength(); - in->Seek(in->GetOffset()+randLen+pad4(randLen)); - uint32_t flags=(uint32_t) in->ReadInt32(); + in.ReadInt64(); // random id + uint32_t randLen=(uint32_t) in.ReadTlLength(); + in.Seek(in.GetOffset()+randLen+pad4(randLen)); + uint32_t flags=(uint32_t) in.ReadInt32(); type=(unsigned char) ((flags >> 24) & 0xFF); if(!(flags & PFLAG_HAS_SEQ && flags & PFLAG_HAS_RECENT_RECV)){ LOGW("Received packet doesn't have PFLAG_HAS_SEQ, PFLAG_HAS_RECENT_RECV, or both"); - delete in; + continue; } if(flags & PFLAG_HAS_CALL_ID){ unsigned char pktCallID[16]; - in->ReadBytes(pktCallID, 16); + in.ReadBytes(pktCallID, 16); if(memcmp(pktCallID, callID, 16)!=0){ LOGW("Received packet has wrong call id"); - delete in; + lastError=TGVOIP_ERROR_UNKNOWN; SetState(STATE_FAILED); return; } } - ackId=(uint32_t) in->ReadInt32(); - pseq=(uint32_t) in->ReadInt32(); - acks=(uint32_t) in->ReadInt32(); + ackId=(uint32_t) in.ReadInt32(); + pseq=(uint32_t) in.ReadInt32(); + acks=(uint32_t) in.ReadInt32(); if(flags & PFLAG_HAS_PROTO){ - uint32_t proto=(uint32_t) in->ReadInt32(); + uint32_t proto=(uint32_t) in.ReadInt32(); if(proto!=PROTOCOL_NAME){ LOGW("Received packet uses wrong protocol"); - delete in; + lastError=TGVOIP_ERROR_INCOMPATIBLE; SetState(STATE_FAILED); return; } } if(flags & PFLAG_HAS_EXTRA){ - uint32_t extraLen=(uint32_t) in->ReadTlLength(); - in->Seek(in->GetOffset()+extraLen+pad4(extraLen)); + uint32_t extraLen=(uint32_t) in.ReadTlLength(); + in.Seek(in.GetOffset()+extraLen+pad4(extraLen)); } if(flags & PFLAG_HAS_DATA){ - packetInnerLen=in->ReadTlLength(); + packetInnerLen=in.ReadTlLength(); } }else if(tlid==TLID_SIMPLE_AUDIO_BLOCK){ - in->ReadInt64(); // random id - uint32_t randLen=(uint32_t) in->ReadTlLength(); - in->Seek(in->GetOffset()+randLen+pad4(randLen)); - packetInnerLen=in->ReadTlLength(); - type=in->ReadByte(); - ackId=(uint32_t) in->ReadInt32(); - pseq=(uint32_t) in->ReadInt32(); - acks=(uint32_t) in->ReadInt32(); + in.ReadInt64(); // random id + uint32_t randLen=(uint32_t) in.ReadTlLength(); + in.Seek(in.GetOffset()+randLen+pad4(randLen)); + packetInnerLen=in.ReadTlLength(); + type=in.ReadByte(); + ackId=(uint32_t) in.ReadInt32(); + pseq=(uint32_t) in.ReadInt32(); + acks=(uint32_t) in.ReadInt32(); }else{ LOGW("Received a packet of unknown type %08X", tlid); - delete in; + continue; } packetsRecieved++; @@ -755,13 +758,13 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA }else if(!seqgt(pseq, lastRemoteSeq) && lastRemoteSeq-pseq<32){ if(recvPacketTimes[lastRemoteSeq-pseq]!=0){ LOGW("Received duplicated packet for seq %u", pseq); - delete in; + continue; } recvPacketTimes[lastRemoteSeq-pseq]=GetCurrentTime(); }else if(lastRemoteSeq-pseq>=32){ LOGW("Packet %u is out of order and too late", pseq); - delete in; + continue; } if(seqgt(ackId, lastRemoteAckSeq)){ @@ -842,16 +845,16 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA preferredRelay=srcEndpoint; LogDebugInfo(); } - peerVersion=(uint32_t) in->ReadInt32(); + peerVersion=(uint32_t) in.ReadInt32(); LOGI("Peer version is %d", peerVersion); - uint32_t minVer=(uint32_t) in->ReadInt32(); + uint32_t minVer=(uint32_t) in.ReadInt32(); if(minVer>PROTOCOL_VERSION || peerVersionReadInt32(); + uint32_t flags=(uint32_t) in.ReadInt32(); if(flags & INIT_FLAG_DATA_SAVING_ENABLED){ dataSavingRequestedByPeer=true; UpdateDataSavingState(); @@ -859,16 +862,16 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA } int i; - int numSupportedAudioCodecs=in->ReadByte(); + int numSupportedAudioCodecs=in.ReadByte(); for(i=0; iReadByte(); // ignore for now + in.ReadByte(); // ignore for now } - int numSupportedVideoCodecs=in->ReadByte(); + int numSupportedVideoCodecs=in.ReadByte(); for(i=0; iReadByte(); // ignore for now + in.ReadByte(); // ignore for now } - CBufferOutputStream *out=new CBufferOutputStream(1024); + BufferOutputStream *out=new BufferOutputStream(1024); WritePacketHeader(out, PKT_INIT_ACK, (peerVersion>=2 ? 10 : 2)+(peerVersion>=2 ? 6 : 4)*outgoingStreams.size()); if(peerVersion>=2){ out->WriteInt32(PROTOCOL_VERSION); @@ -895,11 +898,11 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA if(!receivedInitAck){ receivedInitAck=true; if(packetInnerLen>10){ - peerVersion=in->ReadInt32(); - uint32_t minVer=(uint32_t) in->ReadInt32(); + peerVersion=in.ReadInt32(); + uint32_t minVer=(uint32_t) in.ReadInt32(); if(minVer>PROTOCOL_VERSION || peerVersionReadByte(); + unsigned char streamCount=in.ReadByte(); if(streamCount==0) - goto malformed_packet; + continue; int i; voip_stream_t *incomingAudioStream=NULL; for(i=0; iid=in->ReadByte(); - stm->type=in->ReadByte(); - stm->codec=in->ReadByte(); + stm->id=in.ReadByte(); + stm->type=in.ReadByte(); + stm->codec=in.ReadByte(); if(peerVersion>=2) - stm->frameDuration=(uint16_t) in->ReadInt16(); + stm->frameDuration=(uint16_t) in.ReadInt16(); else stm->frameDuration=20; - stm->enabled=in->ReadByte()==1; + stm->enabled=in.ReadByte()==1; incomingStreams.push_back(stm); if(stm->type==STREAM_TYPE_AUDIO && !incomingAudioStream) incomingAudioStream=stm; } if(!incomingAudioStream) - goto malformed_packet; + continue; voip_stream_t *outgoingAudioStream=outgoingStreams[0]; if(!audioInput){ LOGI("before create audio io"); - audioInput=CAudioInput::Create(); + audioInput=tgvoip::audio::AudioInput::Create(currentAudioInput); audioInput->Configure(48000, 16, 1); - audioOutput=CAudioOutput::Create(); + audioOutput=tgvoip::audio::AudioOutput::Create(currentAudioOutput); audioOutput->Configure(48000, 16, 1); - echoCanceller=new CEchoCanceller(config.enableAEC, config.enableNS, config.enableAGC); - encoder=new COpusEncoder(audioInput); + echoCanceller=new EchoCanceller(config.enableAEC, config.enableNS, config.enableAGC); + encoder=new OpusEncoder(audioInput); encoder->SetCallback(AudioInputCallback, this); encoder->SetOutputFrameDuration(outgoingAudioStream->frameDuration); encoder->SetEchoCanceller(echoCanceller); @@ -949,16 +952,24 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA if(!micMuted){ audioInput->Start(); if(!audioInput->IsInitialized()){ + LOGE("Erorr initializing audio capture"); lastError=TGVOIP_ERROR_AUDIO_IO; - delete in; + SetState(STATE_FAILED); return; } } + if(!audioOutput->IsInitialized()){ + LOGE("Erorr initializing audio playback"); + lastError=TGVOIP_ERROR_AUDIO_IO; + + SetState(STATE_FAILED); + return; + } UpdateAudioBitrate(); - jitterBuffer=new CJitterBuffer(NULL, incomingAudioStream->frameDuration); - decoder=new COpusDecoder(audioOutput); + jitterBuffer=new JitterBuffer(NULL, incomingAudioStream->frameDuration); + decoder=new OpusDecoder(audioOutput); decoder->SetEchoCanceller(echoCanceller); decoder->SetJitterBuffer(jitterBuffer); decoder->SetFrameDuration(incomingAudioStream->frameDuration); @@ -978,7 +989,7 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA needNotifyAcquiredAudioSession=true; }); }else{ - CAudioUnitIO::AudioSessionAcquired(); + audio::AudioUnitIO::AudioSessionAcquired(); } #endif #endif @@ -1007,41 +1018,41 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA peerPreferredRelay=srcEndpoint; } for(i=0;iReadByte(); + unsigned char streamID=in.ReadByte(); unsigned char flags=(unsigned char) (streamID & 0xC0); - uint16_t sdlen=(uint16_t) (flags & STREAM_DATA_FLAG_LEN16 ? in->ReadInt16() : in->ReadByte()); - uint32_t pts=(uint32_t) in->ReadInt32(); - //LOGD("stream data, pts=%d, len=%d, rem=%d", pts, sdlen, in->Remaining()); + uint16_t sdlen=(uint16_t) (flags & STREAM_DATA_FLAG_LEN16 ? in.ReadInt16() : in.ReadByte()); + uint32_t pts=(uint32_t) in.ReadInt32(); + //LOGD("stream data, pts=%d, len=%d, rem=%d", pts, sdlen, in.Remaining()); audioTimestampIn=pts; if(!audioOutStarted && audioOutput){ audioOutput->Start(); audioOutStarted=true; } if(jitterBuffer) - jitterBuffer->HandleInput((unsigned char*) (buffer+in->GetOffset()), sdlen, pts); + jitterBuffer->HandleInput((unsigned char*) (buffer+in.GetOffset()), sdlen, pts); if(iSeek(in->GetOffset()+sdlen); + in.Seek(in.GetOffset()+sdlen); } } if(type==PKT_PING){ LOGD("Received ping from %s:%d", packet.address->ToString().c_str(), srcEndpoint->port); if(srcEndpoint->type!=EP_TYPE_UDP_RELAY && !allowP2p){ LOGW("Received p2p ping but p2p is disabled by manual override"); - delete in; + continue; } if(srcEndpoint==currentEndpoint){ - CBufferOutputStream *pkt=GetOutgoingPacketBuffer(); + BufferOutputStream *pkt=GetOutgoingPacketBuffer(); if(!pkt){ LOGW("Dropping pong packet, queue overflow"); - delete in; + continue; } WritePacketHeader(pkt, PKT_PONG, 4); pkt->WriteInt32(pseq); sendQueue->Put(pkt); }else{ - CBufferOutputStream pkt(32); + BufferOutputStream pkt(32); WritePacketHeader(&pkt, PKT_PONG, 4); pkt.WriteInt32(pseq); SendPacket(pkt.GetBuffer(), pkt.GetLength(), srcEndpoint); @@ -1049,7 +1060,7 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA } if(type==PKT_PONG){ if(packetInnerLen>=4){ - uint32_t pingSeq=(uint32_t) in->ReadInt32(); + uint32_t pingSeq=(uint32_t) in.ReadInt32(); if(pingSeq==srcEndpoint->lastPingSeq){ memmove(&srcEndpoint->rtts[1], srcEndpoint->rtts, sizeof(double)*5); srcEndpoint->rtts[0]=GetCurrentTime()-srcEndpoint->lastPingTime; @@ -1071,8 +1082,8 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA }*/ } if(type==PKT_STREAM_STATE){ - unsigned char id=in->ReadByte(); - unsigned char enabled=in->ReadByte(); + unsigned char id=in.ReadByte(); + unsigned char enabled=in.ReadByte(); int i; for(i=0;iid==id){ @@ -1084,8 +1095,8 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA } if(type==PKT_LAN_ENDPOINT){ LOGV("received lan endpoint"); - uint32_t peerAddr=(uint32_t) in->ReadInt32(); - uint16_t peerPort=(uint16_t) in->ReadInt32(); + uint32_t peerAddr=(uint32_t) in.ReadInt32(); + uint16_t peerPort=(uint16_t) in.ReadInt32(); lock_mutex(endpointsMutex); for(std::vector::iterator itrtr=endpoints.begin();itrtr!=endpoints.end();++itrtr){ if((*itrtr)->type==EP_TYPE_UDP_P2P_LAN){ @@ -1105,14 +1116,14 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA if(allowP2p) SendPublicEndpointsRequest(); if(peerVersion>=2){ - uint32_t flags=(uint32_t) in->ReadInt32(); + uint32_t flags=(uint32_t) in.ReadInt32(); dataSavingRequestedByPeer=(flags & INIT_FLAG_DATA_SAVING_ENABLED)==INIT_FLAG_DATA_SAVING_ENABLED; UpdateDataSavingState(); UpdateAudioBitrate(); } } /*if(type==PKT_SWITCH_PREF_RELAY){ - uint64_t relayId=(uint64_t) in->ReadInt64(); + uint64_t relayId=(uint64_t) in.ReadInt64(); int i; for(i=0;itype==EP_TYPE_UDP_RELAY && endpoints[i]->id==relayId){ @@ -1146,15 +1157,13 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA }catch(std::out_of_range x){ LOGW("Error parsing packet: %s", x.what()); } - malformed_packet: - delete in; } LOGI("=== recv thread exiting ==="); } void VoIPController::RunSendThread(){ while(runReceiver){ - CBufferOutputStream* pkt=(CBufferOutputStream *) sendQueue->GetBlocking(); + BufferOutputStream* pkt=(BufferOutputStream *) sendQueue->GetBlocking(); if(pkt){ SendPacket(pkt->GetBuffer(), pkt->GetLength(), currentEndpoint); pkt->Reset(); @@ -1170,6 +1179,7 @@ void VoIPController::RunSendThread(){ void VoIPController::RunTickThread(){ uint32_t tickCount=0; bool wasWaitingForAcks=false; + double startTime=GetCurrentTime(); while(runReceiver){ #ifndef _WIN32 usleep(100000); @@ -1261,7 +1271,7 @@ void VoIPController::RunTickThread(){ } if((waitingForAcks && tickCount%10==0) || (!areThereAnyEnabledStreams && tickCount%2==0)){ - CBufferOutputStream* pkt=GetOutgoingPacketBuffer(); + BufferOutputStream* pkt=GetOutgoingPacketBuffer(); if(!pkt){ LOGW("Dropping ping packet, queue overflow"); return; @@ -1306,7 +1316,7 @@ void VoIPController::RunTickThread(){ continue; } if(GetCurrentTime()-qp->lastSentTime>=qp->retryInterval){ - CBufferOutputStream* pkt=GetOutgoingPacketBuffer(); + BufferOutputStream* pkt=GetOutgoingPacketBuffer(); if(pkt){ uint32_t seq=WritePacketHeader(pkt, qp->type, qp->length); memmove(&qp->seqs[1], qp->seqs, 4*9); @@ -1334,7 +1344,7 @@ void VoIPController::RunTickThread(){ Endpoint* endpoint=*e; if(GetCurrentTime()-endpoint->lastPingTime>=10){ LOGV("Sending ping to %s", endpoint->address.ToString().c_str()); - CBufferOutputStream pkt(32); + BufferOutputStream pkt(32); uint32_t seq=WritePacketHeader(&pkt, PKT_PING, 0); endpoint->lastPingTime=GetCurrentTime(); endpoint->lastPingSeq=seq; @@ -1353,7 +1363,7 @@ void VoIPController::RunTickThread(){ if(currentEndpoint->type==EP_TYPE_UDP_RELAY) currentEndpoint=preferredRelay; LogDebugInfo(); - /*CBufferOutputStream pkt(32); + /*BufferOutputStream pkt(32); pkt.WriteInt64(preferredRelay->id); SendPacketReliably(PKT_SWITCH_PREF_RELAY, pkt.GetBuffer(), pkt.GetLength(), 1, 9);*/ } @@ -1402,7 +1412,7 @@ void VoIPController::RunTickThread(){ } UpdateDataSavingState(); UpdateAudioBitrate(); - CBufferOutputStream s(4); + BufferOutputStream s(4); s.WriteInt32(dataSavingMode ? INIT_FLAG_DATA_SAVING_ENABLED : 0); SendPacketReliably(PKT_NETWORK_CHANGED, s.GetBuffer(), s.GetLength(), 1, 20); lastRecvPacketTime=GetCurrentTime(); @@ -1412,18 +1422,36 @@ void VoIPController::RunTickThread(){ SetState(STATE_FAILED); } } - }else if(state==STATE_WAIT_INIT){ + }else if(state==STATE_WAIT_INIT || state==STATE_WAIT_INIT_ACK){ if(GetCurrentTime()-connectionInitTime>=config.init_timeout){ LOGW("Init timeout, disconnecting"); lastError=TGVOIP_ERROR_TIMEOUT; SetState(STATE_FAILED); } } + + if(statsDump){ + //fprintf(statsDump, "Time\tRTT\tLISeq\tLASeq\tCWnd\tBitrate\tJitter\tJDelay\tAJDelay\n"); + fprintf(statsDump, "%.3f\t%.3f\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%.3f\t%.3f\t%.3f\n", + GetCurrentTime()-startTime, + currentEndpoint->rtts[0], + lastRemoteSeq, + seq, + lastRemoteAckSeq, + recvLossCount, + conctl ? conctl->GetSendLossCount() : 0, + conctl ? conctl->GetInflightDataSize() : 0, + encoder ? encoder->GetBitrate() : 0, + encoder ? encoder->GetPacketLoss() : 0, + jitterBuffer ? jitterBuffer->GetLastMeasuredJitter() : 0, + jitterBuffer ? jitterBuffer->GetLastMeasuredDelay()*0.06 : 0, + jitterBuffer ? jitterBuffer->GetCurrentDelay()*0.06 : 0); + } #if defined(__APPLE__) && defined(TGVOIP_USE_AUDIO_SESSION) if(needNotifyAcquiredAudioSession){ needNotifyAcquiredAudioSession=false; - CAudioUnitIO::AudioSessionAcquired(); + audio::AudioUnitIO::AudioSessionAcquired(); } #endif } @@ -1443,13 +1471,13 @@ void VoIPController::SendPacket(unsigned char *data, size_t len, Endpoint* ep){ //dst.sin_addr=ep->address; //dst.sin_port=htons(ep->port); //dst.sin_family=AF_INET; - CBufferOutputStream out(len+128); + BufferOutputStream out(len+128); if(ep->type==EP_TYPE_UDP_RELAY) out.WriteBytes((unsigned char*)ep->peerTag, 16); else out.WriteBytes(callID, 16); if(len>0){ - CBufferOutputStream inner(len+128); + BufferOutputStream inner(len+128); inner.WriteInt32(len); inner.WriteBytes(data, len); if(inner.GetLength()%16!=0){ @@ -1514,7 +1542,7 @@ void VoIPController::SetNetworkType(int type){ if(allowP2p && currentEndpoint){ SendPublicEndpointsRequest(); } - CBufferOutputStream s(4); + BufferOutputStream s(4); s.WriteInt32(dataSavingMode ? INIT_FLAG_DATA_SAVING_ENABLED : 0); SendPacketReliably(PKT_NETWORK_CHANGED, s.GetBuffer(), s.GetLength(), 1, 20); } @@ -1590,6 +1618,7 @@ void VoIPController::SetStateCallback(void (* f)(VoIPController*, int)){ void VoIPController::SetState(int state){ this->state=state; + LOGV("Call state changed to %d", state); stateChangeTime=GetCurrentTime(); if(stateCallback){ stateCallback(this, state); @@ -1649,8 +1678,8 @@ void VoIPController::UpdateAudioOutputState(){ } -CBufferOutputStream *VoIPController::GetOutgoingPacketBuffer(){ - CBufferOutputStream* pkt=NULL; +BufferOutputStream *VoIPController::GetOutgoingPacketBuffer(){ + BufferOutputStream* pkt=NULL; lock_mutex(sendBufferMutex); if(emptySendBuffers.size()>0){ pkt=emptySendBuffers[emptySendBuffers.size()-1]; @@ -1663,7 +1692,7 @@ CBufferOutputStream *VoIPController::GetOutgoingPacketBuffer(){ void VoIPController::KDF(unsigned char* msgKey, size_t x, unsigned char* aesKey, unsigned char* aesIv){ uint8_t sA[SHA1_LENGTH], sB[SHA1_LENGTH], sC[SHA1_LENGTH], sD[SHA1_LENGTH]; - CBufferOutputStream buf(128); + BufferOutputStream buf(128); buf.WriteBytes(msgKey, 16); buf.WriteBytes(encryptionKey+x, 32); crypto.sha1(buf.GetBuffer(), buf.GetLength(), sA); @@ -1827,6 +1856,12 @@ void VoIPController::SetConfig(voip_config_t *cfg){ } if(strlen(cfg->logFilePath)) tgvoipLogFile=fopen(cfg->logFilePath, "w"); + if(statsDump) + fclose(statsDump); + if(strlen(cfg->statsDumpFilePath)){ + statsDump=fopen(cfg->statsDumpFilePath, "w"); + fprintf(statsDump, "Time\tRTT\tLRSeq\tLSSeq\tLASeq\tLostR\tLostS\tCWnd\tBitrate\tLoss%%\tJitter\tJDelay\tAJDelay\n"); + } UpdateDataSavingState(); UpdateAudioBitrate(); } @@ -1862,7 +1897,7 @@ void VoIPController::DebugCtl(int request, int param){ }else if(allowP2p){ SendPublicEndpointsRequest(); } - CBufferOutputStream s(4); + BufferOutputStream s(4); s.WriteInt32(dataSavingMode ? INIT_FLAG_DATA_SAVING_ENABLED : 0); SendPacketReliably(PKT_NETWORK_CHANGED, s.GetBuffer(), s.GetLength(), 1, 20); }else if(request==4){ @@ -1995,6 +2030,38 @@ size_t VoIPController::GetDebugLogLength(){ return len; } +std::vector VoIPController::EnumerateAudioInputs(){ + vector devs; + audio::AudioInput::EnumerateDevices(devs); + return devs; +} + +std::vector VoIPController::EnumerateAudioOutputs(){ + vector devs; + audio::AudioOutput::EnumerateDevices(devs); + return devs; +} + +void VoIPController::SetCurrentAudioInput(std::string id){ + currentAudioInput=id; + if(audioInput) + audioInput->SetCurrentDevice(id); +} + +void VoIPController::SetCurrentAudioOutput(std::string id){ + currentAudioOutput=id; + if(audioOutput) + audioOutput->SetCurrentDevice(id); +} + +std::string VoIPController::GetCurrentAudioInputID(){ + return currentAudioInput; +} + +std::string VoIPController::GetCurrentAudioOutputID(){ + return currentAudioOutput; +} + Endpoint::Endpoint(int64_t id, uint16_t port, IPv4Address& _address, IPv6Address& _v6address, char type, unsigned char peerTag[16]) : address(_address), v6address(_v6address){ this->id=id; this->port=port; diff --git a/VoIPController.h b/VoIPController.h index 910eaaef17..864cabc7f4 100644 --- a/VoIPController.h +++ b/VoIPController.h @@ -146,6 +146,7 @@ struct voip_config_t{ double recv_timeout; int data_saving; char logFilePath[256]; + char statsDumpFilePath[256]; bool enableAEC; bool enableNS; @@ -209,6 +210,20 @@ private: double averageRTT; }; +class AudioDevice{ +public: + std::string id; + std::string displayName; +}; + +class AudioOutputDevice : public AudioDevice{ + +}; + +class AudioInputDevice : public AudioDevice{ + +}; + class VoIPController { public: @@ -242,6 +257,12 @@ public: std::string GetDebugLog(); void GetDebugLog(char* buffer); size_t GetDebugLogLength(); + static std::vector EnumerateAudioInputs(); + static std::vector EnumerateAudioOutputs(); + void SetCurrentAudioInput(std::string id); + void SetCurrentAudioOutput(std::string id); + std::string GetCurrentAudioInputID(); + std::string GetCurrentAudioOutputID(); private: static void* StartRecvThread(void* arg); @@ -259,8 +280,8 @@ private: void SendInitAck(); void UpdateDataSavingState(); void KDF(unsigned char* msgKey, size_t x, unsigned char* aesKey, unsigned char* aesIv); - CBufferOutputStream* GetOutgoingPacketBuffer(); - uint32_t WritePacketHeader(CBufferOutputStream* s, unsigned char type, uint32_t length); + BufferOutputStream* GetOutgoingPacketBuffer(); + uint32_t WritePacketHeader(BufferOutputStream* s, unsigned char type, uint32_t length); static size_t AudioInputCallback(unsigned char* data, size_t length, void* param); void SendPublicEndpointsRequest(); void SendPublicEndpointsRequest(Endpoint& relay); @@ -283,14 +304,14 @@ private: uint32_t sendLossCountHistory[32]; uint32_t audioTimestampIn; uint32_t audioTimestampOut; - CAudioInput* audioInput; - CAudioOutput* audioOutput; - CJitterBuffer* jitterBuffer; - COpusDecoder* decoder; - COpusEncoder* encoder; - CBlockingQueue* sendQueue; - CEchoCanceller* echoCanceller; - std::vector emptySendBuffers; + tgvoip::audio::AudioInput* audioInput; + tgvoip::audio::AudioOutput* audioOutput; + JitterBuffer* jitterBuffer; + OpusDecoder* decoder; + OpusEncoder* encoder; + BlockingQueue* sendQueue; + EchoCanceller* echoCanceller; + std::vector emptySendBuffers; tgvoip_mutex_t sendBufferMutex; tgvoip_mutex_t endpointsMutex; bool stopping; @@ -311,7 +332,7 @@ private: int lastError; bool micMuted; uint32_t maxBitrate; - CBufferOutputStream* currentAudioPacket; + BufferOutputStream* currentAudioPacket; void (*stateCallback)(VoIPController*, int); std::vector outgoingStreams; std::vector incomingStreams; @@ -331,13 +352,16 @@ private: double lastRecvPacketTime; voip_config_t config; int32_t peerVersion; - CCongestionControl* conctl; + CongestionControl* conctl; voip_stats_t stats; bool receivedInit; bool receivedInitAck; std::vector debugLogs; bool isOutgoing; tgvoip::NetworkSocket* socket; + FILE* statsDump; + std::string currentAudioInput; + std::string currentAudioOutput; /*** server config values ***/ uint32_t maxAudioBitrate; diff --git a/VoIPServerConfig.cpp b/VoIPServerConfig.cpp index 057f5c273c..dee561dc69 100644 --- a/VoIPServerConfig.cpp +++ b/VoIPServerConfig.cpp @@ -27,7 +27,7 @@ ServerConfig *ServerConfig::GetSharedInstance(){ } bool ServerConfig::GetBoolean(std::string name, bool fallback){ - CMutexGuard sync(mutex); + MutexGuard sync(mutex); if(ContainsKey(name)){ std::string val=config[name]; if(val=="true") @@ -39,7 +39,7 @@ bool ServerConfig::GetBoolean(std::string name, bool fallback){ } double ServerConfig::GetDouble(std::string name, double fallback){ - CMutexGuard sync(mutex); + MutexGuard sync(mutex); if(ContainsKey(name)){ std::string val=config[name]; char* end; @@ -53,7 +53,7 @@ double ServerConfig::GetDouble(std::string name, double fallback){ } int32_t ServerConfig::GetInt(std::string name, int32_t fallback){ - CMutexGuard sync(mutex); + MutexGuard sync(mutex); if(ContainsKey(name)){ std::string val=config[name]; char* end; @@ -67,14 +67,14 @@ int32_t ServerConfig::GetInt(std::string name, int32_t fallback){ } std::string ServerConfig::GetString(std::string name, std::string fallback){ - CMutexGuard sync(mutex); + MutexGuard sync(mutex); if(ContainsKey(name)) return config[name]; return fallback; } void ServerConfig::Update(std::map newValues){ - CMutexGuard sync(mutex); + MutexGuard sync(mutex); LOGD("=== Updating voip config ==="); config.clear(); for(std::map::iterator itr=newValues.begin();itr!=newValues.end();++itr){ diff --git a/audio/AudioInput.cpp b/audio/AudioInput.cpp index 6989c4fc22..c51e6e6c8c 100644 --- a/audio/AudioInput.cpp +++ b/audio/AudioInput.cpp @@ -22,27 +22,56 @@ #error "Unsupported operating system" #endif -CAudioInput::CAudioInput(){ +using namespace tgvoip; +using namespace tgvoip::audio; + +AudioInput::AudioInput() : currentDevice("default"){ failed=false; } -CAudioInput *CAudioInput::Create(){ +AudioInput::AudioInput(std::string deviceID) : currentDevice(deviceID){ + failed=false; +} + +AudioInput *AudioInput::Create(std::string deviceID){ #if defined(__ANDROID__) - return new CAudioInputAndroid(); + return new AudioInputAndroid(); #elif defined(__APPLE__) - return new CAudioInputAudioUnit(); +#if TARGET_OS_OSX + return new AudioInputAudioUnit(deviceID); +#else + return new AudioInputAudioUnit(); +#endif #elif defined(_WIN32) - return new tgvoip::audio::AudioInputWave(); + return new AudioInputWave(deviceID); #elif defined(__linux__) - return new tgvoip::audio::AudioInputALSA(); + return new AudioInputALSA(); #endif } -CAudioInput::~CAudioInput(){ +AudioInput::~AudioInput(){ } -bool CAudioInput::IsInitialized(){ +bool AudioInput::IsInitialized(){ return !failed; } + +void AudioInput::EnumerateDevices(std::vector& devs){ +#if defined(__APPLE__) && TARGET_OS_OSX + AudioInputAudioUnit::EnumerateDevices(devs); +#elif defined(_WIN32) + AudioInputWave::EnumerateDevices(devs); +#elif defined(__linux__) && !defined(__ANDROID__) + return new AudioInputALSA(); +#endif +} + +std::string AudioInput::GetCurrentDevice(){ + return currentDevice; +} + +void AudioInput::SetCurrentDevice(std::string deviceID){ + +} diff --git a/audio/AudioInput.h b/audio/AudioInput.h index 03e6175c7b..73dc533df5 100644 --- a/audio/AudioInput.h +++ b/audio/AudioInput.h @@ -8,20 +8,33 @@ #define LIBTGVOIP_AUDIOINPUT_H #include +#include +#include #include "../MediaStreamItf.h" -class CAudioInput : public CMediaStreamItf{ +namespace tgvoip{ + +class AudioInputDevice; +class AudioOutputDevice; + +namespace audio{ +class AudioInput : public MediaStreamItf{ public: - CAudioInput(); - virtual ~CAudioInput(); + AudioInput(); + AudioInput(std::string deviceID); + virtual ~AudioInput(); virtual void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels)=0; bool IsInitialized(); - static CAudioInput* Create(); + virtual std::string GetCurrentDevice(); + virtual void SetCurrentDevice(std::string deviceID); + static AudioInput* Create(std::string deviceID); + static void EnumerateDevices(std::vector& devs); protected: + std::string currentDevice; bool failed; }; - +}} #endif //LIBTGVOIP_AUDIOINPUT_H diff --git a/audio/AudioOutput.cpp b/audio/AudioOutput.cpp index b13abb59d0..a2d06c1f78 100644 --- a/audio/AudioOutput.cpp +++ b/audio/AudioOutput.cpp @@ -23,40 +23,75 @@ #error "Unsupported operating system" #endif +using namespace tgvoip; +using namespace tgvoip::audio; + #if defined(__ANDROID__) -int CAudioOutput::systemVersion; +int AudioOutput::systemVersion; #endif -CAudioOutput *CAudioOutput::Create(){ +AudioOutput *AudioOutput::Create(std::string deviceID){ #if defined(__ANDROID__) if(systemVersion<21) - return new CAudioOutputAndroid(); - return new CAudioOutputOpenSLES(); + return new AudioOutputAndroid(); + return new AudioOutputOpenSLES(); #elif defined(__APPLE__) - return new CAudioOutputAudioUnit(); +#if TARGET_OS_OSX + return new AudioOutputAudioUnit(deviceID); +#else + return new AudioOutputAudioUnit(); +#endif #elif defined(_WIN32) - return new tgvoip::audio::AudioOutputWave(); + return new AudioOutputWave(deviceID); #elif defined(__linux__) - return new tgvoip::audio::AudioOutputALSA(); + return new AudioOutputALSA(); #endif } -CAudioOutput::CAudioOutput(){ +AudioOutput::AudioOutput() : currentDevice("default"){ failed=false; } -CAudioOutput::~CAudioOutput(){ +AudioOutput::AudioOutput(std::string deviceID) : currentDevice(deviceID){ + failed=false; +} + +AudioOutput::~AudioOutput(){ } -int32_t CAudioOutput::GetEstimatedDelay(){ +int32_t AudioOutput::GetEstimatedDelay(){ #if defined(__ANDROID__) return systemVersion<21 ? 150 : 50; #endif return 60; } -float CAudioOutput::GetLevel(){ +float AudioOutput::GetLevel(){ return 0; } + + +void AudioOutput::EnumerateDevices(std::vector& devs){ +#if defined(__APPLE__) && TARGET_OS_OSX + AudioOutputAudioUnit::EnumerateDevices(devs); +#elif defined(_WIN32) + AudioOutputWave::EnumerateDevices(devs); +#elif defined(__linux__) && !defined(__ANDROID__) + return new AudioInputALSA(); +#endif +} + + +std::string AudioOutput::GetCurrentDevice(){ + return currentDevice; +} + +void AudioOutput::SetCurrentDevice(std::string deviceID){ + +} + +bool AudioOutput::IsInitialized(){ + return !failed; +} diff --git a/audio/AudioOutput.h b/audio/AudioOutput.h index 83b542ee9d..d700e8b867 100644 --- a/audio/AudioOutput.h +++ b/audio/AudioOutput.h @@ -8,25 +8,39 @@ #define LIBTGVOIP_AUDIOOUTPUT_H #include +#include +#include #include "../MediaStreamItf.h" -class CAudioOutput : public CMediaStreamItf{ +namespace tgvoip{ + +class AudioInputDevice; +class AudioOutputDevice; + +namespace audio{ +class AudioOutput : public MediaStreamItf{ public: - CAudioOutput(); - virtual ~CAudioOutput(); + AudioOutput(); + AudioOutput(std::string deviceID); + virtual ~AudioOutput(); virtual void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels)=0; virtual bool IsPlaying()=0; virtual float GetLevel(); - static CAudioOutput* Create(); static int32_t GetEstimatedDelay(); + virtual std::string GetCurrentDevice(); + virtual void SetCurrentDevice(std::string deviceID); + static AudioOutput* Create(std::string deviceID); + static void EnumerateDevices(std::vector& devs); + bool IsInitialized(); #if defined(__ANDROID__) static int systemVersion; #endif protected: + std::string currentDevice; bool failed; }; - +}} #endif //LIBTGVOIP_AUDIOOUTPUT_H diff --git a/client/android/tg_voip_jni.cpp b/client/android/tg_voip_jni.cpp index 82321fc960..8ed226e5ca 100644 --- a/client/android/tg_voip_jni.cpp +++ b/client/android/tg_voip_jni.cpp @@ -28,6 +28,7 @@ struct impl_data_android_t{ }; using namespace tgvoip; +using namespace tgvoip::audio; void updateConnectionState(VoIPController* cntrlr, int state){ impl_data_android_t* impl=(impl_data_android_t*) cntrlr->implData; @@ -50,23 +51,23 @@ void updateConnectionState(VoIPController* cntrlr, int state){ } extern "C" JNIEXPORT jlong Java_org_telegram_messenger_voip_VoIPController_nativeInit(JNIEnv* env, jobject thiz, jint systemVersion){ - CAudioOutputAndroid::systemVersion=systemVersion; + AudioOutputAndroid::systemVersion=systemVersion; env->GetJavaVM(&sharedJVM); - if(!CAudioInputAndroid::jniClass){ + if(!AudioInputAndroid::jniClass){ jclass cls=env->FindClass("org/telegram/messenger/voip/AudioRecordJNI"); - CAudioInputAndroid::jniClass=(jclass) env->NewGlobalRef(cls); - CAudioInputAndroid::initMethod=env->GetMethodID(cls, "init", "(IIII)V"); - CAudioInputAndroid::releaseMethod=env->GetMethodID(cls, "release", "()V"); - CAudioInputAndroid::startMethod=env->GetMethodID(cls, "start", "()Z"); - CAudioInputAndroid::stopMethod=env->GetMethodID(cls, "stop", "()V"); + AudioInputAndroid::jniClass=(jclass) env->NewGlobalRef(cls); + AudioInputAndroid::initMethod=env->GetMethodID(cls, "init", "(IIII)V"); + AudioInputAndroid::releaseMethod=env->GetMethodID(cls, "release", "()V"); + AudioInputAndroid::startMethod=env->GetMethodID(cls, "start", "()Z"); + AudioInputAndroid::stopMethod=env->GetMethodID(cls, "stop", "()V"); cls=env->FindClass("org/telegram/messenger/voip/AudioTrackJNI"); - CAudioOutputAndroid::jniClass=(jclass) env->NewGlobalRef(cls); - CAudioOutputAndroid::initMethod=env->GetMethodID(cls, "init", "(IIII)V"); - CAudioOutputAndroid::releaseMethod=env->GetMethodID(cls, "release", "()V"); - CAudioOutputAndroid::startMethod=env->GetMethodID(cls, "start", "()V"); - CAudioOutputAndroid::stopMethod=env->GetMethodID(cls, "stop", "()V"); + AudioOutputAndroid::jniClass=(jclass) env->NewGlobalRef(cls); + AudioOutputAndroid::initMethod=env->GetMethodID(cls, "init", "(IIII)V"); + AudioOutputAndroid::releaseMethod=env->GetMethodID(cls, "release", "()V"); + AudioOutputAndroid::startMethod=env->GetMethodID(cls, "start", "()V"); + AudioOutputAndroid::stopMethod=env->GetMethodID(cls, "stop", "()V"); } setStateMethod=env->GetMethodID(env->GetObjectClass(thiz), "handleStateChange", "(I)V"); @@ -137,12 +138,12 @@ extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_native } extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_nativeSetNativeBufferSize(JNIEnv* env, jclass thiz, jint size){ - CAudioOutputOpenSLES::nativeBufferSize=size; - CAudioInputOpenSLES::nativeBufferSize=size; + AudioOutputOpenSLES::nativeBufferSize=size; + AudioInputOpenSLES::nativeBufferSize=size; } extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_nativeRelease(JNIEnv* env, jobject thiz, jlong inst){ - //env->DeleteGlobalRef(CAudioInputAndroid::jniClass); + //env->DeleteGlobalRef(AudioInputAndroid::jniClass); VoIPController* ctlr=((VoIPController*)(intptr_t)inst); impl_data_android_t* impl=(impl_data_android_t*)ctlr->implData; @@ -158,7 +159,7 @@ extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_AudioRecordJNI_native audioRecordInstanceFld=env->GetFieldID(env->GetObjectClass(thiz), "nativeInst", "J"); jlong inst=env->GetLongField(thiz, audioRecordInstanceFld); - CAudioInputAndroid* in=(CAudioInputAndroid*)(intptr_t)inst; + AudioInputAndroid* in=(AudioInputAndroid*)(intptr_t)inst; in->HandleCallback(env, buffer); } @@ -167,7 +168,7 @@ extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_AudioTrackJNI_nativeC audioTrackInstanceFld=env->GetFieldID(env->GetObjectClass(thiz), "nativeInst", "J"); jlong inst=env->GetLongField(thiz, audioTrackInstanceFld); - CAudioOutputAndroid* in=(CAudioOutputAndroid*)(intptr_t)inst; + AudioOutputAndroid* in=(AudioOutputAndroid*)(intptr_t)inst; in->HandleCallback(env, buffer); } @@ -185,7 +186,7 @@ extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_native ((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){ +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, jstring statsDumpPath){ voip_config_t cfg; cfg.init_timeout=initTimeout; cfg.recv_timeout=recvTimeout; @@ -201,6 +202,14 @@ extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_native }else{ memset(cfg.logFilePath, 0, sizeof(cfg.logFilePath)); } + if(statsDumpPath){ + char* path=(char *) env->GetStringUTFChars(statsDumpPath, NULL); + strncpy(cfg.statsDumpFilePath, path, sizeof(cfg.statsDumpFilePath)); + cfg.statsDumpFilePath[sizeof(cfg.logFilePath)-1]=0; + env->ReleaseStringUTFChars(logFilePath, path); + }else{ + memset(cfg.statsDumpFilePath, 0, sizeof(cfg.statsDumpFilePath)); + } ((VoIPController*)(intptr_t)inst)->SetConfig(&cfg); } diff --git a/os/android/AudioInputAndroid.cpp b/os/android/AudioInputAndroid.cpp index 2110da6cec..b9499512eb 100644 --- a/os/android/AudioInputAndroid.cpp +++ b/os/android/AudioInputAndroid.cpp @@ -10,13 +10,16 @@ extern JavaVM* sharedJVM; -jmethodID CAudioInputAndroid::initMethod=NULL; -jmethodID CAudioInputAndroid::releaseMethod=NULL; -jmethodID CAudioInputAndroid::startMethod=NULL; -jmethodID CAudioInputAndroid::stopMethod=NULL; -jclass CAudioInputAndroid::jniClass=NULL; +using namespace tgvoip; +using namespace tgvoip::audio; -CAudioInputAndroid::CAudioInputAndroid(){ +jmethodID AudioInputAndroid::initMethod=NULL; +jmethodID AudioInputAndroid::releaseMethod=NULL; +jmethodID AudioInputAndroid::startMethod=NULL; +jmethodID AudioInputAndroid::stopMethod=NULL; +jclass AudioInputAndroid::jniClass=NULL; + +AudioInputAndroid::AudioInputAndroid(){ JNIEnv* env=NULL; bool didAttach=false; sharedJVM->GetEnv((void**) &env, JNI_VERSION_1_6); @@ -36,9 +39,9 @@ CAudioInputAndroid::CAudioInputAndroid(){ init_mutex(mutex); } -CAudioInputAndroid::~CAudioInputAndroid(){ +AudioInputAndroid::~AudioInputAndroid(){ { - CMutexGuard guard(mutex); + MutexGuard guard(mutex); JNIEnv *env=NULL; bool didAttach=false; sharedJVM->GetEnv((void **) &env, JNI_VERSION_1_6); @@ -58,8 +61,8 @@ CAudioInputAndroid::~CAudioInputAndroid(){ free_mutex(mutex); } -void CAudioInputAndroid::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ - CMutexGuard guard(mutex); +void AudioInputAndroid::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ + MutexGuard guard(mutex); JNIEnv* env=NULL; bool didAttach=false; sharedJVM->GetEnv((void**) &env, JNI_VERSION_1_6); @@ -75,8 +78,8 @@ void CAudioInputAndroid::Configure(uint32_t sampleRate, uint32_t bitsPerSample, } } -void CAudioInputAndroid::Start(){ - CMutexGuard guard(mutex); +void AudioInputAndroid::Start(){ + MutexGuard guard(mutex); JNIEnv* env=NULL; bool didAttach=false; sharedJVM->GetEnv((void**) &env, JNI_VERSION_1_6); @@ -93,8 +96,8 @@ void CAudioInputAndroid::Start(){ running=true; } -void CAudioInputAndroid::Stop(){ - CMutexGuard guard(mutex); +void AudioInputAndroid::Stop(){ + MutexGuard guard(mutex); running=false; JNIEnv* env=NULL; bool didAttach=false; @@ -111,7 +114,7 @@ void CAudioInputAndroid::Stop(){ } } -void CAudioInputAndroid::HandleCallback(JNIEnv* env, jobject buffer){ +void AudioInputAndroid::HandleCallback(JNIEnv* env, jobject buffer){ if(!running) return; unsigned char* buf=(unsigned char*) env->GetDirectBufferAddress(buffer); diff --git a/os/android/AudioInputAndroid.h b/os/android/AudioInputAndroid.h index 62af95c348..6a042d6fd7 100644 --- a/os/android/AudioInputAndroid.h +++ b/os/android/AudioInputAndroid.h @@ -11,11 +11,12 @@ #include "../../audio/AudioInput.h" #include "../../threading.h" -class CAudioInputAndroid : public CAudioInput{ +namespace tgvoip{ namespace audio{ +class AudioInputAndroid : public AudioInput{ public: - CAudioInputAndroid(); - virtual ~CAudioInputAndroid(); + AudioInputAndroid(); + virtual ~AudioInputAndroid(); virtual void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels); virtual void Start(); virtual void Stop(); @@ -32,6 +33,6 @@ private: tgvoip_mutex_t mutex; }; - +}} #endif //LIBTGVOIP_AUDIOINPUTANDROID_H diff --git a/os/android/AudioInputOpenSLES.cpp b/os/android/AudioInputOpenSLES.cpp index 0f435a39f9..bfba064726 100644 --- a/os/android/AudioInputOpenSLES.cpp +++ b/os/android/AudioInputOpenSLES.cpp @@ -15,12 +15,13 @@ #define CHECK_SL_ERROR(res, msg) if(res!=SL_RESULT_SUCCESS){ LOGE(msg); return; } #define BUFFER_SIZE 960 // 20 ms -int CAudioInputOpenSLES::nativeBufferSize; +using namespace tgvoip; +using namespace tgvoip::audio; -FILE* test; +int AudioInputOpenSLES::nativeBufferSize; -CAudioInputOpenSLES::CAudioInputOpenSLES(){ - slEngine=COpenSLEngineWrapper::CreateEngine(); +AudioInputOpenSLES::AudioInputOpenSLES(){ + slEngine=OpenSLEngineWrapper::CreateEngine(); LOGI("Native buffer size is %u samples", nativeBufferSize); if(nativeBufferSizeClear(slBufferQueue); (*slRecorderObj)->Destroy(slRecorderObj); @@ -47,18 +47,18 @@ CAudioInputOpenSLES::~CAudioInputOpenSLES(){ slRecorder=NULL; slBufferQueue=NULL; slEngine=NULL; - COpenSLEngineWrapper::DestroyEngine(); + OpenSLEngineWrapper::DestroyEngine(); free(buffer); buffer=NULL; free(nativeBuffer); nativeBuffer=NULL; } -void CAudioInputOpenSLES::BufferCallback(SLAndroidSimpleBufferQueueItf bq, void *context){ - ((CAudioInputOpenSLES*)context)->HandleSLCallback(); +void AudioInputOpenSLES::BufferCallback(SLAndroidSimpleBufferQueueItf bq, void *context){ + ((AudioInputOpenSLES*)context)->HandleSLCallback(); } -void CAudioInputOpenSLES::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ +void AudioInputOpenSLES::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ assert(slRecorderObj==NULL); SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, @@ -90,24 +90,24 @@ void CAudioInputOpenSLES::Configure(uint32_t sampleRate, uint32_t bitsPerSample, result=(*slRecorderObj)->GetInterface(slRecorderObj, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &slBufferQueue); CHECK_SL_ERROR(result, "Error getting buffer queue"); - result=(*slBufferQueue)->RegisterCallback(slBufferQueue, CAudioInputOpenSLES::BufferCallback, this); + result=(*slBufferQueue)->RegisterCallback(slBufferQueue, AudioInputOpenSLES::BufferCallback, this); CHECK_SL_ERROR(result, "Error setting buffer queue callback"); (*slBufferQueue)->Enqueue(slBufferQueue, nativeBuffer, nativeBufferSize*sizeof(int16_t)); } -void CAudioInputOpenSLES::Start(){ +void AudioInputOpenSLES::Start(){ SLresult result=(*slRecorder)->SetRecordState(slRecorder, SL_RECORDSTATE_RECORDING); CHECK_SL_ERROR(result, "Error starting record"); } -void CAudioInputOpenSLES::Stop(){ +void AudioInputOpenSLES::Stop(){ SLresult result=(*slRecorder)->SetRecordState(slRecorder, SL_RECORDSTATE_STOPPED); CHECK_SL_ERROR(result, "Error stopping record"); } -void CAudioInputOpenSLES::HandleSLCallback(){ +void AudioInputOpenSLES::HandleSLCallback(){ //SLmillisecond pMsec = 0; //(*slRecorder)->GetPosition(slRecorder, &pMsec); //LOGI("Callback! pos=%lu", pMsec); diff --git a/os/android/AudioInputOpenSLES.h b/os/android/AudioInputOpenSLES.h index ac5d878dcc..655be250f4 100644 --- a/os/android/AudioInputOpenSLES.h +++ b/os/android/AudioInputOpenSLES.h @@ -12,11 +12,12 @@ #include "../../audio/AudioInput.h" -class CAudioInputOpenSLES : public CAudioInput{ +namespace tgvoip{ namespace audio{ +class AudioInputOpenSLES : public AudioInput{ public: - CAudioInputOpenSLES(); - virtual ~CAudioInputOpenSLES(); + AudioInputOpenSLES(); + virtual ~AudioInputOpenSLES(); virtual void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels); virtual void Start(); virtual void Stop(); @@ -34,6 +35,6 @@ private: int16_t* nativeBuffer; size_t positionInBuffer; }; - +}} #endif //LIBTGVOIP_AUDIOINPUTOPENSLES_H diff --git a/os/android/AudioOutputAndroid.cpp b/os/android/AudioOutputAndroid.cpp index d047806b6c..f5510a9899 100644 --- a/os/android/AudioOutputAndroid.cpp +++ b/os/android/AudioOutputAndroid.cpp @@ -10,13 +10,16 @@ extern JavaVM* sharedJVM; -jmethodID CAudioOutputAndroid::initMethod=NULL; -jmethodID CAudioOutputAndroid::releaseMethod=NULL; -jmethodID CAudioOutputAndroid::startMethod=NULL; -jmethodID CAudioOutputAndroid::stopMethod=NULL; -jclass CAudioOutputAndroid::jniClass=NULL; +using namespace tgvoip; +using namespace tgvoip::audio; -CAudioOutputAndroid::CAudioOutputAndroid(){ +jmethodID AudioOutputAndroid::initMethod=NULL; +jmethodID AudioOutputAndroid::releaseMethod=NULL; +jmethodID AudioOutputAndroid::startMethod=NULL; +jmethodID AudioOutputAndroid::stopMethod=NULL; +jclass AudioOutputAndroid::jniClass=NULL; + +AudioOutputAndroid::AudioOutputAndroid(){ JNIEnv* env=NULL; bool didAttach=false; sharedJVM->GetEnv((void**) &env, JNI_VERSION_1_6); @@ -35,7 +38,7 @@ CAudioOutputAndroid::CAudioOutputAndroid(){ running=false; } -CAudioOutputAndroid::~CAudioOutputAndroid(){ +AudioOutputAndroid::~AudioOutputAndroid(){ JNIEnv* env=NULL; bool didAttach=false; sharedJVM->GetEnv((void**) &env, JNI_VERSION_1_6); @@ -53,7 +56,7 @@ CAudioOutputAndroid::~CAudioOutputAndroid(){ } } -void CAudioOutputAndroid::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ +void AudioOutputAndroid::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ JNIEnv* env=NULL; bool didAttach=false; sharedJVM->GetEnv((void**) &env, JNI_VERSION_1_6); @@ -69,7 +72,7 @@ void CAudioOutputAndroid::Configure(uint32_t sampleRate, uint32_t bitsPerSample, } } -void CAudioOutputAndroid::Start(){ +void AudioOutputAndroid::Start(){ JNIEnv* env=NULL; bool didAttach=false; sharedJVM->GetEnv((void**) &env, JNI_VERSION_1_6); @@ -86,7 +89,7 @@ void CAudioOutputAndroid::Start(){ running=true; } -void CAudioOutputAndroid::Stop(){ +void AudioOutputAndroid::Stop(){ running=false; JNIEnv* env=NULL; bool didAttach=false; @@ -103,7 +106,7 @@ void CAudioOutputAndroid::Stop(){ } } -void CAudioOutputAndroid::HandleCallback(JNIEnv* env, jbyteArray buffer){ +void AudioOutputAndroid::HandleCallback(JNIEnv* env, jbyteArray buffer){ if(!running) return; unsigned char* buf=(unsigned char*) env->GetByteArrayElements(buffer, NULL); @@ -113,10 +116,10 @@ void CAudioOutputAndroid::HandleCallback(JNIEnv* env, jbyteArray buffer){ } -bool CAudioOutputAndroid::IsPlaying(){ +bool AudioOutputAndroid::IsPlaying(){ return false; } -float CAudioOutputAndroid::GetLevel(){ +float AudioOutputAndroid::GetLevel(){ return 0; } diff --git a/os/android/AudioOutputAndroid.h b/os/android/AudioOutputAndroid.h index 16cd28bc8c..6950f8ca08 100644 --- a/os/android/AudioOutputAndroid.h +++ b/os/android/AudioOutputAndroid.h @@ -10,12 +10,13 @@ #include #include "../../audio/AudioOutput.h" -class CAudioOutputAndroid : public CAudioOutput{ +namespace tgvoip{ namespace audio{ +class AudioOutputAndroid : public AudioOutput{ public: - CAudioOutputAndroid(); - virtual ~CAudioOutputAndroid(); + AudioOutputAndroid(); + virtual ~AudioOutputAndroid(); virtual void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels); virtual void Start(); virtual void Stop(); @@ -33,6 +34,6 @@ private: bool running; }; - +}} #endif //LIBTGVOIP_AUDIOOUTPUTANDROID_H diff --git a/os/android/AudioOutputOpenSLES.cpp b/os/android/AudioOutputOpenSLES.cpp index 0f0aab48a7..b290ffb96c 100644 --- a/os/android/AudioOutputOpenSLES.cpp +++ b/os/android/AudioOutputOpenSLES.cpp @@ -16,11 +16,14 @@ #define CHECK_SL_ERROR(res, msg) if(res!=SL_RESULT_SUCCESS){ LOGE(msg); return; } #define BUFFER_SIZE 960 // 20 ms -int CAudioOutputOpenSLES::nativeBufferSize; +using namespace tgvoip; +using namespace tgvoip::audio; -CAudioOutputOpenSLES::CAudioOutputOpenSLES(){ +int AudioOutputOpenSLES::nativeBufferSize; + +AudioOutputOpenSLES::AudioOutputOpenSLES(){ SLresult result; - slEngine=COpenSLEngineWrapper::CreateEngine(); + slEngine=OpenSLEngineWrapper::CreateEngine(); const SLInterfaceID pOutputMixIDs[] = {}; const SLboolean pOutputMixRequired[] = {}; @@ -46,7 +49,7 @@ CAudioOutputOpenSLES::CAudioOutputOpenSLES(){ remainingDataSize=0; } -CAudioOutputOpenSLES::~CAudioOutputOpenSLES(){ +AudioOutputOpenSLES::~AudioOutputOpenSLES(){ if(!stopped) Stop(); (*slBufferQueue)->Clear(slBufferQueue); @@ -54,21 +57,21 @@ CAudioOutputOpenSLES::~CAudioOutputOpenSLES(){ (*slPlayerObj)->Destroy(slPlayerObj); LOGV("destroy slOutputMixObj"); (*slOutputMixObj)->Destroy(slOutputMixObj); - COpenSLEngineWrapper::DestroyEngine(); + OpenSLEngineWrapper::DestroyEngine(); free(buffer); free(nativeBuffer); } -void CAudioOutputOpenSLES::SetNativeBufferSize(int size){ - CAudioOutputOpenSLES::nativeBufferSize=size; +void AudioOutputOpenSLES::SetNativeBufferSize(int size){ + AudioOutputOpenSLES::nativeBufferSize=size; } -void CAudioOutputOpenSLES::BufferCallback(SLAndroidSimpleBufferQueueItf bq, void *context){ - ((CAudioOutputOpenSLES*)context)->HandleSLCallback(); +void AudioOutputOpenSLES::BufferCallback(SLAndroidSimpleBufferQueueItf bq, void *context){ + ((AudioOutputOpenSLES*)context)->HandleSLCallback(); } -void CAudioOutputOpenSLES::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ +void AudioOutputOpenSLES::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ assert(slPlayerObj==NULL); SLDataLocator_AndroidSimpleBufferQueue locatorBufferQueue = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 1}; @@ -100,34 +103,34 @@ void CAudioOutputOpenSLES::Configure(uint32_t sampleRate, uint32_t bitsPerSample result=(*slPlayerObj)->GetInterface(slPlayerObj, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &slBufferQueue); CHECK_SL_ERROR(result, "Error getting buffer queue"); - result=(*slBufferQueue)->RegisterCallback(slBufferQueue, CAudioOutputOpenSLES::BufferCallback, this); + result=(*slBufferQueue)->RegisterCallback(slBufferQueue, AudioOutputOpenSLES::BufferCallback, this); CHECK_SL_ERROR(result, "Error setting buffer queue callback"); (*slBufferQueue)->Enqueue(slBufferQueue, nativeBuffer, nativeBufferSize*sizeof(int16_t)); } -bool CAudioOutputOpenSLES::IsPhone(){ +bool AudioOutputOpenSLES::IsPhone(){ return false; } -void CAudioOutputOpenSLES::EnableLoudspeaker(bool enabled){ +void AudioOutputOpenSLES::EnableLoudspeaker(bool enabled){ } -void CAudioOutputOpenSLES::Start(){ +void AudioOutputOpenSLES::Start(){ stopped=false; SLresult result=(*slPlayer)->SetPlayState(slPlayer, SL_PLAYSTATE_PLAYING); CHECK_SL_ERROR(result, "Error starting player"); } -void CAudioOutputOpenSLES::Stop(){ +void AudioOutputOpenSLES::Stop(){ stopped=true; LOGV("Stopping OpenSL output"); SLresult result=(*slPlayer)->SetPlayState(slPlayer, SL_PLAYSTATE_PAUSED); CHECK_SL_ERROR(result, "Error starting player"); } -void CAudioOutputOpenSLES::HandleSLCallback(){ +void AudioOutputOpenSLES::HandleSLCallback(){ /*if(stopped){ //LOGV("left HandleSLCallback early"); return; @@ -153,7 +156,7 @@ void CAudioOutputOpenSLES::HandleSLCallback(){ } -bool CAudioOutputOpenSLES::IsPlaying(){ +bool AudioOutputOpenSLES::IsPlaying(){ if(slPlayer){ uint32_t state; (*slPlayer)->GetPlayState(slPlayer, &state); @@ -163,6 +166,6 @@ bool CAudioOutputOpenSLES::IsPlaying(){ } -float CAudioOutputOpenSLES::GetLevel(){ +float AudioOutputOpenSLES::GetLevel(){ return 0; // we don't use this anyway } \ No newline at end of file diff --git a/os/android/AudioOutputOpenSLES.h b/os/android/AudioOutputOpenSLES.h index a9af1f9150..67da812376 100644 --- a/os/android/AudioOutputOpenSLES.h +++ b/os/android/AudioOutputOpenSLES.h @@ -12,10 +12,11 @@ #include "../../audio/AudioOutput.h" -class CAudioOutputOpenSLES : public CAudioOutput{ +namespace tgvoip{ namespace audio{ +class AudioOutputOpenSLES : public AudioOutput{ public: - CAudioOutputOpenSLES(); - virtual ~CAudioOutputOpenSLES(); + AudioOutputOpenSLES(); + virtual ~AudioOutputOpenSLES(); virtual void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels); virtual bool IsPhone(); virtual void EnableLoudspeaker(bool enabled); @@ -41,6 +42,6 @@ private: unsigned char remainingData[10240]; size_t remainingDataSize; }; - +}} #endif //LIBTGVOIP_AUDIOOUTPUTANDROID_H diff --git a/os/android/OpenSLEngineWrapper.cpp b/os/android/OpenSLEngineWrapper.cpp index 9c8b754125..0869707261 100644 --- a/os/android/OpenSLEngineWrapper.cpp +++ b/os/android/OpenSLEngineWrapper.cpp @@ -10,11 +10,15 @@ #define CHECK_SL_ERROR(res, msg) if(res!=SL_RESULT_SUCCESS){ LOGE(msg); return NULL; } -SLObjectItf COpenSLEngineWrapper::sharedEngineObj=NULL; -SLEngineItf COpenSLEngineWrapper::sharedEngine=NULL; -int COpenSLEngineWrapper::count=0; +using namespace tgvoip; +using namespace tgvoip::audio; -void COpenSLEngineWrapper::DestroyEngine(){ + +SLObjectItf OpenSLEngineWrapper::sharedEngineObj=NULL; +SLEngineItf OpenSLEngineWrapper::sharedEngine=NULL; +int OpenSLEngineWrapper::count=0; + +void OpenSLEngineWrapper::DestroyEngine(){ count--; LOGI("release: engine instance count %d", count); if(count==0){ @@ -25,7 +29,7 @@ void COpenSLEngineWrapper::DestroyEngine(){ LOGI("after release"); } -SLEngineItf COpenSLEngineWrapper::CreateEngine(){ +SLEngineItf OpenSLEngineWrapper::CreateEngine(){ count++; if(sharedEngine) return sharedEngine; diff --git a/os/android/OpenSLEngineWrapper.h b/os/android/OpenSLEngineWrapper.h index f98970a2a0..ff09586027 100644 --- a/os/android/OpenSLEngineWrapper.h +++ b/os/android/OpenSLEngineWrapper.h @@ -10,7 +10,8 @@ #include #include -class COpenSLEngineWrapper{ +namespace tgvoip{ namespace audio{ +class OpenSLEngineWrapper{ public: static SLEngineItf CreateEngine(); static void DestroyEngine(); @@ -20,6 +21,6 @@ private: static SLEngineItf sharedEngine; static int count; }; - +}} #endif //LIBTGVOIP_OPENSLENGINEWRAPPER_H diff --git a/os/darwin/AudioInputAudioUnit.cpp b/os/darwin/AudioInputAudioUnit.cpp index de8866240c..265f0d3de7 100644 --- a/os/darwin/AudioInputAudioUnit.cpp +++ b/os/darwin/AudioInputAudioUnit.cpp @@ -13,33 +13,36 @@ #define BUFFER_SIZE 960 -CAudioInputAudioUnit::CAudioInputAudioUnit(){ +using namespace tgvoip; +using namespace tgvoip::audio; + +AudioInputAudioUnit::AudioInputAudioUnit(){ remainingDataSize=0; isRecording=false; - this->io=CAudioUnitIO::Get(); + this->io=AudioUnitIO::Get(); io->AttachInput(this); } -CAudioInputAudioUnit::~CAudioInputAudioUnit(){ +AudioInputAudioUnit::~AudioInputAudioUnit(){ io->DetachInput(); - CAudioUnitIO::Release(); + AudioUnitIO::Release(); } -void CAudioInputAudioUnit::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ +void AudioInputAudioUnit::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ io->Configure(sampleRate, bitsPerSample, channels); } -void CAudioInputAudioUnit::Start(){ +void AudioInputAudioUnit::Start(){ isRecording=true; io->EnableInput(true); } -void CAudioInputAudioUnit::Stop(){ +void AudioInputAudioUnit::Stop(){ isRecording=false; io->EnableInput(false); } -void CAudioInputAudioUnit::HandleBufferCallback(AudioBufferList *ioData){ +void AudioInputAudioUnit::HandleBufferCallback(AudioBufferList *ioData){ int i; for(i=0;imNumberBuffers;i++){ AudioBuffer buf=ioData->mBuffers[i]; diff --git a/os/darwin/AudioInputAudioUnit.h b/os/darwin/AudioInputAudioUnit.h index 0c96fef76c..97ea051e14 100644 --- a/os/darwin/AudioInputAudioUnit.h +++ b/os/darwin/AudioInputAudioUnit.h @@ -10,13 +10,14 @@ #include #include "../../audio/AudioInput.h" -class CAudioUnitIO; +namespace tgvoip{ namespace audio{ +class AudioUnitIO; -class CAudioInputAudioUnit : public CAudioInput{ +class AudioInputAudioUnit : public AudioInput{ public: - CAudioInputAudioUnit(); - virtual ~CAudioInputAudioUnit(); + AudioInputAudioUnit(); + virtual ~AudioInputAudioUnit(); virtual void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels); virtual void Start(); virtual void Stop(); @@ -26,8 +27,8 @@ private: unsigned char remainingData[10240]; size_t remainingDataSize; bool isRecording; - CAudioUnitIO* io; + AudioUnitIO* io; }; - +}} #endif //LIBTGVOIP_AUDIOINPUTAUDIOUNIT_H diff --git a/os/darwin/AudioInputAudioUnitOSX.cpp b/os/darwin/AudioInputAudioUnitOSX.cpp index 5bbf8b80d4..fc4ef10f00 100644 --- a/os/darwin/AudioInputAudioUnitOSX.cpp +++ b/os/darwin/AudioInputAudioUnitOSX.cpp @@ -9,6 +9,7 @@ #include "AudioInputAudioUnitOSX.h" #include "../../logging.h" #include "../../audio/Resampler.h" +#include "../../VoIPController.h" #define BUFFER_SIZE 960 #define CHECK_AU_ERROR(res, msg) if(res!=noErr){ LOGE("input: " msg": OSStatus=%d", (int)res); failed=true; return; } @@ -16,8 +17,10 @@ #define kOutputBus 0 #define kInputBus 1 +using namespace tgvoip; +using namespace tgvoip::audio; -CAudioInputAudioUnit::CAudioInputAudioUnit(){ +AudioInputAudioUnit::AudioInputAudioUnit(std::string deviceID) : AudioInput(deviceID){ remainingDataSize=0; isRecording=false; @@ -37,41 +40,21 @@ CAudioInputAudioUnit::CAudioInputAudioUnit(){ status = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &flag, sizeof(flag)); CHECK_AU_ERROR(status, "Error enabling AudioUnit input"); - UInt32 size=sizeof(AudioDeviceID); - AudioDeviceID inputDevice; - AudioObjectPropertyAddress propertyAddress; + SetCurrentDevice(deviceID); + + CFRunLoopRef theRunLoop = NULL; + AudioObjectPropertyAddress propertyAddress = { kAudioHardwarePropertyRunLoop, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster }; + status = AudioObjectSetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop); + propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice; propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; propertyAddress.mElement = kAudioObjectPropertyElementMaster; - - UInt32 propsize = sizeof(AudioDeviceID); - status = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propsize, &inputDevice); - CHECK_AU_ERROR(status, "Error getting default input device"); - - status =AudioUnitSetProperty(unit, - kAudioOutputUnitProperty_CurrentDevice, - kAudioUnitScope_Global, - kInputBus, - &inputDevice, - size); - CHECK_AU_ERROR(status, "Error setting input device"); - - AudioStreamBasicDescription hardwareFormat; - size=sizeof(hardwareFormat); - status=AudioUnitGetProperty(unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kInputBus, &hardwareFormat, &size); - CHECK_AU_ERROR(status, "Error getting hardware format"); - - AudioStreamBasicDescription desiredFormat={ - .mSampleRate=hardwareFormat.mSampleRate, .mFormatID=kAudioFormatLinearPCM, .mFormatFlags=kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked | kAudioFormatFlagsNativeEndian, - .mFramesPerPacket=1, .mChannelsPerFrame=1, .mBitsPerChannel=16, .mBytesPerPacket=2, .mBytesPerFrame=2 - }; - hardwareSampleRate=hardwareFormat.mSampleRate; - - status=AudioUnitSetProperty(unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &desiredFormat, sizeof(desiredFormat)); - CHECK_AU_ERROR(status, "Error setting format"); + AudioObjectAddPropertyListener(kAudioObjectSystemObject, &propertyAddress, AudioInputAudioUnit::DefaultDeviceChangedCallback, this); AURenderCallbackStruct callbackStruct; - callbackStruct.inputProc = CAudioInputAudioUnit::BufferCallback; + callbackStruct.inputProc = AudioInputAudioUnit::BufferCallback; callbackStruct.inputProcRefCon=this; status = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, kInputBus, &callbackStruct, sizeof(callbackStruct)); CHECK_AU_ERROR(status, "Error setting input buffer callback"); @@ -83,36 +66,42 @@ CAudioInputAudioUnit::CAudioInputAudioUnit(){ inBufferList.mNumberBuffers=1; } -CAudioInputAudioUnit::~CAudioInputAudioUnit(){ +AudioInputAudioUnit::~AudioInputAudioUnit(){ + AudioObjectPropertyAddress propertyAddress; + propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice; + propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; + propertyAddress.mElement = kAudioObjectPropertyElementMaster; + AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &propertyAddress, AudioInputAudioUnit::DefaultDeviceChangedCallback, this); + AudioUnitUninitialize(unit); AudioComponentInstanceDispose(unit); free(inBufferList.mBuffers[0].mData); } -void CAudioInputAudioUnit::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ +void AudioInputAudioUnit::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ } -void CAudioInputAudioUnit::Start(){ +void AudioInputAudioUnit::Start(){ isRecording=true; OSStatus status=AudioOutputUnitStart(unit); CHECK_AU_ERROR(status, "Error starting AudioUnit"); } -void CAudioInputAudioUnit::Stop(){ +void AudioInputAudioUnit::Stop(){ isRecording=false; OSStatus status=AudioOutputUnitStart(unit); CHECK_AU_ERROR(status, "Error stopping AudioUnit"); } -OSStatus CAudioInputAudioUnit::BufferCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData){ - CAudioInputAudioUnit* input=(CAudioInputAudioUnit*) inRefCon; +OSStatus AudioInputAudioUnit::BufferCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData){ + AudioInputAudioUnit* input=(AudioInputAudioUnit*) inRefCon; input->inBufferList.mBuffers[0].mDataByteSize=10240; OSStatus res=AudioUnitRender(input->unit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, &input->inBufferList); input->HandleBufferCallback(&input->inBufferList); return noErr; } -void CAudioInputAudioUnit::HandleBufferCallback(AudioBufferList *ioData){ +void AudioInputAudioUnit::HandleBufferCallback(AudioBufferList *ioData){ int i; for(i=0;imNumberBuffers;i++){ AudioBuffer buf=ioData->mBuffers[i]; @@ -133,3 +122,175 @@ void CAudioInputAudioUnit::HandleBufferCallback(AudioBufferList *ioData){ } } } + + +void AudioInputAudioUnit::EnumerateDevices(std::vector& devs){ + AudioObjectPropertyAddress propertyAddress = { + kAudioHardwarePropertyDevices, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster + }; + + UInt32 dataSize = 0; + OSStatus status = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &dataSize); + if(kAudioHardwareNoError != status) { + LOGE("AudioObjectGetPropertyDataSize (kAudioHardwarePropertyDevices) failed: %i", status); + return; + } + + UInt32 deviceCount = (UInt32)(dataSize / sizeof(AudioDeviceID)); + + + AudioDeviceID *audioDevices = (AudioDeviceID*)(malloc(dataSize)); + + status = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &dataSize, audioDevices); + if(kAudioHardwareNoError != status) { + LOGE("AudioObjectGetPropertyData (kAudioHardwarePropertyDevices) failed: %i", status); + free(audioDevices); + audioDevices = NULL; + return; + } + + + // Iterate through all the devices and determine which are input-capable + propertyAddress.mScope = kAudioDevicePropertyScopeInput; + for(UInt32 i = 0; i < deviceCount; ++i) { + // Query device UID + CFStringRef deviceUID = NULL; + dataSize = sizeof(deviceUID); + propertyAddress.mSelector = kAudioDevicePropertyDeviceUID; + status = AudioObjectGetPropertyData(audioDevices[i], &propertyAddress, 0, NULL, &dataSize, &deviceUID); + if(kAudioHardwareNoError != status) { + LOGE("AudioObjectGetPropertyData (kAudioDevicePropertyDeviceUID) failed: %i", status); + continue; + } + + // Query device name + CFStringRef deviceName = NULL; + dataSize = sizeof(deviceName); + propertyAddress.mSelector = kAudioDevicePropertyDeviceNameCFString; + status = AudioObjectGetPropertyData(audioDevices[i], &propertyAddress, 0, NULL, &dataSize, &deviceName); + if(kAudioHardwareNoError != status) { + LOGE("AudioObjectGetPropertyData (kAudioDevicePropertyDeviceNameCFString) failed: %i", status); + continue; + } + + // Determine if the device is an input device (it is an input device if it has input channels) + dataSize = 0; + propertyAddress.mSelector = kAudioDevicePropertyStreamConfiguration; + status = AudioObjectGetPropertyDataSize(audioDevices[i], &propertyAddress, 0, NULL, &dataSize); + if(kAudioHardwareNoError != status) { + LOGE("AudioObjectGetPropertyDataSize (kAudioDevicePropertyStreamConfiguration) failed: %i", status); + continue; + } + + AudioBufferList *bufferList = (AudioBufferList*)(malloc(dataSize)); + + status = AudioObjectGetPropertyData(audioDevices[i], &propertyAddress, 0, NULL, &dataSize, bufferList); + if(kAudioHardwareNoError != status || 0 == bufferList->mNumberBuffers) { + if(kAudioHardwareNoError != status) + LOGE("AudioObjectGetPropertyData (kAudioDevicePropertyStreamConfiguration) failed: %i", status); + free(bufferList); + bufferList = NULL; + continue; + } + + free(bufferList); + bufferList = NULL; + + AudioInputDevice dev; + char buf[1024]; + CFStringGetCString(deviceName, buf, 1024, kCFStringEncodingUTF8); + dev.displayName=std::string(buf); + CFStringGetCString(deviceUID, buf, 1024, kCFStringEncodingUTF8); + dev.id=std::string(buf); + devs.push_back(dev); + } + + free(audioDevices); + audioDevices = NULL; +} + +void AudioInputAudioUnit::SetCurrentDevice(std::string deviceID){ + UInt32 size=sizeof(AudioDeviceID); + AudioDeviceID inputDevice=NULL; + OSStatus status; + + if(deviceID=="default"){ + AudioObjectPropertyAddress propertyAddress; + propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice; + propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; + propertyAddress.mElement = kAudioObjectPropertyElementMaster; + UInt32 propsize = sizeof(AudioDeviceID); + status = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propsize, &inputDevice); + CHECK_AU_ERROR(status, "Error getting default input device"); + }else{ + AudioObjectPropertyAddress propertyAddress = { + kAudioHardwarePropertyDevices, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster + }; + UInt32 dataSize = 0; + status = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &dataSize); + CHECK_AU_ERROR(status, "Error getting devices size"); + UInt32 deviceCount = (UInt32)(dataSize / sizeof(AudioDeviceID)); + AudioDeviceID audioDevices[deviceCount]; + status = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &dataSize, audioDevices); + CHECK_AU_ERROR(status, "Error getting device list"); + for(UInt32 i = 0; i < deviceCount; ++i) { + // Query device UID + CFStringRef deviceUID = NULL; + dataSize = sizeof(deviceUID); + propertyAddress.mSelector = kAudioDevicePropertyDeviceUID; + status = AudioObjectGetPropertyData(audioDevices[i], &propertyAddress, 0, NULL, &dataSize, &deviceUID); + CHECK_AU_ERROR(status, "Error getting device uid"); + char buf[1024]; + CFStringGetCString(deviceUID, buf, 1024, kCFStringEncodingUTF8); + if(deviceID==buf){ + LOGV("Found device for id %s", buf); + inputDevice=audioDevices[i]; + break; + } + } + if(!inputDevice){ + LOGW("Requested device not found, using default"); + SetCurrentDevice("default"); + return; + } + } + + status =AudioUnitSetProperty(unit, + kAudioOutputUnitProperty_CurrentDevice, + kAudioUnitScope_Global, + kInputBus, + &inputDevice, + size); + CHECK_AU_ERROR(status, "Error setting input device"); + + AudioStreamBasicDescription hardwareFormat; + size=sizeof(hardwareFormat); + status=AudioUnitGetProperty(unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kInputBus, &hardwareFormat, &size); + CHECK_AU_ERROR(status, "Error getting hardware format"); + hardwareSampleRate=hardwareFormat.mSampleRate; + + AudioStreamBasicDescription desiredFormat={ + .mSampleRate=hardwareFormat.mSampleRate, .mFormatID=kAudioFormatLinearPCM, .mFormatFlags=kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked | kAudioFormatFlagsNativeEndian, + .mFramesPerPacket=1, .mChannelsPerFrame=1, .mBitsPerChannel=16, .mBytesPerPacket=2, .mBytesPerFrame=2 + }; + + status=AudioUnitSetProperty(unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &desiredFormat, sizeof(desiredFormat)); + CHECK_AU_ERROR(status, "Error setting format"); + + LOGD("Switched capture device, new sample rate %d", hardwareSampleRate); + + this->currentDevice=deviceID; +} + +OSStatus AudioInputAudioUnit::DefaultDeviceChangedCallback(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inClientData){ + LOGV("System default input device changed"); + AudioInputAudioUnit* self=(AudioInputAudioUnit*)inClientData; + if(self->currentDevice=="default"){ + self->SetCurrentDevice(self->currentDevice); + } + return noErr; +} diff --git a/os/darwin/AudioInputAudioUnitOSX.h b/os/darwin/AudioInputAudioUnitOSX.h index f1524c3d83..db6c2db79a 100644 --- a/os/darwin/AudioInputAudioUnitOSX.h +++ b/os/darwin/AudioInputAudioUnitOSX.h @@ -12,18 +12,22 @@ #import #include "../../audio/AudioInput.h" -class CAudioInputAudioUnit : public CAudioInput{ +namespace tgvoip{ namespace audio{ +class AudioInputAudioUnit : public AudioInput{ public: - CAudioInputAudioUnit(); - virtual ~CAudioInputAudioUnit(); + AudioInputAudioUnit(std::string deviceID); + virtual ~AudioInputAudioUnit(); virtual void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels); virtual void Start(); virtual void Stop(); void HandleBufferCallback(AudioBufferList* ioData); + static void EnumerateDevices(std::vector& devs); + virtual void SetCurrentDevice(std::string deviceID); private: static OSStatus BufferCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData); + static OSStatus DefaultDeviceChangedCallback(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inClientData); unsigned char remainingData[10240]; size_t remainingDataSize; bool isRecording; @@ -31,6 +35,6 @@ private: AudioBufferList inBufferList; int hardwareSampleRate; }; - +}} #endif //LIBTGVOIP_AUDIOINPUTAUDIOUNIT_H diff --git a/os/darwin/AudioOutputAudioUnit.cpp b/os/darwin/AudioOutputAudioUnit.cpp index 740ef5b0be..9bc06ae8dd 100644 --- a/os/darwin/AudioOutputAudioUnit.cpp +++ b/os/darwin/AudioOutputAudioUnit.cpp @@ -14,50 +14,53 @@ #define BUFFER_SIZE 960 const int8_t permutation[33]={0,1,2,3,4,4,5,5,5,5,6,6,6,6,6,7,7,7,7,8,8,8,9,9,9,9,9,9,9,9,9,9,9}; -CAudioOutputAudioUnit::CAudioOutputAudioUnit(){ +using namespace tgvoip; +using namespace tgvoip::audio; + +AudioOutputAudioUnit::AudioOutputAudioUnit(){ isPlaying=false; remainingDataSize=0; level=0.0; - this->io=CAudioUnitIO::Get(); + this->io=AudioUnitIO::Get(); io->AttachOutput(this); } -CAudioOutputAudioUnit::~CAudioOutputAudioUnit(){ +AudioOutputAudioUnit::~AudioOutputAudioUnit(){ io->DetachOutput(); - CAudioUnitIO::Release(); + AudioUnitIO::Release(); } -void CAudioOutputAudioUnit::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ +void AudioOutputAudioUnit::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ io->Configure(sampleRate, bitsPerSample, channels); } -bool CAudioOutputAudioUnit::IsPhone(){ +bool AudioOutputAudioUnit::IsPhone(){ return false; } -void CAudioOutputAudioUnit::EnableLoudspeaker(bool enabled){ +void AudioOutputAudioUnit::EnableLoudspeaker(bool enabled){ } -void CAudioOutputAudioUnit::Start(){ +void AudioOutputAudioUnit::Start(){ isPlaying=true; io->EnableOutput(true); } -void CAudioOutputAudioUnit::Stop(){ +void AudioOutputAudioUnit::Stop(){ isPlaying=false; io->EnableOutput(false); } -bool CAudioOutputAudioUnit::IsPlaying(){ +bool AudioOutputAudioUnit::IsPlaying(){ return isPlaying; } -float CAudioOutputAudioUnit::GetLevel(){ +float AudioOutputAudioUnit::GetLevel(){ return level / 9.0; } -void CAudioOutputAudioUnit::HandleBufferCallback(AudioBufferList *ioData){ +void AudioOutputAudioUnit::HandleBufferCallback(AudioBufferList *ioData){ int i; unsigned int k; int16_t absVal=0; diff --git a/os/darwin/AudioOutputAudioUnit.h b/os/darwin/AudioOutputAudioUnit.h index 15b97e86fb..ba591aec6e 100644 --- a/os/darwin/AudioOutputAudioUnit.h +++ b/os/darwin/AudioOutputAudioUnit.h @@ -10,12 +10,13 @@ #include #include "../../audio/AudioOutput.h" -class CAudioUnitIO; +namespace tgvoip{ namespace audio{ +class AudioUnitIO; -class CAudioOutputAudioUnit : public CAudioOutput{ +class AudioOutputAudioUnit : public AudioOutput{ public: - CAudioOutputAudioUnit(); - virtual ~CAudioOutputAudioUnit(); + AudioOutputAudioUnit(); + virtual ~AudioOutputAudioUnit(); virtual void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels); virtual bool IsPhone(); virtual void EnableLoudspeaker(bool enabled); @@ -29,11 +30,11 @@ private: bool isPlaying; unsigned char remainingData[10240]; size_t remainingDataSize; - CAudioUnitIO* io; + AudioUnitIO* io; float level; int16_t absMax; int count; }; - +}} #endif //LIBTGVOIP_AUDIOOUTPUTAUDIOUNIT_H diff --git a/os/darwin/AudioOutputAudioUnitOSX.cpp b/os/darwin/AudioOutputAudioUnitOSX.cpp index 91a6c0bfe7..28d1b29ac8 100644 --- a/os/darwin/AudioOutputAudioUnitOSX.cpp +++ b/os/darwin/AudioOutputAudioUnitOSX.cpp @@ -8,6 +8,7 @@ #include #include "AudioOutputAudioUnitOSX.h" #include "../../logging.h" +#include "../../VoIPController.h" #define BUFFER_SIZE 960 #define CHECK_AU_ERROR(res, msg) if(res!=noErr){ LOGE("output: " msg": OSStatus=%d", (int)res); return; } @@ -15,8 +16,10 @@ #define kOutputBus 0 #define kInputBus 1 +using namespace tgvoip; +using namespace tgvoip::audio; -CAudioOutputAudioUnit::CAudioOutputAudioUnit(){ +AudioOutputAudioUnit::AudioOutputAudioUnit(std::string deviceID){ remainingDataSize=0; isPlaying=false; @@ -36,29 +39,18 @@ CAudioOutputAudioUnit::CAudioOutputAudioUnit(){ status = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &flag, sizeof(flag)); CHECK_AU_ERROR(status, "Error enabling AudioUnit input"); - UInt32 size=sizeof(AudioDeviceID); - AudioDeviceID outputDevice; - AudioObjectPropertyAddress propertyAddress; + SetCurrentDevice(deviceID); + + CFRunLoopRef theRunLoop = NULL; + AudioObjectPropertyAddress propertyAddress = { kAudioHardwarePropertyRunLoop, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster }; + status = AudioObjectSetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop); + propertyAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice; propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; propertyAddress.mElement = kAudioObjectPropertyElementMaster; - - UInt32 propsize = sizeof(AudioDeviceID); - status = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propsize, &outputDevice); - CHECK_AU_ERROR(status, "Error getting default output device"); - - status =AudioUnitSetProperty(unit, - kAudioOutputUnitProperty_CurrentDevice, - kAudioUnitScope_Global, - kOutputBus, - &outputDevice, - size); - CHECK_AU_ERROR(status, "Error setting input device"); - - AudioStreamBasicDescription hardwareFormat; - size=sizeof(hardwareFormat); - status=AudioUnitGetProperty(unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kOutputBus, &hardwareFormat, &size); - CHECK_AU_ERROR(status, "Error getting hardware format"); + AudioObjectAddPropertyListener(kAudioObjectSystemObject, &propertyAddress, AudioOutputAudioUnit::DefaultDeviceChangedCallback, this); AudioStreamBasicDescription desiredFormat={ .mSampleRate=/*hardwareFormat.mSampleRate*/48000, .mFormatID=kAudioFormatLinearPCM, .mFormatFlags=kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked | kAudioFormatFlagsNativeEndian, @@ -69,7 +61,7 @@ CAudioOutputAudioUnit::CAudioOutputAudioUnit(){ CHECK_AU_ERROR(status, "Error setting format"); AURenderCallbackStruct callbackStruct; - callbackStruct.inputProc = CAudioOutputAudioUnit::BufferCallback; + callbackStruct.inputProc = AudioOutputAudioUnit::BufferCallback; callbackStruct.inputProcRefCon=this; status = AudioUnitSetProperty(unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, kOutputBus, &callbackStruct, sizeof(callbackStruct)); CHECK_AU_ERROR(status, "Error setting input buffer callback"); @@ -77,37 +69,43 @@ CAudioOutputAudioUnit::CAudioOutputAudioUnit(){ CHECK_AU_ERROR(status, "Error initializing unit"); } -CAudioOutputAudioUnit::~CAudioOutputAudioUnit(){ +AudioOutputAudioUnit::~AudioOutputAudioUnit(){ + AudioObjectPropertyAddress propertyAddress; + propertyAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice; + propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; + propertyAddress.mElement = kAudioObjectPropertyElementMaster; + AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &propertyAddress, AudioOutputAudioUnit::DefaultDeviceChangedCallback, this); + AudioUnitUninitialize(unit); AudioComponentInstanceDispose(unit); } -void CAudioOutputAudioUnit::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ +void AudioOutputAudioUnit::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ } -void CAudioOutputAudioUnit::Start(){ +void AudioOutputAudioUnit::Start(){ isPlaying=true; OSStatus status=AudioOutputUnitStart(unit); CHECK_AU_ERROR(status, "Error starting AudioUnit"); } -void CAudioOutputAudioUnit::Stop(){ +void AudioOutputAudioUnit::Stop(){ isPlaying=false; OSStatus status=AudioOutputUnitStart(unit); CHECK_AU_ERROR(status, "Error stopping AudioUnit"); } -OSStatus CAudioOutputAudioUnit::BufferCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData){ - CAudioOutputAudioUnit* input=(CAudioOutputAudioUnit*) inRefCon; +OSStatus AudioOutputAudioUnit::BufferCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData){ + AudioOutputAudioUnit* input=(AudioOutputAudioUnit*) inRefCon; input->HandleBufferCallback(ioData); return noErr; } -bool CAudioOutputAudioUnit::IsPlaying(){ +bool AudioOutputAudioUnit::IsPlaying(){ return isPlaying; } -void CAudioOutputAudioUnit::HandleBufferCallback(AudioBufferList *ioData){ +void AudioOutputAudioUnit::HandleBufferCallback(AudioBufferList *ioData){ int i; unsigned int k; int16_t absVal=0; @@ -127,3 +125,175 @@ void CAudioOutputAudioUnit::HandleBufferCallback(AudioBufferList *ioData){ memmove(remainingData, remainingData+buf.mDataByteSize, remainingDataSize); } } + + +void AudioOutputAudioUnit::EnumerateDevices(std::vector& devs){ + AudioObjectPropertyAddress propertyAddress = { + kAudioHardwarePropertyDevices, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster + }; + + UInt32 dataSize = 0; + OSStatus status = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &dataSize); + if(kAudioHardwareNoError != status) { + LOGE("AudioObjectGetPropertyDataSize (kAudioHardwarePropertyDevices) failed: %i", status); + return; + } + + UInt32 deviceCount = (UInt32)(dataSize / sizeof(AudioDeviceID)); + + + AudioDeviceID *audioDevices = (AudioDeviceID*)(malloc(dataSize)); + + status = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &dataSize, audioDevices); + if(kAudioHardwareNoError != status) { + LOGE("AudioObjectGetPropertyData (kAudioHardwarePropertyDevices) failed: %i", status); + free(audioDevices); + audioDevices = NULL; + return; + } + + + // Iterate through all the devices and determine which are input-capable + propertyAddress.mScope = kAudioDevicePropertyScopeOutput; + for(UInt32 i = 0; i < deviceCount; ++i) { + // Query device UID + CFStringRef deviceUID = NULL; + dataSize = sizeof(deviceUID); + propertyAddress.mSelector = kAudioDevicePropertyDeviceUID; + status = AudioObjectGetPropertyData(audioDevices[i], &propertyAddress, 0, NULL, &dataSize, &deviceUID); + if(kAudioHardwareNoError != status) { + LOGE("AudioObjectGetPropertyData (kAudioDevicePropertyDeviceUID) failed: %i", status); + continue; + } + + // Query device name + CFStringRef deviceName = NULL; + dataSize = sizeof(deviceName); + propertyAddress.mSelector = kAudioDevicePropertyDeviceNameCFString; + status = AudioObjectGetPropertyData(audioDevices[i], &propertyAddress, 0, NULL, &dataSize, &deviceName); + if(kAudioHardwareNoError != status) { + LOGE("AudioObjectGetPropertyData (kAudioDevicePropertyDeviceNameCFString) failed: %i", status); + continue; + } + + // Determine if the device is an input device (it is an input device if it has input channels) + dataSize = 0; + propertyAddress.mSelector = kAudioDevicePropertyStreamConfiguration; + status = AudioObjectGetPropertyDataSize(audioDevices[i], &propertyAddress, 0, NULL, &dataSize); + if(kAudioHardwareNoError != status) { + LOGE("AudioObjectGetPropertyDataSize (kAudioDevicePropertyStreamConfiguration) failed: %i", status); + continue; + } + + AudioBufferList *bufferList = (AudioBufferList*)(malloc(dataSize)); + + status = AudioObjectGetPropertyData(audioDevices[i], &propertyAddress, 0, NULL, &dataSize, bufferList); + if(kAudioHardwareNoError != status || 0 == bufferList->mNumberBuffers) { + if(kAudioHardwareNoError != status) + LOGE("AudioObjectGetPropertyData (kAudioDevicePropertyStreamConfiguration) failed: %i", status); + free(bufferList); + bufferList = NULL; + continue; + } + + free(bufferList); + bufferList = NULL; + + AudioOutputDevice dev; + char buf[1024]; + CFStringGetCString(deviceName, buf, 1024, kCFStringEncodingUTF8); + dev.displayName=std::string(buf); + CFStringGetCString(deviceUID, buf, 1024, kCFStringEncodingUTF8); + dev.id=std::string(buf); + devs.push_back(dev); + } + + free(audioDevices); + audioDevices = NULL; +} + +void AudioOutputAudioUnit::SetCurrentDevice(std::string deviceID){ + UInt32 size=sizeof(AudioDeviceID); + AudioDeviceID inputDevice=NULL; + OSStatus status; + + if(deviceID=="default"){ + AudioObjectPropertyAddress propertyAddress; + propertyAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice; + propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; + propertyAddress.mElement = kAudioObjectPropertyElementMaster; + UInt32 propsize = sizeof(AudioDeviceID); + status = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propsize, &inputDevice); + CHECK_AU_ERROR(status, "Error getting default input device"); + }else{ + AudioObjectPropertyAddress propertyAddress = { + kAudioHardwarePropertyDevices, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster + }; + UInt32 dataSize = 0; + status = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &dataSize); + CHECK_AU_ERROR(status, "Error getting devices size"); + UInt32 deviceCount = (UInt32)(dataSize / sizeof(AudioDeviceID)); + AudioDeviceID audioDevices[deviceCount]; + status = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &dataSize, audioDevices); + CHECK_AU_ERROR(status, "Error getting device list"); + for(UInt32 i = 0; i < deviceCount; ++i) { + // Query device UID + CFStringRef deviceUID = NULL; + dataSize = sizeof(deviceUID); + propertyAddress.mSelector = kAudioDevicePropertyDeviceUID; + status = AudioObjectGetPropertyData(audioDevices[i], &propertyAddress, 0, NULL, &dataSize, &deviceUID); + CHECK_AU_ERROR(status, "Error getting device uid"); + char buf[1024]; + CFStringGetCString(deviceUID, buf, 1024, kCFStringEncodingUTF8); + if(deviceID==buf){ + LOGV("Found device for id %s", buf); + inputDevice=audioDevices[i]; + break; + } + } + if(!inputDevice){ + LOGW("Requested device not found, using default"); + SetCurrentDevice("default"); + return; + } + } + + status =AudioUnitSetProperty(unit, + kAudioOutputUnitProperty_CurrentDevice, + kAudioUnitScope_Global, + kOutputBus, + &inputDevice, + size); + CHECK_AU_ERROR(status, "Error setting output device"); + + AudioStreamBasicDescription hardwareFormat; + size=sizeof(hardwareFormat); + status=AudioUnitGetProperty(unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kOutputBus, &hardwareFormat, &size); + CHECK_AU_ERROR(status, "Error getting hardware format"); + hardwareSampleRate=hardwareFormat.mSampleRate; + + AudioStreamBasicDescription desiredFormat={ + .mSampleRate=48000, .mFormatID=kAudioFormatLinearPCM, .mFormatFlags=kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked | kAudioFormatFlagsNativeEndian, + .mFramesPerPacket=1, .mChannelsPerFrame=1, .mBitsPerChannel=16, .mBytesPerPacket=2, .mBytesPerFrame=2 + }; + + status=AudioUnitSetProperty(unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &desiredFormat, sizeof(desiredFormat)); + CHECK_AU_ERROR(status, "Error setting format"); + + LOGD("Switched playback device, new sample rate %d", hardwareSampleRate); + + this->currentDevice=deviceID; +} + +OSStatus AudioOutputAudioUnit::DefaultDeviceChangedCallback(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inClientData){ + LOGV("System default input device changed"); + AudioOutputAudioUnit* self=(AudioOutputAudioUnit*)inClientData; + if(self->currentDevice=="default"){ + self->SetCurrentDevice(self->currentDevice); + } + return noErr; +} diff --git a/os/darwin/AudioOutputAudioUnitOSX.h b/os/darwin/AudioOutputAudioUnitOSX.h index 86a43b75d2..dad1df9201 100644 --- a/os/darwin/AudioOutputAudioUnitOSX.h +++ b/os/darwin/AudioOutputAudioUnitOSX.h @@ -12,25 +12,29 @@ #import #include "../../audio/AudioOutput.h" -class CAudioOutputAudioUnit : public CAudioOutput{ +namespace tgvoip{ namespace audio{ +class AudioOutputAudioUnit : public AudioOutput{ public: - CAudioOutputAudioUnit(); - virtual ~CAudioOutputAudioUnit(); + AudioOutputAudioUnit(std::string deviceID); + virtual ~AudioOutputAudioUnit(); virtual void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels); virtual void Start(); virtual void Stop(); virtual bool IsPlaying(); void HandleBufferCallback(AudioBufferList* ioData); - + static void EnumerateDevices(std::vector& devs); + virtual void SetCurrentDevice(std::string deviceID); + private: static OSStatus BufferCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData); + static OSStatus DefaultDeviceChangedCallback(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inClientData); unsigned char remainingData[10240]; size_t remainingDataSize; bool isPlaying; AudioUnit unit; int hardwareSampleRate; }; - +}} #endif //LIBTGVOIP_AUDIOINPUTAUDIOUNIT_H diff --git a/os/darwin/AudioUnitIO.cpp b/os/darwin/AudioUnitIO.cpp index c461fa783e..be3fd895f8 100644 --- a/os/darwin/AudioUnitIO.cpp +++ b/os/darwin/AudioUnitIO.cpp @@ -18,12 +18,13 @@ #define kInputBus 1 using namespace tgvoip; +using namespace tgvoip::audio; -int CAudioUnitIO::refCount=0; -CAudioUnitIO* CAudioUnitIO::sharedInstance=NULL; -bool CAudioUnitIO::haveAudioSession=false; +int AudioUnitIO::refCount=0; +AudioUnitIO* AudioUnitIO::sharedInstance=NULL; +bool AudioUnitIO::haveAudioSession=false; -CAudioUnitIO::CAudioUnitIO(){ +AudioUnitIO::AudioUnitIO(){ input=NULL; output=NULL; configured=false; @@ -36,7 +37,7 @@ CAudioUnitIO::CAudioUnitIO(){ ProcessAudioSessionAcquired(); } -CAudioUnitIO::~CAudioUnitIO(){ +AudioUnitIO::~AudioUnitIO(){ if(runFakeIO){ runFakeIO=false; join_thread(fakeIOThread); @@ -48,7 +49,7 @@ CAudioUnitIO::~CAudioUnitIO(){ haveAudioSession=false; } -void CAudioUnitIO::ProcessAudioSessionAcquired(){ +void AudioUnitIO::ProcessAudioSessionAcquired(){ OSStatus status; AudioComponentDescription desc; AudioComponent inputComponent; @@ -69,16 +70,16 @@ void CAudioUnitIO::ProcessAudioSessionAcquired(){ ActuallyConfigure(cfgSampleRate, cfgBitsPerSample, cfgChannels); } -CAudioUnitIO* CAudioUnitIO::Get(){ +AudioUnitIO* AudioUnitIO::Get(){ if(refCount==0){ - sharedInstance=new CAudioUnitIO(); + sharedInstance=new AudioUnitIO(); } refCount++; assert(refCount>0); return sharedInstance; } -void CAudioUnitIO::Release(){ +void AudioUnitIO::Release(){ refCount--; assert(refCount>=0); if(refCount==0){ @@ -87,18 +88,18 @@ void CAudioUnitIO::Release(){ } } -void CAudioUnitIO::AudioSessionAcquired(){ +void AudioUnitIO::AudioSessionAcquired(){ haveAudioSession=true; if(sharedInstance) sharedInstance->ProcessAudioSessionAcquired(); } -void CAudioUnitIO::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ +void AudioUnitIO::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ if(configured) return; runFakeIO=true; - start_thread(fakeIOThread, CAudioUnitIO::StartFakeIOThread, this); + start_thread(fakeIOThread, AudioUnitIO::StartFakeIOThread, this); set_thread_priority(fakeIOThread, get_thread_max_priority()); if(haveAudioSession){ @@ -112,7 +113,7 @@ void CAudioUnitIO::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32 configured=true; } -void CAudioUnitIO::ActuallyConfigure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ +void AudioUnitIO::ActuallyConfigure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ UInt32 flag=1; OSStatus status = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, kOutputBus, &flag, sizeof(flag)); CHECK_AU_ERROR(status, "Error enabling AudioUnit output"); @@ -140,7 +141,7 @@ void CAudioUnitIO::ActuallyConfigure(uint32_t sampleRate, uint32_t bitsPerSample AURenderCallbackStruct callbackStruct; - callbackStruct.inputProc = CAudioUnitIO::BufferCallback; + callbackStruct.inputProc = AudioUnitIO::BufferCallback; callbackStruct.inputProcRefCon = this; status = AudioUnitSetProperty(unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, kOutputBus, &callbackStruct, sizeof(callbackStruct)); CHECK_AU_ERROR(status, "Error setting output buffer callback"); @@ -153,12 +154,12 @@ void CAudioUnitIO::ActuallyConfigure(uint32_t sampleRate, uint32_t bitsPerSample CHECK_AU_ERROR(status, "Error starting AudioUnit"); } -OSStatus CAudioUnitIO::BufferCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData){ - ((CAudioUnitIO*)inRefCon)->BufferCallback(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData); +OSStatus AudioUnitIO::BufferCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData){ + ((AudioUnitIO*)inRefCon)->BufferCallback(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData); return noErr; } -void CAudioUnitIO::BufferCallback(AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 bus, UInt32 numFrames, AudioBufferList *ioData){ +void AudioUnitIO::BufferCallback(AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 bus, UInt32 numFrames, AudioBufferList *ioData){ runFakeIO=false; if(bus==kOutputBus){ if(output && outputEnabled){ @@ -175,42 +176,42 @@ void CAudioUnitIO::BufferCallback(AudioUnitRenderActionFlags *ioActionFlags, con } } -void CAudioUnitIO::AttachInput(CAudioInputAudioUnit *i){ +void AudioUnitIO::AttachInput(AudioInputAudioUnit *i){ assert(input==NULL); input=i; } -void CAudioUnitIO::AttachOutput(CAudioOutputAudioUnit *o){ +void AudioUnitIO::AttachOutput(AudioOutputAudioUnit *o){ assert(output==NULL); output=o; } -void CAudioUnitIO::DetachInput(){ +void AudioUnitIO::DetachInput(){ assert(input!=NULL); input=NULL; inputEnabled=false; } -void CAudioUnitIO::DetachOutput(){ +void AudioUnitIO::DetachOutput(){ assert(output!=NULL); output=NULL; outputEnabled=false; } -void CAudioUnitIO::EnableInput(bool enabled){ +void AudioUnitIO::EnableInput(bool enabled){ inputEnabled=enabled; } -void CAudioUnitIO::EnableOutput(bool enabled){ +void AudioUnitIO::EnableOutput(bool enabled){ outputEnabled=enabled; } -void* CAudioUnitIO::StartFakeIOThread(void *arg){ - ((CAudioUnitIO*)arg)->RunFakeIOThread(); +void* AudioUnitIO::StartFakeIOThread(void *arg){ + ((AudioUnitIO*)arg)->RunFakeIOThread(); return NULL; } -void CAudioUnitIO::RunFakeIOThread(){ +void AudioUnitIO::RunFakeIOThread(){ double neededDataDuration=0; double prevTime=VoIPController::GetCurrentTime(); while(runFakeIO){ diff --git a/os/darwin/AudioUnitIO.h b/os/darwin/AudioUnitIO.h index e5d5c7a7d2..b5e7aff764 100644 --- a/os/darwin/AudioUnitIO.h +++ b/os/darwin/AudioUnitIO.h @@ -10,21 +10,22 @@ #include #include "../../threading.h" -class CAudioInputAudioUnit; -class CAudioOutputAudioUnit; +namespace tgvoip{ namespace audio{ +class AudioInputAudioUnit; +class AudioOutputAudioUnit; -class CAudioUnitIO{ +class AudioUnitIO{ public: - CAudioUnitIO(); - ~CAudioUnitIO(); + AudioUnitIO(); + ~AudioUnitIO(); void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels); - void AttachInput(CAudioInputAudioUnit* i); - void AttachOutput(CAudioOutputAudioUnit* o); + void AttachInput(AudioInputAudioUnit* i); + void AttachOutput(AudioOutputAudioUnit* o); void DetachInput(); void DetachOutput(); void EnableInput(bool enabled); void EnableOutput(bool enabled); - static CAudioUnitIO* Get(); + static AudioUnitIO* Get(); static void Release(); static void* StartFakeIOThread(void* arg); static void AudioSessionAcquired(); @@ -37,8 +38,8 @@ private: void ActuallyConfigure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels); void ProcessAudioSessionAcquired(); AudioComponentInstance unit; - CAudioInputAudioUnit* input; - CAudioOutputAudioUnit* output; + AudioInputAudioUnit* input; + AudioOutputAudioUnit* output; AudioBufferList inBufferList; bool configured; bool inputEnabled; @@ -49,8 +50,9 @@ private: uint32_t cfgChannels; tgvoip_thread_t fakeIOThread; static int refCount; - static CAudioUnitIO* sharedInstance; + static AudioUnitIO* sharedInstance; static bool haveAudioSession; }; +}} #endif /* LIBTGVOIP_AUDIOUNITIO_H */ diff --git a/os/linux/AudioInputALSA.h b/os/linux/AudioInputALSA.h index 6d1904cf59..4134834b49 100644 --- a/os/linux/AudioInputALSA.h +++ b/os/linux/AudioInputALSA.h @@ -14,7 +14,7 @@ namespace tgvoip{ namespace audio{ -class AudioInputALSA : public CAudioInput{ +class AudioInputALSA : public AudioInput{ public: AudioInputALSA(); diff --git a/os/linux/AudioOutputALSA.h b/os/linux/AudioOutputALSA.h index 2462e6a207..7b3d08419b 100644 --- a/os/linux/AudioOutputALSA.h +++ b/os/linux/AudioOutputALSA.h @@ -14,7 +14,7 @@ namespace tgvoip{ namespace audio{ -class AudioOutputALSA : public CAudioOutput{ +class AudioOutputALSA : public AudioOutput{ public: AudioOutputALSA(); virtual ~AudioOutputALSA(); diff --git a/os/posix/NetworkSocketPosix.cpp b/os/posix/NetworkSocketPosix.cpp index 5b0ff3d697..86bb529527 100644 --- a/os/posix/NetworkSocketPosix.cpp +++ b/os/posix/NetworkSocketPosix.cpp @@ -48,6 +48,10 @@ void NetworkSocketPosix::SetMaxPriority(){ } void NetworkSocketPosix::Send(NetworkPacket *packet){ + if(!packet || !packet->address){ + LOGW("tried to send null packet"); + return; + } sockaddr_in6 addr; IPv4Address* v4addr=dynamic_cast(packet->address); if(v4addr){ @@ -120,6 +124,7 @@ void NetworkSocketPosix::Receive(NetworkPacket *packet){ if(len>0) packet->length=(size_t) len; else{ + LOGE("error receiving %d / %s", errno, strerror(errno)); packet->length=0; return; } diff --git a/os/windows/AudioInputWave.cpp b/os/windows/AudioInputWave.cpp index 48a3a26735..61a8f0b45d 100644 --- a/os/windows/AudioInputWave.cpp +++ b/os/windows/AudioInputWave.cpp @@ -9,13 +9,14 @@ #include #include "AudioInputWave.h" #include "../../logging.h" +#include "../../VoIPController.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;} +#define CHECK_ERROR(res, msg) if(res!=MMSYSERR_NOERROR){wchar_t _buf[1024]; waveInGetErrorTextW(res, _buf, 1024); LOGE(msg ": %ws (MMRESULT=0x%08X)", _buf, res); failed=true;} -AudioInputWave::AudioInputWave(){ +AudioInputWave::AudioInputWave(std::string deviceID){ isRecording=false; for(int i=0;i<4;i++){ @@ -24,16 +25,9 @@ AudioInputWave::AudioInputWave(){ 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; + hWaveIn=NULL; - MMRESULT res=waveInOpen(&hWaveIn, WAVE_MAPPER, &format, (DWORD_PTR)AudioInputWave::WaveInProc, (DWORD_PTR)this, CALLBACK_FUNCTION); - CHECK_ERROR(res, "waveInOpen failed"); + SetCurrentDevice(deviceID); } AudioInputWave::~AudioInputWave(){ @@ -88,4 +82,89 @@ void AudioInputWave::OnData(WAVEHDR* hdr){ hdr->dwFlags&= ~WHDR_DONE; MMRESULT res=waveInAddBuffer(hWaveIn, hdr, sizeof(WAVEHDR)); CHECK_ERROR(res, "waveInAddBuffer failed"); +} + +void AudioInputWave::EnumerateDevices(std::vector& devs){ + UINT num=waveInGetNumDevs(); + WAVEINCAPSW caps; + char nameBuf[512]; + for(UINT i=0;i +#include +#include #include "../../audio/AudioInput.h" namespace tgvoip{ namespace audio{ -class AudioInputWave : public CAudioInput{ +class AudioInputWave : public AudioInput{ public: - AudioInputWave(); + AudioInputWave(std::string deviceID); virtual ~AudioInputWave(); virtual void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels); virtual void Start(); virtual void Stop(); + virtual void SetCurrentDevice(std::string deviceID); + static void EnumerateDevices(std::vector& devs); private: static void CALLBACK WaveInProc(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2); diff --git a/os/windows/AudioOutputWave.cpp b/os/windows/AudioOutputWave.cpp index fc969eb9dd..debc19061c 100644 --- a/os/windows/AudioOutputWave.cpp +++ b/os/windows/AudioOutputWave.cpp @@ -8,14 +8,16 @@ #include #include "AudioOutputWave.h" #include "../../logging.h" +#include "../../VoIPController.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;} +#define CHECK_ERROR(res, msg) if(res!=MMSYSERR_NOERROR){wchar_t _buf[1024]; waveOutGetErrorTextW(res, _buf, 1024); LOGE(msg ": %ws (MMRESULT=0x%08X)", _buf, res); failed=true;} using namespace tgvoip::audio; -AudioOutputWave::AudioOutputWave(){ +AudioOutputWave::AudioOutputWave(std::string deviceID){ isPlaying=false; + hWaveOut=NULL; for(int i=0;i<4;i++){ ZeroMemory(&buffers[i], sizeof(WAVEHDR)); @@ -23,16 +25,7 @@ AudioOutputWave::AudioOutputWave(){ 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"); + SetCurrentDevice(deviceID); } AudioOutputWave::~AudioOutputWave(){ @@ -88,3 +81,85 @@ void AudioOutputWave::OnBufferDone(WAVEHDR* hdr){ hdr->dwFlags&= ~WHDR_DONE; MMRESULT res=waveOutWrite(hWaveOut, hdr, sizeof(WAVEHDR)); } + +void AudioOutputWave::EnumerateDevices(std::vector& devs){ + UINT num=waveOutGetNumDevs(); + WAVEOUTCAPSW caps; + char nameBuf[512]; + for(UINT i=0;i +#include +#include #include "../../audio/AudioOutput.h" namespace tgvoip{ namespace audio{ -class AudioOutputWave : public CAudioOutput{ +class AudioOutputWave : public AudioOutput{ public: - AudioOutputWave(); + AudioOutputWave(std::string deviceID); virtual ~AudioOutputWave(); virtual void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels); virtual void Start(); virtual void Stop(); virtual bool IsPlaying(); + virtual void SetCurrentDevice(std::string deviceID); + static void EnumerateDevices(std::vector& devs); private: HWAVEOUT hWaveOut; diff --git a/threading.h b/threading.h index 29e9a68a7a..f951b93cd0 100644 --- a/threading.h +++ b/threading.h @@ -10,6 +10,7 @@ #if defined(_POSIX_THREADS) || defined(_POSIX_VERSION) || defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) #include +#include #include typedef pthread_t tgvoip_thread_t; @@ -35,6 +36,40 @@ 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) +namespace tgvoip{ +class Semaphore{ +public: + Semaphore(unsigned int maxCount, unsigned int initValue){ + sem_init(&sem, 0, initValue); + } + + ~Semaphore(){ + sem_destroy(&sem); + } + + void Acquire(){ + sem_wait(&sem); + } + + void Release(){ + sem_post(&sem); + } + + void Acquire(int count){ + for(int i=0;i @@ -62,20 +97,54 @@ typedef HANDLE tgvoip_lock_t; // uncomment for XP compatibility //#define wait_lock(lock, mutex) SleepConditionVariableCS(&lock, &mutex, INFINITE) //#define notify_lock(lock) WakeAllConditionVariable(&lock) +namespace tgvoip{ +class Semaphore{ +public: + Semaphore(unsigned int maxCount, unsigned int initValue){ + h=CreateSemaphore(NULL, initValue, maxCount, NULL); + } + + ~Semaphore(){ + CloseHandle(h); + } + + void Acquire(){ + WaitForSingleObject(h, INFINITE); + } + + void Release(){ + ReleaseSemaphore(h, 1, NULL); + } + + void Acquire(int count){ + for(int i=0;i -#include -#include // memset extern "C" { #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h" @@ -24,6 +21,10 @@ extern "C" { #if defined(WEBRTC_ARCH_X86_FAMILY) +#include +#include +#include // memset + namespace webrtc { __inline static float MulRe(float aRe, float aIm, float bRe, float bIm) {