From 66a7db7f2ad4b641465e332ce7a03ddf6a499cad Mon Sep 17 00:00:00 2001 From: tt2468 Date: Sat, 23 Apr 2022 14:21:47 -0700 Subject: [PATCH] obs-outputs: Implement send timeout in librtmp This fixes a bug where the RTMP send thread can deadlock upon the underlying TCP connection being broken. By introducing a send timeout, this allows the thread to unblock and give up, triggering a reconnect as normal. The correct solution to this problem would be to rewrite librtmp with asynchronous IO, but that seems like something unlikely to happen. **Before**: - Start stream in OBS - Use tool (pfSense) to invalidate connection state - OBS bitrate drops to 0 - Output does not respond to stop signals, and hangs for an undefined amount of time (usually multiple minutes) before finally giving up **After**: - Start stream in OBS - Use tool (pfSense) to invalidate connection state - OBS bitrate drops to 0 - Output sits in blocked state for maximum of 8 seconds, then cleans up and triggers the reconnect logic --- plugins/obs-outputs/librtmp/rtmp.c | 19 ++++++++++++++----- plugins/obs-outputs/librtmp/rtmp.h | 3 ++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/plugins/obs-outputs/librtmp/rtmp.c b/plugins/obs-outputs/librtmp/rtmp.c index ba86666af..7310b4b1c 100644 --- a/plugins/obs-outputs/librtmp/rtmp.c +++ b/plugins/obs-outputs/librtmp/rtmp.c @@ -484,7 +484,8 @@ RTMP_Reset(RTMP *r) r->m_fVideoCodecs = 252.0; r->Link.curStreamIdx = 0; r->Link.nStreams = 0; - r->Link.timeout = 30; + r->Link.receiveTimeout = 30; + r->Link.sendTimeout = 6; r->Link.swfAge = 30; } @@ -928,12 +929,20 @@ RTMP_Connect0(RTMP *r, struct sockaddr * service, socklen_t addrlen) /* set timeout */ { - SET_RCVTIMEO(tv, r->Link.timeout); + SET_RCVTIMEO(tvr, r->Link.receiveTimeout); if (setsockopt - (r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv))) + (r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tvr, sizeof(tvr))) { - RTMP_Log(RTMP_LOGERROR, "%s, Setting socket timeout to %ds failed!", - __FUNCTION__, r->Link.timeout); + RTMP_Log(RTMP_LOGERROR, "%s, Setting socket receive timeout to %ds failed!", + __FUNCTION__, r->Link.receiveTimeout); + } + + SET_RCVTIMEO(tvs, r->Link.sendTimeout); + if (setsockopt + (r->m_sb.sb_socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&tvs, sizeof(tvs))) + { + RTMP_Log(RTMP_LOGERROR, "%s, Setting socket send timeout to %ds failed!", + __FUNCTION__, r->Link.sendTimeout); } } diff --git a/plugins/obs-outputs/librtmp/rtmp.h b/plugins/obs-outputs/librtmp/rtmp.h index cc7e8049e..a3ae1a987 100644 --- a/plugins/obs-outputs/librtmp/rtmp.h +++ b/plugins/obs-outputs/librtmp/rtmp.h @@ -328,7 +328,8 @@ extern "C" int swfAge; int protocol; - int timeout; /* connection timeout in seconds */ + int receiveTimeout; /* connection receive timeout in seconds */ + int sendTimeout; /* connection send timeout in seconds */ #define RTMP_PUB_NAME 0x0001 /* send login to server */ #define RTMP_PUB_RESP 0x0002 /* send salted password hash */