diff --git a/limelight-common/AudioStream.c b/limelight-common/AudioStream.c index fd6fd54..b5745ff 100644 --- a/limelight-common/AudioStream.c +++ b/limelight-common/AudioStream.c @@ -4,10 +4,6 @@ #include "LinkedBlockingQueue.h" #include "RtpReorderQueue.h" -static AUDIO_RENDERER_CALLBACKS callbacks; -static PCONNECTION_LISTENER_CALLBACKS listenerCallbacks; -static IP_ADDRESS remoteHost; - static SOCKET rtpSocket = INVALID_SOCKET; static LINKED_BLOCKING_QUEUE packetQueue; @@ -33,11 +29,7 @@ typedef struct _QUEUED_AUDIO_PACKET { } QUEUED_AUDIO_PACKET, *PQUEUED_AUDIO_PACKET; /* Initialize the audio stream */ -void initializeAudioStream(IP_ADDRESS host, PAUDIO_RENDERER_CALLBACKS arCallbacks, PCONNECTION_LISTENER_CALLBACKS clCallbacks) { - memcpy(&callbacks, arCallbacks, sizeof(callbacks)); - remoteHost = host; - listenerCallbacks = clCallbacks; - +void initializeAudioStream(void) { LbqInitializeLinkedBlockingQueue(&packetQueue, 30); RtpqInitializeQueue(&rtpReorderQueue, RTPQ_DEFAULT_MAX_SIZE, RTPQ_DEFUALT_QUEUE_TIME); } @@ -57,7 +49,7 @@ static void freePacketList(PLINKED_BLOCKING_QUEUE_ENTRY entry) { /* Tear down the audio stream once we're done with it */ void destroyAudioStream(void) { - callbacks.release(); + AudioCallbacks.cleanup(); freePacketList(LbqDestroyLinkedBlockingQueue(&packetQueue)); RtpqCleanupQueue(&rtpReorderQueue); @@ -66,20 +58,18 @@ void destroyAudioStream(void) { static void UdpPingThreadProc(void *context) { /* Ping in ASCII */ char pingData[] = { 0x50, 0x49, 0x4E, 0x47 }; - struct sockaddr_in saddr; + struct sockaddr_in6 saddr; SOCK_RET err; - memset(&saddr, 0, sizeof(saddr)); - saddr.sin_family = AF_INET; - saddr.sin_port = htons(RTP_PORT); - memcpy(&saddr.sin_addr, &remoteHost, sizeof(remoteHost)); + memcpy(&saddr, &RemoteAddr, sizeof(saddr)); + saddr.sin6_port = htons(RTP_PORT); /* Send PING every 500 milliseconds */ while (!PltIsThreadInterrupted(&udpPingThread)) { - err = sendto(rtpSocket, pingData, sizeof(pingData), 0, (struct sockaddr*)&saddr, sizeof(saddr)); + err = sendto(rtpSocket, pingData, sizeof(pingData), 0, (struct sockaddr*)&saddr, RemoteAddrLen); if (err != sizeof(pingData)) { Limelog("UDP ping thread terminating #1\n"); - listenerCallbacks->connectionTerminated(LastSocketError()); + ListenerCallbacks.connectionTerminated(LastSocketError()); return; } @@ -120,7 +110,7 @@ static void ReceiveThreadProc(void* context) { packet = (PQUEUED_AUDIO_PACKET) malloc(sizeof(*packet)); if (packet == NULL) { Limelog("Receive thread terminating\n"); - listenerCallbacks->connectionTerminated(-1); + ListenerCallbacks.connectionTerminated(-1); return; } } @@ -129,7 +119,7 @@ static void ReceiveThreadProc(void* context) { if (packet->size <= 0) { Limelog("Receive thread terminating #2\n"); free(packet); - listenerCallbacks->connectionTerminated(LastSocketError()); + ListenerCallbacks.connectionTerminated(LastSocketError()); return; } @@ -190,20 +180,18 @@ static void DecoderThreadProc(void* context) { 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); + AudioCallbacks.decodeAndPlaySample(NULL, 0); } lastSeq = rtp->sequenceNumber; - callbacks.decodeAndPlaySample((char *) (rtp + 1), packet->size - sizeof(*rtp)); + AudioCallbacks.decodeAndPlaySample((char *) (rtp + 1), packet->size - sizeof(*rtp)); free(packet); } } void stopAudioStream(void) { - callbacks.stop(); - PltInterruptThread(&udpPingThread); PltInterruptThread(&receiveThread); PltInterruptThread(&decoderThread); @@ -225,9 +213,9 @@ void stopAudioStream(void) { int startAudioStream(void) { int err; - callbacks.init(); + AudioCallbacks.init(); - rtpSocket = bindUdpSocket(); + rtpSocket = bindUdpSocket(RemoteAddr.ss_family); if (rtpSocket == INVALID_SOCKET) { return LastSocketError(); } @@ -247,7 +235,5 @@ int startAudioStream(void) { return err; } - callbacks.start(); - return 0; } \ No newline at end of file diff --git a/limelight-common/Connection.c b/limelight-common/Connection.c index 1b3aaf5..29262a7 100644 --- a/limelight-common/Connection.c +++ b/limelight-common/Connection.c @@ -2,20 +2,24 @@ #include "Platform.h" static int stage = STAGE_NONE; -static CONNECTION_LISTENER_CALLBACKS listenerCallbacks; static ConnListenerConnectionTerminated originalTerminationCallback; - -// This is used for debug prints so it's not declared static -PLATFORM_CALLBACKS platformCallbacks; - -int serverMajorVersion; - static int alreadyTerminated; +// Common globals +struct sockaddr_storage RemoteAddr; +SOCKADDR_LEN RemoteAddrLen; +int ServerMajorVersion; +STREAM_CONFIGURATION StreamConfig; +PLATFORM_CALLBACKS PlatformCallbacks; +CONNECTION_LISTENER_CALLBACKS ListenerCallbacks; +DECODER_RENDERER_CALLBACKS VideoCallbacks; +AUDIO_RENDERER_CALLBACKS AudioCallbacks; + /* Connection stages */ static const char* stageNames[STAGE_MAX] = { "none", "platform initialization", + "name resolution", "RTSP handshake", "control stream initialization", "video stream initialization", @@ -91,6 +95,10 @@ void LiStopConnection(void) { stage--; Limelog("done\n"); } + if (stage == STAGE_NAME_RESOLUTION) { + // Nothing to do + stage--; + } if (stage == STAGE_PLATFORM_INIT) { Limelog("Cleaning up platform..."); cleanupPlatform(); @@ -116,144 +124,185 @@ void LiCompleteThreadStart(void) PltRunThreadProc(); } +static int resolveHostName(char *host) +{ + struct addrinfo hints, *res; + int err; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + err = getaddrinfo(host, NULL, &hints, &res); + if (err != 0) { + return err; + } + + if (res == NULL) { + Limelog("getaddrinfo() returned success without addresses\n"); + return -1; + } + + // Use the first address in the list + memcpy(&RemoteAddr, res->ai_addr, res->ai_addrlen); + RemoteAddrLen = res->ai_addrlen; + + freeaddrinfo(res); + return 0; +} + /* Starts the connection to the streaming machine */ -int LiStartConnection(IP_ADDRESS host, PSTREAM_CONFIGURATION streamConfig, PCONNECTION_LISTENER_CALLBACKS clCallbacks, +int LiStartConnection(char* host, PSTREAM_CONFIGURATION streamConfig, PCONNECTION_LISTENER_CALLBACKS clCallbacks, PDECODER_RENDERER_CALLBACKS drCallbacks, PAUDIO_RENDERER_CALLBACKS arCallbacks, PPLATFORM_CALLBACKS plCallbacks, void* renderContext, int drFlags, int _serverMajorVersion) { int err; - - serverMajorVersion = _serverMajorVersion; + + ServerMajorVersion = _serverMajorVersion; + memcpy(&StreamConfig, streamConfig, sizeof(StreamConfig)); // Replace missing callbacks with placeholders fixupMissingCallbacks(&drCallbacks, &arCallbacks, &clCallbacks, &plCallbacks); - memcpy(&platformCallbacks, plCallbacks, sizeof(platformCallbacks)); + memcpy(&PlatformCallbacks, plCallbacks, sizeof(PlatformCallbacks)); + memcpy(&VideoCallbacks, drCallbacks, sizeof(VideoCallbacks)); + memcpy(&AudioCallbacks, arCallbacks, sizeof(AudioCallbacks)); // Hook the termination callback so we can avoid issuing a termination callback // after LiStopConnection() is called originalTerminationCallback = clCallbacks->connectionTerminated; - memcpy(&listenerCallbacks, clCallbacks, sizeof(listenerCallbacks)); - listenerCallbacks.connectionTerminated = ClInternalConnectionTerminated; + memcpy(&ListenerCallbacks, clCallbacks, sizeof(ListenerCallbacks)); + ListenerCallbacks.connectionTerminated = ClInternalConnectionTerminated; alreadyTerminated = 0; Limelog("Initializing platform..."); - listenerCallbacks.stageStarting(STAGE_PLATFORM_INIT); + ListenerCallbacks.stageStarting(STAGE_PLATFORM_INIT); err = initializePlatform(); if (err != 0) { Limelog("failed: %d\n", err); - listenerCallbacks.stageFailed(STAGE_PLATFORM_INIT, err); + ListenerCallbacks.stageFailed(STAGE_PLATFORM_INIT, err); goto Cleanup; } stage++; LC_ASSERT(stage == STAGE_PLATFORM_INIT); - listenerCallbacks.stageComplete(STAGE_PLATFORM_INIT); + ListenerCallbacks.stageComplete(STAGE_PLATFORM_INIT); Limelog("done\n"); + + Limelog("Resolving host name..."); + LC_ASSERT(stage == STAGE_NAME_RESOLUTION); + ListenerCallbacks.stageStarting(STAGE_NAME_RESOLUTION); + err = resolveHostName(host); + if (err != 0) { + Limelog("failed: %d\n", err); + ListenerCallbacks.stageFailed(STAGE_NAME_RESOLUTION, err); + goto Cleanup; + } + stage++; + LC_ASSERT(stage == STAGE_NAME_RESOLUTION); + ListenerCallbacks.stageComplete(STAGE_NAME_RESOLUTION); + Limelog("done\n"); Limelog("Starting RTSP handshake..."); - listenerCallbacks.stageStarting(STAGE_RTSP_HANDSHAKE); - err = performRtspHandshake(host, streamConfig); + ListenerCallbacks.stageStarting(STAGE_RTSP_HANDSHAKE); + err = performRtspHandshake(); if (err != 0) { Limelog("failed: %d\n", err); - listenerCallbacks.stageFailed(STAGE_RTSP_HANDSHAKE, err); + ListenerCallbacks.stageFailed(STAGE_RTSP_HANDSHAKE, err); goto Cleanup; } stage++; LC_ASSERT(stage == STAGE_RTSP_HANDSHAKE); - listenerCallbacks.stageComplete(STAGE_RTSP_HANDSHAKE); + ListenerCallbacks.stageComplete(STAGE_RTSP_HANDSHAKE); Limelog("done\n"); Limelog("Initializing control stream..."); - listenerCallbacks.stageStarting(STAGE_CONTROL_STREAM_INIT); - err = initializeControlStream(host, streamConfig, &listenerCallbacks); + ListenerCallbacks.stageStarting(STAGE_CONTROL_STREAM_INIT); + err = initializeControlStream(); if (err != 0) { Limelog("failed: %d\n", err); - listenerCallbacks.stageFailed(STAGE_CONTROL_STREAM_INIT, err); + ListenerCallbacks.stageFailed(STAGE_CONTROL_STREAM_INIT, err); goto Cleanup; } stage++; LC_ASSERT(stage == STAGE_CONTROL_STREAM_INIT); - listenerCallbacks.stageComplete(STAGE_CONTROL_STREAM_INIT); + ListenerCallbacks.stageComplete(STAGE_CONTROL_STREAM_INIT); Limelog("done\n"); Limelog("Initializing video stream..."); - listenerCallbacks.stageStarting(STAGE_VIDEO_STREAM_INIT); - initializeVideoStream(host, streamConfig, drCallbacks, &listenerCallbacks); + ListenerCallbacks.stageStarting(STAGE_VIDEO_STREAM_INIT); + initializeVideoStream(); stage++; LC_ASSERT(stage == STAGE_VIDEO_STREAM_INIT); - listenerCallbacks.stageComplete(STAGE_VIDEO_STREAM_INIT); + ListenerCallbacks.stageComplete(STAGE_VIDEO_STREAM_INIT); Limelog("done\n"); Limelog("Initializing audio stream..."); - listenerCallbacks.stageStarting(STAGE_AUDIO_STREAM_INIT); - initializeAudioStream(host, arCallbacks, &listenerCallbacks); + ListenerCallbacks.stageStarting(STAGE_AUDIO_STREAM_INIT); + initializeAudioStream(); stage++; LC_ASSERT(stage == STAGE_AUDIO_STREAM_INIT); - listenerCallbacks.stageComplete(STAGE_AUDIO_STREAM_INIT); + ListenerCallbacks.stageComplete(STAGE_AUDIO_STREAM_INIT); Limelog("done\n"); Limelog("Initializing input stream..."); - listenerCallbacks.stageStarting(STAGE_INPUT_STREAM_INIT); - initializeInputStream(host, &listenerCallbacks, - streamConfig->remoteInputAesKey, sizeof(streamConfig->remoteInputAesKey), + ListenerCallbacks.stageStarting(STAGE_INPUT_STREAM_INIT); + initializeInputStream(streamConfig->remoteInputAesKey, sizeof(streamConfig->remoteInputAesKey), streamConfig->remoteInputAesIv, sizeof(streamConfig->remoteInputAesIv)); stage++; LC_ASSERT(stage == STAGE_INPUT_STREAM_INIT); - listenerCallbacks.stageComplete(STAGE_INPUT_STREAM_INIT); + ListenerCallbacks.stageComplete(STAGE_INPUT_STREAM_INIT); Limelog("done\n"); Limelog("Starting control stream..."); - listenerCallbacks.stageStarting(STAGE_CONTROL_STREAM_START); + ListenerCallbacks.stageStarting(STAGE_CONTROL_STREAM_START); err = startControlStream(); if (err != 0) { Limelog("failed: %d\n", err); - listenerCallbacks.stageFailed(STAGE_CONTROL_STREAM_START, err); + ListenerCallbacks.stageFailed(STAGE_CONTROL_STREAM_START, err); goto Cleanup; } stage++; LC_ASSERT(stage == STAGE_CONTROL_STREAM_START); - listenerCallbacks.stageComplete(STAGE_CONTROL_STREAM_START); + ListenerCallbacks.stageComplete(STAGE_CONTROL_STREAM_START); Limelog("done\n"); Limelog("Starting video stream..."); - listenerCallbacks.stageStarting(STAGE_VIDEO_STREAM_START); + ListenerCallbacks.stageStarting(STAGE_VIDEO_STREAM_START); err = startVideoStream(renderContext, drFlags); if (err != 0) { Limelog("Video stream start failed: %d\n", err); - listenerCallbacks.stageFailed(STAGE_VIDEO_STREAM_START, err); + ListenerCallbacks.stageFailed(STAGE_VIDEO_STREAM_START, err); goto Cleanup; } stage++; LC_ASSERT(stage == STAGE_VIDEO_STREAM_START); - listenerCallbacks.stageComplete(STAGE_VIDEO_STREAM_START); + ListenerCallbacks.stageComplete(STAGE_VIDEO_STREAM_START); Limelog("done\n"); Limelog("Starting audio stream..."); - listenerCallbacks.stageStarting(STAGE_AUDIO_STREAM_START); + ListenerCallbacks.stageStarting(STAGE_AUDIO_STREAM_START); err = startAudioStream(); if (err != 0) { Limelog("Audio stream start failed: %d\n", err); - listenerCallbacks.stageFailed(STAGE_AUDIO_STREAM_START, err); + ListenerCallbacks.stageFailed(STAGE_AUDIO_STREAM_START, err); goto Cleanup; } stage++; LC_ASSERT(stage == STAGE_AUDIO_STREAM_START); - listenerCallbacks.stageComplete(STAGE_AUDIO_STREAM_START); + ListenerCallbacks.stageComplete(STAGE_AUDIO_STREAM_START); Limelog("done\n"); Limelog("Starting input stream..."); - listenerCallbacks.stageStarting(STAGE_INPUT_STREAM_START); + ListenerCallbacks.stageStarting(STAGE_INPUT_STREAM_START); err = startInputStream(); if (err != 0) { Limelog("Input stream start failed: %d\n", err); - listenerCallbacks.stageFailed(STAGE_INPUT_STREAM_START, err); + ListenerCallbacks.stageFailed(STAGE_INPUT_STREAM_START, err); goto Cleanup; } stage++; LC_ASSERT(stage == STAGE_INPUT_STREAM_START); - listenerCallbacks.stageComplete(STAGE_INPUT_STREAM_START); + ListenerCallbacks.stageComplete(STAGE_INPUT_STREAM_START); Limelog("done\n"); - listenerCallbacks.connectionStarted(); + ListenerCallbacks.connectionStarted(); Cleanup: return err; diff --git a/limelight-common/ControlStream.c b/limelight-common/ControlStream.c index 411a4b4..963cc27 100644 --- a/limelight-common/ControlStream.c +++ b/limelight-common/ControlStream.c @@ -10,13 +10,10 @@ typedef struct _NVCTL_PACKET_HEADER { unsigned short payloadLength; } NVCTL_PACKET_HEADER, *PNVCTL_PACKET_HEADER; -static IP_ADDRESS host; static SOCKET ctlSock = INVALID_SOCKET; -static STREAM_CONFIGURATION streamConfig; static PLT_THREAD lossStatsThread; static PLT_THREAD resyncThread; static PLT_EVENT resyncEvent; -static PCONNECTION_LISTENER_CALLBACKS listenerCallbacks; static int lossCountSinceLastReport = 0; static long currentFrame = 0; @@ -77,15 +74,10 @@ static char **preconstructedPayloads; #define LOSS_REPORT_INTERVAL_MS 50 /* Initializes the control stream */ -int initializeControlStream(IP_ADDRESS addr, PSTREAM_CONFIGURATION streamConfigPtr, PCONNECTION_LISTENER_CALLBACKS clCallbacks) { - memcpy(&streamConfig, streamConfigPtr, sizeof(*streamConfigPtr)); - +int initializeControlStream(void) { PltCreateEvent(&resyncEvent); - - host = addr; - listenerCallbacks = clCallbacks; - if (serverMajorVersion == 3) { + if (ServerMajorVersion == 3) { packetTypes = (short*)packetTypesGen3; payloadLengths = (short*)payloadLengthsGen3; preconstructedPayloads = (char**)preconstructedPayloadsGen3; @@ -210,7 +202,7 @@ static void lossStatsThreadFunc(void* context) { lossStatsPayload = malloc(payloadLengths[IDX_LOSS_STATS]); if (lossStatsPayload == NULL) { Limelog("Loss stats thread terminating #0\n"); - listenerCallbacks->connectionTerminated(LastSocketError()); + ListenerCallbacks.connectionTerminated(LastSocketError()); return; } @@ -230,7 +222,7 @@ static void lossStatsThreadFunc(void* context) { payloadLengths[IDX_LOSS_STATS], lossStatsPayload)) { free(lossStatsPayload); Limelog("Loss stats thread terminating #1\n"); - listenerCallbacks->connectionTerminated(LastSocketError()); + ListenerCallbacks.connectionTerminated(LastSocketError()); return; } @@ -262,7 +254,7 @@ static void resyncThreadFunc(void* context) { // Send the resync request and read the response if (!sendMessageAndDiscardReply(packetTypes[IDX_RESYNC], payloadLengths[IDX_RESYNC], payload)) { Limelog("Resync thread terminating #1\n"); - listenerCallbacks->connectionTerminated(LastSocketError()); + ListenerCallbacks.connectionTerminated(LastSocketError()); return; } Limelog("Resync complete\n"); @@ -292,7 +284,7 @@ int stopControlStream(void) { int startControlStream(void) { int err; - ctlSock = connectTcpSocket(host, 47995); + ctlSock = connectTcpSocket(&RemoteAddr, RemoteAddrLen, 47995); if (ctlSock == INVALID_SOCKET) { return LastSocketError(); } diff --git a/limelight-common/FakeCallbacks.c b/limelight-common/FakeCallbacks.c index 3b8205d..f62290d 100644 --- a/limelight-common/FakeCallbacks.c +++ b/limelight-common/FakeCallbacks.c @@ -1,30 +1,22 @@ #include "Limelight-internal.h" static void fakeDrSetup(int width, int height, int redrawRate, void* context, int drFlags) {} -static void fakeDrStart(void) {} -static void fakeDrStop(void) {} -static void fakeDrRelease(void) {} +static void fakeDrCleanup(void) {} static int fakeDrSubmitDecodeUnit(PDECODE_UNIT decodeUnit) { return DR_OK; } static DECODER_RENDERER_CALLBACKS fakeDrCallbacks = { .setup = fakeDrSetup, - .start = fakeDrStart, - .stop = fakeDrStop, - .release = fakeDrRelease, + .cleanup = fakeDrCleanup, .submitDecodeUnit = fakeDrSubmitDecodeUnit, }; static void fakeArInit(void) {} -static void fakeArStart(void) {} -static void fakeArStop(void) {} -static void fakeArRelease(void) {} +static void fakeArCleanup(void) {} static void fakeArDecodeAndPlaySample(char* sampleData, int sampleLength) {} AUDIO_RENDERER_CALLBACKS fakeArCallbacks = { .init = fakeArInit, - .start = fakeArStart, - .stop = fakeArStop, - .release = fakeArRelease, + .cleanup = fakeArCleanup, .decodeAndPlaySample = fakeArDecodeAndPlaySample, }; @@ -64,14 +56,8 @@ void fixupMissingCallbacks(PDECODER_RENDERER_CALLBACKS *drCallbacks, PAUDIO_REND if ((*drCallbacks)->setup == NULL) { (*drCallbacks)->setup = fakeDrSetup; } - if ((*drCallbacks)->start == NULL) { - (*drCallbacks)->start = fakeDrStart; - } - if ((*drCallbacks)->stop == NULL) { - (*drCallbacks)->stop = fakeDrStop; - } - if ((*drCallbacks)->release == NULL) { - (*drCallbacks)->release = fakeDrRelease; + if ((*drCallbacks)->cleanup == NULL) { + (*drCallbacks)->cleanup = fakeDrCleanup; } if ((*drCallbacks)->submitDecodeUnit == NULL) { (*drCallbacks)->submitDecodeUnit = fakeDrSubmitDecodeUnit; @@ -85,14 +71,8 @@ void fixupMissingCallbacks(PDECODER_RENDERER_CALLBACKS *drCallbacks, PAUDIO_REND if ((*arCallbacks)->init == NULL) { (*arCallbacks)->init = fakeArInit; } - if ((*arCallbacks)->start == NULL) { - (*arCallbacks)->start = fakeArStart; - } - if ((*arCallbacks)->stop == NULL) { - (*arCallbacks)->stop = fakeArStop; - } - if ((*arCallbacks)->release == NULL) { - (*arCallbacks)->release = fakeArRelease; + if ((*arCallbacks)->cleanup == NULL) { + (*arCallbacks)->cleanup = fakeArCleanup; } if ((*arCallbacks)->decodeAndPlaySample == NULL) { (*arCallbacks)->decodeAndPlaySample = fakeArDecodeAndPlaySample; diff --git a/limelight-common/InputStream.c b/limelight-common/InputStream.c index 5b97f75..2face30 100644 --- a/limelight-common/InputStream.c +++ b/limelight-common/InputStream.c @@ -7,9 +7,7 @@ #include "OpenAES/oaes_lib.h" #include "OpenAES/oaes_common.h" -static IP_ADDRESS host; static SOCKET inputSock = INVALID_SOCKET; -static PCONNECTION_LISTENER_CALLBACKS listenerCallbacks; static int initialized; static LINKED_BLOCKING_QUEUE packetQueue; @@ -33,11 +31,8 @@ typedef struct _PACKET_HOLDER { } PACKET_HOLDER, *PPACKET_HOLDER; /* Initializes the input stream */ -int initializeInputStream(IP_ADDRESS addr, PCONNECTION_LISTENER_CALLBACKS clCallbacks, - char* aesKeyData, int aesKeyDataLength, char* aesIv, int aesIvLength) { - host = addr; - listenerCallbacks = clCallbacks; - +int initializeInputStream(char* aesKeyData, int aesKeyDataLength, + char* aesIv, int aesIvLength) { if (aesIvLength != OAES_BLOCK_SIZE) { Limelog("AES IV is incorrect length. Should be %d\n", aesIvLength); @@ -138,7 +133,7 @@ static void inputSendThreadProc(void* context) { err = LbqWaitForQueueElement(&packetQueue, (void**) &holder); if (err != LBQ_SUCCESS) { Limelog("Input thread terminating #1\n"); - listenerCallbacks->connectionTerminated(err); + ListenerCallbacks.connectionTerminated(err); return; } @@ -250,7 +245,7 @@ static void inputSendThreadProc(void* context) { free(holder); if (err != OAES_RET_SUCCESS) { Limelog("Input thread terminating #2\n"); - listenerCallbacks->connectionTerminated(err); + ListenerCallbacks.connectionTerminated(err); return; } @@ -269,7 +264,7 @@ static void inputSendThreadProc(void* context) { encryptedSize + sizeof(encryptedLengthPrefix), 0); if (err <= 0) { Limelog("Input thread terminating #3\n"); - listenerCallbacks->connectionTerminated(err); + ListenerCallbacks.connectionTerminated(err); return; } } @@ -279,7 +274,7 @@ static void inputSendThreadProc(void* context) { int startInputStream(void) { int err; - inputSock = connectTcpSocket(host, 35043); + inputSock = connectTcpSocket(&RemoteAddr, RemoteAddrLen, 35043); if (inputSock == INVALID_SOCKET) { return LastSocketError(); } @@ -409,7 +404,7 @@ static int sendControllerEventInternal(short controllerNumber, short buttonFlags return -1; } - if (serverMajorVersion == 3) { + if (ServerMajorVersion == 3) { // Generation 3 servers don't support multiple controllers so we send // the legacy packet holder->packetLength = sizeof(NV_CONTROLLER_PACKET); diff --git a/limelight-common/Limelight-internal.h b/limelight-common/Limelight-internal.h index 57601f7..d3baf9c 100644 --- a/limelight-common/Limelight-internal.h +++ b/limelight-common/Limelight-internal.h @@ -6,17 +6,24 @@ #include "PlatformThreads.h" #include "Video.h" -extern int serverMajorVersion; +// Common globals +extern struct sockaddr_storage RemoteAddr; +extern SOCKADDR_LEN RemoteAddrLen; +extern int ServerMajorVersion; +extern STREAM_CONFIGURATION StreamConfig; +extern PLATFORM_CALLBACKS PlatformCallbacks; +extern CONNECTION_LISTENER_CALLBACKS ListenerCallbacks; +extern DECODER_RENDERER_CALLBACKS VideoCallbacks; +extern AUDIO_RENDERER_CALLBACKS AudioCallbacks; int isBeforeSignedInt(int numA, int numB, int ambiguousCase); void fixupMissingCallbacks(PDECODER_RENDERER_CALLBACKS *drCallbacks, PAUDIO_RENDERER_CALLBACKS *arCallbacks, PCONNECTION_LISTENER_CALLBACKS *clCallbacks, PPLATFORM_CALLBACKS *plCallbacks); -char* getSdpPayloadForStreamConfig(PSTREAM_CONFIGURATION streamConfig, struct in_addr targetAddress, - int rtspClientVersion, int *length); +char* getSdpPayloadForStreamConfig(int rtspClientVersion, int *length); -int initializeControlStream(IP_ADDRESS host, PSTREAM_CONFIGURATION streamConfig, PCONNECTION_LISTENER_CALLBACKS clCallbacks); +int initializeControlStream(void); int startControlStream(void); int stopControlStream(void); void destroyControlStream(void); @@ -26,7 +33,7 @@ void connectionDetectedFrameLoss(int startFrame, int endFrame); void connectionReceivedFrame(int frameIndex); void connectionLostPackets(int lastReceivedPacket, int nextReceivedPacket); -int performRtspHandshake(IP_ADDRESS addr, PSTREAM_CONFIGURATION streamConfigPtr); +int performRtspHandshake(void); void terminateRtspHandshake(void); void initializeVideoDepacketizer(int pktSize); @@ -34,18 +41,17 @@ void destroyVideoDepacketizer(void); void processRtpPayload(PNV_VIDEO_PACKET videoPacket, int length); void queueRtpPacket(PRTP_PACKET rtpPacket, int length); -void initializeVideoStream(IP_ADDRESS host, PSTREAM_CONFIGURATION streamConfig, PDECODER_RENDERER_CALLBACKS drCallbacks, PCONNECTION_LISTENER_CALLBACKS clCallbacks); +void initializeVideoStream(void); void destroyVideoStream(void); int startVideoStream(void* rendererContext, int drFlags); void stopVideoStream(void); -void initializeAudioStream(IP_ADDRESS host, PAUDIO_RENDERER_CALLBACKS arCallbacks, PCONNECTION_LISTENER_CALLBACKS clCallbacks); +void initializeAudioStream(void); void destroyAudioStream(void); int startAudioStream(void); void stopAudioStream(void); -int initializeInputStream(IP_ADDRESS addr, PCONNECTION_LISTENER_CALLBACKS clCallbacks, - char* aesKeyData, int aesKeyDataLength, char* aesIv, int aesIvLength); +int initializeInputStream(char* aesKeyData, int aesKeyDataLength, char* aesIv, int aesIvLength); void destroyInputStream(void); int startInputStream(void); int stopInputStream(void); diff --git a/limelight-common/Limelight.h b/limelight-common/Limelight.h index 804af5e..e78cb5a 100644 --- a/limelight-common/Limelight.h +++ b/limelight-common/Limelight.h @@ -8,8 +8,6 @@ extern "C" { #endif -#define IP_ADDRESS unsigned int - typedef struct _STREAM_CONFIGURATION { // Dimensions in pixels of the desired video stream int width; @@ -54,14 +52,8 @@ typedef struct _DECODE_UNIT { // 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); -// This callback is invoked right before video data starts being submitted to the decoder -typedef void(*DecoderRendererStart)(void); - -// After this callback is invoked, no more video data will be submitted to the decoder -typedef void(*DecoderRendererStop)(void); - -// This callback performs the final teardown of the video decoder -typedef void(*DecoderRendererRelease)(void); +// This callback performs the teardown of the video decoder +typedef void(*DecoderRendererCleanup)(void); // This callback provides Annex B formatted H264 elementary stream data to the // decoder. If the decoder is unable to process the submitted data for some reason, @@ -72,32 +64,22 @@ typedef int(*DecoderRendererSubmitDecodeUnit)(PDECODE_UNIT decodeUnit); typedef struct _DECODER_RENDERER_CALLBACKS { DecoderRendererSetup setup; - DecoderRendererStart start; - DecoderRendererStop stop; - DecoderRendererRelease release; + DecoderRendererCleanup cleanup; DecoderRendererSubmitDecodeUnit submitDecodeUnit; } DECODER_RENDERER_CALLBACKS, *PDECODER_RENDERER_CALLBACKS; // This callback initializes the audio renderer typedef void(*AudioRendererInit)(void); -// This callback occurs before audio data is submitted -typedef void(*AudioRendererStart)(void); - -// After this callback is invoked, no more audio data will be submitted -typedef void(*AudioRendererStop)(void); - // This callback performs the final teardown of the audio decoder -typedef void(*AudioRendererRelease)(void); +typedef void(*AudioRendererCleanup)(void); // This callback provides Opus audio data to be decoded and played. sampleLength is in bytes. typedef void(*AudioRendererDecodeAndPlaySample)(char* sampleData, int sampleLength); typedef struct _AUDIO_RENDERER_CALLBACKS { AudioRendererInit init; - AudioRendererStart start; - AudioRendererStop stop; - AudioRendererRelease release; + AudioRendererCleanup cleanup; AudioRendererDecodeAndPlaySample decodeAndPlaySample; } AUDIO_RENDERER_CALLBACKS, *PAUDIO_RENDERER_CALLBACKS; @@ -105,16 +87,17 @@ typedef struct _AUDIO_RENDERER_CALLBACKS { // Use LiGetStageName() for stable stage names #define STAGE_NONE 0 #define STAGE_PLATFORM_INIT 1 -#define STAGE_RTSP_HANDSHAKE 2 -#define STAGE_CONTROL_STREAM_INIT 3 -#define STAGE_VIDEO_STREAM_INIT 4 -#define STAGE_AUDIO_STREAM_INIT 5 -#define STAGE_INPUT_STREAM_INIT 6 -#define STAGE_CONTROL_STREAM_START 7 -#define STAGE_VIDEO_STREAM_START 8 -#define STAGE_AUDIO_STREAM_START 9 -#define STAGE_INPUT_STREAM_START 10 -#define STAGE_MAX 11 +#define STAGE_NAME_RESOLUTION 2 +#define STAGE_RTSP_HANDSHAKE 3 +#define STAGE_CONTROL_STREAM_INIT 4 +#define STAGE_VIDEO_STREAM_INIT 5 +#define STAGE_AUDIO_STREAM_INIT 6 +#define STAGE_INPUT_STREAM_INIT 7 +#define STAGE_CONTROL_STREAM_START 8 +#define STAGE_VIDEO_STREAM_START 9 +#define STAGE_AUDIO_STREAM_START 10 +#define STAGE_INPUT_STREAM_START 11 +#define STAGE_MAX 12 // This callback is invoked to indicate that a stage of initialization is about to begin typedef void(*ConnListenerStageStarting)(int stage); @@ -169,7 +152,7 @@ typedef struct _PLATFORM_CALLBACKS { // // _serverMajorVersion is the major version number of the 'appversion' tag in the /serverinfo request // -int LiStartConnection(IP_ADDRESS host, PSTREAM_CONFIGURATION streamConfig, PCONNECTION_LISTENER_CALLBACKS clCallbacks, +int LiStartConnection(char* host, PSTREAM_CONFIGURATION streamConfig, PCONNECTION_LISTENER_CALLBACKS clCallbacks, PDECODER_RENDERER_CALLBACKS drCallbacks, PAUDIO_RENDERER_CALLBACKS arCallbacks, PPLATFORM_CALLBACKS plCallbacks, void* renderContext, int drFlags, int _serverMajorVersion); diff --git a/limelight-common/PlatformSockets.c b/limelight-common/PlatformSockets.c index bc0e8bb..34eaa7f 100644 --- a/limelight-common/PlatformSockets.c +++ b/limelight-common/PlatformSockets.c @@ -1,20 +1,44 @@ #include "PlatformSockets.h" #include "Limelight-internal.h" -SOCKET bindUdpSocket(void) { +void addrToUrlSafeString(struct sockaddr_storage *addr, char* string) +{ + if (addr->ss_family == AF_INET6) { + char addrstr[INET6_ADDRSTRLEN]; + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr; + inet_ntop(addr->ss_family, &sin6->sin6_addr, addrstr, sizeof(addrstr)); + + // IPv6 addresses need to be enclosed in brackets for URLs + sprintf(string, "[%s]", addrstr); + } + else { + struct sockaddr_in *sin = (struct sockaddr_in *)addr; + char *addrstr = inet_ntoa(sin->sin_addr); + + // IPv4 addresses are returned without changes + sprintf(string, "%s", addrstr); + } +} + +SOCKET bindUdpSocket(int addrfamily) { SOCKET s; - struct sockaddr_in addr; + struct sockaddr_storage addr; int val; int err; - s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + LC_ASSERT(addrfamily == AF_INET || addrfamily == AF_INET6); + + s = socket(addrfamily, SOCK_DGRAM, IPPROTO_UDP); if (s == INVALID_SOCKET) { return INVALID_SOCKET; } memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - if (bind(s, (struct sockaddr*) &addr, sizeof(addr)) == SOCKET_ERROR) { + addr.ss_family = addrfamily; + if (bind(s, (struct sockaddr*) &addr, + addrfamily == AF_INET ? + sizeof(struct sockaddr_in) : + sizeof(struct sockaddr_in6)) == SOCKET_ERROR) { err = LastSocketError(); closesocket(s); SetLastSocketError(err); @@ -34,15 +58,15 @@ SOCKET bindUdpSocket(void) { return s; } -SOCKET connectTcpSocket(IP_ADDRESS dstaddr, unsigned short port) { +SOCKET connectTcpSocket(struct sockaddr_storage *dstaddr, SOCKADDR_LEN addrlen, unsigned short port) { SOCKET s; - struct sockaddr_in addr; + struct sockaddr_in6 addr; int err; #ifdef LC_DARWIN int val; #endif - s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + s = socket(dstaddr->ss_family, SOCK_STREAM, IPPROTO_TCP); if (s == INVALID_SOCKET) { return INVALID_SOCKET; } @@ -53,11 +77,9 @@ SOCKET connectTcpSocket(IP_ADDRESS dstaddr, unsigned short port) { setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, (char* )&val, sizeof(val)); #endif - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - memcpy(&addr.sin_addr, &dstaddr, sizeof(dstaddr)); - if (connect(s, (struct sockaddr*) &addr, sizeof(addr)) == SOCKET_ERROR) { + memcpy(&addr, dstaddr, sizeof(addr)); + addr.sin6_port = htons(port); + if (connect(s, (struct sockaddr*) &addr, addrlen) == SOCKET_ERROR) { err = LastSocketError(); closesocket(s); SetLastSocketError(err); diff --git a/limelight-common/PlatformSockets.h b/limelight-common/PlatformSockets.h index 2d03a1b..00501c1 100644 --- a/limelight-common/PlatformSockets.h +++ b/limelight-common/PlatformSockets.h @@ -10,6 +10,7 @@ #define LastSocketError() WSAGetLastError() typedef int SOCK_RET; +typedef int SOCKADDR_LEN; #else #include @@ -17,6 +18,7 @@ typedef int SOCK_RET; #include #include #include +#include #include #include @@ -28,8 +30,13 @@ typedef int SOCK_RET; typedef int SOCKET; typedef ssize_t SOCK_RET; +typedef socklen_t SOCKADDR_LEN; #endif -SOCKET connectTcpSocket(IP_ADDRESS dstaddr, unsigned short port); -SOCKET bindUdpSocket(void); +// IPv6 addresses have 2 extra characters for URL escaping +#define URLSAFESTRING_LEN INET6_ADDRSTRLEN+2 +void addrToUrlSafeString(struct sockaddr_storage *addr, char* string); + +SOCKET connectTcpSocket(struct sockaddr_storage *dstaddr, SOCKADDR_LEN addrlen, unsigned short port); +SOCKET bindUdpSocket(int addrfamily); int enableNoDelay(SOCKET s); \ No newline at end of file diff --git a/limelight-common/RtspConnection.c b/limelight-common/RtspConnection.c index 5e6f720..81e0651 100644 --- a/limelight-common/RtspConnection.c +++ b/limelight-common/RtspConnection.c @@ -4,7 +4,6 @@ #define RTSP_MAX_RESP_SIZE 16384 static SOCKET sock = INVALID_SOCKET; -static IP_ADDRESS remoteAddr; static int currentSeqNumber; static char rtspTargetUrl[256]; static char sessionIdString[16]; @@ -86,7 +85,7 @@ static int transactRtspMessage(PRTSP_MESSAGE request, PRTSP_MESSAGE response) { char* serializedMessage = NULL; int messageLen; - sock = connectTcpSocket(remoteAddr, 48010); + sock = connectTcpSocket(&RemoteAddr, RemoteAddrLen, 48010); if (sock == INVALID_SOCKET) { return ret; } @@ -238,7 +237,6 @@ static int sendVideoAnnounce(PRTSP_MESSAGE response, PSTREAM_CONFIGURATION strea int ret; int payloadLength; char payloadLengthStr[16]; - struct in_addr sdpAddr; ret = initializeRtspRequest(&request, "ANNOUNCE", "streamid=video"); if (ret != 0) { @@ -249,9 +247,7 @@ static int sendVideoAnnounce(PRTSP_MESSAGE response, PSTREAM_CONFIGURATION strea goto FreeMessage; } - memcpy(&sdpAddr, &remoteAddr, sizeof(remoteAddr)); - request.payload = getSdpPayloadForStreamConfig(streamConfig, sdpAddr, - rtspClientVersion, &payloadLength); + request.payload = getSdpPayloadForStreamConfig(rtspClientVersion, &payloadLength); if (request.payload == NULL) { goto FreeMessage; } @@ -273,17 +269,16 @@ static int sendVideoAnnounce(PRTSP_MESSAGE response, PSTREAM_CONFIGURATION strea } /* Perform RTSP Handshake with the streaming server machine as part of the connection process */ -int performRtspHandshake(IP_ADDRESS addr, PSTREAM_CONFIGURATION streamConfigPtr) { - struct in_addr inaddr; - +int performRtspHandshake(void) { + char urlAddr[URLSAFESTRING_LEN]; + // Initialize global state - remoteAddr = addr; - memcpy(&inaddr, &addr, sizeof(addr)); - sprintf(rtspTargetUrl, "rtsp://%s", inet_ntoa(inaddr)); + addrToUrlSafeString(&RemoteAddr, urlAddr); + sprintf(rtspTargetUrl, "rtsp://%s", urlAddr); currentSeqNumber = 1; hasSessionId = 0; - if (serverMajorVersion == 3) { + if (ServerMajorVersion == 3) { rtspClientVersion = 10; } else { @@ -371,7 +366,7 @@ int performRtspHandshake(IP_ADDRESS addr, PSTREAM_CONFIGURATION streamConfigPtr) { RTSP_MESSAGE response; - if (!sendVideoAnnounce(&response, streamConfigPtr)) { + if (!sendVideoAnnounce(&response, &StreamConfig)) { Limelog("RTSP ANNOUNCE request failed\n"); return -1; } diff --git a/limelight-common/SdpGenerator.c b/limelight-common/SdpGenerator.c index 91b2e5b..17f99f1 100644 --- a/limelight-common/SdpGenerator.c +++ b/limelight-common/SdpGenerator.c @@ -144,7 +144,7 @@ static int addGen4Options(PSDP_OPTION *head, char* addrStr) { return err; } -static PSDP_OPTION getAttributesList(PSTREAM_CONFIGURATION streamConfig, struct in_addr targetAddress) { +static PSDP_OPTION getAttributesList(char *urlSafeAddr) { PSDP_OPTION optionHead; char payloadStr[92]; int err; @@ -152,21 +152,21 @@ static PSDP_OPTION getAttributesList(PSTREAM_CONFIGURATION streamConfig, struct optionHead = NULL; err = 0; - sprintf(payloadStr, "%d", streamConfig->width); + sprintf(payloadStr, "%d", StreamConfig.width); err |= addAttributeString(&optionHead, "x-nv-video[0].clientViewportWd", payloadStr); - sprintf(payloadStr, "%d", streamConfig->height); + sprintf(payloadStr, "%d", StreamConfig.height); err |= addAttributeString(&optionHead, "x-nv-video[0].clientViewportHt", payloadStr); - sprintf(payloadStr, "%d", streamConfig->fps); + sprintf(payloadStr, "%d", StreamConfig.fps); err |= addAttributeString(&optionHead, "x-nv-video[0].maxFPS", payloadStr); - sprintf(payloadStr, "%d", streamConfig->packetSize); + sprintf(payloadStr, "%d", StreamConfig.packetSize); err |= addAttributeString(&optionHead, "x-nv-video[0].packetSize", payloadStr); err |= addAttributeString(&optionHead, "x-nv-video[0].rateControlMode", "4"); // FIXME: Remote optimizations - if (streamConfig->bitrate <= 13000) { + if (StreamConfig.bitrate <= 13000) { err |= addAttributeString(&optionHead, "x-nv-video[0].averageBitrate", "9"); err |= addAttributeString(&optionHead, "x-nv-video[0].peakBitrate", "9"); } @@ -175,18 +175,18 @@ static PSDP_OPTION getAttributesList(PSTREAM_CONFIGURATION streamConfig, struct err |= addAttributeString(&optionHead, "x-nv-video[0].framesWithInvalidRefThreshold", "0"); // Lock the bitrate since we're not scaling resolution so the picture doesn't get too bad - if (streamConfig->height >= 1080 && streamConfig->fps >= 60) { - if (streamConfig->bitrate < 10000) { - sprintf(payloadStr, "%d", streamConfig->bitrate); + if (StreamConfig.height >= 1080 && StreamConfig.fps >= 60) { + if (StreamConfig.bitrate < 10000) { + sprintf(payloadStr, "%d", StreamConfig.bitrate); err |= addAttributeString(&optionHead, "x-nv-vqos[0].bw.minimumBitrate", payloadStr); } else { err |= addAttributeString(&optionHead, "x-nv-vqos[0].bw.minimumBitrate", "10000"); } } - else if (streamConfig->height >= 1080 || streamConfig->fps >= 60) { - if (streamConfig->bitrate < 7000) { - sprintf(payloadStr, "%d", streamConfig->bitrate); + else if (StreamConfig.height >= 1080 || StreamConfig.fps >= 60) { + if (StreamConfig.bitrate < 7000) { + sprintf(payloadStr, "%d", StreamConfig.bitrate); err |= addAttributeString(&optionHead, "x-nv-vqos[0].bw.minimumBitrate", payloadStr); } else { @@ -194,8 +194,8 @@ static PSDP_OPTION getAttributesList(PSTREAM_CONFIGURATION streamConfig, struct } } else { - if (streamConfig->bitrate < 3000) { - sprintf(payloadStr, "%d", streamConfig->bitrate); + if (StreamConfig.bitrate < 3000) { + sprintf(payloadStr, "%d", StreamConfig.bitrate); err |= addAttributeString(&optionHead, "x-nv-vqos[0].bw.minimumBitrate", payloadStr); } else { @@ -203,7 +203,7 @@ static PSDP_OPTION getAttributesList(PSTREAM_CONFIGURATION streamConfig, struct } } - sprintf(payloadStr, "%d", streamConfig->bitrate); + sprintf(payloadStr, "%d", StreamConfig.bitrate); err |= addAttributeString(&optionHead, "x-nv-vqos[0].bw.maximumBitrate", payloadStr); // Using FEC turns padding on which makes us have to take the slow path @@ -218,11 +218,11 @@ static PSDP_OPTION getAttributesList(PSTREAM_CONFIGURATION streamConfig, struct err |= addAttributeString(&optionHead, "x-nv-vqos[0].qosTrafficType", "5"); err |= addAttributeString(&optionHead, "x-nv-aqos.qosTrafficType", "4"); - if (serverMajorVersion == 3) { - err |= addGen3Options(&optionHead, inet_ntoa(targetAddress)); + if (ServerMajorVersion == 3) { + err |= addGen3Options(&optionHead, urlSafeAddr); } else { - err |= addGen4Options(&optionHead, inet_ntoa(targetAddress)); + err |= addGen4Options(&optionHead, urlSafeAddr); } if (err == 0) { @@ -234,11 +234,14 @@ static PSDP_OPTION getAttributesList(PSTREAM_CONFIGURATION streamConfig, struct } /* Populate the SDP header with required information */ -static int fillSdpHeader(char* buffer, struct in_addr targetAddress, int rtspClientVersion) { +static int fillSdpHeader(char* buffer, int rtspClientVersion, char *urlSafeAddr) { return sprintf(buffer, "v=0\r\n" - "o=android 0 %d IN IPv4 %s\r\n" - "s=NVIDIA Streaming Client\r\n", rtspClientVersion, inet_ntoa(targetAddress)); + "o=android 0 %d IN %s %s\r\n" + "s=NVIDIA Streaming Client\r\n", + rtspClientVersion, + RemoteAddr.ss_family == AF_INET ? "IPv4" : "IPv6", + urlSafeAddr); } /* Populate the SDP tail with required information */ @@ -246,17 +249,19 @@ static int fillSdpTail(char* buffer) { return sprintf(buffer, "t=0 0\r\n" "m=video %d \r\n", - serverMajorVersion < 4 ? 47996 : 47998); + ServerMajorVersion < 4 ? 47996 : 47998); } /* Get the SDP attributes for the stream config */ -char* getSdpPayloadForStreamConfig(PSTREAM_CONFIGURATION streamConfig, struct in_addr targetAddress, - int rtspClientVersion, int *length) { +char* getSdpPayloadForStreamConfig(int rtspClientVersion, int *length) { PSDP_OPTION attributeList; int offset; char* payload; + char urlSafeAddr[URLSAFESTRING_LEN]; + + addrToUrlSafeString(&RemoteAddr, urlSafeAddr); - attributeList = getAttributesList(streamConfig, targetAddress); + attributeList = getAttributesList(urlSafeAddr); if (attributeList == NULL) { return NULL; } @@ -268,7 +273,7 @@ char* getSdpPayloadForStreamConfig(PSTREAM_CONFIGURATION streamConfig, struct in return NULL; } - offset = fillSdpHeader(payload, targetAddress, rtspClientVersion); + offset = fillSdpHeader(payload, rtspClientVersion, urlSafeAddr); offset += fillSerializedAttributeList(&payload[offset], attributeList); offset += fillSdpTail(&payload[offset]); diff --git a/limelight-common/VideoStream.c b/limelight-common/VideoStream.c index 05296b6..8f62178 100644 --- a/limelight-common/VideoStream.c +++ b/limelight-common/VideoStream.c @@ -9,10 +9,6 @@ #define RTP_PORT 47998 #define FIRST_FRAME_PORT 47996 -static DECODER_RENDERER_CALLBACKS callbacks; -static STREAM_CONFIGURATION configuration; -static IP_ADDRESS remoteHost; -static PCONNECTION_LISTENER_CALLBACKS listenerCallbacks; static RTP_REORDER_QUEUE rtpQueue; static SOCKET rtpSocket = INVALID_SOCKET; @@ -28,20 +24,14 @@ static PLT_THREAD decoderThread; #define RTP_QUEUE_DELAY 10 /* Initialize the video stream */ -void initializeVideoStream(IP_ADDRESS host, PSTREAM_CONFIGURATION streamConfig, PDECODER_RENDERER_CALLBACKS drCallbacks, - PCONNECTION_LISTENER_CALLBACKS clCallbacks) { - memcpy(&callbacks, drCallbacks, sizeof(callbacks)); - memcpy(&configuration, streamConfig, sizeof(configuration)); - remoteHost = host; - listenerCallbacks = clCallbacks; - - initializeVideoDepacketizer(configuration.packetSize); +void initializeVideoStream(void) { + initializeVideoDepacketizer(StreamConfig.packetSize); RtpqInitializeQueue(&rtpQueue, RTPQ_DEFAULT_MAX_SIZE, RTP_QUEUE_DELAY); } /* Clean up the video stream */ void destroyVideoStream(void) { - callbacks.release(); + VideoCallbacks.cleanup(); destroyVideoDepacketizer(); RtpqCleanupQueue(&rtpQueue); @@ -50,19 +40,17 @@ void destroyVideoStream(void) { /* UDP Ping proc */ static void UdpPingThreadProc(void *context) { char pingData [] = { 0x50, 0x49, 0x4E, 0x47 }; - struct sockaddr_in saddr; + struct sockaddr_in6 saddr; SOCK_RET err; - memset(&saddr, 0, sizeof(saddr)); - saddr.sin_family = AF_INET; - saddr.sin_port = htons(RTP_PORT); - memcpy(&saddr.sin_addr, &remoteHost, sizeof(remoteHost)); + memcpy(&saddr, &RemoteAddr, sizeof(saddr)); + saddr.sin6_port = htons(RTP_PORT); while (!PltIsThreadInterrupted(&udpPingThread)) { - err = sendto(rtpSocket, pingData, sizeof(pingData), 0, (struct sockaddr*)&saddr, sizeof(saddr)); + err = sendto(rtpSocket, pingData, sizeof(pingData), 0, (struct sockaddr*)&saddr, RemoteAddrLen); if (err != sizeof(pingData)) { Limelog("UDP ping thread terminating #1\n"); - listenerCallbacks->connectionTerminated(LastSocketError()); + ListenerCallbacks.connectionTerminated(LastSocketError()); return; } @@ -77,7 +65,7 @@ static void ReceiveThreadProc(void* context) { char* buffer; int queueStatus; - receiveSize = configuration.packetSize + MAX_RTP_HEADER_SIZE; + receiveSize = StreamConfig.packetSize + MAX_RTP_HEADER_SIZE; bufferSize = receiveSize + sizeof(int) + sizeof(RTP_QUEUE_ENTRY); buffer = NULL; @@ -88,7 +76,7 @@ static void ReceiveThreadProc(void* context) { buffer = (char*) malloc(bufferSize); if (buffer == NULL) { Limelog("Receive thread terminating\n"); - listenerCallbacks->connectionTerminated(-1); + ListenerCallbacks.connectionTerminated(-1); return; } } @@ -96,7 +84,7 @@ static void ReceiveThreadProc(void* context) { err = (int) recv(rtpSocket, buffer, receiveSize, 0); if (err <= 0) { Limelog("Receive thread terminating #2\n"); - listenerCallbacks->connectionTerminated(LastSocketError()); + ListenerCallbacks.connectionTerminated(LastSocketError()); break; } @@ -135,11 +123,11 @@ static void DecoderThreadProc(void* context) { PQUEUED_DECODE_UNIT qdu; while (!PltIsThreadInterrupted(&decoderThread)) { if (!getNextQueuedDecodeUnit(&qdu)) { - printf("Decoder thread terminating\n"); + Limelog("Decoder thread terminating\n"); return; } - int ret = callbacks.submitDecodeUnit(&qdu->decodeUnit); + int ret = VideoCallbacks.submitDecodeUnit(&qdu->decodeUnit); freeQueuedDecodeUnit(qdu); @@ -163,8 +151,6 @@ int readFirstFrame(void) { /* Terminate the video stream */ void stopVideoStream(void) { - callbacks.stop(); - PltInterruptThread(&udpPingThread); PltInterruptThread(&receiveThread); PltInterruptThread(&decoderThread); @@ -191,14 +177,12 @@ void stopVideoStream(void) { int startVideoStream(void* rendererContext, int drFlags) { int err; - callbacks.setup(configuration.width, - configuration.height, configuration.fps, rendererContext, drFlags); - // This must be called before the decoder thread starts submitting // decode units - callbacks.start(); + VideoCallbacks.setup(StreamConfig.width, + StreamConfig.height, StreamConfig.fps, rendererContext, drFlags); - rtpSocket = bindUdpSocket(); + rtpSocket = bindUdpSocket(RemoteAddr.ss_family); if (rtpSocket == INVALID_SOCKET) { return LastSocketError(); } @@ -213,9 +197,9 @@ int startVideoStream(void* rendererContext, int drFlags) { return err; } - if (serverMajorVersion == 3) { + if (ServerMajorVersion == 3) { // Connect this socket to open port 47998 for our ping thread - firstFrameSocket = connectTcpSocket(remoteHost, FIRST_FRAME_PORT); + firstFrameSocket = connectTcpSocket(&RemoteAddr, RemoteAddrLen, FIRST_FRAME_PORT); if (firstFrameSocket == INVALID_SOCKET) { return LastSocketError(); } @@ -228,7 +212,7 @@ int startVideoStream(void* rendererContext, int drFlags) { return err; } - if (serverMajorVersion == 3) { + if (ServerMajorVersion == 3) { // Read the first frame to start the flow of video err = readFirstFrame(); if (err != 0) {