omxvideoenc: drain encoder on ALLOCATION and DRAIN queries
[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           (gint) 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 disable 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 disable 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_unref (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: %u", (guint) 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: %u", (guint) param.nBitPerSample);
528   GST_DEBUG_OBJECT (self, "  nSamplingRate: %u", (guint) 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: %u", (guint) port_def.nBufferSize);
569   GST_DEBUG_OBJECT (self, "  nBufferCountActual: %u", (guint)
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_flushing (self->in_port, 5 * GST_SECOND, FALSE);
593   if (err != OMX_ErrorNone) {
594     GST_ERROR_OBJECT (self, "Failed to set port not flushing: %s (0x%08x)",
595         gst_omx_error_to_string (err), err);
596     goto activation;
597   }
598
599   err = gst_omx_port_set_enabled (self->in_port, TRUE);
600   if (err != OMX_ErrorNone) {
601     GST_ERROR_OBJECT (self, "Failed to enable port: %s (0x%08x)",
602         gst_omx_error_to_string (err), err);
603     goto activation;
604   }
605
606   GST_DEBUG_OBJECT (self, "Allocate buffers");
607   err = gst_omx_port_allocate_buffers (self->in_port);
608   if (err != OMX_ErrorNone) {
609     GST_ERROR_OBJECT (self, "Failed on buffer allocation: %s (0x%08x)",
610         gst_omx_error_to_string (err), err);
611     goto activation;
612   }
613
614   err = gst_omx_port_wait_enabled (self->in_port, 5 * GST_SECOND);
615   if (err != OMX_ErrorNone) {
616     GST_ERROR_OBJECT (self, "port not enabled: %s (0x%08x)",
617         gst_omx_error_to_string (err), err);
618     goto activation;
619   }
620
621   err = gst_omx_port_mark_reconfigured (self->in_port);
622   if (err != OMX_ErrorNone) {
623     GST_ERROR_OBJECT (self, "Couln't mark port as reconfigured: %s (0x%08x)",
624         gst_omx_error_to_string (err), err);
625     goto activation;
626   }
627
628   err = gst_omx_component_set_state (self->comp, OMX_StatePause);
629   if (err != OMX_ErrorNone) {
630     GST_ERROR_OBJECT (self, "Failed to set state paused: %s (0x%08x)",
631         gst_omx_error_to_string (err), err);
632     goto activation;
633   }
634
635   if (gst_omx_component_get_state (self->comp,
636           GST_CLOCK_TIME_NONE) != OMX_StatePause)
637     goto activation;
638
639   /* Configure some parameters */
640   GST_OBJECT_LOCK (self);
641   gst_omx_audio_sink_mute_set (self, self->mute);
642   gst_omx_audio_sink_volume_set (self, self->volume);
643   GST_OBJECT_UNLOCK (self);
644
645 #if defined (USE_OMX_TARGET_RPI)
646   {
647     GstOMXAudioSinkClass *klass = GST_OMX_AUDIO_SINK_GET_CLASS (self);
648     OMX_ERRORTYPE err;
649     OMX_CONFIG_BRCMAUDIODESTINATIONTYPE param;
650
651     if (klass->destination
652         && strlen (klass->destination) < sizeof (param.sName)) {
653       GST_DEBUG_OBJECT (self, "Setting destination: %s", klass->destination);
654       GST_OMX_INIT_STRUCT (&param);
655       strcpy ((char *) param.sName, klass->destination);
656       err = gst_omx_component_set_config (self->comp,
657           OMX_IndexConfigBrcmAudioDestination, &param);
658       if (err != OMX_ErrorNone) {
659         GST_ERROR_OBJECT (self,
660             "Failed to configuring destination: %s (0x%08x)",
661             gst_omx_error_to_string (err), err);
662         goto activation;
663       }
664     }
665   }
666 #endif
667
668   return TRUE;
669
670   /* ERRORS */
671 spec_parse:
672   {
673     GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS, (NULL),
674         ("Error parsing spec"));
675     return FALSE;
676   }
677
678 configuration:
679   {
680     GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS, (NULL),
681         ("Configuration failed"));
682     return FALSE;
683   }
684 activation:
685   {
686     GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS, (NULL),
687         ("Component activation failed"));
688     return FALSE;
689   }
690 }
691
692 static gboolean
693 gst_omx_audio_sink_unprepare (GstAudioSink * audiosink)
694 {
695   GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (audiosink);
696   OMX_ERRORTYPE err;
697
698   if (gst_omx_component_get_state (self->comp, 0) == OMX_StateIdle)
699     return TRUE;
700
701   err = gst_omx_port_set_flushing (self->in_port, 5 * GST_SECOND, TRUE);
702   if (err != OMX_ErrorNone) {
703     GST_ERROR_OBJECT (self, "Failed to set port flushing: %s (0x%08x)",
704         gst_omx_error_to_string (err), err);
705     goto failed;
706   }
707
708   err = gst_omx_component_set_state (self->comp, OMX_StateIdle);
709   if (err != OMX_ErrorNone) {
710     GST_ERROR_OBJECT (self, "Failed to set state idle: %s (0x%08x)",
711         gst_omx_error_to_string (err), err);
712     goto failed;
713   }
714
715   err = gst_omx_port_set_enabled (self->in_port, FALSE);
716   if (err != OMX_ErrorNone) {
717     GST_ERROR_OBJECT (self, "Failed to set port disabled: %s (0x%08x)",
718         gst_omx_error_to_string (err), err);
719     goto failed;
720   }
721
722   err = gst_omx_port_wait_buffers_released (self->in_port, 5 * GST_SECOND);
723   if (err != OMX_ErrorNone) {
724     goto failed;
725   }
726
727   err = gst_omx_port_deallocate_buffers (self->in_port);
728   if (err != OMX_ErrorNone) {
729     GST_ERROR_OBJECT (self, "Couldn't deallocate buffers: %s (0x%08x)",
730         gst_omx_error_to_string (err), err);
731     goto failed;
732   }
733
734   err = gst_omx_port_wait_enabled (self->in_port, 1 * GST_SECOND);
735   if (err != OMX_ErrorNone) {
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, GST_OMX_WAIT);
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 #if defined (USE_OMX_TARGET_RPI)
890   GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (audiosink);
891   OMX_PARAM_U32TYPE param;
892   OMX_ERRORTYPE err;
893
894   GST_OMX_INIT_STRUCT (&param);
895   param.nPortIndex = self->in_port->index;
896   param.nU32 = 0;
897   err = gst_omx_component_get_config (self->comp,
898       OMX_IndexConfigAudioRenderingLatency, &param);
899   if (err != OMX_ErrorNone) {
900     GST_ERROR_OBJECT (self, "Failed to get rendering latency: %s (0x%08x)",
901         gst_omx_error_to_string (err), err);
902     param.nU32 = 0;
903   }
904
905   GST_DEBUG_OBJECT (self, "reported delay %u samples", (guint) param.nU32);
906   return param.nU32;
907 #else
908   return 0;
909 #endif
910 }
911
912 static void
913 gst_omx_audio_sink_reset (GstAudioSink * audiosink)
914 {
915   GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (audiosink);
916   OMX_STATETYPE state;
917
918   GST_DEBUG_OBJECT (self, "Flushing sink");
919
920   gst_omx_port_set_flushing (self->in_port, 5 * GST_SECOND, TRUE);
921
922   GST_OMX_AUDIO_SINK_LOCK (self);
923   if ((state = gst_omx_component_get_state (self->comp, 0)) > OMX_StatePause) {
924     gst_omx_component_set_state (self->comp, OMX_StatePause);
925     gst_omx_component_get_state (self->comp, GST_CLOCK_TIME_NONE);
926   }
927
928   gst_omx_component_set_state (self->comp, state);
929   gst_omx_component_get_state (self->comp, GST_CLOCK_TIME_NONE);
930
931   gst_omx_port_set_flushing (self->in_port, 5 * GST_SECOND, FALSE);
932
933   GST_OMX_AUDIO_SINK_UNLOCK (self);
934 }
935
936 static GstBuffer *
937 gst_omx_audio_sink_payload (GstAudioBaseSink * audiobasesink, GstBuffer * buf)
938 {
939   GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (audiobasesink);
940
941   if (self->iec61937) {
942     GstBuffer *out;
943     gint framesize;
944     GstMapInfo iinfo, oinfo;
945     GstAudioRingBufferSpec *spec = &audiobasesink->ringbuffer->spec;
946
947     framesize = gst_audio_iec61937_frame_size (spec);
948     if (framesize <= 0)
949       return NULL;
950
951     out = gst_buffer_new_and_alloc (framesize);
952
953     gst_buffer_map (buf, &iinfo, GST_MAP_READ);
954     gst_buffer_map (out, &oinfo, GST_MAP_WRITE);
955
956     if (!gst_audio_iec61937_payload (iinfo.data, iinfo.size,
957             oinfo.data, oinfo.size, spec, G_BIG_ENDIAN)) {
958       gst_buffer_unref (out);
959       return NULL;
960     }
961
962     gst_buffer_unmap (buf, &iinfo);
963     gst_buffer_unmap (out, &oinfo);
964
965     gst_buffer_copy_into (out, buf, GST_BUFFER_COPY_METADATA, 0, -1);
966     return out;
967   }
968
969   return gst_buffer_ref (buf);
970 }
971
972 static gboolean
973 gst_omx_audio_sink_accept_caps (GstOMXAudioSink * self, GstCaps * caps)
974 {
975   GstPad *pad = GST_BASE_SINK (self)->sinkpad;
976   GstCaps *pad_caps;
977   GstStructure *st;
978   gboolean ret = FALSE;
979   GstAudioRingBufferSpec spec = { 0 };
980
981   pad_caps = gst_pad_query_caps (pad, caps);
982   if (!pad_caps || gst_caps_is_empty (pad_caps)) {
983     if (pad_caps)
984       gst_caps_unref (pad_caps);
985     ret = FALSE;
986     goto done;
987   }
988   gst_caps_unref (pad_caps);
989
990   /* If we've not got fixed caps, creating a stream might fail, so let's just
991    * return from here with default acceptcaps behaviour */
992   if (!gst_caps_is_fixed (caps))
993     goto done;
994
995   /* parse helper expects this set, so avoid nasty warning
996    * will be set properly later on anyway  */
997   spec.latency_time = GST_SECOND;
998   if (!gst_audio_ring_buffer_parse_caps (&spec, caps))
999     goto done;
1000
1001   /* Make sure input is framed (one frame per buffer) and can be payloaded */
1002   switch (spec.type) {
1003     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_AC3:
1004     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_EAC3:
1005     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_DTS:
1006     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG:
1007     {
1008       gboolean framed = FALSE, parsed = FALSE;
1009       st = gst_caps_get_structure (caps, 0);
1010
1011       gst_structure_get_boolean (st, "framed", &framed);
1012       gst_structure_get_boolean (st, "parsed", &parsed);
1013       if ((!framed && !parsed) || gst_audio_iec61937_frame_size (&spec) <= 0)
1014         goto done;
1015     }
1016     default:{
1017     }
1018   }
1019   ret = TRUE;
1020
1021 done:
1022   gst_caps_replace (&spec.caps, NULL);
1023   return ret;
1024 }
1025
1026 static gboolean
1027 gst_omx_audio_sink_query (GstBaseSink * basesink, GstQuery * query)
1028 {
1029   GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (basesink);
1030   gboolean ret;
1031
1032   switch (GST_QUERY_TYPE (query)) {
1033     case GST_QUERY_ACCEPT_CAPS:
1034     {
1035       GstCaps *caps;
1036
1037       gst_query_parse_accept_caps (query, &caps);
1038       ret = gst_omx_audio_sink_accept_caps (self, caps);
1039       gst_query_set_accept_caps_result (query, ret);
1040       ret = TRUE;
1041       break;
1042     }
1043     default:
1044       ret = GST_BASE_SINK_CLASS (parent_class)->query (basesink, query);
1045       break;
1046   }
1047   return ret;
1048 }
1049
1050 static void
1051 gst_omx_audio_sink_set_property (GObject * object, guint prop_id,
1052     const GValue * value, GParamSpec * pspec)
1053 {
1054   GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (object);
1055
1056   switch (prop_id) {
1057     case PROP_MUTE:
1058     {
1059       gboolean mute = g_value_get_boolean (value);
1060       GST_OBJECT_LOCK (self);
1061       if (self->mute != mute) {
1062         gst_omx_audio_sink_mute_set (self, mute);
1063       }
1064       GST_OBJECT_UNLOCK (self);
1065       break;
1066     }
1067     case PROP_VOLUME:
1068     {
1069       gdouble volume = g_value_get_double (value);
1070       GST_OBJECT_LOCK (self);
1071       if (volume != self->volume) {
1072         gst_omx_audio_sink_volume_set (self, volume);
1073       }
1074       GST_OBJECT_UNLOCK (self);
1075       break;
1076     }
1077     default:
1078       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1079       break;
1080   }
1081 }
1082
1083 static void
1084 gst_omx_audio_sink_get_property (GObject * object, guint prop_id,
1085     GValue * value, GParamSpec * pspec)
1086 {
1087   GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (object);
1088
1089   switch (prop_id) {
1090     case PROP_MUTE:
1091       GST_OBJECT_LOCK (self);
1092       g_value_set_boolean (value, self->mute);
1093       GST_OBJECT_UNLOCK (self);
1094       break;
1095     case PROP_VOLUME:
1096       GST_OBJECT_LOCK (self);
1097       g_value_set_double (value, self->volume);
1098       GST_OBJECT_UNLOCK (self);
1099       break;
1100     default:
1101       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1102       break;
1103   }
1104 }
1105
1106 static GstStateChangeReturn
1107 gst_omx_audio_sink_change_state (GstElement * element,
1108     GstStateChange transition)
1109 {
1110   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1111   GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (element);
1112   OMX_ERRORTYPE err;
1113
1114   switch (transition) {
1115     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1116     {
1117       GST_DEBUG_OBJECT (self, "going to PLAYING state");
1118       err = gst_omx_component_set_state (self->comp, OMX_StateExecuting);
1119       if (err != OMX_ErrorNone) {
1120         GST_ERROR_OBJECT (self, "Failed to set state executing: %s (0x%08x)",
1121             gst_omx_error_to_string (err), err);
1122         return GST_STATE_CHANGE_FAILURE;
1123       }
1124
1125       if (gst_omx_component_get_state (self->comp,
1126               GST_CLOCK_TIME_NONE) != OMX_StateExecuting) {
1127         return GST_STATE_CHANGE_FAILURE;
1128       }
1129       GST_DEBUG_OBJECT (self, "in PLAYING state");
1130       break;
1131     }
1132     default:
1133       break;
1134   }
1135
1136   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1137
1138   switch (transition) {
1139     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1140     {
1141       GST_DEBUG_OBJECT (self, "going to PAUSED state");
1142       err = gst_omx_component_set_state (self->comp, OMX_StatePause);
1143       if (err != OMX_ErrorNone) {
1144         GST_ERROR_OBJECT (self, "Failed to set state paused: %s (0x%08x)",
1145             gst_omx_error_to_string (err), err);
1146         return GST_STATE_CHANGE_FAILURE;
1147       }
1148
1149       if (gst_omx_component_get_state (self->comp,
1150               GST_CLOCK_TIME_NONE) != OMX_StatePause) {
1151         return GST_STATE_CHANGE_FAILURE;
1152       }
1153       GST_DEBUG_OBJECT (self, "in PAUSED state");
1154       break;
1155     }
1156     default:
1157       break;
1158   }
1159
1160   return ret;
1161 }
1162
1163 static void
1164 gst_omx_audio_sink_finalize (GObject * object)
1165 {
1166   GstOMXAudioSink *self = GST_OMX_AUDIO_SINK (object);
1167
1168   g_mutex_clear (&self->lock);
1169
1170   G_OBJECT_CLASS (parent_class)->finalize (object);
1171 }
1172
1173 static void
1174 gst_omx_audio_sink_class_init (GstOMXAudioSinkClass * klass)
1175 {
1176   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1177   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
1178   GstBaseSinkClass *basesink_class = GST_BASE_SINK_CLASS (klass);
1179   GstAudioBaseSinkClass *baudiosink_class = GST_AUDIO_BASE_SINK_CLASS (klass);
1180   GstAudioSinkClass *audiosink_class = GST_AUDIO_SINK_CLASS (klass);
1181
1182   gobject_class->set_property = gst_omx_audio_sink_set_property;
1183   gobject_class->get_property = gst_omx_audio_sink_get_property;
1184   gobject_class->finalize = gst_omx_audio_sink_finalize;
1185
1186   g_object_class_install_property (gobject_class, PROP_MUTE,
1187       g_param_spec_boolean ("mute", "Mute", "mute channel",
1188           DEFAULT_PROP_MUTE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1189
1190   g_object_class_install_property (gobject_class, PROP_VOLUME,
1191       g_param_spec_double ("volume", "Volume", "volume factor, 1.0=100%",
1192           0.0, VOLUME_MAX_DOUBLE, DEFAULT_PROP_VOLUME,
1193           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1194
1195   element_class->change_state =
1196       GST_DEBUG_FUNCPTR (gst_omx_audio_sink_change_state);
1197
1198   basesink_class->query = GST_DEBUG_FUNCPTR (gst_omx_audio_sink_query);
1199
1200   baudiosink_class->payload = GST_DEBUG_FUNCPTR (gst_omx_audio_sink_payload);
1201
1202   audiosink_class->open = GST_DEBUG_FUNCPTR (gst_omx_audio_sink_open);
1203   audiosink_class->close = GST_DEBUG_FUNCPTR (gst_omx_audio_sink_close);
1204   audiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_omx_audio_sink_prepare);
1205   audiosink_class->unprepare = GST_DEBUG_FUNCPTR (gst_omx_audio_sink_unprepare);
1206   audiosink_class->write = GST_DEBUG_FUNCPTR (gst_omx_audio_sink_write);
1207   audiosink_class->delay = GST_DEBUG_FUNCPTR (gst_omx_audio_sink_delay);
1208   audiosink_class->reset = GST_DEBUG_FUNCPTR (gst_omx_audio_sink_reset);
1209
1210
1211   klass->cdata.type = GST_OMX_COMPONENT_TYPE_SINK;
1212 }
1213
1214 static void
1215 gst_omx_audio_sink_init (GstOMXAudioSink * self)
1216 {
1217   g_mutex_init (&self->lock);
1218
1219   self->mute = DEFAULT_PROP_MUTE;
1220   self->volume = DEFAULT_PROP_VOLUME;
1221
1222   /* For the Raspberry PI there's a big hw buffer and 400 ms seems a good
1223    * size for our ringbuffer. OpenSL ES Sink also allocates a buffer of 400 ms
1224    * in Android so I guess that this should be a sane value for OpenMax in
1225    * general. */
1226   GST_AUDIO_BASE_SINK (self)->buffer_time = 400000;
1227   gst_audio_base_sink_set_provide_clock (GST_AUDIO_BASE_SINK (self), TRUE);
1228 }