diff --git a/src/Connection.c b/src/Connection.c index 2a37b8e..c7b9385 100644 --- a/src/Connection.c +++ b/src/Connection.c @@ -31,7 +31,7 @@ uint16_t AudioPortNumber; uint16_t VideoPortNumber; SS_PING AudioPingPayload; SS_PING VideoPingPayload; -uint16_t SunshineFeatureFlags; +uint32_t SunshineFeatureFlags; // Connection stages static const char* stageNames[STAGE_MAX] = { diff --git a/src/Limelight-internal.h b/src/Limelight-internal.h index 823ed47..2622220 100644 --- a/src/Limelight-internal.h +++ b/src/Limelight-internal.h @@ -43,7 +43,7 @@ extern SS_PING VideoPingPayload; #define SS_FF_PEN_TOUCH_EVENTS 0x01 #define SS_FF_CONTROLLER_TOUCH_EVENTS 0x02 -extern uint16_t SunshineFeatureFlags; +extern uint32_t SunshineFeatureFlags; #ifndef UINT24_MAX #define UINT24_MAX 0xFFFFFF diff --git a/src/RtspConnection.c b/src/RtspConnection.c index 65fca43..08e5483 100644 --- a/src/RtspConnection.c +++ b/src/RtspConnection.c @@ -707,6 +707,64 @@ static bool parseUrlAddrFromRtspUrlString(const char* rtspUrlString, char* desti return true; } +// SDP attributes are in the form: +// a=x-nv-bwe.bwuSafeZoneLowLimit:70\r\n +bool parseSdpAttributeToUInt(const char* payload, const char* name, unsigned int* val) { + // Find the entry for the specified attribute name + char* attribute = strstr(payload, name); + if (!attribute) { + return false; + } + + // Locate the start of the value + char* valst = strstr(attribute, ":"); + if (!valst) { + return false; + } + + // Locate the end of the value + char* valend; + if (!(valend = strstr(valst, "\r")) && !(valend = strstr(valst, "\n"))) { + return false; + } + + // Swap the end character for a null terminator, read the integer, then swap it back + char valendchar = *valend; + *valend = 0; + *val = strtoul(valst + 1, NULL, 0); + *valend = valendchar; + + return true; +} + +bool parseSdpAttributeToInt(const char* payload, const char* name, int* val) { + // Find the entry for the specified attribute name + char* attribute = strstr(payload, name); + if (!attribute) { + return false; + } + + // Locate the start of the value + char* valst = strstr(attribute, ":"); + if (!valst) { + return false; + } + + // Locate the end of the value + char* valend; + if (!(valend = strstr(valst, "\r")) && !(valend = strstr(valst, "\n"))) { + return false; + } + + // Swap the end character for a null terminator, read the integer, then swap it back + char valendchar = *valend; + *valend = 0; + *val = strtol(valst + 1, NULL, 0); + *valend = valendchar; + + return true; +} + // Perform RTSP Handshake with the streaming server machine as part of the connection process int performRtspHandshake(PSERVER_INFORMATION serverInfo) { int ret; @@ -881,6 +939,11 @@ int performRtspHandshake(PSERVER_INFORMATION serverInfo) { Limelog("Reference frame invalidation is not supported by this host\n"); } + // Look for the Sunshine feature flags in the SDP attributes + if (!parseSdpAttributeToUInt(response.payload, "x-ss-general.featureFlags", &SunshineFeatureFlags)) { + SunshineFeatureFlags = 0; + } + // Parse the Opus surround parameters out of the RTSP DESCRIBE response. ret = parseOpusConfigurations(&response); if (ret != 0) {