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:
parent
3334409ac7
commit
529a3bf14f
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -90,7 +90,10 @@ namespace tgvoip{
|
|||||||
class Buffer{
|
class Buffer{
|
||||||
public:
|
public:
|
||||||
Buffer(size_t capacity){
|
Buffer(size_t capacity){
|
||||||
|
if(capacity>0)
|
||||||
data=(unsigned char *) malloc(capacity);
|
data=(unsigned char *) malloc(capacity);
|
||||||
|
else
|
||||||
|
data=NULL;
|
||||||
length=capacity;
|
length=capacity;
|
||||||
};
|
};
|
||||||
Buffer(const Buffer& other)=delete;
|
Buffer(const Buffer& other)=delete;
|
||||||
|
@ -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,9 +410,7 @@ 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
|
||||||
@ -428,22 +425,17 @@ void VoIPController::HandleAudioInput(unsigned char *data, size_t len, unsigned
|
|||||||
/*.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){
|
|
||||||
BufferOutputStream pkt(buf, outgoingPacketsBufferPool.GetSingleBufferSize());
|
|
||||||
pkt.WriteByte(outgoingStreams[0]->id);
|
pkt.WriteByte(outgoingStreams[0]->id);
|
||||||
pkt.WriteInt32(audioTimestampOut);
|
pkt.WriteInt32(audioTimestampOut);
|
||||||
pkt.WriteByte((unsigned char)ecAudioPackets.size());
|
pkt.WriteByte((unsigned char)ecAudioPackets.size());
|
||||||
@ -456,13 +448,10 @@ void VoIPController::HandleAudioInput(unsigned char *data, size_t len, unsigned
|
|||||||
GenerateOutSeq(),
|
GenerateOutSeq(),
|
||||||
PKT_STREAM_EC,
|
PKT_STREAM_EC,
|
||||||
pkt.GetLength(),
|
pkt.GetLength(),
|
||||||
buf,
|
Buffer(move(pkt)),
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
sendQueue->Put(p);
|
sendQueue->Put(move(p));
|
||||||
}else{
|
|
||||||
LOGW("Out of outgoing packet buffers!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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,10 +1340,7 @@ 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);
|
||||||
@ -1380,12 +1360,11 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA
|
|||||||
/*.seq=*/GenerateOutSeq(),
|
/*.seq=*/GenerateOutSeq(),
|
||||||
/*.type=*/PKT_INIT_ACK,
|
/*.type=*/PKT_INIT_ACK,
|
||||||
/*.len=*/out.GetLength(),
|
/*.len=*/out.GetLength(),
|
||||||
/*.data=*/buf,
|
/*.data=*/Buffer(move(out)),
|
||||||
/*.endpoint=*/0
|
/*.endpoint=*/0
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if(type==PKT_INIT_ACK){
|
if(type==PKT_INIT_ACK){
|
||||||
LOGD("Received init ack");
|
LOGD("Received 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();
|
|
||||||
if(buf){
|
|
||||||
sendQueue->Put(PendingOutgoingPacket{
|
sendQueue->Put(PendingOutgoingPacket{
|
||||||
/*.seq=*/(endpoint->lastPingSeq=GenerateOutSeq()),
|
/*.seq=*/(endpoint->lastPingSeq=GenerateOutSeq()),
|
||||||
/*.type=*/PKT_PING,
|
/*.type=*/PKT_PING,
|
||||||
/*.len=*/0,
|
/*.len=*/0,
|
||||||
/*.data=*/buf,
|
/*.data=*/Buffer(),
|
||||||
/*.endpoint=*/endpoint->id
|
/*.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();
|
|
||||||
if(buf){
|
|
||||||
uint32_t seq=GenerateOutSeq();
|
uint32_t seq=GenerateOutSeq();
|
||||||
qp->seqs.Add(seq);
|
qp->seqs.Add(seq);
|
||||||
qp->lastSentTime=GetCurrentTime();
|
qp->lastSentTime=GetCurrentTime();
|
||||||
//LOGD("Sending queued packet, seq=%u, type=%u, len=%u", seq, qp.type, qp.data.Length());
|
//LOGD("Sending queued packet, seq=%u, type=%u, len=%u", seq, qp.type, qp.data.Length());
|
||||||
|
Buffer buf(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())
|
||||||
memcpy(buf, *qp->data, qp->data.Length());
|
buf.CopyFrom(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=*/buf,
|
/*.data=*/move(buf),
|
||||||
/*.endpoint=*/0
|
/*.endpoint=*/0
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
++qp;
|
++qp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoIPController::SendNopPacket(){
|
void VoIPController::SendNopPacket(){
|
||||||
unsigned char* buf=outgoingPacketsBufferPool.Get();
|
|
||||||
if(buf){
|
|
||||||
sendQueue->Put(PendingOutgoingPacket{
|
sendQueue->Put(PendingOutgoingPacket{
|
||||||
/*.seq=*/(firstSentPing=GenerateOutSeq()),
|
/*.seq=*/(firstSentPing=GenerateOutSeq()),
|
||||||
/*.type=*/PKT_NOP,
|
/*.type=*/PKT_NOP,
|
||||||
/*.len=*/0,
|
/*.len=*/0,
|
||||||
/*.data=*/buf,
|
/*.data=*/Buffer(),
|
||||||
/*.endpoint=*/0
|
/*.endpoint=*/0
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoIPController::SendPublicEndpointsRequest(){
|
void VoIPController::SendPublicEndpointsRequest(){
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
10
threading.h
10
threading.h
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user