interaudiosink: Ensure adapters don't store buffers with audio meta
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / gst / inter / gstinteraudiosink.c
1 /* GStreamer
2  * Copyright (C) 2011 David A. Schleef <ds@schleef.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
17  * Boston, MA 02110-1335, USA.
18  */
19 /**
20  * SECTION:element-interaudiosink
21  * @title: gstinteraudiosink
22  *
23  * The interaudiosink element is an audio sink element.  It is used
24  * in connection with a interaudiosrc element in a different pipeline,
25  * similar to intervideosink and intervideosrc.
26  *
27  * ## Example launch line
28  * |[
29  * gst-launch-1.0 -v audiotestsrc ! queue ! interaudiosink
30  * ]|
31  *
32  * The interaudiosink element cannot be used effectively with gst-launch-1.0,
33  * as it requires a second pipeline in the application to receive the
34  * audio.
35  * See the gstintertest.c example in the gst-plugins-bad source code for
36  * more details.
37  *
38  */
39
40 #ifdef HAVE_CONFIG_H
41 #include "config.h"
42 #endif
43
44 #include <gst/gst.h>
45 #include <gst/base/gstbasesink.h>
46 #include <gst/audio/audio.h>
47 #include "gstinteraudiosink.h"
48 #include <string.h>
49
50 GST_DEBUG_CATEGORY_STATIC (gst_inter_audio_sink_debug_category);
51 #define GST_CAT_DEFAULT gst_inter_audio_sink_debug_category
52
53 /* prototypes */
54 static void gst_inter_audio_sink_set_property (GObject * object,
55     guint property_id, const GValue * value, GParamSpec * pspec);
56 static void gst_inter_audio_sink_get_property (GObject * object,
57     guint property_id, GValue * value, GParamSpec * pspec);
58 static void gst_inter_audio_sink_finalize (GObject * object);
59
60 static void gst_inter_audio_sink_get_times (GstBaseSink * sink,
61     GstBuffer * buffer, GstClockTime * start, GstClockTime * end);
62 static gboolean gst_inter_audio_sink_start (GstBaseSink * sink);
63 static gboolean gst_inter_audio_sink_stop (GstBaseSink * sink);
64 static gboolean gst_inter_audio_sink_set_caps (GstBaseSink * sink,
65     GstCaps * caps);
66 static gboolean gst_inter_audio_sink_event (GstBaseSink * sink,
67     GstEvent * event);
68 static GstFlowReturn gst_inter_audio_sink_render (GstBaseSink * sink,
69     GstBuffer * buffer);
70 static gboolean gst_inter_audio_sink_query (GstBaseSink * sink,
71     GstQuery * query);
72
73 enum
74 {
75   PROP_0,
76   PROP_CHANNEL
77 };
78
79 #define DEFAULT_CHANNEL ("default")
80
81 /* pad templates */
82 static GstStaticPadTemplate gst_inter_audio_sink_sink_template =
83 GST_STATIC_PAD_TEMPLATE ("sink",
84     GST_PAD_SINK,
85     GST_PAD_ALWAYS,
86     GST_STATIC_CAPS (GST_AUDIO_CAPS_MAKE (GST_AUDIO_FORMATS_ALL))
87     );
88
89 /* class initialization */
90 #define parent_class gst_inter_audio_sink_parent_class
91 G_DEFINE_TYPE (GstInterAudioSink, gst_inter_audio_sink, GST_TYPE_BASE_SINK);
92 GST_ELEMENT_REGISTER_DEFINE (interaudiosink, "interaudiosink",
93     GST_RANK_NONE, GST_TYPE_INTER_AUDIO_SINK);
94
95 static void
96 gst_inter_audio_sink_class_init (GstInterAudioSinkClass * klass)
97 {
98   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
99   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
100   GstBaseSinkClass *base_sink_class = GST_BASE_SINK_CLASS (klass);
101
102   GST_DEBUG_CATEGORY_INIT (gst_inter_audio_sink_debug_category,
103       "interaudiosink", 0, "debug category for interaudiosink element");
104   gst_element_class_add_static_pad_template (element_class,
105       &gst_inter_audio_sink_sink_template);
106
107   gst_element_class_set_static_metadata (element_class,
108       "Internal audio sink",
109       "Sink/Audio",
110       "Virtual audio sink for internal process communication",
111       "David Schleef <ds@schleef.org>");
112
113   gobject_class->set_property = gst_inter_audio_sink_set_property;
114   gobject_class->get_property = gst_inter_audio_sink_get_property;
115   gobject_class->finalize = gst_inter_audio_sink_finalize;
116   base_sink_class->get_times =
117       GST_DEBUG_FUNCPTR (gst_inter_audio_sink_get_times);
118   base_sink_class->start = GST_DEBUG_FUNCPTR (gst_inter_audio_sink_start);
119   base_sink_class->stop = GST_DEBUG_FUNCPTR (gst_inter_audio_sink_stop);
120   base_sink_class->event = GST_DEBUG_FUNCPTR (gst_inter_audio_sink_event);
121   base_sink_class->set_caps = GST_DEBUG_FUNCPTR (gst_inter_audio_sink_set_caps);
122   base_sink_class->render = GST_DEBUG_FUNCPTR (gst_inter_audio_sink_render);
123   base_sink_class->query = GST_DEBUG_FUNCPTR (gst_inter_audio_sink_query);
124
125   g_object_class_install_property (gobject_class, PROP_CHANNEL,
126       g_param_spec_string ("channel", "Channel",
127           "Channel name to match inter src and sink elements",
128           DEFAULT_CHANNEL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
129 }
130
131 static void
132 gst_inter_audio_sink_init (GstInterAudioSink * interaudiosink)
133 {
134   interaudiosink->channel = g_strdup (DEFAULT_CHANNEL);
135   interaudiosink->input_adapter = gst_adapter_new ();
136 }
137
138 void
139 gst_inter_audio_sink_set_property (GObject * object, guint property_id,
140     const GValue * value, GParamSpec * pspec)
141 {
142   GstInterAudioSink *interaudiosink = GST_INTER_AUDIO_SINK (object);
143
144   switch (property_id) {
145     case PROP_CHANNEL:
146       g_free (interaudiosink->channel);
147       interaudiosink->channel = g_value_dup_string (value);
148       break;
149     default:
150       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
151       break;
152   }
153 }
154
155 void
156 gst_inter_audio_sink_get_property (GObject * object, guint property_id,
157     GValue * value, GParamSpec * pspec)
158 {
159   GstInterAudioSink *interaudiosink = GST_INTER_AUDIO_SINK (object);
160
161   switch (property_id) {
162     case PROP_CHANNEL:
163       g_value_set_string (value, interaudiosink->channel);
164       break;
165     default:
166       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
167       break;
168   }
169 }
170
171 void
172 gst_inter_audio_sink_finalize (GObject * object)
173 {
174   GstInterAudioSink *interaudiosink = GST_INTER_AUDIO_SINK (object);
175
176   /* clean up object here */
177   g_free (interaudiosink->channel);
178   gst_object_unref (interaudiosink->input_adapter);
179
180   G_OBJECT_CLASS (gst_inter_audio_sink_parent_class)->finalize (object);
181 }
182
183 static void
184 gst_inter_audio_sink_get_times (GstBaseSink * sink, GstBuffer * buffer,
185     GstClockTime * start, GstClockTime * end)
186 {
187   GstInterAudioSink *interaudiosink = GST_INTER_AUDIO_SINK (sink);
188
189   if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) {
190     *start = GST_BUFFER_TIMESTAMP (buffer);
191     if (GST_BUFFER_DURATION_IS_VALID (buffer)) {
192       *end = *start + GST_BUFFER_DURATION (buffer);
193     } else {
194       if (interaudiosink->info.rate > 0) {
195         *end = *start +
196             gst_util_uint64_scale_int (gst_buffer_get_size (buffer), GST_SECOND,
197             interaudiosink->info.rate * interaudiosink->info.bpf);
198       }
199     }
200   }
201 }
202
203 static gboolean
204 gst_inter_audio_sink_start (GstBaseSink * sink)
205 {
206   GstInterAudioSink *interaudiosink = GST_INTER_AUDIO_SINK (sink);
207
208   GST_DEBUG_OBJECT (interaudiosink, "start");
209
210   interaudiosink->surface = gst_inter_surface_get (interaudiosink->channel);
211   g_mutex_lock (&interaudiosink->surface->mutex);
212   memset (&interaudiosink->surface->audio_info, 0, sizeof (GstAudioInfo));
213
214   /* We want to write latency-time before syncing has happened */
215   /* FIXME: The other side can change this value when it starts */
216   gst_base_sink_set_render_delay (sink,
217       interaudiosink->surface->audio_latency_time);
218   g_mutex_unlock (&interaudiosink->surface->mutex);
219
220   return TRUE;
221 }
222
223 static gboolean
224 gst_inter_audio_sink_stop (GstBaseSink * sink)
225 {
226   GstInterAudioSink *interaudiosink = GST_INTER_AUDIO_SINK (sink);
227
228   GST_DEBUG_OBJECT (interaudiosink, "stop");
229
230   g_mutex_lock (&interaudiosink->surface->mutex);
231   gst_adapter_clear (interaudiosink->surface->audio_adapter);
232   memset (&interaudiosink->surface->audio_info, 0, sizeof (GstAudioInfo));
233   g_mutex_unlock (&interaudiosink->surface->mutex);
234
235   gst_inter_surface_unref (interaudiosink->surface);
236   interaudiosink->surface = NULL;
237
238   gst_adapter_clear (interaudiosink->input_adapter);
239
240   return TRUE;
241 }
242
243 static gboolean
244 gst_inter_audio_sink_set_caps (GstBaseSink * sink, GstCaps * caps)
245 {
246   GstInterAudioSink *interaudiosink = GST_INTER_AUDIO_SINK (sink);
247   GstAudioInfo info;
248
249   if (!gst_audio_info_from_caps (&info, caps)) {
250     GST_ERROR_OBJECT (sink, "Failed to parse caps %" GST_PTR_FORMAT, caps);
251     return FALSE;
252   }
253
254   g_mutex_lock (&interaudiosink->surface->mutex);
255   interaudiosink->surface->audio_info = info;
256   interaudiosink->info = info;
257   /* TODO: Ideally we would drain the source here */
258   gst_adapter_clear (interaudiosink->surface->audio_adapter);
259   g_mutex_unlock (&interaudiosink->surface->mutex);
260
261   return TRUE;
262 }
263
264 static gboolean
265 gst_inter_audio_sink_event (GstBaseSink * sink, GstEvent * event)
266 {
267   GstInterAudioSink *interaudiosink = GST_INTER_AUDIO_SINK (sink);
268
269   switch (GST_EVENT_TYPE (event)) {
270     case GST_EVENT_EOS:{
271       GstBuffer *tmp;
272       guint n;
273
274       if ((n = gst_adapter_available (interaudiosink->input_adapter)) > 0) {
275         g_mutex_lock (&interaudiosink->surface->mutex);
276         tmp = gst_adapter_take_buffer (interaudiosink->input_adapter, n);
277         gst_adapter_push (interaudiosink->surface->audio_adapter, tmp);
278         g_mutex_unlock (&interaudiosink->surface->mutex);
279       }
280       break;
281     }
282     default:
283       break;
284   }
285
286   return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
287 }
288
289 static GstFlowReturn
290 gst_inter_audio_sink_render (GstBaseSink * sink, GstBuffer * buffer)
291 {
292   GstInterAudioSink *interaudiosink = GST_INTER_AUDIO_SINK (sink);
293   guint n, bpf;
294   guint64 period_time, buffer_time;
295   guint64 period_samples, buffer_samples;
296   GstBuffer *tmp;
297
298   GST_DEBUG_OBJECT (interaudiosink, "render %" G_GSIZE_FORMAT,
299       gst_buffer_get_size (buffer));
300   bpf = interaudiosink->info.bpf;
301
302   g_mutex_lock (&interaudiosink->surface->mutex);
303
304   buffer_time = interaudiosink->surface->audio_buffer_time;
305   period_time = interaudiosink->surface->audio_period_time;
306
307   if (buffer_time < period_time) {
308     GST_ERROR_OBJECT (interaudiosink,
309         "Buffer time smaller than period time (%" GST_TIME_FORMAT " < %"
310         GST_TIME_FORMAT ")", GST_TIME_ARGS (buffer_time),
311         GST_TIME_ARGS (period_time));
312     g_mutex_unlock (&interaudiosink->surface->mutex);
313     return GST_FLOW_ERROR;
314   }
315
316   buffer_samples =
317       gst_util_uint64_scale (buffer_time, interaudiosink->info.rate,
318       GST_SECOND);
319   period_samples =
320       gst_util_uint64_scale (period_time, interaudiosink->info.rate,
321       GST_SECOND);
322
323   n = gst_adapter_available (interaudiosink->surface->audio_adapter) / bpf;
324   while (n > buffer_samples) {
325     GST_DEBUG_OBJECT (interaudiosink, "flushing %" GST_TIME_FORMAT,
326         GST_TIME_ARGS (period_time));
327     gst_adapter_flush (interaudiosink->surface->audio_adapter,
328         period_samples * bpf);
329     n -= period_samples;
330   }
331
332   n = gst_adapter_available (interaudiosink->input_adapter);
333   if (period_samples * bpf > gst_buffer_get_size (buffer) + n) {
334     GstAudioMeta *audio_meta = NULL;
335
336     tmp = gst_buffer_copy_deep (buffer);
337     audio_meta = gst_buffer_get_audio_meta (tmp);
338     if (audio_meta != NULL)
339       gst_buffer_remove_meta (tmp, GST_META_CAST (audio_meta));
340
341     gst_adapter_push (interaudiosink->input_adapter, tmp);
342   } else {
343     GstAudioMeta *audio_meta = NULL;
344
345     if (n > 0) {
346       tmp = gst_adapter_take_buffer (interaudiosink->input_adapter, n);
347       gst_adapter_push (interaudiosink->surface->audio_adapter, tmp);
348     }
349     tmp = gst_buffer_copy_deep (buffer);
350     audio_meta = gst_buffer_get_audio_meta (tmp);
351     if (audio_meta != NULL)
352       gst_buffer_remove_meta (tmp, GST_META_CAST (audio_meta));
353     gst_adapter_push (interaudiosink->surface->audio_adapter, tmp);
354   }
355   g_mutex_unlock (&interaudiosink->surface->mutex);
356
357   return GST_FLOW_OK;
358 }
359
360 static gboolean
361 gst_inter_audio_sink_query (GstBaseSink * sink, GstQuery * query)
362 {
363   GstInterAudioSink *interaudiosink = GST_INTER_AUDIO_SINK (sink);
364   gboolean ret;
365
366   GST_DEBUG_OBJECT (sink, "query");
367
368   switch (GST_QUERY_TYPE (query)) {
369     case GST_QUERY_LATENCY:{
370       gboolean live, us_live;
371       GstClockTime min_l, max_l;
372
373       GST_DEBUG_OBJECT (sink, "latency query");
374
375       if ((ret =
376               gst_base_sink_query_latency (GST_BASE_SINK_CAST (sink), &live,
377                   &us_live, &min_l, &max_l))) {
378         GstClockTime base_latency, min_latency, max_latency;
379
380         /* we and upstream are both live, adjust the min_latency */
381         if (live && us_live) {
382           /* FIXME: The other side can change this value when it starts */
383           base_latency = interaudiosink->surface->audio_latency_time;
384
385           /* we cannot go lower than the buffer size and the min peer latency */
386           min_latency = base_latency + min_l;
387           /* the max latency is the max of the peer, we can delay an infinite
388            * amount of time. */
389           max_latency = (max_l == -1) ? -1 : (base_latency + max_l);
390
391           GST_DEBUG_OBJECT (sink,
392               "peer min %" GST_TIME_FORMAT ", our min latency: %"
393               GST_TIME_FORMAT, GST_TIME_ARGS (min_l),
394               GST_TIME_ARGS (min_latency));
395           GST_DEBUG_OBJECT (sink,
396               "peer max %" GST_TIME_FORMAT ", our max latency: %"
397               GST_TIME_FORMAT, GST_TIME_ARGS (max_l),
398               GST_TIME_ARGS (max_latency));
399         } else {
400           GST_DEBUG_OBJECT (sink,
401               "peer or we are not live, don't care about latency");
402           min_latency = min_l;
403           max_latency = max_l;
404         }
405         gst_query_set_latency (query, live, min_latency, max_latency);
406       }
407       break;
408     }
409     default:
410       ret =
411           GST_BASE_SINK_CLASS (gst_inter_audio_sink_parent_class)->query (sink,
412           query);
413       break;
414   }
415
416   return ret;
417 }