diff --git a/src/Limelight-internal.h b/src/Limelight-internal.h index 10bcb8d..c8b77ab 100644 --- a/src/Limelight-internal.h +++ b/src/Limelight-internal.h @@ -37,6 +37,10 @@ extern int OriginalVideoBitrate; #define UDP_RECV_POLL_TIMEOUT_MS 100 +// At this value, we will request high quality audio unless CAPABILITY_SLOW_OPUS_DECODER +// is set on the audio renderer. +#define HIGH_AUDIO_BITRATE_THRESHOLD 15000 + int serviceEnetHost(ENetHost* client, ENetEvent* event, enet_uint32 timeoutMs); int extractVersionQuadFromString(const char* string, int* quad); int isReferenceFrameInvalidationEnabled(void); diff --git a/src/Limelight.h b/src/Limelight.h index 74bfad9..fdd065b 100644 --- a/src/Limelight.h +++ b/src/Limelight.h @@ -166,6 +166,11 @@ typedef struct _DECODE_UNIT { // supports reference frame invalidation for HEVC/H.265 streams. This flag is only valid on video renderers. #define CAPABILITY_REFERENCE_FRAME_INVALIDATION_HEVC 0x4 +// If set in the audio renderer capabilities field, this flag will cause the RTSP negotiation +// to never request the "high quality" audio preset. If unset, high quality audio will be +// used with video streams above 15 Mbps. +#define CAPABILITY_SLOW_OPUS_DECODER 0x8 + // If set in the video renderer capabilities field, this macro specifies that the renderer // supports slicing to increase decoding performance. The parameter specifies the desired // number of slices per frame. This capability is only valid on video renderers. diff --git a/src/RtspConnection.c b/src/RtspConnection.c index 8451d95..75d9139 100644 --- a/src/RtspConnection.c +++ b/src/RtspConnection.c @@ -430,9 +430,20 @@ static int sendVideoAnnounce(PRTSP_MESSAGE response, int* error) { int performRtspHandshake(void) { int ret; + // HACK: In order to get GFE to respect our request for a lower audio bitrate, we must + // fake our target address so it doesn't match any of the PC's local interfaces. It seems + // that the only way to get it to give you "low quality" stereo audio nowadays is if it + // thinks you are remote (target address != any local address). + if (OriginalVideoBitrate >= HIGH_AUDIO_BITRATE_THRESHOLD && + (AudioCallbacks.capabilities & CAPABILITY_SLOW_OPUS_DECODER) == 0) { + addrToUrlSafeString(&RemoteAddr, urlAddr); + } + else { + strcpy(urlAddr, "0.0.0.0"); + } + // Initialize global state useEnet = (AppVersionQuad[0] >= 5) && (AppVersionQuad[0] <= 7) && (AppVersionQuad[2] < 404); - addrToUrlSafeString(&RemoteAddr, urlAddr); sprintf(rtspTargetUrl, "rtsp%s://%s:48010", useEnet ? "ru" : "", urlAddr); currentSeqNumber = 1; hasSessionId = 0; diff --git a/src/SdpGenerator.c b/src/SdpGenerator.c index 9bb085b..2019585 100644 --- a/src/SdpGenerator.c +++ b/src/SdpGenerator.c @@ -11,8 +11,6 @@ #define CHANNEL_MASK_STEREO 0x3 #define CHANNEL_MASK_51_SURROUND 0xFC -#define HIGH_BITRATE_THRESHOLD 15000 - typedef struct _SDP_OPTION { char name[MAX_OPTION_NAME_LEN + 1]; void* payload; @@ -362,7 +360,8 @@ static PSDP_OPTION getAttributesList(char*urlSafeAddr) { if (AppVersionQuad[0] >= 7) { // Decide to use HQ audio based on the original video bitrate, not the HEVC-adjusted value - if (OriginalVideoBitrate >= HIGH_BITRATE_THRESHOLD && audioChannelCount > 2) { + if (OriginalVideoBitrate >= HIGH_AUDIO_BITRATE_THRESHOLD && audioChannelCount > 2 && + (AudioCallbacks.capabilities & CAPABILITY_SLOW_OPUS_DECODER) == 0) { // Enable high quality mode for surround sound err |= addAttributeString(&optionHead, "x-nv-audio.surround.AudioQuality", "1");