Add basic QoS attributes to our A/V sockets

This commit is contained in:
Cameron Gutman 2024-01-31 23:59:23 -06:00
parent 68153174bc
commit c0e3dc64a4
5 changed files with 64 additions and 5 deletions

View File

@ -93,7 +93,7 @@ int notifyAudioPortNegotiationComplete(void) {
// For GFE 3.22 compatibility, we must start the audio ping thread before the RTSP handshake.
// It will not reply to our RTSP PLAY request until the audio ping has been received.
rtpSocket = bindUdpSocket(RemoteAddr.ss_family, &LocalAddr, AddrLen, 0);
rtpSocket = bindUdpSocket(RemoteAddr.ss_family, &LocalAddr, AddrLen, 0, SOCK_QOS_TYPE_AUDIO);
if (rtpSocket == INVALID_SOCKET) {
return LastSocketFail();
}

View File

@ -235,7 +235,56 @@ void closeSocket(SOCKET s) {
#endif
}
SOCKET bindUdpSocket(int addressFamily, struct sockaddr_storage* localAddr, SOCKADDR_LEN addrLen, int bufferSize) {
// These set "safe" host or link-local QoS options that we can unconditionally
// set without having to worry about routers blockholing the traffic.
static void setSocketQos(SOCKET s, int socketQosType) {
#ifdef SO_NET_SERVICE_TYPE
int value;
switch (socketQosType) {
case SOCK_QOS_TYPE_BEST_EFFORT:
value = NET_SERVICE_TYPE_BE;
break;
case SOCK_QOS_TYPE_AUDIO:
value = NET_SERVICE_TYPE_VO;
break;
case SOCK_QOS_TYPE_VIDEO:
value = NET_SERVICE_TYPE_VI;
break;
default:
Limelog("Unknown QoS type: %d\n", socketQosType);
return;
}
// iOS/macOS
if (setsockopt(s, SOL_SOCKET, SO_NET_SERVICE_TYPE, (char*)&value, sizeof(value)) < 0) {
Limelog("setsockopt(SO_NET_SERVICE_TYPE, %d) failed: %d\n", value, (int)LastSocketError());
}
#endif
#ifdef SO_PRIORITY
int value;
switch (socketQosType) {
case SOCK_QOS_TYPE_BEST_EFFORT:
value = 0;
break;
case SOCK_QOS_TYPE_AUDIO:
value = 6;
break;
case SOCK_QOS_TYPE_VIDEO:
value = 5;
break;
default:
Limelog("Unknown QoS type: %d\n", socketQosType);
return;
}
// Linux
if (setsockopt(s, SOL_SOCKET, SO_PRIORITY, (char*)&value, sizeof(value)) < 0) {
Limelog("setsockopt(SO_PRIORITY, %d) failed: %d\n", value, (int)LastSocketError());
}
#endif
}
SOCKET bindUdpSocket(int addressFamily, struct sockaddr_storage* localAddr, SOCKADDR_LEN addrLen, int bufferSize, int socketQosType) {
SOCKET s;
LC_SOCKADDR bindAddr;
int err;
@ -294,6 +343,11 @@ SOCKET bindUdpSocket(int addressFamily, struct sockaddr_storage* localAddr, SOCK
}
#endif
// Enable QOS for the socket (best effort)
if (socketQosType != SOCK_QOS_TYPE_BEST_EFFORT) {
setSocketQos(s, socketQosType);
}
if (bufferSize != 0) {
// We start at the requested recv buffer value and step down until we find
// a value that the OS will accept.

View File

@ -95,10 +95,14 @@ typedef struct sockaddr_in LC_SOCKADDR;
#endif
void addrToUrlSafeString(struct sockaddr_storage* addr, char* string, size_t stringLength);
#define SOCK_QOS_TYPE_BEST_EFFORT 0
#define SOCK_QOS_TYPE_AUDIO 1
#define SOCK_QOS_TYPE_VIDEO 2
SOCKET createSocket(int addressFamily, int socketType, int protocol, bool nonBlocking);
SOCKET connectTcpSocket(struct sockaddr_storage* dstaddr, SOCKADDR_LEN addrlen, unsigned short port, int timeoutSec);
int sendMtuSafe(SOCKET s, char* buffer, int size);
SOCKET bindUdpSocket(int addressFamily, struct sockaddr_storage* localAddr, SOCKADDR_LEN addrLen, int bufferSize);
SOCKET bindUdpSocket(int addressFamily, struct sockaddr_storage* localAddr, SOCKADDR_LEN addrLen, int bufferSize, int socketQosType);
int enableNoDelay(SOCKET s);
int setSocketNonBlocking(SOCKET s, bool enabled);
int recvUdpSocket(SOCKET s, char* buffer, int size, bool useSelect);

View File

@ -73,7 +73,7 @@ int LiFindExternalAddressIP4(const char* stunServer, unsigned short stunPort, un
goto Exit;
}
sock = bindUdpSocket(hints.ai_family, NULL, 0, 0);
sock = bindUdpSocket(hints.ai_family, NULL, 0, 0, SOCK_QOS_TYPE_BEST_EFFORT);
if (sock == INVALID_SOCKET) {
err = LastSocketFail();
Limelog("Failed to connect to STUN server: %d\n", err);

View File

@ -337,7 +337,8 @@ int startVideoStream(void* rendererContext, int drFlags) {
}
rtpSocket = bindUdpSocket(RemoteAddr.ss_family, &LocalAddr, AddrLen,
RTP_RECV_PACKETS_BUFFERED * (StreamConfig.packetSize + MAX_RTP_HEADER_SIZE));
RTP_RECV_PACKETS_BUFFERED * (StreamConfig.packetSize + MAX_RTP_HEADER_SIZE),
SOCK_QOS_TYPE_VIDEO);
if (rtpSocket == INVALID_SOCKET) {
VideoCallbacks.cleanup();
return LastSocketError();