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