mirror of
https://github.com/moonlight-stream/moonlight-common-c.git
synced 2025-08-18 01:15:46 +00:00
Merge pull request #14 from irtimmer/gen5
Add support for Generation 5 servers (GFE 2.10.2+)
This commit is contained in:
commit
88edbd8dc1
@ -21,7 +21,8 @@ static PLT_THREAD lossStatsThread;
|
|||||||
static PLT_THREAD invalidateRefFramesThread;
|
static PLT_THREAD invalidateRefFramesThread;
|
||||||
static PLT_EVENT invalidateRefFramesEvent;
|
static PLT_EVENT invalidateRefFramesEvent;
|
||||||
static int lossCountSinceLastReport;
|
static int lossCountSinceLastReport;
|
||||||
static long currentFrame;
|
static long lastGoodFrame;
|
||||||
|
static long lastSeenFrame;
|
||||||
static int stopping;
|
static int stopping;
|
||||||
|
|
||||||
static int idrFrameRequired;
|
static int idrFrameRequired;
|
||||||
@ -49,6 +50,13 @@ static const short packetTypesGen4[] = {
|
|||||||
0x060a, // Loss Stats
|
0x060a, // Loss Stats
|
||||||
0x0611, // Frame Stats (unused)
|
0x0611, // Frame Stats (unused)
|
||||||
};
|
};
|
||||||
|
static const short packetTypesGen5[] = {
|
||||||
|
0x0305, // Start A
|
||||||
|
0x0307, // Start B
|
||||||
|
0x0301, // Invalidate reference frames
|
||||||
|
0x0201, // Loss Stats
|
||||||
|
0x0204, // Frame Stats (unused)
|
||||||
|
};
|
||||||
|
|
||||||
static const char startAGen3[] = { 0 };
|
static const char startAGen3[] = { 0 };
|
||||||
static const int startBGen3[] = { 0, 0, 0, 0xa };
|
static const int startBGen3[] = { 0, 0, 0, 0xa };
|
||||||
@ -56,6 +64,9 @@ static const int startBGen3[] = { 0, 0, 0, 0xa };
|
|||||||
static const char requestIdrFrameGen4[] = { 0, 0 };
|
static const char requestIdrFrameGen4[] = { 0, 0 };
|
||||||
static const char startBGen4[] = { 0 };
|
static const char startBGen4[] = { 0 };
|
||||||
|
|
||||||
|
static const char startAGen5[] = { 0, 0 };
|
||||||
|
static const char startBGen5[] = { 0 };
|
||||||
|
|
||||||
static const short payloadLengthsGen3[] = {
|
static const short payloadLengthsGen3[] = {
|
||||||
sizeof(startAGen3), // Start A
|
sizeof(startAGen3), // Start A
|
||||||
sizeof(startBGen3), // Start B
|
sizeof(startBGen3), // Start B
|
||||||
@ -70,6 +81,13 @@ static const short payloadLengthsGen4[] = {
|
|||||||
32, // Loss Stats
|
32, // Loss Stats
|
||||||
64, // Frame Stats
|
64, // Frame Stats
|
||||||
};
|
};
|
||||||
|
static const short payloadLengthsGen5[] = {
|
||||||
|
sizeof(startAGen5), // Start A
|
||||||
|
sizeof(startBGen5), // Start B
|
||||||
|
24, // Invalidate reference frames
|
||||||
|
32, // Loss Stats
|
||||||
|
80, // Frame Stats
|
||||||
|
};
|
||||||
|
|
||||||
static const char* preconstructedPayloadsGen3[] = {
|
static const char* preconstructedPayloadsGen3[] = {
|
||||||
startAGen3,
|
startAGen3,
|
||||||
@ -79,6 +97,10 @@ static const char* preconstructedPayloadsGen4[] = {
|
|||||||
requestIdrFrameGen4,
|
requestIdrFrameGen4,
|
||||||
startBGen4
|
startBGen4
|
||||||
};
|
};
|
||||||
|
static const char* preconstructedPayloadsGen5[] = {
|
||||||
|
startAGen5,
|
||||||
|
startBGen5
|
||||||
|
};
|
||||||
|
|
||||||
static short* packetTypes;
|
static short* packetTypes;
|
||||||
static short* payloadLengths;
|
static short* payloadLengths;
|
||||||
@ -97,14 +119,20 @@ int initializeControlStream(void) {
|
|||||||
payloadLengths = (short*)payloadLengthsGen3;
|
payloadLengths = (short*)payloadLengthsGen3;
|
||||||
preconstructedPayloads = (char**)preconstructedPayloadsGen3;
|
preconstructedPayloads = (char**)preconstructedPayloadsGen3;
|
||||||
}
|
}
|
||||||
else {
|
else if (ServerMajorVersion == 4) {
|
||||||
packetTypes = (short*)packetTypesGen4;
|
packetTypes = (short*)packetTypesGen4;
|
||||||
payloadLengths = (short*)payloadLengthsGen4;
|
payloadLengths = (short*)payloadLengthsGen4;
|
||||||
preconstructedPayloads = (char**)preconstructedPayloadsGen4;
|
preconstructedPayloads = (char**)preconstructedPayloadsGen4;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
packetTypes = (short*)packetTypesGen5;
|
||||||
|
payloadLengths = (short*)payloadLengthsGen5;
|
||||||
|
preconstructedPayloads = (char**)preconstructedPayloadsGen5;
|
||||||
|
}
|
||||||
|
|
||||||
idrFrameRequired = 0;
|
idrFrameRequired = 0;
|
||||||
currentFrame = 0;
|
lastGoodFrame = 0;
|
||||||
|
lastSeenFrame = 0;
|
||||||
lossCountSinceLastReport = 0;
|
lossCountSinceLastReport = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -173,8 +201,12 @@ void connectionDetectedFrameLoss(int startFrame, int endFrame) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// When we receive a frame, update the number of our current frame
|
// When we receive a frame, update the number of our current frame
|
||||||
void connectionReceivedFrame(int frameIndex) {
|
void connectionReceivedCompleteFrame(int frameIndex) {
|
||||||
currentFrame = frameIndex;
|
lastGoodFrame = frameIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void connectionSawFrame(int frameIndex) {
|
||||||
|
lastSeenFrame = frameIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
// When we lose packets, update our packet loss count
|
// When we lose packets, update our packet loss count
|
||||||
@ -270,7 +302,7 @@ static void lossStatsThreadFunc(void* context) {
|
|||||||
BbPutInt(&byteBuffer, lossCountSinceLastReport);
|
BbPutInt(&byteBuffer, lossCountSinceLastReport);
|
||||||
BbPutInt(&byteBuffer, LOSS_REPORT_INTERVAL_MS);
|
BbPutInt(&byteBuffer, LOSS_REPORT_INTERVAL_MS);
|
||||||
BbPutInt(&byteBuffer, 1000);
|
BbPutInt(&byteBuffer, 1000);
|
||||||
BbPutLong(&byteBuffer, currentFrame);
|
BbPutLong(&byteBuffer, lastGoodFrame);
|
||||||
BbPutInt(&byteBuffer, 0);
|
BbPutInt(&byteBuffer, 0);
|
||||||
BbPutInt(&byteBuffer, 0);
|
BbPutInt(&byteBuffer, 0);
|
||||||
BbPutInt(&byteBuffer, 0x14);
|
BbPutInt(&byteBuffer, 0x14);
|
||||||
@ -297,10 +329,17 @@ static void lossStatsThreadFunc(void* context) {
|
|||||||
static void requestIdrFrame(void) {
|
static void requestIdrFrame(void) {
|
||||||
long long payload[3];
|
long long payload[3];
|
||||||
|
|
||||||
if (ServerMajorVersion == 3) {
|
if (ServerMajorVersion != 4) {
|
||||||
// Form the payload
|
// Form the payload
|
||||||
payload[0] = 0;
|
if (lastSeenFrame < 0x20) {
|
||||||
payload[1] = 0xFFFFF;
|
payload[0] = 0;
|
||||||
|
payload[1] = 0x20;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
payload[0] = lastSeenFrame - 0x20;
|
||||||
|
payload[1] = lastSeenFrame;
|
||||||
|
}
|
||||||
|
|
||||||
payload[2] = 0;
|
payload[2] = 0;
|
||||||
|
|
||||||
// Send the reference frame invalidation request and read the response
|
// Send the reference frame invalidation request and read the response
|
||||||
@ -454,4 +493,4 @@ int startControlStream(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -326,7 +326,11 @@ int LiSendMouseMoveEvent(short deltaX, short deltaY) {
|
|||||||
|
|
||||||
holder->packetLength = sizeof(NV_MOUSE_MOVE_PACKET);
|
holder->packetLength = sizeof(NV_MOUSE_MOVE_PACKET);
|
||||||
holder->packet.mouseMove.header.packetType = htonl(PACKET_TYPE_MOUSE_MOVE);
|
holder->packet.mouseMove.header.packetType = htonl(PACKET_TYPE_MOUSE_MOVE);
|
||||||
holder->packet.mouseMove.magic = htonl(MOUSE_MOVE_MAGIC);
|
holder->packet.mouseMove.magic = (MOUSE_MOVE_MAGIC);
|
||||||
|
// On Gen 5 servers, the header code is incremented by one
|
||||||
|
if (ServerMajorVersion >= 5) {
|
||||||
|
holder->packet.mouseMove.magic += 0x01000000;
|
||||||
|
}
|
||||||
holder->packet.mouseMove.deltaX = htons(deltaX);
|
holder->packet.mouseMove.deltaX = htons(deltaX);
|
||||||
holder->packet.mouseMove.deltaY = htons(deltaY);
|
holder->packet.mouseMove.deltaY = htons(deltaY);
|
||||||
|
|
||||||
@ -355,6 +359,9 @@ int LiSendMouseButtonEvent(char action, int button) {
|
|||||||
holder->packetLength = sizeof(NV_MOUSE_BUTTON_PACKET);
|
holder->packetLength = sizeof(NV_MOUSE_BUTTON_PACKET);
|
||||||
holder->packet.mouseButton.header.packetType = htonl(PACKET_TYPE_MOUSE_BUTTON);
|
holder->packet.mouseButton.header.packetType = htonl(PACKET_TYPE_MOUSE_BUTTON);
|
||||||
holder->packet.mouseButton.action = action;
|
holder->packet.mouseButton.action = action;
|
||||||
|
if (ServerMajorVersion >= 5) {
|
||||||
|
holder->packet.mouseButton.action++;
|
||||||
|
}
|
||||||
holder->packet.mouseButton.button = htonl(button);
|
holder->packet.mouseButton.button = htonl(button);
|
||||||
|
|
||||||
err = LbqOfferQueueItem(&packetQueue, holder, &holder->entry);
|
err = LbqOfferQueueItem(&packetQueue, holder, &holder->entry);
|
||||||
@ -432,6 +439,10 @@ static int sendControllerEventInternal(short controllerNumber, short buttonFlags
|
|||||||
holder->packetLength = sizeof(NV_MULTI_CONTROLLER_PACKET);
|
holder->packetLength = sizeof(NV_MULTI_CONTROLLER_PACKET);
|
||||||
holder->packet.multiController.header.packetType = htonl(PACKET_TYPE_MULTI_CONTROLLER);
|
holder->packet.multiController.header.packetType = htonl(PACKET_TYPE_MULTI_CONTROLLER);
|
||||||
holder->packet.multiController.headerA = MC_HEADER_A;
|
holder->packet.multiController.headerA = MC_HEADER_A;
|
||||||
|
// On Gen 5 servers, the header code is decremented by one
|
||||||
|
if (ServerMajorVersion >= 5) {
|
||||||
|
holder->packet.multiController.headerA--;
|
||||||
|
}
|
||||||
holder->packet.multiController.headerB = MC_HEADER_B;
|
holder->packet.multiController.headerB = MC_HEADER_B;
|
||||||
holder->packet.multiController.controllerNumber = controllerNumber;
|
holder->packet.multiController.controllerNumber = controllerNumber;
|
||||||
holder->packet.multiController.midA = MC_ACTIVE_CONTROLLER_FLAGS;
|
holder->packet.multiController.midA = MC_ACTIVE_CONTROLLER_FLAGS;
|
||||||
@ -488,6 +499,10 @@ int LiSendScrollEvent(signed char scrollClicks) {
|
|||||||
holder->packetLength = sizeof(NV_SCROLL_PACKET);
|
holder->packetLength = sizeof(NV_SCROLL_PACKET);
|
||||||
holder->packet.scroll.header.packetType = htonl(PACKET_TYPE_SCROLL);
|
holder->packet.scroll.header.packetType = htonl(PACKET_TYPE_SCROLL);
|
||||||
holder->packet.scroll.magicA = MAGIC_A;
|
holder->packet.scroll.magicA = MAGIC_A;
|
||||||
|
// On Gen 5 servers, the header code is incremented by one
|
||||||
|
if (ServerMajorVersion >= 5) {
|
||||||
|
holder->packet.scroll.magicA++;
|
||||||
|
}
|
||||||
holder->packet.scroll.zero1 = 0;
|
holder->packet.scroll.zero1 = 0;
|
||||||
holder->packet.scroll.zero2 = 0;
|
holder->packet.scroll.zero2 = 0;
|
||||||
holder->packet.scroll.scrollAmt1 = htons(scrollClicks * 120);
|
holder->packet.scroll.scrollAmt1 = htons(scrollClicks * 120);
|
||||||
@ -500,4 +515,4 @@ int LiSendScrollEvent(signed char scrollClicks) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,8 @@ void destroyControlStream(void);
|
|||||||
void requestIdrOnDemand(void);
|
void requestIdrOnDemand(void);
|
||||||
void connectionSinkTooSlow(int startFrame, int endFrame);
|
void connectionSinkTooSlow(int startFrame, int endFrame);
|
||||||
void connectionDetectedFrameLoss(int startFrame, int endFrame);
|
void connectionDetectedFrameLoss(int startFrame, int endFrame);
|
||||||
void connectionReceivedFrame(int frameIndex);
|
void connectionReceivedCompleteFrame(int frameIndex);
|
||||||
|
void connectionSawFrame(int frameIndex);
|
||||||
void connectionLostPackets(int lastReceivedPacket, int nextReceivedPacket);
|
void connectionLostPackets(int lastReceivedPacket, int nextReceivedPacket);
|
||||||
|
|
||||||
int performRtspHandshake(void);
|
int performRtspHandshake(void);
|
||||||
|
@ -299,9 +299,12 @@ int performRtspHandshake(void) {
|
|||||||
if (ServerMajorVersion == 3) {
|
if (ServerMajorVersion == 3) {
|
||||||
rtspClientVersion = 10;
|
rtspClientVersion = 10;
|
||||||
}
|
}
|
||||||
else {
|
else if (ServerMajorVersion == 4) {
|
||||||
rtspClientVersion = 11;
|
rtspClientVersion = 11;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
rtspClientVersion = 12;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
RTSP_MESSAGE response;
|
RTSP_MESSAGE response;
|
||||||
@ -440,4 +443,4 @@ int performRtspHandshake(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -139,8 +139,6 @@ static int addGen4Options(PSDP_OPTION* head, char* addrStr) {
|
|||||||
char payloadStr[92];
|
char payloadStr[92];
|
||||||
int err = 0;
|
int err = 0;
|
||||||
unsigned char slicesPerFrame;
|
unsigned char slicesPerFrame;
|
||||||
int audioChannelCount;
|
|
||||||
int audioChannelMask;
|
|
||||||
|
|
||||||
sprintf(payloadStr, "rtsp://%s:48010", addrStr);
|
sprintf(payloadStr, "rtsp://%s:48010", addrStr);
|
||||||
err |= addAttributeString(head, "x-nv-general.serverAddress", payloadStr);
|
err |= addAttributeString(head, "x-nv-general.serverAddress", payloadStr);
|
||||||
@ -156,32 +154,25 @@ static int addGen4Options(PSDP_OPTION* head, char* addrStr) {
|
|||||||
sprintf(payloadStr, "%d", slicesPerFrame);
|
sprintf(payloadStr, "%d", slicesPerFrame);
|
||||||
err |= addAttributeString(head, "x-nv-video[0].videoEncoderSlicesPerFrame", payloadStr);
|
err |= addAttributeString(head, "x-nv-video[0].videoEncoderSlicesPerFrame", payloadStr);
|
||||||
|
|
||||||
if (StreamConfig.audioConfiguration == AUDIO_CONFIGURATION_51_SURROUND) {
|
return err;
|
||||||
audioChannelCount = CHANNEL_COUNT_51_SURROUND;
|
}
|
||||||
audioChannelMask = CHANNEL_MASK_51_SURROUND;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
audioChannelCount = CHANNEL_COUNT_STEREO;
|
|
||||||
audioChannelMask = CHANNEL_MASK_STEREO;
|
|
||||||
}
|
|
||||||
|
|
||||||
sprintf(payloadStr, "%d", audioChannelCount);
|
static int addGen5Options(PSDP_OPTION* head) {
|
||||||
err |= addAttributeString(head, "x-nv-audio.surround.numChannels", payloadStr);
|
int err = 0;
|
||||||
sprintf(payloadStr, "%d", audioChannelMask);
|
|
||||||
err |= addAttributeString(head, "x-nv-audio.surround.channelMask", payloadStr);
|
|
||||||
if (audioChannelCount > 2) {
|
|
||||||
err |= addAttributeString(head, "x-nv-audio.surround.enable", "1");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
err |= addAttributeString(head, "x-nv-audio.surround.enable", "0");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// We want to use the legacy TCP connections for control and input rather than the new UDP stuff
|
||||||
|
err |= addAttributeString(head, "x-nv-general.useReliableUdp", "0");
|
||||||
|
err |= addAttributeString(head, "x-nv-ri.useControlChannel", "0");
|
||||||
|
err |= addAttributeString(head, "x-nv-vqos[0].enableQec", "0");
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PSDP_OPTION getAttributesList(char*urlSafeAddr) {
|
static PSDP_OPTION getAttributesList(char*urlSafeAddr) {
|
||||||
PSDP_OPTION optionHead;
|
PSDP_OPTION optionHead;
|
||||||
char payloadStr[92];
|
char payloadStr[92];
|
||||||
|
int audioChannelCount;
|
||||||
|
int audioChannelMask;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
optionHead = NULL;
|
optionHead = NULL;
|
||||||
@ -200,20 +191,26 @@ static PSDP_OPTION getAttributesList(char*urlSafeAddr) {
|
|||||||
|
|
||||||
err |= addAttributeString(&optionHead, "x-nv-video[0].rateControlMode", "4");
|
err |= addAttributeString(&optionHead, "x-nv-video[0].rateControlMode", "4");
|
||||||
|
|
||||||
if (StreamConfig.streamingRemotely) {
|
|
||||||
err |= addAttributeString(&optionHead, "x-nv-video[0].averageBitrate", "4");
|
|
||||||
err |= addAttributeString(&optionHead, "x-nv-video[0].peakBitrate", "4");
|
|
||||||
}
|
|
||||||
|
|
||||||
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");
|
||||||
|
|
||||||
// We don't support dynamic bitrate scaling properly (it tends to bounce between min and max and never
|
|
||||||
// settle on the optimal bitrate if it's somewhere in the middle), so we'll just latch the bitrate
|
|
||||||
// to the requested value.
|
|
||||||
sprintf(payloadStr, "%d", StreamConfig.bitrate);
|
sprintf(payloadStr, "%d", StreamConfig.bitrate);
|
||||||
err |= addAttributeString(&optionHead, "x-nv-vqos[0].bw.minimumBitrate", payloadStr);
|
if (ServerMajorVersion >= 5) {
|
||||||
err |= addAttributeString(&optionHead, "x-nv-vqos[0].bw.maximumBitrate", payloadStr);
|
err |= addAttributeString(&optionHead, "x-nv-vqos[0].bw.minimumBitrateKbps", payloadStr);
|
||||||
|
err |= addAttributeString(&optionHead, "x-nv-vqos[0].bw.maximumBitrateKbps", payloadStr);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (StreamConfig.streamingRemotely) {
|
||||||
|
err |= addAttributeString(&optionHead, "x-nv-video[0].averageBitrate", "4");
|
||||||
|
err |= addAttributeString(&optionHead, "x-nv-video[0].peakBitrate", "4");
|
||||||
|
}
|
||||||
|
// We don't support dynamic bitrate scaling properly (it tends to bounce between min and max and never
|
||||||
|
// settle on the optimal bitrate if it's somewhere in the middle), so we'll just latch the bitrate
|
||||||
|
// to the requested value.
|
||||||
|
|
||||||
|
err |= addAttributeString(&optionHead, "x-nv-vqos[0].bw.minimumBitrate", payloadStr);
|
||||||
|
err |= addAttributeString(&optionHead, "x-nv-vqos[0].bw.maximumBitrate", payloadStr);
|
||||||
|
}
|
||||||
|
|
||||||
// Using FEC turns padding on which makes us have to take the slow path
|
// Using FEC turns padding on which makes us have to take the slow path
|
||||||
// in the depacketizer, not to mention exposing some ambiguous cases with
|
// in the depacketizer, not to mention exposing some ambiguous cases with
|
||||||
@ -235,9 +232,34 @@ static PSDP_OPTION getAttributesList(char*urlSafeAddr) {
|
|||||||
if (ServerMajorVersion == 3) {
|
if (ServerMajorVersion == 3) {
|
||||||
err |= addGen3Options(&optionHead, urlSafeAddr);
|
err |= addGen3Options(&optionHead, urlSafeAddr);
|
||||||
}
|
}
|
||||||
else {
|
else if (ServerMajorVersion == 4) {
|
||||||
err |= addGen4Options(&optionHead, urlSafeAddr);
|
err |= addGen4Options(&optionHead, urlSafeAddr);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
err |= addGen5Options(&optionHead);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ServerMajorVersion >= 4) {
|
||||||
|
if (StreamConfig.audioConfiguration == AUDIO_CONFIGURATION_51_SURROUND) {
|
||||||
|
audioChannelCount = CHANNEL_COUNT_51_SURROUND;
|
||||||
|
audioChannelMask = CHANNEL_MASK_51_SURROUND;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
audioChannelCount = CHANNEL_COUNT_STEREO;
|
||||||
|
audioChannelMask = CHANNEL_MASK_STEREO;
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf(payloadStr, "%d", audioChannelCount);
|
||||||
|
err |= addAttributeString(&optionHead, "x-nv-audio.surround.numChannels", payloadStr);
|
||||||
|
sprintf(payloadStr, "%d", audioChannelMask);
|
||||||
|
err |= addAttributeString(&optionHead, "x-nv-audio.surround.channelMask", payloadStr);
|
||||||
|
if (audioChannelCount > 2) {
|
||||||
|
err |= addAttributeString(&optionHead, "x-nv-audio.surround.enable", "1");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
err |= addAttributeString(&optionHead, "x-nv-audio.surround.enable", "0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
return optionHead;
|
return optionHead;
|
||||||
@ -294,4 +316,4 @@ char* getSdpPayloadForStreamConfig(int rtspClientVersion, int* length) {
|
|||||||
freeAttributeList(attributeList);
|
freeAttributeList(attributeList);
|
||||||
*length = offset;
|
*length = offset;
|
||||||
return payload;
|
return payload;
|
||||||
}
|
}
|
||||||
|
@ -231,7 +231,7 @@ static void reassembleAvcFrame(int frameNumber) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Notify the control connection
|
// Notify the control connection
|
||||||
connectionReceivedFrame(frameNumber);
|
connectionReceivedCompleteFrame(frameNumber);
|
||||||
|
|
||||||
// Clear frame drops
|
// Clear frame drops
|
||||||
consecutiveFrameDrops = 0;
|
consecutiveFrameDrops = 0;
|
||||||
@ -392,6 +392,9 @@ void processRtpPayload(PNV_VIDEO_PACKET videoPacket, int length) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Notify the listener of the latest frame we've seen from the PC
|
||||||
|
connectionSawFrame(frameIndex);
|
||||||
|
|
||||||
// Look for a frame start before receiving a frame end
|
// Look for a frame start before receiving a frame end
|
||||||
if (firstPacket && decodingFrame)
|
if (firstPacket && decodingFrame)
|
||||||
{
|
{
|
||||||
@ -469,6 +472,12 @@ void processRtpPayload(PNV_VIDEO_PACKET videoPacket, int length) {
|
|||||||
}
|
}
|
||||||
lastPacketInStream = streamPacketIndex;
|
lastPacketInStream = streamPacketIndex;
|
||||||
|
|
||||||
|
// If this is the first packet, skip the frame header (if one exists)
|
||||||
|
if (firstPacket && ServerMajorVersion >= 5) {
|
||||||
|
currentPos.offset += 8;
|
||||||
|
currentPos.length -= 8;
|
||||||
|
}
|
||||||
|
|
||||||
if (firstPacket &&
|
if (firstPacket &&
|
||||||
getSpecialSeq(¤tPos, &specialSeq) &&
|
getSpecialSeq(¤tPos, &specialSeq) &&
|
||||||
isSeqFrameStart(&specialSeq) &&
|
isSeqFrameStart(&specialSeq) &&
|
||||||
@ -519,4 +528,4 @@ void queueRtpPacket(PRTP_PACKET rtpPacket, int length) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
processRtpPayload((PNV_VIDEO_PACKET)(((char*)rtpPacket) + dataOffset), length - dataOffset);
|
processRtpPayload((PNV_VIDEO_PACKET)(((char*)rtpPacket) + dataOffset), length - dataOffset);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user