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