omxaudiosink: Implements OpenMAX based audio sinks
[platform/upstream/gstreamer.git] / omx / gstomxaudiosink.c
1 /*
2  * Copyright (C) 2014, Fluendo, S.A.
3  * Copyright (C) 2014, Metrological Media Innovations B.V.
4  *   Author: Josep Torra <josep@fluendo.com>
5  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26
27 #include <gst/gst.h>
28 #include <gst/audio/audio.h>
29
30 #include <math.h>
31
32 #include "gstomxaudiosink.h"
33
34 GST_DEBUG_CATEGORY_STATIC (gst_omx_audio_sink_debug_category);
35 #define GST_CAT_DEFAULT gst_omx_audio_sink_debug_category
36
37 #define DEBUG_INIT \
38   GST_DEBUG_CATEGORY_INIT (gst_omx_audio_sink_debug_category, "omxaudiosink", \
39       0, "debug category for gst-omx audio sink base class");
40
41 #define DEFAULT_PROP_MUTE       FALSE
42 #define DEFAULT_PROP_VOLUME     1.0
43
44 #define VOLUME_MAX_DOUBLE       10.0
45 #define OUT_CHANNELS(num_channels) ((num_channels) > 4 ? 8: (num_channels) > 2 ? 4: (num_channels))
46
47 enum
48 {
49   PROP_0,
50   PROP_MUTE,
51   PROP_VOLUME
52 };
53
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);
57     DEBUG_INIT);
58
59 #define transform_3_4(type) \
60 static inline void \
61 transform_3_4_##type (gpointer psrc, gpointer pdst, guint len) \
62 { \
63   g##type *src = (g##type *) psrc; \
64   g##type *dst = (g##type *) pdst; \
65   for (; len > 0; len--) { \
66     dst[0] = src[0]; \
67     dst[1] = src[1]; \
68     dst[2] = src[2]; \
69     dst[3] = 0; \
70     src += 3; \
71     dst += 4; \
72   } \
73 }
74
75 #define transform_5_8(type) \
76 static inline void \
77 transform_5_8_##type (gpointer psrc, gpointer pdst, guint len) \
78 { \
79   g##type *src = (g##type *) psrc; \
80   g##type *dst = (g##type *) pdst; \
81   for (; len > 0; len--) { \
82     dst[0] = src[0]; \
83     dst[1] = src[1]; \
84     dst[2] = src[2]; \
85     dst[3] = src[3]; \
86     dst[4] = src[4]; \
87     dst[5] = 0; \
88     dst[6] = 0; \
89     dst[7] = 0; \
90     src += 5; \
91     dst += 8; \
92   } \
93 }
94
95 #define transform_6_8(type) \
96 static inline void \
97 transform_6_8_##type (gpointer psrc, gpointer pdst, guint len) \
98 { \
99   g##type *src = (g##type *) psrc; \
100   g##type *dst = (g##type *) pdst; \
101   for (; len > 0; len--) { \
102     dst[0] = src[0]; \
103     dst[1] = src[1]; \
104     dst[2] = src[2]; \
105     dst[3] = src[3]; \
106     dst[4] = src[4]; \
107     dst[5] = src[5]; \
108     dst[6] = 0; \
109     dst[7] = 0; \
110     src += 6; \
111     dst += 8; \
112   } \
113 }
114
115 #define transform_7_8(type) \
116 static inline void \
117 transform_7_8_##type (gpointer psrc, gpointer pdst, guint len) \
118 { \
119   g##type *src = (g##type *) psrc; \
120   g##type *dst = (g##type *) pdst; \
121   for (; len > 0; len--) { \
122     dst[0] = src[0]; \
123     dst[1] = src[1]; \
124     dst[2] = src[2]; \
125     dst[3] = src[3]; \
126     dst[4] = src[4]; \
127     dst[5] = src[5]; \
128     dst[6] = src[6]; \
129     dst[7] = 0; \
130     src += 7; \
131     dst += 8; \
132   } \
133 }
134
135 transform_3_4 (int16);
136 transform_5_8 (int16);
137 transform_6_8 (int16);
138 transform_7_8 (int16);
139
140 transform_3_4 (int32);
141 transform_5_8 (int32);
142 transform_6_8 (int32);
143 transform_7_8 (int32);
144
145 static void inline
146 transform (guint in_chan, guint width, gpointer psrc, gpointer pdst, guint len)
147 {
148   guint out_chan = OUT_CHANNELS (in_chan);
149   if (width == 16) {
150     switch (out_chan) {
151       case 4:
152         if (in_chan == 3) {
153           transform_3_4_int16 (psrc, pdst, len);
154         } else {
155           g_assert (FALSE);
156         }
157         break;
158       case 8:
159         switch (in_chan) {
160           case 5:
161             transform_5_8_int16 (psrc, pdst, len);
162             break;
163           case 6:
164             transform_6_8_int16 (psrc, pdst, len);
165             break;
166           case 7:
167             transform_7_8_int16 (psrc, pdst, len);
168             break;
169           default:
170             g_assert (FALSE);
171         }
172         break;
173       default:
174         g_assert (FALSE);
175     }
176   } else if (width == 32) {
177     switch (out_chan) {
178       case 4:
179         if (in_chan == 3) {
180           transform_3_4_int32 (psrc, pdst, len);
181         } else {
182           g_assert (FALSE);
183         }
184         break;
185       case 8:
186         switch (in_chan) {
187           case 5:
188             transform_5_8_int32 (psrc, pdst, len);
189             break;
190           case 6:
191             transform_6_8_int32 (psrc, pdst, len);
192             break;
193           case 7:
194             transform_7_8_int32 (psrc, pdst, len);
195             break;
196           default:
197             g_assert (FALSE);
198         }
199         break;
200       default:
201         g_assert (FALSE);
202     }
203   } else {
204     g_assert (FALSE);
205   }
206 }
207
208 static void
209 gst_omx_audio_sink_mute_set (GstOMXAudioSink * self, gboolean mute)
210 {
211   if (self->comp) {
212     OMX_ERRORTYPE err;
213     OMX_AUDIO_CONFIG_MUTETYPE param;
214
215     GST_OMX_INIT_STRUCT (&param);
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, &param);
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);
223     }
224   }
225   self->mute = mute;
226 }
227
228 static void
229 gst_omx_audio_sink_volume_set (GstOMXAudioSink * self, gdouble volume)
230 {
231   if (self->comp) {
232     OMX_ERRORTYPE err;
233     OMX_AUDIO_CONFIG_VOLUMETYPE param;
234     GST_OMX_INIT_STRUCT (&param);
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, &param);
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);
243     }
244   }
245   self->volume = volume;
246 }
247
248 static gboolean
249 gst_omx_audio_sink_open (GstAudioSink * audiosink)
250 {
251   GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (audiosink);
252   GstOMXAudioSinkClass *klass = GST_OMX_AUDIO_SINK_GET_CLASS (self);
253   gint port_index;
254   OMX_ERRORTYPE err;
255
256   GST_DEBUG_OBJECT (self, "Opening audio sink");
257
258   self->comp =
259       gst_omx_component_new (GST_OBJECT_CAST (self), klass->cdata.core_name,
260       klass->cdata.component_name, klass->cdata.component_role,
261       klass->cdata.hacks);
262
263   if (!self->comp)
264     return FALSE;
265
266   if (gst_omx_component_get_state (self->comp,
267           GST_CLOCK_TIME_NONE) != OMX_StateLoaded)
268     return FALSE;
269
270   port_index = klass->cdata.in_port_index;
271
272   if (port_index == -1) {
273     OMX_PORT_PARAM_TYPE param;
274
275     GST_OMX_INIT_STRUCT (&param);
276
277     err =
278         gst_omx_component_get_parameter (self->comp, OMX_IndexParamAudioInit,
279         &param);
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);
283       /* Fallback */
284       port_index = 0;
285     } else {
286       GST_DEBUG_OBJECT (self, "Detected %u ports, starting at %u",
287           (guint) param.nPorts, (guint) param.nStartPortNumber);
288       port_index = param.nStartPortNumber + 0;
289     }
290   }
291   self->in_port = gst_omx_component_add_port (self->comp, port_index);
292
293   port_index = klass->cdata.out_port_index;
294
295   if (port_index == -1) {
296     OMX_PORT_PARAM_TYPE param;
297
298     GST_OMX_INIT_STRUCT (&param);
299
300     err =
301         gst_omx_component_get_parameter (self->comp, OMX_IndexParamAudioInit,
302         &param);
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);
306       /* Fallback */
307       port_index = 0;
308     } else {
309       GST_DEBUG_OBJECT (self, "Detected %u ports, starting at %u",
310           (guint) param.nPorts, (guint) param.nStartPortNumber);
311       port_index = param.nStartPortNumber + 1;
312     }
313   }
314   self->out_port = gst_omx_component_add_port (self->comp, port_index);
315
316   if (!self->in_port || !self->out_port)
317     return FALSE;
318
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);
323     return FALSE;
324   }
325
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);
330     return FALSE;
331   }
332
333   GST_DEBUG_OBJECT (self, "Opened audio sink");
334
335   return TRUE;
336 }
337
338 static gboolean
339 gst_omx_audio_sink_close (GstAudioSink * audiosink)
340 {
341   GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (audiosink);
342   OMX_STATETYPE state;
343
344   GST_DEBUG_OBJECT (self, "Closing audio sink");
345
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);
351     }
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);
356   }
357
358   self->in_port = NULL;
359   self->out_port = NULL;
360   if (self->comp)
361     gst_omx_component_free (self->comp);
362   self->comp = NULL;
363
364   GST_DEBUG_OBJECT (self, "Closed audio sink");
365
366   return TRUE;
367 }
368
369 static gboolean
370 gst_omx_audio_sink_parse_spec (GstOMXAudioSink * self,
371     GstAudioRingBufferSpec * spec)
372 {
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);
380
381   switch (spec->type) {
382     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW:
383     {
384       guint out_channels = OUT_CHANNELS (self->channels);
385
386       self->samples = spec->segsize / self->channels / (self->width >> 3);
387       if (self->channels == out_channels) {
388         self->buffer_size = spec->segsize;
389       } else {
390         self->buffer_size = (spec->segsize / self->channels) * out_channels;
391       }
392       break;
393     }
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;
400       self->channels = 2;
401       self->width = 16;
402       self->is_signed = TRUE;
403       self->is_float = FALSE;
404       self->buffer_size = spec->segsize;
405       break;
406     default:
407       return FALSE;
408   }
409
410   return TRUE;
411 }
412
413 static inline void
414 channel_mapping (GstAudioRingBufferSpec * spec,
415     OMX_AUDIO_CHANNELTYPE * eChannelMapping)
416 {
417   gint i, nchan = GST_AUDIO_INFO_CHANNELS (&spec->info);
418
419   for (i = 0; i < nchan; i++) {
420     OMX_AUDIO_CHANNELTYPE pos;
421
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;
426         break;
427       case GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT:
428         pos = OMX_AUDIO_ChannelLF;
429         break;
430       case GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT:
431         pos = OMX_AUDIO_ChannelRF;
432         break;
433       case GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT:
434         pos = OMX_AUDIO_ChannelLS;
435         break;
436       case GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT:
437         pos = OMX_AUDIO_ChannelRS;
438         break;
439       case GST_AUDIO_CHANNEL_POSITION_LFE1:
440         pos = OMX_AUDIO_ChannelLFE;
441         break;
442       case GST_AUDIO_CHANNEL_POSITION_REAR_CENTER:
443         pos = OMX_AUDIO_ChannelCS;
444         break;
445       case GST_AUDIO_CHANNEL_POSITION_REAR_LEFT:
446         pos = OMX_AUDIO_ChannelLR;
447         break;
448       case GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT:
449         pos = OMX_AUDIO_ChannelRR;
450         break;
451       default:
452         pos = OMX_AUDIO_ChannelNone;
453         break;
454     }
455     eChannelMapping[i] = pos;
456   }
457 }
458
459 static inline const gchar *
460 ch2str (OMX_AUDIO_CHANNELTYPE ch)
461 {
462   switch (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";
483     default:
484       return "Invalid value";
485   }
486 }
487
488 static inline gboolean
489 gst_omx_audio_sink_configure_pcm (GstOMXAudioSink * self,
490     GstAudioRingBufferSpec * spec)
491 {
492   OMX_AUDIO_PARAM_PCMMODETYPE param;
493   OMX_ERRORTYPE err;
494
495   GST_OMX_INIT_STRUCT (&param);
496   param.nPortIndex = self->in_port->index;
497   param.nChannels = OUT_CHANNELS (self->channels);
498   param.eNumData =
499       (self->is_signed ? OMX_NumericalDataSigned : OMX_NumericalDataUnsigned);
500   param.eEndian =
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;
506
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
510      */
511     param.ePCMMode = (OMX_AUDIO_PCMMODETYPE) 0x8000;
512   } else {
513     param.ePCMMode = OMX_AUDIO_PCMModeLinear;
514   }
515
516   if (spec->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW) {
517     channel_mapping (spec, &param.eChannelMapping[0]);
518   }
519
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]));
535
536   err =
537       gst_omx_component_set_parameter (self->comp, OMX_IndexParamAudioPcm,
538       &param);
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);
542     return FALSE;
543   }
544
545   return TRUE;
546 }
547
548 static gboolean
549 gst_omx_audio_sink_prepare (GstAudioSink * audiosink,
550     GstAudioRingBufferSpec * spec)
551 {
552   GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (audiosink);
553   OMX_PARAM_PORTDEFINITIONTYPE port_def;
554   OMX_ERRORTYPE err;
555
556   if (!gst_omx_audio_sink_parse_spec (self, spec))
557     goto spec_parse;
558
559   gst_omx_port_get_port_definition (self->in_port, &port_def);
560
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;
566
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);
573
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);
578     goto configuration;
579   }
580
581   if (!gst_omx_audio_sink_configure_pcm (self, spec)) {
582     goto configuration;
583   }
584
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);
589     goto activation;
590   }
591
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);
596     goto activation;
597   }
598
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);
604     goto activation;
605   }
606
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);
611     goto activation;
612   }
613
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);
618     goto activation;
619   }
620
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);
625     goto activation;
626   }
627
628   if (gst_omx_component_get_state (self->comp,
629           GST_CLOCK_TIME_NONE) != OMX_StatePause)
630     goto activation;
631
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);
637
638 #if defined (USE_OMX_TARGET_RPI)
639   {
640     GstOMXAudioSinkClass *klass = GST_OMX_AUDIO_SINK_GET_CLASS (self);
641     OMX_ERRORTYPE err;
642     OMX_CONFIG_BRCMAUDIODESTINATIONTYPE param;
643
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 (&param);
648       strcpy ((char *) param.sName, klass->destination);
649       err = gst_omx_component_set_config (self->comp,
650           OMX_IndexConfigBrcmAudioDestination, &param);
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);
655         goto activation;
656       }
657     }
658   }
659 #endif
660
661   return TRUE;
662
663   /* ERRORS */
664 spec_parse:
665   {
666     GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS, (NULL),
667         ("Error parsing spec"));
668     return FALSE;
669   }
670
671 configuration:
672   {
673     GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS, (NULL),
674         ("Configuration failed"));
675     return FALSE;
676   }
677 activation:
678   {
679     GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS, (NULL),
680         ("Component activation failed"));
681     return FALSE;
682   }
683 }
684
685 static gboolean
686 gst_omx_audio_sink_unprepare (GstAudioSink * audiosink)
687 {
688   GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (audiosink);
689   OMX_ERRORTYPE err;
690
691   if (gst_omx_component_get_state (self->comp, 0) == OMX_StateIdle)
692     return TRUE;
693
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);
698     goto failed;
699   }
700
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);
705     goto failed;
706   }
707
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);
712     goto failed;
713   }
714
715   err = gst_omx_port_wait_buffers_released (self->in_port, 5 * GST_SECOND);
716   if (err != OMX_ErrorNone) {
717     goto failed;
718   }
719
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);
724     goto failed;
725   }
726
727   err = gst_omx_port_wait_enabled (self->in_port, 1 * GST_SECOND);
728   if (err != OMX_ErrorNone) {
729     goto failed;
730   }
731
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);
736     goto failed;
737   }
738
739   gst_omx_component_get_state (self->comp, GST_CLOCK_TIME_NONE);
740
741   return TRUE;
742
743   /* ERRORS */
744 failed:
745   {
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)));
750     return FALSE;
751   }
752 }
753
754 static GstOMXBuffer *
755 gst_omx_audio_sink_acquire_buffer (GstOMXAudioSink * self)
756 {
757   GstOMXAcquireBufferReturn acq_ret = GST_OMX_ACQUIRE_BUFFER_ERROR;
758   GstOMXPort *port = self->in_port;
759   OMX_ERRORTYPE err;
760   GstOMXBuffer *buf = NULL;
761
762   while (!buf) {
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...");
768       goto 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;
777       }
778
779       err = gst_omx_port_wait_buffers_released (port, 5 * GST_SECOND);
780       if (err != OMX_ErrorNone) {
781         goto reconfigure_error;
782       }
783
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;
789       }
790
791       err = gst_omx_port_wait_enabled (port, 1 * GST_SECOND);
792       if (err != OMX_ErrorNone) {
793         goto reconfigure_error;
794       }
795
796       err = gst_omx_port_set_enabled (port, TRUE);
797       if (err != OMX_ErrorNone) {
798         goto reconfigure_error;
799       }
800
801       err = gst_omx_port_allocate_buffers (port);
802       if (err != OMX_ErrorNone) {
803         goto reconfigure_error;
804       }
805
806       err = gst_omx_port_wait_enabled (port, 5 * GST_SECOND);
807       if (err != OMX_ErrorNone) {
808         goto reconfigure_error;
809       }
810
811       err = gst_omx_port_mark_reconfigured (port);
812       if (err != OMX_ErrorNone) {
813         goto reconfigure_error;
814       }
815       continue;
816     }
817   }
818
819   return buf;
820
821   /* ERRORS */
822 component_error:
823   {
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)));
828     return NULL;
829   }
830 reconfigure_error:
831   {
832     GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
833         ("Unable to reconfigure input port"));
834     return NULL;
835   }
836 flushing:
837   {
838     return NULL;
839   }
840 }
841
842 static gint
843 gst_omx_audio_sink_write (GstAudioSink * audiosink, gpointer data, guint length)
844 {
845   GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (audiosink);
846   GstOMXBuffer *buf;
847   OMX_ERRORTYPE err;
848
849   GST_LOG_OBJECT (self, "received audio samples buffer of %u bytes", length);
850
851   GST_OMX_AUDIO_SINK_LOCK (self);
852
853   if (!(buf = gst_omx_audio_sink_acquire_buffer (self))) {
854     goto beach;
855   }
856
857   if (buf->omx_buf->nAllocLen == length) {
858     memcpy (buf->omx_buf->pBuffer + buf->omx_buf->nOffset, data, length);
859   } else {
860     transform (self->channels, self->width, data,
861         buf->omx_buf->pBuffer + buf->omx_buf->nOffset, self->samples);
862   }
863   buf->omx_buf->nFilledLen = buf->omx_buf->nAllocLen;
864
865   err = gst_omx_port_release_buffer (self->in_port, buf);
866   if (err != OMX_ErrorNone)
867     goto release_error;
868
869 beach:
870
871   GST_OMX_AUDIO_SINK_UNLOCK (self);
872
873   return length;
874
875   /* ERRORS */
876 release_error:
877   {
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));
882     return 0;
883   }
884 }
885
886 static guint
887 gst_omx_audio_sink_delay (GstAudioSink * audiosink)
888 {
889   GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (audiosink);
890   OMX_PARAM_U32TYPE param;
891   OMX_ERRORTYPE err;
892
893   GST_OMX_INIT_STRUCT (&param);
894   param.nPortIndex = self->in_port->index;
895   param.nU32 = 0;
896   err = gst_omx_component_get_config (self->comp,
897       OMX_IndexConfigAudioRenderingLatency, &param);
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);
901     param.nU32 = 0;
902   }
903
904   GST_DEBUG_OBJECT (self, "reported delay %d samples", param.nU32);
905   return param.nU32;
906 }
907
908 static void
909 gst_omx_audio_sink_reset (GstAudioSink * audiosink)
910 {
911   GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (audiosink);
912   OMX_STATETYPE state;
913
914   GST_DEBUG_OBJECT (self, "Flushing sink");
915
916   gst_omx_port_set_flushing (self->in_port, 5 * GST_SECOND, TRUE);
917
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);
922   }
923
924   gst_omx_component_set_state (self->comp, state);
925   gst_omx_component_get_state (self->comp, GST_CLOCK_TIME_NONE);
926
927   gst_omx_port_set_flushing (self->in_port, 5 * GST_SECOND, FALSE);
928
929   GST_OMX_AUDIO_SINK_UNLOCK (self);
930 }
931
932 static GstBuffer *
933 gst_omx_audio_sink_payload (GstAudioBaseSink * audiobasesink, GstBuffer * buf)
934 {
935   GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (audiobasesink);
936
937   if (self->iec61937) {
938     GstBuffer *out;
939     gint framesize;
940     GstMapInfo iinfo, oinfo;
941     GstAudioRingBufferSpec *spec = &audiobasesink->ringbuffer->spec;
942
943     framesize = gst_audio_iec61937_frame_size (spec);
944     if (framesize <= 0)
945       return NULL;
946
947     out = gst_buffer_new_and_alloc (framesize);
948
949     gst_buffer_map (buf, &iinfo, GST_MAP_READ);
950     gst_buffer_map (out, &oinfo, GST_MAP_WRITE);
951
952     if (!gst_audio_iec61937_payload (iinfo.data, iinfo.size,
953             oinfo.data, oinfo.size, spec, G_BIG_ENDIAN)) {
954       gst_buffer_unref (out);
955       return NULL;
956     }
957
958     gst_buffer_unmap (buf, &iinfo);
959     gst_buffer_unmap (out, &oinfo);
960
961     gst_buffer_copy_into (out, buf, GST_BUFFER_COPY_METADATA, 0, -1);
962     return out;
963   }
964
965   return gst_buffer_ref (buf);
966 }
967
968 static gboolean
969 gst_omx_audio_sink_accept_caps (GstOMXAudioSink * self, GstCaps * caps)
970 {
971   GstPad *pad = GST_BASE_SINK (self)->sinkpad;
972   GstCaps *pad_caps;
973   GstStructure *st;
974   gboolean ret = FALSE;
975   GstAudioRingBufferSpec spec = { 0 };
976
977   pad_caps = gst_pad_query_caps (pad, caps);
978   if (!pad_caps || gst_caps_is_empty (pad_caps)) {
979     if (pad_caps)
980       gst_caps_unref (pad_caps);
981     ret = FALSE;
982     goto done;
983   }
984   gst_caps_unref (pad_caps);
985
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))
989     goto done;
990
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))
995     goto done;
996
997   /* Make sure input is framed (one frame per buffer) and can be payloaded */
998   switch (spec.type) {
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:
1003     {
1004       gboolean framed = FALSE, parsed = FALSE;
1005       st = gst_caps_get_structure (caps, 0);
1006
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)
1010         goto done;
1011     }
1012     default:{
1013     }
1014   }
1015   ret = TRUE;
1016
1017 done:
1018   gst_caps_replace (&spec.caps, NULL);
1019   return ret;
1020 }
1021
1022 static gboolean
1023 gst_omx_audio_sink_query (GstBaseSink * basesink, GstQuery * query)
1024 {
1025   GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (basesink);
1026   gboolean ret;
1027
1028   switch (GST_QUERY_TYPE (query)) {
1029     case GST_QUERY_ACCEPT_CAPS:
1030     {
1031       GstCaps *caps;
1032
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);
1036       ret = TRUE;
1037       break;
1038     }
1039     default:
1040       ret = GST_BASE_SINK_CLASS (parent_class)->query (basesink, query);
1041       break;
1042   }
1043   return ret;
1044 }
1045
1046 static void
1047 gst_omx_audio_sink_set_property (GObject * object, guint prop_id,
1048     const GValue * value, GParamSpec * pspec)
1049 {
1050   GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (object);
1051
1052   switch (prop_id) {
1053     case PROP_MUTE:
1054     {
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);
1059       }
1060       GST_OBJECT_UNLOCK (self);
1061       break;
1062     }
1063     case PROP_VOLUME:
1064     {
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);
1069       }
1070       GST_OBJECT_UNLOCK (self);
1071       break;
1072     }
1073     default:
1074       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1075       break;
1076   }
1077 }
1078
1079 static void
1080 gst_omx_audio_sink_get_property (GObject * object, guint prop_id,
1081     GValue * value, GParamSpec * pspec)
1082 {
1083   GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (object);
1084
1085   switch (prop_id) {
1086     case PROP_MUTE:
1087       GST_OBJECT_LOCK (self);
1088       g_value_set_boolean (value, self->mute);
1089       GST_OBJECT_UNLOCK (self);
1090       break;
1091     case PROP_VOLUME:
1092       GST_OBJECT_LOCK (self);
1093       g_value_set_double (value, self->volume);
1094       GST_OBJECT_UNLOCK (self);
1095       break;
1096     default:
1097       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1098       break;
1099   }
1100 }
1101
1102 static GstStateChangeReturn
1103 gst_omx_audio_sink_change_state (GstElement * element,
1104     GstStateChange transition)
1105 {
1106   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1107   GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (element);
1108   OMX_ERRORTYPE err;
1109
1110   switch (transition) {
1111     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1112     {
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;
1119       }
1120
1121       if (gst_omx_component_get_state (self->comp,
1122               GST_CLOCK_TIME_NONE) != OMX_StateExecuting) {
1123         return GST_STATE_CHANGE_FAILURE;
1124       }
1125       GST_DEBUG_OBJECT (self, "in PLAYING state");
1126       break;
1127     }
1128     default:
1129       break;
1130   }
1131
1132   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1133
1134   switch (transition) {
1135     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1136     {
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;
1143       }
1144
1145       if (gst_omx_component_get_state (self->comp,
1146               GST_CLOCK_TIME_NONE) != OMX_StatePause) {
1147         return GST_STATE_CHANGE_FAILURE;
1148       }
1149       GST_DEBUG_OBJECT (self, "in PAUSED state");
1150       break;
1151     }
1152     default:
1153       break;
1154   }
1155
1156   return ret;
1157 }
1158
1159 static void
1160 gst_omx_audio_sink_finalize (GObject * object)
1161 {
1162   GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (object);
1163
1164   g_mutex_clear (&self->lock);
1165
1166   G_OBJECT_CLASS (parent_class)->finalize (object);
1167 }
1168
1169 static void
1170 gst_omx_audio_sink_class_init (GstOMXAudioSinkClass * klass)
1171 {
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);
1177
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;
1181
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));
1185
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));
1190
1191   element_class->change_state =
1192       GST_DEBUG_FUNCPTR (gst_omx_audio_sink_change_state);
1193
1194   basesink_class->query = GST_DEBUG_FUNCPTR (gst_omx_audio_sink_query);
1195
1196   baudiosink_class->payload = GST_DEBUG_FUNCPTR (gst_omx_audio_sink_payload);
1197
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);
1205
1206
1207   klass->cdata.type = GST_OMX_COMPONENT_TYPE_SINK;
1208 }
1209
1210 static void
1211 gst_omx_audio_sink_init (GstOMXAudioSink * self)
1212 {
1213   g_mutex_init (&self->lock);
1214
1215   self->mute = DEFAULT_PROP_MUTE;
1216   self->volume = DEFAULT_PROP_VOLUME;
1217
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
1221    * general. */
1222   GST_AUDIO_BASE_SINK (self)->buffer_time = 400000;
1223   gst_audio_base_sink_set_provide_clock (GST_AUDIO_BASE_SINK (self), TRUE);
1224 }