title: gstreamer: multiple RTSP clients connecting at the same time makes the video stream crash
body: <p><strong>Quick summary</strong></p>
  <p>video stream crashes if multiple clients connect at the same time due to the clients (all but 1) that skip the media-configure callback trying to change the bitrate by accessing a not yet configured pipeline. I'm asking how to wait with calling <code>change_bitrate</code> as long as the <code>configure-media</code> callback hasn't yet finished.</p>
  <p><strong>Detailed overview</strong></p>
  <p>I'm developing a door phone application that shows video footage of a user (that just rang the door) over the RTSP protocol on one or multiple screens (called <strong>clients</strong> from now on) in e.g. an appartment building.</p>
  <p>When the application is running, it will not create a pipeline before the first client has connected. A new client callback is created in the following way:</p>
  <pre><code>    /* Configure Callbacks */
      /* Create new client handler (Called on new client connect) */
      LOG_debug(&quot;Creating 'client-connected' signal handler&quot;);
      g_signal_connect(info.server, &quot;client-connected&quot;, G_CALLBACK(new_client_handler), &amp;info);
  
  </code></pre>
  <p>Which calls this function as soon as a client has connected:</p>
  <pre><code>/**
   * new_client_handler
   * Called by rtsp server on a new client connection
   */
  static void new_client_handler(GstRTSPServer *server, GstRTSPClient *client, struct stream_info *si)
  {
      DEBUG_ENTER;
  
      /* Used to initiate the media-configure callback */
      static gboolean first_run = TRUE;
  
      GstRTSPConnection *connection = gst_rtsp_client_get_connection(client);
      if (connection == NULL)
      {
          LOG_err(&quot;Could not get RTSP connection&quot;);
          DEBUG_EXIT;
          return;
      }
  
      GstRTSPUrl *url = gst_rtsp_connection_get_url(connection);
      if (url == NULL)
      {
          LOG_err(&quot;Could not get RTSP connection URL&quot;);
          DEBUG_EXIT;
          return;
      }
  
  
      si-&gt;num_cli++;
  
      gchar* uri = gst_rtsp_url_get_request_uri(url);
      LOG_info(&quot;[%d]A new client %s has connected&quot;, si-&gt;num_cli, uri);
      g_free(uri);
  
      si-&gt;connected = TRUE;
  
      /* Create media-configure handler */
      /*relevant part for question*/
      if (si-&gt;num_cli == 1)
      { /* Initial Setup */
  
          /**
           * Stream info is required, which is only
           * available on the first connection. Stream info is created
           * upon the first connection and is never destroyed after that.
           */
          if (first_run == TRUE)
          {
              LOG_debug(&quot;Creating 'media-configure' signal handler&quot;);
              g_signal_connect(si-&gt;factory, &quot;media-configure&quot;, G_CALLBACK(media_configure_handler),
                      si);
          }
      }
      else
      {
          change_bitrate(si); //This makes video stream crash if 'media_configure_handler' isn't yet finished
      }
  
      /* Create new client_close_handler */
      LOG_debug(&quot;Creating 'closed' signal handler&quot;);
      g_signal_connect(client, &quot;closed&quot;, G_CALLBACK(client_close_handler), si);
  
      first_run = FALSE;
      DEBUG_EXIT;
  }
  
  </code></pre>
  <p>When a client is the first one to connect, it sets up the <code>media-configure</code> callback to initialize the pipeline. The configuration code looks like this:</p>
  <pre><code>**
   * media_configure_handler
   * Setup pipeline when the stream is first configured
   */
  static void media_configure_handler(GstRTSPMediaFactory *factory, GstRTSPMedia *media,
          struct stream_info *si)
  {
      DEBUG_ENTER;
  
      si-&gt;media = media;
  
      LOG_info(&quot;[%d]Configuring pipeline...&quot;, si-&gt;num_cli);
  
      si-&gt;pipeline = GST_BIN(gst_rtsp_media_get_element(media)); //Pipeline gets configured here
      setup_elements(si);
  
      if (si-&gt;num_cli == 1)
      {
          /* Create Msg Event Handler */
          LOG_debug(&quot;Creating 'periodic message' handler&quot;);
          g_timeout_add(si-&gt;msg_rate * 1000, (GSourceFunc) periodic_msg_handler, si);
      }
      DEBUG_EXIT;
  }
  </code></pre>
  <p>A second (or nth) client that connects skips the media configuration step and instead goes to <code>change_bitrate</code>. Here the bitrate is adjusted based on the amount of connected clients.</p>
  <pre><code>/**
   * change_bitrate
   * handle changing of bitrates
   */
  static void change_bitrate(struct stream_info *si)
  {
      DEBUG_ENTER;
  
      int c = si-&gt;curr_bitrate;
      int step = (si-&gt;max_bitrate - si-&gt;min_bitrate) / si-&gt;steps;
      GstElement *elem = search_pipeline(si-&gt;pipeline, &quot;enc&quot;); //crashes due to an unitialized pipeline
      const gchar *name = g_ascii_strdown(G_OBJECT_TYPE_NAME(elem), -1);
      GstStructure *extra_controls;
  ...
  }
  </code></pre>
  <p>This all works fine if a single client connects first. Later, the connection can handle multiple clients and adjusts the bitrate accordingly.</p>
  <p><strong>The problem arises if the first connection is by multiple clients</strong>:
  In this case, both clients enter an instance of <code>new_client_handler</code>, in which the <strong>first one</strong> will set up the <code>media_configure_handler</code>. The <strong>second connection</strong> tries to <strong>change the bitrate</strong>, but <strong>fails</strong>  because the <strong>pipeline is not yet configured</strong> by the callback.</p>
  <p>How can i make the second (and nth) connection wait until the media configure callback has finished and thus a pipeline is available?</p>