Add support for controller and mouse movement batching

This commit is contained in:
Cameron Gutman 2015-05-28 10:13:26 -05:00
parent 626cbbf951
commit a6cb892a28
3 changed files with 186 additions and 0 deletions

View File

@ -94,6 +94,35 @@ void destroyInputStream(void) {
initialized = 0;
}
// Checks if values are compatible with controller batching
static int checkDirs(short currentVal, short newVal, int* dir) {
if (currentVal == newVal) {
return 1;
}
// We want to send a new packet if we've now zeroed an axis
if (newVal == 0) {
return 0;
}
if (*dir == 0) {
if (newVal < currentVal) {
*dir = -1;
}
else {
*dir = 1;
}
}
else if (*dir == -1) {
return newVal < currentVal;
}
else if (newVal < currentVal) {
return 0;
}
return 1;
}
#define OAES_DATA_OFFSET 32
/* Input thread proc */
@ -112,6 +141,106 @@ static void inputSendThreadProc(void* context) {
listenerCallbacks->connectionTerminated(err);
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];
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 = htons(holder->packet.mouseMove.deltaX);
int totalDeltaY = 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 = htons(mouseBatchHolder->packet.mouseMove.deltaX);
partialDeltaY = 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,

View File

@ -85,6 +85,60 @@ int LbqOfferQueueItem(PLINKED_BLOCKING_QUEUE queueHead, void* data, PLINKED_BLOC
return LBQ_SUCCESS;
}
// This must be synchronized with LbqFlushQueueItems by the caller
int LbqPeekQueueElement(PLINKED_BLOCKING_QUEUE queueHead, void** data) {
if (queueHead->head == NULL) {
return LBQ_NO_ELEMENT;
}
PltLockMutex(&queueHead->mutex);
if (queueHead->head == NULL) {
PltUnlockMutex(&queueHead->mutex);
return LBQ_NO_ELEMENT;
}
*data = queueHead->head->data;
PltUnlockMutex(&queueHead->mutex);
return LBQ_SUCCESS;
}
int LbqPollQueueElement(PLINKED_BLOCKING_QUEUE queueHead, void** data) {
PLINKED_BLOCKING_QUEUE_ENTRY entry;
if (queueHead->head == NULL) {
return LBQ_NO_ELEMENT;
}
PltLockMutex(&queueHead->mutex);
if (queueHead->head == NULL) {
PltUnlockMutex(&queueHead->mutex);
return LBQ_NO_ELEMENT;
}
entry = queueHead->head;
queueHead->head = entry->flink;
queueHead->currentSize--;
if (queueHead->head == NULL) {
LC_ASSERT(queueHead->currentSize == 0);
queueHead->tail = NULL;
PltClearEvent(&queueHead->containsDataEvent);
}
else {
LC_ASSERT(queueHead->currentSize != 0);
queueHead->head->blink = NULL;
}
*data = entry->data;
PltUnlockMutex(&queueHead->mutex);
return LBQ_SUCCESS;
}
int LbqWaitForQueueElement(PLINKED_BLOCKING_QUEUE queueHead, void** data) {
PLINKED_BLOCKING_QUEUE_ENTRY entry;
int err;

View File

@ -6,6 +6,7 @@
#define LBQ_SUCCESS 0
#define LBQ_INTERRUPTED 1
#define LBQ_BOUND_EXCEEDED 2
#define LBQ_NO_ELEMENT 3
typedef struct _LINKED_BLOCKING_QUEUE_ENTRY {
struct _LINKED_BLOCKING_QUEUE_ENTRY *flink;
@ -25,5 +26,7 @@ typedef struct _LINKED_BLOCKING_QUEUE {
int LbqInitializeLinkedBlockingQueue(PLINKED_BLOCKING_QUEUE queueHead, int sizeBound);
int LbqOfferQueueItem(PLINKED_BLOCKING_QUEUE queueHead, void* data, PLINKED_BLOCKING_QUEUE_ENTRY entry);
int LbqWaitForQueueElement(PLINKED_BLOCKING_QUEUE queueHead, void** data);
int LbqPollQueueElement(PLINKED_BLOCKING_QUEUE queueHead, void** data);
int LbqPeekQueueElement(PLINKED_BLOCKING_QUEUE queueHead, void** data);
PLINKED_BLOCKING_QUEUE_ENTRY LbqDestroyLinkedBlockingQueue(PLINKED_BLOCKING_QUEUE queueHead);
PLINKED_BLOCKING_QUEUE_ENTRY LbqFlushQueueItems(PLINKED_BLOCKING_QUEUE queueHead);