gst_plugins_base/gst-libs/gst/audio/gstaudiosink.c
changeset 8 4a7fac7dd34a
parent 0 0e761a78d257
child 30 7e817e7e631c
--- a/gst_plugins_base/gst-libs/gst/audio/gstaudiosink.c	Fri Mar 19 09:35:09 2010 +0200
+++ b/gst_plugins_base/gst-libs/gst/audio/gstaudiosink.c	Fri Apr 16 15:15:52 2010 +0300
@@ -71,10 +71,6 @@
 
 #include "gstaudiosink.h"
 
-#ifdef __SYMBIAN32__
-#include <glib_global.h>
-#endif
-
 GST_DEBUG_CATEGORY_STATIC (gst_audio_sink_debug);
 #define GST_CAT_DEFAULT gst_audio_sink_debug
 
@@ -133,6 +129,8 @@
 static gboolean gst_audioringbuffer_pause (GstRingBuffer * buf);
 static gboolean gst_audioringbuffer_stop (GstRingBuffer * buf);
 static guint gst_audioringbuffer_delay (GstRingBuffer * buf);
+static gboolean gst_audioringbuffer_activate (GstRingBuffer * buf,
+    gboolean active);
 
 /* ringbuffer abstract base class */
 static GType
@@ -191,6 +189,8 @@
   gstringbuffer_class->stop = GST_DEBUG_FUNCPTR (gst_audioringbuffer_stop);
 
   gstringbuffer_class->delay = GST_DEBUG_FUNCPTR (gst_audioringbuffer_delay);
+  gstringbuffer_class->activate =
+      GST_DEBUG_FUNCPTR (gst_audioringbuffer_activate);
 }
 
 typedef guint (*WriteFunc) (GstAudioSink * sink, gpointer data, guint length);
@@ -207,36 +207,55 @@
   GstAudioSinkClass *csink;
   GstAudioRingBuffer *abuf = GST_AUDIORING_BUFFER_CAST (buf);
   WriteFunc writefunc;
+  GstMessage *message;
+  GValue val = { 0 };
 
   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
   csink = GST_AUDIO_SINK_GET_CLASS (sink);
 
   GST_DEBUG_OBJECT (sink, "enter thread");
 
+  GST_OBJECT_LOCK (abuf);
+  GST_DEBUG_OBJECT (sink, "signal wait");
+  GST_AUDIORING_BUFFER_SIGNAL (buf);
+  GST_OBJECT_UNLOCK (abuf);
+
   writefunc = csink->write;
   if (writefunc == NULL)
     goto no_function;
 
+  g_value_init (&val, G_TYPE_POINTER);
+  g_value_set_pointer (&val, sink->thread);
+  message = gst_message_new_stream_status (GST_OBJECT_CAST (buf),
+      GST_STREAM_STATUS_TYPE_ENTER, GST_ELEMENT_CAST (sink));
+  gst_message_set_stream_status_object (message, &val);
+  GST_DEBUG_OBJECT (sink, "posting ENTER stream status");
+  gst_element_post_message (GST_ELEMENT_CAST (sink), message);
+
   while (TRUE) {
     gint left, len;
     guint8 *readptr;
     gint readseg;
 
+    /* buffer must be started */
     if (gst_ring_buffer_prepare_read (buf, &readseg, &readptr, &len)) {
-      gint written = 0;
+      gint written;
 
       left = len;
       do {
-        written = writefunc (sink, readptr + written, left);
+        written = writefunc (sink, readptr, left);
         GST_LOG_OBJECT (sink, "transfered %d bytes of %d from segment %d",
             written, left, readseg);
         if (written < 0 || written > left) {
+          /* might not be critical, it e.g. happens when aborting playback */
           GST_WARNING_OBJECT (sink,
-              "error writing data (reason: %s), skipping segment",
-              g_strerror (errno));
+              "error writing data in %s (reason: %s), skipping segment (left: %d, written: %d)",
+              GST_DEBUG_FUNCPTR_NAME (writefunc),
+              (errno > 1 ? g_strerror (errno) : "unknown"), left, written);
           break;
         }
         left -= written;
+        readptr += written;
       } while (left > 0);
 
       /* clear written samples */
@@ -259,8 +278,9 @@
       GST_OBJECT_UNLOCK (abuf);
     }
   }
-  GST_DEBUG_OBJECT (sink, "exit thread");
 
+  /* Will never be reached */
+  g_assert_not_reached ();
   return;
 
   /* ERROR */
@@ -273,6 +293,11 @@
   {
     GST_OBJECT_UNLOCK (abuf);
     GST_DEBUG_OBJECT (sink, "stop running, exit thread");
+    message = gst_message_new_stream_status (GST_OBJECT_CAST (buf),
+        GST_STREAM_STATUS_TYPE_LEAVE, GST_ELEMENT_CAST (sink));
+    gst_message_set_stream_status_object (message, &val);
+    GST_DEBUG_OBJECT (sink, "posting LEAVE stream status");
+    gst_element_post_message (GST_ELEMENT_CAST (sink), message);
     return;
   }
 }
@@ -358,7 +383,6 @@
 {
   GstAudioSink *sink;
   GstAudioSinkClass *csink;
-  GstAudioRingBuffer *abuf;
   gboolean result = FALSE;
 
   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
@@ -366,26 +390,18 @@
 
   if (csink->prepare)
     result = csink->prepare (sink, spec);
-
   if (!result)
     goto could_not_prepare;
 
-  /* allocate one more segment as we need some headroom */
-  spec->segtotal++;
+  /* set latency to one more segment as we need some headroom */
+  spec->seglatency = spec->segtotal + 1;
 
   buf->data = gst_buffer_new_and_alloc (spec->segtotal * spec->segsize);
   memset (GST_BUFFER_DATA (buf->data), 0, GST_BUFFER_SIZE (buf->data));
 
-  abuf = GST_AUDIORING_BUFFER_CAST (buf);
-  abuf->running = TRUE;
+  return TRUE;
 
-  sink->thread =
-      g_thread_create ((GThreadFunc) audioringbuffer_thread_func, buf, TRUE,
-      NULL);
-  GST_AUDIORING_BUFFER_WAIT (buf);
-
-  return result;
-
+  /* ERRORS */
 could_not_prepare:
   {
     GST_DEBUG_OBJECT (sink, "could not prepare device");
@@ -393,6 +409,55 @@
   }
 }
 
+static gboolean
+gst_audioringbuffer_activate (GstRingBuffer * buf, gboolean active)
+{
+  GstAudioSink *sink;
+  GstAudioRingBuffer *abuf;
+  GError *error = NULL;
+
+  sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
+  abuf = GST_AUDIORING_BUFFER_CAST (buf);
+
+  if (active) {
+    abuf->running = TRUE;
+
+    GST_DEBUG_OBJECT (sink, "starting thread");
+    sink->thread =
+        g_thread_create ((GThreadFunc) audioringbuffer_thread_func, buf, TRUE,
+        &error);
+    if (!sink->thread || error != NULL)
+      goto thread_failed;
+
+    GST_DEBUG_OBJECT (sink, "waiting for thread");
+    /* the object lock is taken */
+    GST_AUDIORING_BUFFER_WAIT (buf);
+    GST_DEBUG_OBJECT (sink, "thread is started");
+  } else {
+    abuf->running = FALSE;
+    GST_DEBUG_OBJECT (sink, "signal wait");
+    GST_AUDIORING_BUFFER_SIGNAL (buf);
+
+    GST_OBJECT_UNLOCK (buf);
+
+    /* join the thread */
+    g_thread_join (sink->thread);
+
+    GST_OBJECT_LOCK (buf);
+  }
+  return TRUE;
+
+  /* ERRORS */
+thread_failed:
+  {
+    if (error)
+      GST_ERROR_OBJECT (sink, "could not create thread %s", error->message);
+    else
+      GST_ERROR_OBJECT (sink, "could not create thread for unknown reason");
+    return FALSE;
+  }
+}
+
 /* function is called with LOCK */
 static gboolean
 gst_audioringbuffer_release (GstRingBuffer * buf)
@@ -406,16 +471,6 @@
   csink = GST_AUDIO_SINK_GET_CLASS (sink);
   abuf = GST_AUDIORING_BUFFER_CAST (buf);
 
-  abuf->running = FALSE;
-  GST_DEBUG_OBJECT (sink, "signal wait");
-  GST_AUDIORING_BUFFER_SIGNAL (buf);
-  GST_OBJECT_UNLOCK (buf);
-
-  /* join the thread */
-  g_thread_join (sink->thread);
-
-  GST_OBJECT_LOCK (buf);
-
   /* free the buffer */
   gst_buffer_unref (buf->data);
   buf->data = NULL;
@@ -426,6 +481,8 @@
   if (!result)
     goto could_not_unprepare;
 
+  GST_DEBUG_OBJECT (sink, "unprepared");
+
   return result;
 
 could_not_unprepare:
@@ -484,12 +541,13 @@
     csink->reset (sink);
     GST_DEBUG_OBJECT (sink, "reset done");
   }
-
+#if 0
   if (abuf->running) {
     GST_DEBUG_OBJECT (sink, "stop, waiting...");
     GST_AUDIORING_BUFFER_WAIT (buf);
     GST_DEBUG_OBJECT (sink, "stopped");
   }
+#endif
 
   return TRUE;
 }
@@ -551,6 +609,8 @@
 
   gstbaseaudiosink_class->create_ringbuffer =
       GST_DEBUG_FUNCPTR (gst_audio_sink_create_ringbuffer);
+
+  g_type_class_ref (GST_TYPE_AUDIORING_BUFFER);
 }
 
 static void