From d9bbe53681054edebf9c6a2ce8097a053fefe915 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 30 Aug 2014 10:58:43 -0700 Subject: [PATCH 1/6] Implement LiSendControllerEvent --- limelight-common/Input.h | 20 ++++++++++++++++++++ limelight-common/InputStream.c | 32 ++++++++++++++++++++++++++++++++ limelight-common/Limelight.h | 18 ++++++++++++++++++ 3 files changed, 70 insertions(+) diff --git a/limelight-common/Input.h b/limelight-common/Input.h index 0fb92ef..b0dc0cf 100644 --- a/limelight-common/Input.h +++ b/limelight-common/Input.h @@ -32,4 +32,24 @@ typedef struct _NV_MOUSE_BUTTON_PACKET { int button; } NV_MOUSE_BUTTON_PACKET, *PNV_MOUSE_BUTTON_PACKET; +#define PACKET_TYPE_CONTROLLER 0x18 +#define HEADER_A 0x0000000A +#define HEADER_B 0x1400 +#define TAIL_A 0x0000009C +#define TAIL_B 0x0055 +typedef struct _NV_CONTROLLER_PACKET { + NV_INPUT_HEADER header; + int headerA; + short headerB; + short buttonFlags; + char leftTrigger; + char rightTrigger; + short leftStickX; + short leftStickY; + short rightStickX; + short rightStickY; + int tailA; + short tailB; +} NV_CONTROLLER_PACKET, *PNV_CONTROLLER_PACKET; + #pragma pack(pop) \ No newline at end of file diff --git a/limelight-common/InputStream.c b/limelight-common/InputStream.c index 99ea77f..7c9611c 100644 --- a/limelight-common/InputStream.c +++ b/limelight-common/InputStream.c @@ -23,6 +23,7 @@ typedef struct _PACKET_HOLDER { NV_KEYBOARD_PACKET keyboard; NV_MOUSE_MOVE_PACKET mouseMove; NV_MOUSE_BUTTON_PACKET mouseButton; + NV_CONTROLLER_PACKET controller; } packet; } PACKET_HOLDER, *PPACKET_HOLDER; @@ -229,3 +230,34 @@ int LiSendKeyboardEvent(short keyCode, char keyAction, char modifiers) { return err; } +int LiSendControllerEvent(short buttonFlags, char leftTrigger, char rightTrigger, + short leftStickX, short leftStickY, short rightStickX, short rightStickY) +{ + PPACKET_HOLDER holder; + int err; + + holder = malloc(sizeof(*holder)); + if (holder == NULL) { + return -1; + } + + holder->packetLength = sizeof(NV_CONTROLLER_PACKET); + holder->packet.controller.header.packetType = PACKET_TYPE_CONTROLLER; + holder->packet.controller.headerA = HEADER_A; + holder->packet.controller.headerB = HEADER_B; + holder->packet.controller.buttonFlags = buttonFlags; + holder->packet.controller.leftTrigger = leftTrigger; + holder->packet.controller.rightTrigger = rightTrigger; + holder->packet.controller.leftStickX = leftStickX; + holder->packet.controller.leftStickY = leftStickY; + holder->packet.controller.rightStickX = rightStickX; + holder->packet.controller.rightStickY = rightStickY; + holder->packet.controller.tailA = TAIL_A; + holder->packet.controller.tailB = TAIL_B; + err = LbqOfferQueueItem(&packetQueue, holder); + if (err != LBQ_SUCCESS) { + free(holder); + } + + return err; +} diff --git a/limelight-common/Limelight.h b/limelight-common/Limelight.h index 1ee9803..19e0c4c 100644 --- a/limelight-common/Limelight.h +++ b/limelight-common/Limelight.h @@ -111,6 +111,24 @@ int LiSendMouseButtonEvent(char action, int button); #define MODIFIER_ALT 0x04 int LiSendKeyboardEvent(short keyCode, char keyAction, char modifiers); +#define A_FLAG 0x1000 +#define B_FLAG 0x2000 +#define X_FLAG 0x4000 +#define Y_FLAG 0x8000 +#define UP_FLAG 0x0001 +#define DOWN_FLAG 0x0002 +#define LEFT_FLAG 0x0004 +#define RIGHT_FLAG 0x0008 +#define LB_FLAG 0x0100 +#define RB_FLAG 0x0200 +#define PLAY_FLAG 0x0010 +#define BACK_FLAG 0x0020 +#define LS_CLK_FLAG 0x0040 +#define RS_CLK_FLAG 0x0080 +#define SPECIAL_FLAG 0x0400 +int LiSendControllerEvent(short buttonFlags, char leftTrigger, char rightTrigger, + short leftStickX, short leftStickY, short rightStickX, short rightStickY); + #ifdef __cplusplus } #endif \ No newline at end of file From 0b0dbbdaab081e559dc969e08378c6e9ef177dd8 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 30 Aug 2014 12:54:12 -0700 Subject: [PATCH 2/6] Prevent queuing input packets before the queue is initialized --- limelight-common/InputStream.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/limelight-common/InputStream.c b/limelight-common/InputStream.c index 7c9611c..ba9bce7 100644 --- a/limelight-common/InputStream.c +++ b/limelight-common/InputStream.c @@ -10,6 +10,7 @@ static IP_ADDRESS host; static SOCKET inputSock = INVALID_SOCKET; static PCONNECTION_LISTENER_CALLBACKS listenerCallbacks; +static int initialized; static LINKED_BLOCKING_QUEUE packetQueue; static PLT_THREAD inputSendThread; @@ -59,6 +60,7 @@ int initializeInputStream(IP_ADDRESS addr, PCONNECTION_LISTENER_CALLBACKS clCall LbqInitializeLinkedBlockingQueue(&packetQueue, 30); + initialized = 1; return 0; } @@ -164,6 +166,10 @@ int LiSendMouseMoveEvent(short deltaX, short deltaY) { PPACKET_HOLDER holder; int err; + if (!initialized) { + return -2; + } + holder = malloc(sizeof(*holder)); if (holder == NULL) { return -1; @@ -187,6 +193,10 @@ int LiSendMouseButtonEvent(char action, int button) { PPACKET_HOLDER holder; int err; + if (!initialized) { + return -2; + } + holder = malloc(sizeof(*holder)); if (holder == NULL) { return -1; @@ -209,6 +219,10 @@ int LiSendKeyboardEvent(short keyCode, char keyAction, char modifiers) { PPACKET_HOLDER holder; int err; + if (!initialized) { + return -2; + } + holder = malloc(sizeof(*holder)); if (holder == NULL) { return -1; @@ -236,6 +250,10 @@ int LiSendControllerEvent(short buttonFlags, char leftTrigger, char rightTrigger PPACKET_HOLDER holder; int err; + if (!initialized) { + return -2; + } + holder = malloc(sizeof(*holder)); if (holder == NULL) { return -1; From a7aabe0ea68b9c8289594cb0331e0f0377b07450 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 30 Aug 2014 13:36:54 -0700 Subject: [PATCH 3/6] Fix controller and keyboard packets --- limelight-common/InputStream.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/limelight-common/InputStream.c b/limelight-common/InputStream.c index ba9bce7..65fd3a3 100644 --- a/limelight-common/InputStream.c +++ b/limelight-common/InputStream.c @@ -232,7 +232,7 @@ int LiSendKeyboardEvent(short keyCode, char keyAction, char modifiers) { holder->packet.keyboard.header.packetType = htonl(PACKET_TYPE_KEYBOARD); holder->packet.keyboard.keyAction = keyAction; holder->packet.keyboard.zero1 = 0; - holder->packet.keyboard.keyCode = htons(keyCode); + holder->packet.keyboard.keyCode = keyCode; holder->packet.keyboard.modifiers = modifiers; holder->packet.keyboard.zero2 = 0; @@ -260,7 +260,7 @@ int LiSendControllerEvent(short buttonFlags, char leftTrigger, char rightTrigger } holder->packetLength = sizeof(NV_CONTROLLER_PACKET); - holder->packet.controller.header.packetType = PACKET_TYPE_CONTROLLER; + holder->packet.controller.header.packetType = htonl(PACKET_TYPE_CONTROLLER); holder->packet.controller.headerA = HEADER_A; holder->packet.controller.headerB = HEADER_B; holder->packet.controller.buttonFlags = buttonFlags; From cff7ec1d1035974755c0dd07b1c23c51288e7341 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 30 Aug 2014 16:22:00 -0700 Subject: [PATCH 4/6] Fix debugging on Windows 8.1 --- limelight-common/Platform.h | 4 ++-- limelight-common/PlatformThreads.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/limelight-common/Platform.h b/limelight-common/Platform.h index 4b38740..f4cf1a9 100644 --- a/limelight-common/Platform.h +++ b/limelight-common/Platform.h @@ -24,11 +24,11 @@ #endif #include -#ifdef LC_WINDOWS_PHONE +#if defined(LC_WINDOWS_PHONE) || defined(LC_WINDOWS) extern WCHAR DbgBuf[512]; #define Limelog(s, ...) \ swprintf(DbgBuf, sizeof(DbgBuf) / sizeof(WCHAR), L ## s, ##__VA_ARGS__); \ - OutputDebugString(DbgBuf) + OutputDebugStringW(DbgBuf) #else #define Limelog printf #endif diff --git a/limelight-common/PlatformThreads.c b/limelight-common/PlatformThreads.c index 7f79285..5444a71 100644 --- a/limelight-common/PlatformThreads.c +++ b/limelight-common/PlatformThreads.c @@ -6,7 +6,7 @@ struct thread_context { void* context; }; -#if defined(LC_WINDOWS_PHONE) +#if defined(LC_WINDOWS_PHONE) || defined(LC_WINDOWS) WCHAR DbgBuf[512]; #endif From dc926946dd3f53a2460e695b7c6911916f0b3eef Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 30 Aug 2014 16:39:26 -0700 Subject: [PATCH 5/6] Handle reuse of limelight-common for another stream --- limelight-common/InputStream.c | 3 +++ limelight-common/RtspConnection.c | 6 ++++-- limelight-common/VideoDepacketizer.c | 19 ++++++++++++++----- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/limelight-common/InputStream.c b/limelight-common/InputStream.c index 65fd3a3..1283e04 100644 --- a/limelight-common/InputStream.c +++ b/limelight-common/InputStream.c @@ -70,6 +70,7 @@ void destroyInputStream(void) { if (oaesContext != NULL) { oaes_free(oaesContext); + oaesContext = NULL; } entry = LbqDestroyLinkedBlockingQueue(&packetQueue); @@ -80,6 +81,8 @@ void destroyInputStream(void) { free(entry); entry = nextEntry; } + + initialized = 0; } static void inputSendThreadProc(void* context) { diff --git a/limelight-common/RtspConnection.c b/limelight-common/RtspConnection.c index 2227750..983c159 100644 --- a/limelight-common/RtspConnection.c +++ b/limelight-common/RtspConnection.c @@ -5,10 +5,10 @@ static SOCKET sock = INVALID_SOCKET; static IP_ADDRESS remoteAddr; -static int currentSeqNumber = 1; +static int currentSeqNumber; static char rtspTargetUrl[256]; static char sessionIdString[16]; -static int hasSessionId = 0; +static int hasSessionId; static char responseBuffer[RTSP_MAX_RESP_SIZE]; /* GFE 2.1.1 */ @@ -280,6 +280,8 @@ int performRtspHandshake(IP_ADDRESS addr, PSTREAM_CONFIGURATION streamConfigPtr) remoteAddr = addr; inaddr.S_un.S_addr = addr; sprintf(rtspTargetUrl, "rtsp://%s", inet_ntoa(inaddr)); + currentSeqNumber = 1; + hasSessionId = 0; { RTSP_MESSAGE response; diff --git a/limelight-common/VideoDepacketizer.c b/limelight-common/VideoDepacketizer.c index 7af9a8b..e4bac33 100644 --- a/limelight-common/VideoDepacketizer.c +++ b/limelight-common/VideoDepacketizer.c @@ -6,14 +6,14 @@ static PLENTRY nalChainHead; static int nalChainDataLength; -static int nextFrameNumber = 1; +static int nextFrameNumber; static int nextPacketNumber; -static int startFrameNumber = 1; +static int startFrameNumber; static int waitingForNextSuccessfulFrame; -static int waitingForIdrFrame = 1; +static int waitingForIdrFrame; static int gotNextFrameStart; -static int lastPacketInStream = 0; -static int decodingFrame = 0; +static int lastPacketInStream; +static int decodingFrame; static LINKED_BLOCKING_QUEUE decodeUnitQueue; static unsigned int nominalPacketDataLength; @@ -30,6 +30,15 @@ typedef struct _BUFFER_DESC { void initializeVideoDepacketizer(int pktSize) { LbqInitializeLinkedBlockingQueue(&decodeUnitQueue, 15); nominalPacketDataLength = pktSize - sizeof(NV_VIDEO_PACKET); + + nextFrameNumber = 1; + nextPacketNumber = 0; + startFrameNumber = 1; + waitingForNextSuccessfulFrame = 0; + waitingForIdrFrame = 1; + gotNextFrameStart = 0; + lastPacketInStream = 0; + decodingFrame = 0; } /* Free malloced memory in AvcFrameState*/ From 0ee1609cc41d082329932e4c66eeb3379135f77e Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 30 Aug 2014 17:07:08 -0700 Subject: [PATCH 6/6] Properly flush the DU queue when we hit the limit. Fixes extreme lag that occurs after streaming for a bit. --- limelight-common/AudioStream.c | 19 ++++++++++++------- limelight-common/LinkedBlockingQueue.c | 19 +++++++++++++++++++ limelight-common/LinkedBlockingQueue.h | 3 ++- limelight-common/VideoDepacketizer.c | 24 ++++++++++++++++-------- 4 files changed, 49 insertions(+), 16 deletions(-) diff --git a/limelight-common/AudioStream.c b/limelight-common/AudioStream.c index 9d87976..f1b3ec4 100644 --- a/limelight-common/AudioStream.c +++ b/limelight-common/AudioStream.c @@ -28,13 +28,8 @@ void initializeAudioStream(IP_ADDRESS host, PAUDIO_RENDERER_CALLBACKS arCallback LbqInitializeLinkedBlockingQueue(&packetQueue, 30); } -/* Tear down the audio stream once we're done with it */ -void destroyAudioStream(void) { - PLINKED_BLOCKING_QUEUE_ENTRY entry, nextEntry; - - callbacks.release(); - - entry = LbqDestroyLinkedBlockingQueue(&packetQueue); +static void freePacketList(PLINKED_BLOCKING_QUEUE_ENTRY entry) { + PLINKED_BLOCKING_QUEUE_ENTRY nextEntry; while (entry != NULL) { nextEntry = entry->flink; @@ -44,6 +39,15 @@ void destroyAudioStream(void) { } } +/* Tear down the audio stream once we're done with it */ +void destroyAudioStream(void) { + callbacks.release(); + + freePacketList(LbqDestroyLinkedBlockingQueue(&packetQueue)); +} + + + static void UdpPingThreadProc(void *context) { /* Ping in ASCII */ char pingData[] = { 0x50, 0x49, 0x4E, 0x47 }; @@ -112,6 +116,7 @@ static void ReceiveThreadProc(void* context) { if (err == LBQ_BOUND_EXCEEDED) { Limelog("Audio packet queue overflow\n"); + freePacketList(LbqFlushQueueItems(&packetQueue)); } else if (err == LBQ_INTERRUPTED) { Limelog("Receive thread terminating #2\n"); diff --git a/limelight-common/LinkedBlockingQueue.c b/limelight-common/LinkedBlockingQueue.c index 8804665..9856fae 100644 --- a/limelight-common/LinkedBlockingQueue.c +++ b/limelight-common/LinkedBlockingQueue.c @@ -7,6 +7,25 @@ PLINKED_BLOCKING_QUEUE_ENTRY LbqDestroyLinkedBlockingQueue(PLINKED_BLOCKING_QUEU return queueHead->head; } +PLINKED_BLOCKING_QUEUE_ENTRY LbqFlushQueueItems(PLINKED_BLOCKING_QUEUE queueHead) { + PLINKED_BLOCKING_QUEUE_ENTRY head; + + PltLockMutex(&queueHead->mutex); + + // Save the old head + head = queueHead->head; + + // Reinitialize the queue to empty + queueHead->head = NULL; + queueHead->tail = NULL; + queueHead->currentSize = 0; + PltClearEvent(&queueHead->containsDataEvent); + + PltUnlockMutex(&queueHead->mutex); + + return head; +} + int LbqInitializeLinkedBlockingQueue(PLINKED_BLOCKING_QUEUE queueHead, int sizeBound) { int err; diff --git a/limelight-common/LinkedBlockingQueue.h b/limelight-common/LinkedBlockingQueue.h index 1f03efe..033aec2 100644 --- a/limelight-common/LinkedBlockingQueue.h +++ b/limelight-common/LinkedBlockingQueue.h @@ -26,4 +26,5 @@ typedef struct _LINKED_BLOCKING_QUEUE { int LbqInitializeLinkedBlockingQueue(PLINKED_BLOCKING_QUEUE queueHead, int sizeBound); int LbqOfferQueueItem(PLINKED_BLOCKING_QUEUE queueHead, void* data); int LbqWaitForQueueElement(PLINKED_BLOCKING_QUEUE queueHead, void** data); -PLINKED_BLOCKING_QUEUE_ENTRY LbqDestroyLinkedBlockingQueue(PLINKED_BLOCKING_QUEUE queueHead); \ No newline at end of file +PLINKED_BLOCKING_QUEUE_ENTRY LbqDestroyLinkedBlockingQueue(PLINKED_BLOCKING_QUEUE queueHead); +PLINKED_BLOCKING_QUEUE_ENTRY LbqFlushQueueItems(PLINKED_BLOCKING_QUEUE queueHead); \ No newline at end of file diff --git a/limelight-common/VideoDepacketizer.c b/limelight-common/VideoDepacketizer.c index e4bac33..2f891c3 100644 --- a/limelight-common/VideoDepacketizer.c +++ b/limelight-common/VideoDepacketizer.c @@ -59,16 +59,20 @@ static void dropAvcFrameState(void) { cleanupAvcFrameState(); } -/* Cleanup video depacketizer and free malloced memory */ -void destroyVideoDepacketizer(void) { - PLINKED_BLOCKING_QUEUE_ENTRY entry, nextEntry; - - entry = LbqDestroyLinkedBlockingQueue(&decodeUnitQueue); +static void freeDecodeUnitList(PLINKED_BLOCKING_QUEUE_ENTRY entry) { + PLINKED_BLOCKING_QUEUE_ENTRY nextEntry; + while (entry != NULL) { nextEntry = entry->flink; + free(entry->data); free(entry); entry = nextEntry; } +} + +/* Cleanup video depacketizer and free malloced memory */ +void destroyVideoDepacketizer(void) { + freeDecodeUnitList(LbqDestroyLinkedBlockingQueue(&decodeUnitQueue)); cleanupAvcFrameState(); } @@ -139,15 +143,19 @@ static void reassembleAvcFrame(int frameNumber) { if (LbqOfferQueueItem(&decodeUnitQueue, du) == LBQ_BOUND_EXCEEDED) { Limelog("Decode unit queue overflow\n"); + // Clear frame state and wait for an IDR nalChainHead = du->bufferList; nalChainDataLength = du->fullLength; + dropAvcFrameState(); + + // Free the DU free(du); + // Flush the decode unit queue + freeDecodeUnitList(LbqFlushQueueItems(&decodeUnitQueue)); + // FIXME: Get proper lower bound connectionSinkTooSlow(0, frameNumber); - - // Clear frame state and wait for an IDR - dropAvcFrameState(); return; }