gst_plugins_base/gst-libs/gst/audio/gstaudiosink.c
changeset 16 8e837d1bf446
parent 0 0e761a78d257
child 30 7e817e7e631c
equal deleted inserted replaced
15:4b0c6ed43234 16:8e837d1bf446
    69 
    69 
    70 #include <string.h>
    70 #include <string.h>
    71 
    71 
    72 #include "gstaudiosink.h"
    72 #include "gstaudiosink.h"
    73 
    73 
    74 #ifdef __SYMBIAN32__
       
    75 #include <glib_global.h>
       
    76 #endif
       
    77 
       
    78 GST_DEBUG_CATEGORY_STATIC (gst_audio_sink_debug);
    74 GST_DEBUG_CATEGORY_STATIC (gst_audio_sink_debug);
    79 #define GST_CAT_DEFAULT gst_audio_sink_debug
    75 #define GST_CAT_DEFAULT gst_audio_sink_debug
    80 
    76 
    81 #define GST_TYPE_AUDIORING_BUFFER        \
    77 #define GST_TYPE_AUDIORING_BUFFER        \
    82         (gst_audioringbuffer_get_type())
    78         (gst_audioringbuffer_get_type())
   131 static gboolean gst_audioringbuffer_release (GstRingBuffer * buf);
   127 static gboolean gst_audioringbuffer_release (GstRingBuffer * buf);
   132 static gboolean gst_audioringbuffer_start (GstRingBuffer * buf);
   128 static gboolean gst_audioringbuffer_start (GstRingBuffer * buf);
   133 static gboolean gst_audioringbuffer_pause (GstRingBuffer * buf);
   129 static gboolean gst_audioringbuffer_pause (GstRingBuffer * buf);
   134 static gboolean gst_audioringbuffer_stop (GstRingBuffer * buf);
   130 static gboolean gst_audioringbuffer_stop (GstRingBuffer * buf);
   135 static guint gst_audioringbuffer_delay (GstRingBuffer * buf);
   131 static guint gst_audioringbuffer_delay (GstRingBuffer * buf);
       
   132 static gboolean gst_audioringbuffer_activate (GstRingBuffer * buf,
       
   133     gboolean active);
   136 
   134 
   137 /* ringbuffer abstract base class */
   135 /* ringbuffer abstract base class */
   138 static GType
   136 static GType
   139 gst_audioringbuffer_get_type (void)
   137 gst_audioringbuffer_get_type (void)
   140 {
   138 {
   189   gstringbuffer_class->pause = GST_DEBUG_FUNCPTR (gst_audioringbuffer_pause);
   187   gstringbuffer_class->pause = GST_DEBUG_FUNCPTR (gst_audioringbuffer_pause);
   190   gstringbuffer_class->resume = GST_DEBUG_FUNCPTR (gst_audioringbuffer_start);
   188   gstringbuffer_class->resume = GST_DEBUG_FUNCPTR (gst_audioringbuffer_start);
   191   gstringbuffer_class->stop = GST_DEBUG_FUNCPTR (gst_audioringbuffer_stop);
   189   gstringbuffer_class->stop = GST_DEBUG_FUNCPTR (gst_audioringbuffer_stop);
   192 
   190 
   193   gstringbuffer_class->delay = GST_DEBUG_FUNCPTR (gst_audioringbuffer_delay);
   191   gstringbuffer_class->delay = GST_DEBUG_FUNCPTR (gst_audioringbuffer_delay);
       
   192   gstringbuffer_class->activate =
       
   193       GST_DEBUG_FUNCPTR (gst_audioringbuffer_activate);
   194 }
   194 }
   195 
   195 
   196 typedef guint (*WriteFunc) (GstAudioSink * sink, gpointer data, guint length);
   196 typedef guint (*WriteFunc) (GstAudioSink * sink, gpointer data, guint length);
   197 
   197 
   198 /* this internal thread does nothing else but write samples to the audio device.
   198 /* this internal thread does nothing else but write samples to the audio device.
   205 {
   205 {
   206   GstAudioSink *sink;
   206   GstAudioSink *sink;
   207   GstAudioSinkClass *csink;
   207   GstAudioSinkClass *csink;
   208   GstAudioRingBuffer *abuf = GST_AUDIORING_BUFFER_CAST (buf);
   208   GstAudioRingBuffer *abuf = GST_AUDIORING_BUFFER_CAST (buf);
   209   WriteFunc writefunc;
   209   WriteFunc writefunc;
       
   210   GstMessage *message;
       
   211   GValue val = { 0 };
   210 
   212 
   211   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
   213   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
   212   csink = GST_AUDIO_SINK_GET_CLASS (sink);
   214   csink = GST_AUDIO_SINK_GET_CLASS (sink);
   213 
   215 
   214   GST_DEBUG_OBJECT (sink, "enter thread");
   216   GST_DEBUG_OBJECT (sink, "enter thread");
       
   217 
       
   218   GST_OBJECT_LOCK (abuf);
       
   219   GST_DEBUG_OBJECT (sink, "signal wait");
       
   220   GST_AUDIORING_BUFFER_SIGNAL (buf);
       
   221   GST_OBJECT_UNLOCK (abuf);
   215 
   222 
   216   writefunc = csink->write;
   223   writefunc = csink->write;
   217   if (writefunc == NULL)
   224   if (writefunc == NULL)
   218     goto no_function;
   225     goto no_function;
       
   226 
       
   227   g_value_init (&val, G_TYPE_POINTER);
       
   228   g_value_set_pointer (&val, sink->thread);
       
   229   message = gst_message_new_stream_status (GST_OBJECT_CAST (buf),
       
   230       GST_STREAM_STATUS_TYPE_ENTER, GST_ELEMENT_CAST (sink));
       
   231   gst_message_set_stream_status_object (message, &val);
       
   232   GST_DEBUG_OBJECT (sink, "posting ENTER stream status");
       
   233   gst_element_post_message (GST_ELEMENT_CAST (sink), message);
   219 
   234 
   220   while (TRUE) {
   235   while (TRUE) {
   221     gint left, len;
   236     gint left, len;
   222     guint8 *readptr;
   237     guint8 *readptr;
   223     gint readseg;
   238     gint readseg;
   224 
   239 
       
   240     /* buffer must be started */
   225     if (gst_ring_buffer_prepare_read (buf, &readseg, &readptr, &len)) {
   241     if (gst_ring_buffer_prepare_read (buf, &readseg, &readptr, &len)) {
   226       gint written = 0;
   242       gint written;
   227 
   243 
   228       left = len;
   244       left = len;
   229       do {
   245       do {
   230         written = writefunc (sink, readptr + written, left);
   246         written = writefunc (sink, readptr, left);
   231         GST_LOG_OBJECT (sink, "transfered %d bytes of %d from segment %d",
   247         GST_LOG_OBJECT (sink, "transfered %d bytes of %d from segment %d",
   232             written, left, readseg);
   248             written, left, readseg);
   233         if (written < 0 || written > left) {
   249         if (written < 0 || written > left) {
       
   250           /* might not be critical, it e.g. happens when aborting playback */
   234           GST_WARNING_OBJECT (sink,
   251           GST_WARNING_OBJECT (sink,
   235               "error writing data (reason: %s), skipping segment",
   252               "error writing data in %s (reason: %s), skipping segment (left: %d, written: %d)",
   236               g_strerror (errno));
   253               GST_DEBUG_FUNCPTR_NAME (writefunc),
       
   254               (errno > 1 ? g_strerror (errno) : "unknown"), left, written);
   237           break;
   255           break;
   238         }
   256         }
   239         left -= written;
   257         left -= written;
       
   258         readptr += written;
   240       } while (left > 0);
   259       } while (left > 0);
   241 
   260 
   242       /* clear written samples */
   261       /* clear written samples */
   243       gst_ring_buffer_clear (buf, readseg);
   262       gst_ring_buffer_clear (buf, readseg);
   244 
   263 
   257         goto stop_running;
   276         goto stop_running;
   258       GST_DEBUG_OBJECT (sink, "continue running");
   277       GST_DEBUG_OBJECT (sink, "continue running");
   259       GST_OBJECT_UNLOCK (abuf);
   278       GST_OBJECT_UNLOCK (abuf);
   260     }
   279     }
   261   }
   280   }
   262   GST_DEBUG_OBJECT (sink, "exit thread");
   281 
   263 
   282   /* Will never be reached */
       
   283   g_assert_not_reached ();
   264   return;
   284   return;
   265 
   285 
   266   /* ERROR */
   286   /* ERROR */
   267 no_function:
   287 no_function:
   268   {
   288   {
   271   }
   291   }
   272 stop_running:
   292 stop_running:
   273   {
   293   {
   274     GST_OBJECT_UNLOCK (abuf);
   294     GST_OBJECT_UNLOCK (abuf);
   275     GST_DEBUG_OBJECT (sink, "stop running, exit thread");
   295     GST_DEBUG_OBJECT (sink, "stop running, exit thread");
       
   296     message = gst_message_new_stream_status (GST_OBJECT_CAST (buf),
       
   297         GST_STREAM_STATUS_TYPE_LEAVE, GST_ELEMENT_CAST (sink));
       
   298     gst_message_set_stream_status_object (message, &val);
       
   299     GST_DEBUG_OBJECT (sink, "posting LEAVE stream status");
       
   300     gst_element_post_message (GST_ELEMENT_CAST (sink), message);
   276     return;
   301     return;
   277   }
   302   }
   278 }
   303 }
   279 
   304 
   280 static void
   305 static void
   356 static gboolean
   381 static gboolean
   357 gst_audioringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
   382 gst_audioringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
   358 {
   383 {
   359   GstAudioSink *sink;
   384   GstAudioSink *sink;
   360   GstAudioSinkClass *csink;
   385   GstAudioSinkClass *csink;
   361   GstAudioRingBuffer *abuf;
       
   362   gboolean result = FALSE;
   386   gboolean result = FALSE;
   363 
   387 
   364   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
   388   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
   365   csink = GST_AUDIO_SINK_GET_CLASS (sink);
   389   csink = GST_AUDIO_SINK_GET_CLASS (sink);
   366 
   390 
   367   if (csink->prepare)
   391   if (csink->prepare)
   368     result = csink->prepare (sink, spec);
   392     result = csink->prepare (sink, spec);
   369 
       
   370   if (!result)
   393   if (!result)
   371     goto could_not_prepare;
   394     goto could_not_prepare;
   372 
   395 
   373   /* allocate one more segment as we need some headroom */
   396   /* set latency to one more segment as we need some headroom */
   374   spec->segtotal++;
   397   spec->seglatency = spec->segtotal + 1;
   375 
   398 
   376   buf->data = gst_buffer_new_and_alloc (spec->segtotal * spec->segsize);
   399   buf->data = gst_buffer_new_and_alloc (spec->segtotal * spec->segsize);
   377   memset (GST_BUFFER_DATA (buf->data), 0, GST_BUFFER_SIZE (buf->data));
   400   memset (GST_BUFFER_DATA (buf->data), 0, GST_BUFFER_SIZE (buf->data));
   378 
   401 
   379   abuf = GST_AUDIORING_BUFFER_CAST (buf);
   402   return TRUE;
   380   abuf->running = TRUE;
   403 
   381 
   404   /* ERRORS */
   382   sink->thread =
       
   383       g_thread_create ((GThreadFunc) audioringbuffer_thread_func, buf, TRUE,
       
   384       NULL);
       
   385   GST_AUDIORING_BUFFER_WAIT (buf);
       
   386 
       
   387   return result;
       
   388 
       
   389 could_not_prepare:
   405 could_not_prepare:
   390   {
   406   {
   391     GST_DEBUG_OBJECT (sink, "could not prepare device");
   407     GST_DEBUG_OBJECT (sink, "could not prepare device");
   392     return FALSE;
   408     return FALSE;
   393   }
   409   }
   394 }
   410 }
   395 
   411 
       
   412 static gboolean
       
   413 gst_audioringbuffer_activate (GstRingBuffer * buf, gboolean active)
       
   414 {
       
   415   GstAudioSink *sink;
       
   416   GstAudioRingBuffer *abuf;
       
   417   GError *error = NULL;
       
   418 
       
   419   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
       
   420   abuf = GST_AUDIORING_BUFFER_CAST (buf);
       
   421 
       
   422   if (active) {
       
   423     abuf->running = TRUE;
       
   424 
       
   425     GST_DEBUG_OBJECT (sink, "starting thread");
       
   426     sink->thread =
       
   427         g_thread_create ((GThreadFunc) audioringbuffer_thread_func, buf, TRUE,
       
   428         &error);
       
   429     if (!sink->thread || error != NULL)
       
   430       goto thread_failed;
       
   431 
       
   432     GST_DEBUG_OBJECT (sink, "waiting for thread");
       
   433     /* the object lock is taken */
       
   434     GST_AUDIORING_BUFFER_WAIT (buf);
       
   435     GST_DEBUG_OBJECT (sink, "thread is started");
       
   436   } else {
       
   437     abuf->running = FALSE;
       
   438     GST_DEBUG_OBJECT (sink, "signal wait");
       
   439     GST_AUDIORING_BUFFER_SIGNAL (buf);
       
   440 
       
   441     GST_OBJECT_UNLOCK (buf);
       
   442 
       
   443     /* join the thread */
       
   444     g_thread_join (sink->thread);
       
   445 
       
   446     GST_OBJECT_LOCK (buf);
       
   447   }
       
   448   return TRUE;
       
   449 
       
   450   /* ERRORS */
       
   451 thread_failed:
       
   452   {
       
   453     if (error)
       
   454       GST_ERROR_OBJECT (sink, "could not create thread %s", error->message);
       
   455     else
       
   456       GST_ERROR_OBJECT (sink, "could not create thread for unknown reason");
       
   457     return FALSE;
       
   458   }
       
   459 }
       
   460 
   396 /* function is called with LOCK */
   461 /* function is called with LOCK */
   397 static gboolean
   462 static gboolean
   398 gst_audioringbuffer_release (GstRingBuffer * buf)
   463 gst_audioringbuffer_release (GstRingBuffer * buf)
   399 {
   464 {
   400   GstAudioSink *sink;
   465   GstAudioSink *sink;
   403   gboolean result = FALSE;
   468   gboolean result = FALSE;
   404 
   469 
   405   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
   470   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
   406   csink = GST_AUDIO_SINK_GET_CLASS (sink);
   471   csink = GST_AUDIO_SINK_GET_CLASS (sink);
   407   abuf = GST_AUDIORING_BUFFER_CAST (buf);
   472   abuf = GST_AUDIORING_BUFFER_CAST (buf);
   408 
       
   409   abuf->running = FALSE;
       
   410   GST_DEBUG_OBJECT (sink, "signal wait");
       
   411   GST_AUDIORING_BUFFER_SIGNAL (buf);
       
   412   GST_OBJECT_UNLOCK (buf);
       
   413 
       
   414   /* join the thread */
       
   415   g_thread_join (sink->thread);
       
   416 
       
   417   GST_OBJECT_LOCK (buf);
       
   418 
   473 
   419   /* free the buffer */
   474   /* free the buffer */
   420   gst_buffer_unref (buf->data);
   475   gst_buffer_unref (buf->data);
   421   buf->data = NULL;
   476   buf->data = NULL;
   422 
   477 
   423   if (csink->unprepare)
   478   if (csink->unprepare)
   424     result = csink->unprepare (sink);
   479     result = csink->unprepare (sink);
   425 
   480 
   426   if (!result)
   481   if (!result)
   427     goto could_not_unprepare;
   482     goto could_not_unprepare;
       
   483 
       
   484   GST_DEBUG_OBJECT (sink, "unprepared");
   428 
   485 
   429   return result;
   486   return result;
   430 
   487 
   431 could_not_unprepare:
   488 could_not_unprepare:
   432   {
   489   {
   482   if (csink->reset) {
   539   if (csink->reset) {
   483     GST_DEBUG_OBJECT (sink, "reset...");
   540     GST_DEBUG_OBJECT (sink, "reset...");
   484     csink->reset (sink);
   541     csink->reset (sink);
   485     GST_DEBUG_OBJECT (sink, "reset done");
   542     GST_DEBUG_OBJECT (sink, "reset done");
   486   }
   543   }
   487 
   544 #if 0
   488   if (abuf->running) {
   545   if (abuf->running) {
   489     GST_DEBUG_OBJECT (sink, "stop, waiting...");
   546     GST_DEBUG_OBJECT (sink, "stop, waiting...");
   490     GST_AUDIORING_BUFFER_WAIT (buf);
   547     GST_AUDIORING_BUFFER_WAIT (buf);
   491     GST_DEBUG_OBJECT (sink, "stopped");
   548     GST_DEBUG_OBJECT (sink, "stopped");
   492   }
   549   }
       
   550 #endif
   493 
   551 
   494   return TRUE;
   552   return TRUE;
   495 }
   553 }
   496 
   554 
   497 static guint
   555 static guint
   549   gstbasesink_class = (GstBaseSinkClass *) klass;
   607   gstbasesink_class = (GstBaseSinkClass *) klass;
   550   gstbaseaudiosink_class = (GstBaseAudioSinkClass *) klass;
   608   gstbaseaudiosink_class = (GstBaseAudioSinkClass *) klass;
   551 
   609 
   552   gstbaseaudiosink_class->create_ringbuffer =
   610   gstbaseaudiosink_class->create_ringbuffer =
   553       GST_DEBUG_FUNCPTR (gst_audio_sink_create_ringbuffer);
   611       GST_DEBUG_FUNCPTR (gst_audio_sink_create_ringbuffer);
       
   612 
       
   613   g_type_class_ref (GST_TYPE_AUDIORING_BUFFER);
   554 }
   614 }
   555 
   615 
   556 static void
   616 static void
   557 gst_audio_sink_init (GstAudioSink * audiosink, GstAudioSinkClass * g_class)
   617 gst_audio_sink_init (GstAudioSink * audiosink, GstAudioSinkClass * g_class)
   558 {
   618 {