static void DecoderThreadProc(void* context) { int err; PQUEUED_AUDIO_PACKET packet; while (!PltIsThreadInterrupted(&decoderThread)) { err = LbqWaitForQueueElement(&packetQueue, (void**)&packet); if (err != LBQ_SUCCESS) { // An exit signal was received return; } decodeInputData(packet); free(packet); } }
static void DecoderThreadProc(void* context) { PRTP_PACKET rtp; int length; int err; char *data; unsigned short lastSeq = 0; while (!PltIsThreadInterrupted(&decoderThread)) { err = LbqWaitForQueueElement(&packetQueue, (void**) &data); if (err != LBQ_SUCCESS) { Limelog("Decoder thread terminating\n"); return; } memcpy(&length, data, sizeof(int)); rtp = (PRTP_PACKET) &data[sizeof(int)]; if (length < sizeof(RTP_PACKET)) { // Runt packet goto freeandcontinue; } if (rtp->packetType != 97) { // Not audio goto freeandcontinue; } rtp->sequenceNumber = htons(rtp->sequenceNumber); if (lastSeq != 0 && (unsigned short) (lastSeq + 1) != rtp->sequenceNumber) { Limelog("Received OOS audio data (expected %d, but got %d)\n", lastSeq + 1, rtp->sequenceNumber); callbacks.decodeAndPlaySample(NULL, 0); } lastSeq = rtp->sequenceNumber; callbacks.decodeAndPlaySample((char *) (rtp + 1), length - sizeof(*rtp)); freeandcontinue: free(data); } }
/* Input thread proc */ static void inputSendThreadProc(void* context) { SOCK_RET err; PPACKET_HOLDER holder; char encryptedBuffer[MAX_INPUT_PACKET_SIZE]; size_t encryptedSize; while (!PltIsThreadInterrupted(&inputSendThread)) { int encryptedLengthPrefix; err = LbqWaitForQueueElement(&packetQueue, (void**) &holder); if (err != LBQ_SUCCESS) { return; } // If it's a multi-controller packet we can do batching if (holder->packet.multiController.header.packetType == htonl(PACKET_TYPE_MULTI_CONTROLLER)) { PPACKET_HOLDER controllerBatchHolder; PNV_MULTI_CONTROLLER_PACKET origPkt; int dirs[6]; memset(dirs, 0, sizeof(dirs)); origPkt = &holder->packet.multiController; for (;;) { PNV_MULTI_CONTROLLER_PACKET newPkt; // Peek at the next packet if (LbqPeekQueueElement(&packetQueue, (void**)&controllerBatchHolder) != LBQ_SUCCESS) { break; } // If it's not a controller packet, we're done if (controllerBatchHolder->packet.multiController.header.packetType != htonl(PACKET_TYPE_MULTI_CONTROLLER)) { break; } // Check if it's able to be batched newPkt = &controllerBatchHolder->packet.multiController; if (newPkt->buttonFlags != origPkt->buttonFlags || newPkt->controllerNumber != origPkt->controllerNumber || !checkDirs(origPkt->leftTrigger, newPkt->leftTrigger, &dirs[0]) || !checkDirs(origPkt->rightTrigger, newPkt->rightTrigger, &dirs[1]) || !checkDirs(origPkt->leftStickX, newPkt->leftStickX, &dirs[2]) || !checkDirs(origPkt->leftStickY, newPkt->leftStickY, &dirs[3]) || !checkDirs(origPkt->rightStickX, newPkt->rightStickX, &dirs[4]) || !checkDirs(origPkt->rightStickY, newPkt->rightStickY, &dirs[5])) { // Batching not allowed break; } // Remove the batchable controller packet if (LbqPollQueueElement(&packetQueue, (void**)&controllerBatchHolder) != LBQ_SUCCESS) { break; } // Update the original packet origPkt->leftTrigger = newPkt->leftTrigger; origPkt->rightTrigger = newPkt->rightTrigger; origPkt->leftStickX = newPkt->leftStickX; origPkt->leftStickY = newPkt->leftStickY; origPkt->rightStickX = newPkt->rightStickX; origPkt->rightStickY = newPkt->rightStickY; // Free the batched packet holder free(controllerBatchHolder); } } // If it's a mouse move packet, we can also do batching else if (holder->packet.mouseMove.header.packetType == htonl(PACKET_TYPE_MOUSE_MOVE)) { PPACKET_HOLDER mouseBatchHolder; int totalDeltaX = (short)htons(holder->packet.mouseMove.deltaX); int totalDeltaY = (short)htons(holder->packet.mouseMove.deltaY); for (;;) { int partialDeltaX; int partialDeltaY; // Peek at the next packet if (LbqPeekQueueElement(&packetQueue, (void**)&mouseBatchHolder) != LBQ_SUCCESS) { break; } // If it's not a mouse move packet, we're done if (mouseBatchHolder->packet.mouseMove.header.packetType != htonl(PACKET_TYPE_MOUSE_MOVE)) { break; } partialDeltaX = (short)htons(mouseBatchHolder->packet.mouseMove.deltaX); partialDeltaY = (short)htons(mouseBatchHolder->packet.mouseMove.deltaY); // Check for overflow if (partialDeltaX + totalDeltaX > INT16_MAX || partialDeltaX + totalDeltaX < INT16_MIN || partialDeltaY + totalDeltaY > INT16_MAX || partialDeltaY + totalDeltaY < INT16_MIN) { // Total delta would overflow our 16-bit short break; } // Remove the batchable mouse move packet if (LbqPollQueueElement(&packetQueue, (void**)&mouseBatchHolder) != LBQ_SUCCESS) { break; } totalDeltaX += partialDeltaX; totalDeltaY += partialDeltaY; // Free the batched packet holder free(mouseBatchHolder); } // Update the original packet holder->packet.mouseMove.deltaX = htons((short)totalDeltaX); holder->packet.mouseMove.deltaY = htons((short)totalDeltaY); } encryptedSize = sizeof(encryptedBuffer); err = oaes_encrypt(oaesContext, (const unsigned char*) &holder->packet, holder->packetLength, (unsigned char*) encryptedBuffer, &encryptedSize); free(holder); if (err != OAES_RET_SUCCESS) { Limelog("Input: Encryption failed: %d\n", (int)err); ListenerCallbacks.connectionTerminated(err); return; } // The first 32-bytes of the output are internal OAES stuff that we want to ignore encryptedSize -= OAES_DATA_OFFSET; // Overwrite the last 4 bytes before the encrypted data with the length so // we can send the message all at once. GFE can choke if it gets the header // before the rest of the message. encryptedLengthPrefix = htonl((unsigned long) encryptedSize); memcpy(&encryptedBuffer[OAES_DATA_OFFSET - sizeof(encryptedLengthPrefix)], &encryptedLengthPrefix, sizeof(encryptedLengthPrefix)); // Send the encrypted payload err = send(inputSock, (const char*) &encryptedBuffer[OAES_DATA_OFFSET - sizeof(encryptedLengthPrefix)], (int)(encryptedSize + sizeof(encryptedLengthPrefix)), 0); if (err <= 0) { Limelog("Input: send() failed: %d\n", (int)LastSocketError()); ListenerCallbacks.connectionTerminated(LastSocketError()); return; } } }