[the-board/sound-thing: 1/4] initial sketch for sound recorder and player



commit 52c2764bd4644a5823b6d470bc9adc7f6a674413
Author: Lucas Rocha <lucasr gnome org>
Date:   Sun Dec 26 00:19:00 2010 +0000

    initial sketch for sound recorder and player

 src/Makefile-tb.am         |    8 +-
 src/tb/tb-sound-player.c   |  425 ++++++++++++++++++++++++++++++++++++++++++++
 src/tb/tb-sound-player.h   |   44 +++++
 src/tb/tb-sound-recorder.c |  389 ++++++++++++++++++++++++++++++++++++++++
 src/tb/tb-sound-recorder.h |   47 +++++
 5 files changed, 911 insertions(+), 2 deletions(-)
---
diff --git a/src/Makefile-tb.am b/src/Makefile-tb.am
index 69d7811..55d6213 100644
--- a/src/Makefile-tb.am
+++ b/src/Makefile-tb.am
@@ -23,7 +23,9 @@ tb_source_h = \
     tb/tb-gio-util.h \
     tb/tb-gdk-util.h \
     tb/tb-gobject-util.h \
-    tb/tb-mx-util.h
+    tb/tb-mx-util.h \
+    tb/tb-sound-player.h \
+    tb/tb-sound-recorder.h
 
 if HAVE_LIBSOUP
 tb_source_h += tb/tb-soup-util.h
@@ -34,7 +36,9 @@ tb_source_c = \
     tb/tb-gio-util.c \
     tb/tb-gdk-util.c \
     tb/tb-gobject-util.c \
-    tb/tb-mx-util.c
+    tb/tb-mx-util.c \
+    tb/tb-sound-player.c \
+    tb/tb-sound-recorder.c
 
 if HAVE_LIBSOUP
 tb_source_c += tb/tb-soup-util.c
diff --git a/src/tb/tb-sound-player.c b/src/tb/tb-sound-player.c
new file mode 100644
index 0000000..5cb998d
--- /dev/null
+++ b/src/tb/tb-sound-player.c
@@ -0,0 +1,425 @@
+#include <glib.h>
+#include <glib-object.h>
+#include <gst/gst.h>
+
+#include "tb-enum-types.h"
+#include "tb/tb-sound-player.h"
+
+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))
+
+enum
+{
+  PROP_0,
+
+  PROP_PLAYING,
+  PROP_STATE,
+  PROP_FILENAME
+};
+
+struct _TbSoundPlayerPrivate
+{
+  GstElement            *pipeline;
+  GstBus                *bus;
+  TbSoundPlayerState     state;
+  char                  *filename;
+  gboolean               playing;
+};
+
+static void tb_sound_player_destroy_pipeline (TbSoundPlayer *player);
+
+static void
+tb_sound_player_set_state (TbSoundPlayer      *player,
+                           TbSoundPlayerState  state)
+{
+  TbSoundPlayerPrivate *priv;
+
+  g_return_if_fail (TB_IS_SOUND_PLAYER (player));
+
+  priv = TB_SOUND_PLAYER_GET_PRIVATE (player);
+
+  if (priv->state == state)
+    return;
+
+  priv->state = state;
+
+  g_object_notify (G_OBJECT (player), "state");
+}
+
+static void
+tb_sound_player_set_filename (TbSoundPlayer *player,
+                                const char      *filename)
+{
+  TbSoundPlayerPrivate *priv;
+
+  g_return_if_fail (TB_IS_SOUND_PLAYER (player));
+  g_return_if_fail (filename != NULL);
+
+  priv = TB_SOUND_PLAYER_GET_PRIVATE (player);
+
+  if (priv->filename &&
+      !strcmp (priv->filename, filename))
+    return;
+
+  g_free (priv->filename);
+  priv->filename = g_strdup (filename);
+
+  if (priv->pipeline)
+    tb_sound_player_destroy_pipeline (player);
+
+  g_object_notify (G_OBJECT (player), "filename");
+}
+
+static void
+tb_sound_player_reset_pipeline (TbSoundPlayer *player)
+{
+  TbSoundPlayerPrivate *priv;
+  GstState state, pending;
+  GstMessage *msg;
+
+  priv = TB_SOUND_PLAYER_GET_PRIVATE (player);
+
+  if (!priv->pipeline)
+    return;
+
+  gst_element_get_state (priv->pipeline, &state, &pending, 0);
+
+  if (state == GST_STATE_NULL && pending == GST_STATE_VOID_PENDING)
+    {
+      return;
+    }
+  else if (state == GST_STATE_NULL && pending != GST_STATE_VOID_PENDING)
+    {
+      gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+      return;
+    }
+
+  gst_element_set_state (priv->pipeline, GST_STATE_READY);
+  gst_element_get_state (priv->pipeline, NULL, NULL, -1);
+
+  while ((msg = gst_bus_pop (priv->bus)))
+    gst_bus_async_signal_func (priv->bus, msg, NULL);
+
+  gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+}
+
+static void
+tb_sound_player_destroy_pipeline (TbSoundPlayer *player)
+{
+  TbSoundPlayerPrivate *priv;
+
+  priv = TB_SOUND_PLAYER_GET_PRIVATE (player);
+
+  if (priv->bus)
+    {
+      gst_bus_set_flushing (priv->bus, TRUE);
+      gst_bus_remove_signal_watch (priv->bus);
+
+      gst_object_unref (priv->bus);
+      priv->bus = NULL;
+    }
+
+  if (priv->pipeline)
+    {
+      gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+
+      gst_object_unref (priv->pipeline);
+      priv->pipeline = NULL;
+    }
+}
+
+static void
+tb_sound_player_on_state_changed (GstBus          *bus,
+                                  GstMessage      *msg,
+                                  TbSoundPlayer *player)
+{
+  TbSoundPlayerPrivate *priv;
+  GstState state;
+
+  g_return_if_fail (TB_IS_SOUND_PLAYER (player));
+
+  priv = TB_SOUND_PLAYER_GET_PRIVATE (player);
+
+  if (msg->src != GST_OBJECT (priv->pipeline))
+    return;
+
+  gst_message_parse_state_changed (msg, NULL, &state, NULL);
+
+  switch (state)
+    {
+    case GST_STATE_PLAYING:
+      tb_sound_player_set_state (player, TB_SOUND_PLAYER_STATE_PLAYING);
+      break;
+
+    case GST_STATE_READY:
+    case GST_STATE_PAUSED:
+      tb_sound_player_set_state (player, TB_SOUND_PLAYER_STATE_IDLE);
+      break;
+
+    default:
+      /* Do nothing */
+      break;
+    }
+}
+
+static void
+tb_sound_player_on_error (GstBus          *bus,
+                          GstMessage      *msg,
+                          TbSoundPlayer *player)
+{
+  tb_sound_player_reset_pipeline (player);
+  tb_sound_player_set_state (player, TB_SOUND_PLAYER_STATE_ERROR);
+}
+
+static void
+tb_sound_player_on_eos (GstBus          *bus,
+                        GstMessage      *msg,
+                        TbSoundPlayer *player)
+{
+  tb_sound_player_set_state (player, TB_SOUND_PLAYER_STATE_DONE);
+  tb_sound_player_reset_pipeline (player);
+}
+
+static gboolean
+tb_sound_player_ensure_pipeline (TbSoundPlayer *player)
+{
+  TbSoundPlayerPrivate *priv;
+  GError *error;
+  gchar *pipeline_desc;
+
+  priv = TB_SOUND_PLAYER_GET_PRIVATE (player);
+
+  if (priv->pipeline)
+    return TRUE;
+
+  if (priv->filename == NULL)
+    {
+      tb_sound_player_set_state (player, TB_SOUND_PLAYER_STATE_ERROR);
+      return FALSE;
+    }
+
+  error = NULL;
+
+  pipeline_desc = g_strdup_printf("playbin uri=file://%s",
+                                  priv->filename);
+
+  priv->pipeline = gst_parse_launch (pipeline_desc, &error);
+
+  g_free (pipeline_desc);
+
+  if (error)
+    {
+      g_error_free (error);
+      priv->pipeline = NULL;
+
+      tb_sound_player_set_state (player, TB_SOUND_PLAYER_STATE_ERROR);
+      return FALSE;
+    }
+
+  if (!gst_element_set_state (priv->pipeline, GST_STATE_READY))
+    {
+      g_object_unref (priv->pipeline);
+      priv->pipeline = NULL;
+
+      tb_sound_player_set_state (player, TB_SOUND_PLAYER_STATE_ERROR);
+      return FALSE;
+    }
+
+  priv->bus = gst_element_get_bus (priv->pipeline);
+
+  gst_bus_add_signal_watch (priv->bus);
+
+  g_signal_connect (priv->bus,
+                    "message::state-changed",
+                    G_CALLBACK (tb_sound_player_on_state_changed),
+                    player);
+
+  g_signal_connect (priv->bus,
+                    "message::error",
+                    G_CALLBACK (tb_sound_player_on_error),
+                    player);
+
+  g_signal_connect (priv->bus,
+                    "message::eos",
+                    G_CALLBACK (tb_sound_player_on_eos),
+                    player);
+
+  return TRUE;
+}
+
+void
+tb_sound_player_set_playing (TbSoundPlayer *player,
+                             gboolean       playing)
+{
+  TbSoundPlayerPrivate *priv;
+  GstState state;
+
+  g_return_if_fail (TB_IS_SOUND_PLAYER (player));
+
+  priv = TB_SOUND_PLAYER_GET_PRIVATE (player);
+
+  if (playing)
+    state = GST_STATE_PLAYING;
+  else
+    state = GST_STATE_PAUSED;
+
+  if (tb_sound_player_ensure_pipeline (player))
+    gst_element_set_state (priv->pipeline, state);
+
+  g_object_notify (G_OBJECT (player), "playing");
+}
+
+static gboolean
+tb_sound_player_get_playing (TbSoundPlayer *player)
+{
+  TbSoundPlayerPrivate *priv;
+  GstState state, pending;
+  gboolean playing;
+
+  g_return_if_fail (TB_IS_SOUND_PLAYER (player));
+
+  priv = TB_SOUND_PLAYER_GET_PRIVATE (player);
+
+  if (!priv->pipeline)
+    return FALSE;
+
+  gst_element_get_state (priv->pipeline, &state, &pending, 0);
+
+  if (pending)
+    playing = (pending == GST_STATE_PLAYING);
+  else
+    playing = (state == GST_STATE_PLAYING);
+
+  return playing;
+}
+
+static void
+tb_sound_player_finalize (GObject *gobject)
+{
+  G_OBJECT_CLASS (tb_sound_player_parent_class)->finalize (gobject);
+}
+
+static void
+tb_sound_player_dispose (GObject *gobject)
+{
+  tb_sound_player_destroy_pipeline (TB_SOUND_PLAYER (gobject));
+
+  G_OBJECT_CLASS (tb_sound_player_parent_class)->dispose (gobject);
+}
+
+static void
+tb_sound_player_get_property (GObject    *gobject,
+                              guint       prop_id,
+                              GValue     *value,
+                              GParamSpec *pspec)
+{
+  TbSoundPlayerPrivate *priv;
+  
+  priv = TB_SOUND_PLAYER_GET_PRIVATE (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_PLAYING:
+      g_value_set_boolean (value,
+                           tb_sound_player_get_playing (TB_SOUND_PLAYER (gobject)));
+      break;
+
+    case PROP_STATE:
+      g_value_set_enum (value, priv->state);
+      break;
+
+    case PROP_FILENAME:
+      g_value_set_string (value, priv->filename);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+tb_sound_player_set_property (GObject      *gobject,
+                              guint         prop_id,
+                              const GValue *value,
+                              GParamSpec   *pspec)
+{
+  TbSoundPlayerPrivate *priv;
+  
+  priv = TB_SOUND_PLAYER_GET_PRIVATE (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_PLAYING:
+      tb_sound_player_set_playing (TB_SOUND_PLAYER (gobject),
+                                   g_value_get_boolean (value));
+      break;
+
+    case PROP_FILENAME:
+      tb_sound_player_set_filename (TB_SOUND_PLAYER (gobject),
+                                      g_value_get_string (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+tb_sound_player_class_init (TbSoundPlayerClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (TbSoundPlayerPrivate));
+
+  gobject_class->get_property = tb_sound_player_get_property;
+  gobject_class->set_property = tb_sound_player_set_property;
+  gobject_class->dispose = tb_sound_player_dispose;
+  gobject_class->finalize = tb_sound_player_finalize;
+
+  g_object_class_install_property
+                 (gobject_class,
+                  PROP_PLAYING,
+                  g_param_spec_boolean ("playing",
+                                        "Playing",
+                                        "Whether player is playing or not",
+                                        FALSE,
+                                        G_PARAM_READWRITE));
+
+  g_object_class_install_property
+                 (gobject_class,
+                  PROP_STATE,
+                  g_param_spec_enum ("state",
+                                     "State",
+                                     "State of the sound player",
+                                     TB_TYPE_SOUND_PLAYER_STATE,
+                                     TB_SOUND_PLAYER_STATE_UNKNOWN,
+                                     G_PARAM_READABLE));
+
+  g_object_class_install_property
+                 (gobject_class,
+                  PROP_FILENAME,
+                  g_param_spec_string ("filename",
+                                       "Filename",
+                                       "Filename to save sound to",
+                                       NULL,
+                                       G_PARAM_READWRITE |
+                                       G_PARAM_CONSTRUCT));
+}
+
+static void
+tb_sound_player_init (TbSoundPlayer *player)
+{
+  TbSoundPlayerPrivate *priv;
+
+  player->priv = TB_SOUND_PLAYER_GET_PRIVATE (player);
+
+  player->priv->state = TB_SOUND_PLAYER_STATE_UNKNOWN;
+  player->priv->playing = FALSE;
+  player->priv->filename = NULL;
+  player->priv->pipeline = NULL;
+  player->priv->bus = NULL;
+}
diff --git a/src/tb/tb-sound-player.h b/src/tb/tb-sound-player.h
new file mode 100644
index 0000000..5dd7459
--- /dev/null
+++ b/src/tb/tb-sound-player.h
@@ -0,0 +1,44 @@
+#ifndef __TB_SOUND_PLAYER_H__
+#define __TB_SOUND_PLAYER_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define TB_TYPE_SOUND_PLAYER            (tb_sound_player_get_type ())
+#define TB_SOUND_PLAYER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), TB_TYPE_SOUND_PLAYER, TbSoundPlayer))
+#define TB_IS_SOUND_PLAYER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TB_TYPE_SOUND_PLAYER))
+#define TB_SOUND_PLAYER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  TB_TYPE_SOUND_PLAYER, TbSoundPlayerClass))
+#define TB_IS_SOUND_PLAYER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  TB_TYPE_SOUND_PLAYER))
+#define TB_SOUND_PLAYER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  TB_TYPE_SOUND_PLAYER, TbSoundPlayerClass))
+
+typedef struct _TbSoundPlayer          TbSoundPlayer;
+typedef struct _TbSoundPlayerPrivate   TbSoundPlayerPrivate;
+typedef struct _TbSoundPlayerClass     TbSoundPlayerClass;
+
+typedef enum
+{
+  TB_SOUND_PLAYER_STATE_UNKNOWN = 0,
+  TB_SOUND_PLAYER_STATE_IDLE    = 1,
+  TB_SOUND_PLAYER_STATE_PLAYING = 2,
+  TB_SOUND_PLAYER_STATE_DONE    = 3,
+  TB_SOUND_PLAYER_STATE_ERROR   = 4
+} TbSoundPlayerState;
+
+struct _TbSoundPlayer
+{
+  GObject parent_instance;
+
+  TbSoundPlayerPrivate *priv;
+};
+
+struct _TbSoundPlayerClass
+{
+  GObjectClass parent_class;
+};
+
+GType    tb_sound_player_get_type     (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __TB_SOUND_PLAYER_H__ */
diff --git a/src/tb/tb-sound-recorder.c b/src/tb/tb-sound-recorder.c
new file mode 100644
index 0000000..ec87aea
--- /dev/null
+++ b/src/tb/tb-sound-recorder.c
@@ -0,0 +1,389 @@
+#include <glib.h>
+#include <glib-object.h>
+#include <gst/gst.h>
+
+#include "tb-enum-types.h"
+#include "tb/tb-sound-recorder.h"
+
+G_DEFINE_TYPE (TbSoundRecorder, tb_sound_recorder, G_TYPE_OBJECT);
+
+#define TB_SOUND_RECORDER_GET_PRIVATE(obj)    \
+(G_TYPE_INSTANCE_GET_PRIVATE ((obj), TB_TYPE_SOUND_RECORDER, TbSoundRecorderPrivate))
+
+enum
+{
+  PROP_0,
+
+  PROP_STATE,
+  PROP_FILENAME
+};
+
+struct _TbSoundRecorderPrivate
+{
+  GstElement            *pipeline;
+  GstBus                *bus;
+  TbSoundRecorderState   state;
+  char                  *filename;
+};
+
+static void tb_sound_recorder_destroy_pipeline (TbSoundRecorder *recorder);
+
+static void
+tb_sound_recorder_set_state (TbSoundRecorder      *recorder,
+                             TbSoundRecorderState  state)
+{
+  TbSoundRecorderPrivate *priv;
+
+  g_return_if_fail (TB_IS_SOUND_RECORDER (recorder));
+
+  priv = TB_SOUND_RECORDER_GET_PRIVATE (recorder);
+
+  if (priv->state == state)
+    return;
+
+  priv->state = state;
+
+  g_object_notify (G_OBJECT (recorder), "state");
+}
+
+static void
+tb_sound_recorder_set_filename (TbSoundRecorder *recorder,
+                                const char      *filename)
+{
+  TbSoundRecorderPrivate *priv;
+
+  g_return_if_fail (TB_IS_SOUND_RECORDER (recorder));
+  g_return_if_fail (filename != NULL);
+
+  priv = TB_SOUND_RECORDER_GET_PRIVATE (recorder);
+
+  if (priv->filename &&
+      !strcmp (priv->filename, filename))
+    return;
+
+  g_free (priv->filename);
+  priv->filename = g_strdup (filename);
+
+  if (priv->pipeline)
+    tb_sound_recorder_destroy_pipeline (recorder);
+
+  g_object_notify (G_OBJECT (recorder), "filename");
+}
+
+static void
+tb_sound_recorder_reset_pipeline (TbSoundRecorder *recorder)
+{
+  TbSoundRecorderPrivate *priv;
+  GstState state, pending;
+  GstMessage *msg;
+
+  priv = TB_SOUND_RECORDER_GET_PRIVATE (recorder);
+
+  if (!priv->pipeline)
+    return;
+
+  gst_element_get_state (priv->pipeline, &state, &pending, 0);
+
+  if (state == GST_STATE_NULL && pending == GST_STATE_VOID_PENDING)
+    {
+      return;
+    }
+  else if (state == GST_STATE_NULL && pending != GST_STATE_VOID_PENDING)
+    {
+      gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+      return;
+    }
+
+  gst_element_set_state (priv->pipeline, GST_STATE_READY);
+  gst_element_get_state (priv->pipeline, NULL, NULL, -1);
+
+  while ((msg = gst_bus_pop (priv->bus)))
+    gst_bus_async_signal_func (priv->bus, msg, NULL);
+
+  gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+}
+
+static void
+tb_sound_recorder_destroy_pipeline (TbSoundRecorder *recorder)
+{
+  TbSoundRecorderPrivate *priv;
+
+  priv = TB_SOUND_RECORDER_GET_PRIVATE (recorder);
+
+  if (priv->bus)
+    {
+      gst_bus_set_flushing (priv->bus, TRUE);
+      gst_bus_remove_signal_watch (priv->bus);
+
+      gst_object_unref (priv->bus);
+      priv->bus = NULL;
+    }
+
+  if (priv->pipeline)
+    {
+      gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+
+      gst_object_unref (priv->pipeline);
+      priv->pipeline = NULL;
+    }
+}
+
+static void
+tb_sound_recorder_on_state_changed (GstBus          *bus,
+                                    GstMessage      *msg,
+                                    TbSoundRecorder *recorder)
+{
+  TbSoundRecorderPrivate *priv;
+  GstState state;
+
+  g_return_if_fail (TB_IS_SOUND_RECORDER (recorder));
+
+  priv = TB_SOUND_RECORDER_GET_PRIVATE (recorder);
+
+  if (msg->src != GST_OBJECT (priv->pipeline))
+    return;
+
+  gst_message_parse_state_changed (msg, NULL, &state, NULL);
+
+  switch (state)
+    {
+    case GST_STATE_PLAYING:
+      tb_sound_recorder_set_state (recorder, TB_SOUND_RECORDER_STATE_RECORDING);
+      break;
+
+    case GST_STATE_READY:
+    case GST_STATE_PAUSED:
+      tb_sound_recorder_set_state (recorder, TB_SOUND_RECORDER_STATE_IDLE);
+      break;
+
+    default:
+      /* Do nothing */
+      break;
+    }
+}
+
+static void
+tb_sound_recorder_on_error (GstBus          *bus,
+                            GstMessage      *msg,
+                            TbSoundRecorder *recorder)
+{
+  tb_sound_recorder_reset_pipeline (recorder);
+  tb_sound_recorder_set_state (recorder, TB_SOUND_RECORDER_STATE_ERROR);
+}
+
+static void
+tb_sound_recorder_on_eos (GstBus          *bus,
+                          GstMessage      *msg,
+                          TbSoundRecorder *recorder)
+{
+  tb_sound_recorder_set_state (recorder, TB_SOUND_RECORDER_STATE_DONE);
+  tb_sound_recorder_reset_pipeline (recorder);
+}
+
+static gboolean
+tb_sound_recorder_ensure_pipeline (TbSoundRecorder *recorder)
+{
+  TbSoundRecorderPrivate *priv;
+  GError *error;
+  gchar *pipeline_desc;
+
+  priv = TB_SOUND_RECORDER_GET_PRIVATE (recorder);
+
+  if (priv->pipeline)
+    return TRUE;
+
+  if (priv->filename == NULL)
+    {
+      tb_sound_recorder_set_state (recorder, TB_SOUND_RECORDER_STATE_ERROR);
+      return FALSE;
+    }
+
+  error = NULL;
+
+  pipeline_desc = g_strdup_printf("autoaudiosrc name=source ! "
+                                  "audioconvert ! "
+                                  "wavenc ! "
+                                  "filesink location=%s",
+                                  priv->filename);
+
+  priv->pipeline = gst_parse_launch (pipeline_desc, &error);
+
+  g_free (pipeline_desc);
+
+  if (error)
+    {
+      g_error_free (error);
+      priv->pipeline = NULL;
+
+      tb_sound_recorder_set_state (recorder, TB_SOUND_RECORDER_STATE_ERROR);
+      return FALSE;
+    }
+
+  if (!gst_element_set_state (priv->pipeline, GST_STATE_READY))
+    {
+      g_object_unref (priv->pipeline);
+      priv->pipeline = NULL;
+
+      tb_sound_recorder_set_state (recorder, TB_SOUND_RECORDER_STATE_ERROR);
+      return FALSE;
+    }
+
+  priv->bus = gst_element_get_bus (priv->pipeline);
+
+  gst_bus_add_signal_watch (priv->bus);
+
+  g_signal_connect (priv->bus,
+                    "message::state-changed",
+                    G_CALLBACK (tb_sound_recorder_on_state_changed),
+                    recorder);
+
+  g_signal_connect (priv->bus,
+                    "message::error",
+                    G_CALLBACK (tb_sound_recorder_on_error),
+                    recorder);
+
+  g_signal_connect (priv->bus,
+                    "message::eos",
+                    G_CALLBACK (tb_sound_recorder_on_eos),
+                    recorder);
+
+  return TRUE;
+}
+
+static void
+tb_sound_recorder_finalize (GObject *gobject)
+{
+  G_OBJECT_CLASS (tb_sound_recorder_parent_class)->finalize (gobject);
+}
+
+static void
+tb_sound_recorder_dispose (GObject *gobject)
+{
+  tb_sound_recorder_destroy_pipeline (TB_SOUND_RECORDER (gobject));
+
+  G_OBJECT_CLASS (tb_sound_recorder_parent_class)->dispose (gobject);
+}
+
+static void
+tb_sound_recorder_get_property (GObject    *gobject,
+                                guint       prop_id,
+                                GValue     *value,
+                                GParamSpec *pspec)
+{
+  TbSoundRecorderPrivate *priv;
+  
+  priv = TB_SOUND_RECORDER_GET_PRIVATE (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_STATE:
+      g_value_set_enum (value, priv->state);
+      break;
+
+    case PROP_FILENAME:
+      g_value_set_string (value, priv->filename);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+tb_sound_recorder_set_property (GObject      *gobject,
+                                guint         prop_id,
+                                const GValue *value,
+                                GParamSpec   *pspec)
+{
+  TbSoundRecorderPrivate *priv;
+  
+  priv = TB_SOUND_RECORDER_GET_PRIVATE (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_FILENAME:
+      tb_sound_recorder_set_filename (TB_SOUND_RECORDER (gobject),
+                                      g_value_get_string (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+tb_sound_recorder_class_init (TbSoundRecorderClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (TbSoundRecorderPrivate));
+
+  gobject_class->get_property = tb_sound_recorder_get_property;
+  gobject_class->set_property = tb_sound_recorder_set_property;
+  gobject_class->dispose = tb_sound_recorder_dispose;
+  gobject_class->finalize = tb_sound_recorder_finalize;
+
+  g_object_class_install_property
+                 (gobject_class,
+                  PROP_STATE,
+                  g_param_spec_enum ("state",
+                                     "State",
+                                     "State of the sound recorder",
+                                     TB_TYPE_SOUND_RECORDER_STATE,
+                                     TB_SOUND_RECORDER_STATE_UNKNOWN,
+                                     G_PARAM_READABLE));
+
+  g_object_class_install_property
+                 (gobject_class,
+                  PROP_FILENAME,
+                  g_param_spec_string ("filename",
+                                       "Filename",
+                                       "Filename to save sound to",
+                                       NULL,
+                                       G_PARAM_READWRITE |
+                                       G_PARAM_CONSTRUCT));
+}
+
+static void
+tb_sound_recorder_init (TbSoundRecorder *recorder)
+{
+  TbSoundRecorderPrivate *priv;
+
+  recorder->priv = TB_SOUND_RECORDER_GET_PRIVATE (recorder);
+
+  recorder->priv->state = TB_SOUND_RECORDER_STATE_UNKNOWN;
+  recorder->priv->filename = NULL;
+  recorder->priv->pipeline = NULL;
+  recorder->priv->bus = NULL;
+}
+
+void
+tb_sound_recorder_start (TbSoundRecorder *recorder)
+{
+  TbSoundRecorderPrivate *priv;
+
+  g_return_if_fail (TB_IS_SOUND_RECORDER (recorder));
+
+  priv = TB_SOUND_RECORDER_GET_PRIVATE (recorder);
+
+  if (tb_sound_recorder_ensure_pipeline (recorder))
+    gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
+}
+
+void
+tb_sound_recorder_stop (TbSoundRecorder *recorder)
+{
+  TbSoundRecorderPrivate *priv;
+  GstElement *source;
+
+  g_return_if_fail (TB_IS_SOUND_RECORDER (recorder));
+
+  priv = TB_SOUND_RECORDER_GET_PRIVATE (recorder);
+
+  if (priv->pipeline == NULL)
+    return;
+
+  gst_element_send_event (priv->pipeline, gst_event_new_eos());
+}
diff --git a/src/tb/tb-sound-recorder.h b/src/tb/tb-sound-recorder.h
new file mode 100644
index 0000000..31199ca
--- /dev/null
+++ b/src/tb/tb-sound-recorder.h
@@ -0,0 +1,47 @@
+#ifndef __TB_SOUND_RECORDER_H__
+#define __TB_SOUND_RECORDER_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define TB_TYPE_SOUND_RECORDER            (tb_sound_recorder_get_type ())
+#define TB_SOUND_RECORDER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), TB_TYPE_SOUND_RECORDER, TbSoundRecorder))
+#define TB_IS_SOUND_RECORDER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TB_TYPE_SOUND_RECORDER))
+#define TB_SOUND_RECORDER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  TB_TYPE_SOUND_RECORDER, TbSoundRecorderClass))
+#define TB_IS_SOUND_RECORDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  TB_TYPE_SOUND_RECORDER))
+#define TB_SOUND_RECORDER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  TB_TYPE_SOUND_RECORDER, TbSoundRecorderClass))
+
+typedef struct _TbSoundRecorder          TbSoundRecorder;
+typedef struct _TbSoundRecorderPrivate   TbSoundRecorderPrivate;
+typedef struct _TbSoundRecorderClass     TbSoundRecorderClass;
+
+typedef enum
+{
+  TB_SOUND_RECORDER_STATE_UNKNOWN   = 0,
+  TB_SOUND_RECORDER_STATE_IDLE      = 1,
+  TB_SOUND_RECORDER_STATE_RECORDING = 2,
+  TB_SOUND_RECORDER_STATE_DONE      = 3,
+  TB_SOUND_RECORDER_STATE_ERROR     = 4
+} TbSoundRecorderState;
+
+struct _TbSoundRecorder
+{
+  GObject parent_instance;
+
+  TbSoundRecorderPrivate *priv;
+};
+
+struct _TbSoundRecorderClass
+{
+  GObjectClass parent_class;
+};
+
+GType    tb_sound_recorder_get_type     (void) G_GNUC_CONST;
+
+void     tb_sound_recorder_start        (TbSoundRecorder *recorder);
+void     tb_sound_recorder_stop         (TbSoundRecorder *recorder);
+
+G_END_DECLS
+
+#endif /* __TB_SOUND_RECORDER_H__ */



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