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>
7 * audiomixer.c: AudioMixer element, N in, one out, samples are added
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.
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.
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.
25 * SECTION:element-audiomixer
27 * The audiomixer allows to mix several streams into one by adding the data.
28 * Mixed data is clamped to the min/max values of the data format.
30 * The audiomixer currently mixes all data received on the sinkpads as soon as
31 * possible without trying to synchronize the streams.
33 * The input pads are from a GstPad subclass and have additional
34 * properties to mute each pad individually and set the volume:
38 * "mute": Whether to mute the pad or not (#gboolean)
41 * "volume": The volume of the pad, between 0.0 and 10.0 (#gdouble)
46 * <title>Example launch line</title>
48 * gst-launch audiotestsrc freq=100 ! audiomixer name=mix ! audioconvert ! alsasink audiotestsrc freq=500 ! mix.
49 * ]| This pipeline produces two sine waves mixed together.
58 #include "gstaudiomixer.h"
59 #include <gst/audio/audio.h>
60 #include <string.h> /* strcmp */
61 #include "gstaudiomixerorc.h"
63 #define GST_CAT_DEFAULT gst_audiomixer_debug
64 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
66 #define DEFAULT_PAD_VOLUME (1.0)
67 #define DEFAULT_PAD_MUTE (FALSE)
69 /* some defines for audio processing */
70 /* the volume factor is a range from 0.0 to (arbitrary) VOLUME_MAX_DOUBLE = 10.0
71 * we map 1.0 to VOLUME_UNITY_INT*
73 #define VOLUME_UNITY_INT8 8 /* internal int for unity 2^(8-5) */
74 #define VOLUME_UNITY_INT8_BIT_SHIFT 3 /* number of bits to shift for unity */
75 #define VOLUME_UNITY_INT16 2048 /* internal int for unity 2^(16-5) */
76 #define VOLUME_UNITY_INT16_BIT_SHIFT 11 /* number of bits to shift for unity */
77 #define VOLUME_UNITY_INT24 524288 /* internal int for unity 2^(24-5) */
78 #define VOLUME_UNITY_INT24_BIT_SHIFT 19 /* number of bits to shift for unity */
79 #define VOLUME_UNITY_INT32 134217728 /* internal int for unity 2^(32-5) */
80 #define VOLUME_UNITY_INT32_BIT_SHIFT 27
89 G_DEFINE_TYPE (GstAudioMixerPad, gst_audiomixer_pad, GST_TYPE_AGGREGATOR_PAD);
92 gst_audiomixer_pad_get_property (GObject * object, guint prop_id,
93 GValue * value, GParamSpec * pspec)
95 GstAudioMixerPad *pad = GST_AUDIO_MIXER_PAD (object);
99 g_value_set_double (value, pad->volume);
102 g_value_set_boolean (value, pad->mute);
105 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
111 gst_audiomixer_pad_set_property (GObject * object, guint prop_id,
112 const GValue * value, GParamSpec * pspec)
114 GstAudioMixerPad *pad = GST_AUDIO_MIXER_PAD (object);
117 case PROP_PAD_VOLUME:
118 GST_OBJECT_LOCK (pad);
119 pad->volume = g_value_get_double (value);
120 pad->volume_i8 = pad->volume * VOLUME_UNITY_INT8;
121 pad->volume_i16 = pad->volume * VOLUME_UNITY_INT16;
122 pad->volume_i32 = pad->volume * VOLUME_UNITY_INT32;
123 GST_OBJECT_UNLOCK (pad);
126 GST_OBJECT_LOCK (pad);
127 pad->mute = g_value_get_boolean (value);
128 GST_OBJECT_UNLOCK (pad);
131 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
137 gst_audiomixer_pad_flush_pad (GstAggregatorPad * aggpad,
138 GstAggregator * aggregator)
140 GstAudioMixerPad *pad = GST_AUDIO_MIXER_PAD (aggpad);
142 GST_OBJECT_LOCK (aggpad);
143 pad->position = pad->size = 0;
144 pad->output_offset = pad->next_offset = -1;
145 pad->discont_time = GST_CLOCK_TIME_NONE;
146 gst_buffer_replace (&pad->buffer, NULL);
147 GST_OBJECT_UNLOCK (aggpad);
153 gst_audiomixer_pad_class_init (GstAudioMixerPadClass * klass)
155 GObjectClass *gobject_class = (GObjectClass *) klass;
156 GstAggregatorPadClass *aggpadclass = (GstAggregatorPadClass *) klass;
158 gobject_class->set_property = gst_audiomixer_pad_set_property;
159 gobject_class->get_property = gst_audiomixer_pad_get_property;
161 g_object_class_install_property (gobject_class, PROP_PAD_VOLUME,
162 g_param_spec_double ("volume", "Volume", "Volume of this pad",
163 0.0, 10.0, DEFAULT_PAD_VOLUME,
164 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
165 g_object_class_install_property (gobject_class, PROP_PAD_MUTE,
166 g_param_spec_boolean ("mute", "Mute", "Mute this pad",
168 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
170 aggpadclass->flush = GST_DEBUG_FUNCPTR (gst_audiomixer_pad_flush_pad);
174 gst_audiomixer_pad_init (GstAudioMixerPad * pad)
176 pad->volume = DEFAULT_PAD_VOLUME;
177 pad->mute = DEFAULT_PAD_MUTE;
182 pad->output_offset = -1;
183 pad->next_offset = -1;
184 pad->discont_time = GST_CLOCK_TIME_NONE;
187 #define DEFAULT_ALIGNMENT_THRESHOLD (40 * GST_MSECOND)
188 #define DEFAULT_DISCONT_WAIT (1 * GST_SECOND)
189 #define DEFAULT_OUTPUT_BUFFER_DURATION (10 * GST_MSECOND)
195 PROP_ALIGNMENT_THRESHOLD,
197 PROP_OUTPUT_BUFFER_DURATION
200 /* elementfactory information */
202 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
204 GST_AUDIO_CAPS_MAKE ("{ S32LE, U32LE, S16LE, U16LE, S8, U8, F32LE, F64LE }") \
205 ", layout = (string) { interleaved, non-interleaved }"
208 GST_AUDIO_CAPS_MAKE ("{ S32BE, U32BE, S16BE, U16BE, S8, U8, F32BE, F64BE }") \
209 ", layout = (string) { interleaved, non-interleaved }"
212 static GstStaticPadTemplate gst_audiomixer_src_template =
213 GST_STATIC_PAD_TEMPLATE ("src",
216 GST_STATIC_CAPS (CAPS)
219 static GstStaticPadTemplate gst_audiomixer_sink_template =
220 GST_STATIC_PAD_TEMPLATE ("sink_%u",
223 GST_STATIC_CAPS (CAPS)
226 static void gst_audiomixer_child_proxy_init (gpointer g_iface,
227 gpointer iface_data);
229 #define gst_audiomixer_parent_class parent_class
230 G_DEFINE_TYPE_WITH_CODE (GstAudioMixer, gst_audiomixer, GST_TYPE_AGGREGATOR,
231 G_IMPLEMENT_INTERFACE (GST_TYPE_CHILD_PROXY,
232 gst_audiomixer_child_proxy_init));
234 static void gst_audiomixer_dispose (GObject * object);
235 static void gst_audiomixer_set_property (GObject * object, guint prop_id,
236 const GValue * value, GParamSpec * pspec);
237 static void gst_audiomixer_get_property (GObject * object, guint prop_id,
238 GValue * value, GParamSpec * pspec);
240 static gboolean gst_audiomixer_setcaps (GstAudioMixer * audiomixer,
241 GstPad * pad, GstCaps * caps);
242 static GstPad *gst_audiomixer_request_new_pad (GstElement * element,
243 GstPadTemplate * temp, const gchar * req_name, const GstCaps * caps);
244 static void gst_audiomixer_release_pad (GstElement * element, GstPad * pad);
247 gst_audiomixer_do_clip (GstAggregator * agg,
248 GstAggregatorPad * bpad, GstBuffer * buffer, GstBuffer ** outbuf);
249 static GstFlowReturn gst_audiomixer_aggregate (GstAggregator * agg,
253 gst_audiomixer_get_next_time (GstAggregator * agg)
255 if (agg->segment.position == -1)
256 return agg->segment.start;
258 return agg->segment.position;
261 /* we can only accept caps that we and downstream can handle.
262 * if we have filtercaps set, use those to constrain the target caps.
265 gst_audiomixer_sink_getcaps (GstPad * pad, GstCaps * filter)
268 GstAudioMixer *audiomixer;
269 GstCaps *result, *peercaps, *current_caps, *filter_caps;
273 audiomixer = GST_AUDIO_MIXER (GST_PAD_PARENT (pad));
274 agg = GST_AGGREGATOR (audiomixer);
276 GST_OBJECT_LOCK (audiomixer);
278 if ((filter_caps = audiomixer->filter_caps)) {
281 gst_caps_intersect_full (filter, filter_caps,
282 GST_CAPS_INTERSECT_FIRST);
284 gst_caps_ref (filter_caps);
286 filter_caps = filter ? gst_caps_ref (filter) : NULL;
288 GST_OBJECT_UNLOCK (audiomixer);
290 if (filter_caps && gst_caps_is_empty (filter_caps)) {
291 GST_WARNING_OBJECT (pad, "Empty filter caps");
295 /* get the downstream possible caps */
296 peercaps = gst_pad_peer_query_caps (agg->srcpad, filter_caps);
298 /* get the allowed caps on this sinkpad */
299 GST_OBJECT_LOCK (audiomixer);
301 audiomixer->current_caps ? gst_caps_ref (audiomixer->current_caps) : NULL;
302 if (current_caps == NULL) {
303 current_caps = gst_pad_get_pad_template_caps (pad);
305 current_caps = gst_caps_new_any ();
307 GST_OBJECT_UNLOCK (audiomixer);
310 /* if the peer has caps, intersect */
311 GST_DEBUG_OBJECT (audiomixer, "intersecting peer and our caps");
313 gst_caps_intersect_full (peercaps, current_caps,
314 GST_CAPS_INTERSECT_FIRST);
315 gst_caps_unref (peercaps);
316 gst_caps_unref (current_caps);
318 /* the peer has no caps (or there is no peer), just use the allowed caps
319 * of this sinkpad. */
320 /* restrict with filter-caps if any */
322 GST_DEBUG_OBJECT (audiomixer, "no peer caps, using filtered caps");
324 gst_caps_intersect_full (filter_caps, current_caps,
325 GST_CAPS_INTERSECT_FIRST);
326 gst_caps_unref (current_caps);
328 GST_DEBUG_OBJECT (audiomixer, "no peer caps, using our caps");
329 result = current_caps;
333 result = gst_caps_make_writable (result);
335 n = gst_caps_get_size (result);
336 for (i = 0; i < n; i++) {
339 s = gst_caps_get_structure (result, i);
340 sref = gst_structure_copy (s);
341 gst_structure_set (sref, "channels", GST_TYPE_INT_RANGE, 0, 2, NULL);
342 if (gst_structure_is_subset (s, sref)) {
343 /* This field is irrelevant when in mono or stereo */
344 gst_structure_remove_field (s, "channel-mask");
346 gst_structure_free (sref);
350 gst_caps_unref (filter_caps);
352 GST_LOG_OBJECT (audiomixer, "getting caps on pad %p,%s to %" GST_PTR_FORMAT,
353 pad, GST_PAD_NAME (pad), result);
359 gst_audiomixer_sink_query (GstAggregator * agg, GstAggregatorPad * aggpad,
362 gboolean res = FALSE;
364 switch (GST_QUERY_TYPE (query)) {
367 GstCaps *filter, *caps;
369 gst_query_parse_caps (query, &filter);
370 caps = gst_audiomixer_sink_getcaps (GST_PAD (aggpad), filter);
371 gst_query_set_caps_result (query, caps);
372 gst_caps_unref (caps);
378 GST_AGGREGATOR_CLASS (parent_class)->sink_query (agg, aggpad, query);
385 /* the first caps we receive on any of the sinkpads will define the caps for all
386 * the other sinkpads because we can only mix streams with the same caps.
389 gst_audiomixer_setcaps (GstAudioMixer * audiomixer, GstPad * pad,
397 caps = gst_caps_copy (orig_caps);
399 s = gst_caps_get_structure (caps, 0);
400 if (gst_structure_get_int (s, "channels", &channels))
402 gst_structure_remove_field (s, "channel-mask");
404 if (!gst_audio_info_from_caps (&info, caps))
407 GST_OBJECT_LOCK (audiomixer);
408 /* don't allow reconfiguration for now; there's still a race between the
409 * different upstream threads doing query_caps + accept_caps + sending
410 * (possibly different) CAPS events, but there's not much we can do about
411 * that, upstream needs to deal with it. */
412 if (audiomixer->current_caps != NULL) {
413 if (gst_audio_info_is_equal (&info, &audiomixer->info)) {
414 GST_OBJECT_UNLOCK (audiomixer);
415 gst_caps_unref (caps);
418 GST_DEBUG_OBJECT (pad, "got input caps %" GST_PTR_FORMAT ", but "
419 "current caps are %" GST_PTR_FORMAT, caps, audiomixer->current_caps);
420 GST_OBJECT_UNLOCK (audiomixer);
421 gst_pad_push_event (pad, gst_event_new_reconfigure ());
422 gst_caps_unref (caps);
427 GST_INFO_OBJECT (pad, "setting caps to %" GST_PTR_FORMAT, caps);
428 gst_caps_replace (&audiomixer->current_caps, caps);
430 memcpy (&audiomixer->info, &info, sizeof (info));
431 audiomixer->send_caps = TRUE;
432 GST_OBJECT_UNLOCK (audiomixer);
433 /* send caps event later, after stream-start event */
435 GST_INFO_OBJECT (pad, "handle caps change to %" GST_PTR_FORMAT, caps);
437 gst_caps_unref (caps);
444 gst_caps_unref (caps);
445 GST_WARNING_OBJECT (audiomixer, "invalid format set as caps");
450 /* FIXME, the duration query should reflect how long you will produce
451 * data, that is the amount of stream time until you will emit EOS.
453 * For synchronized mixing this is always the max of all the durations
454 * of upstream since we emit EOS when all of them finished.
456 * We don't do synchronized mixing so this really depends on where the
457 * streams where punched in and what their relative offsets are against
458 * eachother which we can get from the first timestamps we see.
460 * When we add a new stream (or remove a stream) the duration might
461 * also become invalid again and we need to post a new DURATION
462 * message to notify this fact to the parent.
463 * For now we take the max of all the upstream elements so the simple
464 * cases work at least somewhat.
467 gst_audiomixer_query_duration (GstAudioMixer * audiomixer, GstQuery * query)
474 GValue item = { 0, };
477 gst_query_parse_duration (query, &format, NULL);
483 it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (audiomixer));
485 GstIteratorResult ires;
487 ires = gst_iterator_next (it, &item);
489 case GST_ITERATOR_DONE:
492 case GST_ITERATOR_OK:
494 GstPad *pad = g_value_get_object (&item);
497 /* ask sink peer for duration */
498 res &= gst_pad_peer_query_duration (pad, format, &duration);
499 /* take max from all valid return values */
501 /* valid unknown length, stop searching */
502 if (duration == -1) {
506 /* else see if bigger than current max */
507 else if (duration > max)
510 g_value_reset (&item);
513 case GST_ITERATOR_RESYNC:
516 gst_iterator_resync (it);
524 g_value_unset (&item);
525 gst_iterator_free (it);
528 /* and store the max */
529 GST_DEBUG_OBJECT (audiomixer, "Total duration in format %s: %"
530 GST_TIME_FORMAT, gst_format_get_name (format), GST_TIME_ARGS (max));
531 gst_query_set_duration (query, format, max);
538 gst_audiomixer_src_query (GstAggregator * agg, GstQuery * query)
540 GstAudioMixer *audiomixer = GST_AUDIO_MIXER (agg);
541 gboolean res = FALSE;
543 switch (GST_QUERY_TYPE (query)) {
544 case GST_QUERY_POSITION:
548 gst_query_parse_position (query, &format, NULL);
551 case GST_FORMAT_TIME:
552 /* FIXME, bring to stream time, might be tricky */
553 gst_query_set_position (query, format, agg->segment.position);
556 case GST_FORMAT_DEFAULT:
557 gst_query_set_position (query, format, audiomixer->offset);
565 case GST_QUERY_DURATION:
566 res = gst_audiomixer_query_duration (audiomixer, query);
570 GST_AGGREGATOR_CLASS (gst_audiomixer_parent_class)->src_query
587 gst_audiomixer_src_event (GstAggregator * agg, GstEvent * event)
591 GstAudioMixer *audiomixer = GST_AUDIO_MIXER (agg);
592 GST_DEBUG_OBJECT (agg->srcpad, "Got %s event on src pad",
593 GST_EVENT_TYPE_NAME (event));
595 switch (GST_EVENT_TYPE (event)) {
597 /* QoS might be tricky */
598 gst_event_unref (event);
600 case GST_EVENT_NAVIGATION:
601 /* navigation is rather pointless. */
602 gst_event_unref (event);
609 GstSeekType start_type, stop_type;
611 GstFormat seek_format, dest_format;
613 /* parse the seek parameters */
614 gst_event_parse_seek (event, &rate, &seek_format, &flags, &start_type,
615 &start, &stop_type, &stop);
617 /* Check the seeking parametters before linking up */
618 if ((start_type != GST_SEEK_TYPE_NONE)
619 && (start_type != GST_SEEK_TYPE_SET)) {
621 GST_DEBUG_OBJECT (audiomixer,
622 "seeking failed, unhandled seek type for start: %d", start_type);
625 if ((stop_type != GST_SEEK_TYPE_NONE) && (stop_type != GST_SEEK_TYPE_SET)) {
627 GST_DEBUG_OBJECT (audiomixer,
628 "seeking failed, unhandled seek type for end: %d", stop_type);
632 dest_format = agg->segment.format;
633 if (seek_format != dest_format) {
635 GST_DEBUG_OBJECT (audiomixer,
636 "seeking failed, unhandled seek format: %d", seek_format);
641 result = GST_AGGREGATOR_CLASS (parent_class)->src_event (agg, event);
649 return GST_AGGREGATOR_CLASS (parent_class)->src_event (agg, event);
656 gst_audiomixer_sink_event (GstAggregator * agg, GstAggregatorPad * aggpad,
659 GstAudioMixer *audiomixer = GST_AUDIO_MIXER (agg);
662 GST_DEBUG_OBJECT (aggpad, "Got %s event on sink pad",
663 GST_EVENT_TYPE_NAME (event));
665 switch (GST_EVENT_TYPE (event)) {
670 gst_event_parse_caps (event, &caps);
671 res = gst_audiomixer_setcaps (audiomixer, GST_PAD_CAST (aggpad), caps);
672 gst_event_unref (event);
676 case GST_EVENT_SEGMENT:
678 const GstSegment *segment;
679 gst_event_parse_segment (event, &segment);
680 if (segment->rate != agg->segment.rate) {
681 GST_ERROR_OBJECT (aggpad,
682 "Got segment event with wrong rate %lf, expected %lf",
683 segment->rate, agg->segment.rate);
685 gst_event_unref (event);
687 } else if (segment->rate < 0.0) {
688 GST_ERROR_OBJECT (aggpad, "Negative rates not supported yet");
690 gst_event_unref (event);
700 return GST_AGGREGATOR_CLASS (parent_class)->sink_event (agg, aggpad, event);
706 gst_audiomixer_reset (GstAudioMixer * audiomixer)
708 GstAggregator *agg = GST_AGGREGATOR (audiomixer);
710 audiomixer->offset = 0;
711 agg->segment.position = -1;
713 gst_audio_info_init (&audiomixer->info);
714 gst_caps_replace (&audiomixer->current_caps, NULL);
715 gst_buffer_replace (&audiomixer->current_buffer, NULL);
719 gst_audiomixer_start (GstAggregator * agg)
721 GstAudioMixer *audiomixer = GST_AUDIO_MIXER (agg);
723 gst_audiomixer_reset (audiomixer);
729 gst_audiomixer_stop (GstAggregator * agg)
731 GstAudioMixer *audiomixer = GST_AUDIO_MIXER (agg);
733 gst_audiomixer_reset (audiomixer);
739 gst_audiomixer_flush (GstAggregator * agg)
741 GstAudioMixer *audiomixer = GST_AUDIO_MIXER (agg);
743 audiomixer->offset = 0;
744 agg->segment.position = -1;
745 gst_buffer_replace (&audiomixer->current_buffer, NULL);
751 gst_audiomixer_class_init (GstAudioMixerClass * klass)
753 GObjectClass *gobject_class = (GObjectClass *) klass;
754 GstElementClass *gstelement_class = (GstElementClass *) klass;
755 GstAggregatorClass *agg_class = (GstAggregatorClass *) klass;
757 gobject_class->set_property = gst_audiomixer_set_property;
758 gobject_class->get_property = gst_audiomixer_get_property;
759 gobject_class->dispose = gst_audiomixer_dispose;
761 g_object_class_install_property (gobject_class, PROP_FILTER_CAPS,
762 g_param_spec_boxed ("caps", "Target caps",
763 "Set target format for mixing (NULL means ANY). "
764 "Setting this property takes a reference to the supplied GstCaps "
765 "object", GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
767 g_object_class_install_property (gobject_class, PROP_ALIGNMENT_THRESHOLD,
768 g_param_spec_uint64 ("alignment-threshold", "Alignment Threshold",
769 "Timestamp alignment threshold in nanoseconds", 0,
770 G_MAXUINT64 - 1, DEFAULT_ALIGNMENT_THRESHOLD,
771 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
773 g_object_class_install_property (gobject_class, PROP_DISCONT_WAIT,
774 g_param_spec_uint64 ("discont-wait", "Discont Wait",
775 "Window of time in nanoseconds to wait before "
776 "creating a discontinuity", 0,
777 G_MAXUINT64 - 1, DEFAULT_DISCONT_WAIT,
778 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
780 g_object_class_install_property (gobject_class, PROP_OUTPUT_BUFFER_DURATION,
781 g_param_spec_uint64 ("output-buffer-duration", "Output Buffer Duration",
782 "Output block size in nanoseconds", 1,
783 G_MAXUINT64, DEFAULT_OUTPUT_BUFFER_DURATION,
784 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
786 gst_element_class_add_pad_template (gstelement_class,
787 gst_static_pad_template_get (&gst_audiomixer_src_template));
788 gst_element_class_add_pad_template (gstelement_class,
789 gst_static_pad_template_get (&gst_audiomixer_sink_template));
790 gst_element_class_set_static_metadata (gstelement_class, "AudioMixer",
792 "Mixes multiple audio streams",
793 "Sebastian Dröge <sebastian@centricular.com>");
795 gstelement_class->request_new_pad =
796 GST_DEBUG_FUNCPTR (gst_audiomixer_request_new_pad);
797 gstelement_class->release_pad =
798 GST_DEBUG_FUNCPTR (gst_audiomixer_release_pad);
800 agg_class->sinkpads_type = GST_TYPE_AUDIO_MIXER_PAD;
801 agg_class->start = gst_audiomixer_start;
802 agg_class->stop = gst_audiomixer_stop;
804 agg_class->get_next_time = gst_audiomixer_get_next_time;
806 agg_class->sink_query = GST_DEBUG_FUNCPTR (gst_audiomixer_sink_query);
807 agg_class->sink_event = GST_DEBUG_FUNCPTR (gst_audiomixer_sink_event);
809 agg_class->aggregate = GST_DEBUG_FUNCPTR (gst_audiomixer_aggregate);
810 agg_class->clip = GST_DEBUG_FUNCPTR (gst_audiomixer_do_clip);
812 agg_class->src_event = GST_DEBUG_FUNCPTR (gst_audiomixer_src_event);
813 agg_class->src_query = GST_DEBUG_FUNCPTR (gst_audiomixer_src_query);
815 agg_class->flush = GST_DEBUG_FUNCPTR (gst_audiomixer_flush);
819 gst_audiomixer_init (GstAudioMixer * audiomixer)
821 audiomixer->current_caps = NULL;
822 gst_audio_info_init (&audiomixer->info);
824 audiomixer->filter_caps = NULL;
825 audiomixer->alignment_threshold = DEFAULT_ALIGNMENT_THRESHOLD;
826 audiomixer->discont_wait = DEFAULT_DISCONT_WAIT;
827 audiomixer->output_buffer_duration = DEFAULT_OUTPUT_BUFFER_DURATION;
828 gst_aggregator_set_latency (GST_AGGREGATOR (audiomixer),
829 audiomixer->output_buffer_duration, audiomixer->output_buffer_duration);
833 gst_audiomixer_dispose (GObject * object)
835 GstAudioMixer *audiomixer = GST_AUDIO_MIXER (object);
837 gst_caps_replace (&audiomixer->filter_caps, NULL);
838 gst_caps_replace (&audiomixer->current_caps, NULL);
840 G_OBJECT_CLASS (parent_class)->dispose (object);
844 gst_audiomixer_set_property (GObject * object, guint prop_id,
845 const GValue * value, GParamSpec * pspec)
847 GstAudioMixer *audiomixer = GST_AUDIO_MIXER (object);
850 case PROP_FILTER_CAPS:{
851 GstCaps *new_caps = NULL;
853 const GstCaps *new_caps_val = gst_value_get_caps (value);
855 if (new_caps_val != NULL) {
856 new_caps = (GstCaps *) new_caps_val;
857 gst_caps_ref (new_caps);
860 GST_OBJECT_LOCK (audiomixer);
861 old_caps = audiomixer->filter_caps;
862 audiomixer->filter_caps = new_caps;
863 GST_OBJECT_UNLOCK (audiomixer);
866 gst_caps_unref (old_caps);
868 GST_DEBUG_OBJECT (audiomixer, "set new caps %" GST_PTR_FORMAT, new_caps);
871 case PROP_ALIGNMENT_THRESHOLD:
872 audiomixer->alignment_threshold = g_value_get_uint64 (value);
874 case PROP_DISCONT_WAIT:
875 audiomixer->discont_wait = g_value_get_uint64 (value);
877 case PROP_OUTPUT_BUFFER_DURATION:
878 audiomixer->output_buffer_duration = g_value_get_uint64 (value);
879 gst_aggregator_set_latency (GST_AGGREGATOR (audiomixer),
880 audiomixer->output_buffer_duration,
881 audiomixer->output_buffer_duration);
884 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
890 gst_audiomixer_get_property (GObject * object, guint prop_id, GValue * value,
893 GstAudioMixer *audiomixer = GST_AUDIO_MIXER (object);
896 case PROP_FILTER_CAPS:
897 GST_OBJECT_LOCK (audiomixer);
898 gst_value_set_caps (value, audiomixer->filter_caps);
899 GST_OBJECT_UNLOCK (audiomixer);
901 case PROP_ALIGNMENT_THRESHOLD:
902 g_value_set_uint64 (value, audiomixer->alignment_threshold);
904 case PROP_DISCONT_WAIT:
905 g_value_set_uint64 (value, audiomixer->discont_wait);
907 case PROP_OUTPUT_BUFFER_DURATION:
908 g_value_set_uint64 (value, audiomixer->output_buffer_duration);
911 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
917 gst_audiomixer_request_new_pad (GstElement * element, GstPadTemplate * templ,
918 const gchar * req_name, const GstCaps * caps)
920 GstAudioMixerPad *newpad;
922 newpad = (GstAudioMixerPad *)
923 GST_ELEMENT_CLASS (parent_class)->request_new_pad (element,
924 templ, req_name, caps);
927 goto could_not_create;
929 gst_child_proxy_child_added (GST_CHILD_PROXY (element), G_OBJECT (newpad),
930 GST_OBJECT_NAME (newpad));
932 return GST_PAD_CAST (newpad);
936 GST_DEBUG_OBJECT (element, "could not create/add pad");
942 gst_audiomixer_release_pad (GstElement * element, GstPad * pad)
944 GstAudioMixer *audiomixer;
946 audiomixer = GST_AUDIO_MIXER (element);
948 GST_DEBUG_OBJECT (audiomixer, "release pad %s:%s", GST_DEBUG_PAD_NAME (pad));
950 gst_child_proxy_child_removed (GST_CHILD_PROXY (audiomixer), G_OBJECT (pad),
951 GST_OBJECT_NAME (pad));
953 GST_ELEMENT_CLASS (parent_class)->release_pad (element, pad);
957 gst_audiomixer_do_clip (GstAggregator * agg,
958 GstAggregatorPad * bpad, GstBuffer * buffer, GstBuffer ** out)
960 GstAudioMixer *audiomixer = GST_AUDIO_MIXER (agg);
963 rate = GST_AUDIO_INFO_RATE (&audiomixer->info);
964 bpf = GST_AUDIO_INFO_BPF (&audiomixer->info);
966 buffer = gst_audio_buffer_clip (buffer, &bpad->segment, rate, bpf);
973 gst_audio_mixer_fill_buffer (GstAudioMixer * audiomixer, GstAudioMixerPad * pad,
976 GstClockTime start_time, end_time;
977 gboolean discont = FALSE;
978 guint64 start_offset, end_offset;
979 GstClockTime timestamp, stream_time;
982 GstAggregator *agg = GST_AGGREGATOR (audiomixer);
983 GstAggregatorPad *aggpad = GST_AGGREGATOR_PAD (pad);
985 g_assert (pad->buffer == NULL);
987 rate = GST_AUDIO_INFO_RATE (&audiomixer->info);
988 bpf = GST_AUDIO_INFO_BPF (&audiomixer->info);
990 timestamp = GST_BUFFER_TIMESTAMP (inbuf);
991 stream_time = gst_segment_to_stream_time (&agg->segment, GST_FORMAT_TIME,
994 /* sync object properties on stream time */
995 /* TODO: Ideally we would want to do that on every sample */
996 if (GST_CLOCK_TIME_IS_VALID (stream_time))
997 gst_object_sync_values (GST_OBJECT (pad), stream_time);
1000 pad->size = gst_buffer_get_size (inbuf);
1002 start_time = GST_BUFFER_PTS (inbuf);
1004 start_time + gst_util_uint64_scale_ceil (pad->size / bpf,
1007 start_offset = gst_util_uint64_scale (start_time, rate, GST_SECOND);
1008 end_offset = start_offset + pad->size / bpf;
1010 if (GST_BUFFER_IS_DISCONT (inbuf)
1011 || GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_RESYNC)
1012 || pad->next_offset == -1) {
1015 guint64 diff, max_sample_diff;
1017 /* Check discont, based on audiobasesink */
1018 if (start_offset <= pad->next_offset)
1019 diff = pad->next_offset - start_offset;
1021 diff = start_offset - pad->next_offset;
1024 gst_util_uint64_scale_int (audiomixer->alignment_threshold, rate,
1028 if (G_UNLIKELY (diff >= max_sample_diff)) {
1029 if (audiomixer->discont_wait > 0) {
1030 if (pad->discont_time == GST_CLOCK_TIME_NONE) {
1031 pad->discont_time = start_time;
1032 } else if (start_time - pad->discont_time >= audiomixer->discont_wait) {
1034 pad->discont_time = GST_CLOCK_TIME_NONE;
1039 } else if (G_UNLIKELY (pad->discont_time != GST_CLOCK_TIME_NONE)) {
1040 /* we have had a discont, but are now back on track! */
1041 pad->discont_time = GST_CLOCK_TIME_NONE;
1046 /* Have discont, need resync */
1047 if (pad->next_offset != -1)
1048 GST_INFO_OBJECT (pad, "Have discont. Expected %"
1049 G_GUINT64_FORMAT ", got %" G_GUINT64_FORMAT,
1050 pad->next_offset, start_offset);
1051 pad->output_offset = -1;
1053 pad->discont_time = GST_CLOCK_TIME_NONE;
1056 pad->next_offset = end_offset;
1058 if (pad->output_offset == -1) {
1059 GstClockTime start_running_time;
1060 GstClockTime end_running_time;
1061 guint64 start_running_time_offset;
1062 guint64 end_running_time_offset;
1064 start_running_time =
1065 gst_segment_to_running_time (&aggpad->segment,
1066 GST_FORMAT_TIME, start_time);
1068 gst_segment_to_running_time (&aggpad->segment,
1069 GST_FORMAT_TIME, end_time);
1070 start_running_time_offset =
1071 gst_util_uint64_scale (start_running_time, rate, GST_SECOND);
1072 end_running_time_offset =
1073 gst_util_uint64_scale (end_running_time, rate, GST_SECOND);
1075 if (end_running_time_offset < audiomixer->offset) {
1078 /* Before output segment, drop */
1079 gst_buffer_unref (inbuf);
1081 buf = gst_aggregator_pad_steal_buffer (aggpad);
1083 gst_buffer_unref (buf);
1086 pad->output_offset = -1;
1087 GST_DEBUG_OBJECT (pad,
1088 "Buffer before segment or current position: %" G_GUINT64_FORMAT " < %"
1089 G_GUINT64_FORMAT, end_running_time_offset, audiomixer->offset);
1093 if (start_running_time_offset < audiomixer->offset) {
1095 guint diff = (audiomixer->offset - start_running_time_offset) * bpf;
1097 pad->position += diff;
1098 if (pad->position >= pad->size) {
1099 /* Empty buffer, drop */
1100 gst_buffer_unref (inbuf);
1102 buf = gst_aggregator_pad_steal_buffer (aggpad);
1104 gst_buffer_unref (buf);
1107 pad->output_offset = -1;
1108 GST_DEBUG_OBJECT (pad,
1109 "Buffer before segment or current position: %" G_GUINT64_FORMAT
1110 " < %" G_GUINT64_FORMAT, end_running_time_offset,
1111 audiomixer->offset);
1116 pad->output_offset = MAX (start_running_time_offset, audiomixer->offset);
1117 GST_DEBUG_OBJECT (pad,
1118 "Buffer resynced: Pad offset %" G_GUINT64_FORMAT
1119 ", current mixer offset %" G_GUINT64_FORMAT, pad->output_offset,
1120 audiomixer->offset);
1123 GST_LOG_OBJECT (pad,
1124 "Queued new buffer at offset %" G_GUINT64_FORMAT, pad->output_offset);
1125 pad->buffer = inbuf;
1131 gst_audio_mixer_mix_buffer (GstAudioMixer * audiomixer, GstAudioMixerPad * pad,
1132 GstMapInfo * outmap)
1141 GstAggregatorPad *aggpad = GST_AGGREGATOR_PAD (pad);
1144 gst_util_uint64_scale (audiomixer->output_buffer_duration,
1145 GST_AUDIO_INFO_RATE (&audiomixer->info), GST_SECOND);
1146 blocksize = MAX (1, blocksize);
1148 bpf = GST_AUDIO_INFO_BPF (&audiomixer->info);
1150 /* Overlap => mix */
1151 if (audiomixer->offset < pad->output_offset)
1152 out_start = pad->output_offset - audiomixer->offset;
1156 overlap = pad->size / bpf - pad->position / bpf;
1157 if (overlap > blocksize - out_start)
1158 overlap = blocksize - out_start;
1160 inbuf = gst_aggregator_pad_get_buffer (aggpad);
1164 GST_OBJECT_LOCK (pad);
1165 if (pad->mute || pad->volume < G_MINDOUBLE) {
1166 GST_DEBUG_OBJECT (pad, "Skipping muted pad");
1167 gst_buffer_unref (inbuf);
1168 pad->position += overlap * bpf;
1169 pad->output_offset += overlap;
1170 if (pad->position >= pad->size) {
1172 /* Buffer done, drop it */
1173 gst_buffer_replace (&pad->buffer, NULL);
1174 buf = gst_aggregator_pad_steal_buffer (aggpad);
1176 gst_buffer_unref (buf);
1178 GST_OBJECT_UNLOCK (pad);
1182 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) {
1183 GstBuffer *aggpadbuf = gst_aggregator_pad_steal_buffer (aggpad);
1185 /* skip gap buffer */
1186 GST_LOG_OBJECT (pad, "skipping GAP buffer");
1187 gst_buffer_unref (inbuf);
1188 pad->output_offset += pad->size / bpf;
1189 /* Buffer done, drop it */
1190 gst_buffer_replace (&pad->buffer, NULL);
1192 gst_buffer_unref (aggpadbuf);
1193 GST_OBJECT_UNLOCK (pad);
1197 gst_buffer_map (inbuf, &inmap, GST_MAP_READ);
1198 GST_LOG_OBJECT (pad, "mixing %u bytes at offset %u from offset %u",
1199 overlap * bpf, out_start * bpf, pad->position);
1200 /* further buffers, need to add them */
1201 if (pad->volume == 1.0) {
1202 switch (audiomixer->info.finfo->format) {
1203 case GST_AUDIO_FORMAT_U8:
1204 audiomixer_orc_add_u8 ((gpointer) (outmap->data + out_start * bpf),
1205 (gpointer) (inmap.data + pad->position),
1206 overlap * audiomixer->info.channels);
1208 case GST_AUDIO_FORMAT_S8:
1209 audiomixer_orc_add_s8 ((gpointer) (outmap->data + out_start * bpf),
1210 (gpointer) (inmap.data + pad->position),
1211 overlap * audiomixer->info.channels);
1213 case GST_AUDIO_FORMAT_U16:
1214 audiomixer_orc_add_u16 ((gpointer) (outmap->data + out_start * bpf),
1215 (gpointer) (inmap.data + pad->position),
1216 overlap * audiomixer->info.channels);
1218 case GST_AUDIO_FORMAT_S16:
1219 audiomixer_orc_add_s16 ((gpointer) (outmap->data + out_start * bpf),
1220 (gpointer) (inmap.data + pad->position),
1221 overlap * audiomixer->info.channels);
1223 case GST_AUDIO_FORMAT_U32:
1224 audiomixer_orc_add_u32 ((gpointer) (outmap->data + out_start * bpf),
1225 (gpointer) (inmap.data + pad->position),
1226 overlap * audiomixer->info.channels);
1228 case GST_AUDIO_FORMAT_S32:
1229 audiomixer_orc_add_s32 ((gpointer) (outmap->data + out_start * bpf),
1230 (gpointer) (inmap.data + pad->position),
1231 overlap * audiomixer->info.channels);
1233 case GST_AUDIO_FORMAT_F32:
1234 audiomixer_orc_add_f32 ((gpointer) (outmap->data + out_start * bpf),
1235 (gpointer) (inmap.data + pad->position),
1236 overlap * audiomixer->info.channels);
1238 case GST_AUDIO_FORMAT_F64:
1239 audiomixer_orc_add_f64 ((gpointer) (outmap->data + out_start * bpf),
1240 (gpointer) (inmap.data + pad->position),
1241 overlap * audiomixer->info.channels);
1244 g_assert_not_reached ();
1248 switch (audiomixer->info.finfo->format) {
1249 case GST_AUDIO_FORMAT_U8:
1250 audiomixer_orc_add_volume_u8 ((gpointer) (outmap->data +
1251 out_start * bpf), (gpointer) (inmap.data + pad->position),
1252 pad->volume_i8, overlap * audiomixer->info.channels);
1254 case GST_AUDIO_FORMAT_S8:
1255 audiomixer_orc_add_volume_s8 ((gpointer) (outmap->data +
1256 out_start * bpf), (gpointer) (inmap.data + pad->position),
1257 pad->volume_i8, overlap * audiomixer->info.channels);
1259 case GST_AUDIO_FORMAT_U16:
1260 audiomixer_orc_add_volume_u16 ((gpointer) (outmap->data +
1261 out_start * bpf), (gpointer) (inmap.data + pad->position),
1262 pad->volume_i16, overlap * audiomixer->info.channels);
1264 case GST_AUDIO_FORMAT_S16:
1265 audiomixer_orc_add_volume_s16 ((gpointer) (outmap->data +
1266 out_start * bpf), (gpointer) (inmap.data + pad->position),
1267 pad->volume_i16, overlap * audiomixer->info.channels);
1269 case GST_AUDIO_FORMAT_U32:
1270 audiomixer_orc_add_volume_u32 ((gpointer) (outmap->data +
1271 out_start * bpf), (gpointer) (inmap.data + pad->position),
1272 pad->volume_i32, overlap * audiomixer->info.channels);
1274 case GST_AUDIO_FORMAT_S32:
1275 audiomixer_orc_add_volume_s32 ((gpointer) (outmap->data +
1276 out_start * bpf), (gpointer) (inmap.data + pad->position),
1277 pad->volume_i32, overlap * audiomixer->info.channels);
1279 case GST_AUDIO_FORMAT_F32:
1280 audiomixer_orc_add_volume_f32 ((gpointer) (outmap->data +
1281 out_start * bpf), (gpointer) (inmap.data + pad->position),
1282 pad->volume, overlap * audiomixer->info.channels);
1284 case GST_AUDIO_FORMAT_F64:
1285 audiomixer_orc_add_volume_f64 ((gpointer) (outmap->data +
1286 out_start * bpf), (gpointer) (inmap.data + pad->position),
1287 pad->volume, overlap * audiomixer->info.channels);
1290 g_assert_not_reached ();
1294 gst_buffer_unmap (inbuf, &inmap);
1295 gst_buffer_unref (inbuf);
1297 pad->position += overlap * bpf;
1298 pad->output_offset += overlap;
1300 if (pad->position == pad->size) {
1303 /* Buffer done, drop it */
1304 gst_buffer_replace (&pad->buffer, NULL);
1305 buf = gst_aggregator_pad_steal_buffer (aggpad);
1307 gst_buffer_unref (buf);
1308 GST_DEBUG_OBJECT (pad, "Finished mixing buffer, waiting for next");
1311 GST_OBJECT_UNLOCK (pad);
1314 static GstFlowReturn
1315 gst_audiomixer_aggregate (GstAggregator * agg, gboolean timeout)
1317 /* Get all pads that have data for us and store them in a
1320 * Calculate the current output offset/timestamp and
1321 * offset_end/timestamp_end. Allocate a silence buffer
1322 * for this and store it.
1325 * 1) Once per input buffer (cached)
1326 * 1) Check discont (flag and timestamp with tolerance)
1327 * 2) If discont or new, resync. That means:
1328 * 1) Drop all start data of the buffer that comes before
1329 * the current position/offset.
1330 * 2) Calculate the offset (output segment!) that the first
1331 * frame of the input buffer corresponds to. Base this on
1334 * 2) If the current pad's offset/offset_end overlaps with the output
1335 * offset/offset_end, mix it at the appropiate position in the output
1336 * buffer and advance the pad's position. Remember if this pad needs
1337 * a new buffer to advance behind the output offset_end.
1339 * 3) If we had no pad with a buffer, go EOS.
1341 * 4) If we had at least one pad that did not advance behind output
1342 * offset_end, let collected be called again for the current
1343 * output offset/offset_end.
1345 GstAudioMixer *audiomixer;
1348 GstBuffer *outbuf = NULL;
1351 gint64 next_timestamp;
1353 gboolean dropped = FALSE;
1354 gboolean is_eos = TRUE;
1355 gboolean is_done = TRUE;
1358 audiomixer = GST_AUDIO_MIXER (agg);
1360 /* Update position from the segment start/stop if needed */
1361 if (agg->segment.position == -1) {
1362 if (agg->segment.rate > 0.0)
1363 agg->segment.position = agg->segment.start;
1365 agg->segment.position = agg->segment.stop;
1368 if (G_UNLIKELY (audiomixer->info.finfo->format == GST_AUDIO_FORMAT_UNKNOWN)) {
1370 GST_DEBUG_OBJECT (audiomixer,
1371 "Got timeout before receiving any caps, don't output anything");
1373 /* Advance position */
1374 if (agg->segment.rate > 0.0)
1375 agg->segment.position += audiomixer->output_buffer_duration;
1376 else if (agg->segment.position > audiomixer->output_buffer_duration)
1377 agg->segment.position -= audiomixer->output_buffer_duration;
1379 agg->segment.position = 0;
1383 goto not_negotiated;
1388 gst_util_uint64_scale (audiomixer->output_buffer_duration,
1389 GST_AUDIO_INFO_RATE (&audiomixer->info), GST_SECOND);
1390 blocksize = MAX (1, blocksize);
1392 if (audiomixer->send_caps) {
1393 gst_aggregator_set_src_caps (agg, audiomixer->current_caps);
1395 audiomixer->offset = gst_util_uint64_scale (agg->segment.position,
1396 GST_AUDIO_INFO_RATE (&audiomixer->info), GST_SECOND);
1398 audiomixer->send_caps = FALSE;
1401 rate = GST_AUDIO_INFO_RATE (&audiomixer->info);
1402 bpf = GST_AUDIO_INFO_BPF (&audiomixer->info);
1404 /* for the next timestamp, use the sample counter, which will
1405 * never accumulate rounding errors */
1407 /* FIXME: Reverse mixing does not work at all yet */
1408 if (agg->segment.rate > 0.0) {
1409 next_offset = audiomixer->offset + blocksize;
1411 next_offset = audiomixer->offset - blocksize;
1413 next_timestamp = gst_util_uint64_scale (next_offset, GST_SECOND, rate);
1415 if (audiomixer->current_buffer) {
1416 outbuf = audiomixer->current_buffer;
1418 outbuf = gst_buffer_new_and_alloc (blocksize * bpf);
1419 gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
1420 gst_audio_format_fill_silence (audiomixer->info.finfo, outmap.data,
1422 gst_buffer_unmap (outbuf, &outmap);
1423 audiomixer->current_buffer = outbuf;
1426 GST_LOG_OBJECT (agg,
1427 "Starting to mix %u samples for offset %" G_GUINT64_FORMAT
1428 " with timestamp %" GST_TIME_FORMAT, blocksize,
1429 audiomixer->offset, GST_TIME_ARGS (agg->segment.position));
1431 gst_buffer_map (outbuf, &outmap, GST_MAP_READWRITE);
1433 GST_OBJECT_LOCK (agg);
1434 for (iter = GST_ELEMENT (agg)->sinkpads; iter; iter = iter->next) {
1436 GstAudioMixerPad *pad = GST_AUDIO_MIXER_PAD (iter->data);
1437 GstAggregatorPad *aggpad = GST_AGGREGATOR_PAD (iter->data);
1439 if (!gst_aggregator_pad_is_eos (aggpad))
1442 inbuf = gst_aggregator_pad_get_buffer (aggpad);
1446 g_assert (!pad->buffer || pad->buffer == inbuf);
1450 /* Takes ownership of buffer */
1451 if (!gst_audio_mixer_fill_buffer (audiomixer, pad, inbuf)) {
1456 gst_buffer_unref (inbuf);
1459 if (!pad->buffer && !dropped && gst_aggregator_pad_is_eos (aggpad)) {
1460 GST_DEBUG_OBJECT (aggpad, "Pad is in EOS state");
1464 g_assert (pad->buffer);
1466 /* This pad is lacking behind, we need to update the offset
1467 * and maybe drop the current buffer */
1468 if (pad->output_offset < audiomixer->offset) {
1469 gint64 diff = audiomixer->offset - pad->output_offset;
1470 gint bpf = GST_AUDIO_INFO_BPF (&audiomixer->info);
1472 pad->position += diff * bpf;
1473 if (pad->position > pad->size) {
1474 diff = (pad->position - pad->size) / bpf;
1475 pad->position = pad->size;
1477 pad->output_offset += diff;
1479 if (pad->position == pad->size) {
1482 /* Buffer done, drop it */
1483 gst_buffer_replace (&pad->buffer, NULL);
1484 buf = gst_aggregator_pad_steal_buffer (aggpad);
1486 gst_buffer_unref (buf);
1492 if (pad->output_offset >= audiomixer->offset
1493 && pad->output_offset < audiomixer->offset + blocksize && pad->buffer) {
1494 GST_LOG_OBJECT (aggpad, "Mixing buffer for current offset");
1495 gst_audio_mixer_mix_buffer (audiomixer, pad, &outmap);
1497 if (pad->output_offset >= next_offset) {
1498 GST_DEBUG_OBJECT (pad,
1499 "Pad is after current offset: %" G_GUINT64_FORMAT " >= %"
1500 G_GUINT64_FORMAT, pad->output_offset, next_offset);
1506 GST_OBJECT_UNLOCK (agg);
1508 gst_buffer_unmap (outbuf, &outmap);
1510 if (dropped && !timeout) {
1511 /* We dropped a buffer, retry */
1512 GST_INFO_OBJECT (audiomixer,
1513 "A pad dropped a buffer, wait for the next one");
1517 if (!is_done && !is_eos && !timeout) {
1518 /* Get more buffers */
1519 GST_INFO_OBJECT (audiomixer,
1520 "We're not done yet for the current offset, waiting for more data");
1525 gint64 max_offset = 0;
1526 gboolean empty_buffer = TRUE;
1528 GST_DEBUG_OBJECT (audiomixer, "We're EOS");
1530 GST_OBJECT_LOCK (agg);
1531 for (iter = GST_ELEMENT (agg)->sinkpads; iter; iter = iter->next) {
1532 GstAudioMixerPad *pad = GST_AUDIO_MIXER_PAD (iter->data);
1534 max_offset = MAX ((gint64) max_offset, (gint64) pad->output_offset);
1535 if (pad->output_offset > audiomixer->offset)
1536 empty_buffer = FALSE;
1538 GST_OBJECT_UNLOCK (agg);
1540 /* This means EOS or no pads at all */
1542 gst_buffer_replace (&audiomixer->current_buffer, NULL);
1546 if (max_offset <= next_offset) {
1547 GST_DEBUG_OBJECT (audiomixer,
1548 "Last buffer is incomplete: %" G_GUINT64_FORMAT " <= %"
1549 G_GUINT64_FORMAT, max_offset, next_offset);
1550 next_offset = max_offset;
1551 if (next_offset > audiomixer->offset)
1552 gst_buffer_resize (outbuf, 0, (next_offset - audiomixer->offset) * bpf);
1554 next_timestamp = gst_util_uint64_scale (next_offset, GST_SECOND, rate);
1558 /* set timestamps on the output buffer */
1559 if (agg->segment.rate > 0.0) {
1560 GST_BUFFER_TIMESTAMP (outbuf) = agg->segment.position;
1561 GST_BUFFER_OFFSET (outbuf) = audiomixer->offset;
1562 GST_BUFFER_OFFSET_END (outbuf) = next_offset;
1563 GST_BUFFER_DURATION (outbuf) = next_timestamp - agg->segment.position;
1565 GST_BUFFER_TIMESTAMP (outbuf) = next_timestamp;
1566 GST_BUFFER_OFFSET (outbuf) = next_offset;
1567 GST_BUFFER_OFFSET_END (outbuf) = audiomixer->offset;
1568 GST_BUFFER_DURATION (outbuf) = agg->segment.position - next_timestamp;
1571 audiomixer->offset = next_offset;
1572 agg->segment.position = next_timestamp;
1575 GST_LOG_OBJECT (audiomixer,
1576 "pushing outbuf %p, timestamp %" GST_TIME_FORMAT " offset %"
1577 G_GINT64_FORMAT, outbuf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1578 GST_BUFFER_OFFSET (outbuf));
1580 ret = gst_aggregator_finish_buffer (agg, audiomixer->current_buffer);
1581 audiomixer->current_buffer = NULL;
1583 GST_LOG_OBJECT (audiomixer, "pushed outbuf, result = %s",
1584 gst_flow_get_name (ret));
1586 if (ret == GST_FLOW_OK && is_eos)
1593 GST_ELEMENT_ERROR (audiomixer, STREAM, FORMAT, (NULL),
1594 ("Unknown data received, not negotiated"));
1595 return GST_FLOW_NOT_NEGOTIATED;
1600 GST_DEBUG_OBJECT (audiomixer, "EOS");
1601 return GST_FLOW_EOS;
1605 /* GstChildProxy implementation */
1607 gst_audiomixer_child_proxy_get_child_by_index (GstChildProxy * child_proxy,
1610 GstAudioMixer *audiomixer = GST_AUDIO_MIXER (child_proxy);
1611 GObject *obj = NULL;
1613 GST_OBJECT_LOCK (audiomixer);
1614 obj = g_list_nth_data (GST_ELEMENT_CAST (audiomixer)->sinkpads, index);
1616 gst_object_ref (obj);
1617 GST_OBJECT_UNLOCK (audiomixer);
1623 gst_audiomixer_child_proxy_get_children_count (GstChildProxy * child_proxy)
1626 GstAudioMixer *audiomixer = GST_AUDIO_MIXER (child_proxy);
1628 GST_OBJECT_LOCK (audiomixer);
1629 count = GST_ELEMENT_CAST (audiomixer)->numsinkpads;
1630 GST_OBJECT_UNLOCK (audiomixer);
1631 GST_INFO_OBJECT (audiomixer, "Children Count: %d", count);
1637 gst_audiomixer_child_proxy_init (gpointer g_iface, gpointer iface_data)
1639 GstChildProxyInterface *iface = g_iface;
1641 GST_INFO ("intializing child proxy interface");
1642 iface->get_child_by_index = gst_audiomixer_child_proxy_get_child_by_index;
1643 iface->get_children_count = gst_audiomixer_child_proxy_get_children_count;
1647 plugin_init (GstPlugin * plugin)
1649 GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "audiomixer", 0,
1650 "audio mixing element");
1652 if (!gst_element_register (plugin, "audiomixer", GST_RANK_NONE,
1653 GST_TYPE_AUDIO_MIXER))
1659 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1662 "Mixes multiple audio streams",
1663 plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)