// Receive thread proc static void ReceiveThreadProc(void* context) { int err; int bufferSize, receiveSize; char* buffer; int queueStatus; receiveSize = StreamConfig.packetSize + MAX_RTP_HEADER_SIZE; bufferSize = receiveSize + sizeof(int) + sizeof(RTP_QUEUE_ENTRY); buffer = NULL; while (!PltIsThreadInterrupted(&receiveThread)) { PRTP_PACKET packet; if (buffer == NULL) { buffer = (char*)malloc(bufferSize); if (buffer == NULL) { Limelog("Video Receive: malloc() failed\n"); ListenerCallbacks.connectionTerminated(-1); return; } } err = recvUdpSocket(rtpSocket, buffer, receiveSize); if (err < 0) { Limelog("Video Receive: recvUdpSocket() failed: %d\n", (int)LastSocketError()); ListenerCallbacks.connectionTerminated(LastSocketError()); break; } else if (err == 0) { // Receive timed out; try again continue; } memcpy(&buffer[receiveSize], &err, sizeof(int)); // RTP sequence number must be in host order for the RTP queue packet = (PRTP_PACKET)&buffer[0]; packet->sequenceNumber = htons(packet->sequenceNumber); queueStatus = RtpqAddPacket(&rtpQueue, packet, (PRTP_QUEUE_ENTRY)&buffer[receiveSize + sizeof(int)]); if (queueStatus == RTPQ_RET_HANDLE_IMMEDIATELY) { // queueRtpPacket() copies the data it needs to we can reuse the buffer queueRtpPacket(packet, err); } else if (queueStatus == RTPQ_RET_QUEUED_PACKETS_READY) { // The packet queue now has packets ready while ((buffer = (char*)RtpqGetQueuedPacket(&rtpQueue)) != NULL) { memcpy(&err, &buffer[receiveSize], sizeof(int)); queueRtpPacket((PRTP_PACKET)buffer, err); free(buffer); } } else if (queueStatus == RTPQ_RET_QUEUED_NOTHING_READY) { // The queue owns the buffer buffer = NULL; } } if (buffer != NULL) { free(buffer); } }
static void ReceiveThreadProc(void* context) { PRTP_PACKET rtp; PQUEUED_AUDIO_PACKET packet; int queueStatus; int useSelect; int packetsToDrop = 100; packet = NULL; if (setNonFatalRecvTimeoutMs(rtpSocket, UDP_RECV_POLL_TIMEOUT_MS) < 0) { // SO_RCVTIMEO failed, so use select() to wait useSelect = 1; } else { // SO_RCVTIMEO timeout set for recv() useSelect = 0; } while (!PltIsThreadInterrupted(&receiveThread)) { if (packet == NULL) { packet = (PQUEUED_AUDIO_PACKET)malloc(sizeof(*packet)); if (packet == NULL) { Limelog("Audio Receive: malloc() failed\n"); ListenerCallbacks.connectionTerminated(-1); break; } } packet->size = recvUdpSocket(rtpSocket, &packet->data[0], MAX_PACKET_SIZE, useSelect); if (packet->size < 0) { Limelog("Audio Receive: recvUdpSocket() failed: %d\n", (int)LastSocketError()); ListenerCallbacks.connectionTerminated(LastSocketFail()); break; } else if (packet->size == 0) { // Receive timed out; try again // If we hit this path, there are no queued audio packets on the host PC, // so we don't need to drop anything. packetsToDrop = 0; continue; } if (packet->size < sizeof(RTP_PACKET)) { // Runt packet continue; } rtp = (PRTP_PACKET)&packet->data[0]; if (rtp->packetType != 97) { // Not audio continue; } // We've received data, so we can stop sending our ping packets // as quickly, since we're now just keeping the NAT session open. receivedDataFromPeer = 1; // GFE accumulates audio samples before we are ready to receive them, // so we will drop the first 100 packets to avoid accumulating latency // by sending audio frames to the player faster than they can be played. if (packetsToDrop > 0) { packetsToDrop--; continue; } // RTP sequence number must be in host order for the RTP queue rtp->sequenceNumber = htons(rtp->sequenceNumber); queueStatus = RtpqAddPacket(&rtpReorderQueue, (PRTP_PACKET)packet, &packet->q.rentry); if (RTPQ_HANDLE_NOW(queueStatus)) { if ((AudioCallbacks.capabilities & CAPABILITY_DIRECT_SUBMIT) == 0) { if (!queuePacketToLbq(&packet)) { // An exit signal was received break; } } else { decodeInputData(packet); } } else { if (RTPQ_PACKET_CONSUMED(queueStatus)) { // The queue consumed our packet, so we must allocate a new one packet = NULL; } if (RTPQ_PACKET_READY(queueStatus)) { // If packets are ready, pull them and send them to the decoder while ((packet = (PQUEUED_AUDIO_PACKET)RtpqGetQueuedPacket(&rtpReorderQueue)) != NULL) { if ((AudioCallbacks.capabilities & CAPABILITY_DIRECT_SUBMIT) == 0) { if (!queuePacketToLbq(&packet)) { // An exit signal was received break; } } else { decodeInputData(packet); free(packet); } } // Break on exit if (packet != NULL) { break; } } } } if (packet != NULL) { free(packet); } }