Update to API 1.1

This commit is contained in:
Cameron Gutman 2015-06-17 23:21:58 -07:00
parent 43e6d35b8f
commit c4d19edb4c
12 changed files with 265 additions and 261 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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();
}

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -10,6 +10,7 @@
#define LastSocketError() WSAGetLastError()
typedef int SOCK_RET;
typedef int SOCKADDR_LEN;
#else
#include <sys/types.h>
@ -17,6 +18,7 @@ typedef int SOCK_RET;
#include <netinet/tcp.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <signal.h>
@ -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);

View File

@ -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;
}

View File

@ -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]);

View File

@ -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) {