mirror of
https://github.com/moonlight-stream/moonlight-common-c.git
synced 2025-08-17 17:05:50 +00:00
Update to API 1.1
This commit is contained in:
parent
43e6d35b8f
commit
c4d19edb4c
@ -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;
|
||||
}
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
@ -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;
|
||||
}
|
||||
|
@ -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]);
|
||||
|
||||
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user