2 * Copyright (C) 2014, Fluendo, S.A.
3 * Copyright (C) 2014, Metrological Media Innovations B.V.
4 * Author: Josep Torra <josep@fluendo.com>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation
9 * version 2.1 of the License.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
28 #include <gst/audio/audio.h>
32 #include "gstomxaudiosink.h"
34 GST_DEBUG_CATEGORY_STATIC (gst_omx_audio_sink_debug_category);
35 #define GST_CAT_DEFAULT gst_omx_audio_sink_debug_category
38 GST_DEBUG_CATEGORY_INIT (gst_omx_audio_sink_debug_category, "omxaudiosink", \
39 0, "debug category for gst-omx audio sink base class");
41 #define DEFAULT_PROP_MUTE FALSE
42 #define DEFAULT_PROP_VOLUME 1.0
44 #define VOLUME_MAX_DOUBLE 10.0
45 #define OUT_CHANNELS(num_channels) ((num_channels) > 4 ? 8: (num_channels) > 2 ? 4: (num_channels))
54 #define gst_omx_audio_sink_parent_class parent_class
55 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstOMXAudioSink, gst_omx_audio_sink,
56 GST_TYPE_AUDIO_SINK, G_IMPLEMENT_INTERFACE (GST_TYPE_STREAM_VOLUME, NULL);
59 #define transform_3_4(type) \
61 transform_3_4_##type (gpointer psrc, gpointer pdst, guint len) \
63 g##type *src = (g##type *) psrc; \
64 g##type *dst = (g##type *) pdst; \
65 for (; len > 0; len--) { \
75 #define transform_5_8(type) \
77 transform_5_8_##type (gpointer psrc, gpointer pdst, guint len) \
79 g##type *src = (g##type *) psrc; \
80 g##type *dst = (g##type *) pdst; \
81 for (; len > 0; len--) { \
95 #define transform_6_8(type) \
97 transform_6_8_##type (gpointer psrc, gpointer pdst, guint len) \
99 g##type *src = (g##type *) psrc; \
100 g##type *dst = (g##type *) pdst; \
101 for (; len > 0; len--) { \
115 #define transform_7_8(type) \
117 transform_7_8_##type (gpointer psrc, gpointer pdst, guint len) \
119 g##type *src = (g##type *) psrc; \
120 g##type *dst = (g##type *) pdst; \
121 for (; len > 0; len--) { \
135 transform_3_4 (int16);
136 transform_5_8 (int16);
137 transform_6_8 (int16);
138 transform_7_8 (int16);
140 transform_3_4 (int32);
141 transform_5_8 (int32);
142 transform_6_8 (int32);
143 transform_7_8 (int32);
146 transform (guint in_chan, guint width, gpointer psrc, gpointer pdst, guint len)
148 guint out_chan = OUT_CHANNELS (in_chan);
153 transform_3_4_int16 (psrc, pdst, len);
161 transform_5_8_int16 (psrc, pdst, len);
164 transform_6_8_int16 (psrc, pdst, len);
167 transform_7_8_int16 (psrc, pdst, len);
176 } else if (width == 32) {
180 transform_3_4_int32 (psrc, pdst, len);
188 transform_5_8_int32 (psrc, pdst, len);
191 transform_6_8_int32 (psrc, pdst, len);
194 transform_7_8_int32 (psrc, pdst, len);
209 gst_omx_audio_sink_mute_set (GstOMXAudioSink * self, gboolean mute)
213 OMX_AUDIO_CONFIG_MUTETYPE param;
215 GST_OMX_INIT_STRUCT (¶m);
216 param.nPortIndex = self->in_port->index;
217 param.bMute = (mute ? OMX_TRUE : OMX_FALSE);
218 err = gst_omx_component_set_config (self->comp,
219 OMX_IndexConfigAudioMute, ¶m);
220 if (err != OMX_ErrorNone) {
221 GST_ERROR_OBJECT (self, "Failed to set mute to %d: %s (0x%08x)",
222 param.bMute, gst_omx_error_to_string (err), err);
229 gst_omx_audio_sink_volume_set (GstOMXAudioSink * self, gdouble volume)
233 OMX_AUDIO_CONFIG_VOLUMETYPE param;
234 GST_OMX_INIT_STRUCT (¶m);
235 param.nPortIndex = self->in_port->index;
236 param.bLinear = OMX_TRUE;
237 param.sVolume.nValue = volume * 100;
238 err = gst_omx_component_set_config (self->comp,
239 OMX_IndexConfigAudioVolume, ¶m);
240 if (err != OMX_ErrorNone) {
241 GST_ERROR_OBJECT (self, "Failed to set volume to %d: %s (0x%08x)",
242 param.sVolume.nValue, gst_omx_error_to_string (err), err);
245 self->volume = volume;
249 gst_omx_audio_sink_open (GstAudioSink * audiosink)
251 GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (audiosink);
252 GstOMXAudioSinkClass *klass = GST_OMX_AUDIO_SINK_GET_CLASS (self);
256 GST_DEBUG_OBJECT (self, "Opening audio sink");
259 gst_omx_component_new (GST_OBJECT_CAST (self), klass->cdata.core_name,
260 klass->cdata.component_name, klass->cdata.component_role,
266 if (gst_omx_component_get_state (self->comp,
267 GST_CLOCK_TIME_NONE) != OMX_StateLoaded)
270 port_index = klass->cdata.in_port_index;
272 if (port_index == -1) {
273 OMX_PORT_PARAM_TYPE param;
275 GST_OMX_INIT_STRUCT (¶m);
278 gst_omx_component_get_parameter (self->comp, OMX_IndexParamAudioInit,
280 if (err != OMX_ErrorNone) {
281 GST_WARNING_OBJECT (self, "Couldn't get port information: %s (0x%08x)",
282 gst_omx_error_to_string (err), err);
286 GST_DEBUG_OBJECT (self, "Detected %u ports, starting at %u",
287 (guint) param.nPorts, (guint) param.nStartPortNumber);
288 port_index = param.nStartPortNumber + 0;
291 self->in_port = gst_omx_component_add_port (self->comp, port_index);
293 port_index = klass->cdata.out_port_index;
295 if (port_index == -1) {
296 OMX_PORT_PARAM_TYPE param;
298 GST_OMX_INIT_STRUCT (¶m);
301 gst_omx_component_get_parameter (self->comp, OMX_IndexParamAudioInit,
303 if (err != OMX_ErrorNone) {
304 GST_WARNING_OBJECT (self, "Couldn't get port information: %s (0x%08x)",
305 gst_omx_error_to_string (err), err);
309 GST_DEBUG_OBJECT (self, "Detected %u ports, starting at %u",
310 (guint) param.nPorts, (guint) param.nStartPortNumber);
311 port_index = param.nStartPortNumber + 1;
314 self->out_port = gst_omx_component_add_port (self->comp, port_index);
316 if (!self->in_port || !self->out_port)
319 err = gst_omx_port_set_enabled (self->in_port, FALSE);
320 if (err != OMX_ErrorNone) {
321 GST_ERROR_OBJECT (self, "Failed to enable port: %s (0x%08x)",
322 gst_omx_error_to_string (err), err);
326 err = gst_omx_port_set_enabled (self->out_port, FALSE);
327 if (err != OMX_ErrorNone) {
328 GST_ERROR_OBJECT (self, "Failed to enable port: %s (0x%08x)",
329 gst_omx_error_to_string (err), err);
333 GST_DEBUG_OBJECT (self, "Opened audio sink");
339 gst_omx_audio_sink_close (GstAudioSink * audiosink)
341 GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (audiosink);
344 GST_DEBUG_OBJECT (self, "Closing audio sink");
346 state = gst_omx_component_get_state (self->comp, 0);
347 if (state > OMX_StateLoaded || state == OMX_StateInvalid) {
348 if (state > OMX_StateIdle) {
349 gst_omx_component_set_state (self->comp, OMX_StateIdle);
350 gst_omx_component_get_state (self->comp, 5 * GST_SECOND);
352 gst_omx_component_set_state (self->comp, OMX_StateLoaded);
353 gst_omx_port_deallocate_buffers (self->in_port);
354 if (state > OMX_StateLoaded)
355 gst_omx_component_get_state (self->comp, 5 * GST_SECOND);
358 self->in_port = NULL;
359 self->out_port = NULL;
361 gst_omx_component_free (self->comp);
364 GST_DEBUG_OBJECT (self, "Closed audio sink");
370 gst_omx_audio_sink_parse_spec (GstOMXAudioSink * self,
371 GstAudioRingBufferSpec * spec)
373 self->iec61937 = FALSE;
374 self->endianness = GST_AUDIO_INFO_ENDIANNESS (&spec->info);
375 self->rate = GST_AUDIO_INFO_RATE (&spec->info);
376 self->channels = GST_AUDIO_INFO_CHANNELS (&spec->info);
377 self->width = GST_AUDIO_INFO_WIDTH (&spec->info);
378 self->is_signed = GST_AUDIO_INFO_IS_SIGNED (&spec->info);
379 self->is_float = GST_AUDIO_INFO_IS_FLOAT (&spec->info);
381 switch (spec->type) {
382 case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW:
384 guint out_channels = OUT_CHANNELS (self->channels);
386 self->samples = spec->segsize / self->channels / (self->width >> 3);
387 if (self->channels == out_channels) {
388 self->buffer_size = spec->segsize;
390 self->buffer_size = (spec->segsize / self->channels) * out_channels;
394 case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_AC3:
395 case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_EAC3:
396 case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_DTS:
397 case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG:
398 self->iec61937 = TRUE;
399 self->endianness = G_LITTLE_ENDIAN;
402 self->is_signed = TRUE;
403 self->is_float = FALSE;
404 self->buffer_size = spec->segsize;
414 channel_mapping (GstAudioRingBufferSpec * spec,
415 OMX_AUDIO_CHANNELTYPE * eChannelMapping)
417 gint i, nchan = GST_AUDIO_INFO_CHANNELS (&spec->info);
419 for (i = 0; i < nchan; i++) {
420 OMX_AUDIO_CHANNELTYPE pos;
422 switch (GST_AUDIO_INFO_POSITION (&spec->info, i)) {
423 case GST_AUDIO_CHANNEL_POSITION_MONO:
424 case GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER:
425 pos = OMX_AUDIO_ChannelCF;
427 case GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT:
428 pos = OMX_AUDIO_ChannelLF;
430 case GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT:
431 pos = OMX_AUDIO_ChannelRF;
433 case GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT:
434 pos = OMX_AUDIO_ChannelLS;
436 case GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT:
437 pos = OMX_AUDIO_ChannelRS;
439 case GST_AUDIO_CHANNEL_POSITION_LFE1:
440 pos = OMX_AUDIO_ChannelLFE;
442 case GST_AUDIO_CHANNEL_POSITION_REAR_CENTER:
443 pos = OMX_AUDIO_ChannelCS;
445 case GST_AUDIO_CHANNEL_POSITION_REAR_LEFT:
446 pos = OMX_AUDIO_ChannelLR;
448 case GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT:
449 pos = OMX_AUDIO_ChannelRR;
452 pos = OMX_AUDIO_ChannelNone;
455 eChannelMapping[i] = pos;
459 static inline const gchar *
460 ch2str (OMX_AUDIO_CHANNELTYPE ch)
463 case OMX_AUDIO_ChannelNone:
464 return "OMX_AUDIO_ChannelNone";
465 case OMX_AUDIO_ChannelLF:
466 return "OMX_AUDIO_ChannelLF";
467 case OMX_AUDIO_ChannelRF:
468 return "OMX_AUDIO_ChannelRF";
469 case OMX_AUDIO_ChannelCF:
470 return "OMX_AUDIO_ChannelCF";
471 case OMX_AUDIO_ChannelLS:
472 return "OMX_AUDIO_ChannelLS";
473 case OMX_AUDIO_ChannelRS:
474 return "OMX_AUDIO_ChannelRS";
475 case OMX_AUDIO_ChannelLFE:
476 return "OMX_AUDIO_ChannelLFE";
477 case OMX_AUDIO_ChannelCS:
478 return "OMX_AUDIO_ChannelCS";
479 case OMX_AUDIO_ChannelLR:
480 return "OMX_AUDIO_ChannelLR";
481 case OMX_AUDIO_ChannelRR:
482 return "OMX_AUDIO_ChannelRR";
484 return "Invalid value";
488 static inline gboolean
489 gst_omx_audio_sink_configure_pcm (GstOMXAudioSink * self,
490 GstAudioRingBufferSpec * spec)
492 OMX_AUDIO_PARAM_PCMMODETYPE param;
495 GST_OMX_INIT_STRUCT (¶m);
496 param.nPortIndex = self->in_port->index;
497 param.nChannels = OUT_CHANNELS (self->channels);
499 (self->is_signed ? OMX_NumericalDataSigned : OMX_NumericalDataUnsigned);
501 ((self->endianness ==
502 G_LITTLE_ENDIAN) ? OMX_EndianLittle : OMX_EndianBig);
503 param.bInterleaved = OMX_TRUE;
504 param.nBitPerSample = self->width;
505 param.nSamplingRate = self->rate;
507 if (self->is_float) {
508 /* This is cherrypicked from xbmc but it doesn't seems to be valid on my RPI.
509 * https://github.com/xbmc/xbmc/blob/master/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp
511 param.ePCMMode = (OMX_AUDIO_PCMMODETYPE) 0x8000;
513 param.ePCMMode = OMX_AUDIO_PCMModeLinear;
516 if (spec->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW) {
517 channel_mapping (spec, ¶m.eChannelMapping[0]);
520 GST_DEBUG_OBJECT (self, "Setting PCM parameters");
521 GST_DEBUG_OBJECT (self, " nChannels: %d", param.nChannels);
522 GST_DEBUG_OBJECT (self, " eNumData: %s",
523 (param.eNumData == OMX_NumericalDataSigned ? "signed" : "unsigned"));
524 GST_DEBUG_OBJECT (self, " eEndian: %s",
525 (param.eEndian == OMX_EndianLittle ? "little endian" : "big endian"));
526 GST_DEBUG_OBJECT (self, " bInterleaved: %d", param.bInterleaved);
527 GST_DEBUG_OBJECT (self, " nBitPerSample: %d", param.nBitPerSample);
528 GST_DEBUG_OBJECT (self, " nSamplingRate: %d", param.nSamplingRate);
529 GST_DEBUG_OBJECT (self, " ePCMMode: %04x", param.ePCMMode);
530 GST_DEBUG_OBJECT (self, " eChannelMapping: {%s, %s, %s, %s, %s, %s, %s, %s}",
531 ch2str (param.eChannelMapping[0]), ch2str (param.eChannelMapping[1]),
532 ch2str (param.eChannelMapping[2]), ch2str (param.eChannelMapping[3]),
533 ch2str (param.eChannelMapping[4]), ch2str (param.eChannelMapping[5]),
534 ch2str (param.eChannelMapping[6]), ch2str (param.eChannelMapping[7]));
537 gst_omx_component_set_parameter (self->comp, OMX_IndexParamAudioPcm,
539 if (err != OMX_ErrorNone) {
540 GST_ERROR_OBJECT (self, "Failed to set PCM parameters: %s (0x%08x)",
541 gst_omx_error_to_string (err), err);
549 gst_omx_audio_sink_prepare (GstAudioSink * audiosink,
550 GstAudioRingBufferSpec * spec)
552 GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (audiosink);
553 OMX_PARAM_PORTDEFINITIONTYPE port_def;
556 if (!gst_omx_audio_sink_parse_spec (self, spec))
559 gst_omx_port_get_port_definition (self->in_port, &port_def);
561 port_def.nBufferSize = self->buffer_size;
562 /* Only allocate a min number of buffers for transfers from our ringbuffer to
563 * the hw ringbuffer as we want to keep our small */
564 port_def.nBufferCountActual = MAX (port_def.nBufferCountMin, 2);
565 port_def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
567 GST_DEBUG_OBJECT (self, "Updating outport port definition");
568 GST_DEBUG_OBJECT (self, " nBufferSize: %d", port_def.nBufferSize);
569 GST_DEBUG_OBJECT (self, " nBufferCountActual: %d",
570 port_def.nBufferCountActual);
571 GST_DEBUG_OBJECT (self, " audio.eEncoding: 0x%08x",
572 port_def.format.audio.eEncoding);
574 err = gst_omx_port_update_port_definition (self->in_port, &port_def);
575 if (err != OMX_ErrorNone) {
576 GST_ERROR_OBJECT (self, "Failed to configure port: %s (0x%08x)",
577 gst_omx_error_to_string (err), err);
581 if (!gst_omx_audio_sink_configure_pcm (self, spec)) {
585 err = gst_omx_component_set_state (self->comp, OMX_StateIdle);
586 if (err != OMX_ErrorNone) {
587 GST_ERROR_OBJECT (self, "Failed to set state idle: %s (0x%08x)",
588 gst_omx_error_to_string (err), err);
592 err = gst_omx_port_set_enabled (self->in_port, TRUE);
593 if (err != OMX_ErrorNone) {
594 GST_ERROR_OBJECT (self, "Failed to enable port: %s (0x%08x)",
595 gst_omx_error_to_string (err), err);
599 GST_DEBUG_OBJECT (self, "Allocate buffers");
600 err = gst_omx_port_allocate_buffers (self->in_port);
601 if (err != OMX_ErrorNone) {
602 GST_ERROR_OBJECT (self, "Failed on buffer allocation: %s (0x%08x)",
603 gst_omx_error_to_string (err), err);
607 err = gst_omx_port_wait_enabled (self->in_port, 5 * GST_SECOND);
608 if (err != OMX_ErrorNone) {
609 GST_ERROR_OBJECT (self, "port not enabled: %s (0x%08x)",
610 gst_omx_error_to_string (err), err);
614 err = gst_omx_port_mark_reconfigured (self->in_port);
615 if (err != OMX_ErrorNone) {
616 GST_ERROR_OBJECT (self, "Couln't mark port as reconfigured: %s (0x%08x)",
617 gst_omx_error_to_string (err), err);
621 err = gst_omx_component_set_state (self->comp, OMX_StatePause);
622 if (err != OMX_ErrorNone) {
623 GST_ERROR_OBJECT (self, "Failed to set state paused: %s (0x%08x)",
624 gst_omx_error_to_string (err), err);
628 if (gst_omx_component_get_state (self->comp,
629 GST_CLOCK_TIME_NONE) != OMX_StatePause)
632 /* Configure some parameters */
633 GST_OBJECT_LOCK (self);
634 gst_omx_audio_sink_mute_set (self, self->mute);
635 gst_omx_audio_sink_volume_set (self, self->volume);
636 GST_OBJECT_UNLOCK (self);
638 #if defined (USE_OMX_TARGET_RPI)
640 GstOMXAudioSinkClass *klass = GST_OMX_AUDIO_SINK_GET_CLASS (self);
642 OMX_CONFIG_BRCMAUDIODESTINATIONTYPE param;
644 if (klass->destination
645 && strlen (klass->destination) < sizeof (param.sName)) {
646 GST_DEBUG_OBJECT (self, "Setting destination: %s", klass->destination);
647 GST_OMX_INIT_STRUCT (¶m);
648 strcpy ((char *) param.sName, klass->destination);
649 err = gst_omx_component_set_config (self->comp,
650 OMX_IndexConfigBrcmAudioDestination, ¶m);
651 if (err != OMX_ErrorNone) {
652 GST_ERROR_OBJECT (self,
653 "Failed to configuring destination: %s (0x%08x)",
654 gst_omx_error_to_string (err), err);
666 GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS, (NULL),
667 ("Error parsing spec"));
673 GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS, (NULL),
674 ("Configuration failed"));
679 GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS, (NULL),
680 ("Component activation failed"));
686 gst_omx_audio_sink_unprepare (GstAudioSink * audiosink)
688 GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (audiosink);
691 if (gst_omx_component_get_state (self->comp, 0) == OMX_StateIdle)
694 err = gst_omx_port_set_flushing (self->in_port, 5 * GST_SECOND, TRUE);
695 if (err != OMX_ErrorNone) {
696 GST_ERROR_OBJECT (self, "Failed to set port flushing: %s (0x%08x)",
697 gst_omx_error_to_string (err), err);
701 err = gst_omx_component_set_state (self->comp, OMX_StateIdle);
702 if (err != OMX_ErrorNone) {
703 GST_ERROR_OBJECT (self, "Failed to set state idle: %s (0x%08x)",
704 gst_omx_error_to_string (err), err);
708 err = gst_omx_port_set_enabled (self->in_port, FALSE);
709 if (err != OMX_ErrorNone) {
710 GST_ERROR_OBJECT (self, "Failed to set port disabled: %s (0x%08x)",
711 gst_omx_error_to_string (err), err);
715 err = gst_omx_port_wait_buffers_released (self->in_port, 5 * GST_SECOND);
716 if (err != OMX_ErrorNone) {
720 err = gst_omx_port_deallocate_buffers (self->in_port);
721 if (err != OMX_ErrorNone) {
722 GST_ERROR_OBJECT (self, "Couldn't deallocate buffers: %s (0x%08x)",
723 gst_omx_error_to_string (err), err);
727 err = gst_omx_port_wait_enabled (self->in_port, 1 * GST_SECOND);
728 if (err != OMX_ErrorNone) {
732 err = gst_omx_port_set_flushing (self->in_port, 5 * GST_SECOND, FALSE);
733 if (err != OMX_ErrorNone) {
734 GST_ERROR_OBJECT (self, "Failed to set port not flushing: %s (0x%08x)",
735 gst_omx_error_to_string (err), err);
739 gst_omx_component_get_state (self->comp, GST_CLOCK_TIME_NONE);
746 GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
747 ("OpenMAX component in error state %s (0x%08x)",
748 gst_omx_component_get_last_error_string (self->comp),
749 gst_omx_component_get_last_error (self->comp)));
754 static GstOMXBuffer *
755 gst_omx_audio_sink_acquire_buffer (GstOMXAudioSink * self)
757 GstOMXAcquireBufferReturn acq_ret = GST_OMX_ACQUIRE_BUFFER_ERROR;
758 GstOMXPort *port = self->in_port;
760 GstOMXBuffer *buf = NULL;
763 acq_ret = gst_omx_port_acquire_buffer (port, &buf);
764 if (acq_ret == GST_OMX_ACQUIRE_BUFFER_ERROR) {
765 goto component_error;
766 } else if (acq_ret == GST_OMX_ACQUIRE_BUFFER_FLUSHING) {
767 GST_DEBUG_OBJECT (self, "Flushing...");
769 } else if (acq_ret == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
770 GST_DEBUG_OBJECT (self, "Reconfigure...");
771 /* Reallocate all buffers */
772 err = gst_omx_port_set_enabled (port, FALSE);
773 if (err != OMX_ErrorNone) {
774 GST_ERROR_OBJECT (self, "Failed to set port disabled: %s (0x%08x)",
775 gst_omx_error_to_string (err), err);
776 goto reconfigure_error;
779 err = gst_omx_port_wait_buffers_released (port, 5 * GST_SECOND);
780 if (err != OMX_ErrorNone) {
781 goto reconfigure_error;
784 err = gst_omx_port_deallocate_buffers (port);
785 if (err != OMX_ErrorNone) {
786 GST_ERROR_OBJECT (self, "Couldn't deallocate buffers: %s (0x%08x)",
787 gst_omx_error_to_string (err), err);
788 goto reconfigure_error;
791 err = gst_omx_port_wait_enabled (port, 1 * GST_SECOND);
792 if (err != OMX_ErrorNone) {
793 goto reconfigure_error;
796 err = gst_omx_port_set_enabled (port, TRUE);
797 if (err != OMX_ErrorNone) {
798 goto reconfigure_error;
801 err = gst_omx_port_allocate_buffers (port);
802 if (err != OMX_ErrorNone) {
803 goto reconfigure_error;
806 err = gst_omx_port_wait_enabled (port, 5 * GST_SECOND);
807 if (err != OMX_ErrorNone) {
808 goto reconfigure_error;
811 err = gst_omx_port_mark_reconfigured (port);
812 if (err != OMX_ErrorNone) {
813 goto reconfigure_error;
824 GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
825 ("OpenMAX component in error state %s (0x%08x)",
826 gst_omx_component_get_last_error_string (self->comp),
827 gst_omx_component_get_last_error (self->comp)));
832 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
833 ("Unable to reconfigure input port"));
843 gst_omx_audio_sink_write (GstAudioSink * audiosink, gpointer data, guint length)
845 GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (audiosink);
849 GST_LOG_OBJECT (self, "received audio samples buffer of %u bytes", length);
851 GST_OMX_AUDIO_SINK_LOCK (self);
853 if (!(buf = gst_omx_audio_sink_acquire_buffer (self))) {
857 if (buf->omx_buf->nAllocLen == length) {
858 memcpy (buf->omx_buf->pBuffer + buf->omx_buf->nOffset, data, length);
860 transform (self->channels, self->width, data,
861 buf->omx_buf->pBuffer + buf->omx_buf->nOffset, self->samples);
863 buf->omx_buf->nFilledLen = buf->omx_buf->nAllocLen;
865 err = gst_omx_port_release_buffer (self->in_port, buf);
866 if (err != OMX_ErrorNone)
871 GST_OMX_AUDIO_SINK_UNLOCK (self);
878 GST_OMX_AUDIO_SINK_UNLOCK (self);
879 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
880 ("Failed to relase input buffer to component: %s (0x%08x)",
881 gst_omx_error_to_string (err), err));
887 gst_omx_audio_sink_delay (GstAudioSink * audiosink)
889 GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (audiosink);
890 OMX_PARAM_U32TYPE param;
893 GST_OMX_INIT_STRUCT (¶m);
894 param.nPortIndex = self->in_port->index;
896 err = gst_omx_component_get_config (self->comp,
897 OMX_IndexConfigAudioRenderingLatency, ¶m);
898 if (err != OMX_ErrorNone) {
899 GST_ERROR_OBJECT (self, "Failed to get rendering latency: %s (0x%08x)",
900 gst_omx_error_to_string (err), err);
904 GST_DEBUG_OBJECT (self, "reported delay %d samples", param.nU32);
909 gst_omx_audio_sink_reset (GstAudioSink * audiosink)
911 GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (audiosink);
914 GST_DEBUG_OBJECT (self, "Flushing sink");
916 gst_omx_port_set_flushing (self->in_port, 5 * GST_SECOND, TRUE);
918 GST_OMX_AUDIO_SINK_LOCK (self);
919 if ((state = gst_omx_component_get_state (self->comp, 0)) > OMX_StatePause) {
920 gst_omx_component_set_state (self->comp, OMX_StatePause);
921 gst_omx_component_get_state (self->comp, GST_CLOCK_TIME_NONE);
924 gst_omx_component_set_state (self->comp, state);
925 gst_omx_component_get_state (self->comp, GST_CLOCK_TIME_NONE);
927 gst_omx_port_set_flushing (self->in_port, 5 * GST_SECOND, FALSE);
929 GST_OMX_AUDIO_SINK_UNLOCK (self);
933 gst_omx_audio_sink_payload (GstAudioBaseSink * audiobasesink, GstBuffer * buf)
935 GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (audiobasesink);
937 if (self->iec61937) {
940 GstMapInfo iinfo, oinfo;
941 GstAudioRingBufferSpec *spec = &audiobasesink->ringbuffer->spec;
943 framesize = gst_audio_iec61937_frame_size (spec);
947 out = gst_buffer_new_and_alloc (framesize);
949 gst_buffer_map (buf, &iinfo, GST_MAP_READ);
950 gst_buffer_map (out, &oinfo, GST_MAP_WRITE);
952 if (!gst_audio_iec61937_payload (iinfo.data, iinfo.size,
953 oinfo.data, oinfo.size, spec, G_BIG_ENDIAN)) {
954 gst_buffer_unref (out);
958 gst_buffer_unmap (buf, &iinfo);
959 gst_buffer_unmap (out, &oinfo);
961 gst_buffer_copy_into (out, buf, GST_BUFFER_COPY_METADATA, 0, -1);
965 return gst_buffer_ref (buf);
969 gst_omx_audio_sink_accept_caps (GstOMXAudioSink * self, GstCaps * caps)
971 GstPad *pad = GST_BASE_SINK (self)->sinkpad;
974 gboolean ret = FALSE;
975 GstAudioRingBufferSpec spec = { 0 };
977 pad_caps = gst_pad_query_caps (pad, caps);
978 if (!pad_caps || gst_caps_is_empty (pad_caps)) {
980 gst_caps_unref (pad_caps);
984 gst_caps_unref (pad_caps);
986 /* If we've not got fixed caps, creating a stream might fail, so let's just
987 * return from here with default acceptcaps behaviour */
988 if (!gst_caps_is_fixed (caps))
991 /* parse helper expects this set, so avoid nasty warning
992 * will be set properly later on anyway */
993 spec.latency_time = GST_SECOND;
994 if (!gst_audio_ring_buffer_parse_caps (&spec, caps))
997 /* Make sure input is framed (one frame per buffer) and can be payloaded */
999 case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_AC3:
1000 case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_EAC3:
1001 case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_DTS:
1002 case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG:
1004 gboolean framed = FALSE, parsed = FALSE;
1005 st = gst_caps_get_structure (caps, 0);
1007 gst_structure_get_boolean (st, "framed", &framed);
1008 gst_structure_get_boolean (st, "parsed", &parsed);
1009 if ((!framed && !parsed) || gst_audio_iec61937_frame_size (&spec) <= 0)
1018 gst_caps_replace (&spec.caps, NULL);
1023 gst_omx_audio_sink_query (GstBaseSink * basesink, GstQuery * query)
1025 GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (basesink);
1028 switch (GST_QUERY_TYPE (query)) {
1029 case GST_QUERY_ACCEPT_CAPS:
1033 gst_query_parse_accept_caps (query, &caps);
1034 ret = gst_omx_audio_sink_accept_caps (self, caps);
1035 gst_query_set_accept_caps_result (query, ret);
1040 ret = GST_BASE_SINK_CLASS (parent_class)->query (basesink, query);
1047 gst_omx_audio_sink_set_property (GObject * object, guint prop_id,
1048 const GValue * value, GParamSpec * pspec)
1050 GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (object);
1055 gboolean mute = g_value_get_boolean (value);
1056 GST_OBJECT_LOCK (self);
1057 if (self->mute != mute) {
1058 gst_omx_audio_sink_mute_set (self, mute);
1060 GST_OBJECT_UNLOCK (self);
1065 gdouble volume = g_value_get_double (value);
1066 GST_OBJECT_LOCK (self);
1067 if (volume != self->volume) {
1068 gst_omx_audio_sink_volume_set (self, volume);
1070 GST_OBJECT_UNLOCK (self);
1074 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1080 gst_omx_audio_sink_get_property (GObject * object, guint prop_id,
1081 GValue * value, GParamSpec * pspec)
1083 GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (object);
1087 GST_OBJECT_LOCK (self);
1088 g_value_set_boolean (value, self->mute);
1089 GST_OBJECT_UNLOCK (self);
1092 GST_OBJECT_LOCK (self);
1093 g_value_set_double (value, self->volume);
1094 GST_OBJECT_UNLOCK (self);
1097 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1102 static GstStateChangeReturn
1103 gst_omx_audio_sink_change_state (GstElement * element,
1104 GstStateChange transition)
1106 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1107 GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (element);
1110 switch (transition) {
1111 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1113 GST_DEBUG_OBJECT (self, "going to PLAYING state");
1114 err = gst_omx_component_set_state (self->comp, OMX_StateExecuting);
1115 if (err != OMX_ErrorNone) {
1116 GST_ERROR_OBJECT (self, "Failed to set state executing: %s (0x%08x)",
1117 gst_omx_error_to_string (err), err);
1118 return GST_STATE_CHANGE_FAILURE;
1121 if (gst_omx_component_get_state (self->comp,
1122 GST_CLOCK_TIME_NONE) != OMX_StateExecuting) {
1123 return GST_STATE_CHANGE_FAILURE;
1125 GST_DEBUG_OBJECT (self, "in PLAYING state");
1132 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1134 switch (transition) {
1135 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1137 GST_DEBUG_OBJECT (self, "going to PAUSED state");
1138 err = gst_omx_component_set_state (self->comp, OMX_StatePause);
1139 if (err != OMX_ErrorNone) {
1140 GST_ERROR_OBJECT (self, "Failed to set state paused: %s (0x%08x)",
1141 gst_omx_error_to_string (err), err);
1142 return GST_STATE_CHANGE_FAILURE;
1145 if (gst_omx_component_get_state (self->comp,
1146 GST_CLOCK_TIME_NONE) != OMX_StatePause) {
1147 return GST_STATE_CHANGE_FAILURE;
1149 GST_DEBUG_OBJECT (self, "in PAUSED state");
1160 gst_omx_audio_sink_finalize (GObject * object)
1162 GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (object);
1164 g_mutex_clear (&self->lock);
1166 G_OBJECT_CLASS (parent_class)->finalize (object);
1170 gst_omx_audio_sink_class_init (GstOMXAudioSinkClass * klass)
1172 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1173 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
1174 GstBaseSinkClass *basesink_class = GST_BASE_SINK_CLASS (klass);
1175 GstAudioBaseSinkClass *baudiosink_class = GST_AUDIO_BASE_SINK_CLASS (klass);
1176 GstAudioSinkClass *audiosink_class = GST_AUDIO_SINK_CLASS (klass);
1178 gobject_class->set_property = gst_omx_audio_sink_set_property;
1179 gobject_class->get_property = gst_omx_audio_sink_get_property;
1180 gobject_class->finalize = gst_omx_audio_sink_finalize;
1182 g_object_class_install_property (gobject_class, PROP_MUTE,
1183 g_param_spec_boolean ("mute", "Mute", "mute channel",
1184 DEFAULT_PROP_MUTE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1186 g_object_class_install_property (gobject_class, PROP_VOLUME,
1187 g_param_spec_double ("volume", "Volume", "volume factor, 1.0=100%",
1188 0.0, VOLUME_MAX_DOUBLE, DEFAULT_PROP_VOLUME,
1189 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1191 element_class->change_state =
1192 GST_DEBUG_FUNCPTR (gst_omx_audio_sink_change_state);
1194 basesink_class->query = GST_DEBUG_FUNCPTR (gst_omx_audio_sink_query);
1196 baudiosink_class->payload = GST_DEBUG_FUNCPTR (gst_omx_audio_sink_payload);
1198 audiosink_class->open = GST_DEBUG_FUNCPTR (gst_omx_audio_sink_open);
1199 audiosink_class->close = GST_DEBUG_FUNCPTR (gst_omx_audio_sink_close);
1200 audiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_omx_audio_sink_prepare);
1201 audiosink_class->unprepare = GST_DEBUG_FUNCPTR (gst_omx_audio_sink_unprepare);
1202 audiosink_class->write = GST_DEBUG_FUNCPTR (gst_omx_audio_sink_write);
1203 audiosink_class->delay = GST_DEBUG_FUNCPTR (gst_omx_audio_sink_delay);
1204 audiosink_class->reset = GST_DEBUG_FUNCPTR (gst_omx_audio_sink_reset);
1207 klass->cdata.type = GST_OMX_COMPONENT_TYPE_SINK;
1211 gst_omx_audio_sink_init (GstOMXAudioSink * self)
1213 g_mutex_init (&self->lock);
1215 self->mute = DEFAULT_PROP_MUTE;
1216 self->volume = DEFAULT_PROP_VOLUME;
1218 /* For the Raspberry PI there's a big hw buffer and 400 ms seems a good
1219 * size for our ringbuffer. OpenSL ES Sink also allocates a buffer of 400 ms
1220 * in Android so I guess that this should be a sane value for OpenMax in
1222 GST_AUDIO_BASE_SINK (self)->buffer_time = 400000;
1223 gst_audio_base_sink_set_provide_clock (GST_AUDIO_BASE_SINK (self), TRUE);