Improve high quality audio support

High quality audio now works on IPv6 and remote connections
This commit is contained in:
Cameron Gutman 2022-11-04 21:44:07 -05:00
commit 50c0a51b10
3 changed files with 84 additions and 15 deletions

View file

@ -399,7 +399,7 @@ int LiStartConnection(PSERVER_INFORMATION serverInfo, PSTREAM_CONFIGURATION stre
Limelog("Starting RTSP handshake...");
ListenerCallbacks.stageStarting(STAGE_RTSP_HANDSHAKE);
err = performRtspHandshake();
err = performRtspHandshake(serverInfo);
if (err != 0) {
Limelog("failed: %d\n", err);
ListenerCallbacks.stageFailed(STAGE_RTSP_HANDSHAKE, err);

View file

@ -91,7 +91,7 @@ void connectionLostPackets(int lastReceivedPacket, int nextReceivedPacket);
int sendInputPacketOnControlStream(unsigned char* data, int length);
bool isControlDataInTransit(void);
int performRtspHandshake(void);
int performRtspHandshake(PSERVER_INFORMATION serverInfo);
void initializeVideoDepacketizer(int pktSize);
void destroyVideoDepacketizer(void);

View file

@ -657,32 +657,101 @@ static int parseOpusConfigurations(PRTSP_MESSAGE response) {
return 0;
}
// Perform RTSP Handshake with the streaming server machine as part of the connection process
int performRtspHandshake(void) {
int ret;
static bool parseUrlAddrFromRtspUrlString(const char* rtspUrlString, char* destination) {
char* rtspUrlScratchBuffer;
char* portSeparator;
char* v6EscapeEndChar;
char* urlPathSeparator;
int prefixLen;
// 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);
// Create a copy that we can modify
rtspUrlScratchBuffer = strdup(rtspUrlString);
if (rtspUrlScratchBuffer == NULL) {
return false;
}
else {
strcpy(urlAddr, "0.0.0.0");
// If we have a v6 address, we want to stop one character after the closing ]
// If we have a v4 address, we want to stop at the port separator
portSeparator = strrchr(rtspUrlScratchBuffer, ':');
v6EscapeEndChar = strchr(rtspUrlScratchBuffer, ']');
// Count the prefix length to skip past the initial rtsp:// or rtspru:// part
for (prefixLen = 2; rtspUrlScratchBuffer[prefixLen - 2] != 0 && (rtspUrlScratchBuffer[prefixLen - 2] != '/' || rtspUrlScratchBuffer[prefixLen - 1] != '/'); prefixLen++);
// If we hit the end of the string prior to parsing the prefix, we cannot proceed
if (rtspUrlScratchBuffer[prefixLen - 2] == 0) {
free(rtspUrlScratchBuffer);
return false;
}
// Look for a slash at the end of the host portion of the URL (may not be present)
urlPathSeparator = strchr(rtspUrlScratchBuffer + prefixLen, '/');
// Check for a v6 address first since they also have colons
if (v6EscapeEndChar) {
// Terminate the string at the next character
*(v6EscapeEndChar + 1) = 0;
}
else if (portSeparator) {
// Terminate the string prior to the port separator
*portSeparator = 0;
}
else if (urlPathSeparator) {
// Terminate the string prior to the path separator
*urlPathSeparator = 0;
}
strcpy(destination, rtspUrlScratchBuffer + prefixLen);
free(rtspUrlScratchBuffer);
return true;
}
// Perform RTSP Handshake with the streaming server machine as part of the connection process
int performRtspHandshake(PSERVER_INFORMATION serverInfo) {
int ret;
LC_ASSERT(RtspPortNumber != 0);
// Initialize global state
useEnet = (AppVersionQuad[0] >= 5) && (AppVersionQuad[0] <= 7) && (AppVersionQuad[2] < 404);
sprintf(rtspTargetUrl, "rtsp%s://%s:%u", useEnet ? "ru" : "", urlAddr, RtspPortNumber);
currentSeqNumber = 1;
hasSessionId = false;
controlStreamId = APP_VERSION_AT_LEAST(7, 1, 431) ? "streamid=control/13/0" : "streamid=control/1/0";
AudioEncryptionEnabled = false;
// 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).
//
// We will enable high quality audio if the following are all true:
// 1. Video bitrate is higher than 15 Mbps (to ensure most bandwidth is reserved for video)
// 2. The audio decoder has not declared that it is slow
// 3. The stream is either local or not surround sound (to prevent MTU issues over the Internet)
LC_ASSERT(StreamConfig.streamingRemotely != STREAM_CFG_AUTO);
if (OriginalVideoBitrate >= HIGH_AUDIO_BITRATE_THRESHOLD &&
(AudioCallbacks.capabilities & CAPABILITY_SLOW_OPUS_DECODER) == 0 &&
(StreamConfig.streamingRemotely != STREAM_CFG_REMOTE || CHANNEL_COUNT_FROM_AUDIO_CONFIGURATION(StreamConfig.audioConfiguration) <= 2)) {
// If we have an RTSP URL string and it was successfully parsed, use that string
if (serverInfo->rtspSessionUrl != NULL && parseUrlAddrFromRtspUrlString(serverInfo->rtspSessionUrl, urlAddr)) {
strcpy(rtspTargetUrl, serverInfo->rtspSessionUrl);
}
else {
// If an RTSP URL string was not provided or failed to parse, we will construct one now as best we can.
//
// NB: If the remote address is not a LAN address, the host will likely not enable high quality
// audio since it only does that for local streaming normally. We can avoid this limitation,
// but only if the caller gave us the RTSP session URL that it received from the host during launch.
addrToUrlSafeString(&RemoteAddr, urlAddr);
sprintf(rtspTargetUrl, "rtsp%s://%s:%u", useEnet ? "ru" : "", urlAddr, RtspPortNumber);
}
}
else {
strcpy(urlAddr, "0.0.0.0");
sprintf(rtspTargetUrl, "rtsp%s://%s:%u", useEnet ? "ru" : "", urlAddr, RtspPortNumber);
}
switch (AppVersionQuad[0]) {
case 3:
rtspClientVersion = 10;