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