mirror of
https://github.com/moonlight-stream/moonlight-common-c.git
synced 2025-08-17 17:05:50 +00:00
Add capability to combine audio receive and decode thread
This commit is contained in:
parent
de37896c22
commit
c829d9c742
@ -13,6 +13,8 @@ static PLT_THREAD udpPingThread;
|
|||||||
static PLT_THREAD receiveThread;
|
static PLT_THREAD receiveThread;
|
||||||
static PLT_THREAD decoderThread;
|
static PLT_THREAD decoderThread;
|
||||||
|
|
||||||
|
static unsigned short lastSeq = 0;
|
||||||
|
|
||||||
#define RTP_PORT 48000
|
#define RTP_PORT 48000
|
||||||
|
|
||||||
#define MAX_PACKET_SIZE 100
|
#define MAX_PACKET_SIZE 100
|
||||||
@ -30,7 +32,9 @@ typedef struct _QUEUED_AUDIO_PACKET {
|
|||||||
|
|
||||||
/* Initialize the audio stream */
|
/* Initialize the audio stream */
|
||||||
void initializeAudioStream(void) {
|
void initializeAudioStream(void) {
|
||||||
LbqInitializeLinkedBlockingQueue(&packetQueue, 30);
|
if ((AudioCallbacks.capabilities & CAPABILITY_DIRECT_SUBMIT) == 0) {
|
||||||
|
LbqInitializeLinkedBlockingQueue(&packetQueue, 30);
|
||||||
|
}
|
||||||
RtpqInitializeQueue(&rtpReorderQueue, RTPQ_DEFAULT_MAX_SIZE, RTPQ_DEFUALT_QUEUE_TIME);
|
RtpqInitializeQueue(&rtpReorderQueue, RTPQ_DEFAULT_MAX_SIZE, RTPQ_DEFUALT_QUEUE_TIME);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +53,9 @@ static void freePacketList(PLINKED_BLOCKING_QUEUE_ENTRY entry) {
|
|||||||
|
|
||||||
/* Tear down the audio stream once we're done with it */
|
/* Tear down the audio stream once we're done with it */
|
||||||
void destroyAudioStream(void) {
|
void destroyAudioStream(void) {
|
||||||
freePacketList(LbqDestroyLinkedBlockingQueue(&packetQueue));
|
if ((AudioCallbacks.capabilities & CAPABILITY_DIRECT_SUBMIT) == 0) {
|
||||||
|
freePacketList(LbqDestroyLinkedBlockingQueue(&packetQueue));
|
||||||
|
}
|
||||||
RtpqCleanupQueue(&rtpReorderQueue);
|
RtpqCleanupQueue(&rtpReorderQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,6 +101,21 @@ static int queuePacketToLbq(PQUEUED_AUDIO_PACKET *packet) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void decodeInputData(PQUEUED_AUDIO_PACKET packet) {
|
||||||
|
PRTP_PACKET rtp;
|
||||||
|
|
||||||
|
rtp = (PRTP_PACKET) &packet->data[0];
|
||||||
|
if (lastSeq != 0 && (unsigned short) (lastSeq + 1) != rtp->sequenceNumber) {
|
||||||
|
Limelog("Received OOS audio data (expected %d, but got %d)\n", lastSeq + 1, rtp->sequenceNumber);
|
||||||
|
|
||||||
|
AudioCallbacks.decodeAndPlaySample(NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
lastSeq = rtp->sequenceNumber;
|
||||||
|
|
||||||
|
AudioCallbacks.decodeAndPlaySample((char *) (rtp + 1), packet->size - sizeof(*rtp));
|
||||||
|
}
|
||||||
|
|
||||||
static void ReceiveThreadProc(void* context) {
|
static void ReceiveThreadProc(void* context) {
|
||||||
PRTP_PACKET rtp;
|
PRTP_PACKET rtp;
|
||||||
PQUEUED_AUDIO_PACKET packet;
|
PQUEUED_AUDIO_PACKET packet;
|
||||||
@ -136,9 +157,13 @@ static void ReceiveThreadProc(void* context) {
|
|||||||
|
|
||||||
queueStatus = RtpqAddPacket(&rtpReorderQueue, (PRTP_PACKET) packet, &packet->q.rentry);
|
queueStatus = RtpqAddPacket(&rtpReorderQueue, (PRTP_PACKET) packet, &packet->q.rentry);
|
||||||
if (queueStatus == RTPQ_RET_HANDLE_IMMEDIATELY) {
|
if (queueStatus == RTPQ_RET_HANDLE_IMMEDIATELY) {
|
||||||
if (!queuePacketToLbq(&packet)) {
|
if ((AudioCallbacks.capabilities & CAPABILITY_DIRECT_SUBMIT) == 0) {
|
||||||
// An exit signal was received
|
if (!queuePacketToLbq(&packet)) {
|
||||||
return;
|
// An exit signal was received
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
decodeInputData(packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -150,9 +175,13 @@ static void ReceiveThreadProc(void* context) {
|
|||||||
if (queueStatus == RTPQ_RET_QUEUED_PACKETS_READY) {
|
if (queueStatus == RTPQ_RET_QUEUED_PACKETS_READY) {
|
||||||
// If packets are ready, pull them and send them to the decoder
|
// If packets are ready, pull them and send them to the decoder
|
||||||
while ((packet = (PQUEUED_AUDIO_PACKET) RtpqGetQueuedPacket(&rtpReorderQueue)) != NULL) {
|
while ((packet = (PQUEUED_AUDIO_PACKET) RtpqGetQueuedPacket(&rtpReorderQueue)) != NULL) {
|
||||||
if (!queuePacketToLbq(&packet)) {
|
if ((AudioCallbacks.capabilities & CAPABILITY_DIRECT_SUBMIT) == 0) {
|
||||||
// An exit signal was received
|
if (!queuePacketToLbq(&packet)) {
|
||||||
return;
|
// An exit signal was received
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
decodeInputData(packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -164,7 +193,6 @@ static void DecoderThreadProc(void* context) {
|
|||||||
PRTP_PACKET rtp;
|
PRTP_PACKET rtp;
|
||||||
int err;
|
int err;
|
||||||
PQUEUED_AUDIO_PACKET packet;
|
PQUEUED_AUDIO_PACKET packet;
|
||||||
unsigned short lastSeq = 0;
|
|
||||||
|
|
||||||
while (!PltIsThreadInterrupted(&decoderThread)) {
|
while (!PltIsThreadInterrupted(&decoderThread)) {
|
||||||
err = LbqWaitForQueueElement(&packetQueue, (void**) &packet);
|
err = LbqWaitForQueueElement(&packetQueue, (void**) &packet);
|
||||||
@ -173,16 +201,7 @@ static void DecoderThreadProc(void* context) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtp = (PRTP_PACKET) &packet->data[0];
|
decodeInputData(packet);
|
||||||
if (lastSeq != 0 && (unsigned short) (lastSeq + 1) != rtp->sequenceNumber) {
|
|
||||||
Limelog("Received OOS audio data (expected %d, but got %d)\n", lastSeq + 1, rtp->sequenceNumber);
|
|
||||||
|
|
||||||
AudioCallbacks.decodeAndPlaySample(NULL, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
lastSeq = rtp->sequenceNumber;
|
|
||||||
|
|
||||||
AudioCallbacks.decodeAndPlaySample((char *) (rtp + 1), packet->size - sizeof(*rtp));
|
|
||||||
|
|
||||||
free(packet);
|
free(packet);
|
||||||
}
|
}
|
||||||
@ -191,7 +210,9 @@ static void DecoderThreadProc(void* context) {
|
|||||||
void stopAudioStream(void) {
|
void stopAudioStream(void) {
|
||||||
PltInterruptThread(&udpPingThread);
|
PltInterruptThread(&udpPingThread);
|
||||||
PltInterruptThread(&receiveThread);
|
PltInterruptThread(&receiveThread);
|
||||||
PltInterruptThread(&decoderThread);
|
if ((AudioCallbacks.capabilities & CAPABILITY_DIRECT_SUBMIT) == 0) {
|
||||||
|
PltInterruptThread(&decoderThread);
|
||||||
|
}
|
||||||
|
|
||||||
if (rtpSocket != INVALID_SOCKET) {
|
if (rtpSocket != INVALID_SOCKET) {
|
||||||
closesocket(rtpSocket);
|
closesocket(rtpSocket);
|
||||||
@ -200,11 +221,15 @@ void stopAudioStream(void) {
|
|||||||
|
|
||||||
PltJoinThread(&udpPingThread);
|
PltJoinThread(&udpPingThread);
|
||||||
PltJoinThread(&receiveThread);
|
PltJoinThread(&receiveThread);
|
||||||
PltJoinThread(&decoderThread);
|
if ((AudioCallbacks.capabilities & CAPABILITY_DIRECT_SUBMIT) == 0) {
|
||||||
|
PltJoinThread(&decoderThread);
|
||||||
|
}
|
||||||
|
|
||||||
PltCloseThread(&udpPingThread);
|
PltCloseThread(&udpPingThread);
|
||||||
PltCloseThread(&receiveThread);
|
PltCloseThread(&receiveThread);
|
||||||
PltCloseThread(&decoderThread);
|
if ((AudioCallbacks.capabilities & CAPABILITY_DIRECT_SUBMIT) == 0) {
|
||||||
|
PltCloseThread(&decoderThread);
|
||||||
|
}
|
||||||
|
|
||||||
AudioCallbacks.cleanup();
|
AudioCallbacks.cleanup();
|
||||||
}
|
}
|
||||||
@ -229,9 +254,11 @@ int startAudioStream(void) {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = PltCreateThread(DecoderThreadProc, NULL, &decoderThread);
|
if ((AudioCallbacks.capabilities & CAPABILITY_DIRECT_SUBMIT) == 0) {
|
||||||
if (err != 0) {
|
err = PltCreateThread(DecoderThreadProc, NULL, &decoderThread);
|
||||||
return err;
|
if (err != 0) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -52,6 +52,8 @@ typedef struct _DECODE_UNIT {
|
|||||||
PLENTRY bufferList;
|
PLENTRY bufferList;
|
||||||
} DECODE_UNIT, *PDECODE_UNIT;
|
} DECODE_UNIT, *PDECODE_UNIT;
|
||||||
|
|
||||||
|
#define CAPABILITY_DIRECT_SUBMIT 0x1
|
||||||
|
|
||||||
// This callback is invoked to provide details about the video stream and allow configuration of the decoder
|
// This callback is invoked to provide details about the video stream and allow configuration of the decoder
|
||||||
typedef void(*DecoderRendererSetup)(int width, int height, int redrawRate, void* context, int drFlags);
|
typedef void(*DecoderRendererSetup)(int width, int height, int redrawRate, void* context, int drFlags);
|
||||||
|
|
||||||
@ -84,6 +86,7 @@ typedef struct _AUDIO_RENDERER_CALLBACKS {
|
|||||||
AudioRendererInit init;
|
AudioRendererInit init;
|
||||||
AudioRendererCleanup cleanup;
|
AudioRendererCleanup cleanup;
|
||||||
AudioRendererDecodeAndPlaySample decodeAndPlaySample;
|
AudioRendererDecodeAndPlaySample decodeAndPlaySample;
|
||||||
|
int capabilities;
|
||||||
} AUDIO_RENDERER_CALLBACKS, *PAUDIO_RENDERER_CALLBACKS;
|
} AUDIO_RENDERER_CALLBACKS, *PAUDIO_RENDERER_CALLBACKS;
|
||||||
|
|
||||||
// Subject to change in future releases
|
// Subject to change in future releases
|
||||||
|
Loading…
x
Reference in New Issue
Block a user