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