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 |
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 |