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