media: add suspend modes
authorWim Taymans <wtaymans@redhat.com>
Thu, 28 Nov 2013 13:10:19 +0000 (14:10 +0100)
committerWim Taymans <wtaymans@redhat.com>
Thu, 28 Nov 2013 15:18:39 +0000 (16:18 +0100)
Add support for different suspend modes. The stream is suspended right after
producing the SDP and after PAUSE. Different suspend modes are available that
affect the state of the pipeline. NONE leaves the pipeline state unchanged and
is the current and old behaviour, PAUSE will set the pipeline to the PAUSED
state and RESET will bring the pipeline to the NULL state.
A stream is also unsuspended when it goes back to PLAYING, for RESET streams,
this means that the pipeline needs to be prerolled again.

Base on patches by Ognyan Tonchev <ognyan@axis.com>

See https://bugzilla.gnome.org/show_bug.cgi?id=711257

gst/rtsp-server/rtsp-media-factory.c
gst/rtsp-server/rtsp-media-factory.h
gst/rtsp-server/rtsp-media.c
gst/rtsp-server/rtsp-media.h
gst/rtsp-server/rtsp-session-media.c
gst/rtsp-server/rtsp-session.c
tests/check/gst/media.c
tests/check/gst/mediafactory.c

index d04c638..590b1f7 100644 (file)
@@ -51,6 +51,7 @@ struct _GstRTSPMediaFactoryPrivate
   GstRTSPPermissions *permissions;
   gchar *launch;
   gboolean shared;
+  GstRTSPSuspendMode suspend_mode;
   gboolean eos_shutdown;
   GstRTSPLowerTrans protocols;
   guint buffer_size;
@@ -62,6 +63,7 @@ struct _GstRTSPMediaFactoryPrivate
 
 #define DEFAULT_LAUNCH          NULL
 #define DEFAULT_SHARED          FALSE
+#define DEFAULT_SUSPEND_MODE    GST_RTSP_SUSPEND_MODE_NONE
 #define DEFAULT_EOS_SHUTDOWN    FALSE
 #define DEFAULT_PROTOCOLS       GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | \
                                         GST_RTSP_LOWER_TRANS_TCP
@@ -72,6 +74,7 @@ enum
   PROP_0,
   PROP_LAUNCH,
   PROP_SHARED,
+  PROP_SUSPEND_MODE,
   PROP_EOS_SHUTDOWN,
   PROP_PROTOCOLS,
   PROP_BUFFER_SIZE,
@@ -148,6 +151,11 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass)
           "If media from this factory is shared", DEFAULT_SHARED,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
+  g_object_class_install_property (gobject_class, PROP_SUSPEND_MODE,
+      g_param_spec_enum ("suspend-mode", "Suspend Mode",
+          "Control how media will be suspended", GST_TYPE_RTSP_SUSPEND_MODE,
+          DEFAULT_SUSPEND_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   g_object_class_install_property (gobject_class, PROP_EOS_SHUTDOWN,
       g_param_spec_boolean ("eos-shutdown", "EOS Shutdown",
           "Send EOS down the pipeline before shutting down",
@@ -194,6 +202,7 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory)
 
   priv->launch = g_strdup (DEFAULT_LAUNCH);
   priv->shared = DEFAULT_SHARED;
+  priv->suspend_mode = DEFAULT_SUSPEND_MODE;
   priv->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
   priv->protocols = DEFAULT_PROTOCOLS;
   priv->buffer_size = DEFAULT_BUFFER_SIZE;
@@ -235,6 +244,10 @@ gst_rtsp_media_factory_get_property (GObject * object, guint propid,
     case PROP_SHARED:
       g_value_set_boolean (value, gst_rtsp_media_factory_is_shared (factory));
       break;
+    case PROP_SUSPEND_MODE:
+      g_value_set_enum (value,
+          gst_rtsp_media_factory_get_suspend_mode (factory));
+      break;
     case PROP_EOS_SHUTDOWN:
       g_value_set_boolean (value,
           gst_rtsp_media_factory_is_eos_shutdown (factory));
@@ -264,6 +277,10 @@ gst_rtsp_media_factory_set_property (GObject * object, guint propid,
     case PROP_SHARED:
       gst_rtsp_media_factory_set_shared (factory, g_value_get_boolean (value));
       break;
+    case PROP_SUSPEND_MODE:
+      gst_rtsp_media_factory_set_suspend_mode (factory,
+          g_value_get_enum (value));
+      break;
     case PROP_EOS_SHUTDOWN:
       gst_rtsp_media_factory_set_eos_shutdown (factory,
           g_value_get_boolean (value));
@@ -443,6 +460,54 @@ gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory * factory)
 }
 
 /**
+ * gst_rtsp_media_factory_set_suspend_mode:
+ * @factory: a #GstRTSPMediaFactory
+ * @mode: the new #GstRTSPSuspendMode
+ *
+ * Configure how media created from this factory will be suspended.
+ */
+void
+gst_rtsp_media_factory_set_suspend_mode (GstRTSPMediaFactory * factory,
+    GstRTSPSuspendMode mode)
+{
+  GstRTSPMediaFactoryPrivate *priv;
+
+  g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
+
+  priv = factory->priv;
+
+  GST_RTSP_MEDIA_FACTORY_LOCK (factory);
+  priv->suspend_mode = mode;
+  GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
+}
+
+/**
+ * gst_rtsp_media_factory_get_suspend_mode:
+ * @factory: a #GstRTSPMediaFactory
+ *
+ * Get how media created from this factory will be suspended.
+ *
+ * Returns: a #GstRTSPSuspendMode.
+ */
+GstRTSPSuspendMode
+gst_rtsp_media_factory_get_suspend_mode (GstRTSPMediaFactory * factory)
+{
+  GstRTSPMediaFactoryPrivate *priv;
+  GstRTSPSuspendMode result;
+
+  g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory),
+      GST_RTSP_SUSPEND_MODE_NONE);
+
+  priv = factory->priv;
+
+  GST_RTSP_MEDIA_FACTORY_LOCK (factory);
+  result = priv->suspend_mode;
+  GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
+
+  return result;
+}
+
+/**
  * gst_rtsp_media_factory_set_shared:
  * @factory: a #GstRTSPMediaFactory
  * @shared: the new value
@@ -946,18 +1011,21 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
   GstRTSPMediaFactoryPrivate *priv = factory->priv;
   gboolean shared, eos_shutdown;
   guint size;
+  GstRTSPSuspendMode suspend_mode;
   GstRTSPLowerTrans protocols;
   GstRTSPAddressPool *pool;
   GstRTSPPermissions *perms;
 
   /* configure the sharedness */
   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
+  suspend_mode = priv->suspend_mode;
   shared = priv->shared;
   eos_shutdown = priv->eos_shutdown;
   size = priv->buffer_size;
   protocols = priv->protocols;
   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
 
+  gst_rtsp_media_set_suspend_mode (media, suspend_mode);
   gst_rtsp_media_set_shared (media, shared);
   gst_rtsp_media_set_eos_shutdown (media, eos_shutdown);
   gst_rtsp_media_set_buffer_size (media, size);
index d8819b1..63f4d82 100644 (file)
@@ -114,6 +114,10 @@ void                  gst_rtsp_media_factory_set_shared       (GstRTSPMediaFacto
                                                                gboolean shared);
 gboolean              gst_rtsp_media_factory_is_shared        (GstRTSPMediaFactory *factory);
 
+void                  gst_rtsp_media_factory_set_suspend_mode (GstRTSPMediaFactory *factory,
+                                                               GstRTSPSuspendMode mode);
+GstRTSPSuspendMode    gst_rtsp_media_factory_get_suspend_mode (GstRTSPMediaFactory *factory);
+
 void                  gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFactory *factory,
                                                                gboolean eos_shutdown);
 gboolean              gst_rtsp_media_factory_is_eos_shutdown  (GstRTSPMediaFactory *factory);
index e1dd573..2c72d97 100644 (file)
@@ -80,6 +80,7 @@ struct _GstRTSPMediaPrivate
   /* protected by lock */
   GstRTSPPermissions *permissions;
   gboolean shared;
+  gboolean suspend_mode;
   gboolean reusable;
   GstRTSPLowerTrans protocols;
   gboolean reused;
@@ -122,6 +123,7 @@ struct _GstRTSPMediaPrivate
 };
 
 #define DEFAULT_SHARED          FALSE
+#define DEFAULT_SUSPEND_MODE    GST_RTSP_SUSPEND_MODE_NONE
 #define DEFAULT_REUSABLE        FALSE
 #define DEFAULT_PROTOCOLS       GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | \
                                         GST_RTSP_LOWER_TRANS_TCP
@@ -136,6 +138,7 @@ enum
 {
   PROP_0,
   PROP_SHARED,
+  PROP_SUSPEND_MODE,
   PROP_REUSABLE,
   PROP_PROTOCOLS,
   PROP_EOS_SHUTDOWN,
@@ -178,6 +181,29 @@ static gboolean wait_preroll (GstRTSPMedia * media);
 
 static guint gst_rtsp_media_signals[SIGNAL_LAST] = { 0 };
 
+#define C_ENUM(v) ((gint) v)
+
+#define GST_TYPE_RTSP_SUSPEND_MODE (gst_rtsp_suspend_mode_get_type())
+GType
+gst_rtsp_suspend_mode_get_type (void)
+{
+  static gsize id = 0;
+  static const GEnumValue values[] = {
+    {C_ENUM (GST_RTSP_SUSPEND_MODE_NONE), "GST_RTSP_SUSPEND_MODE_NONE", "none"},
+    {C_ENUM (GST_RTSP_SUSPEND_MODE_PAUSE), "GST_RTSP_SUSPEND_MODE_PAUSE",
+        "pause"},
+    {C_ENUM (GST_RTSP_SUSPEND_MODE_RESET), "GST_RTSP_SUSPEND_MODE_RESET",
+        "reset"},
+    {0, NULL, NULL}
+  };
+
+  if (g_once_init_enter (&id)) {
+    GType tmp = g_enum_register_static ("GstRTSPSuspendMode", values);
+    g_once_init_leave (&id, tmp);
+  }
+  return (GType) id;
+}
+
 G_DEFINE_TYPE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT);
 
 static void
@@ -198,6 +224,11 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass)
           "If this media pipeline can be shared", DEFAULT_SHARED,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
+  g_object_class_install_property (gobject_class, PROP_SUSPEND_MODE,
+      g_param_spec_enum ("suspend-mode", "Suspend Mode",
+          "How to suspend the media in PAUSED", GST_TYPE_RTSP_SUSPEND_MODE,
+          DEFAULT_SUSPEND_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   g_object_class_install_property (gobject_class, PROP_REUSABLE,
       g_param_spec_boolean ("reusable", "Reusable",
           "If this media pipeline can be reused after an unprepare",
@@ -276,6 +307,7 @@ gst_rtsp_media_init (GstRTSPMedia * media)
   g_rec_mutex_init (&priv->state_lock);
 
   priv->shared = DEFAULT_SHARED;
+  priv->suspend_mode = DEFAULT_SUSPEND_MODE;
   priv->reusable = DEFAULT_REUSABLE;
   priv->protocols = DEFAULT_PROTOCOLS;
   priv->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
@@ -328,6 +360,9 @@ gst_rtsp_media_get_property (GObject * object, guint propid,
     case PROP_SHARED:
       g_value_set_boolean (value, gst_rtsp_media_is_shared (media));
       break;
+    case PROP_SUSPEND_MODE:
+      g_value_set_enum (value, gst_rtsp_media_get_suspend_mode (media));
+      break;
     case PROP_REUSABLE:
       g_value_set_boolean (value, gst_rtsp_media_is_reusable (media));
       break;
@@ -362,6 +397,9 @@ gst_rtsp_media_set_property (GObject * object, guint propid,
     case PROP_SHARED:
       gst_rtsp_media_set_shared (media, g_value_get_boolean (value));
       break;
+    case PROP_SUSPEND_MODE:
+      gst_rtsp_media_set_suspend_mode (media, g_value_get_enum (value));
+      break;
     case PROP_REUSABLE:
       gst_rtsp_media_set_reusable (media, g_value_get_boolean (value));
       break;
@@ -607,6 +645,66 @@ gst_rtsp_media_get_permissions (GstRTSPMedia * media)
 }
 
 /**
+ * gst_rtsp_media_set_suspend_mode:
+ * @media: a #GstRTSPMedia
+ * @mode: the new #GstRTSPSuspendMode
+ *
+ * Control how @ media will be suspended after the SDP has been generated and
+ * after a PAUSE request has been performed.
+ *
+ * Media must be unprepared when setting the suspend mode.
+ */
+void
+gst_rtsp_media_set_suspend_mode (GstRTSPMedia * media, GstRTSPSuspendMode mode)
+{
+  GstRTSPMediaPrivate *priv;
+
+  g_return_if_fail (GST_IS_RTSP_MEDIA (media));
+
+  priv = media->priv;
+
+  g_rec_mutex_lock (&priv->state_lock);
+  if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED)
+    goto was_prepared;
+  priv->suspend_mode = mode;
+  g_rec_mutex_unlock (&priv->state_lock);
+
+  return;
+
+  /* ERRORS */
+was_prepared:
+  {
+    GST_WARNING ("media %p was prepared", media);
+    g_rec_mutex_unlock (&priv->state_lock);
+  }
+}
+
+/**
+ * gst_rtsp_media_get_suspend_mode:
+ * @media: a #GstRTSPMedia
+ *
+ * Get how @media will be suspended.
+ *
+ * Returns: #GstRTSPSuspendMode.
+ */
+GstRTSPSuspendMode
+gst_rtsp_media_get_suspend_mode (GstRTSPMedia * media)
+{
+  GstRTSPMediaPrivate *priv;
+  GstRTSPSuspendMode res;
+
+  g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), GST_RTSP_SUSPEND_MODE_NONE);
+
+  priv = media->priv;
+
+  g_rec_mutex_lock (&priv->state_lock);
+  res = priv->suspend_mode;
+  g_rec_mutex_unlock (&priv->state_lock);
+
+  return res;
+}
+
+/**
  * gst_rtsp_media_set_shared:
  * @media: a #GstRTSPMedia
  * @shared: the new value
@@ -2271,6 +2369,144 @@ gst_rtsp_media_get_time_provider (GstRTSPMedia * media, const gchar * address,
   return provider;
 }
 
+/**
+ * gst_rtsp_media_suspend:
+ * @media: a #GstRTSPMedia
+ *
+ * Suspend @media. The state of the pipeline managed by @media is set to
+ * GST_STATE_NULL but all streams are kept. @media can be prepared again
+ * with gst_rtsp_media_undo_reset()
+ *
+ * @media must be prepared with gst_rtsp_media_prepare();
+ *
+ * Returns: %TRUE on success.
+ */
+gboolean
+gst_rtsp_media_suspend (GstRTSPMedia * media)
+{
+  GstRTSPMediaPrivate *priv = media->priv;
+  GstStateChangeReturn ret;
+
+  g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
+
+  GST_FIXME ("suspend for dynamic pipelines needs fixing");
+
+  g_rec_mutex_lock (&priv->state_lock);
+  if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED)
+    goto not_prepared;
+
+  /* don't attempt to suspend when something is busy */
+  if (priv->n_active > 0)
+    goto done;
+
+  switch (priv->suspend_mode) {
+    case GST_RTSP_SUSPEND_MODE_NONE:
+      GST_DEBUG ("media %p no suspend", media);
+      break;
+    case GST_RTSP_SUSPEND_MODE_PAUSE:
+      GST_DEBUG ("media %p suspend to PAUSED", media);
+      priv->target_state = GST_STATE_PAUSED;
+      ret = gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
+      if (ret == GST_STATE_CHANGE_FAILURE)
+        goto state_failed;
+      break;
+    case GST_RTSP_SUSPEND_MODE_RESET:
+      GST_DEBUG ("media %p suspend to NULL", media);
+      priv->target_state = GST_STATE_NULL;
+      ret = gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+      if (ret == GST_STATE_CHANGE_FAILURE)
+        goto state_failed;
+      break;
+    default:
+      break;
+  }
+  /* let the streams do the state changes freely, if any */
+  media_streams_set_blocked (media, FALSE);
+  priv->status = GST_RTSP_MEDIA_STATUS_SUSPENDED;
+done:
+  g_rec_mutex_unlock (&priv->state_lock);
+
+  return TRUE;
+
+  /* ERRORS */
+not_prepared:
+  {
+    g_rec_mutex_unlock (&priv->state_lock);
+    GST_WARNING ("media %p was not prepared", media);
+    return FALSE;
+  }
+state_failed:
+  {
+    g_rec_mutex_unlock (&priv->state_lock);
+    gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
+    GST_WARNING ("failed changing pipeline's state for media %p", media);
+    return FALSE;
+  }
+}
+
+/**
+ * gst_rtsp_media_unsuspend:
+ * @media: a #GstRTSPMedia
+ *
+ * Unsuspend @media if it was in a suspended state. This method does nothing
+ * when the media was not in the suspended state.
+ *
+ * Returns: %TRUE on success.
+ */
+gboolean
+gst_rtsp_media_unsuspend (GstRTSPMedia * media)
+{
+  GstRTSPMediaPrivate *priv = media->priv;
+
+  g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
+
+  g_rec_mutex_lock (&priv->state_lock);
+  if (priv->status != GST_RTSP_MEDIA_STATUS_SUSPENDED)
+    goto done;
+
+  switch (priv->suspend_mode) {
+    case GST_RTSP_SUSPEND_MODE_NONE:
+      priv->status = GST_RTSP_MEDIA_STATUS_PREPARED;
+      break;
+    case GST_RTSP_SUSPEND_MODE_PAUSE:
+      priv->status = GST_RTSP_MEDIA_STATUS_PREPARED;
+      break;
+    case GST_RTSP_SUSPEND_MODE_RESET:
+    {
+      priv->status = GST_RTSP_MEDIA_STATUS_PREPARING;
+      if (!start_preroll (media))
+        goto start_failed;
+      g_rec_mutex_unlock (&priv->state_lock);
+
+      if (!wait_preroll (media))
+        goto preroll_failed;
+
+      g_rec_mutex_lock (&priv->state_lock);
+    }
+    default:
+      break;
+  }
+done:
+  g_rec_mutex_unlock (&priv->state_lock);
+
+  return TRUE;
+
+  /* ERRORS */
+start_failed:
+  {
+    g_rec_mutex_unlock (&priv->state_lock);
+    GST_WARNING ("failed to preroll pipeline");
+    gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
+    return FALSE;
+  }
+preroll_failed:
+  {
+    GST_WARNING ("failed to preroll pipeline");
+    return FALSE;
+  }
+}
+
+/* must be called with state-lock */
 static void
 media_set_pipeline_state_locked (GstRTSPMedia * media, GstState state)
 {
@@ -2291,6 +2527,10 @@ media_set_pipeline_state_locked (GstRTSPMedia * media, GstState state)
         media_streams_set_blocked (media, FALSE);
 
       gst_element_set_state (priv->pipeline, state);
+
+      /* and suspend after pause */
+      if (state == GST_STATE_PAUSED)
+        gst_rtsp_media_suspend (media);
     }
   }
 }
index 016526d..735576b 100644 (file)
@@ -41,11 +41,6 @@ typedef struct _GstRTSPMedia GstRTSPMedia;
 typedef struct _GstRTSPMediaClass GstRTSPMediaClass;
 typedef struct _GstRTSPMediaPrivate GstRTSPMediaPrivate;
 
-#include "rtsp-stream.h"
-#include "rtsp-thread-pool.h"
-#include "rtsp-permissions.h"
-#include "rtsp-address-pool.h"
-
 /**
  * GstRTSPMediaStatus:
  * @GST_RTSP_MEDIA_STATUS_UNPREPARED: media pipeline not prerolled
@@ -53,6 +48,7 @@ typedef struct _GstRTSPMediaPrivate GstRTSPMediaPrivate;
  *                                     shutdown.
  * @GST_RTSP_MEDIA_STATUS_PREPARING: media pipeline is prerolling
  * @GST_RTSP_MEDIA_STATUS_PREPARED: media pipeline is prerolled
+ * @GST_RTSP_MEDIA_STATUS_SUSPENDED: media is suspended
  * @GST_RTSP_MEDIA_STATUS_ERROR: media pipeline is in error
  *
  * The state of the media pipeline.
@@ -62,10 +58,34 @@ typedef enum {
   GST_RTSP_MEDIA_STATUS_UNPREPARING = 1,
   GST_RTSP_MEDIA_STATUS_PREPARING   = 2,
   GST_RTSP_MEDIA_STATUS_PREPARED    = 3,
-  GST_RTSP_MEDIA_STATUS_ERROR       = 4
+  GST_RTSP_MEDIA_STATUS_SUSPENDED   = 4,
+  GST_RTSP_MEDIA_STATUS_ERROR       = 5
 } GstRTSPMediaStatus;
 
 /**
+ * GstRTSPSuspendMode:
+ * @GST_RTSP_SUSPEND_MODE_NONE: Media is not suspended
+ * @GST_RTSP_SUSPEND_MODE_PAUSE: Media is PAUSED in suspend
+ * @GST_RTSP_SUSPEND_MODE_RESET: The media is set to NULL when suspended
+ *
+ * The suspend mode of the media pipeline. A media pipeline is suspended right
+ * after creating the SDP and when the client preforms a PAUSED request.
+ */
+typedef enum {
+  GST_RTSP_SUSPEND_MODE_NONE   = 0,
+  GST_RTSP_SUSPEND_MODE_PAUSE  = 1,
+  GST_RTSP_SUSPEND_MODE_RESET  = 2
+} GstRTSPSuspendMode;
+
+#define GST_TYPE_RTSP_SUSPEND_MODE (gst_rtsp_suspend_mode_get_type())
+GType gst_rtsp_suspend_mode_get_type (void);
+
+#include "rtsp-stream.h"
+#include "rtsp-thread-pool.h"
+#include "rtsp-permissions.h"
+#include "rtsp-address-pool.h"
+
+/**
  * GstRTSPMedia:
  *
  * A class that contains the GStreamer element along with a list of
@@ -154,6 +174,12 @@ GstNetTimeProvider *  gst_rtsp_media_get_time_provider (GstRTSPMedia *media,
 gboolean              gst_rtsp_media_prepare          (GstRTSPMedia *media, GstRTSPThread *thread);
 gboolean              gst_rtsp_media_unprepare        (GstRTSPMedia *media);
 
+void                  gst_rtsp_media_set_suspend_mode (GstRTSPMedia *media, GstRTSPSuspendMode mode);
+GstRTSPSuspendMode    gst_rtsp_media_get_suspend_mode (GstRTSPMedia *media);
+
+gboolean              gst_rtsp_media_suspend          (GstRTSPMedia *media);
+gboolean              gst_rtsp_media_unsuspend        (GstRTSPMedia *media);
+
 /* creating streams */
 void                  gst_rtsp_media_collect_streams  (GstRTSPMedia *media);
 GstRTSPStream *       gst_rtsp_media_create_stream    (GstRTSPMedia *media,
index 796da5a..d042ea0 100644 (file)
@@ -138,11 +138,13 @@ gst_rtsp_session_media_new (const gchar * path, GstRTSPMedia * media)
   GstRTSPSessionMediaPrivate *priv;
   GstRTSPSessionMedia *result;
   guint n_streams;
+  GstRTSPMediaStatus status;
 
   g_return_val_if_fail (path != NULL, NULL);
   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
-  g_return_val_if_fail (gst_rtsp_media_get_status (media) ==
-      GST_RTSP_MEDIA_STATUS_PREPARED, NULL);
+  status = gst_rtsp_media_get_status (media);
+  g_return_val_if_fail (status == GST_RTSP_MEDIA_STATUS_PREPARED || status ==
+      GST_RTSP_MEDIA_STATUS_SUSPENDED, NULL);
 
   result = g_object_new (GST_TYPE_RTSP_SESSION_MEDIA, NULL);
   priv = result->priv;
index 204ccf7..b2ff36d 100644 (file)
@@ -205,12 +205,14 @@ gst_rtsp_session_manage_media (GstRTSPSession * sess, const gchar * path,
 {
   GstRTSPSessionPrivate *priv;
   GstRTSPSessionMedia *result;
+  GstRTSPMediaStatus status;
 
   g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), NULL);
   g_return_val_if_fail (path != NULL, NULL);
   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
-  g_return_val_if_fail (gst_rtsp_media_get_status (media) ==
-      GST_RTSP_MEDIA_STATUS_PREPARED, NULL);
+  status = gst_rtsp_media_get_status (media);
+  g_return_val_if_fail (status == GST_RTSP_MEDIA_STATUS_PREPARED || status ==
+      GST_RTSP_MEDIA_STATUS_SUSPENDED, NULL);
 
   priv = sess->priv;
 
index ca2c324..23e8586 100644 (file)
@@ -300,6 +300,50 @@ GST_START_TEST (test_media_take_pipeline)
 
 GST_END_TEST;
 
+GST_START_TEST (test_media_reset)
+{
+  GstRTSPMediaFactory *factory;
+  GstRTSPMedia *media;
+  GstRTSPUrl *url;
+  GstRTSPThreadPool *pool;
+  GstRTSPThread *thread;
+
+  pool = gst_rtsp_thread_pool_new ();
+
+  factory = gst_rtsp_media_factory_new ();
+  fail_if (gst_rtsp_media_factory_is_shared (factory));
+  gst_rtsp_url_parse ("rtsp://localhost:8554/test", &url);
+
+  gst_rtsp_media_factory_set_launch (factory,
+      "( videotestsrc ! rtpvrawpay pt=96 name=pay0 )");
+
+  media = gst_rtsp_media_factory_construct (factory, url);
+  fail_unless (GST_IS_RTSP_MEDIA (media));
+
+  thread = gst_rtsp_thread_pool_get_thread (pool,
+      GST_RTSP_THREAD_TYPE_MEDIA, NULL);
+  fail_unless (gst_rtsp_media_prepare (media, thread));
+  fail_unless (gst_rtsp_media_suspend (media));
+  fail_unless (gst_rtsp_media_unprepare (media));
+  g_object_unref (media);
+
+  media = gst_rtsp_media_factory_construct (factory, url);
+  fail_unless (GST_IS_RTSP_MEDIA (media));
+
+  thread = gst_rtsp_thread_pool_get_thread (pool,
+      GST_RTSP_THREAD_TYPE_MEDIA, NULL);
+  gst_rtsp_media_set_suspend_mode (media, GST_RTSP_SUSPEND_MODE_RESET);
+  fail_unless (gst_rtsp_media_prepare (media, thread));
+  fail_unless (gst_rtsp_media_suspend (media));
+  fail_unless (gst_rtsp_media_unprepare (media));
+  g_object_unref (media);
+
+  gst_rtsp_url_free (url);
+  g_object_unref (factory);
+}
+
+GST_END_TEST;
+
 static Suite *
 rtspmedia_suite (void)
 {
@@ -313,6 +357,7 @@ rtspmedia_suite (void)
   tcase_add_test (tc, test_media_prepare);
   tcase_add_test (tc, test_media_dyn_prepare);
   tcase_add_test (tc, test_media_take_pipeline);
+  tcase_add_test (tc, test_media_reset);
 
   return s;
 }
index 73e4883..b6b250b 100644 (file)
@@ -280,6 +280,40 @@ GST_START_TEST (test_permissions)
 
 GST_END_TEST;
 
+GST_START_TEST (test_reset)
+{
+  GstRTSPMediaFactory *factory;
+  GstRTSPMedia *media;
+  GstRTSPUrl *url;
+
+  factory = gst_rtsp_media_factory_new ();
+  fail_if (gst_rtsp_media_factory_is_shared (factory));
+  gst_rtsp_url_parse ("rtsp://localhost:8554/test", &url);
+
+  gst_rtsp_media_factory_set_launch (factory,
+      "( videotestsrc ! rtpvrawpay pt=96 name=pay0 )");
+
+  media = gst_rtsp_media_factory_construct (factory, url);
+  fail_unless (GST_IS_RTSP_MEDIA (media));
+  fail_if (gst_rtsp_media_get_suspend_mode (media) !=
+      GST_RTSP_SUSPEND_MODE_NONE);
+  g_object_unref (media);
+
+  gst_rtsp_media_factory_set_suspend_mode (factory,
+      GST_RTSP_SUSPEND_MODE_RESET);
+
+  media = gst_rtsp_media_factory_construct (factory, url);
+  fail_unless (GST_IS_RTSP_MEDIA (media));
+  fail_if (gst_rtsp_media_get_suspend_mode (media) !=
+      GST_RTSP_SUSPEND_MODE_RESET);
+  g_object_unref (media);
+
+  gst_rtsp_url_free (url);
+  g_object_unref (factory);
+}
+
+GST_END_TEST;
+
 static Suite *
 rtspmediafactory_suite (void)
 {
@@ -294,6 +328,7 @@ rtspmediafactory_suite (void)
   tcase_add_test (tc, test_shared);
   tcase_add_test (tc, test_addresspool);
   tcase_add_test (tc, test_permissions);
+  tcase_add_test (tc, test_reset);
 
   return s;
 }