Merge branch 'upstream/1.22.7' into tizen_gst_1.22.7
[platform/upstream/gstreamer.git] / subprojects / gst-rtsp-server / gst / rtsp-server / rtsp-client.c
index 5a2085b..382ef2f 100644 (file)
@@ -217,7 +217,6 @@ static GstRTSPStatusCode default_pre_signal_handler (GstRTSPClient * client,
     GstRTSPContext * ctx);
 static gboolean pre_signal_accumulator (GSignalInvocationHint * ihint,
     GValue * return_accu, const GValue * handler_return, gpointer data);
-gboolean gst_rtsp_media_has_completed_sender (GstRTSPMedia * media);
 
 G_DEFINE_TYPE_WITH_PRIVATE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT);
 
@@ -948,6 +947,23 @@ send_generic_response (GstRTSPClient * client, GstRTSPStatusCode code,
 }
 
 static void
+send_generic_error_response (GstRTSPClient * client, GstRTSPStatusCode code,
+    GstRTSPContext * ctx)
+{
+  GstRTSPClientClass *klass = GST_RTSP_CLIENT_GET_CLASS (client);
+  GstRTSPStatusCode adjusted_code = code;
+
+  if (klass->adjust_error_code != NULL) {
+    adjusted_code = klass->adjust_error_code (client, ctx, code);
+    if (adjusted_code != code) {
+      GST_DEBUG ("adjusted response error code from %d to %d", code,
+          adjusted_code);
+    }
+  }
+  send_generic_response (client, adjusted_code, ctx);
+}
+
+static void
 send_option_not_supported_response (GstRTSPClient * client,
     GstRTSPContext * ctx, const gchar * unsupported_options)
 {
@@ -991,6 +1007,7 @@ find_media (GstRTSPClient * client, GstRTSPContext * ctx, gchar * path,
   GstRTSPClientPrivate *priv = client->priv;
   GstRTSPMediaFactory *factory;
   GstRTSPMedia *media;
+  GstRTSPUrl *url;
   gint path_len;
 
   /* find the longest matching factory for the uri first */
@@ -1011,13 +1028,20 @@ find_media (GstRTSPClient * client, GstRTSPContext * ctx, gchar * path,
   else
     path_len = strlen (path);
 
+  url = gst_rtsp_url_copy (ctx->uri);
+  /* normalize rtsp://<IP>:<PORT> to rtsp://<IP>:<PORT>/ */
+  if (url->abspath[0] == 0) {
+    g_free (url->abspath);
+    url->abspath = g_strdup ("/");
+  }
+
   if (!paths_are_equal (priv->path, path, path_len)) {
     /* remove any previously cached values before we try to construct a new
      * media for uri */
     clean_cached_media (client, TRUE);
 
     /* prepare the media and add it to the pipeline */
-    if (!(media = gst_rtsp_media_factory_construct (factory, ctx->uri)))
+    if (!(media = gst_rtsp_media_factory_construct (factory, url)))
       goto no_media;
 
     ctx->media = media;
@@ -1046,6 +1070,7 @@ find_media (GstRTSPClient * client, GstRTSPContext * ctx, gchar * path,
     GST_INFO ("reusing cached media %p for path %s", media, priv->path);
   }
 
+  gst_rtsp_url_free (url);
   g_object_unref (factory);
   ctx->factory = NULL;
 
@@ -1058,7 +1083,7 @@ find_media (GstRTSPClient * client, GstRTSPContext * ctx, gchar * path,
 no_factory:
   {
     GST_ERROR ("client %p: no factory for path %s", client, path);
-    send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
     return NULL;
   }
 no_factory_access:
@@ -1081,7 +1106,8 @@ not_authorized:
 no_media:
   {
     GST_ERROR ("client %p: can't create media", client);
-    send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
+    gst_rtsp_url_free (url);
     g_object_unref (factory);
     ctx->factory = NULL;
     return NULL;
@@ -1089,7 +1115,8 @@ no_media:
 no_thread:
   {
     GST_ERROR ("client %p: can't create thread", client);
-    send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
+    gst_rtsp_url_free (url);
     g_object_unref (media);
     ctx->media = NULL;
     g_object_unref (factory);
@@ -1099,7 +1126,8 @@ no_thread:
 no_prepare:
   {
     GST_ERROR ("client %p: can't prepare media", client);
-    send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
+    gst_rtsp_url_free (url);
     g_object_unref (media);
     ctx->media = NULL;
     g_object_unref (factory);
@@ -1461,7 +1489,7 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx)
   path = klass->make_path_from_uri (client, ctx->uri);
 
   /* get a handle to the configuration of the media in the session */
-  sessmedia = gst_rtsp_session_get_media (session, path, &matched);
+  sessmedia = gst_rtsp_session_dup_media (session, path, &matched);
   if (!sessmedia)
     goto not_found;
 
@@ -1496,6 +1524,7 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx)
   /* unmanage the media in the session, returns false if all media session
    * are torn down. */
   keep_session = gst_rtsp_session_release_media (session, sessmedia);
+  g_object_unref (sessmedia);
 
   /* construct the response now */
   code = GST_RTSP_STS_OK;
@@ -1524,37 +1553,39 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx)
 no_session:
   {
     GST_ERROR ("client %p: no session", client);
-    send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
     return FALSE;
   }
 no_uri:
   {
     GST_ERROR ("client %p: no uri supplied", client);
-    send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
     return FALSE;
   }
 not_found:
   {
     GST_ERROR ("client %p: no media for uri", client);
-    send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
     g_free (path);
     return FALSE;
   }
 no_aggregate:
   {
     GST_ERROR ("client %p: no aggregate path %s", client, path);
-    send_generic_response (client,
+    send_generic_error_response (client,
         GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx);
     g_free (path);
+    g_object_unref (sessmedia);
     return FALSE;
   }
 sig_failed:
   {
     GST_ERROR ("client %p: pre signal returned error: %s", client,
         gst_rtsp_status_as_text (sig_result));
-    send_generic_response (client, sig_result, ctx);
+    send_generic_error_response (client, sig_result, ctx);
     gst_rtsp_media_unlock (media);
     g_object_unref (media);
+    g_object_unref (sessmedia);
     return FALSE;
   }
 }
@@ -1626,13 +1657,13 @@ sig_failed:
   {
     GST_ERROR ("client %p: pre signal returned error: %s", client,
         gst_rtsp_status_as_text (sig_result));
-    send_generic_response (client, sig_result, ctx);
+    send_generic_error_response (client, sig_result, ctx);
     return FALSE;
   }
 bad_request:
   {
     GST_ERROR ("client %p: bad request", client);
-    send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
     return FALSE;
   }
 }
@@ -1678,13 +1709,13 @@ sig_failed:
   {
     GST_ERROR ("client %p: pre signal returned error: %s", client,
         gst_rtsp_status_as_text (sig_result));
-    send_generic_response (client, sig_result, ctx);
+    send_generic_error_response (client, sig_result, ctx);
     return FALSE;
   }
 bad_request:
   {
     GST_ERROR ("client %p: bad request", client);
-    send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
     return FALSE;
   }
 }
@@ -1713,7 +1744,7 @@ handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx)
   path = klass->make_path_from_uri (client, ctx->uri);
 
   /* get a handle to the configuration of the media in the session */
-  sessmedia = gst_rtsp_session_get_media (session, path, &matched);
+  sessmedia = gst_rtsp_session_dup_media (session, path, &matched);
   if (!sessmedia)
     goto not_found;
 
@@ -1760,6 +1791,7 @@ handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx)
 
   /* the state is now READY */
   gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_READY);
+  g_object_unref (sessmedia);
 
   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PAUSE_REQUEST], 0, ctx);
 
@@ -1772,27 +1804,28 @@ handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx)
 no_session:
   {
     GST_ERROR ("client %p: no session", client);
-    send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
     return FALSE;
   }
 no_uri:
   {
     GST_ERROR ("client %p: no uri supplied", client);
-    send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
     return FALSE;
   }
 not_found:
   {
     GST_ERROR ("client %p: no media for uri", client);
-    send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
     g_free (path);
     return FALSE;
   }
 no_aggregate:
   {
     GST_ERROR ("client %p: no aggregate path %s", client, path);
-    send_generic_response (client,
+    send_generic_error_response (client,
         GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx);
+    g_object_unref (sessmedia);
     g_free (path);
     return FALSE;
   }
@@ -1800,25 +1833,28 @@ sig_failed:
   {
     GST_ERROR ("client %p: pre signal returned error: %s", client,
         gst_rtsp_status_as_text (sig_result));
-    send_generic_response (client, sig_result, ctx);
+    send_generic_error_response (client, sig_result, ctx);
     gst_rtsp_media_unlock (media);
+    g_object_unref (sessmedia);
     g_object_unref (media);
     return FALSE;
   }
 invalid_state:
   {
     GST_ERROR ("client %p: not PLAYING or RECORDING", client);
-    send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
-        ctx);
+    send_generic_error_response (client,
+        GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, ctx);
     gst_rtsp_media_unlock (media);
+    g_object_unref (sessmedia);
     g_object_unref (media);
     return FALSE;
   }
 not_supported:
   {
     GST_ERROR ("client %p: pausing not supported", client);
-    send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
     gst_rtsp_media_unlock (media);
+    g_object_unref (sessmedia);
     g_object_unref (media);
     return FALSE;
   }
@@ -2082,7 +2118,7 @@ default_handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx)
   path = klass->make_path_from_uri (client, uri);
 
   /* get a handle to the configuration of the media in the session */
-  sessmedia = gst_rtsp_session_get_media (session, path, &matched);
+  sessmedia = gst_rtsp_session_dup_media (session, path, &matched);
   if (!sessmedia)
     goto not_found;
 
@@ -2152,10 +2188,14 @@ default_handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx)
     /* the scale and speed headers must always be added if they were present in
      * the request. however, even if they were not, we still add them if
      * applied_rate or rate deviate from the "normal", i.e. 1.0 */
+#ifdef TIZEN_PROFILE_TV
+    /* Temporal workaround fix for TV */
+    rate = applied_rate = 1.0;
+#else
     if (!gst_rtsp_media_get_rates (media, &rate, &applied_rate))
       goto get_rates_error;
     g_assert (rate != 0 && applied_rate != 0);
-
+#endif
     if (scale_present || applied_rate != 1.0)
       gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_SCALE,
           g_strdup_printf ("%1.3f", applied_rate));
@@ -2177,6 +2217,7 @@ default_handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx)
   gst_rtsp_session_media_set_state (sessmedia, GST_STATE_PLAYING);
 
   gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_PLAYING);
+  g_object_unref (sessmedia);
 
   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PLAY_REQUEST], 0, ctx);
 
@@ -2189,26 +2230,27 @@ default_handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx)
 no_session:
   {
     GST_ERROR ("client %p: no session", client);
-    send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
     return FALSE;
   }
 no_uri:
   {
     GST_ERROR ("client %p: no uri supplied", client);
-    send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
     return FALSE;
   }
 not_found:
   {
     GST_ERROR ("client %p: media not found", client);
-    send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
     return FALSE;
   }
 no_aggregate:
   {
     GST_ERROR ("client %p: no aggregate path %s", client, path);
-    send_generic_response (client,
+    send_generic_error_response (client,
         GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx);
+    g_object_unref (sessmedia);
     g_free (path);
     return FALSE;
   }
@@ -2216,75 +2258,86 @@ sig_failed:
   {
     GST_ERROR ("client %p: pre signal returned error: %s", client,
         gst_rtsp_status_as_text (sig_result));
-    send_generic_response (client, sig_result, ctx);
+    send_generic_error_response (client, sig_result, ctx);
     gst_rtsp_media_unlock (media);
     g_object_unref (media);
+    g_object_unref (sessmedia);
     return FALSE;
   }
 invalid_state:
   {
     GST_ERROR ("client %p: not PLAYING or READY", client);
-    send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
-        ctx);
+    send_generic_error_response (client,
+        GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, ctx);
     gst_rtsp_media_unlock (media);
     g_object_unref (media);
+    g_object_unref (sessmedia);
     return FALSE;
   }
 pipeline_error:
   {
     GST_ERROR ("client %p: failed to configure the pipeline", client);
-    send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
-        ctx);
+    send_generic_error_response (client,
+        GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, ctx);
     gst_rtsp_media_unlock (media);
     g_object_unref (media);
+    g_object_unref (sessmedia);
     return FALSE;
   }
 unsuspend_failed:
   {
     GST_ERROR ("client %p: unsuspend failed", client);
-    send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
     gst_rtsp_media_unlock (media);
     g_object_unref (media);
+    g_object_unref (sessmedia);
     return FALSE;
   }
 invalid_mode:
   {
     GST_ERROR ("client %p: seek failed", client);
-    send_generic_response (client, code, ctx);
+    send_generic_error_response (client, code, ctx);
     gst_rtsp_media_unlock (media);
     g_object_unref (media);
+    g_object_unref (sessmedia);
     return FALSE;
   }
 unsupported_mode:
   {
     GST_ERROR ("client %p: media does not support PLAY", client);
-    send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx);
     gst_rtsp_media_unlock (media);
     g_object_unref (media);
+    g_object_unref (sessmedia);
     return FALSE;
   }
 get_rates_error:
   {
     GST_ERROR ("client %p: failed obtaining rate and applied_rate", client);
-    send_generic_response (client, GST_RTSP_STS_INTERNAL_SERVER_ERROR, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_INTERNAL_SERVER_ERROR,
+        ctx);
     gst_rtsp_media_unlock (media);
     g_object_unref (media);
+    g_object_unref (sessmedia);
     return FALSE;
   }
 adjust_play_response_failed:
   {
     GST_ERROR ("client %p: failed to adjust play response", client);
-    send_generic_response (client, code, ctx);
+    send_generic_error_response (client, code, ctx);
     gst_rtsp_media_unlock (media);
     g_object_unref (media);
+    g_object_unref (sessmedia);
     return FALSE;
   }
 rtp_info_error:
   {
     GST_ERROR ("client %p: failed to add RTP-Info", client);
-    send_generic_response (client, GST_RTSP_STS_INTERNAL_SERVER_ERROR, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_INTERNAL_SERVER_ERROR,
+        ctx);
     gst_rtsp_media_unlock (media);
     g_object_unref (media);
+    g_object_unref (sessmedia);
     return FALSE;
   }
 }
@@ -2379,7 +2432,7 @@ done:
 parse_failed:
   {
     GST_ERROR_OBJECT (client, "failed to parse blocksize");
-    send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
     return FALSE;
   }
 }
@@ -3072,19 +3125,20 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx)
 no_uri:
   {
     GST_ERROR ("client %p: no uri", client);
-    send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
     return FALSE;
   }
 no_transport:
   {
     GST_ERROR ("client %p: no transport", client);
-    send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT,
+        ctx);
     goto cleanup_path;
   }
 no_pool:
   {
     GST_ERROR ("client %p: no session pool configured", client);
-    send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
     goto cleanup_path;
   }
 media_not_found_no_reply:
@@ -3096,13 +3150,13 @@ media_not_found_no_reply:
 media_not_found:
   {
     GST_ERROR ("client %p: media '%s' not found", client, path);
-    send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
     goto cleanup_session;
   }
 control_not_found:
   {
     GST_ERROR ("client %p: no control in path '%s'", client, path);
-    send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
     gst_rtsp_media_unlock (media);
     g_object_unref (media);
     goto cleanup_session;
@@ -3111,7 +3165,7 @@ stream_not_found:
   {
     GST_ERROR ("client %p: stream '%s' not found", client,
         GST_STR_NULL (control));
-    send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
     gst_rtsp_media_unlock (media);
     g_object_unref (media);
     goto cleanup_session;
@@ -3120,7 +3174,7 @@ sig_failed:
   {
     GST_ERROR ("client %p: pre signal returned error: %s", client,
         gst_rtsp_status_as_text (sig_result));
-    send_generic_response (client, sig_result, ctx);
+    send_generic_error_response (client, sig_result, ctx);
     gst_rtsp_media_unlock (media);
     g_object_unref (media);
     goto cleanup_path;
@@ -3128,7 +3182,7 @@ sig_failed:
 service_unavailable:
   {
     GST_ERROR ("client %p: can't create session", client);
-    send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
     gst_rtsp_media_unlock (media);
     g_object_unref (media);
     goto cleanup_session;
@@ -3136,7 +3190,7 @@ service_unavailable:
 sessmedia_unavailable:
   {
     GST_ERROR ("client %p: can't create session media", client);
-    send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
     goto cleanup_transport;
   }
 configure_media_failed_no_reply:
@@ -3150,13 +3204,15 @@ configure_media_failed_no_reply:
 unsupported_transports:
   {
     GST_ERROR ("client %p: unsupported transports", client);
-    send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT,
+        ctx);
     goto cleanup_transport;
   }
 unsupported_client_transport:
   {
     GST_ERROR ("client %p: unsupported client transport", client);
-    send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT,
+        ctx);
     goto cleanup_transport;
   }
 unsupported_mode:
@@ -3167,20 +3223,22 @@ unsupported_mode:
             GST_RTSP_TRANSPORT_MODE_PLAY),
         ! !(gst_rtsp_media_get_transport_mode (media) &
             GST_RTSP_TRANSPORT_MODE_RECORD), ct->mode_play, ct->mode_record);
-    send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT,
+        ctx);
     goto cleanup_transport;
   }
 unsupported_range_unit:
   {
     GST_ERROR ("Client %p: does not support any range format we support",
         client);
-    send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, ctx);
     goto cleanup_transport;
   }
 keymgmt_error:
   {
     GST_ERROR ("client %p: keymgmt error", client);
-    send_generic_response (client, GST_RTSP_STS_KEY_MANAGEMENT_FAILURE, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_KEY_MANAGEMENT_FAILURE,
+        ctx);
     goto cleanup_transport;
   }
   {
@@ -3349,25 +3407,25 @@ sig_failed:
   {
     GST_ERROR ("client %p: pre signal returned error: %s", client,
         gst_rtsp_status_as_text (sig_result));
-    send_generic_response (client, sig_result, ctx);
+    send_generic_error_response (client, sig_result, ctx);
     return FALSE;
   }
 no_uri:
   {
     GST_ERROR ("client %p: no uri", client);
-    send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
     return FALSE;
   }
 no_mount_points:
   {
     GST_ERROR ("client %p: no mount points configured", client);
-    send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
     return FALSE;
   }
 no_path:
   {
     GST_ERROR ("client %p: can't find path for url", client);
-    send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
     return FALSE;
   }
 no_media:
@@ -3380,7 +3438,7 @@ no_media:
 unsupported_mode:
   {
     GST_ERROR ("client %p: media does not support DESCRIBE", client);
-    send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx);
     g_free (path);
     gst_rtsp_media_unlock (media);
     g_object_unref (media);
@@ -3389,7 +3447,7 @@ unsupported_mode:
 no_sdp:
   {
     GST_ERROR ("client %p: can't create SDP", client);
-    send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
     g_free (path);
     gst_rtsp_media_unlock (media);
     g_object_unref (media);
@@ -3542,38 +3600,38 @@ handle_announce_request (GstRTSPClient * client, GstRTSPContext * ctx)
 no_uri:
   {
     GST_ERROR ("client %p: no uri", client);
-    send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
     return FALSE;
   }
 no_mount_points:
   {
     GST_ERROR ("client %p: no mount points configured", client);
-    send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
     return FALSE;
   }
 no_path:
   {
     GST_ERROR ("client %p: can't find path for url", client);
-    send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
     gst_sdp_message_free (sdp);
     return FALSE;
   }
 wrong_content_type:
   {
     GST_ERROR ("client %p: unknown content type", client);
-    send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
     return FALSE;
   }
 no_message:
   {
     GST_ERROR ("client %p: can't find SDP message", client);
-    send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
     return FALSE;
   }
 sdp_parse_failed:
   {
     GST_ERROR ("client %p: failed to parse SDP message", client);
-    send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
     gst_sdp_message_free (sdp);
     return FALSE;
   }
@@ -3589,7 +3647,7 @@ sig_failed:
   {
     GST_ERROR ("client %p: pre signal returned error: %s", client,
         gst_rtsp_status_as_text (sig_result));
-    send_generic_response (client, sig_result, ctx);
+    send_generic_error_response (client, sig_result, ctx);
     gst_sdp_message_free (sdp);
     gst_rtsp_media_unlock (media);
     g_object_unref (media);
@@ -3598,7 +3656,7 @@ sig_failed:
 unsupported_mode:
   {
     GST_ERROR ("client %p: media does not support ANNOUNCE", client);
-    send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx);
     g_free (path);
     gst_rtsp_media_unlock (media);
     g_object_unref (media);
@@ -3608,7 +3666,8 @@ unsupported_mode:
 unhandled_sdp:
   {
     GST_ERROR ("client %p: can't handle SDP", client);
-    send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_MEDIA_TYPE, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_UNSUPPORTED_MEDIA_TYPE,
+        ctx);
     g_free (path);
     gst_rtsp_media_unlock (media);
     g_object_unref (media);
@@ -3699,25 +3758,25 @@ handle_record_request (GstRTSPClient * client, GstRTSPContext * ctx)
 no_session:
   {
     GST_ERROR ("client %p: no session", client);
-    send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
     return FALSE;
   }
 no_uri:
   {
     GST_ERROR ("client %p: no uri supplied", client);
-    send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
     return FALSE;
   }
 not_found:
   {
     GST_ERROR ("client %p: media not found", client);
-    send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
     return FALSE;
   }
 no_aggregate:
   {
     GST_ERROR ("client %p: no aggregate path %s", client, path);
-    send_generic_response (client,
+    send_generic_error_response (client,
         GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx);
     g_free (path);
     return FALSE;
@@ -3726,33 +3785,33 @@ sig_failed:
   {
     GST_ERROR ("client %p: pre signal returned error: %s", client,
         gst_rtsp_status_as_text (sig_result));
-    send_generic_response (client, sig_result, ctx);
+    send_generic_error_response (client, sig_result, ctx);
     return FALSE;
   }
 unsupported_mode:
   {
     GST_ERROR ("client %p: media does not support RECORD", client);
-    send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx);
     return FALSE;
   }
 invalid_state:
   {
     GST_ERROR ("client %p: not PLAYING or READY", client);
-    send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
-        ctx);
+    send_generic_error_response (client,
+        GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, ctx);
     return FALSE;
   }
 pipeline_error:
   {
     GST_ERROR ("client %p: failed to configure the pipeline", client);
-    send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
-        ctx);
+    send_generic_error_response (client,
+        GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, ctx);
     return FALSE;
   }
 unsuspend_failed:
   {
     GST_ERROR ("client %p: unsuspend failed", client);
-    send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
     return FALSE;
   }
 }
@@ -3803,7 +3862,7 @@ sig_failed:
   {
     GST_ERROR ("client %p: pre signal returned error: %s", client,
         gst_rtsp_status_as_text (sig_result));
-    send_generic_response (client, sig_result, ctx);
+    send_generic_error_response (client, sig_result, ctx);
     gst_rtsp_message_free (ctx->response);
     return FALSE;
   }
@@ -4119,32 +4178,32 @@ done:
 not_supported:
   {
     GST_ERROR ("client %p: version %d not supported", client, version);
-    send_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED,
-        ctx);
+    send_generic_error_response (client,
+        GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED, ctx);
     goto done;
   }
 invalid_command_for_version:
   {
     GST_ERROR ("client %p: invalid command for version", client);
-    send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
     goto done;
   }
 bad_request:
   {
     GST_ERROR ("client %p: bad request", client);
-    send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
     goto done;
   }
 no_pool:
   {
     GST_ERROR ("client %p: no pool configured", client);
-    send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
     goto done;
   }
 session_not_found:
   {
     GST_ERROR ("client %p: session not found", client);
-    send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
     goto done;
   }
 not_authorized:
@@ -4164,7 +4223,7 @@ unsupported_requirement:
 not_implemented:
   {
     GST_ERROR ("client %p: method %d not implemented", client, method);
-    send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, ctx);
     goto done;
   }
 }
@@ -5033,11 +5092,12 @@ error_full (GstRTSPWatch * watch, GstRTSPResult result,
     goto done;
 
   if (result == GST_RTSP_ENOMEM) {
-    send_generic_response (client, GST_RTSP_STS_REQUEST_ENTITY_TOO_LARGE, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_REQUEST_ENTITY_TOO_LARGE,
+        ctx);
     goto done;
   }
   if (result == GST_RTSP_EPARSE) {
-    send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
+    send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
     goto done;
   }
 
@@ -5306,12 +5366,15 @@ gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context)
 
   gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE);
 
+  /* take the lock before attaching the client watch, so that the client thread
+   * can not access the control channel timer until it's properly in place */
+  g_mutex_lock (&priv->lock);
+
   GST_INFO ("client %p: attaching to context %p", client, context);
   res = gst_rtsp_watch_attach (priv->watch, context);
 
   /* Setting up a timeout for the RTSP control channel until a session
    * is up where it is handling timeouts. */
-  g_mutex_lock (&priv->lock);
 
   /* remove old timeout if any */
   rtsp_ctrl_timeout_remove_unlocked (client->priv);