[vlc-commits] [Git][videolan/vlc][master] Add SRT listener mode to SRT input access module

Steve Lhomme (@robUx4) gitlab at videolan.org
Thu Nov 27 10:58:28 UTC 2025



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
0c100530 by Noah Davis at 2025-11-27T10:58:09+00:00
Add SRT listener mode to SRT input access module

- - - - -


4 changed files:

- AUTHORS
- modules/access/srt.c
- modules/access/srt_common.c
- modules/access/srt_common.h


Changes:

=====================================
AUTHORS
=====================================
@@ -819,6 +819,7 @@ Zhao Zhili
 أحمد المحم ودي (Ahmed El-Mahmoudy)
 Баярсайхан Энхтайван
 Сергей Дарьичев
+Noah Davis
 
 Artwork
 -------


=====================================
modules/access/srt.c
=====================================
@@ -99,7 +99,15 @@ static bool srt_schedule_reconnect(stream_t *p_stream)
     char *psz_streamid = var_InheritString( p_stream, SRT_PARAM_STREAMID );
     bool streamid_needs_free = true;
     char *url = NULL;
-    srt_params_t params;
+    srt_params_t params = {
+        .latency = -1,
+        .passphrase = NULL,
+        .key_length = SRT_DEFAULT_KEY_LENGTH,
+        .payload_size = SRT_DEFAULT_PAYLOAD_SIZE,
+        .bandwidth_overhead_limit = SRT_DEFAULT_BANDWIDTH_OVERHEAD_LIMIT,
+        .streamid = NULL,
+        .mode = SRT_DEFAULT_MODE, /* default = caller */
+    };
     struct addrinfo hints = {
         .ai_socktype = SOCK_DGRAM,
     }, *res = NULL;
@@ -107,16 +115,43 @@ static bool srt_schedule_reconnect(stream_t *p_stream)
     stream_sys_t *p_sys = p_stream->p_sys;
     bool failed = false;
 
-    stat = vlc_getaddrinfo( p_sys->psz_host, p_sys->i_port, &hints, &res );
-    if ( stat )
+    /* Parse URL */
+    if (p_stream->psz_url) {
+        url = strdup( p_stream->psz_url );
+        if ( !url ) {
+            failed = true;
+            goto out;
+        }
+
+        if (srt_parse_url( url, &params )) {
+            if (params.latency != -1)
+                i_latency = params.latency;
+            if (params.passphrase != NULL) {
+                free(psz_passphrase);
+                passphrase_needs_free = false;
+                psz_passphrase = (char *) params.passphrase;
+            }
+            if (params.streamid != NULL) {
+                free(psz_streamid);
+                streamid_needs_free = false;
+                psz_streamid = (char *) params.streamid;
+            }
+        }
+    }
+
+    if (params.mode != SRT_MODE_LISTENER)
     {
-        msg_Err( p_stream, "Cannot resolve [%s]:%d (reason: %s)",
-                 p_sys->psz_host,
-                 p_sys->i_port,
-                 gai_strerror( stat ) );
+        stat = vlc_getaddrinfo( p_sys->psz_host, p_sys->i_port, &hints, &res);
+        if ( stat )
+        {
+            msg_Err( p_stream, "Cannot resolve [%s]:%d (reason: %s)",
+                    p_sys->psz_host,
+                    p_sys->i_port,
+                    gai_strerror( stat ) );
 
-        failed = true;
-        goto out;
+            failed = true;
+            goto out;
+        }
     }
 
     /* Always start with a fresh socket */
@@ -125,7 +160,7 @@ static bool srt_schedule_reconnect(stream_t *p_stream)
         srt_epoll_remove_usock( p_sys->i_poll_id, p_sys->sock );
         srt_close( p_sys->sock );
     }
-
+    
     p_sys->sock = srt_create_socket( );
     if ( p_sys->sock == SRT_INVALID_SOCK )
     {
@@ -134,24 +169,6 @@ static bool srt_schedule_reconnect(stream_t *p_stream)
         goto out;
     }
 
-    if (p_stream->psz_url) {
-        url = strdup( p_stream->psz_url );
-        if (srt_parse_url( url, &params )) {
-            if (params.latency != -1)
-                i_latency = params.latency;
-            if (params.passphrase != NULL) {
-                free( psz_passphrase );
-                passphrase_needs_free = false;
-                psz_passphrase = (char *) params.passphrase;
-            }
-            if (params.streamid != NULL ) {
-                free( psz_streamid );
-                streamid_needs_free = false;
-                psz_streamid = (char *) params.streamid;
-            }
-        }
-    }
-
     /* Make SRT non-blocking */
     srt_setsockopt( p_sys->sock, 0, SRTO_SNDSYN,
         &(bool) { false }, sizeof( bool ) );
@@ -187,18 +204,99 @@ static bool srt_schedule_reconnect(stream_t *p_stream)
                 SRTO_STREAMID, psz_streamid, strlen(psz_streamid) );
     }
 
-    srt_epoll_add_usock( p_sys->i_poll_id, p_sys->sock,
-        &(int) { SRT_EPOLL_ERR | SRT_EPOLL_IN });
+    msg_Dbg(p_stream, "SRT mode=%d host='%s' port=%d", params.mode,
+            p_sys->psz_host ? p_sys->psz_host : "(null)", p_sys->i_port);
+
+    if (params.mode == SRT_MODE_CALLER)
+    {
+        /* Schedule a connect */
+        msg_Dbg( p_stream, "Schedule SRT connect (dest address: %s, port: %d).",
+            p_sys->psz_host, p_sys->i_port);
+    
+        stat = srt_connect( p_sys->sock, res->ai_addr, res->ai_addrlen );
+        if (stat == SRT_ERROR) {
+            msg_Err( p_stream, "Failed to connect to server (reason: %s)",
+                    srt_getlasterror_str() );
+            failed = true;
+            goto out;
+        }
+
+        srt_epoll_add_usock( p_sys->i_poll_id, p_sys->sock,
+            &(int) { SRT_EPOLL_ERR | SRT_EPOLL_IN });
+    }
+    else if (params.mode == SRT_MODE_LISTENER)
+    {
+        msg_Dbg(p_stream, "Binding for SRT listener.");
+
+        struct addrinfo hints = {
+            .ai_family   = AF_UNSPEC,
+            .ai_socktype = SOCK_DGRAM,
+            .ai_flags    = AI_PASSIVE
+        }, *res_local = NULL;
+
+        /* Use the specific NIC or NULL for wildcard */
+        char *node = NULL;
+        if (p_sys->psz_host && *p_sys->psz_host)
+            node = p_sys->psz_host;
+        
+        stat = vlc_getaddrinfo(node, p_sys->i_port, &hints, &res_local);
+        if (stat) {
+            msg_Err(p_stream, "Cannot resolve local address (reason: %s)", gai_strerror(stat));
+            failed = true; goto out;
+        }
+
+        /* If binding IPv6 configure the socket */
+        if (res_local->ai_family == AF_INET6) {
+            srt_setsockopt(p_sys->sock, 0, SRTO_IPV6ONLY, &(int) { 0 }, sizeof(int));
+        }
 
-    /* Schedule a connect */
-    msg_Dbg( p_stream, "Schedule SRT connect (dest address: %s, port: %d).",
-        p_sys->psz_host, p_sys->i_port);
+        srt_setsockopt(p_sys->sock, 0, SRTO_REUSEADDR, &(int) { 1 }, sizeof(int));
 
-    stat = srt_connect( p_sys->sock, res->ai_addr, res->ai_addrlen );
-    if (stat == SRT_ERROR) {
-        msg_Err( p_stream, "Failed to connect to server (reason: %s)",
-                srt_getlasterror_str() );
+        stat = srt_bind(p_sys->sock, res_local->ai_addr, res_local->ai_addrlen);
+        if ( stat ) {
+            msg_Err(p_stream, "Failed to bind socket (reason: %s)", srt_getlasterror_str());
+            freeaddrinfo(res_local);
+            failed = true;
+            goto out;
+        }
+
+        freeaddrinfo(res_local);
+
+        stat = srt_listen(p_sys->sock, 1);
+        if ( stat ) {
+            msg_Err(p_stream, "Failed to listen on socket (reason: %s)", srt_getlasterror_str());
+            failed = true;
+            goto out;
+        }
+
+        if (srt_epoll_add_usock(p_sys->i_poll_id, p_sys->sock,
+            &(int) { SRT_EPOLL_ERR | SRT_EPOLL_IN }) < 0) {
+            msg_Err(p_stream, "epoll add failed: %s", srt_getlasterror_str());
+            failed = true;
+            goto out;
+        }
+
+        /* Try to accept a caller (non-blocking). */
+        SRTSOCKET accepted = srt_accept(p_sys->sock, NULL, NULL);
+        if (accepted == SRT_INVALID_SOCK) {
+            int serr;
+            srt_getlasterror(&serr);
+            if (serr != SRT_EASYNCRCV && serr != SRT_EASYNCSND && serr != SRT_ETIMEOUT) {
+                msg_Warn(p_stream, "srt_accept() temporary error: %s", srt_getlasterror_str());
+            }
+        } else {
+            srt_epoll_remove_usock(p_sys->i_poll_id, p_sys->sock);
+            srt_close(p_sys->sock);
+            p_sys->sock = accepted;
+            srt_epoll_add_usock(p_sys->i_poll_id, p_sys->sock,
+                &(int) { SRT_EPOLL_ERR | SRT_EPOLL_IN });
+        }
+    }
+    else
+    {
+        msg_Err(p_stream, "Unknown SRT mode %d", params.mode);
         failed = true;
+        goto out;
     }
 
     /* Reset the number of chunks to allocate as the bitrate of
@@ -218,7 +316,8 @@ out:
         free( psz_passphrase );
     if (streamid_needs_free)
         free( psz_streamid );
-    freeaddrinfo( res );
+    if (res)
+        freeaddrinfo( res );
     free( url );
 
     return !failed;
@@ -252,9 +351,9 @@ static block_t *BlockSRT(stream_t *p_stream, bool *restrict eof)
 
     SRTSOCKET ready[1];
     int readycnt = 1;
-    while ( srt_epoll_wait( p_sys->i_poll_id,
-        ready, &readycnt, 0, 0,
-        i_poll_timeout, NULL, 0, NULL, 0 ) >= 0)
+    while ( (readycnt = 1,
+             srt_epoll_wait(p_sys->i_poll_id, ready, &readycnt,
+                            0, 0, i_poll_timeout, NULL, 0, NULL, 0)) >= 0)
     {
         if ( readycnt < 0  || ready[0] != p_sys->sock )
         {
@@ -265,6 +364,23 @@ static block_t *BlockSRT(stream_t *p_stream, bool *restrict eof)
 
         switch( srt_getsockstate( p_sys->sock ) )
         {
+            case SRTS_LISTENING: {
+                /* Try to accept a caller (non-blocking). */
+                SRTSOCKET accepted = srt_accept(p_sys->sock, NULL, NULL);
+                if (accepted == SRT_INVALID_SOCK) {
+                    int serr; srt_getlasterror(&serr);
+                    /* No pending connection yet: keep waiting. */
+                    continue;
+                }
+                /* Swap listening socket -> connected socket */
+                srt_epoll_remove_usock(p_sys->i_poll_id, p_sys->sock);
+                srt_close(p_sys->sock);
+                p_sys->sock = accepted;
+                srt_epoll_add_usock(p_sys->i_poll_id, p_sys->sock,
+                    &(int){ SRT_EPOLL_ERR | SRT_EPOLL_IN });
+                /* Now loop back; next iteration will see CONNECTED. */
+                continue;
+            }
             case SRTS_CONNECTED:
                 /* Good to go */
                 break;
@@ -373,7 +489,11 @@ static int Open(vlc_object_t *p_this)
     }
 
     p_sys->psz_host = vlc_obj_strdup( p_this, parsed_url.psz_host );
-    p_sys->i_port = parsed_url.i_port;
+
+    if ( parsed_url.i_port != 0 )
+        p_sys->i_port = parsed_url.i_port;
+    else
+        p_sys->i_port = SRT_DEFAULT_PORT;
 
     vlc_UrlClean( &parsed_url );
 
@@ -436,7 +556,10 @@ vlc_module_begin ()
             SRT_KEY_LENGTH_TEXT, NULL )
     change_integer_list( srt_key_lengths, srt_key_length_names )
     add_string(SRT_PARAM_STREAMID, "",
-            N_(" SRT Stream ID"), NULL)
+            N_( "SRT Stream ID"), NULL)
+    add_integer( SRT_PARAM_MODE, SRT_DEFAULT_MODE,
+            SRT_MODE_TEXT, NULL )
+    change_integer_list( srt_mode_values, srt_mode_names )
     change_safe()
 
     set_capability("access", 0)


=====================================
modules/access/srt_common.c
=====================================
@@ -106,6 +106,7 @@ bool srt_parse_url(char* url, srt_params_t* params)
     params->payload_size = -1;
     params->bandwidth_overhead_limit = -1;
     params->streamid = NULL;
+    params->mode = SRT_MODE_CALLER;
 
     /* Parse URL parameters */
     query = find( url, '?' );
@@ -147,6 +148,12 @@ bool srt_parse_url(char* url, srt_params_t* params)
                     if (temp >= 0)
                         params->bandwidth_overhead_limit = temp;
 
+                } else if (strcmp (local_params[i].key, SRT_PARAM_MODE) == 0) {
+                    if (strcmp(val, SRT_MODE_LISTENER_TEXT) == 0) {
+                        params->mode = SRT_MODE_LISTENER;
+                    } else {
+                        params->mode = SRT_MODE_CALLER;
+                    }
                 }
             }
         }


=====================================
modules/access/srt_common.h
=====================================
@@ -40,6 +40,16 @@
 #define SRT_PARAM_POLL_TIMEOUT                "poll-timeout"
 #define SRT_PARAM_KEY_LENGTH                  "key-length"
 #define SRT_PARAM_STREAMID                    "streamid"
+#define SRT_PARAM_MODE                        "mode"
+
+/* SRT modes */
+#define SRT_MODE_CALLER_TEXT        "caller"
+#define SRT_MODE_LISTENER_TEXT      "listener"
+
+typedef enum srt_mode {
+    SRT_MODE_CALLER,
+    SRT_MODE_LISTENER,
+} srt_mode_t;
 
 
 #define SRT_DEFAULT_BANDWIDTH_OVERHEAD_LIMIT 25
@@ -62,6 +72,13 @@
 static const int srt_key_lengths[] = { 16, 24, 32, };
 static const char * const srt_key_length_names[] = { N_( "16 bytes" ), N_(
         "24 bytes" ), N_( "32 bytes" ), };
+/* SRT modes */
+#define SRT_MODE_TEXT N_( "SRT mode" )
+#define SRT_DEFAULT_MODE SRT_MODE_CALLER
+static const char * const srt_mode_names[] = { SRT_MODE_CALLER_TEXT,
+        SRT_MODE_LISTENER_TEXT, };
+static const int srt_mode_values[] = { SRT_MODE_CALLER,
+        SRT_MODE_LISTENER, };
 
 typedef struct srt_params {
     int latency;
@@ -70,6 +87,7 @@ typedef struct srt_params {
     int payload_size;
     int bandwidth_overhead_limit;
     const char* streamid;
+    srt_mode_t mode;
 } srt_params_t;
 
 bool srt_parse_url(char* url, srt_params_t* params);



View it on GitLab: https://code.videolan.org/videolan/vlc/-/commit/0c100530542ccbaee72180bc380a31eccd3bda54

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/commit/0c100530542ccbaee72180bc380a31eccd3bda54
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list