57 const GValue * value, GParamSpec * pspec); |
61 const GValue * value, GParamSpec * pspec); |
58 |
62 |
59 static GstCaps *gst_devsound_sink_getcaps(GstBaseSink * bsink); |
63 static GstCaps *gst_devsound_sink_getcaps(GstBaseSink * bsink); |
60 static gboolean gst_devsound_sink_setcaps(GstBaseSink *bsink, GstCaps *caps); |
64 static gboolean gst_devsound_sink_setcaps(GstBaseSink *bsink, GstCaps *caps); |
61 |
65 |
62 |
|
63 static gboolean gst_devsound_sink_event(GstBaseSink * asink, GstEvent * event); |
66 static gboolean gst_devsound_sink_event(GstBaseSink * asink, GstEvent * event); |
|
67 #ifdef AV_SYNC |
|
68 static void gst_devsound_sink_get_times(GstBaseSink * bsink, GstBuffer * buffer, |
|
69 GstClockTime * start, GstClockTime * end); |
|
70 static GstClock *gst_devsound_sink_provide_clock (GstElement * element); |
|
71 static GstClockTime gst_devsound_sink_get_time (GstClock * clock, |
|
72 gpointer user_data); |
|
73 #endif /*AV_SYNC*/ |
|
74 |
|
75 static GstStateChangeReturn gst_devsound_sink_change_state (GstElement * element, |
|
76 GstStateChange transition); |
|
77 |
64 |
78 |
65 static void *StartDevSoundThread(void *threadid); |
79 static void *StartDevSoundThread(void *threadid); |
66 |
|
67 |
80 |
68 //Error concealment interface impl |
81 //Error concealment interface impl |
69 static void gst_error_concealment_handler_init (gpointer g_iface, |
82 static void gst_error_concealment_handler_init (gpointer g_iface, |
70 gpointer iface_data); |
83 gpointer iface_data); |
71 static gint gst_ConcealErrorForNextBuffer(); |
84 static gint gst_ConcealErrorForNextBuffer(); |
158 PROP_0, |
172 PROP_0, |
159 PROP_DEVICE, |
173 PROP_DEVICE, |
160 VOLUME, |
174 VOLUME, |
161 MAXVOLUME, |
175 MAXVOLUME, |
162 VOLUMERAMP, |
176 VOLUMERAMP, |
163 CHANNELS, |
177 /* CHANNELS,*/ |
164 LEFTBALANCE, |
178 LEFTBALANCE, |
165 RIGHTBALANCE, |
179 RIGHTBALANCE, |
166 RATE, |
180 /* RATE,*/ |
167 PRIORITY, |
181 PRIORITY, |
168 PREFERENCE, |
182 PREFERENCE, |
169 SAMPLESPLAYED, |
183 /* SAMPLESPLAYED,*/ |
170 FOURCC, //FOURCC is not needed |
184 /* FOURCC, //FOURCC is not needed*/ |
171 MIMETYPE, |
185 /* MIMETYPE,*/ |
172 OUTPUTDEVICE |
186 OUTPUTDEVICE |
173 }; |
187 }; |
174 |
188 |
175 enum command_to_consumer_thread_enum |
189 enum command_to_consumer_thread_enum |
176 { |
190 { |
177 OPEN = 2, |
191 OPEN = 2, |
178 WRITEDATA, |
192 PLAYING, |
|
193 PAUSE, |
|
194 RESUME, |
179 /*UPDATE,*/ |
195 /*UPDATE,*/ |
|
196 WAIT, |
180 CLOSE |
197 CLOSE |
181 }; |
198 }; |
182 enum command_to_consumer_thread_enum cmd; |
199 enum command_to_consumer_thread_enum cmd; |
183 |
200 |
184 static GstStaticPadTemplate devsoundsink_sink_factory= |
201 static GstStaticPadTemplate devsoundsink_sink_factory= |
185 GST_STATIC_PAD_TEMPLATE ("sink", |
202 GST_STATIC_PAD_TEMPLATE ("sink", |
186 GST_PAD_SINK, |
203 GST_PAD_SINK, |
187 GST_PAD_ALWAYS, |
204 GST_PAD_ALWAYS, |
188 GST_STATIC_CAPS ("audio/x-raw-int, " |
205 GST_STATIC_CAPS ("audio/x-raw-int, " "endianness = (int) { " G_STRINGIFY (G_BYTE_ORDER) " }, " "signed = (boolean) TRUE, " "width = (int) 16, " "depth = (int) 16, " "rate = (int) [ 8000, 48000 ]," "channels = (int) [ 1, 2 ]; " |
189 "endianness = (int) { " G_STRINGIFY (G_BYTE_ORDER) " }, " |
206 "audio/amr, " "rate = (int) 8000, " "channels = (int) 1 ; " |
190 "signed = (boolean) TRUE, " |
207 "audio/AMR, " "rate = (int) 8000, " "channels = (int) 1 ; " |
191 "width = (int) 16, " |
208 "audio/x-alaw, " "rate = (int) [ 8000, 48000 ], " "channels = (int) [ 1, 2 ]; " |
192 "depth = (int) 16, " |
209 "audio/g729, " "rate = (int) [ 8000, 48000 ], " "channels = (int) [ 1, 2 ]; " |
193 "rate = (int) [ 8000, 48000 ]," |
210 "audio/mp3, " "rate = (int) [ 8000, 48000 ], " "channels = (int) [ 1, 2 ]; " |
194 "channels = (int) [ 1, 2 ]; " |
211 "audio/ilbc, " "rate = (int) [ 8000, 48000 ], " "channels = (int) [ 1, 2 ]; " |
195 "audio/amr, " |
212 "audio/x-mulaw, " "rate = (int) [ 8000, 48000 ], " "channels = (int) [ 1, 2 ]") |
196 //"width = (int) 8, " |
|
197 //"depth = (int) 8, " |
|
198 "rate = (int) 8000, " |
|
199 "channels = (int) 1 ; " |
|
200 "audio/x-alaw, " |
|
201 "rate = (int) [ 8000, 48000 ], " |
|
202 "channels = (int) [ 1, 2 ]; " |
|
203 "audio/g729, " |
|
204 "rate = (int) [ 8000, 48000 ], " |
|
205 "channels = (int) [ 1, 2 ]; " |
|
206 "audio/mp3, " |
|
207 "rate = (int) [ 8000, 48000 ], " |
|
208 "channels = (int) [ 1, 2 ]; " |
|
209 "audio/ilbc, " |
|
210 "rate = (int) [ 8000, 48000 ], " |
|
211 "channels = (int) [ 1, 2 ]; " |
|
212 "audio/x-mulaw, " |
|
213 "rate = (int) [ 8000, 48000 ], " |
|
214 "channels = (int) [ 1, 2 ]") |
|
215 ); |
213 ); |
216 |
214 |
217 static GstElementClass *parent_class= NULL; |
215 static GstElementClass *parent_class= NULL; |
218 |
216 |
219 GType gst_devsound_sink_get_type(void) |
217 GType gst_devsound_sink_get_type(void) |
346 -1, G_MAXINT, -1, G_PARAM_READWRITE)); |
353 -1, G_MAXINT, -1, G_PARAM_READWRITE)); |
347 |
354 |
348 g_object_class_install_property(gobject_class, RIGHTBALANCE, |
355 g_object_class_install_property(gobject_class, RIGHTBALANCE, |
349 g_param_spec_int("rightbalance", "Right Balance", "Right Balance", |
356 g_param_spec_int("rightbalance", "Right Balance", "Right Balance", |
350 -1, G_MAXINT, -1, G_PARAM_READWRITE)); |
357 -1, G_MAXINT, -1, G_PARAM_READWRITE)); |
351 |
358 /* |
352 g_object_class_install_property(gobject_class, SAMPLESPLAYED, |
359 g_object_class_install_property(gobject_class, SAMPLESPLAYED, |
353 g_param_spec_int("samplesplayed", "Samples Played", "Samples Played", |
360 g_param_spec_int("samplesplayed", "Samples Played", "Samples Played", |
354 -1, G_MAXINT, -1, G_PARAM_READABLE)); |
361 -1, G_MAXINT, -1, G_PARAM_READABLE)); |
355 |
362 */ |
356 g_object_class_install_property(gobject_class, PRIORITY, |
363 g_object_class_install_property(gobject_class, PRIORITY, |
357 g_param_spec_int("priority", "Priority", "Priority ", -1, |
364 g_param_spec_int("priority", "Priority", "Priority ", -1, |
358 G_MAXINT, -1, |
365 G_MAXINT, -1, |
359 G_PARAM_READWRITE)); |
366 G_PARAM_READWRITE)); |
360 |
367 |
361 g_object_class_install_property(gobject_class, PREFERENCE, |
368 g_object_class_install_property(gobject_class, PREFERENCE, |
362 g_param_spec_int("preference", "Preference", "Preference ", -1, |
369 g_param_spec_int("preference", "Preference", "Preference ", -1, |
363 G_MAXINT, -1, |
370 G_MAXINT, -1, |
364 G_PARAM_READWRITE)); |
371 G_PARAM_READWRITE)); |
365 |
372 /* |
366 g_object_class_install_property(gobject_class, RATE, |
373 g_object_class_install_property(gobject_class, RATE, |
367 g_param_spec_int("rate", "Rate", "Rate ", -1, |
374 g_param_spec_int("rate", "Rate", "Rate ", -1, |
368 G_MAXINT, -1, |
375 G_MAXINT, -1, |
369 G_PARAM_READWRITE)); |
376 G_PARAM_READWRITE)); |
370 |
377 |
371 g_object_class_install_property(gobject_class, CHANNELS, |
378 g_object_class_install_property(gobject_class, CHANNELS, |
372 g_param_spec_int("channels", "Channels", "Channels ", -1, |
379 g_param_spec_int("channels", "Channels", "Channels ", -1, |
373 G_MAXINT, -1, |
380 G_MAXINT, -1, |
374 G_PARAM_READWRITE)); |
381 G_PARAM_READWRITE)); |
375 |
382 */ |
376 g_object_class_install_property(gobject_class, OUTPUTDEVICE, |
383 g_object_class_install_property(gobject_class, OUTPUTDEVICE, |
377 g_param_spec_int("outputdevice", "Output Device", "Output Device ", -1, |
384 g_param_spec_int("outputdevice", "Output Device", "Output Device ", -1, |
378 G_MAXINT, -1, |
385 G_MAXINT, -1, |
379 G_PARAM_READWRITE)); |
386 G_PARAM_READWRITE)); |
380 |
387 |
|
388 #ifdef AV_SYNC |
|
389 gstelement_class->provide_clock = GST_DEBUG_FUNCPTR (gst_devsound_sink_provide_clock); |
|
390 #endif /*AV_SYNC*/ |
|
391 |
381 gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_sink_start); |
392 gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_sink_start); |
382 gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_sink_stop); |
393 gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_sink_stop); |
383 gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_sink_render); |
394 gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_sink_render); |
384 |
395 |
385 gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_devsound_sink_getcaps); |
396 gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_devsound_sink_getcaps); |
386 gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_devsound_sink_setcaps); |
397 gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_devsound_sink_setcaps); |
387 gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_devsound_sink_event); |
398 gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_devsound_sink_event); |
388 } |
399 #ifdef AV_SYNC |
389 |
400 gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_devsound_sink_get_times); |
390 static void gst_devsound_sink_init(GstDevsoundSink * devsoundsink) |
401 #endif /*AV_SYNC*/ |
391 { |
402 } |
392 GST_DEBUG_OBJECT(devsoundsink, "initializing devsoundsink"); |
403 |
393 devsoundsink->device = g_strdup(DEFAULT_DEVICE); |
404 static void gst_devsound_sink_init(GstDevsoundSink * dssink) |
394 devsoundsink->handle = NULL; |
405 { |
395 devsoundsink->preference = 0; //default=>EMdaPriorityPreferenceNone; |
406 GST_DEBUG_OBJECT(dssink, "initializing devsoundsink"); |
396 devsoundsink->priority = 0; //default=>EMdaPriorityNormal; |
407 dssink->device = g_strdup(DEFAULT_DEVICE); |
|
408 dssink->handle = NULL; |
|
409 dssink->preference = 0; //default=>EMdaPriorityPreferenceNone; |
|
410 dssink->priority = 0; //default=>EMdaPriorityNormal; |
|
411 #ifdef AV_SYNC |
|
412 dssink->time_or_samples_played = 0; |
|
413 dssink->timeplayedavailable = FALSE; |
|
414 /* Create the provided clock. */ |
|
415 dssink->clock = gst_audio_clock_new ("clock", gst_devsound_sink_get_time, dssink); |
|
416 #endif /*AV_SYNC*/ |
397 pthread_mutex_init(&ds_mutex, NULL); |
417 pthread_mutex_init(&ds_mutex, NULL); |
398 pthread_cond_init(&ds_condition, NULL); |
418 pthread_cond_init(&ds_condition, NULL); |
399 } |
419 } |
400 |
420 |
401 static void *StartDevSoundThread(void *threadarg) |
421 static void *StartDevSoundThread(void *threadarg) |
402 { |
422 { |
403 |
423 GstDevsoundSink *dssink; |
404 GstDevsoundSink *devsound; |
|
405 |
424 |
406 gint remainingDataLen = 0; |
425 gint remainingDataLen = 0; |
407 GstBuffer *buffer = NULL; |
426 GstBuffer *buffer = NULL; |
408 gboolean lastBufferSet=FALSE; |
427 gboolean lastBufferSet=FALSE; |
409 devsound = (GstDevsoundSink*) threadarg; |
428 dssink = (GstDevsoundSink*) threadarg; |
410 |
429 |
411 open_devsound(&(devsound->handle)); |
430 // TODO handle error here |
|
431 open_devsound(&(dssink->handle)); |
|
432 #ifdef AV_SYNC |
|
433 dssink->timeplayedavailable = is_timeplayed_supported(dssink->handle); |
|
434 #endif /*AV_SYNC*/ |
412 |
435 |
413 |
436 |
414 //get supported (in/out)put datatypes |
437 //get supported (in/out)put datatypes |
415 //from devsound to build caps |
438 //from devsound to build caps |
416 getsupporteddatatypes(devsound); |
439 getsupporteddatatypes(dssink); |
417 |
440 |
418 // TODO obtain mutex to update variable here??? |
441 // TODO obtain mutex to update variable here??? |
419 consumer_thread_state = CONSUMER_THREAD_INITIALIZED; |
442 consumer_thread_state = CONSUMER_THREAD_INITIALIZED; |
420 |
443 |
421 // Signal any waiting threads that consumer thread creation was successful. |
444 // Signal any waiting threads that consumer thread creation was successful. |
436 // without putting it to play state |
459 // without putting it to play state |
437 if ( cmd != CLOSE ) |
460 if ( cmd != CLOSE ) |
438 { |
461 { |
439 //TODO if there is preemption we have to somehow signal |
462 //TODO if there is preemption we have to somehow signal |
440 //the pipeline in the render |
463 //the pipeline in the render |
441 initialize_devsound(devsound); |
464 initialize_devsound(dssink); |
442 |
465 |
443 playinit(devsound->handle); |
466 playinit(dssink->handle); |
444 initproperties(devsound); |
467 dssink->eosreceived = FALSE; |
|
468 initproperties(dssink); |
445 } |
469 } |
446 while (1) |
470 while (1) |
447 { |
471 { |
448 switch (cmd) |
472 switch (cmd) |
449 { |
473 { |
450 case WRITEDATA: |
474 case PAUSE: |
|
475 pause_devsound(dssink); |
|
476 cmd = WAIT; |
|
477 break; |
|
478 |
|
479 case RESUME: |
|
480 resume_devsound(dssink); |
|
481 cmd = PLAYING; |
|
482 break; |
|
483 |
|
484 case WAIT: |
|
485 pthread_mutex_lock(&ds_mutex); |
|
486 pthread_cond_signal(&ds_condition); |
|
487 pthread_mutex_unlock(&ds_mutex); |
|
488 |
|
489 pthread_mutex_lock(&ds_mutex); |
|
490 pthread_cond_wait(&ds_condition, &ds_mutex); |
|
491 pthread_mutex_unlock(&ds_mutex); |
|
492 break; |
|
493 |
|
494 case PLAYING: |
451 { |
495 { |
452 pre_init_setconf(devsound); |
496 pre_init_setconf(dssink); |
453 gst_Apply_ErrorConcealment_Update(devsound); |
497 gst_Apply_ErrorConcealment_Update(dssink); |
454 gst_Apply_G711_Decoder_Update(devsound); |
498 gst_Apply_G711_Decoder_Update(dssink); |
455 gst_Apply_G729_Decoder_Update(devsound); |
499 gst_Apply_G729_Decoder_Update(dssink); |
456 gst_Apply_Ilbc_Decoder_Update(devsound); |
500 gst_Apply_Ilbc_Decoder_Update(dssink); |
457 |
501 |
458 // TODO we could do this in BTBF callback |
502 // TODO we could do this in BTBF callback |
459 populateproperties(devsound); |
503 populateproperties(dssink); |
460 |
504 get_PopulateIntfcProperties(dssink); |
461 framemodereq = devsound->framemodereq; |
505 |
462 g711cng = devsound->g711cng; |
|
463 ilbccng = devsound->ilbccng; |
|
464 output = devsound->output; |
|
465 |
|
466 if(buffer_queue->length > 0) |
506 if(buffer_queue->length > 0) |
467 { |
507 { |
468 if (remainingDataLen == 0) |
508 if (remainingDataLen == 0) |
469 { |
509 { |
470 // TODO enable lock and unlock |
510 // TODO enable lock and unlock |
471 GST_OBJECT_LOCK (devsound); |
511 GST_OBJECT_LOCK (dssink); |
472 buffer = GST_BUFFER_CAST(g_queue_peek_head(buffer_queue)); |
512 buffer = GST_BUFFER_CAST(g_queue_peek_head(buffer_queue)); |
473 GST_OBJECT_UNLOCK(devsound); |
513 GST_OBJECT_UNLOCK(dssink); |
474 remainingDataLen = GST_BUFFER_SIZE(buffer); |
514 remainingDataLen = GST_BUFFER_SIZE(buffer); |
475 } |
515 } |
476 |
516 |
477 lastBufferSet = GST_BUFFER_FLAG_IS_SET(buffer,GST_BUFFER_FLAG_LAST); |
517 lastBufferSet = GST_BUFFER_FLAG_IS_SET(buffer,GST_BUFFER_FLAG_LAST); |
478 remainingDataLen = write_data(devsound->handle, |
518 remainingDataLen = write_data(dssink->handle, |
479 GST_BUFFER_DATA(buffer) + (GST_BUFFER_SIZE(buffer) - remainingDataLen), |
519 GST_BUFFER_DATA(buffer) + (GST_BUFFER_SIZE(buffer) - remainingDataLen), |
480 remainingDataLen, |
520 remainingDataLen, |
481 lastBufferSet); |
521 lastBufferSet); |
482 |
522 |
483 if (remainingDataLen == 0) |
523 if (remainingDataLen == 0) |
484 { |
524 { |
485 GST_OBJECT_LOCK (devsound); |
525 GST_OBJECT_LOCK (dssink); |
486 buffer = GST_BUFFER_CAST(g_queue_pop_head(buffer_queue)); |
526 buffer = GST_BUFFER_CAST(g_queue_pop_head(buffer_queue)); |
487 GST_OBJECT_UNLOCK(devsound); |
527 GST_OBJECT_UNLOCK(dssink); |
488 gst_buffer_unref(buffer); |
528 gst_buffer_unref(buffer); |
489 buffer = NULL; |
529 buffer = NULL; |
490 } |
530 } |
491 |
531 |
492 if (lastBufferSet && remainingDataLen == 0) |
532 if (lastBufferSet && remainingDataLen == 0) |
493 { |
533 { |
494 // Last Buffer is already sent to DevSound |
534 lastBufferSet = FALSE; |
495 // and we have received PlayError so now we exit |
535 dssink->eosreceived = FALSE; |
496 // from the big loop next time |
536 playinit(dssink->handle); |
497 /* |
537 initproperties(dssink); |
498 pthread_mutex_lock(&ds_mutex); |
538 get_PopulateIntfcProperties(dssink); |
499 pthread_cond_signal(&ds_condition); |
539 cmd = WAIT; |
500 pthread_mutex_unlock(&ds_mutex); |
540 } |
501 */ |
|
502 cmd = CLOSE; |
|
503 } |
|
504 } |
541 } |
505 else |
542 else |
506 { |
543 { |
507 pthread_mutex_lock(&ds_mutex); |
544 cmd = WAIT; |
508 pthread_cond_wait(&ds_condition, &ds_mutex); |
|
509 pthread_mutex_unlock(&ds_mutex); |
|
510 } |
545 } |
511 } |
546 } |
512 break; |
547 break; |
513 case CLOSE: |
548 case CLOSE: |
514 { |
549 { |
515 close_devsound(devsound); |
550 close_devsound(dssink); |
516 devsound->handle= NULL; |
551 dssink->handle= NULL; |
517 pthread_mutex_lock(&ds_mutex); |
552 pthread_mutex_lock(&ds_mutex); |
518 pthread_cond_signal(&ds_condition); |
553 pthread_cond_signal(&ds_condition); |
519 pthread_mutex_unlock(&ds_mutex); |
554 pthread_mutex_unlock(&ds_mutex); |
520 // TODO obtain mutex here |
555 // TODO obtain mutex here |
521 consumer_thread_state = CONSUMER_THREAD_UNINITIALIZED; |
556 consumer_thread_state = CONSUMER_THREAD_UNINITIALIZED; |
572 } |
607 } |
573 |
608 |
574 static gboolean gst_sink_stop (GstBaseSink * sink) |
609 static gboolean gst_sink_stop (GstBaseSink * sink) |
575 { |
610 { |
576 GstBuffer *tmp_gstbuffer=NULL; |
611 GstBuffer *tmp_gstbuffer=NULL; |
577 GstDevsoundSink *devsound = GST_DEVSOUND_SINK(sink); |
612 GstDevsoundSink *dssink = GST_DEVSOUND_SINK(sink); |
578 |
613 |
579 cmd = CLOSE; |
614 cmd = CLOSE; |
580 |
615 |
581 pthread_mutex_lock(&ds_mutex); |
616 pthread_mutex_lock(&ds_mutex); |
582 pthread_cond_signal(&ds_condition); |
617 pthread_cond_signal(&ds_condition); |
583 pthread_mutex_unlock(&ds_mutex); |
618 pthread_mutex_unlock(&ds_mutex); |
584 |
619 |
585 GST_OBJECT_LOCK(devsound); |
620 pthread_mutex_lock(&ds_mutex); |
|
621 pthread_cond_wait(&ds_condition, &ds_mutex); |
|
622 pthread_mutex_unlock(&ds_mutex); |
|
623 |
|
624 |
|
625 GST_OBJECT_LOCK(dssink); |
586 while (buffer_queue->length) |
626 while (buffer_queue->length) |
587 { |
627 { |
588 tmp_gstbuffer = (GstBuffer*)g_queue_pop_tail(buffer_queue); |
628 tmp_gstbuffer = (GstBuffer*)g_queue_pop_tail(buffer_queue); |
589 gst_buffer_unref(tmp_gstbuffer); |
629 gst_buffer_unref(tmp_gstbuffer); |
590 } |
630 } |
591 g_queue_free(buffer_queue); |
631 g_queue_free(buffer_queue); |
592 buffer_queue = NULL; |
632 buffer_queue = NULL; |
593 GST_OBJECT_UNLOCK(devsound); |
633 GST_OBJECT_UNLOCK(dssink); |
594 |
634 |
595 return TRUE; |
635 return TRUE; |
596 } |
636 } |
597 |
637 |
598 static GstFlowReturn gst_sink_render (GstBaseSink * sink, |
638 static GstFlowReturn gst_sink_render (GstBaseSink * sink, |
599 GstBuffer * buffer) |
639 GstBuffer * buffer) |
600 { |
640 { |
601 GstDevsoundSink *devsound = GST_DEVSOUND_SINK(sink); |
641 GstDevsoundSink *dssink = GST_DEVSOUND_SINK(sink); |
602 GstBuffer* tmp; |
642 GstBuffer* tmp; |
603 |
643 |
604 if (get_ds_cb_error(devsound->handle)) |
644 if (get_ds_cb_error(dssink->handle)) |
605 { |
645 { |
606 return GST_FLOW_CUSTOM_ERROR; |
646 return GST_FLOW_CUSTOM_ERROR; |
607 } |
647 } |
608 |
648 |
609 tmp = gst_buffer_copy(buffer); |
649 tmp = gst_buffer_copy(buffer); |
610 |
650 |
611 GST_OBJECT_LOCK (devsound); |
651 GST_OBJECT_LOCK (dssink); |
612 g_queue_push_tail (buffer_queue, tmp); |
652 g_queue_push_tail (buffer_queue, tmp); |
613 GST_OBJECT_UNLOCK (devsound); |
653 GST_OBJECT_UNLOCK (dssink); |
614 |
654 |
615 cmd = WRITEDATA; |
655 cmd = PLAYING; |
616 pthread_mutex_lock(&ds_mutex); |
656 pthread_mutex_lock(&ds_mutex); |
617 pthread_cond_signal(&ds_condition); |
657 pthread_cond_signal(&ds_condition); |
618 pthread_mutex_unlock(&ds_mutex); |
658 pthread_mutex_unlock(&ds_mutex); |
619 |
659 |
620 return GST_FLOW_OK; |
660 return GST_FLOW_OK; |
621 } |
661 } |
622 |
662 |
623 static void gst_devsound_sink_finalise(GObject * object) |
663 static void gst_devsound_sink_finalise(GObject * object) |
624 { |
664 { |
625 GstDevsoundSink *devsoundsink= GST_DEVSOUND_SINK (object); |
665 GstDevsoundSink *devsoundsink = GST_DEVSOUND_SINK (object); |
626 g_free(devsoundsink->device); |
666 g_free(devsoundsink->device); |
627 |
667 |
628 } |
668 } |
629 |
669 |
630 static void gst_devsound_sink_set_property(GObject * object, guint prop_id, |
670 static void gst_devsound_sink_set_property(GObject * object, guint prop_id, |
960 } |
999 } |
961 |
1000 |
962 return TRUE; |
1001 return TRUE; |
963 } |
1002 } |
964 |
1003 |
|
1004 #ifdef AV_SYNC |
|
1005 static void gst_devsound_sink_get_times (GstBaseSink * bsink, GstBuffer * buffer, |
|
1006 GstClockTime * start, GstClockTime * end) |
|
1007 { |
|
1008 /* Like GstBaseAudioSink, we set these to NONE */ |
|
1009 *start = GST_CLOCK_TIME_NONE; |
|
1010 *end = GST_CLOCK_TIME_NONE; |
|
1011 } |
|
1012 |
|
1013 static GstClock *gst_devsound_sink_provide_clock (GstElement * element) |
|
1014 { |
|
1015 GstDevsoundSink *sink = GST_DEVSOUND_SINK (element); |
|
1016 return GST_CLOCK (gst_object_ref (sink->clock)); |
|
1017 } |
|
1018 |
|
1019 static GstClockTime gst_devsound_sink_get_time (GstClock * clock, gpointer user_data) |
|
1020 { |
|
1021 GstClockTime result = 0; |
|
1022 GstDevsoundSink *sink = GST_DEVSOUND_SINK (user_data); |
|
1023 |
|
1024 /* The value returned must be in nano seconds. 1 sec = 1000000000 nano seconds (9 zeros)*/ |
|
1025 /*If time played is available from DevSound (a3f devsound onwards) get it*/ |
|
1026 if (sink->timeplayedavailable) |
|
1027 { |
|
1028 result = sink->time_or_samples_played; |
|
1029 } |
|
1030 else if ((sink->time_or_samples_played > 0 ) && (sink->rate > 0 ))/*This is a pre-a3f devsound. So calculate times played based on samples played*/ |
|
1031 { /*GST_SECOND = 1000000000*/ |
|
1032 result = gst_util_uint64_scale_int (sink->time_or_samples_played, GST_SECOND, sink->rate); |
|
1033 } |
|
1034 GST_LOG_OBJECT (sink, "Time: %" GST_TIME_FORMAT, GST_TIME_ARGS (result)); |
|
1035 return result; |
|
1036 } |
|
1037 #endif /*AV_SYNC*/ |
|
1038 |
|
1039 static GstStateChangeReturn gst_devsound_sink_change_state (GstElement * element, GstStateChange transition) |
|
1040 { |
|
1041 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; |
|
1042 GstDevsoundSink *sink= GST_DEVSOUND_SINK (element); |
|
1043 |
|
1044 switch (transition) |
|
1045 { |
|
1046 case GST_STATE_CHANGE_NULL_TO_READY: |
|
1047 { |
|
1048 #ifdef AV_SYNC |
|
1049 sink->time_or_samples_played = 0; |
|
1050 #endif /*AV_SYNC*/ |
|
1051 } |
|
1052 break; |
|
1053 |
|
1054 case GST_STATE_CHANGE_PAUSED_TO_PLAYING: |
|
1055 if(cmd == WAIT) |
|
1056 { |
|
1057 cmd = RESUME; |
|
1058 pthread_mutex_lock(&ds_mutex); |
|
1059 pthread_cond_signal(&ds_condition); |
|
1060 pthread_mutex_unlock(&ds_mutex); |
|
1061 |
|
1062 pthread_mutex_lock(&ds_mutex); |
|
1063 pthread_cond_wait(&ds_condition, &ds_mutex); |
|
1064 pthread_mutex_unlock(&ds_mutex); |
|
1065 } |
|
1066 break; |
|
1067 default: |
|
1068 break; |
|
1069 } |
|
1070 |
|
1071 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); |
|
1072 if (G_UNLIKELY (ret == GST_STATE_CHANGE_FAILURE)) |
|
1073 goto activate_failed; |
|
1074 |
|
1075 switch (transition) { |
|
1076 |
|
1077 case GST_STATE_CHANGE_PLAYING_TO_PAUSED: |
|
1078 cmd = PAUSE; |
|
1079 pthread_mutex_lock(&ds_mutex); |
|
1080 pthread_cond_signal(&ds_condition); |
|
1081 pthread_mutex_unlock(&ds_mutex); |
|
1082 |
|
1083 pthread_mutex_lock(&ds_mutex); |
|
1084 pthread_cond_wait(&ds_condition, &ds_mutex); |
|
1085 pthread_mutex_unlock(&ds_mutex); |
|
1086 break; |
|
1087 default: |
|
1088 break; |
|
1089 } |
|
1090 |
|
1091 return ret; |
|
1092 |
|
1093 activate_failed: |
|
1094 { |
|
1095 GST_DEBUG_OBJECT (sink, |
|
1096 "element failed to change states -- activation problem?"); |
|
1097 return GST_STATE_CHANGE_FAILURE; |
|
1098 } |
|
1099 } |
|
1100 |
965 |
1101 |
966 /************************************ |
1102 /************************************ |
967 * Error Concealment Interface begins |
1103 * Error Concealment Interface begins |
968 * **********************************/ |
1104 * **********************************/ |
969 static void gst_error_concealment_handler_init (gpointer g_iface, |
1105 static void gst_error_concealment_handler_init (gpointer g_iface, |