1
0
mirror of https://github.com/danog/libtgvoip.git synced 2025-01-22 13:01:21 +01:00

2.2.2: more fixes

- Probable fix for a mysterious crash in WASAPI
- Hopefully fixes telegramdesktop/tdesktop/4219 by setting PA stream role and bypassing filters
- Outgoing packet queue now uses Buffer instead of BufferPool
This commit is contained in:
Grishka 2018-08-07 23:10:31 +03:00
parent 3334409ac7
commit 529a3bf14f
12 changed files with 152 additions and 156 deletions

View File

@ -29,12 +29,12 @@ public:
void Put(T thing){ void Put(T thing){
MutexGuard sync(mutex); MutexGuard sync(mutex);
queue.push_back(thing); queue.push_back(std::move(thing));
bool didOverflow=false; bool didOverflow=false;
while(queue.size()>capacity){ while(queue.size()>capacity){
didOverflow=true; didOverflow=true;
if(overflowCallback){ if(overflowCallback){
overflowCallback(queue.front()); overflowCallback(std::move(queue.front()));
queue.pop_front(); queue.pop_front();
}else{ }else{
abort(); abort();
@ -47,16 +47,14 @@ public:
T GetBlocking(){ T GetBlocking(){
semaphore.Acquire(); semaphore.Acquire();
MutexGuard sync(mutex); MutexGuard sync(mutex);
T r=GetInternal(); return GetInternal();
return r;
} }
T Get(){ T Get(){
MutexGuard sync(mutex); MutexGuard sync(mutex);
if(queue.size()>0) if(queue.size()>0)
semaphore.Acquire(); semaphore.Acquire();
T r=GetInternal(); return GetInternal();
return r;
} }
unsigned int Size(){ unsigned int Size(){
@ -75,7 +73,7 @@ private:
T GetInternal(){ T GetInternal(){
//if(queue.size()==0) //if(queue.size()==0)
// return NULL; // return NULL;
T r=queue.front(); T r=std::move(queue.front());
queue.pop_front(); queue.pop_front();
return r; return r;
} }

View File

@ -90,7 +90,10 @@ namespace tgvoip{
class Buffer{ class Buffer{
public: public:
Buffer(size_t capacity){ Buffer(size_t capacity){
data=(unsigned char *) malloc(capacity); if(capacity>0)
data=(unsigned char *) malloc(capacity);
else
data=NULL;
length=capacity; length=capacity;
}; };
Buffer(const Buffer& other)=delete; Buffer(const Buffer& other)=delete;

View File

@ -122,7 +122,6 @@ extern FILE* tgvoipLogFile;
VoIPController::VoIPController() : activeNetItfName(""), VoIPController::VoIPController() : activeNetItfName(""),
currentAudioInput("default"), currentAudioInput("default"),
currentAudioOutput("default"), currentAudioOutput("default"),
outgoingPacketsBufferPool(1024, 20),
proxyAddress(""), proxyAddress(""),
proxyUsername(""), proxyUsername(""),
proxyPassword(""){ proxyPassword(""){
@ -411,58 +410,48 @@ void VoIPController::HandleAudioInput(unsigned char *data, size_t len, unsigned
} }
//LOGV("Audio packet size %u", (unsigned int)len); //LOGV("Audio packet size %u", (unsigned int)len);
unsigned char* buf=outgoingPacketsBufferPool.Get(); BufferOutputStream pkt(1500);
if(buf){
BufferOutputStream pkt(buf, outgoingPacketsBufferPool.GetSingleBufferSize());
unsigned char flags=(unsigned char) (len>255 ? STREAM_DATA_FLAG_LEN16 : 0); unsigned char flags=(unsigned char) (len>255 ? STREAM_DATA_FLAG_LEN16 : 0);
pkt.WriteByte((unsigned char) (1 | flags)); // streamID + flags pkt.WriteByte((unsigned char) (1 | flags)); // streamID + flags
if(len>255) if(len>255)
pkt.WriteInt16((int16_t) len); pkt.WriteInt16((int16_t) len);
else else
pkt.WriteByte((unsigned char) len); pkt.WriteByte((unsigned char) len);
pkt.WriteInt32(audioTimestampOut); pkt.WriteInt32(audioTimestampOut);
pkt.WriteBytes(data, len); pkt.WriteBytes(data, len);
PendingOutgoingPacket p{ PendingOutgoingPacket p{
/*.seq=*/GenerateOutSeq(), /*.seq=*/GenerateOutSeq(),
/*.type=*/PKT_STREAM_DATA, /*.type=*/PKT_STREAM_DATA,
/*.len=*/pkt.GetLength(), /*.len=*/pkt.GetLength(),
/*.data=*/buf, /*.data=*/Buffer(move(pkt)),
/*.endpoint=*/0, /*.endpoint=*/0,
}; };
sendQueue->Put(p); sendQueue->Put(move(p));
}else{
LOGW("Out of outgoing packet buffers!");
}
if(secondaryData && secondaryLen && shittyInternetMode){ if(secondaryData && secondaryLen && shittyInternetMode){
Buffer ecBuf(secondaryLen); Buffer ecBuf(secondaryLen);
ecBuf.CopyFrom(secondaryData, 0, secondaryLen); ecBuf.CopyFrom(secondaryData, 0, secondaryLen);
ecAudioPackets.push_back(move(ecBuf)); ecAudioPackets.push_back(move(ecBuf));
while(ecAudioPackets.size()>4) while(ecAudioPackets.size()>4)
ecAudioPackets.erase(ecAudioPackets.begin()); ecAudioPackets.erase(ecAudioPackets.begin());
buf=outgoingPacketsBufferPool.Get(); pkt=BufferOutputStream(1500);
if(buf){ pkt.WriteByte(outgoingStreams[0]->id);
BufferOutputStream pkt(buf, outgoingPacketsBufferPool.GetSingleBufferSize()); pkt.WriteInt32(audioTimestampOut);
pkt.WriteByte(outgoingStreams[0]->id); pkt.WriteByte((unsigned char)ecAudioPackets.size());
pkt.WriteInt32(audioTimestampOut); for(Buffer& ecData:ecAudioPackets){
pkt.WriteByte((unsigned char)ecAudioPackets.size()); pkt.WriteByte((unsigned char)ecData.Length());
for(Buffer& ecData:ecAudioPackets){ pkt.WriteBytes(ecData);
pkt.WriteByte((unsigned char)ecData.Length());
pkt.WriteBytes(ecData);
}
PendingOutgoingPacket p{
GenerateOutSeq(),
PKT_STREAM_EC,
pkt.GetLength(),
buf,
0
};
sendQueue->Put(p);
}else{
LOGW("Out of outgoing packet buffers!");
} }
PendingOutgoingPacket p{
GenerateOutSeq(),
PKT_STREAM_EC,
pkt.GetLength(),
Buffer(move(pkt)),
0
};
sendQueue->Put(move(p));
} }
audioTimestampOut+=outgoingStreams[0]->frameDuration; audioTimestampOut+=outgoingStreams[0]->frameDuration;
@ -685,12 +674,7 @@ void VoIPController::SendInit(){
for(shared_ptr<Endpoint>& e:endpoints){ for(shared_ptr<Endpoint>& e:endpoints){
if(e->type==Endpoint::TYPE_TCP_RELAY && !useTCP) if(e->type==Endpoint::TYPE_TCP_RELAY && !useTCP)
continue; continue;
unsigned char *pkt=outgoingPacketsBufferPool.Get(); BufferOutputStream out(1024);
if(!pkt){
LOGW("can't send init, queue overflow");
continue;
}
BufferOutputStream out(pkt, outgoingPacketsBufferPool.GetSingleBufferSize());
out.WriteInt32(PROTOCOL_VERSION); out.WriteInt32(PROTOCOL_VERSION);
out.WriteInt32(MIN_PROTOCOL_VERSION); out.WriteInt32(MIN_PROTOCOL_VERSION);
uint32_t flags=0; uint32_t flags=0;
@ -722,7 +706,7 @@ void VoIPController::SendInit(){
/*.seq=*/initSeq, /*.seq=*/initSeq,
/*.type=*/PKT_INIT, /*.type=*/PKT_INIT,
/*.len=*/out.GetLength(), /*.len=*/out.GetLength(),
/*.data=*/pkt, /*.data=*/Buffer(move(out)),
/*.endpoint=*/e->id /*.endpoint=*/e->id
}); });
} }
@ -899,7 +883,7 @@ void VoIPController::RunSendThread(void* arg){
unsigned char buf[1500]; unsigned char buf[1500];
while(runReceiver){ while(runReceiver){
PendingOutgoingPacket pkt=sendQueue->GetBlocking(); PendingOutgoingPacket pkt=sendQueue->GetBlocking();
if(pkt.data){ //if(pkt.data.Length()){
shared_ptr<Endpoint> endpoint; shared_ptr<Endpoint> endpoint;
if(pkt.endpoint){ if(pkt.endpoint){
endpoint=GetEndpointByID(pkt.endpoint); endpoint=GetEndpointByID(pkt.endpoint);
@ -910,13 +894,12 @@ void VoIPController::RunSendThread(void* arg){
if((endpoint->type==Endpoint::TYPE_TCP_RELAY && useTCP) || (endpoint->type!=Endpoint::TYPE_TCP_RELAY && useUDP)){ if((endpoint->type==Endpoint::TYPE_TCP_RELAY && useTCP) || (endpoint->type!=Endpoint::TYPE_TCP_RELAY && useUDP)){
BufferOutputStream p(buf, sizeof(buf)); BufferOutputStream p(buf, sizeof(buf));
WritePacketHeader(pkt.seq, &p, pkt.type, (uint32_t)pkt.len); WritePacketHeader(pkt.seq, &p, pkt.type, (uint32_t)pkt.len);
p.WriteBytes(pkt.data, pkt.len); p.WriteBytes(pkt.data);
SendPacket(p.GetBuffer(), p.GetLength(), endpoint, pkt); SendPacket(p.GetBuffer(), p.GetLength(), endpoint, pkt);
} }
outgoingPacketsBufferPool.Reuse(pkt.data); //}else{
}else{ // LOGE("tried to send null packet");
LOGE("tried to send null packet"); //}
}
} }
LOGI("=== send thread exiting ==="); LOGI("=== send thread exiting ===");
} }
@ -1357,33 +1340,29 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA
in.ReadInt32(); in.ReadInt32();
} }
unsigned char *buf=outgoingPacketsBufferPool.Get(); BufferOutputStream out(1024);
if(buf){
BufferOutputStream out(buf, outgoingPacketsBufferPool.GetSingleBufferSize());
//WritePacketHeader(out, PKT_INIT_ACK, (peerVersion>=2 ? 10 : 2)+(peerVersion>=2 ? 6 : 4)*outgoingStreams.size());
out.WriteInt32(PROTOCOL_VERSION); out.WriteInt32(PROTOCOL_VERSION);
out.WriteInt32(MIN_PROTOCOL_VERSION); out.WriteInt32(MIN_PROTOCOL_VERSION);
out.WriteByte((unsigned char) outgoingStreams.size()); out.WriteByte((unsigned char) outgoingStreams.size());
for(vector<shared_ptr<Stream>>::iterator s=outgoingStreams.begin(); s!=outgoingStreams.end(); ++s){ for(vector<shared_ptr<Stream>>::iterator s=outgoingStreams.begin(); s!=outgoingStreams.end(); ++s){
out.WriteByte((*s)->id); out.WriteByte((*s)->id);
out.WriteByte((*s)->type); out.WriteByte((*s)->type);
if(peerVersion<5) if(peerVersion<5)
out.WriteByte((unsigned char) ((*s)->codec==CODEC_OPUS ? CODEC_OPUS_OLD : 0)); out.WriteByte((unsigned char) ((*s)->codec==CODEC_OPUS ? CODEC_OPUS_OLD : 0));
else else
out.WriteInt32((*s)->codec); out.WriteInt32((*s)->codec);
out.WriteInt16((*s)->frameDuration); out.WriteInt16((*s)->frameDuration);
out.WriteByte((unsigned char) ((*s)->enabled ? 1 : 0)); out.WriteByte((unsigned char) ((*s)->enabled ? 1 : 0));
}
sendQueue->Put(PendingOutgoingPacket{
/*.seq=*/GenerateOutSeq(),
/*.type=*/PKT_INIT_ACK,
/*.len=*/out.GetLength(),
/*.data=*/buf,
/*.endpoint=*/0
});
} }
sendQueue->Put(PendingOutgoingPacket{
/*.seq=*/GenerateOutSeq(),
/*.type=*/PKT_INIT_ACK,
/*.len=*/out.GetLength(),
/*.data=*/Buffer(move(out)),
/*.endpoint=*/0
});
} }
} }
if(type==PKT_INIT_ACK){ if(type==PKT_INIT_ACK){
@ -1527,18 +1506,13 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA
LOGW("Received p2p ping but p2p is disabled by manual override"); LOGW("Received p2p ping but p2p is disabled by manual override");
return; return;
} }
unsigned char* buf=outgoingPacketsBufferPool.Get(); BufferOutputStream pkt(128);
if(!buf){
LOGW("Dropping pong packet, queue overflow");
return;
}
BufferOutputStream pkt(buf, outgoingPacketsBufferPool.GetSingleBufferSize());
pkt.WriteInt32(pseq); pkt.WriteInt32(pseq);
sendQueue->Put(PendingOutgoingPacket{ sendQueue->Put(PendingOutgoingPacket{
/*.seq=*/GenerateOutSeq(), /*.seq=*/GenerateOutSeq(),
/*.type=*/PKT_PONG, /*.type=*/PKT_PONG,
/*.len=*/pkt.GetLength(), /*.len=*/pkt.GetLength(),
/*.data=*/buf, /*.data=*/Buffer(move(pkt)),
/*.endpoint=*/srcEndpoint->id, /*.endpoint=*/srcEndpoint->id,
}); });
} }
@ -2846,16 +2820,13 @@ void VoIPController::SendRelayPings(){
continue; continue;
if(GetCurrentTime()-endpoint->lastPingTime>=10){ if(GetCurrentTime()-endpoint->lastPingTime>=10){
LOGV("Sending ping to %s", endpoint->GetAddress().ToString().c_str()); LOGV("Sending ping to %s", endpoint->GetAddress().ToString().c_str());
unsigned char* buf=outgoingPacketsBufferPool.Get(); sendQueue->Put(PendingOutgoingPacket{
if(buf){ /*.seq=*/(endpoint->lastPingSeq=GenerateOutSeq()),
sendQueue->Put(PendingOutgoingPacket{ /*.type=*/PKT_PING,
/*.seq=*/(endpoint->lastPingSeq=GenerateOutSeq()), /*.len=*/0,
/*.type=*/PKT_PING, /*.data=*/Buffer(),
/*.len=*/0, /*.endpoint=*/endpoint->id
/*.data=*/buf, });
/*.endpoint=*/endpoint->id
});
}
endpoint->lastPingTime=GetCurrentTime(); endpoint->lastPingTime=GetCurrentTime();
} }
if(endpoint->type==Endpoint::TYPE_UDP_RELAY || (useTCP && endpoint->type==Endpoint::TYPE_TCP_RELAY)){ if(endpoint->type==Endpoint::TYPE_UDP_RELAY || (useTCP && endpoint->type==Endpoint::TYPE_TCP_RELAY)){
@ -3086,40 +3057,35 @@ void VoIPController::UpdateQueuedPackets(){
} }
if(GetCurrentTime()-qp->lastSentTime>=qp->retryInterval){ if(GetCurrentTime()-qp->lastSentTime>=qp->retryInterval){
messageThread.Post(std::bind(&VoIPController::UpdateQueuedPackets, this), qp->retryInterval); messageThread.Post(std::bind(&VoIPController::UpdateQueuedPackets, this), qp->retryInterval);
unsigned char *buf=outgoingPacketsBufferPool.Get(); uint32_t seq=GenerateOutSeq();
if(buf){ qp->seqs.Add(seq);
uint32_t seq=GenerateOutSeq(); qp->lastSentTime=GetCurrentTime();
qp->seqs.Add(seq); //LOGD("Sending queued packet, seq=%u, type=%u, len=%u", seq, qp.type, qp.data.Length());
qp->lastSentTime=GetCurrentTime(); Buffer buf(qp->data.Length());
//LOGD("Sending queued packet, seq=%u, type=%u, len=%u", seq, qp.type, qp.data.Length()); if(qp->firstSentTime==0)
if(qp->firstSentTime==0) qp->firstSentTime=qp->lastSentTime;
qp->firstSentTime=qp->lastSentTime; if(qp->data.Length())
if(qp->data.Length()) buf.CopyFrom(qp->data, qp->data.Length());
memcpy(buf, *qp->data, qp->data.Length()); sendQueue->Put(PendingOutgoingPacket{
sendQueue->Put(PendingOutgoingPacket{ /*.seq=*/seq,
/*.seq=*/seq, /*.type=*/qp->type,
/*.type=*/qp->type, /*.len=*/qp->data.Length(),
/*.len=*/qp->data.Length(), /*.data=*/move(buf),
/*.data=*/buf, /*.endpoint=*/0
/*.endpoint=*/0 });
});
}
} }
++qp; ++qp;
} }
} }
void VoIPController::SendNopPacket(){ void VoIPController::SendNopPacket(){
unsigned char* buf=outgoingPacketsBufferPool.Get(); sendQueue->Put(PendingOutgoingPacket{
if(buf){ /*.seq=*/(firstSentPing=GenerateOutSeq()),
sendQueue->Put(PendingOutgoingPacket{ /*.type=*/PKT_NOP,
/*.seq=*/(firstSentPing=GenerateOutSeq()), /*.len=*/0,
/*.type=*/PKT_NOP, /*.data=*/Buffer(),
/*.len=*/0, /*.endpoint=*/0
/*.data=*/buf, });
/*.endpoint=*/0
});
}
} }
void VoIPController::SendPublicEndpointsRequest(){ void VoIPController::SendPublicEndpointsRequest(){

View File

@ -34,7 +34,7 @@
#include "PacketReassembler.h" #include "PacketReassembler.h"
#include "MessageThread.h" #include "MessageThread.h"
#define LIBTGVOIP_VERSION "2.2.1" #define LIBTGVOIP_VERSION "2.2.2"
#ifdef _WIN32 #ifdef _WIN32
#undef GetCurrentTime #undef GetCurrentTime
@ -384,9 +384,8 @@ namespace tgvoip{
struct PendingOutgoingPacket{ struct PendingOutgoingPacket{
uint32_t seq; uint32_t seq;
unsigned char type; unsigned char type;
//Buffer data;
size_t len; size_t len;
unsigned char* data; Buffer data;
int64_t endpoint; int64_t endpoint;
}; };
struct SegmentedPacket{ struct SegmentedPacket{
@ -554,7 +553,6 @@ namespace tgvoip{
NetworkSocket* openingTcpSocket; NetworkSocket* openingTcpSocket;
HistoricBuffer<unsigned char, 4, int> signalBarsHistory; HistoricBuffer<unsigned char, 4, int> signalBarsHistory;
BufferPool outgoingPacketsBufferPool;
int udpConnectivityState; int udpConnectivityState;
double lastUdpPingTime; double lastUdpPingTime;
int udpPingCount; int udpPingCount;

View File

@ -39,7 +39,10 @@ AudioInputPulse::AudioInputPulse(pa_context* context, pa_threaded_mainloop* main
.channels=1 .channels=1
}; };
stream=pa_stream_new(context, "libtgvoip capture", &sample_specifications, NULL); pa_proplist* proplist=pa_proplist_new();
pa_proplist_sets(proplist, PA_PROP_FILTER_APPLY, ""); // according to PA sources, this disables any possible filters
stream=pa_stream_new_with_proplist(context, "libtgvoip capture", &sample_specifications, NULL, proplist);
pa_proplist_free(proplist);
if(!stream){ if(!stream){
LOGE("Error initializing PulseAudio (pa_stream_new)"); LOGE("Error initializing PulseAudio (pa_stream_new)");
failed=true; failed=true;

View File

@ -41,7 +41,10 @@ AudioOutputPulse::AudioOutputPulse(pa_context* context, pa_threaded_mainloop* ma
}; };
pa_threaded_mainloop_lock(mainloop); pa_threaded_mainloop_lock(mainloop);
stream=pa_stream_new(context, "libtgvoip playback", &sample_specifications, NULL); pa_proplist* proplist=pa_proplist_new();
pa_proplist_sets(proplist, PA_PROP_FILTER_APPLY, ""); // according to PA sources, this disables any possible filters
stream=pa_stream_new_with_proplist(context, "libtgvoip playback", &sample_specifications, NULL, proplist);
pa_proplist_free(proplist);
if(!stream){ if(!stream){
LOGE("Error initializing PulseAudio (pa_stream_new)"); LOGE("Error initializing PulseAudio (pa_stream_new)");
pa_threaded_mainloop_unlock(mainloop); pa_threaded_mainloop_unlock(mainloop);
@ -154,7 +157,10 @@ void AudioOutputPulse::StreamWriteCallback(pa_stream *stream, size_t requestedBy
} }
void AudioOutputPulse::StreamWriteCallback(pa_stream *stream, size_t requestedBytes) { void AudioOutputPulse::StreamWriteCallback(pa_stream *stream, size_t requestedBytes) {
assert(requestedBytes<=sizeof(remainingData)); //assert(requestedBytes<=sizeof(remainingData));
if(requestedBytes>sizeof(remainingData)){
requestedBytes=960*2; // force buffer size to 20ms. This probably wrecks the jitter buffer, but still better than crashing
}
while(requestedBytes>remainingDataSize){ while(requestedBytes>remainingDataSize){
if(isPlaying){ if(isPlaying){
InvokeCallback(remainingData+remainingDataSize, 960*2); InvokeCallback(remainingData+remainingDataSize, 960*2);

View File

@ -22,6 +22,7 @@ void* AudioPulse::lib=NULL;
DECLARE_DL_FUNCTION(pa_threaded_mainloop_new); DECLARE_DL_FUNCTION(pa_threaded_mainloop_new);
DECLARE_DL_FUNCTION(pa_threaded_mainloop_get_api); DECLARE_DL_FUNCTION(pa_threaded_mainloop_get_api);
DECLARE_DL_FUNCTION(pa_context_new); DECLARE_DL_FUNCTION(pa_context_new);
DECLARE_DL_FUNCTION(pa_context_new_with_proplist);
DECLARE_DL_FUNCTION(pa_context_set_state_callback); DECLARE_DL_FUNCTION(pa_context_set_state_callback);
DECLARE_DL_FUNCTION(pa_threaded_mainloop_lock); DECLARE_DL_FUNCTION(pa_threaded_mainloop_lock);
DECLARE_DL_FUNCTION(pa_threaded_mainloop_unlock); DECLARE_DL_FUNCTION(pa_threaded_mainloop_unlock);
@ -29,7 +30,7 @@ DECLARE_DL_FUNCTION(pa_threaded_mainloop_start);
DECLARE_DL_FUNCTION(pa_context_connect); DECLARE_DL_FUNCTION(pa_context_connect);
DECLARE_DL_FUNCTION(pa_context_get_state); DECLARE_DL_FUNCTION(pa_context_get_state);
DECLARE_DL_FUNCTION(pa_threaded_mainloop_wait); DECLARE_DL_FUNCTION(pa_threaded_mainloop_wait);
DECLARE_DL_FUNCTION(pa_stream_new); DECLARE_DL_FUNCTION(pa_stream_new_with_proplist);
DECLARE_DL_FUNCTION(pa_stream_set_state_callback); DECLARE_DL_FUNCTION(pa_stream_set_state_callback);
DECLARE_DL_FUNCTION(pa_stream_set_write_callback); DECLARE_DL_FUNCTION(pa_stream_set_write_callback);
DECLARE_DL_FUNCTION(pa_stream_connect_playback); DECLARE_DL_FUNCTION(pa_stream_connect_playback);
@ -57,6 +58,9 @@ DECLARE_DL_FUNCTION(pa_mainloop_free);
DECLARE_DL_FUNCTION(pa_context_get_sink_info_list); DECLARE_DL_FUNCTION(pa_context_get_sink_info_list);
DECLARE_DL_FUNCTION(pa_context_get_source_info_list); DECLARE_DL_FUNCTION(pa_context_get_source_info_list);
DECLARE_DL_FUNCTION(pa_operation_get_state); DECLARE_DL_FUNCTION(pa_operation_get_state);
DECLARE_DL_FUNCTION(pa_proplist_new);
DECLARE_DL_FUNCTION(pa_proplist_sets);
DECLARE_DL_FUNCTION(pa_proplist_free);
#include "PulseFunctions.h" #include "PulseFunctions.h"
@ -75,6 +79,7 @@ bool AudioPulse::Load(){
LOAD_DL_FUNCTION(pa_threaded_mainloop_new); LOAD_DL_FUNCTION(pa_threaded_mainloop_new);
LOAD_DL_FUNCTION(pa_threaded_mainloop_get_api); LOAD_DL_FUNCTION(pa_threaded_mainloop_get_api);
LOAD_DL_FUNCTION(pa_context_new); LOAD_DL_FUNCTION(pa_context_new);
LOAD_DL_FUNCTION(pa_context_new_with_proplist);
LOAD_DL_FUNCTION(pa_context_set_state_callback); LOAD_DL_FUNCTION(pa_context_set_state_callback);
LOAD_DL_FUNCTION(pa_threaded_mainloop_lock); LOAD_DL_FUNCTION(pa_threaded_mainloop_lock);
LOAD_DL_FUNCTION(pa_threaded_mainloop_unlock); LOAD_DL_FUNCTION(pa_threaded_mainloop_unlock);
@ -82,7 +87,7 @@ bool AudioPulse::Load(){
LOAD_DL_FUNCTION(pa_context_connect); LOAD_DL_FUNCTION(pa_context_connect);
LOAD_DL_FUNCTION(pa_context_get_state); LOAD_DL_FUNCTION(pa_context_get_state);
LOAD_DL_FUNCTION(pa_threaded_mainloop_wait); LOAD_DL_FUNCTION(pa_threaded_mainloop_wait);
LOAD_DL_FUNCTION(pa_stream_new); LOAD_DL_FUNCTION(pa_stream_new_with_proplist);
LOAD_DL_FUNCTION(pa_stream_set_state_callback); LOAD_DL_FUNCTION(pa_stream_set_state_callback);
LOAD_DL_FUNCTION(pa_stream_set_write_callback); LOAD_DL_FUNCTION(pa_stream_set_write_callback);
LOAD_DL_FUNCTION(pa_stream_connect_playback); LOAD_DL_FUNCTION(pa_stream_connect_playback);
@ -110,6 +115,9 @@ bool AudioPulse::Load(){
LOAD_DL_FUNCTION(pa_context_get_sink_info_list); LOAD_DL_FUNCTION(pa_context_get_sink_info_list);
LOAD_DL_FUNCTION(pa_context_get_source_info_list); LOAD_DL_FUNCTION(pa_context_get_source_info_list);
LOAD_DL_FUNCTION(pa_operation_get_state); LOAD_DL_FUNCTION(pa_operation_get_state);
LOAD_DL_FUNCTION(pa_proplist_new);
LOAD_DL_FUNCTION(pa_proplist_sets);
LOAD_DL_FUNCTION(pa_proplist_free);
loaded=true; loaded=true;
return true; return true;
@ -146,7 +154,10 @@ AudioPulse::AudioPulse(std::string inputDevice, std::string outputDevice){
{ {
snprintf(exeName, sizeof(exeName), "Process %d", getpid()); snprintf(exeName, sizeof(exeName), "Process %d", getpid());
} }
context=pa_context_new(mainloopApi, exeName); pa_proplist* proplist=pa_proplist_new();
pa_proplist_sets(proplist, PA_PROP_MEDIA_ROLE, "phone");
context=pa_context_new_with_proplist(mainloopApi, exeName, proplist);
pa_proplist_free(proplist);
if(!context){ if(!context){
LOGE("Error initializing PulseAudio (pa_context_new)"); LOGE("Error initializing PulseAudio (pa_context_new)");
failed=true; failed=true;

View File

@ -31,6 +31,7 @@ namespace tgvoip{
DECLARE_DL_FUNCTION(pa_threaded_mainloop_new); DECLARE_DL_FUNCTION(pa_threaded_mainloop_new);
DECLARE_DL_FUNCTION(pa_threaded_mainloop_get_api); DECLARE_DL_FUNCTION(pa_threaded_mainloop_get_api);
DECLARE_DL_FUNCTION(pa_context_new); DECLARE_DL_FUNCTION(pa_context_new);
DECLARE_DL_FUNCTION(pa_context_new_with_proplist);
DECLARE_DL_FUNCTION(pa_context_set_state_callback); DECLARE_DL_FUNCTION(pa_context_set_state_callback);
DECLARE_DL_FUNCTION(pa_threaded_mainloop_lock); DECLARE_DL_FUNCTION(pa_threaded_mainloop_lock);
DECLARE_DL_FUNCTION(pa_threaded_mainloop_unlock); DECLARE_DL_FUNCTION(pa_threaded_mainloop_unlock);
@ -38,7 +39,7 @@ namespace tgvoip{
DECLARE_DL_FUNCTION(pa_context_connect); DECLARE_DL_FUNCTION(pa_context_connect);
DECLARE_DL_FUNCTION(pa_context_get_state); DECLARE_DL_FUNCTION(pa_context_get_state);
DECLARE_DL_FUNCTION(pa_threaded_mainloop_wait); DECLARE_DL_FUNCTION(pa_threaded_mainloop_wait);
DECLARE_DL_FUNCTION(pa_stream_new); DECLARE_DL_FUNCTION(pa_stream_new_with_proplist);
DECLARE_DL_FUNCTION(pa_stream_set_state_callback); DECLARE_DL_FUNCTION(pa_stream_set_state_callback);
DECLARE_DL_FUNCTION(pa_stream_set_write_callback); DECLARE_DL_FUNCTION(pa_stream_set_write_callback);
DECLARE_DL_FUNCTION(pa_stream_connect_playback); DECLARE_DL_FUNCTION(pa_stream_connect_playback);
@ -68,6 +69,10 @@ namespace tgvoip{
DECLARE_DL_FUNCTION(pa_context_get_source_info_list); DECLARE_DL_FUNCTION(pa_context_get_source_info_list);
DECLARE_DL_FUNCTION(pa_operation_get_state); DECLARE_DL_FUNCTION(pa_operation_get_state);
DECLARE_DL_FUNCTION(pa_proplist_new);
DECLARE_DL_FUNCTION(pa_proplist_sets);
DECLARE_DL_FUNCTION(pa_proplist_free);
private: private:
static void* lib; static void* lib;
static bool loaded; static bool loaded;

View File

@ -4,6 +4,7 @@
#define pa_threaded_mainloop_new AudioPulse::_import_pa_threaded_mainloop_new #define pa_threaded_mainloop_new AudioPulse::_import_pa_threaded_mainloop_new
#define pa_threaded_mainloop_get_api AudioPulse::_import_pa_threaded_mainloop_get_api #define pa_threaded_mainloop_get_api AudioPulse::_import_pa_threaded_mainloop_get_api
#define pa_context_new AudioPulse::_import_pa_context_new #define pa_context_new AudioPulse::_import_pa_context_new
#define pa_context_new_with_proplist AudioPulse::_import_pa_context_new_with_proplist
#define pa_context_set_state_callback AudioPulse::_import_pa_context_set_state_callback #define pa_context_set_state_callback AudioPulse::_import_pa_context_set_state_callback
#define pa_threaded_mainloop_lock AudioPulse::_import_pa_threaded_mainloop_lock #define pa_threaded_mainloop_lock AudioPulse::_import_pa_threaded_mainloop_lock
#define pa_threaded_mainloop_unlock AudioPulse::_import_pa_threaded_mainloop_unlock #define pa_threaded_mainloop_unlock AudioPulse::_import_pa_threaded_mainloop_unlock
@ -11,7 +12,7 @@
#define pa_context_connect AudioPulse::_import_pa_context_connect #define pa_context_connect AudioPulse::_import_pa_context_connect
#define pa_context_get_state AudioPulse::_import_pa_context_get_state #define pa_context_get_state AudioPulse::_import_pa_context_get_state
#define pa_threaded_mainloop_wait AudioPulse::_import_pa_threaded_mainloop_wait #define pa_threaded_mainloop_wait AudioPulse::_import_pa_threaded_mainloop_wait
#define pa_stream_new AudioPulse::_import_pa_stream_new #define pa_stream_new_with_proplist AudioPulse::_import_pa_stream_new_with_proplist
#define pa_stream_set_state_callback AudioPulse::_import_pa_stream_set_state_callback #define pa_stream_set_state_callback AudioPulse::_import_pa_stream_set_state_callback
#define pa_stream_set_write_callback AudioPulse::_import_pa_stream_set_write_callback #define pa_stream_set_write_callback AudioPulse::_import_pa_stream_set_write_callback
#define pa_stream_connect_playback AudioPulse::_import_pa_stream_connect_playback #define pa_stream_connect_playback AudioPulse::_import_pa_stream_connect_playback
@ -39,5 +40,8 @@
#define pa_context_get_sink_info_list AudioPulse::_import_pa_context_get_sink_info_list #define pa_context_get_sink_info_list AudioPulse::_import_pa_context_get_sink_info_list
#define pa_context_get_source_info_list AudioPulse::_import_pa_context_get_source_info_list #define pa_context_get_source_info_list AudioPulse::_import_pa_context_get_source_info_list
#define pa_operation_get_state AudioPulse::_import_pa_operation_get_state #define pa_operation_get_state AudioPulse::_import_pa_operation_get_state
#define pa_proplist_new AudioPulse::_import_pa_proplist_new
#define pa_proplist_sets AudioPulse::_import_pa_proplist_sets
#define pa_proplist_free AudioPulse::_import_pa_proplist_free
#endif //LIBTGVOIP_PULSE_FUNCTIONS_H #endif //LIBTGVOIP_PULSE_FUNCTIONS_H

View File

@ -30,7 +30,7 @@ AudioInputWASAPI::AudioInputWASAPI(std::string deviceID){
remainingDataLen=0; remainingDataLen=0;
refCount=1; refCount=1;
HRESULT res; HRESULT res;
res=CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); res=CoInitializeEx(NULL, COINIT_MULTITHREADED);
CHECK_RES(res, "CoInitializeEx"); CHECK_RES(res, "CoInitializeEx");
#ifdef TGVOIP_WINXP_COMPAT #ifdef TGVOIP_WINXP_COMPAT
HANDLE (WINAPI *__CreateEventExA)(LPSECURITY_ATTRIBUTES lpEventAttributes, LPCSTR lpName, DWORD dwFlags, DWORD dwDesiredAccess); HANDLE (WINAPI *__CreateEventExA)(LPSECURITY_ATTRIBUTES lpEventAttributes, LPCSTR lpName, DWORD dwFlags, DWORD dwDesiredAccess);
@ -123,7 +123,7 @@ bool AudioInputWASAPI::IsRecording(){
void AudioInputWASAPI::EnumerateDevices(std::vector<tgvoip::AudioInputDevice>& devs){ void AudioInputWASAPI::EnumerateDevices(std::vector<tgvoip::AudioInputDevice>& devs){
#ifdef TGVOIP_WINDOWS_DESKTOP #ifdef TGVOIP_WINDOWS_DESKTOP
HRESULT res; HRESULT res;
res=CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); res=CoInitializeEx(NULL, COINIT_MULTITHREADED);
SCHECK_RES(res, "CoInitializeEx"); SCHECK_RES(res, "CoInitializeEx");
IMMDeviceEnumerator *deviceEnumerator = NULL; IMMDeviceEnumerator *deviceEnumerator = NULL;
@ -324,7 +324,7 @@ void AudioInputWASAPI::RunThread() {
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
HANDLE waitArray[]={shutdownEvent, streamSwitchEvent, audioSamplesReadyEvent}; HANDLE waitArray[]={shutdownEvent, streamSwitchEvent, audioSamplesReadyEvent};
HRESULT res=CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); HRESULT res=CoInitializeEx(NULL, COINIT_MULTITHREADED);
CHECK_RES(res, "CoInitializeEx in capture thread"); CHECK_RES(res, "CoInitializeEx in capture thread");
uint32_t bufferSize=0; uint32_t bufferSize=0;

View File

@ -34,7 +34,7 @@ AudioOutputWASAPI::AudioOutputWASAPI(std::string deviceID){
remainingDataLen=0; remainingDataLen=0;
refCount=1; refCount=1;
HRESULT res; HRESULT res;
res=CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); res=CoInitializeEx(NULL, COINIT_MULTITHREADED);
CHECK_RES(res, "CoInitializeEx"); CHECK_RES(res, "CoInitializeEx");
#ifdef TGVOIP_WINXP_COMPAT #ifdef TGVOIP_WINXP_COMPAT
HANDLE (WINAPI *__CreateEventExA)(LPSECURITY_ATTRIBUTES lpEventAttributes, LPCSTR lpName, DWORD dwFlags, DWORD dwDesiredAccess); HANDLE (WINAPI *__CreateEventExA)(LPSECURITY_ATTRIBUTES lpEventAttributes, LPCSTR lpName, DWORD dwFlags, DWORD dwDesiredAccess);
@ -119,7 +119,7 @@ bool AudioOutputWASAPI::IsPlaying(){
void AudioOutputWASAPI::EnumerateDevices(std::vector<tgvoip::AudioOutputDevice>& devs){ void AudioOutputWASAPI::EnumerateDevices(std::vector<tgvoip::AudioOutputDevice>& devs){
#ifdef TGVOIP_WINDOWS_DESKTOP #ifdef TGVOIP_WINDOWS_DESKTOP
HRESULT res; HRESULT res;
res=CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); res=CoInitializeEx(NULL, COINIT_MULTITHREADED);
SCHECK_RES(res, "CoInitializeEx"); SCHECK_RES(res, "CoInitializeEx");
IMMDeviceEnumerator *deviceEnumerator = NULL; IMMDeviceEnumerator *deviceEnumerator = NULL;
@ -324,7 +324,7 @@ void AudioOutputWASAPI::RunThread() {
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
HANDLE waitArray[]={shutdownEvent, streamSwitchEvent, audioSamplesReadyEvent}; HANDLE waitArray[]={shutdownEvent, streamSwitchEvent, audioSamplesReadyEvent};
HRESULT res=CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); HRESULT res=CoInitializeEx(NULL, COINIT_MULTITHREADED);
CHECK_RES(res, "CoInitializeEx in render thread"); CHECK_RES(res, "CoInitializeEx in render thread");
uint32_t bufferSize; uint32_t bufferSize;

View File

@ -75,7 +75,6 @@ namespace tgvoip{
public: public:
Thread(MethodPointerBase* entry, void* arg) : entry(entry), arg(arg){ Thread(MethodPointerBase* entry, void* arg) : entry(entry), arg(arg){
name=NULL; name=NULL;
thread=NULL;
} }
virtual ~Thread(){ virtual ~Thread(){
@ -83,11 +82,13 @@ namespace tgvoip{
} }
void Start(){ void Start(){
pthread_create(&thread, NULL, Thread::ActualEntryPoint, this); if(pthread_create(&thread, NULL, Thread::ActualEntryPoint, this)==0){
valid=true;
}
} }
void Join(){ void Join(){
if(thread) if(valid)
pthread_join(thread, NULL); pthread_join(thread, NULL);
} }
@ -107,7 +108,7 @@ namespace tgvoip{
} }
bool IsCurrent(){ bool IsCurrent(){
return thread==pthread_self(); return pthread_equal(thread, pthread_self())!=0;
} }
private: private:
@ -131,6 +132,7 @@ namespace tgvoip{
pthread_t thread; pthread_t thread;
const char* name; const char* name;
bool maxPriority=false; bool maxPriority=false;
bool valid=false;
}; };
} }