diff --git a/limelight-common/AudioStream.c b/limelight-common/AudioStream.c index 0aca999..2ae39f7 100644 --- a/limelight-common/AudioStream.c +++ b/limelight-common/AudioStream.c @@ -161,12 +161,16 @@ static void ReceiveThreadProc(void* context) { } } - packet->size = (int)recv(rtpSocket, &packet->data[0], MAX_PACKET_SIZE, 0); - if (packet->size <= 0) { - Limelog("Audio Receive: recv() failed: %d\n", (int)LastSocketError()); + packet->size = recvUdpSocket(rtpSocket, &packet->data[0], MAX_PACKET_SIZE); + if (packet->size < 0) { + Limelog("Audio Receive: recvUdpSocket() failed: %d\n", (int)LastSocketError()); ListenerCallbacks.connectionTerminated(LastSocketError()); break; } + else if (packet->size == 0) { + // Receive timed out; try again + continue; + } if (packet->size < sizeof(RTP_PACKET)) { // Runt packet @@ -252,11 +256,7 @@ void stopAudioStream(void) { LbqSignalQueueShutdown(&packetQueue); PltInterruptThread(&decoderThread); } - - if (rtpSocket != INVALID_SOCKET) { - shutdownUdpSocket(rtpSocket); - } - + PltJoinThread(&udpPingThread); PltJoinThread(&receiveThread); if ((AudioCallbacks.capabilities & CAPABILITY_DIRECT_SUBMIT) == 0) { diff --git a/limelight-common/PlatformSockets.c b/limelight-common/PlatformSockets.c index 9b13859..1481bf8 100644 --- a/limelight-common/PlatformSockets.c +++ b/limelight-common/PlatformSockets.c @@ -27,23 +27,26 @@ void shutdownTcpSocket(SOCKET s) { shutdown(s, SHUT_RDWR); } -void shutdownUdpSocket(SOCKET s) { - SOCKADDR_LEN len; - struct sockaddr_storage addr; - unsigned char buf[1]; +int recvUdpSocket(SOCKET s, char* buffer, int size) { + fd_set readfds; + int err; + struct timeval tv; - // UDP sockets can't be shutdown(), so we'll indicate - // termination by sending a 0 byte packet to ourselves - - if (getsockname(s, (struct sockaddr*)&addr, &len) < 0) { - Limelog("getsockname() failed: %d\n", (int)LastSocketError()); - return; + FD_ZERO(&readfds); + FD_SET(s, &readfds); + + // Wait up to 500 ms for the socket to be readable + tv.tv_sec = 0; + tv.tv_usec = 500 * 1000; + + err = select((int)(s) + 1, &readfds, NULL, NULL, &tv); + if (err <= 0) { + // Return if an error or timeout occurs + return err; } - if (sendto(s, buf, 0, 0, (struct sockaddr*)&addr, len) < 0) { - Limelog("sendto() failed: %d\n", (int)LastSocketError()); - return; - } + // This won't block since the socket is readable + return (int)recv(s, buffer, size, 0); } void closeSocket(SOCKET s) { diff --git a/limelight-common/PlatformSockets.h b/limelight-common/PlatformSockets.h index 971227f..0124000 100644 --- a/limelight-common/PlatformSockets.h +++ b/limelight-common/PlatformSockets.h @@ -17,6 +17,7 @@ typedef int SOCKADDR_LEN; #else #include #include +#include #include #include #include @@ -43,6 +44,6 @@ void addrToUrlSafeString(struct sockaddr_storage* addr, char* string); SOCKET connectTcpSocket(struct sockaddr_storage* dstaddr, SOCKADDR_LEN addrlen, unsigned short port); SOCKET bindUdpSocket(int addrfamily, int bufferSize); int enableNoDelay(SOCKET s); -void shutdownUdpSocket(SOCKET s); +int recvUdpSocket(SOCKET s, char* buffer, int size); void shutdownTcpSocket(SOCKET s); void closeSocket(SOCKET s); \ No newline at end of file diff --git a/limelight-common/VideoStream.c b/limelight-common/VideoStream.c index a38c103..ffde1ca 100644 --- a/limelight-common/VideoStream.c +++ b/limelight-common/VideoStream.c @@ -80,12 +80,16 @@ static void ReceiveThreadProc(void* context) { } } - err = (int)recv(rtpSocket, buffer, receiveSize, 0); - if (err <= 0) { - Limelog("Video Receive: recv() failed: %d\n", (int)LastSocketError()); + err = recvUdpSocket(rtpSocket, buffer, receiveSize); + if (err < 0) { + Limelog("Video Receive: recvUdpSocket() failed: %d\n", (int)LastSocketError()); ListenerCallbacks.connectionTerminated(LastSocketError()); break; } + else if (err == 0) { + // Receive timed out; try again + continue; + } memcpy(&buffer[receiveSize], &err, sizeof(int)); @@ -161,9 +165,6 @@ void stopVideoStream(void) { if (firstFrameSocket != INVALID_SOCKET) { shutdownTcpSocket(firstFrameSocket); } - if (rtpSocket != INVALID_SOCKET) { - shutdownUdpSocket(rtpSocket); - } PltJoinThread(&udpPingThread); PltJoinThread(&receiveThread);