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-gstinteraudiosrc
21  * @title: gstinteraudiosrc
22  *
23  * The interaudiosrc element is an audio source element.  It is used
24  * in connection with a interaudiosink element in a different pipeline.
25  *
26  * ## Example launch line
27  * |[
28  * gst-launch-1.0 -v interaudiosrc ! queue ! autoaudiosink
29  * ]|
30  *
31  * The interaudiosrc element cannot be used effectively with gst-launch-1.0,
32  * as it requires a second pipeline in the application to send audio.
33  * See the gstintertest.c example in the gst-plugins-bad source code for
34  * more details.
35  *
36  */
37 
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
41 
42 #include "gstinteraudiosrc.h"
43 
44 #include <gst/gst.h>
45 #include <gst/base/gstbasesrc.h>
46 #include <gst/audio/audio.h>
47 
48 #include <string.h>
49 
50 GST_DEBUG_CATEGORY_STATIC (gst_inter_audio_src_debug_category);
51 #define GST_CAT_DEFAULT gst_inter_audio_src_debug_category
52 
53 /* prototypes */
54 static void gst_inter_audio_src_set_property (GObject * object,
55     guint property_id, const GValue * value, GParamSpec * pspec);
56 static void gst_inter_audio_src_get_property (GObject * object,
57     guint property_id, GValue * value, GParamSpec * pspec);
58 static void gst_inter_audio_src_finalize (GObject * object);
59 
60 static GstCaps *gst_inter_audio_src_get_caps (GstBaseSrc * src,
61     GstCaps * filter);
62 static gboolean gst_inter_audio_src_set_caps (GstBaseSrc * src, GstCaps * caps);
63 static gboolean gst_inter_audio_src_start (GstBaseSrc * src);
64 static gboolean gst_inter_audio_src_stop (GstBaseSrc * src);
65 static void
66 gst_inter_audio_src_get_times (GstBaseSrc * src, GstBuffer * buffer,
67     GstClockTime * start, GstClockTime * end);
68 static GstFlowReturn
69 gst_inter_audio_src_create (GstBaseSrc * src, guint64 offset, guint size,
70     GstBuffer ** buf);
71 static gboolean gst_inter_audio_src_query (GstBaseSrc * src, GstQuery * query);
72 static GstCaps *gst_inter_audio_src_fixate (GstBaseSrc * src, GstCaps * caps);
73 
74 enum
75 {
76   PROP_0,
77   PROP_CHANNEL,
78   PROP_BUFFER_TIME,
79   PROP_LATENCY_TIME,
80   PROP_PERIOD_TIME
81 };
82 
83 #define DEFAULT_CHANNEL ("default")
84 
85 /* pad templates */
86 static GstStaticPadTemplate gst_inter_audio_src_src_template =
87 GST_STATIC_PAD_TEMPLATE ("src",
88     GST_PAD_SRC,
89     GST_PAD_ALWAYS,
90     GST_STATIC_CAPS (GST_AUDIO_CAPS_MAKE (GST_AUDIO_FORMATS_ALL)
91         ", layout = (string) interleaved")
92     );
93 
94 
95 /* class initialization */
96 #define parent_class gst_inter_audio_src_parent_class
97 G_DEFINE_TYPE (GstInterAudioSrc, gst_inter_audio_src, GST_TYPE_BASE_SRC);
98 
99 static void
gst_inter_audio_src_class_init(GstInterAudioSrcClass * klass)100 gst_inter_audio_src_class_init (GstInterAudioSrcClass * klass)
101 {
102   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
103   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
104   GstBaseSrcClass *base_src_class = GST_BASE_SRC_CLASS (klass);
105 
106   GST_DEBUG_CATEGORY_INIT (gst_inter_audio_src_debug_category, "interaudiosrc",
107       0, "debug category for interaudiosrc element");
108 
109   gst_element_class_add_static_pad_template (element_class,
110       &gst_inter_audio_src_src_template);
111 
112   gst_element_class_set_static_metadata (element_class,
113       "Internal audio source",
114       "Source/Audio",
115       "Virtual audio source for internal process communication",
116       "David Schleef <ds@schleef.org>");
117 
118   gobject_class->set_property = gst_inter_audio_src_set_property;
119   gobject_class->get_property = gst_inter_audio_src_get_property;
120   gobject_class->finalize = gst_inter_audio_src_finalize;
121   base_src_class->get_caps = GST_DEBUG_FUNCPTR (gst_inter_audio_src_get_caps);
122   base_src_class->set_caps = GST_DEBUG_FUNCPTR (gst_inter_audio_src_set_caps);
123   base_src_class->start = GST_DEBUG_FUNCPTR (gst_inter_audio_src_start);
124   base_src_class->stop = GST_DEBUG_FUNCPTR (gst_inter_audio_src_stop);
125   base_src_class->get_times = GST_DEBUG_FUNCPTR (gst_inter_audio_src_get_times);
126   base_src_class->create = GST_DEBUG_FUNCPTR (gst_inter_audio_src_create);
127   base_src_class->query = GST_DEBUG_FUNCPTR (gst_inter_audio_src_query);
128   base_src_class->fixate = GST_DEBUG_FUNCPTR (gst_inter_audio_src_fixate);
129 
130   g_object_class_install_property (gobject_class, PROP_CHANNEL,
131       g_param_spec_string ("channel", "Channel",
132           "Channel name to match inter src and sink elements",
133           DEFAULT_CHANNEL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
134 
135   g_object_class_install_property (gobject_class, PROP_BUFFER_TIME,
136       g_param_spec_uint64 ("buffer-time", "Buffer Time",
137           "Size of audio buffer", 1, G_MAXUINT64, DEFAULT_AUDIO_BUFFER_TIME,
138           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
139 
140   g_object_class_install_property (gobject_class, PROP_LATENCY_TIME,
141       g_param_spec_uint64 ("latency-time", "Latency Time",
142           "Latency as reported by the source",
143           1, G_MAXUINT64, DEFAULT_AUDIO_LATENCY_TIME,
144           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
145 
146   g_object_class_install_property (gobject_class, PROP_PERIOD_TIME,
147       g_param_spec_uint64 ("period-time", "Period Time",
148           "The minimum amount of data to read in each iteration",
149           1, G_MAXUINT64, DEFAULT_AUDIO_PERIOD_TIME,
150           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
151 }
152 
153 static void
gst_inter_audio_src_init(GstInterAudioSrc * interaudiosrc)154 gst_inter_audio_src_init (GstInterAudioSrc * interaudiosrc)
155 {
156   gst_base_src_set_format (GST_BASE_SRC (interaudiosrc), GST_FORMAT_TIME);
157   gst_base_src_set_live (GST_BASE_SRC (interaudiosrc), TRUE);
158   gst_base_src_set_blocksize (GST_BASE_SRC (interaudiosrc), -1);
159 
160   interaudiosrc->channel = g_strdup (DEFAULT_CHANNEL);
161   interaudiosrc->buffer_time = DEFAULT_AUDIO_BUFFER_TIME;
162   interaudiosrc->latency_time = DEFAULT_AUDIO_LATENCY_TIME;
163   interaudiosrc->period_time = DEFAULT_AUDIO_PERIOD_TIME;
164 }
165 
166 void
gst_inter_audio_src_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)167 gst_inter_audio_src_set_property (GObject * object, guint property_id,
168     const GValue * value, GParamSpec * pspec)
169 {
170   GstInterAudioSrc *interaudiosrc = GST_INTER_AUDIO_SRC (object);
171 
172   switch (property_id) {
173     case PROP_CHANNEL:
174       g_free (interaudiosrc->channel);
175       interaudiosrc->channel = g_value_dup_string (value);
176       break;
177     case PROP_BUFFER_TIME:
178       interaudiosrc->buffer_time = g_value_get_uint64 (value);
179       break;
180     case PROP_LATENCY_TIME:
181       interaudiosrc->latency_time = g_value_get_uint64 (value);
182       break;
183     case PROP_PERIOD_TIME:
184       interaudiosrc->period_time = g_value_get_uint64 (value);
185       break;
186     default:
187       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
188       break;
189   }
190 }
191 
192 void
gst_inter_audio_src_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)193 gst_inter_audio_src_get_property (GObject * object, guint property_id,
194     GValue * value, GParamSpec * pspec)
195 {
196   GstInterAudioSrc *interaudiosrc = GST_INTER_AUDIO_SRC (object);
197 
198   switch (property_id) {
199     case PROP_CHANNEL:
200       g_value_set_string (value, interaudiosrc->channel);
201       break;
202     case PROP_BUFFER_TIME:
203       g_value_set_uint64 (value, interaudiosrc->buffer_time);
204       break;
205     case PROP_LATENCY_TIME:
206       g_value_set_uint64 (value, interaudiosrc->latency_time);
207       break;
208     case PROP_PERIOD_TIME:
209       g_value_set_uint64 (value, interaudiosrc->period_time);
210       break;
211     default:
212       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
213       break;
214   }
215 }
216 
217 void
gst_inter_audio_src_finalize(GObject * object)218 gst_inter_audio_src_finalize (GObject * object)
219 {
220   GstInterAudioSrc *interaudiosrc = GST_INTER_AUDIO_SRC (object);
221 
222   /* clean up object here */
223   g_free (interaudiosrc->channel);
224 
225   G_OBJECT_CLASS (gst_inter_audio_src_parent_class)->finalize (object);
226 }
227 
228 static GstCaps *
gst_inter_audio_src_get_caps(GstBaseSrc * src,GstCaps * filter)229 gst_inter_audio_src_get_caps (GstBaseSrc * src, GstCaps * filter)
230 {
231   GstInterAudioSrc *interaudiosrc = GST_INTER_AUDIO_SRC (src);
232   GstCaps *caps;
233 
234   GST_DEBUG_OBJECT (interaudiosrc, "get_caps");
235 
236   if (!interaudiosrc->surface)
237     return GST_BASE_SRC_CLASS (parent_class)->get_caps (src, filter);
238 
239   g_mutex_lock (&interaudiosrc->surface->mutex);
240   if (interaudiosrc->surface->audio_info.finfo) {
241     caps = gst_audio_info_to_caps (&interaudiosrc->surface->audio_info);
242     if (filter) {
243       GstCaps *tmp;
244 
245       tmp = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
246       gst_caps_unref (caps);
247       caps = tmp;
248     }
249   } else {
250     caps = NULL;
251   }
252   g_mutex_unlock (&interaudiosrc->surface->mutex);
253 
254   if (caps)
255     return caps;
256   else
257     return GST_BASE_SRC_CLASS (parent_class)->get_caps (src, filter);
258 }
259 
260 static gboolean
gst_inter_audio_src_set_caps(GstBaseSrc * src,GstCaps * caps)261 gst_inter_audio_src_set_caps (GstBaseSrc * src, GstCaps * caps)
262 {
263   GstInterAudioSrc *interaudiosrc = GST_INTER_AUDIO_SRC (src);
264 
265   GST_DEBUG_OBJECT (interaudiosrc, "set_caps");
266 
267   if (!gst_audio_info_from_caps (&interaudiosrc->info, caps)) {
268     GST_ERROR_OBJECT (src, "Failed to parse caps %" GST_PTR_FORMAT, caps);
269     return FALSE;
270   }
271 
272   return TRUE;
273 }
274 
275 static gboolean
gst_inter_audio_src_start(GstBaseSrc * src)276 gst_inter_audio_src_start (GstBaseSrc * src)
277 {
278   GstInterAudioSrc *interaudiosrc = GST_INTER_AUDIO_SRC (src);
279 
280   GST_DEBUG_OBJECT (interaudiosrc, "start");
281 
282   interaudiosrc->surface = gst_inter_surface_get (interaudiosrc->channel);
283   interaudiosrc->timestamp_offset = 0;
284   interaudiosrc->n_samples = 0;
285 
286   g_mutex_lock (&interaudiosrc->surface->mutex);
287   interaudiosrc->surface->audio_buffer_time = interaudiosrc->buffer_time;
288   interaudiosrc->surface->audio_latency_time = interaudiosrc->latency_time;
289   interaudiosrc->surface->audio_period_time = interaudiosrc->period_time;
290   g_mutex_unlock (&interaudiosrc->surface->mutex);
291 
292   return TRUE;
293 }
294 
295 static gboolean
gst_inter_audio_src_stop(GstBaseSrc * src)296 gst_inter_audio_src_stop (GstBaseSrc * src)
297 {
298   GstInterAudioSrc *interaudiosrc = GST_INTER_AUDIO_SRC (src);
299 
300   GST_DEBUG_OBJECT (interaudiosrc, "stop");
301 
302   gst_inter_surface_unref (interaudiosrc->surface);
303   interaudiosrc->surface = NULL;
304 
305   return TRUE;
306 }
307 
308 static void
gst_inter_audio_src_get_times(GstBaseSrc * src,GstBuffer * buffer,GstClockTime * start,GstClockTime * end)309 gst_inter_audio_src_get_times (GstBaseSrc * src, GstBuffer * buffer,
310     GstClockTime * start, GstClockTime * end)
311 {
312   GstInterAudioSrc *interaudiosrc = GST_INTER_AUDIO_SRC (src);
313 
314   GST_DEBUG_OBJECT (src, "get_times");
315 
316   /* for live sources, sync on the timestamp of the buffer */
317   if (gst_base_src_is_live (src)) {
318     if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) {
319       *start = GST_BUFFER_TIMESTAMP (buffer);
320       if (GST_BUFFER_DURATION_IS_VALID (buffer)) {
321         *end = *start + GST_BUFFER_DURATION (buffer);
322       } else {
323         if (interaudiosrc->info.rate > 0) {
324           *end = *start +
325               gst_util_uint64_scale_int (gst_buffer_get_size (buffer),
326               GST_SECOND, interaudiosrc->info.rate * interaudiosrc->info.bpf);
327         }
328       }
329     }
330   }
331 }
332 
333 static GstFlowReturn
gst_inter_audio_src_create(GstBaseSrc * src,guint64 offset,guint size,GstBuffer ** buf)334 gst_inter_audio_src_create (GstBaseSrc * src, guint64 offset, guint size,
335     GstBuffer ** buf)
336 {
337   GstInterAudioSrc *interaudiosrc = GST_INTER_AUDIO_SRC (src);
338   GstCaps *caps;
339   GstBuffer *buffer;
340   guint n, bpf;
341   guint64 period_time;
342   guint64 period_samples;
343 
344   GST_DEBUG_OBJECT (interaudiosrc, "create");
345 
346   buffer = NULL;
347   caps = NULL;
348 
349   g_mutex_lock (&interaudiosrc->surface->mutex);
350   if (interaudiosrc->surface->audio_info.finfo) {
351     if (!gst_audio_info_is_equal (&interaudiosrc->surface->audio_info,
352             &interaudiosrc->info)) {
353       caps = gst_audio_info_to_caps (&interaudiosrc->surface->audio_info);
354       interaudiosrc->timestamp_offset +=
355           gst_util_uint64_scale (interaudiosrc->n_samples, GST_SECOND,
356           interaudiosrc->info.rate);
357       interaudiosrc->n_samples = 0;
358     }
359   }
360 
361   bpf = interaudiosrc->surface->audio_info.bpf;
362   period_time = interaudiosrc->surface->audio_period_time;
363   period_samples =
364       gst_util_uint64_scale (period_time, interaudiosrc->info.rate, GST_SECOND);
365 
366   if (bpf > 0)
367     n = gst_adapter_available (interaudiosrc->surface->audio_adapter) / bpf;
368   else
369     n = 0;
370 
371   if (n > period_samples)
372     n = period_samples;
373   if (n > 0) {
374     buffer = gst_adapter_take_buffer (interaudiosrc->surface->audio_adapter,
375         n * bpf);
376   } else {
377     buffer = gst_buffer_new ();
378     GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_GAP);
379   }
380   g_mutex_unlock (&interaudiosrc->surface->mutex);
381 
382   if (caps) {
383     gboolean ret = gst_base_src_set_caps (src, caps);
384     gst_caps_unref (caps);
385     if (!ret) {
386       GST_ERROR_OBJECT (src, "Failed to set caps %" GST_PTR_FORMAT, caps);
387       if (buffer)
388         gst_buffer_unref (buffer);
389       return GST_FLOW_NOT_NEGOTIATED;
390     }
391   }
392 
393   buffer = gst_buffer_make_writable (buffer);
394 
395   bpf = interaudiosrc->info.bpf;
396   if (n < period_samples) {
397     GstMapInfo map;
398     GstMemory *mem;
399 
400     GST_DEBUG_OBJECT (interaudiosrc,
401         "creating %" G_GUINT64_FORMAT " samples of silence",
402         period_samples - n);
403     mem = gst_allocator_alloc (NULL, (period_samples - n) * bpf, NULL);
404     if (gst_memory_map (mem, &map, GST_MAP_WRITE)) {
405       gst_audio_format_fill_silence (interaudiosrc->info.finfo, map.data,
406           map.size);
407       gst_memory_unmap (mem, &map);
408     }
409     gst_buffer_prepend_memory (buffer, mem);
410   }
411   n = period_samples;
412 
413   GST_BUFFER_OFFSET (buffer) = interaudiosrc->n_samples;
414   GST_BUFFER_OFFSET_END (buffer) = interaudiosrc->n_samples + n;
415   GST_BUFFER_DTS (buffer) = GST_CLOCK_TIME_NONE;
416   GST_BUFFER_PTS (buffer) = interaudiosrc->timestamp_offset +
417       gst_util_uint64_scale (interaudiosrc->n_samples, GST_SECOND,
418       interaudiosrc->info.rate);
419   GST_DEBUG_OBJECT (interaudiosrc, "create ts %" GST_TIME_FORMAT,
420       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
421   GST_BUFFER_DURATION (buffer) = interaudiosrc->timestamp_offset +
422       gst_util_uint64_scale (interaudiosrc->n_samples + n, GST_SECOND,
423       interaudiosrc->info.rate) - GST_BUFFER_TIMESTAMP (buffer);
424   GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DISCONT);
425   if (interaudiosrc->n_samples == 0) {
426     GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
427   }
428   interaudiosrc->n_samples += n;
429 
430   *buf = buffer;
431 
432   return GST_FLOW_OK;
433 }
434 
435 static gboolean
gst_inter_audio_src_query(GstBaseSrc * src,GstQuery * query)436 gst_inter_audio_src_query (GstBaseSrc * src, GstQuery * query)
437 {
438   GstInterAudioSrc *interaudiosrc = GST_INTER_AUDIO_SRC (src);
439   gboolean ret;
440 
441   GST_DEBUG_OBJECT (src, "query");
442 
443   switch (GST_QUERY_TYPE (query)) {
444     case GST_QUERY_LATENCY:{
445       GstClockTime min_latency, max_latency;
446 
447       min_latency = interaudiosrc->latency_time;
448       max_latency = interaudiosrc->buffer_time;
449 
450       GST_DEBUG_OBJECT (src,
451           "report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
452           GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
453 
454       gst_query_set_latency (query,
455           gst_base_src_is_live (src), min_latency, max_latency);
456 
457       ret = TRUE;
458       break;
459     }
460     default:
461       ret = GST_BASE_SRC_CLASS (gst_inter_audio_src_parent_class)->query (src,
462           query);
463       break;
464   }
465 
466   return ret;
467 }
468 
469 static GstCaps *
gst_inter_audio_src_fixate(GstBaseSrc * src,GstCaps * caps)470 gst_inter_audio_src_fixate (GstBaseSrc * src, GstCaps * caps)
471 {
472   GstStructure *structure;
473 
474   GST_DEBUG_OBJECT (src, "fixate");
475 
476   caps = gst_caps_make_writable (caps);
477   caps = gst_caps_truncate (caps);
478 
479   structure = gst_caps_get_structure (caps, 0);
480 
481   gst_structure_fixate_field_string (structure, "format", GST_AUDIO_NE (S16));
482   gst_structure_fixate_field_nearest_int (structure, "channels", 2);
483   gst_structure_fixate_field_nearest_int (structure, "rate", 48000);
484   gst_structure_fixate_field_string (structure, "layout", "interleaved");
485 
486   return caps;
487 }
488