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