mirror of
https://github.com/moonlight-stream/moonlight-common-c.git
synced 2025-08-18 01:15:46 +00:00
Update for GFE 2.2.2+
This commit is contained in:
parent
8671e4e7ae
commit
41d823923b
@ -20,21 +20,21 @@ 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 0x140b
|
#define PTYPE_START_STREAM_A 0x0606
|
||||||
#define PPAYLEN_START_STREAM_A 1
|
#define PPAYLEN_START_STREAM_A 2
|
||||||
static const char PPAYLOAD_START_STREAM_A[1] = { 0 };
|
static const char PPAYLOAD_START_STREAM_A[PPAYLEN_START_STREAM_A] = { 0, 0 };
|
||||||
|
|
||||||
#define PTYPE_START_STREAM_B 0x1410
|
#define PTYPE_START_STREAM_B 0x0609
|
||||||
#define PPAYLEN_START_STREAM_B 16
|
#define PPAYLEN_START_STREAM_B 1
|
||||||
static const int PPAYLOAD_START_STREAM_B[4] = { 0, 0, 0, 0xa }; // FIXME: Little endian
|
static const char PPAYLOAD_START_STREAM_B[PPAYLEN_START_STREAM_B] = { 0 };
|
||||||
|
|
||||||
#define PTYPE_RESYNC 0x1404
|
#define PTYPE_RESYNC 0x0604
|
||||||
#define PPAYLEN_RESYNC 24
|
#define PPAYLEN_RESYNC 24
|
||||||
|
|
||||||
#define PTYPE_LOSS_STATS 0x140c
|
#define PTYPE_LOSS_STATS 0x060a
|
||||||
#define PPAYLEN_LOSS_STATS 32
|
#define PPAYLEN_LOSS_STATS 32
|
||||||
|
|
||||||
#define PTYPE_FRAME_STATS 0x1417
|
#define PTYPE_FRAME_STATS 0x0611
|
||||||
#define PPAYLEN_FRAME_STATS 64
|
#define PPAYLEN_FRAME_STATS 64
|
||||||
|
|
||||||
#define LOSS_REPORT_INTERVAL_MS 50
|
#define LOSS_REPORT_INTERVAL_MS 50
|
||||||
|
@ -6,6 +6,10 @@
|
|||||||
#include "PlatformThreads.h"
|
#include "PlatformThreads.h"
|
||||||
#include "Video.h"
|
#include "Video.h"
|
||||||
|
|
||||||
|
/* GFE 2.2.2+ RTSP/SDP version code */
|
||||||
|
#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 *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);
|
||||||
|
@ -11,10 +11,6 @@ static char sessionIdString[16];
|
|||||||
static int hasSessionId;
|
static int hasSessionId;
|
||||||
static char responseBuffer[RTSP_MAX_RESP_SIZE];
|
static char responseBuffer[RTSP_MAX_RESP_SIZE];
|
||||||
|
|
||||||
/* GFE 2.1.1 */
|
|
||||||
#define RTSP_CLIENT_VERSION 10
|
|
||||||
#define RTSP_CLIENT_VERSION_S "10"
|
|
||||||
|
|
||||||
/* Create RTSP Option */
|
/* Create RTSP Option */
|
||||||
static POPTION_ITEM createOptionItem(char* option, char* content)
|
static POPTION_ITEM createOptionItem(char* option, char* content)
|
||||||
{
|
{
|
||||||
|
@ -5,8 +5,6 @@
|
|||||||
#define MAX_SDP_HEADER_LEN 128
|
#define MAX_SDP_HEADER_LEN 128
|
||||||
#define MAX_SDP_TAIL_LEN 128
|
#define MAX_SDP_TAIL_LEN 128
|
||||||
|
|
||||||
#define RTSP_CLIENT_VERSION_S "10"
|
|
||||||
|
|
||||||
typedef struct _SDP_OPTION {
|
typedef struct _SDP_OPTION {
|
||||||
char name[MAX_OPTION_NAME_LEN+1];
|
char name[MAX_OPTION_NAME_LEN+1];
|
||||||
void* payload;
|
void* payload;
|
||||||
@ -92,19 +90,14 @@ static int addAttributeString(PSDP_OPTION *head, char* name, const char* payload
|
|||||||
|
|
||||||
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;
|
||||||
int payloadInt;
|
char payloadStr[92];
|
||||||
char payloadStr[64];
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
optionHead = NULL;
|
optionHead = NULL;
|
||||||
|
|
||||||
err = 0;
|
err = 0;
|
||||||
err |= addAttributeString(&optionHead, "x-nv-general.serverAddress",
|
|
||||||
inet_ntoa(targetAddress));
|
|
||||||
|
|
||||||
payloadInt = htonl(0x42774141);
|
sprintf(payloadStr, "rtsp://%s:48010", inet_ntoa(targetAddress));
|
||||||
err |= addAttributeBinary(&optionHead,
|
err |= addAttributeString(&optionHead, "x-nv-general.serverAddress", payloadStr);
|
||||||
"x-nv-general.featureFlags", &payloadInt, sizeof(payloadInt));
|
|
||||||
|
|
||||||
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);
|
||||||
@ -117,26 +110,7 @@ static PSDP_OPTION getAttributesList(PSTREAM_CONFIGURATION streamConfig, struct
|
|||||||
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].packetSize", payloadStr);
|
||||||
|
|
||||||
payloadInt = htonl(0x41514141);
|
err |= addAttributeString(&optionHead, "x-nv-video[0].rateControlMode", "4");
|
||||||
err |= addAttributeBinary(&optionHead,
|
|
||||||
"x-nv-video[0].transferProtocol", &payloadInt, sizeof(payloadInt));
|
|
||||||
err |= addAttributeBinary(&optionHead,
|
|
||||||
"x-nv-video[1].transferProtocol", &payloadInt, sizeof(payloadInt));
|
|
||||||
err |= addAttributeBinary(&optionHead,
|
|
||||||
"x-nv-video[2].transferProtocol", &payloadInt, sizeof(payloadInt));
|
|
||||||
err |= addAttributeBinary(&optionHead,
|
|
||||||
"x-nv-video[3].transferProtocol", &payloadInt, sizeof(payloadInt));
|
|
||||||
|
|
||||||
payloadInt = htonl(0x42414141);
|
|
||||||
err |= addAttributeBinary(&optionHead,
|
|
||||||
"x-nv-video[0].rateControlMode", &payloadInt, sizeof(payloadInt));
|
|
||||||
payloadInt = htonl(0x42514141);
|
|
||||||
err |= addAttributeBinary(&optionHead,
|
|
||||||
"x-nv-video[1].rateControlMode", &payloadInt, sizeof(payloadInt));
|
|
||||||
err |= addAttributeBinary(&optionHead,
|
|
||||||
"x-nv-video[2].rateControlMode", &payloadInt, sizeof(payloadInt));
|
|
||||||
err |= addAttributeBinary(&optionHead,
|
|
||||||
"x-nv-video[3].rateControlMode", &payloadInt, sizeof(payloadInt));
|
|
||||||
|
|
||||||
// FIXME: Remote optimizations
|
// FIXME: Remote optimizations
|
||||||
if (streamConfig->bitrate <= 13000) {
|
if (streamConfig->bitrate <= 13000) {
|
||||||
@ -148,7 +122,7 @@ static PSDP_OPTION getAttributesList(PSTREAM_CONFIGURATION streamConfig, struct
|
|||||||
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
|
// This flags value will mean that resolution won't change as bitrate falls
|
||||||
err |= addAttributeString(&optionHead, "x-nv-vqos[0].bw.flags", "14083");
|
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) {
|
||||||
@ -192,13 +166,6 @@ 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-vqos[0].videoQosMaxConsecutiveDrops", "0");
|
|
||||||
err |= addAttributeString(&optionHead, "x-nv-vqos[1].videoQosMaxConsecutiveDrops", "0");
|
|
||||||
err |= addAttributeString(&optionHead, "x-nv-vqos[2].videoQosMaxConsecutiveDrops", "0");
|
|
||||||
err |= addAttributeString(&optionHead, "x-nv-vqos[3].videoQosMaxConsecutiveDrops", "0");
|
|
||||||
|
|
||||||
// FIXME: Remote optimizations
|
|
||||||
err |= addAttributeString(&optionHead, "x-nv-aqos.qosTrafficType", "4");
|
err |= addAttributeString(&optionHead, "x-nv-aqos.qosTrafficType", "4");
|
||||||
|
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
@ -221,7 +188,7 @@ static int fillSdpHeader(char* buffer, struct in_addr targetAddress) {
|
|||||||
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 47996 \r\n");
|
"m=video 47998 \r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the SDP attributes for the stream config */
|
/* Get the SDP attributes for the stream config */
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
#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;
|
||||||
@ -14,7 +13,6 @@ 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;
|
||||||
@ -110,37 +108,6 @@ static void DecoderThreadProc(void* context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read the first frame of the video stream */
|
|
||||||
int readFirstFrame(void) {
|
|
||||||
char* firstFrame;
|
|
||||||
SOCK_RET err;
|
|
||||||
int offset = 0;
|
|
||||||
|
|
||||||
firstFrame = (char*) malloc(FIRST_FRAME_MAX);
|
|
||||||
if (firstFrame == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Limelog("Waiting for first frame\n");
|
|
||||||
for (;;) {
|
|
||||||
err = recv(firstFrameSocket, &firstFrame[offset], FIRST_FRAME_MAX - offset, 0);
|
|
||||||
if (err <= 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += err;
|
|
||||||
}
|
|
||||||
Limelog("Read %d bytes\n", offset);
|
|
||||||
|
|
||||||
// We can just ignore this data for now. It's the act of reading
|
|
||||||
// it that matters. If this changes, we'll need to move this call before
|
|
||||||
// starting the receive thread to avoid state corruption in the depacketizer.
|
|
||||||
|
|
||||||
free(firstFrame);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Terminate the video stream */
|
/* Terminate the video stream */
|
||||||
void stopVideoStream(void) {
|
void stopVideoStream(void) {
|
||||||
callbacks.stop();
|
callbacks.stop();
|
||||||
@ -149,10 +116,6 @@ 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;
|
||||||
@ -193,21 +156,9 @@ int startVideoStream(void* rendererContext, int drFlags) {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the first frame to start the flow of video
|
|
||||||
err = readFirstFrame();
|
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user