mirror of
https://github.com/moonlight-stream/moonlight-common-c.git
synced 2025-08-17 17:05:50 +00:00
Add backwards compatibility for GFE 2.1.x
This commit is contained in:
parent
7883ce67cd
commit
0fa1a02e0a
@ -8,6 +8,8 @@ static CONNECTION_LISTENER_CALLBACKS originalCallbacks;
|
|||||||
// This is used for debug prints so it's not declared static
|
// This is used for debug prints so it's not declared static
|
||||||
PLATFORM_CALLBACKS platformCallbacks;
|
PLATFORM_CALLBACKS platformCallbacks;
|
||||||
|
|
||||||
|
int serverMajorVersion;
|
||||||
|
|
||||||
static int alreadyTerminated;
|
static int alreadyTerminated;
|
||||||
|
|
||||||
/* Connection stages */
|
/* Connection stages */
|
||||||
@ -148,8 +150,10 @@ void LiCompleteThreadStart(void)
|
|||||||
/* Starts the connection to the streaming machine */
|
/* Starts the connection to the streaming machine */
|
||||||
int LiStartConnection(IP_ADDRESS host, PSTREAM_CONFIGURATION streamConfig, PCONNECTION_LISTENER_CALLBACKS clCallbacks,
|
int LiStartConnection(IP_ADDRESS host, PSTREAM_CONFIGURATION streamConfig, PCONNECTION_LISTENER_CALLBACKS clCallbacks,
|
||||||
PDECODER_RENDERER_CALLBACKS drCallbacks, PAUDIO_RENDERER_CALLBACKS arCallbacks, PPLATFORM_CALLBACKS plCallbacks,
|
PDECODER_RENDERER_CALLBACKS drCallbacks, PAUDIO_RENDERER_CALLBACKS arCallbacks, PPLATFORM_CALLBACKS plCallbacks,
|
||||||
void* renderContext, int drFlags) {
|
void* renderContext, int drFlags, int _serverMajorVersion) {
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
serverMajorVersion = _serverMajorVersion;
|
||||||
|
|
||||||
memcpy(&originalCallbacks, clCallbacks, sizeof(originalCallbacks));
|
memcpy(&originalCallbacks, clCallbacks, sizeof(originalCallbacks));
|
||||||
memcpy(&platformCallbacks, plCallbacks, sizeof(platformCallbacks));
|
memcpy(&platformCallbacks, plCallbacks, sizeof(platformCallbacks));
|
||||||
|
@ -20,22 +20,59 @@ static PCONNECTION_LISTENER_CALLBACKS listenerCallbacks;
|
|||||||
static int lossCountSinceLastReport = 0;
|
static int lossCountSinceLastReport = 0;
|
||||||
static long currentFrame = 0;
|
static long currentFrame = 0;
|
||||||
|
|
||||||
#define PTYPE_START_STREAM_A 0x0606
|
#define IDX_START_A 0
|
||||||
#define PPAYLEN_START_STREAM_A 2
|
#define IDX_START_B 1
|
||||||
static const char PPAYLOAD_START_STREAM_A[PPAYLEN_START_STREAM_A] = { 0, 0 };
|
#define IDX_RESYNC 2
|
||||||
|
#define IDX_LOSS_STATS 3
|
||||||
|
|
||||||
#define PTYPE_START_STREAM_B 0x0609
|
static const short packetTypesGen3[] = {
|
||||||
#define PPAYLEN_START_STREAM_B 1
|
0x140b, // Start A
|
||||||
static const char PPAYLOAD_START_STREAM_B[PPAYLEN_START_STREAM_B] = { 0 };
|
0x1410, // Start B
|
||||||
|
0x1404, // Resync
|
||||||
|
0x140c, // Loss Stats
|
||||||
|
0x1417, // Frame Stats (unused)
|
||||||
|
};
|
||||||
|
static const short packetTypesGen4[] = {
|
||||||
|
0x0606, // Start A
|
||||||
|
0x0609, // Start B
|
||||||
|
0x0604, // Resync
|
||||||
|
0x060a, // Loss Stats
|
||||||
|
0x0611, // Frame Stats (unused)
|
||||||
|
};
|
||||||
|
|
||||||
#define PTYPE_RESYNC 0x0604
|
static const char startAGen3[] = {0};
|
||||||
#define PPAYLEN_RESYNC 24
|
static const int startBGen3[] = {0, 0, 0, 0xa};
|
||||||
|
|
||||||
#define PTYPE_LOSS_STATS 0x060a
|
static const char startAGen4[] = {0, 0};
|
||||||
#define PPAYLEN_LOSS_STATS 32
|
static const char startBGen4[] = {0};
|
||||||
|
|
||||||
#define PTYPE_FRAME_STATS 0x0611
|
static const short payloadLengthsGen3[] = {
|
||||||
#define PPAYLEN_FRAME_STATS 64
|
sizeof(startAGen3), // Start A
|
||||||
|
sizeof(startBGen3), // Start B
|
||||||
|
24, // Resync
|
||||||
|
32, // Loss Stats
|
||||||
|
64, // Frame Stats
|
||||||
|
};
|
||||||
|
static const short payloadLengthsGen4[] = {
|
||||||
|
sizeof(startAGen4), // Start A
|
||||||
|
sizeof(startBGen4), // Start B
|
||||||
|
24, // Resync
|
||||||
|
32, // Loss Stats
|
||||||
|
64, // Frame Stats
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char* preconstructedPayloadsGen3[] = {
|
||||||
|
startAGen3,
|
||||||
|
(char*)startBGen3
|
||||||
|
};
|
||||||
|
static const char* preconstructedPayloadsGen4[] = {
|
||||||
|
startAGen4,
|
||||||
|
startBGen4
|
||||||
|
};
|
||||||
|
|
||||||
|
static short *packetTypes;
|
||||||
|
static short *payloadLengths;
|
||||||
|
static char **preconstructedPayloads;
|
||||||
|
|
||||||
#define LOSS_REPORT_INTERVAL_MS 50
|
#define LOSS_REPORT_INTERVAL_MS 50
|
||||||
|
|
||||||
@ -47,6 +84,17 @@ int initializeControlStream(IP_ADDRESS addr, PSTREAM_CONFIGURATION streamConfigP
|
|||||||
|
|
||||||
host = addr;
|
host = addr;
|
||||||
listenerCallbacks = clCallbacks;
|
listenerCallbacks = clCallbacks;
|
||||||
|
|
||||||
|
if (serverMajorVersion == 3) {
|
||||||
|
packetTypes = (short*)packetTypesGen3;
|
||||||
|
payloadLengths = (short*)payloadLengthsGen3;
|
||||||
|
preconstructedPayloads = (char**)preconstructedPayloadsGen3;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
packetTypes = (short*)packetTypesGen4;
|
||||||
|
payloadLengths = (short*)payloadLengthsGen4;
|
||||||
|
preconstructedPayloads = (char**)preconstructedPayloadsGen4;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -156,12 +204,12 @@ static int sendMessageAndDiscardReply(short ptype, short paylen, const void* pay
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void lossStatsThreadFunc(void* context) {
|
static void lossStatsThreadFunc(void* context) {
|
||||||
char lossStatsPayload[PPAYLEN_LOSS_STATS];
|
char lossStatsPayload[payloadLengths[IDX_LOSS_STATS]];
|
||||||
BYTE_BUFFER byteBuffer;
|
BYTE_BUFFER byteBuffer;
|
||||||
|
|
||||||
while (!PltIsThreadInterrupted(&lossStatsThread)) {
|
while (!PltIsThreadInterrupted(&lossStatsThread)) {
|
||||||
// Construct the payload
|
// Construct the payload
|
||||||
BbInitializeWrappedBuffer(&byteBuffer, lossStatsPayload, 0, PPAYLEN_LOSS_STATS, BYTE_ORDER_LITTLE);
|
BbInitializeWrappedBuffer(&byteBuffer, lossStatsPayload, 0, payloadLengths[IDX_LOSS_STATS], BYTE_ORDER_LITTLE);
|
||||||
BbPutInt(&byteBuffer, lossCountSinceLastReport);
|
BbPutInt(&byteBuffer, lossCountSinceLastReport);
|
||||||
BbPutInt(&byteBuffer, LOSS_REPORT_INTERVAL_MS);
|
BbPutInt(&byteBuffer, LOSS_REPORT_INTERVAL_MS);
|
||||||
BbPutInt(&byteBuffer, 1000);
|
BbPutInt(&byteBuffer, 1000);
|
||||||
@ -171,8 +219,8 @@ static void lossStatsThreadFunc(void* context) {
|
|||||||
BbPutInt(&byteBuffer, 0x14);
|
BbPutInt(&byteBuffer, 0x14);
|
||||||
|
|
||||||
// Send the message (and don't expect a response)
|
// Send the message (and don't expect a response)
|
||||||
if (!sendMessageAndForget(PTYPE_LOSS_STATS,
|
if (!sendMessageAndForget(packetTypes[IDX_LOSS_STATS],
|
||||||
PPAYLEN_LOSS_STATS, lossStatsPayload)) {
|
payloadLengths[IDX_LOSS_STATS], lossStatsPayload)) {
|
||||||
Limelog("Loss stats thread terminating #1\n");
|
Limelog("Loss stats thread terminating #1\n");
|
||||||
listenerCallbacks->connectionTerminated(LastSocketError());
|
listenerCallbacks->connectionTerminated(LastSocketError());
|
||||||
return;
|
return;
|
||||||
@ -202,7 +250,7 @@ static void resyncThreadFunc(void* context) {
|
|||||||
PltClearEvent(&resyncEvent);
|
PltClearEvent(&resyncEvent);
|
||||||
|
|
||||||
// Send the resync request and read the response
|
// Send the resync request and read the response
|
||||||
if (!sendMessageAndDiscardReply(PTYPE_RESYNC, PPAYLEN_RESYNC, payload)) {
|
if (!sendMessageAndDiscardReply(packetTypes[IDX_RESYNC], payloadLengths[IDX_RESYNC], payload)) {
|
||||||
Limelog("Resync thread terminating #1\n");
|
Limelog("Resync thread terminating #1\n");
|
||||||
listenerCallbacks->connectionTerminated(LastSocketError());
|
listenerCallbacks->connectionTerminated(LastSocketError());
|
||||||
return;
|
return;
|
||||||
@ -242,16 +290,16 @@ int startControlStream(void) {
|
|||||||
enableNoDelay(ctlSock);
|
enableNoDelay(ctlSock);
|
||||||
|
|
||||||
// Send START A
|
// Send START A
|
||||||
if (!sendMessageAndDiscardReply(PTYPE_START_STREAM_A,
|
if (!sendMessageAndDiscardReply(packetTypes[IDX_START_A],
|
||||||
PPAYLEN_START_STREAM_A,
|
payloadLengths[IDX_START_A],
|
||||||
PPAYLOAD_START_STREAM_A)) {
|
preconstructedPayloads[IDX_START_A])) {
|
||||||
return LastSocketError();
|
return LastSocketError();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send START B
|
// Send START B
|
||||||
if (!sendMessageAndDiscardReply(PTYPE_START_STREAM_B,
|
if (!sendMessageAndDiscardReply(packetTypes[IDX_START_B],
|
||||||
PPAYLEN_START_STREAM_B,
|
payloadLengths[IDX_START_B],
|
||||||
PPAYLOAD_START_STREAM_B)) {
|
preconstructedPayloads[IDX_START_B])) {
|
||||||
return LastSocketError();
|
return LastSocketError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,11 +6,10 @@
|
|||||||
#include "PlatformThreads.h"
|
#include "PlatformThreads.h"
|
||||||
#include "Video.h"
|
#include "Video.h"
|
||||||
|
|
||||||
/* GFE 2.2.2+ RTSP/SDP version code */
|
extern int serverMajorVersion;
|
||||||
#define RTSP_CLIENT_VERSION 11
|
|
||||||
#define RTSP_CLIENT_VERSION_S "11"
|
|
||||||
|
|
||||||
char* getSdpPayloadForStreamConfig(PSTREAM_CONFIGURATION streamConfig, struct in_addr targetAddress, int *length);
|
char* getSdpPayloadForStreamConfig(PSTREAM_CONFIGURATION streamConfig, struct in_addr targetAddress,
|
||||||
|
int rtspClientVersion, int *length);
|
||||||
|
|
||||||
int initializeControlStream(IP_ADDRESS host, PSTREAM_CONFIGURATION streamConfig, PCONNECTION_LISTENER_CALLBACKS clCallbacks);
|
int initializeControlStream(IP_ADDRESS host, PSTREAM_CONFIGURATION streamConfig, PCONNECTION_LISTENER_CALLBACKS clCallbacks);
|
||||||
int startControlStream(void);
|
int startControlStream(void);
|
||||||
|
@ -103,7 +103,7 @@ typedef struct _PLATFORM_CALLBACKS {
|
|||||||
|
|
||||||
int LiStartConnection(IP_ADDRESS host, PSTREAM_CONFIGURATION streamConfig, PCONNECTION_LISTENER_CALLBACKS clCallbacks,
|
int LiStartConnection(IP_ADDRESS host, PSTREAM_CONFIGURATION streamConfig, PCONNECTION_LISTENER_CALLBACKS clCallbacks,
|
||||||
PDECODER_RENDERER_CALLBACKS drCallbacks, PAUDIO_RENDERER_CALLBACKS arCallbacks, PPLATFORM_CALLBACKS plCallbacks,
|
PDECODER_RENDERER_CALLBACKS drCallbacks, PAUDIO_RENDERER_CALLBACKS arCallbacks, PPLATFORM_CALLBACKS plCallbacks,
|
||||||
void* renderContext, int drFlags);
|
void* renderContext, int drFlags, int _serverMajorVersion);
|
||||||
void LiStopConnection(void);
|
void LiStopConnection(void);
|
||||||
const char* LiGetStageName(int stage);
|
const char* LiGetStageName(int stage);
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ static char rtspTargetUrl[256];
|
|||||||
static char sessionIdString[16];
|
static char sessionIdString[16];
|
||||||
static int hasSessionId;
|
static int hasSessionId;
|
||||||
static char responseBuffer[RTSP_MAX_RESP_SIZE];
|
static char responseBuffer[RTSP_MAX_RESP_SIZE];
|
||||||
|
static int rtspClientVersion;
|
||||||
|
|
||||||
/* Create RTSP Option */
|
/* Create RTSP Option */
|
||||||
static POPTION_ITEM createOptionItem(char* option, char* content)
|
static POPTION_ITEM createOptionItem(char* option, char* content)
|
||||||
@ -60,14 +61,16 @@ static int addOption(PRTSP_MESSAGE msg, char* option, char* content)
|
|||||||
static int initializeRtspRequest(PRTSP_MESSAGE msg, char* command, char* target)
|
static int initializeRtspRequest(PRTSP_MESSAGE msg, char* command, char* target)
|
||||||
{
|
{
|
||||||
char sequenceNumberStr[16];
|
char sequenceNumberStr[16];
|
||||||
|
char clientVersionStr[16];
|
||||||
|
|
||||||
// FIXME: Hacked CSeq attribute due to RTSP parser bug
|
// FIXME: Hacked CSeq attribute due to RTSP parser bug
|
||||||
createRtspRequest(msg, NULL, 0, command, target, "RTSP/1.0",
|
createRtspRequest(msg, NULL, 0, command, target, "RTSP/1.0",
|
||||||
0, NULL, NULL, 0);
|
0, NULL, NULL, 0);
|
||||||
|
|
||||||
sprintf(sequenceNumberStr, "%d", currentSeqNumber++);
|
sprintf(sequenceNumberStr, "%d", currentSeqNumber++);
|
||||||
|
sprintf(clientVersionStr, "%d", rtspClientVersion);
|
||||||
if (!addOption(msg, "CSeq", sequenceNumberStr) ||
|
if (!addOption(msg, "CSeq", sequenceNumberStr) ||
|
||||||
!addOption(msg, "X-GS-ClientVersion", RTSP_CLIENT_VERSION_S)) {
|
!addOption(msg, "X-GS-ClientVersion", clientVersionStr)) {
|
||||||
freeMessage(msg);
|
freeMessage(msg);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -247,7 +250,8 @@ static int sendVideoAnnounce(PRTSP_MESSAGE response, PSTREAM_CONFIGURATION strea
|
|||||||
}
|
}
|
||||||
|
|
||||||
memcpy(&sdpAddr, &remoteAddr, sizeof(remoteAddr));
|
memcpy(&sdpAddr, &remoteAddr, sizeof(remoteAddr));
|
||||||
request.payload = getSdpPayloadForStreamConfig(streamConfig, sdpAddr, &payloadLength);
|
request.payload = getSdpPayloadForStreamConfig(streamConfig, sdpAddr,
|
||||||
|
rtspClientVersion, &payloadLength);
|
||||||
if (request.payload == NULL) {
|
if (request.payload == NULL) {
|
||||||
goto FreeMessage;
|
goto FreeMessage;
|
||||||
}
|
}
|
||||||
@ -278,6 +282,13 @@ int performRtspHandshake(IP_ADDRESS addr, PSTREAM_CONFIGURATION streamConfigPtr)
|
|||||||
sprintf(rtspTargetUrl, "rtsp://%s", inet_ntoa(inaddr));
|
sprintf(rtspTargetUrl, "rtsp://%s", inet_ntoa(inaddr));
|
||||||
currentSeqNumber = 1;
|
currentSeqNumber = 1;
|
||||||
hasSessionId = 0;
|
hasSessionId = 0;
|
||||||
|
|
||||||
|
if (serverMajorVersion == 3) {
|
||||||
|
rtspClientVersion = 10;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rtspClientVersion = 11;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
RTSP_MESSAGE response;
|
RTSP_MESSAGE response;
|
||||||
|
@ -88,6 +88,62 @@ static int addAttributeString(PSDP_OPTION *head, char* name, const char* payload
|
|||||||
return addAttributeBinary(head, name, payload, (int)strlen(payload));
|
return addAttributeBinary(head, name, payload, (int)strlen(payload));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int addGen3Options(PSDP_OPTION *head, char* addrStr) {
|
||||||
|
int payloadInt;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
err |= addAttributeString(head, "x-nv-general.serverAddress", addrStr);
|
||||||
|
|
||||||
|
payloadInt = htonl(0x42774141);
|
||||||
|
err |= addAttributeBinary(head,
|
||||||
|
"x-nv-general.featureFlags", &payloadInt, sizeof(payloadInt));
|
||||||
|
|
||||||
|
|
||||||
|
payloadInt = htonl(0x41514141);
|
||||||
|
err |= addAttributeBinary(head,
|
||||||
|
"x-nv-video[0].transferProtocol", &payloadInt, sizeof(payloadInt));
|
||||||
|
err |= addAttributeBinary(head,
|
||||||
|
"x-nv-video[1].transferProtocol", &payloadInt, sizeof(payloadInt));
|
||||||
|
err |= addAttributeBinary(head,
|
||||||
|
"x-nv-video[2].transferProtocol", &payloadInt, sizeof(payloadInt));
|
||||||
|
err |= addAttributeBinary(head,
|
||||||
|
"x-nv-video[3].transferProtocol", &payloadInt, sizeof(payloadInt));
|
||||||
|
|
||||||
|
payloadInt = htonl(0x42414141);
|
||||||
|
err |= addAttributeBinary(head,
|
||||||
|
"x-nv-video[0].rateControlMode", &payloadInt, sizeof(payloadInt));
|
||||||
|
payloadInt = htonl(0x42514141);
|
||||||
|
err |= addAttributeBinary(head,
|
||||||
|
"x-nv-video[1].rateControlMode", &payloadInt, sizeof(payloadInt));
|
||||||
|
err |= addAttributeBinary(head,
|
||||||
|
"x-nv-video[2].rateControlMode", &payloadInt, sizeof(payloadInt));
|
||||||
|
err |= addAttributeBinary(head,
|
||||||
|
"x-nv-video[3].rateControlMode", &payloadInt, sizeof(payloadInt));
|
||||||
|
|
||||||
|
err |= addAttributeString(head, "x-nv-vqos[0].bw.flags", "14083");
|
||||||
|
|
||||||
|
err |= addAttributeString(head, "x-nv-vqos[0].videoQosMaxConsecutiveDrops", "0");
|
||||||
|
err |= addAttributeString(head, "x-nv-vqos[1].videoQosMaxConsecutiveDrops", "0");
|
||||||
|
err |= addAttributeString(head, "x-nv-vqos[2].videoQosMaxConsecutiveDrops", "0");
|
||||||
|
err |= addAttributeString(head, "x-nv-vqos[3].videoQosMaxConsecutiveDrops", "0");
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int addGen4Options(PSDP_OPTION *head, char* addrStr) {
|
||||||
|
char payloadStr[92];
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
sprintf(payloadStr, "rtsp://%s:48010", addrStr);
|
||||||
|
err |= addAttributeString(head, "x-nv-general.serverAddress", payloadStr);
|
||||||
|
|
||||||
|
err |= addAttributeString(head, "x-nv-video[0].rateControlMode", "4");
|
||||||
|
|
||||||
|
err |= addAttributeString(head, "x-nv-vqos[0].bw.flags", "51");
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static PSDP_OPTION getAttributesList(PSTREAM_CONFIGURATION streamConfig, struct in_addr targetAddress) {
|
static PSDP_OPTION getAttributesList(PSTREAM_CONFIGURATION streamConfig, struct in_addr targetAddress) {
|
||||||
PSDP_OPTION optionHead;
|
PSDP_OPTION optionHead;
|
||||||
char payloadStr[92];
|
char payloadStr[92];
|
||||||
@ -95,9 +151,6 @@ static PSDP_OPTION getAttributesList(PSTREAM_CONFIGURATION streamConfig, struct
|
|||||||
|
|
||||||
optionHead = NULL;
|
optionHead = NULL;
|
||||||
err = 0;
|
err = 0;
|
||||||
|
|
||||||
sprintf(payloadStr, "rtsp://%s:48010", inet_ntoa(targetAddress));
|
|
||||||
err |= addAttributeString(&optionHead, "x-nv-general.serverAddress", payloadStr);
|
|
||||||
|
|
||||||
sprintf(payloadStr, "%d", streamConfig->width);
|
sprintf(payloadStr, "%d", streamConfig->width);
|
||||||
err |= addAttributeString(&optionHead, "x-nv-video[0].clientViewportWd", payloadStr);
|
err |= addAttributeString(&optionHead, "x-nv-video[0].clientViewportWd", payloadStr);
|
||||||
@ -121,9 +174,6 @@ static PSDP_OPTION getAttributesList(PSTREAM_CONFIGURATION streamConfig, struct
|
|||||||
err |= addAttributeString(&optionHead, "x-nv-video[0].timeoutLengthMs", "7000");
|
err |= addAttributeString(&optionHead, "x-nv-video[0].timeoutLengthMs", "7000");
|
||||||
err |= addAttributeString(&optionHead, "x-nv-video[0].framesWithInvalidRefThreshold", "0");
|
err |= addAttributeString(&optionHead, "x-nv-video[0].framesWithInvalidRefThreshold", "0");
|
||||||
|
|
||||||
// This flags value will mean that resolution won't change as bitrate falls
|
|
||||||
err |= addAttributeString(&optionHead, "x-nv-vqos[0].bw.flags", "51");
|
|
||||||
|
|
||||||
// Lock the bitrate since we're not scaling resolution so the picture doesn't get too bad
|
// 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->height >= 1080 && streamConfig->fps >= 60) {
|
||||||
if (streamConfig->bitrate < 10000) {
|
if (streamConfig->bitrate < 10000) {
|
||||||
@ -167,6 +217,13 @@ static PSDP_OPTION getAttributesList(PSTREAM_CONFIGURATION streamConfig, struct
|
|||||||
// FIXME: Remote optimizations
|
// FIXME: Remote optimizations
|
||||||
err |= addAttributeString(&optionHead, "x-nv-vqos[0].qosTrafficType", "5");
|
err |= addAttributeString(&optionHead, "x-nv-vqos[0].qosTrafficType", "5");
|
||||||
err |= addAttributeString(&optionHead, "x-nv-aqos.qosTrafficType", "4");
|
err |= addAttributeString(&optionHead, "x-nv-aqos.qosTrafficType", "4");
|
||||||
|
|
||||||
|
if (serverMajorVersion == 3) {
|
||||||
|
err |= addGen3Options(&optionHead, inet_ntoa(targetAddress));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
err |= addGen4Options(&optionHead, inet_ntoa(targetAddress));
|
||||||
|
}
|
||||||
|
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
return optionHead;
|
return optionHead;
|
||||||
@ -177,22 +234,24 @@ static PSDP_OPTION getAttributesList(PSTREAM_CONFIGURATION streamConfig, struct
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Populate the SDP header with required information */
|
/* Populate the SDP header with required information */
|
||||||
static int fillSdpHeader(char* buffer, struct in_addr targetAddress) {
|
static int fillSdpHeader(char* buffer, struct in_addr targetAddress, int rtspClientVersion) {
|
||||||
return sprintf(buffer,
|
return sprintf(buffer,
|
||||||
"v=0\r\n"
|
"v=0\r\n"
|
||||||
"o=android 0 "RTSP_CLIENT_VERSION_S" IN IPv4 %s\r\n"
|
"o=android 0 %d IN IPv4 %s\r\n"
|
||||||
"s=NVIDIA Streaming Client\r\n", inet_ntoa(targetAddress));
|
"s=NVIDIA Streaming Client\r\n", rtspClientVersion, inet_ntoa(targetAddress));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Populate the SDP tail with required information */
|
/* Populate the SDP tail with required information */
|
||||||
static int fillSdpTail(char* buffer) {
|
static int fillSdpTail(char* buffer) {
|
||||||
return sprintf(buffer,
|
return sprintf(buffer,
|
||||||
"t=0 0\r\n"
|
"t=0 0\r\n"
|
||||||
"m=video 47998 \r\n");
|
"m=video %d \r\n",
|
||||||
|
serverMajorVersion < 4 ? 47996 : 47998);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the SDP attributes for the stream config */
|
/* Get the SDP attributes for the stream config */
|
||||||
char* getSdpPayloadForStreamConfig(PSTREAM_CONFIGURATION streamConfig, struct in_addr targetAddress, int *length) {
|
char* getSdpPayloadForStreamConfig(PSTREAM_CONFIGURATION streamConfig, struct in_addr targetAddress,
|
||||||
|
int rtspClientVersion, int *length) {
|
||||||
PSDP_OPTION attributeList;
|
PSDP_OPTION attributeList;
|
||||||
int offset;
|
int offset;
|
||||||
char* payload;
|
char* payload;
|
||||||
@ -209,7 +268,7 @@ char* getSdpPayloadForStreamConfig(PSTREAM_CONFIGURATION streamConfig, struct in
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
offset = fillSdpHeader(payload, targetAddress);
|
offset = fillSdpHeader(payload, targetAddress, rtspClientVersion);
|
||||||
offset += fillSerializedAttributeList(&payload[offset], attributeList);
|
offset += fillSerializedAttributeList(&payload[offset], attributeList);
|
||||||
offset += fillSdpTail(&payload[offset]);
|
offset += fillSdpTail(&payload[offset]);
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#define FIRST_FRAME_MAX 1500
|
#define FIRST_FRAME_MAX 1500
|
||||||
|
|
||||||
#define RTP_PORT 47998
|
#define RTP_PORT 47998
|
||||||
|
#define FIRST_FRAME_PORT 47996
|
||||||
|
|
||||||
static DECODER_RENDERER_CALLBACKS callbacks;
|
static DECODER_RENDERER_CALLBACKS callbacks;
|
||||||
static STREAM_CONFIGURATION configuration;
|
static STREAM_CONFIGURATION configuration;
|
||||||
@ -13,6 +14,7 @@ static IP_ADDRESS remoteHost;
|
|||||||
static PCONNECTION_LISTENER_CALLBACKS listenerCallbacks;
|
static PCONNECTION_LISTENER_CALLBACKS listenerCallbacks;
|
||||||
|
|
||||||
static SOCKET rtpSocket = INVALID_SOCKET;
|
static SOCKET rtpSocket = INVALID_SOCKET;
|
||||||
|
static SOCKET firstFrameSocket = INVALID_SOCKET;
|
||||||
|
|
||||||
static PLT_THREAD udpPingThread;
|
static PLT_THREAD udpPingThread;
|
||||||
static PLT_THREAD receiveThread;
|
static PLT_THREAD receiveThread;
|
||||||
@ -108,6 +110,17 @@ static void DecoderThreadProc(void* context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Read the first frame of the video stream */
|
||||||
|
int readFirstFrame(void) {
|
||||||
|
// All that matters is that we close this socket.
|
||||||
|
// This starts the flow of video on Gen 3 servers.
|
||||||
|
|
||||||
|
closesocket(firstFrameSocket);
|
||||||
|
firstFrameSocket = INVALID_SOCKET;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Terminate the video stream */
|
/* Terminate the video stream */
|
||||||
void stopVideoStream(void) {
|
void stopVideoStream(void) {
|
||||||
callbacks.stop();
|
callbacks.stop();
|
||||||
@ -116,6 +129,10 @@ void stopVideoStream(void) {
|
|||||||
PltInterruptThread(&receiveThread);
|
PltInterruptThread(&receiveThread);
|
||||||
PltInterruptThread(&decoderThread);
|
PltInterruptThread(&decoderThread);
|
||||||
|
|
||||||
|
if (firstFrameSocket != INVALID_SOCKET) {
|
||||||
|
closesocket(firstFrameSocket);
|
||||||
|
firstFrameSocket = INVALID_SOCKET;
|
||||||
|
}
|
||||||
if (rtpSocket != INVALID_SOCKET) {
|
if (rtpSocket != INVALID_SOCKET) {
|
||||||
closesocket(rtpSocket);
|
closesocket(rtpSocket);
|
||||||
rtpSocket = INVALID_SOCKET;
|
rtpSocket = INVALID_SOCKET;
|
||||||
@ -156,12 +173,28 @@ int startVideoStream(void* rendererContext, int drFlags) {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (serverMajorVersion == 3) {
|
||||||
|
// Connect this socket to open port 47998 for our ping thread
|
||||||
|
firstFrameSocket = connectTcpSocket(remoteHost, FIRST_FRAME_PORT);
|
||||||
|
if (firstFrameSocket == INVALID_SOCKET) {
|
||||||
|
return LastSocketError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Start pinging before reading the first frame so GFE knows where
|
// Start pinging before reading the first frame so GFE knows where
|
||||||
// to send UDP data
|
// to send UDP data
|
||||||
err = PltCreateThread(UdpPingThreadProc, NULL, &udpPingThread);
|
err = PltCreateThread(UdpPingThreadProc, NULL, &udpPingThread);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (serverMajorVersion == 3) {
|
||||||
|
// Read the first frame to start the flow of video
|
||||||
|
err = readFirstFrame();
|
||||||
|
if (err != 0) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user