[the-board/sound-thing] more player (duration and progress)



commit 8464d78a288db2b170f745d79c92762e5f827ec2
Author: Lucas Rocha <lucasr gnome org>
Date:   Wed Jan 5 16:06:49 2011 +0000

    more player (duration and progress)

 src/tb/tb-sound-player.c |  296 +++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 281 insertions(+), 15 deletions(-)
---
diff --git a/src/tb/tb-sound-player.c b/src/tb/tb-sound-player.c
index c89761c..9103576 100644
--- a/src/tb/tb-sound-player.c
+++ b/src/tb/tb-sound-player.c
@@ -10,12 +10,16 @@ G_DEFINE_TYPE (TbSoundPlayer, tb_sound_player, G_TYPE_OBJECT);
 #define TB_SOUND_PLAYER_GET_PRIVATE(obj)    \
 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TB_TYPE_SOUND_PLAYER, TbSoundPlayerPrivate))
 
+#define TICK_TIMEOUT 0.5
+
 enum
 {
   PROP_0,
 
   PROP_PLAYING,
   PROP_STATE,
+  PROP_PROGRESS,
+  PROP_DURATION,
   PROP_FILENAME
 };
 
@@ -26,6 +30,13 @@ struct _TbSoundPlayerPrivate
   TbSoundPlayerState     state;
   char                  *filename;
   gboolean               playing;
+  GstState               stacked_state;
+  gdouble                stacked_progress;
+  gdouble                target_progress;
+  gdouble                duration;
+  guint                  tick_timeout_id;
+
+  guint                  in_seek : 1;
 };
 
 static void tb_sound_player_destroy_pipeline (TbSoundPlayer *player);
@@ -50,7 +61,7 @@ tb_sound_player_set_state (TbSoundPlayer      *player,
 
 static void
 tb_sound_player_set_filename (TbSoundPlayer *player,
-                              const char      *filename)
+                              const char    *filename)
 {
   TbSoundPlayerPrivate *priv;
 
@@ -72,6 +83,132 @@ tb_sound_player_set_filename (TbSoundPlayer *player,
 }
 
 static void
+tb_sound_player_set_progress (TbSoundPlayer *player,
+                              gdouble        progress)
+{
+  TbSoundPlayerPrivate *priv;
+  GstState pending;
+  GstQuery *duration_q;
+  gint64 position;
+
+  priv = TB_SOUND_PLAYER_GET_PRIVATE (player);
+
+  if (!priv->pipeline)
+    return;
+
+  priv->target_progress = progress;
+
+  if (priv->in_seek)
+    {
+      priv->stacked_progress = progress;
+      return;
+    }
+
+  gst_element_get_state (priv->pipeline, &priv->stacked_state, &pending, 0);
+
+  if (pending)
+    priv->stacked_state = pending;
+
+  gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
+
+  duration_q = gst_query_new_duration (GST_FORMAT_TIME);
+
+  if (gst_element_query (priv->pipeline, duration_q))
+    {
+      gint64 duration = 0;
+
+      gst_query_parse_duration (duration_q, NULL, &duration);
+
+      position = progress * duration;
+    }
+  else
+    position = 0;
+
+  gst_query_unref (duration_q);
+
+  gst_element_seek (priv->pipeline,
+		    1.0,
+		    GST_FORMAT_TIME,
+		    GST_SEEK_FLAG_FLUSH,
+		    GST_SEEK_TYPE_SET,
+		    position,
+		    GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
+
+  priv->in_seek = TRUE;
+  priv->stacked_progress = 0.0;
+}
+
+static gdouble
+tb_sound_player_get_progress (TbSoundPlayer *player)
+{
+  TbSoundPlayerPrivate *priv;
+  GstQuery *position_q, *duration_q;
+  gdouble progress;
+
+  priv = TB_SOUND_PLAYER_GET_PRIVATE (player);
+
+  if (!priv->pipeline)
+    return 0.0;
+
+  if (priv->in_seek)
+    {
+      return priv->target_progress;
+    }
+
+  position_q = gst_query_new_position (GST_FORMAT_TIME);
+  duration_q = gst_query_new_duration (GST_FORMAT_TIME);
+
+  if (gst_element_query (priv->pipeline, position_q) &&
+      gst_element_query (priv->pipeline, duration_q))
+    {
+      gint64 position, duration;
+
+      position = duration = 0;
+
+      gst_query_parse_position (position_q, NULL, &position);
+      gst_query_parse_duration (duration_q, NULL, &duration);
+
+      progress = CLAMP ((gdouble) position / (gdouble) duration, 0.0, 1.0);
+    }
+  else
+    progress = 0.0;
+
+  gst_query_unref (position_q);
+  gst_query_unref (duration_q);
+
+  return progress;
+}
+
+static void
+tb_sound_player_query_duration (TbSoundPlayer *player)
+{
+  TbSoundPlayerPrivate *priv;
+  GstFormat format = GST_FORMAT_TIME;
+  gdouble new_duration, difference;
+  gboolean success;
+  gint64 duration;
+
+  priv = TB_SOUND_PLAYER_GET_PRIVATE (player);
+
+  success = gst_element_query_duration (priv->pipeline, &format, &duration);
+
+  if (G_UNLIKELY (success != TRUE))
+    return;
+
+  new_duration = (gdouble) duration / GST_SECOND;
+
+  difference = ABS (priv->duration - new_duration);
+
+  if (difference > 1e-3)
+    {
+      priv->duration = new_duration;
+
+      if (difference > 1.0)
+        g_object_notify (G_OBJECT (player), "duration");
+    }
+}
+
+static void
 tb_sound_player_reset_pipeline (TbSoundPlayer *player)
 {
   TbSoundPlayerPrivate *priv;
@@ -102,6 +239,11 @@ tb_sound_player_reset_pipeline (TbSoundPlayer *player)
     gst_bus_async_signal_func (priv->bus, msg, NULL);
 
   gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+
+  priv->duration = 0;
+
+  g_object_notify (G_OBJECT (player), "duration");
+  g_object_notify (G_OBJECT (player), "progress");
 }
 
 static void
@@ -127,15 +269,24 @@ tb_sound_player_destroy_pipeline (TbSoundPlayer *player)
       gst_object_unref (priv->pipeline);
       priv->pipeline = NULL;
     }
+
+  if (priv->tick_timeout_id != 0)
+    {
+      g_source_remove (priv->tick_timeout_id);
+      priv->tick_timeout_id = 0;
+    }
+
+  g_object_notify (G_OBJECT (player), "duration");
+  g_object_notify (G_OBJECT (player), "progress");
 }
 
 static void
-tb_sound_player_on_state_changed (GstBus          *bus,
-                                  GstMessage      *msg,
+tb_sound_player_on_state_changed (GstBus        *bus,
+                                  GstMessage    *msg,
                                   TbSoundPlayer *player)
 {
   TbSoundPlayerPrivate *priv;
-  GstState state;
+  GstState state, old_state;
 
   g_return_if_fail (TB_IS_SOUND_PLAYER (player));
 
@@ -144,7 +295,10 @@ tb_sound_player_on_state_changed (GstBus          *bus,
   if (msg->src != GST_OBJECT (priv->pipeline))
     return;
 
-  gst_message_parse_state_changed (msg, NULL, &state, NULL);
+  gst_message_parse_state_changed (msg, &old_state, &state, NULL);
+
+  if (state == GST_STATE_PAUSED && old_state == GST_STATE_READY)
+    tb_sound_player_query_duration (player);
 
   switch (state)
     {
@@ -164,8 +318,8 @@ tb_sound_player_on_state_changed (GstBus          *bus,
 }
 
 static void
-tb_sound_player_on_error (GstBus          *bus,
-                          GstMessage      *msg,
+tb_sound_player_on_error (GstBus        *bus,
+                          GstMessage    *msg,
                           TbSoundPlayer *player)
 {
   tb_sound_player_reset_pipeline (player);
@@ -173,14 +327,64 @@ tb_sound_player_on_error (GstBus          *bus,
 }
 
 static void
-tb_sound_player_on_eos (GstBus          *bus,
-                        GstMessage      *msg,
+tb_sound_player_on_eos (GstBus        *bus,
+                        GstMessage    *msg,
                         TbSoundPlayer *player)
 {
+  g_object_notify (G_OBJECT (player), "progress");
+
   tb_sound_player_set_state (player, TB_SOUND_PLAYER_STATE_DONE);
   tb_sound_player_reset_pipeline (player);
 }
 
+static void
+tb_sound_player_on_async_done (GstBus        *bus,
+                               GstMessage    *msg,
+                               TbSoundPlayer *player)
+{
+  TbSoundPlayerPrivate *priv;
+
+  priv = TB_SOUND_PLAYER_GET_PRIVATE (player);
+
+  if (priv->in_seek)
+    {
+      g_object_notify (G_OBJECT (player), "progress");
+
+      priv->in_seek = FALSE;
+      gst_element_set_state (priv->pipeline, priv->stacked_state);
+
+      if (priv->stacked_progress)
+        {
+          tb_sound_player_set_progress (player, priv->stacked_progress);
+        }
+    }
+}
+
+static void
+tb_sound_player_on_duration (GstBus        *bus,
+                             GstMessage    *msg,
+                             TbSoundPlayer *player)
+{
+  gint64 duration;
+
+  gst_message_parse_duration (msg, NULL, &duration);
+
+  if (G_UNLIKELY (duration != GST_CLOCK_TIME_NONE))
+    return;
+
+  tb_sound_player_query_duration (player);
+}
+
+static gboolean
+tb_sound_player_tick_timeout (gpointer user_data)
+{
+  GObject *player = user_data;
+
+  g_object_notify (player, "progress");
+
+  return TRUE;
+}
+
 static gboolean
 tb_sound_player_ensure_pipeline (TbSoundPlayer *player)
 {
@@ -245,6 +449,24 @@ tb_sound_player_ensure_pipeline (TbSoundPlayer *player)
                     G_CALLBACK (tb_sound_player_on_eos),
                     player);
 
+  g_signal_connect (priv->bus,
+                    "message::async-done",
+                    G_CALLBACK (tb_sound_player_on_async_done),
+                    player);
+
+  g_signal_connect (priv->bus,
+                    "message::duration",
+                    G_CALLBACK (tb_sound_player_on_duration),
+                    player);
+
+  if (priv->tick_timeout_id == 0)
+    {
+      priv->tick_timeout_id =
+        g_timeout_add (TICK_TIMEOUT * 1000,
+                       tb_sound_player_tick_timeout,
+                       player);
+    }
+
   return TRUE;
 }
 
@@ -268,6 +490,7 @@ tb_sound_player_set_playing (TbSoundPlayer *player,
     gst_element_set_state (priv->pipeline, state);
 
   g_object_notify (G_OBJECT (player), "playing");
+  g_object_notify (G_OBJECT (player), "progress");
 }
 
 static gboolean
@@ -314,21 +537,32 @@ tb_sound_player_get_property (GObject    *gobject,
                               GValue     *value,
                               GParamSpec *pspec)
 {
+  TbSoundPlayer *player;
   TbSoundPlayerPrivate *priv;
   
-  priv = TB_SOUND_PLAYER_GET_PRIVATE (gobject);
+  player = TB_SOUND_PLAYER (gobject);
+  priv = TB_SOUND_PLAYER_GET_PRIVATE (player);
 
   switch (prop_id)
     {
     case PROP_PLAYING:
       g_value_set_boolean (value,
-                           tb_sound_player_get_playing (TB_SOUND_PLAYER (gobject)));
+                           tb_sound_player_get_playing (player));
       break;
 
     case PROP_STATE:
       g_value_set_enum (value, priv->state);
       break;
 
+    case PROP_PROGRESS:
+      g_value_set_double (value,
+                          tb_sound_player_get_progress (player));
+      break;
+
+    case PROP_DURATION:
+      g_value_set_double (value, priv->duration);
+      break;
+
     case PROP_FILENAME:
       g_value_set_string (value, priv->filename);
       break;
@@ -345,20 +579,27 @@ tb_sound_player_set_property (GObject      *gobject,
                               const GValue *value,
                               GParamSpec   *pspec)
 {
+  TbSoundPlayer *player;
   TbSoundPlayerPrivate *priv;
   
-  priv = TB_SOUND_PLAYER_GET_PRIVATE (gobject);
+  player = TB_SOUND_PLAYER (gobject);
+  priv = TB_SOUND_PLAYER_GET_PRIVATE (player);
 
   switch (prop_id)
     {
     case PROP_PLAYING:
-      tb_sound_player_set_playing (TB_SOUND_PLAYER (gobject),
+      tb_sound_player_set_playing (player,
                                    g_value_get_boolean (value));
       break;
 
+    case PROP_PROGRESS:
+      tb_sound_player_set_progress (player,
+                                    g_value_get_double (value));
+      break;
+
     case PROP_FILENAME:
-      tb_sound_player_set_filename (TB_SOUND_PLAYER (gobject),
-                                      g_value_get_string (value));
+      tb_sound_player_set_filename (player,
+                                    g_value_get_string (value));
       break;
 
     default:
@@ -390,6 +631,28 @@ tb_sound_player_class_init (TbSoundPlayerClass *klass)
 
   g_object_class_install_property
                  (gobject_class,
+                  PROP_PROGRESS,
+                  g_param_spec_double ("progress",
+                                       "Progress",
+                                       "Player's playback progress",
+                                       0.0,
+                                       1.0,
+                                       0.0,
+                                       G_PARAM_READWRITE));
+
+  g_object_class_install_property
+                 (gobject_class,
+                  PROP_DURATION,
+                  g_param_spec_double ("duration",
+                                       "Duration",
+                                       "Sound duration",
+                                       0.0,
+                                       G_MAXDOUBLE,
+                                       0.0,
+                                       G_PARAM_READABLE));
+
+  g_object_class_install_property
+                 (gobject_class,
                   PROP_STATE,
                   g_param_spec_enum ("state",
                                      "State",
@@ -421,4 +684,7 @@ tb_sound_player_init (TbSoundPlayer *player)
   player->priv->filename = NULL;
   player->priv->pipeline = NULL;
   player->priv->bus = NULL;
+  player->priv->stacked_progress = 0.0;
+  player->priv->duration = 0.0;
+  player->priv->tick_timeout_id = 0;
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]