• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2001 Thomas <thomas@apestaart.org>
4  *               2005,2006 Wim Taymans <wim@fluendo.com>
5  *                    2013 Sebastian Dröge <sebastian@centricular.com>
6  *
7  * audiomixer.c: AudioMixer element, N in, one out, samples are added
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24 /**
25  * SECTION:element-audiomixer
26  * @title: audiomixer
27  *
28  * The audiomixer allows to mix several streams into one by adding the data.
29  * Mixed data is clamped to the min/max values of the data format.
30  *
31  * Unlike the adder element audiomixer properly synchronises all input streams
32  * and also handles live inputs such as capture sources or RTP properly.
33  *
34  * The audiomixer element can accept any sort of raw audio data, it will
35  * be converted to the target format if necessary, with the exception
36  * of the sample rate, which has to be identical to either what downstream
37  * expects, or the sample rate of the first configured pad. Use a capsfilter
38  * after the audiomixer element if you want to precisely control the format
39  * that comes out of the audiomixer, which supports changing the format of
40  * its output while playing.
41  *
42  * If you want to control the manner in which incoming data gets converted,
43  * see the #GstAudioAggregatorConvertPad:converter-config property, which will let
44  * you for example change the way in which channels may get remapped.
45  *
46  * The input pads are from a GstPad subclass and have additional
47  * properties to mute each pad individually and set the volume:
48  *
49  * * "mute": Whether to mute the pad or not (#gboolean)
50  * * "volume": The volume of the pad, between 0.0 and 10.0 (#gdouble)
51  *
52  * ## Example launch line
53  * |[
54  * gst-launch-1.0 audiotestsrc freq=100 ! audiomixer name=mix ! audioconvert ! alsasink audiotestsrc freq=500 ! mix.
55  * ]| This pipeline produces two sine waves mixed together.
56  *
57  */
58 
59 #ifdef HAVE_CONFIG_H
60 #include "config.h"
61 #endif
62 
63 #include "gstaudiomixerelements.h"
64 #include "gstaudiomixerorc.h"
65 
66 
67 #define DEFAULT_PAD_VOLUME (1.0)
68 #define DEFAULT_PAD_MUTE (FALSE)
69 
70 /* some defines for audio processing */
71 /* the volume factor is a range from 0.0 to (arbitrary) VOLUME_MAX_DOUBLE = 10.0
72  * we map 1.0 to VOLUME_UNITY_INT*
73  */
74 #define VOLUME_UNITY_INT8            8  /* internal int for unity 2^(8-5) */
75 #define VOLUME_UNITY_INT8_BIT_SHIFT  3  /* number of bits to shift for unity */
76 #define VOLUME_UNITY_INT16           2048       /* internal int for unity 2^(16-5) */
77 #define VOLUME_UNITY_INT16_BIT_SHIFT 11 /* number of bits to shift for unity */
78 #define VOLUME_UNITY_INT24           524288     /* internal int for unity 2^(24-5) */
79 #define VOLUME_UNITY_INT24_BIT_SHIFT 19 /* number of bits to shift for unity */
80 #define VOLUME_UNITY_INT32           134217728  /* internal int for unity 2^(32-5) */
81 #define VOLUME_UNITY_INT32_BIT_SHIFT 27
82 
83 enum
84 {
85   PROP_PAD_0,
86   PROP_PAD_VOLUME,
87   PROP_PAD_MUTE
88 };
89 
90 G_DEFINE_TYPE (GstAudioMixerPad, gst_audiomixer_pad,
91     GST_TYPE_AUDIO_AGGREGATOR_CONVERT_PAD);
92 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (audiomixer, "audiomixer",
93     GST_RANK_NONE, GST_TYPE_AUDIO_MIXER, audiomixer_element_init (plugin));
94 
95 static void
gst_audiomixer_pad_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)96 gst_audiomixer_pad_get_property (GObject * object, guint prop_id,
97     GValue * value, GParamSpec * pspec)
98 {
99   GstAudioMixerPad *pad = GST_AUDIO_MIXER_PAD (object);
100 
101   switch (prop_id) {
102     case PROP_PAD_VOLUME:
103       g_value_set_double (value, pad->volume);
104       break;
105     case PROP_PAD_MUTE:
106       g_value_set_boolean (value, pad->mute);
107       break;
108     default:
109       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
110       break;
111   }
112 }
113 
114 static void
gst_audiomixer_pad_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)115 gst_audiomixer_pad_set_property (GObject * object, guint prop_id,
116     const GValue * value, GParamSpec * pspec)
117 {
118   GstAudioMixerPad *pad = GST_AUDIO_MIXER_PAD (object);
119 
120   switch (prop_id) {
121     case PROP_PAD_VOLUME:
122       GST_OBJECT_LOCK (pad);
123       pad->volume = g_value_get_double (value);
124       pad->volume_i8 = pad->volume * VOLUME_UNITY_INT8;
125       pad->volume_i16 = pad->volume * VOLUME_UNITY_INT16;
126       pad->volume_i32 = pad->volume * VOLUME_UNITY_INT32;
127       GST_OBJECT_UNLOCK (pad);
128       break;
129     case PROP_PAD_MUTE:
130       GST_OBJECT_LOCK (pad);
131       pad->mute = g_value_get_boolean (value);
132       GST_OBJECT_UNLOCK (pad);
133       break;
134     default:
135       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
136       break;
137   }
138 }
139 
140 static void
gst_audiomixer_pad_class_init(GstAudioMixerPadClass * klass)141 gst_audiomixer_pad_class_init (GstAudioMixerPadClass * klass)
142 {
143   GObjectClass *gobject_class = (GObjectClass *) klass;
144 
145   gobject_class->set_property = gst_audiomixer_pad_set_property;
146   gobject_class->get_property = gst_audiomixer_pad_get_property;
147 
148   g_object_class_install_property (gobject_class, PROP_PAD_VOLUME,
149       g_param_spec_double ("volume", "Volume", "Volume of this pad",
150           0.0, 10.0, DEFAULT_PAD_VOLUME,
151           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
152   g_object_class_install_property (gobject_class, PROP_PAD_MUTE,
153       g_param_spec_boolean ("mute", "Mute", "Mute this pad",
154           DEFAULT_PAD_MUTE,
155           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
156 }
157 
158 static void
gst_audiomixer_pad_init(GstAudioMixerPad * pad)159 gst_audiomixer_pad_init (GstAudioMixerPad * pad)
160 {
161   pad->volume = DEFAULT_PAD_VOLUME;
162   pad->mute = DEFAULT_PAD_MUTE;
163 }
164 
165 enum
166 {
167   PROP_0
168 };
169 
170 /* These are the formats we can mix natively */
171 
172 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
173 #define CAPS \
174   GST_AUDIO_CAPS_MAKE ("{ S32LE, U32LE, S16LE, U16LE, S8, U8, F32LE, F64LE }") \
175   ", layout = interleaved"
176 #else
177 #define CAPS \
178   GST_AUDIO_CAPS_MAKE ("{ S32BE, U32BE, S16BE, U16BE, S8, U8, F32BE, F64BE }") \
179   ", layout = interleaved"
180 #endif
181 
182 static GstStaticPadTemplate gst_audiomixer_src_template =
183 GST_STATIC_PAD_TEMPLATE ("src",
184     GST_PAD_SRC,
185     GST_PAD_ALWAYS,
186     GST_STATIC_CAPS (CAPS)
187     );
188 
189 #define SINK_CAPS \
190   GST_STATIC_CAPS (GST_AUDIO_CAPS_MAKE (GST_AUDIO_FORMATS_ALL) \
191       ", layout=interleaved")
192 
193 static GstStaticPadTemplate gst_audiomixer_sink_template =
194 GST_STATIC_PAD_TEMPLATE ("sink_%u",
195     GST_PAD_SINK,
196     GST_PAD_REQUEST,
197     SINK_CAPS);
198 
199 static void gst_audiomixer_child_proxy_init (gpointer g_iface,
200     gpointer iface_data);
201 
202 #define gst_audiomixer_parent_class parent_class
203 G_DEFINE_TYPE_WITH_CODE (GstAudioMixer, gst_audiomixer,
204     GST_TYPE_AUDIO_AGGREGATOR, G_IMPLEMENT_INTERFACE (GST_TYPE_CHILD_PROXY,
205         gst_audiomixer_child_proxy_init));
206 
207 static GstPad *gst_audiomixer_request_new_pad (GstElement * element,
208     GstPadTemplate * temp, const gchar * req_name, const GstCaps * caps);
209 static void gst_audiomixer_release_pad (GstElement * element, GstPad * pad);
210 
211 static gboolean
212 gst_audiomixer_aggregate_one_buffer (GstAudioAggregator * aagg,
213     GstAudioAggregatorPad * aaggpad, GstBuffer * inbuf, guint in_offset,
214     GstBuffer * outbuf, guint out_offset, guint num_samples);
215 
216 
217 static void
gst_audiomixer_class_init(GstAudioMixerClass * klass)218 gst_audiomixer_class_init (GstAudioMixerClass * klass)
219 {
220   GstElementClass *gstelement_class = (GstElementClass *) klass;
221   GstAudioAggregatorClass *aagg_class = (GstAudioAggregatorClass *) klass;
222 
223   gst_element_class_add_static_pad_template_with_gtype (gstelement_class,
224       &gst_audiomixer_src_template, GST_TYPE_AUDIO_AGGREGATOR_CONVERT_PAD);
225   gst_element_class_add_static_pad_template_with_gtype (gstelement_class,
226       &gst_audiomixer_sink_template, GST_TYPE_AUDIO_MIXER_PAD);
227   gst_element_class_set_static_metadata (gstelement_class, "AudioMixer",
228       "Generic/Audio", "Mixes multiple audio streams",
229       "Sebastian Dröge <sebastian@centricular.com>");
230 
231   gstelement_class->request_new_pad =
232       GST_DEBUG_FUNCPTR (gst_audiomixer_request_new_pad);
233   gstelement_class->release_pad =
234       GST_DEBUG_FUNCPTR (gst_audiomixer_release_pad);
235 
236   aagg_class->aggregate_one_buffer = gst_audiomixer_aggregate_one_buffer;
237 
238   gst_type_mark_as_plugin_api (GST_TYPE_AUDIO_MIXER_PAD, 0);
239 }
240 
241 static void
gst_audiomixer_init(GstAudioMixer * audiomixer)242 gst_audiomixer_init (GstAudioMixer * audiomixer)
243 {
244 }
245 
246 static GstPad *
gst_audiomixer_request_new_pad(GstElement * element,GstPadTemplate * templ,const gchar * req_name,const GstCaps * caps)247 gst_audiomixer_request_new_pad (GstElement * element, GstPadTemplate * templ,
248     const gchar * req_name, const GstCaps * caps)
249 {
250   GstAudioMixerPad *newpad;
251 
252   newpad = (GstAudioMixerPad *)
253       GST_ELEMENT_CLASS (parent_class)->request_new_pad (element,
254       templ, req_name, caps);
255 
256   if (newpad == NULL)
257     goto could_not_create;
258 
259   gst_child_proxy_child_added (GST_CHILD_PROXY (element), G_OBJECT (newpad),
260       GST_OBJECT_NAME (newpad));
261 
262   return GST_PAD_CAST (newpad);
263 
264 could_not_create:
265   {
266     GST_DEBUG_OBJECT (element, "could not create/add  pad");
267     return NULL;
268   }
269 }
270 
271 static void
gst_audiomixer_release_pad(GstElement * element,GstPad * pad)272 gst_audiomixer_release_pad (GstElement * element, GstPad * pad)
273 {
274   GstAudioMixer *audiomixer;
275 
276   audiomixer = GST_AUDIO_MIXER (element);
277 
278   GST_DEBUG_OBJECT (audiomixer, "release pad %s:%s", GST_DEBUG_PAD_NAME (pad));
279 
280   gst_child_proxy_child_removed (GST_CHILD_PROXY (audiomixer), G_OBJECT (pad),
281       GST_OBJECT_NAME (pad));
282 
283   GST_ELEMENT_CLASS (parent_class)->release_pad (element, pad);
284 }
285 
286 
287 static gboolean
gst_audiomixer_aggregate_one_buffer(GstAudioAggregator * aagg,GstAudioAggregatorPad * aaggpad,GstBuffer * inbuf,guint in_offset,GstBuffer * outbuf,guint out_offset,guint num_frames)288 gst_audiomixer_aggregate_one_buffer (GstAudioAggregator * aagg,
289     GstAudioAggregatorPad * aaggpad, GstBuffer * inbuf, guint in_offset,
290     GstBuffer * outbuf, guint out_offset, guint num_frames)
291 {
292   GstAudioMixerPad *pad = GST_AUDIO_MIXER_PAD (aaggpad);
293   GstMapInfo inmap;
294   GstMapInfo outmap;
295   gint bpf;
296   GstAggregator *agg = GST_AGGREGATOR (aagg);
297   GstAudioAggregatorPad *srcpad = GST_AUDIO_AGGREGATOR_PAD (agg->srcpad);
298 
299   GST_OBJECT_LOCK (aagg);
300   GST_OBJECT_LOCK (aaggpad);
301 
302   if (pad->mute || pad->volume < G_MINDOUBLE) {
303     GST_DEBUG_OBJECT (pad, "Skipping muted pad");
304     GST_OBJECT_UNLOCK (aaggpad);
305     GST_OBJECT_UNLOCK (aagg);
306     return FALSE;
307   }
308 
309   bpf = GST_AUDIO_INFO_BPF (&srcpad->info);
310 
311   gst_buffer_map (outbuf, &outmap, GST_MAP_READWRITE);
312   gst_buffer_map (inbuf, &inmap, GST_MAP_READ);
313   GST_LOG_OBJECT (pad, "mixing %u bytes at offset %u from offset %u",
314       num_frames * bpf, out_offset * bpf, in_offset * bpf);
315 
316   /* further buffers, need to add them */
317   if (pad->volume == 1.0) {
318     switch (srcpad->info.finfo->format) {
319       case GST_AUDIO_FORMAT_U8:
320         audiomixer_orc_add_u8 ((gpointer) (outmap.data + out_offset * bpf),
321             (gpointer) (inmap.data + in_offset * bpf),
322             num_frames * srcpad->info.channels);
323         break;
324       case GST_AUDIO_FORMAT_S8:
325         audiomixer_orc_add_s8 ((gpointer) (outmap.data + out_offset * bpf),
326             (gpointer) (inmap.data + in_offset * bpf),
327             num_frames * srcpad->info.channels);
328         break;
329       case GST_AUDIO_FORMAT_U16:
330         audiomixer_orc_add_u16 ((gpointer) (outmap.data + out_offset * bpf),
331             (gpointer) (inmap.data + in_offset * bpf),
332             num_frames * srcpad->info.channels);
333         break;
334       case GST_AUDIO_FORMAT_S16:
335         audiomixer_orc_add_s16 ((gpointer) (outmap.data + out_offset * bpf),
336             (gpointer) (inmap.data + in_offset * bpf),
337             num_frames * srcpad->info.channels);
338         break;
339       case GST_AUDIO_FORMAT_U32:
340         audiomixer_orc_add_u32 ((gpointer) (outmap.data + out_offset * bpf),
341             (gpointer) (inmap.data + in_offset * bpf),
342             num_frames * srcpad->info.channels);
343         break;
344       case GST_AUDIO_FORMAT_S32:
345         audiomixer_orc_add_s32 ((gpointer) (outmap.data + out_offset * bpf),
346             (gpointer) (inmap.data + in_offset * bpf),
347             num_frames * srcpad->info.channels);
348         break;
349       case GST_AUDIO_FORMAT_F32:
350         audiomixer_orc_add_f32 ((gpointer) (outmap.data + out_offset * bpf),
351             (gpointer) (inmap.data + in_offset * bpf),
352             num_frames * srcpad->info.channels);
353         break;
354       case GST_AUDIO_FORMAT_F64:
355         audiomixer_orc_add_f64 ((gpointer) (outmap.data + out_offset * bpf),
356             (gpointer) (inmap.data + in_offset * bpf),
357             num_frames * srcpad->info.channels);
358         break;
359       default:
360         g_assert_not_reached ();
361         break;
362     }
363   } else {
364     switch (srcpad->info.finfo->format) {
365       case GST_AUDIO_FORMAT_U8:
366         audiomixer_orc_add_volume_u8 ((gpointer) (outmap.data +
367                 out_offset * bpf), (gpointer) (inmap.data + in_offset * bpf),
368             pad->volume_i8, num_frames * srcpad->info.channels);
369         break;
370       case GST_AUDIO_FORMAT_S8:
371         audiomixer_orc_add_volume_s8 ((gpointer) (outmap.data +
372                 out_offset * bpf), (gpointer) (inmap.data + in_offset * bpf),
373             pad->volume_i8, num_frames * srcpad->info.channels);
374         break;
375       case GST_AUDIO_FORMAT_U16:
376         audiomixer_orc_add_volume_u16 ((gpointer) (outmap.data +
377                 out_offset * bpf), (gpointer) (inmap.data + in_offset * bpf),
378             pad->volume_i16, num_frames * srcpad->info.channels);
379         break;
380       case GST_AUDIO_FORMAT_S16:
381         audiomixer_orc_add_volume_s16 ((gpointer) (outmap.data +
382                 out_offset * bpf), (gpointer) (inmap.data + in_offset * bpf),
383             pad->volume_i16, num_frames * srcpad->info.channels);
384         break;
385       case GST_AUDIO_FORMAT_U32:
386         audiomixer_orc_add_volume_u32 ((gpointer) (outmap.data +
387                 out_offset * bpf), (gpointer) (inmap.data + in_offset * bpf),
388             pad->volume_i32, num_frames * srcpad->info.channels);
389         break;
390       case GST_AUDIO_FORMAT_S32:
391         audiomixer_orc_add_volume_s32 ((gpointer) (outmap.data +
392                 out_offset * bpf), (gpointer) (inmap.data + in_offset * bpf),
393             pad->volume_i32, num_frames * srcpad->info.channels);
394         break;
395       case GST_AUDIO_FORMAT_F32:
396         audiomixer_orc_add_volume_f32 ((gpointer) (outmap.data +
397                 out_offset * bpf), (gpointer) (inmap.data + in_offset * bpf),
398             pad->volume, num_frames * srcpad->info.channels);
399         break;
400       case GST_AUDIO_FORMAT_F64:
401         audiomixer_orc_add_volume_f64 ((gpointer) (outmap.data +
402                 out_offset * bpf), (gpointer) (inmap.data + in_offset * bpf),
403             pad->volume, num_frames * srcpad->info.channels);
404         break;
405       default:
406         g_assert_not_reached ();
407         break;
408     }
409   }
410   gst_buffer_unmap (inbuf, &inmap);
411   gst_buffer_unmap (outbuf, &outmap);
412 
413   GST_OBJECT_UNLOCK (aaggpad);
414   GST_OBJECT_UNLOCK (aagg);
415 
416   return TRUE;
417 }
418 
419 
420 /* GstChildProxy implementation */
421 static GObject *
gst_audiomixer_child_proxy_get_child_by_index(GstChildProxy * child_proxy,guint index)422 gst_audiomixer_child_proxy_get_child_by_index (GstChildProxy * child_proxy,
423     guint index)
424 {
425   GstAudioMixer *audiomixer = GST_AUDIO_MIXER (child_proxy);
426   GObject *obj = NULL;
427 
428   GST_OBJECT_LOCK (audiomixer);
429   obj = g_list_nth_data (GST_ELEMENT_CAST (audiomixer)->sinkpads, index);
430   if (obj)
431     gst_object_ref (obj);
432   GST_OBJECT_UNLOCK (audiomixer);
433 
434   return obj;
435 }
436 
437 static guint
gst_audiomixer_child_proxy_get_children_count(GstChildProxy * child_proxy)438 gst_audiomixer_child_proxy_get_children_count (GstChildProxy * child_proxy)
439 {
440   guint count = 0;
441   GstAudioMixer *audiomixer = GST_AUDIO_MIXER (child_proxy);
442 
443   GST_OBJECT_LOCK (audiomixer);
444   count = GST_ELEMENT_CAST (audiomixer)->numsinkpads;
445   GST_OBJECT_UNLOCK (audiomixer);
446   GST_INFO_OBJECT (audiomixer, "Children Count: %d", count);
447 
448   return count;
449 }
450 
451 static void
gst_audiomixer_child_proxy_init(gpointer g_iface,gpointer iface_data)452 gst_audiomixer_child_proxy_init (gpointer g_iface, gpointer iface_data)
453 {
454   GstChildProxyInterface *iface = g_iface;
455 
456   GST_INFO ("initializing child proxy interface");
457   iface->get_child_by_index = gst_audiomixer_child_proxy_get_child_by_index;
458   iface->get_children_count = gst_audiomixer_child_proxy_get_children_count;
459 }
460