1 /*
2 * GStreamer pulseaudio plugin
3 *
4 * Copyright (c) 2004-2008 Lennart Poettering
5 *
6 * gst-pulse is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation; either version 2.1 of the
9 * License, or (at your option) any later version.
10 *
11 * gst-pulse is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with gst-pulse; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
19 * USA.
20 */
21
22 /**
23 * SECTION:element-pulsesrc
24 * @title: pulsesrc
25 * @see_also: pulsesink
26 *
27 * This element captures audio from a
28 * [PulseAudio sound server](http://www.pulseaudio.org).
29 *
30 * ## Example pipelines
31 * |[
32 * gst-launch-1.0 -v pulsesrc ! audioconvert ! vorbisenc ! oggmux ! filesink location=alsasrc.ogg
33 * ]| Record from a sound card using pulseaudio and encode to Ogg/Vorbis.
34 *
35 */
36
37 #ifdef HAVE_CONFIG_H
38 #include "config.h"
39 #endif
40
41 #include <string.h>
42 #include <stdio.h>
43
44 #include <gst/base/gstbasesrc.h>
45 #include <gst/gsttaglist.h>
46 #include <gst/audio/audio.h>
47
48 #include "gstpulseelements.h"
49 #include "pulsesrc.h"
50 #include "pulseutil.h"
51
52 GST_DEBUG_CATEGORY_EXTERN (pulse_debug);
53 #define GST_CAT_DEFAULT pulse_debug
54
55 #define DEFAULT_SERVER NULL
56 #define DEFAULT_DEVICE NULL
57 #define DEFAULT_CURRENT_DEVICE NULL
58 #define DEFAULT_DEVICE_NAME NULL
59
60 #define DEFAULT_VOLUME 1.0
61 #define DEFAULT_MUTE FALSE
62 #define MAX_VOLUME 10.0
63
64 /* See the pulsesink code for notes on how we interact with the PA mainloop
65 * thread. */
66
67 enum
68 {
69 PROP_0,
70 PROP_SERVER,
71 PROP_DEVICE,
72 PROP_DEVICE_NAME,
73 PROP_CURRENT_DEVICE,
74 PROP_CLIENT_NAME,
75 PROP_STREAM_PROPERTIES,
76 PROP_SOURCE_OUTPUT_INDEX,
77 PROP_VOLUME,
78 PROP_MUTE,
79 PROP_LAST
80 };
81
82 static void gst_pulsesrc_destroy_stream (GstPulseSrc * pulsesrc);
83 static void gst_pulsesrc_destroy_context (GstPulseSrc * pulsesrc);
84
85 static void gst_pulsesrc_set_property (GObject * object, guint prop_id,
86 const GValue * value, GParamSpec * pspec);
87 static void gst_pulsesrc_get_property (GObject * object, guint prop_id,
88 GValue * value, GParamSpec * pspec);
89 static void gst_pulsesrc_finalize (GObject * object);
90
91 static gboolean gst_pulsesrc_set_corked (GstPulseSrc * psrc, gboolean corked,
92 gboolean wait);
93 static gboolean gst_pulsesrc_open (GstAudioSrc * asrc);
94
95 static gboolean gst_pulsesrc_close (GstAudioSrc * asrc);
96
97 static gboolean gst_pulsesrc_prepare (GstAudioSrc * asrc,
98 GstAudioRingBufferSpec * spec);
99
100 static gboolean gst_pulsesrc_unprepare (GstAudioSrc * asrc);
101
102 static guint gst_pulsesrc_read (GstAudioSrc * asrc, gpointer data,
103 guint length, GstClockTime * timestamp);
104 static guint gst_pulsesrc_delay (GstAudioSrc * asrc);
105
106 static void gst_pulsesrc_reset (GstAudioSrc * src);
107
108 static gboolean gst_pulsesrc_negotiate (GstBaseSrc * basesrc);
109 static gboolean gst_pulsesrc_event (GstBaseSrc * basesrc, GstEvent * event);
110
111 static GstStateChangeReturn gst_pulsesrc_change_state (GstElement *
112 element, GstStateChange transition);
113
114 static GstClockTime gst_pulsesrc_get_time (GstClock * clock, GstPulseSrc * src);
115
116 #define gst_pulsesrc_parent_class parent_class
117 G_DEFINE_TYPE_WITH_CODE (GstPulseSrc, gst_pulsesrc, GST_TYPE_AUDIO_SRC,
118 G_IMPLEMENT_INTERFACE (GST_TYPE_STREAM_VOLUME, NULL));
119 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (pulsesrc, "pulsesrc",
120 GST_RANK_PRIMARY + 10, GST_TYPE_PULSESRC, pulse_element_init (plugin));
121
122 static void
gst_pulsesrc_class_init(GstPulseSrcClass * klass)123 gst_pulsesrc_class_init (GstPulseSrcClass * klass)
124 {
125 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
126 GstAudioSrcClass *gstaudiosrc_class = GST_AUDIO_SRC_CLASS (klass);
127 GstBaseSrcClass *gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
128 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
129 GstCaps *caps;
130 gchar *clientname;
131
132 gobject_class->finalize = gst_pulsesrc_finalize;
133 gobject_class->set_property = gst_pulsesrc_set_property;
134 gobject_class->get_property = gst_pulsesrc_get_property;
135
136 gstelement_class->change_state =
137 GST_DEBUG_FUNCPTR (gst_pulsesrc_change_state);
138
139 gstbasesrc_class->event = GST_DEBUG_FUNCPTR (gst_pulsesrc_event);
140 gstbasesrc_class->negotiate = GST_DEBUG_FUNCPTR (gst_pulsesrc_negotiate);
141
142 gstaudiosrc_class->open = GST_DEBUG_FUNCPTR (gst_pulsesrc_open);
143 gstaudiosrc_class->close = GST_DEBUG_FUNCPTR (gst_pulsesrc_close);
144 gstaudiosrc_class->prepare = GST_DEBUG_FUNCPTR (gst_pulsesrc_prepare);
145 gstaudiosrc_class->unprepare = GST_DEBUG_FUNCPTR (gst_pulsesrc_unprepare);
146 gstaudiosrc_class->read = GST_DEBUG_FUNCPTR (gst_pulsesrc_read);
147 gstaudiosrc_class->delay = GST_DEBUG_FUNCPTR (gst_pulsesrc_delay);
148 gstaudiosrc_class->reset = GST_DEBUG_FUNCPTR (gst_pulsesrc_reset);
149
150 /* Overwrite GObject fields */
151 g_object_class_install_property (gobject_class,
152 PROP_SERVER,
153 g_param_spec_string ("server", "Server",
154 "The PulseAudio server to connect to", DEFAULT_SERVER,
155 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
156
157 g_object_class_install_property (gobject_class, PROP_DEVICE,
158 g_param_spec_string ("device", "Device",
159 "The PulseAudio source device to connect to", DEFAULT_DEVICE,
160 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
161
162 g_object_class_install_property (gobject_class, PROP_CURRENT_DEVICE,
163 g_param_spec_string ("current-device", "Current Device",
164 "The current PulseAudio source device", DEFAULT_CURRENT_DEVICE,
165 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
166
167 g_object_class_install_property (gobject_class,
168 PROP_DEVICE_NAME,
169 g_param_spec_string ("device-name", "Device name",
170 "Human-readable name of the sound device", DEFAULT_DEVICE_NAME,
171 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
172
173 clientname = gst_pulse_client_name ();
174 /**
175 * GstPulseSrc:client-name
176 *
177 * The PulseAudio client name to use.
178 */
179 g_object_class_install_property (gobject_class,
180 PROP_CLIENT_NAME,
181 g_param_spec_string ("client-name", "Client Name",
182 "The PulseAudio client_name_to_use", clientname,
183 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
184 GST_PARAM_MUTABLE_READY));
185 g_free (clientname);
186
187 /**
188 * GstPulseSrc:stream-properties:
189 *
190 * List of pulseaudio stream properties. A list of defined properties can be
191 * found in the [pulseaudio api docs](http://0pointer.de/lennart/projects/pulseaudio/doxygen/proplist_8h.html).
192 *
193 * Below is an example for registering as a music application to pulseaudio.
194 * |[
195 * GstStructure *props;
196 *
197 * props = gst_structure_from_string ("props,media.role=music", NULL);
198 * g_object_set (pulse, "stream-properties", props, NULL);
199 * gst_structure_free (props);
200 * ]|
201 */
202 g_object_class_install_property (gobject_class,
203 PROP_STREAM_PROPERTIES,
204 g_param_spec_boxed ("stream-properties", "stream properties",
205 "list of pulseaudio stream properties",
206 GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
207 /**
208 * GstPulseSrc:source-output-index:
209 *
210 * The index of the PulseAudio source output corresponding to this element.
211 */
212 g_object_class_install_property (gobject_class,
213 PROP_SOURCE_OUTPUT_INDEX,
214 g_param_spec_uint ("source-output-index", "source output index",
215 "The index of the PulseAudio source output corresponding to this "
216 "record stream", 0, G_MAXUINT, PA_INVALID_INDEX,
217 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
218
219 gst_element_class_set_static_metadata (gstelement_class,
220 "PulseAudio Audio Source",
221 "Source/Audio",
222 "Captures audio from a PulseAudio server", "Lennart Poettering");
223
224 caps = gst_pulse_fix_pcm_caps (gst_caps_from_string (_PULSE_CAPS_PCM));
225 gst_element_class_add_pad_template (gstelement_class,
226 gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, caps));
227 gst_caps_unref (caps);
228
229 /**
230 * GstPulseSrc:volume:
231 *
232 * The volume of the record stream.
233 */
234 g_object_class_install_property (gobject_class,
235 PROP_VOLUME, g_param_spec_double ("volume", "Volume",
236 "Linear volume of this stream, 1.0=100%",
237 0.0, MAX_VOLUME, DEFAULT_VOLUME,
238 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
239
240 /**
241 * GstPulseSrc:mute:
242 *
243 * Whether the stream is muted or not.
244 */
245 g_object_class_install_property (gobject_class,
246 PROP_MUTE, g_param_spec_boolean ("mute", "Mute",
247 "Mute state of this stream",
248 DEFAULT_MUTE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
249 }
250
251 static void
gst_pulsesrc_init(GstPulseSrc * pulsesrc)252 gst_pulsesrc_init (GstPulseSrc * pulsesrc)
253 {
254 pulsesrc->server = NULL;
255 pulsesrc->device = NULL;
256 pulsesrc->client_name = gst_pulse_client_name ();
257 pulsesrc->device_description = NULL;
258
259 pulsesrc->context = NULL;
260 pulsesrc->stream = NULL;
261 pulsesrc->stream_connected = FALSE;
262 pulsesrc->source_output_idx = PA_INVALID_INDEX;
263
264 pulsesrc->read_buffer = NULL;
265 pulsesrc->read_buffer_length = 0;
266
267 pa_sample_spec_init (&pulsesrc->sample_spec);
268
269 pulsesrc->operation_success = FALSE;
270 pulsesrc->paused = TRUE;
271 pulsesrc->in_read = FALSE;
272
273 pulsesrc->volume = DEFAULT_VOLUME;
274 pulsesrc->volume_set = FALSE;
275
276 pulsesrc->mute = DEFAULT_MUTE;
277 pulsesrc->mute_set = FALSE;
278
279 pulsesrc->notify = 0;
280
281 pulsesrc->properties = NULL;
282 pulsesrc->proplist = NULL;
283
284 /* this should be the default but it isn't yet */
285 gst_audio_base_src_set_slave_method (GST_AUDIO_BASE_SRC (pulsesrc),
286 GST_AUDIO_BASE_SRC_SLAVE_SKEW);
287
288 /* override with a custom clock */
289 if (GST_AUDIO_BASE_SRC (pulsesrc)->clock)
290 gst_object_unref (GST_AUDIO_BASE_SRC (pulsesrc)->clock);
291
292 GST_AUDIO_BASE_SRC (pulsesrc)->clock =
293 gst_audio_clock_new ("GstPulseSrcClock",
294 (GstAudioClockGetTimeFunc) gst_pulsesrc_get_time, pulsesrc, NULL);
295 }
296
297 static void
gst_pulsesrc_destroy_stream(GstPulseSrc * pulsesrc)298 gst_pulsesrc_destroy_stream (GstPulseSrc * pulsesrc)
299 {
300 if (pulsesrc->stream) {
301 pa_stream_disconnect (pulsesrc->stream);
302 pa_stream_unref (pulsesrc->stream);
303 pulsesrc->stream = NULL;
304 pulsesrc->stream_connected = FALSE;
305 pulsesrc->source_output_idx = PA_INVALID_INDEX;
306 g_object_notify (G_OBJECT (pulsesrc), "source-output-index");
307 }
308
309 g_free (pulsesrc->device_description);
310 pulsesrc->device_description = NULL;
311 }
312
313 static void
gst_pulsesrc_destroy_context(GstPulseSrc * pulsesrc)314 gst_pulsesrc_destroy_context (GstPulseSrc * pulsesrc)
315 {
316
317 gst_pulsesrc_destroy_stream (pulsesrc);
318
319 if (pulsesrc->context) {
320 pa_context_disconnect (pulsesrc->context);
321
322 /* Make sure we don't get any further callbacks */
323 pa_context_set_state_callback (pulsesrc->context, NULL, NULL);
324 pa_context_set_subscribe_callback (pulsesrc->context, NULL, NULL);
325
326 pa_context_unref (pulsesrc->context);
327
328 pulsesrc->context = NULL;
329 }
330 }
331
332 static void
gst_pulsesrc_finalize(GObject * object)333 gst_pulsesrc_finalize (GObject * object)
334 {
335 GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (object);
336
337 g_free (pulsesrc->server);
338 g_free (pulsesrc->device);
339 g_free (pulsesrc->client_name);
340 g_free (pulsesrc->current_source_name);
341
342 if (pulsesrc->properties)
343 gst_structure_free (pulsesrc->properties);
344 if (pulsesrc->proplist)
345 pa_proplist_free (pulsesrc->proplist);
346
347 G_OBJECT_CLASS (parent_class)->finalize (object);
348 }
349
350 #define CONTEXT_OK(c) ((c) && PA_CONTEXT_IS_GOOD (pa_context_get_state ((c))))
351 #define STREAM_OK(s) ((s) && PA_STREAM_IS_GOOD (pa_stream_get_state ((s))))
352
353 static gboolean
gst_pulsesrc_is_dead(GstPulseSrc * pulsesrc,gboolean check_stream)354 gst_pulsesrc_is_dead (GstPulseSrc * pulsesrc, gboolean check_stream)
355 {
356 if (!pulsesrc->stream_connected)
357 return TRUE;
358
359 if (!CONTEXT_OK (pulsesrc->context))
360 goto error;
361
362 if (check_stream && !STREAM_OK (pulsesrc->stream))
363 goto error;
364
365 return FALSE;
366
367 error:
368 {
369 const gchar *err_str = pulsesrc->context ?
370 pa_strerror (pa_context_errno (pulsesrc->context)) : NULL;
371 GST_ELEMENT_ERROR ((pulsesrc), RESOURCE, FAILED, ("Disconnected: %s",
372 err_str), (NULL));
373 return TRUE;
374 }
375 }
376
377 static void
gst_pulsesrc_source_info_cb(pa_context * c,const pa_source_info * i,int eol,void * userdata)378 gst_pulsesrc_source_info_cb (pa_context * c, const pa_source_info * i, int eol,
379 void *userdata)
380 {
381 GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (userdata);
382
383 if (!i)
384 goto done;
385
386 g_free (pulsesrc->device_description);
387 pulsesrc->device_description = g_strdup (i->description);
388
389 done:
390 pa_threaded_mainloop_signal (pulsesrc->mainloop, 0);
391 }
392
393 static gchar *
gst_pulsesrc_device_description(GstPulseSrc * pulsesrc)394 gst_pulsesrc_device_description (GstPulseSrc * pulsesrc)
395 {
396 pa_operation *o = NULL;
397 gchar *t;
398
399 if (!pulsesrc->mainloop)
400 goto no_mainloop;
401
402 pa_threaded_mainloop_lock (pulsesrc->mainloop);
403
404 if (!(o = pa_context_get_source_info_by_name (pulsesrc->context,
405 pulsesrc->device, gst_pulsesrc_source_info_cb, pulsesrc))) {
406
407 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
408 ("pa_stream_get_source_info() failed: %s",
409 pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
410 goto unlock;
411 }
412
413 while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
414
415 if (gst_pulsesrc_is_dead (pulsesrc, FALSE))
416 goto unlock;
417
418 pa_threaded_mainloop_wait (pulsesrc->mainloop);
419 }
420
421 unlock:
422
423 if (o)
424 pa_operation_unref (o);
425
426 t = g_strdup (pulsesrc->device_description);
427
428 pa_threaded_mainloop_unlock (pulsesrc->mainloop);
429
430 return t;
431
432 no_mainloop:
433 {
434 GST_DEBUG_OBJECT (pulsesrc, "have no mainloop");
435 return NULL;
436 }
437 }
438
439 static void
gst_pulsesrc_source_output_info_cb(pa_context * c,const pa_source_output_info * i,int eol,void * userdata)440 gst_pulsesrc_source_output_info_cb (pa_context * c,
441 const pa_source_output_info * i, int eol, void *userdata)
442 {
443 GstPulseSrc *psrc;
444
445 psrc = GST_PULSESRC_CAST (userdata);
446
447 if (!i)
448 goto done;
449
450 /* If the index doesn't match our current stream,
451 * it implies we just recreated the stream (caps change)
452 */
453 if (i->index == psrc->source_output_idx) {
454 psrc->volume = pa_sw_volume_to_linear (pa_cvolume_max (&i->volume));
455 psrc->mute = i->mute;
456 psrc->current_source_idx = i->source;
457
458 if (G_UNLIKELY (psrc->volume > MAX_VOLUME)) {
459 GST_WARNING_OBJECT (psrc, "Clipped volume from %f to %f",
460 psrc->volume, MAX_VOLUME);
461 psrc->volume = MAX_VOLUME;
462 }
463 }
464
465 done:
466 pa_threaded_mainloop_signal (psrc->mainloop, 0);
467 }
468
469 static void
gst_pulsesrc_get_source_output_info(GstPulseSrc * pulsesrc,gdouble * volume,gboolean * mute)470 gst_pulsesrc_get_source_output_info (GstPulseSrc * pulsesrc, gdouble * volume,
471 gboolean * mute)
472 {
473 pa_operation *o = NULL;
474
475 if (!pulsesrc->mainloop)
476 goto no_mainloop;
477
478 if (pulsesrc->source_output_idx == PA_INVALID_INDEX)
479 goto no_index;
480
481 pa_threaded_mainloop_lock (pulsesrc->mainloop);
482
483 if (!(o = pa_context_get_source_output_info (pulsesrc->context,
484 pulsesrc->source_output_idx, gst_pulsesrc_source_output_info_cb,
485 pulsesrc)))
486 goto info_failed;
487
488 while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
489 pa_threaded_mainloop_wait (pulsesrc->mainloop);
490 if (gst_pulsesrc_is_dead (pulsesrc, TRUE))
491 goto unlock;
492 }
493
494 unlock:
495
496 if (volume)
497 *volume = pulsesrc->volume;
498 if (mute)
499 *mute = pulsesrc->mute;
500
501 if (o)
502 pa_operation_unref (o);
503
504 pa_threaded_mainloop_unlock (pulsesrc->mainloop);
505
506 return;
507
508 /* ERRORS */
509 no_mainloop:
510 {
511 GST_DEBUG_OBJECT (pulsesrc, "we have no mainloop");
512 if (volume)
513 *volume = pulsesrc->volume;
514 if (mute)
515 *mute = pulsesrc->mute;
516 return;
517 }
518 no_index:
519 {
520 GST_DEBUG_OBJECT (pulsesrc, "we don't have a stream index");
521 if (volume)
522 *volume = pulsesrc->volume;
523 if (mute)
524 *mute = pulsesrc->mute;
525 return;
526 }
527 info_failed:
528 {
529 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
530 ("pa_context_get_source_output_info() failed: %s",
531 pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
532 goto unlock;
533 }
534 }
535
536 static void
gst_pulsesrc_current_source_info_cb(pa_context * c,const pa_source_info * i,int eol,void * userdata)537 gst_pulsesrc_current_source_info_cb (pa_context * c, const pa_source_info * i,
538 int eol, void *userdata)
539 {
540 GstPulseSrc *psrc;
541
542 psrc = GST_PULSESRC_CAST (userdata);
543
544 if (!i)
545 goto done;
546
547 /* If the index doesn't match our current stream,
548 * it implies we just recreated the stream (caps change)
549 */
550 if (i->index == psrc->current_source_idx) {
551 g_free (psrc->current_source_name);
552 psrc->current_source_name = g_strdup (i->name);
553 }
554
555 done:
556 pa_threaded_mainloop_signal (psrc->mainloop, 0);
557 }
558
559 static gchar *
gst_pulsesrc_get_current_device(GstPulseSrc * pulsesrc)560 gst_pulsesrc_get_current_device (GstPulseSrc * pulsesrc)
561 {
562 pa_operation *o = NULL;
563 gchar *current_src;
564
565 if (!pulsesrc->mainloop)
566 goto no_mainloop;
567
568 if (pulsesrc->source_output_idx == PA_INVALID_INDEX)
569 goto no_index;
570
571 gst_pulsesrc_get_source_output_info (pulsesrc, NULL, NULL);
572
573 pa_threaded_mainloop_lock (pulsesrc->mainloop);
574
575
576 if (!(o = pa_context_get_source_info_by_index (pulsesrc->context,
577 pulsesrc->current_source_idx, gst_pulsesrc_current_source_info_cb,
578 pulsesrc)))
579 goto info_failed;
580
581 while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
582 pa_threaded_mainloop_wait (pulsesrc->mainloop);
583 if (gst_pulsesrc_is_dead (pulsesrc, TRUE))
584 goto unlock;
585 }
586
587 unlock:
588
589 current_src = g_strdup (pulsesrc->current_source_name);
590
591 if (o)
592 pa_operation_unref (o);
593
594 pa_threaded_mainloop_unlock (pulsesrc->mainloop);
595
596 return current_src;
597
598 /* ERRORS */
599 no_mainloop:
600 {
601 GST_DEBUG_OBJECT (pulsesrc, "we have no mainloop");
602 return NULL;
603 }
604 no_index:
605 {
606 GST_DEBUG_OBJECT (pulsesrc, "we don't have a stream index");
607 return NULL;
608 }
609 info_failed:
610 {
611 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
612 ("pa_context_get_source_output_info() failed: %s",
613 pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
614 goto unlock;
615 }
616 }
617
618 static void
gst_pulsesrc_set_stream_volume(GstPulseSrc * pulsesrc,gdouble volume)619 gst_pulsesrc_set_stream_volume (GstPulseSrc * pulsesrc, gdouble volume)
620 {
621 pa_cvolume v;
622 pa_operation *o = NULL;
623
624 if (!pulsesrc->mainloop)
625 goto no_mainloop;
626
627 if (pulsesrc->source_output_idx == PA_INVALID_INDEX)
628 goto no_index;
629
630 pa_threaded_mainloop_lock (pulsesrc->mainloop);
631
632 GST_DEBUG_OBJECT (pulsesrc, "setting volume to %f", volume);
633
634 gst_pulse_cvolume_from_linear (&v, pulsesrc->sample_spec.channels, volume);
635
636 if (!(o = pa_context_set_source_output_volume (pulsesrc->context,
637 pulsesrc->source_output_idx, &v, NULL, NULL)))
638 goto volume_failed;
639
640 /* We don't really care about the result of this call */
641 unlock:
642
643 if (o)
644 pa_operation_unref (o);
645
646 pa_threaded_mainloop_unlock (pulsesrc->mainloop);
647
648 return;
649
650 /* ERRORS */
651 no_mainloop:
652 {
653 pulsesrc->volume = volume;
654 pulsesrc->volume_set = TRUE;
655 GST_DEBUG_OBJECT (pulsesrc, "we have no mainloop");
656 return;
657 }
658 no_index:
659 {
660 pulsesrc->volume = volume;
661 pulsesrc->volume_set = TRUE;
662 GST_DEBUG_OBJECT (pulsesrc, "we don't have a stream index");
663 return;
664 }
665 volume_failed:
666 {
667 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
668 ("pa_stream_set_source_output_volume() failed: %s",
669 pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
670 goto unlock;
671 }
672 }
673
674 static void
gst_pulsesrc_set_stream_mute(GstPulseSrc * pulsesrc,gboolean mute)675 gst_pulsesrc_set_stream_mute (GstPulseSrc * pulsesrc, gboolean mute)
676 {
677 pa_operation *o = NULL;
678
679 if (!pulsesrc->mainloop)
680 goto no_mainloop;
681
682 if (pulsesrc->source_output_idx == PA_INVALID_INDEX)
683 goto no_index;
684
685 pa_threaded_mainloop_lock (pulsesrc->mainloop);
686
687 GST_DEBUG_OBJECT (pulsesrc, "setting mute state to %d", mute);
688
689 if (!(o = pa_context_set_source_output_mute (pulsesrc->context,
690 pulsesrc->source_output_idx, mute, NULL, NULL)))
691 goto mute_failed;
692
693 /* We don't really care about the result of this call */
694 unlock:
695
696 if (o)
697 pa_operation_unref (o);
698
699 pa_threaded_mainloop_unlock (pulsesrc->mainloop);
700
701 return;
702
703 /* ERRORS */
704 no_mainloop:
705 {
706 pulsesrc->mute = mute;
707 pulsesrc->mute_set = TRUE;
708 GST_DEBUG_OBJECT (pulsesrc, "we have no mainloop");
709 return;
710 }
711 no_index:
712 {
713 pulsesrc->mute = mute;
714 pulsesrc->mute_set = TRUE;
715 GST_DEBUG_OBJECT (pulsesrc, "we don't have a stream index");
716 return;
717 }
718 mute_failed:
719 {
720 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
721 ("pa_stream_set_source_output_mute() failed: %s",
722 pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
723 goto unlock;
724 }
725 }
726
727 static void
gst_pulsesrc_set_stream_device(GstPulseSrc * pulsesrc,const gchar * device)728 gst_pulsesrc_set_stream_device (GstPulseSrc * pulsesrc, const gchar * device)
729 {
730 pa_operation *o = NULL;
731
732 if (!pulsesrc->mainloop)
733 goto no_mainloop;
734
735 if (pulsesrc->source_output_idx == PA_INVALID_INDEX)
736 goto no_index;
737
738 pa_threaded_mainloop_lock (pulsesrc->mainloop);
739
740 GST_DEBUG_OBJECT (pulsesrc, "setting stream device to %s", device);
741
742 if (!(o = pa_context_move_source_output_by_name (pulsesrc->context,
743 pulsesrc->source_output_idx, device, NULL, NULL)))
744 goto move_failed;
745
746 unlock:
747
748 if (o)
749 pa_operation_unref (o);
750
751 pa_threaded_mainloop_unlock (pulsesrc->mainloop);
752
753 return;
754
755 /* ERRORS */
756 no_mainloop:
757 {
758 GST_DEBUG_OBJECT (pulsesrc, "we have no mainloop");
759 return;
760 }
761 no_index:
762 {
763 GST_DEBUG_OBJECT (pulsesrc, "we don't have a stream index");
764 return;
765 }
766 move_failed:
767 {
768 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
769 ("pa_context_move_source_output_by_name(%s) failed: %s",
770 device, pa_strerror (pa_context_errno (pulsesrc->context))),
771 (NULL));
772 goto unlock;
773 }
774 }
775
776 static void
gst_pulsesrc_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)777 gst_pulsesrc_set_property (GObject * object,
778 guint prop_id, const GValue * value, GParamSpec * pspec)
779 {
780
781 GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (object);
782
783 switch (prop_id) {
784 case PROP_SERVER:
785 g_free (pulsesrc->server);
786 pulsesrc->server = g_value_dup_string (value);
787 break;
788 case PROP_DEVICE:
789 g_free (pulsesrc->device);
790 pulsesrc->device = g_value_dup_string (value);
791 gst_pulsesrc_set_stream_device (pulsesrc, pulsesrc->device);
792 break;
793 case PROP_CLIENT_NAME:
794 g_free (pulsesrc->client_name);
795 if (!g_value_get_string (value)) {
796 GST_WARNING_OBJECT (pulsesrc,
797 "Empty PulseAudio client name not allowed. Resetting to default value");
798 pulsesrc->client_name = gst_pulse_client_name ();
799 } else
800 pulsesrc->client_name = g_value_dup_string (value);
801 break;
802 case PROP_STREAM_PROPERTIES:
803 if (pulsesrc->properties)
804 gst_structure_free (pulsesrc->properties);
805 pulsesrc->properties =
806 gst_structure_copy (gst_value_get_structure (value));
807 if (pulsesrc->proplist)
808 pa_proplist_free (pulsesrc->proplist);
809 pulsesrc->proplist = gst_pulse_make_proplist (pulsesrc->properties);
810 break;
811 case PROP_VOLUME:
812 gst_pulsesrc_set_stream_volume (pulsesrc, g_value_get_double (value));
813 break;
814 case PROP_MUTE:
815 gst_pulsesrc_set_stream_mute (pulsesrc, g_value_get_boolean (value));
816 break;
817 default:
818 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
819 break;
820 }
821 }
822
823 static void
gst_pulsesrc_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)824 gst_pulsesrc_get_property (GObject * object,
825 guint prop_id, GValue * value, GParamSpec * pspec)
826 {
827
828 GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (object);
829
830 switch (prop_id) {
831 case PROP_SERVER:
832 g_value_set_string (value, pulsesrc->server);
833 break;
834 case PROP_DEVICE:
835 g_value_set_string (value, pulsesrc->device);
836 break;
837 case PROP_CURRENT_DEVICE:
838 {
839 gchar *current_device = gst_pulsesrc_get_current_device (pulsesrc);
840 if (current_device)
841 g_value_take_string (value, current_device);
842 else
843 g_value_set_string (value, "");
844 break;
845 }
846 case PROP_DEVICE_NAME:
847 g_value_take_string (value, gst_pulsesrc_device_description (pulsesrc));
848 break;
849 case PROP_CLIENT_NAME:
850 g_value_set_string (value, pulsesrc->client_name);
851 break;
852 case PROP_STREAM_PROPERTIES:
853 gst_value_set_structure (value, pulsesrc->properties);
854 break;
855 case PROP_SOURCE_OUTPUT_INDEX:
856 g_value_set_uint (value, pulsesrc->source_output_idx);
857 break;
858 case PROP_VOLUME:
859 {
860 gdouble volume;
861 gst_pulsesrc_get_source_output_info (pulsesrc, &volume, NULL);
862 g_value_set_double (value, volume);
863 break;
864 }
865 case PROP_MUTE:
866 {
867 gboolean mute;
868 gst_pulsesrc_get_source_output_info (pulsesrc, NULL, &mute);
869 g_value_set_boolean (value, mute);
870 break;
871 }
872 default:
873 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
874 break;
875 }
876 }
877
878 static void
gst_pulsesrc_context_state_cb(pa_context * c,void * userdata)879 gst_pulsesrc_context_state_cb (pa_context * c, void *userdata)
880 {
881 GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (userdata);
882
883 switch (pa_context_get_state (c)) {
884 case PA_CONTEXT_READY:
885 case PA_CONTEXT_TERMINATED:
886 case PA_CONTEXT_FAILED:
887 pa_threaded_mainloop_signal (pulsesrc->mainloop, 0);
888 break;
889
890 case PA_CONTEXT_UNCONNECTED:
891 case PA_CONTEXT_CONNECTING:
892 case PA_CONTEXT_AUTHORIZING:
893 case PA_CONTEXT_SETTING_NAME:
894 break;
895 }
896 }
897
898 static void
gst_pulsesrc_stream_state_cb(pa_stream * s,void * userdata)899 gst_pulsesrc_stream_state_cb (pa_stream * s, void *userdata)
900 {
901 GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (userdata);
902
903 switch (pa_stream_get_state (s)) {
904
905 case PA_STREAM_READY:
906 case PA_STREAM_FAILED:
907 case PA_STREAM_TERMINATED:
908 pa_threaded_mainloop_signal (pulsesrc->mainloop, 0);
909 break;
910
911 case PA_STREAM_UNCONNECTED:
912 case PA_STREAM_CREATING:
913 break;
914 }
915 }
916
917 static void
gst_pulsesrc_stream_request_cb(pa_stream * s,size_t length,void * userdata)918 gst_pulsesrc_stream_request_cb (pa_stream * s, size_t length, void *userdata)
919 {
920 GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (userdata);
921
922 GST_LOG_OBJECT (pulsesrc, "got request for length %" G_GSIZE_FORMAT, length);
923
924 if (pulsesrc->in_read) {
925 /* only signal when reading */
926 pa_threaded_mainloop_signal (pulsesrc->mainloop, 0);
927 }
928 }
929
930 static void
gst_pulsesrc_stream_latency_update_cb(pa_stream * s,void * userdata)931 gst_pulsesrc_stream_latency_update_cb (pa_stream * s, void *userdata)
932 {
933 const pa_timing_info *info;
934 pa_usec_t source_usec;
935
936 info = pa_stream_get_timing_info (s);
937
938 if (!info) {
939 GST_LOG_OBJECT (GST_PULSESRC_CAST (userdata),
940 "latency update (information unknown)");
941 return;
942 }
943 source_usec = info->configured_source_usec;
944
945 GST_LOG_OBJECT (GST_PULSESRC_CAST (userdata),
946 "latency_update, %" G_GUINT64_FORMAT ", %d:%" G_GINT64_FORMAT ", %d:%"
947 G_GUINT64_FORMAT ", %" G_GUINT64_FORMAT ", %" G_GUINT64_FORMAT,
948 GST_TIMEVAL_TO_TIME (info->timestamp), info->write_index_corrupt,
949 info->write_index, info->read_index_corrupt, info->read_index,
950 info->source_usec, source_usec);
951 }
952
953 static void
gst_pulsesrc_stream_underflow_cb(pa_stream * s,void * userdata)954 gst_pulsesrc_stream_underflow_cb (pa_stream * s, void *userdata)
955 {
956 GST_WARNING_OBJECT (GST_PULSESRC_CAST (userdata), "Got underflow");
957 }
958
959 static void
gst_pulsesrc_stream_overflow_cb(pa_stream * s,void * userdata)960 gst_pulsesrc_stream_overflow_cb (pa_stream * s, void *userdata)
961 {
962 GST_WARNING_OBJECT (GST_PULSESRC_CAST (userdata), "Got overflow");
963 }
964
965 static void
gst_pulsesrc_context_subscribe_cb(pa_context * c,pa_subscription_event_type_t t,uint32_t idx,void * userdata)966 gst_pulsesrc_context_subscribe_cb (pa_context * c,
967 pa_subscription_event_type_t t, uint32_t idx, void *userdata)
968 {
969 GstPulseSrc *psrc = GST_PULSESRC (userdata);
970
971 if (t != (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT | PA_SUBSCRIPTION_EVENT_CHANGE)
972 && t != (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT | PA_SUBSCRIPTION_EVENT_NEW))
973 return;
974
975 if (idx != psrc->source_output_idx)
976 return;
977
978 /* Actually this event is also triggered when other properties of the stream
979 * change that are unrelated to the volume. However it is probably cheaper to
980 * signal the change here and check for the volume when the GObject property
981 * is read instead of querying it always. */
982
983 /* inform streaming thread to notify */
984 g_atomic_int_compare_and_exchange (&psrc->notify, 0, 1);
985 }
986
987 static gboolean
gst_pulsesrc_open(GstAudioSrc * asrc)988 gst_pulsesrc_open (GstAudioSrc * asrc)
989 {
990 GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc);
991
992 pa_threaded_mainloop_lock (pulsesrc->mainloop);
993
994 g_assert (!pulsesrc->context);
995 g_assert (!pulsesrc->stream);
996
997 GST_DEBUG_OBJECT (pulsesrc, "opening device");
998
999 if (!(pulsesrc->context =
1000 pa_context_new (pa_threaded_mainloop_get_api (pulsesrc->mainloop),
1001 pulsesrc->client_name))) {
1002 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to create context"),
1003 (NULL));
1004 goto unlock_and_fail;
1005 }
1006
1007 pa_context_set_state_callback (pulsesrc->context,
1008 gst_pulsesrc_context_state_cb, pulsesrc);
1009 pa_context_set_subscribe_callback (pulsesrc->context,
1010 gst_pulsesrc_context_subscribe_cb, pulsesrc);
1011
1012 GST_DEBUG_OBJECT (pulsesrc, "connect to server %s",
1013 GST_STR_NULL (pulsesrc->server));
1014
1015 if (pa_context_connect (pulsesrc->context, pulsesrc->server, 0, NULL) < 0) {
1016 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to connect: %s",
1017 pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
1018 goto unlock_and_fail;
1019 }
1020
1021 for (;;) {
1022 pa_context_state_t state;
1023
1024 state = pa_context_get_state (pulsesrc->context);
1025
1026 if (!PA_CONTEXT_IS_GOOD (state)) {
1027 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to connect: %s",
1028 pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
1029 goto unlock_and_fail;
1030 }
1031
1032 if (state == PA_CONTEXT_READY)
1033 break;
1034
1035 /* Wait until the context is ready */
1036 pa_threaded_mainloop_wait (pulsesrc->mainloop);
1037 }
1038 GST_DEBUG_OBJECT (pulsesrc, "connected");
1039
1040 pa_threaded_mainloop_unlock (pulsesrc->mainloop);
1041
1042 return TRUE;
1043
1044 /* ERRORS */
1045 unlock_and_fail:
1046 {
1047 gst_pulsesrc_destroy_context (pulsesrc);
1048
1049 pa_threaded_mainloop_unlock (pulsesrc->mainloop);
1050
1051 return FALSE;
1052 }
1053 }
1054
1055 static gboolean
gst_pulsesrc_close(GstAudioSrc * asrc)1056 gst_pulsesrc_close (GstAudioSrc * asrc)
1057 {
1058 GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc);
1059
1060 pa_threaded_mainloop_lock (pulsesrc->mainloop);
1061 gst_pulsesrc_destroy_context (pulsesrc);
1062 pa_threaded_mainloop_unlock (pulsesrc->mainloop);
1063
1064 return TRUE;
1065 }
1066
1067 static gboolean
gst_pulsesrc_unprepare(GstAudioSrc * asrc)1068 gst_pulsesrc_unprepare (GstAudioSrc * asrc)
1069 {
1070 GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc);
1071
1072 pa_threaded_mainloop_lock (pulsesrc->mainloop);
1073 gst_pulsesrc_destroy_stream (pulsesrc);
1074
1075 pa_threaded_mainloop_unlock (pulsesrc->mainloop);
1076
1077 pulsesrc->read_buffer = NULL;
1078 pulsesrc->read_buffer_length = 0;
1079
1080 return TRUE;
1081 }
1082
1083 static guint
gst_pulsesrc_read(GstAudioSrc * asrc,gpointer data,guint length,GstClockTime * timestamp)1084 gst_pulsesrc_read (GstAudioSrc * asrc, gpointer data, guint length,
1085 GstClockTime * timestamp)
1086 {
1087 GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc);
1088 size_t sum = 0;
1089
1090 if (g_atomic_int_compare_and_exchange (&pulsesrc->notify, 1, 0)) {
1091 g_object_notify (G_OBJECT (pulsesrc), "volume");
1092 g_object_notify (G_OBJECT (pulsesrc), "mute");
1093 g_object_notify (G_OBJECT (pulsesrc), "current-device");
1094 }
1095
1096 pa_threaded_mainloop_lock (pulsesrc->mainloop);
1097 pulsesrc->in_read = TRUE;
1098
1099 if (!pulsesrc->stream_connected)
1100 goto not_connected;
1101
1102 if (pulsesrc->paused)
1103 goto was_paused;
1104
1105 while (length > 0) {
1106 size_t l;
1107
1108 GST_LOG_OBJECT (pulsesrc, "reading %u bytes", length);
1109
1110 /*check if we have a leftover buffer */
1111 if (!pulsesrc->read_buffer) {
1112 for (;;) {
1113 if (gst_pulsesrc_is_dead (pulsesrc, TRUE))
1114 goto unlock_and_fail;
1115
1116 /* read all available data, we keep a pointer to the data and the length
1117 * and take from it what we need. */
1118 if (pa_stream_peek (pulsesrc->stream, &pulsesrc->read_buffer,
1119 &pulsesrc->read_buffer_length) < 0)
1120 goto peek_failed;
1121
1122 GST_LOG_OBJECT (pulsesrc, "have data of %" G_GSIZE_FORMAT " bytes",
1123 pulsesrc->read_buffer_length);
1124
1125 /* if we have data, process if */
1126 if (pulsesrc->read_buffer && pulsesrc->read_buffer_length)
1127 break;
1128
1129 /* now wait for more data to become available */
1130 GST_LOG_OBJECT (pulsesrc, "waiting for data");
1131 pa_threaded_mainloop_wait (pulsesrc->mainloop);
1132
1133 if (pulsesrc->paused)
1134 goto was_paused;
1135 }
1136 }
1137
1138 l = pulsesrc->read_buffer_length >
1139 length ? length : pulsesrc->read_buffer_length;
1140
1141 memcpy (data, pulsesrc->read_buffer, l);
1142
1143 pulsesrc->read_buffer = (const guint8 *) pulsesrc->read_buffer + l;
1144 pulsesrc->read_buffer_length -= l;
1145
1146 data = (guint8 *) data + l;
1147 length -= l;
1148 sum += l;
1149
1150 if (pulsesrc->read_buffer_length <= 0) {
1151 /* we copied all of the data, drop it now */
1152 if (pa_stream_drop (pulsesrc->stream) < 0)
1153 goto drop_failed;
1154
1155 /* reset pointer to data */
1156 pulsesrc->read_buffer = NULL;
1157 pulsesrc->read_buffer_length = 0;
1158 }
1159 }
1160
1161 pulsesrc->in_read = FALSE;
1162 pa_threaded_mainloop_unlock (pulsesrc->mainloop);
1163
1164 return sum;
1165
1166 /* ERRORS */
1167 not_connected:
1168 {
1169 GST_LOG_OBJECT (pulsesrc, "we are not connected");
1170 goto unlock_and_fail;
1171 }
1172 was_paused:
1173 {
1174 GST_LOG_OBJECT (pulsesrc, "we are paused");
1175 goto unlock_and_fail;
1176 }
1177 peek_failed:
1178 {
1179 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
1180 ("pa_stream_peek() failed: %s",
1181 pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
1182 goto unlock_and_fail;
1183 }
1184 drop_failed:
1185 {
1186 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
1187 ("pa_stream_drop() failed: %s",
1188 pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
1189 goto unlock_and_fail;
1190 }
1191 unlock_and_fail:
1192 {
1193 pulsesrc->in_read = FALSE;
1194 pa_threaded_mainloop_unlock (pulsesrc->mainloop);
1195
1196 return (guint) - 1;
1197 }
1198 }
1199
1200 /* return the delay in samples */
1201 static guint
gst_pulsesrc_delay(GstAudioSrc * asrc)1202 gst_pulsesrc_delay (GstAudioSrc * asrc)
1203 {
1204 GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc);
1205 pa_usec_t t;
1206 int negative, res;
1207 guint result;
1208
1209 pa_threaded_mainloop_lock (pulsesrc->mainloop);
1210 if (gst_pulsesrc_is_dead (pulsesrc, TRUE))
1211 goto server_dead;
1212
1213 /* get the latency, this can fail when we don't have a latency update yet.
1214 * We don't want to wait for latency updates here but we just return 0. */
1215 res = pa_stream_get_latency (pulsesrc->stream, &t, &negative);
1216
1217 pa_threaded_mainloop_unlock (pulsesrc->mainloop);
1218
1219 if (res < 0) {
1220 GST_DEBUG_OBJECT (pulsesrc, "could not get latency");
1221 result = 0;
1222 } else {
1223 if (negative)
1224 result = 0;
1225 else
1226 result = (guint) ((t * pulsesrc->sample_spec.rate) / 1000000LL);
1227 }
1228 return result;
1229
1230 /* ERRORS */
1231 server_dead:
1232 {
1233 GST_DEBUG_OBJECT (pulsesrc, "the server is dead");
1234 pa_threaded_mainloop_unlock (pulsesrc->mainloop);
1235 return 0;
1236 }
1237 }
1238
1239 static gboolean
gst_pulsesrc_create_stream(GstPulseSrc * pulsesrc,GstCaps ** caps,GstAudioRingBufferSpec * rspec)1240 gst_pulsesrc_create_stream (GstPulseSrc * pulsesrc, GstCaps ** caps,
1241 GstAudioRingBufferSpec * rspec)
1242 {
1243 pa_channel_map channel_map;
1244 const pa_channel_map *m;
1245 GstStructure *s;
1246 gboolean need_channel_layout = FALSE;
1247 GstAudioRingBufferSpec new_spec, *spec = NULL;
1248 const gchar *name;
1249 int i;
1250
1251 /* If we already have a stream (renegotiation), free it first */
1252 if (pulsesrc->stream)
1253 gst_pulsesrc_destroy_stream (pulsesrc);
1254
1255 if (rspec) {
1256 /* Post-negotiation, we already have a ringbuffer spec, so we just need to
1257 * use it to create a stream. */
1258 spec = rspec;
1259
1260 /* At this point, we expect the channel-mask to be set in caps, so we just
1261 * use that */
1262 if (!gst_pulse_gst_to_channel_map (&channel_map, spec))
1263 goto invalid_spec;
1264
1265 } else if (caps) {
1266 /* At negotiation time, we get a fixed caps and use it to set up a stream */
1267 s = gst_caps_get_structure (*caps, 0);
1268 gst_structure_get_int (s, "channels", &new_spec.info.channels);
1269 if (!gst_structure_has_field (s, "channel-mask")) {
1270 if (new_spec.info.channels == 1) {
1271 pa_channel_map_init_mono (&channel_map);
1272 } else if (new_spec.info.channels == 2) {
1273 pa_channel_map_init_stereo (&channel_map);
1274 } else {
1275 need_channel_layout = TRUE;
1276 gst_structure_set (s, "channel-mask", GST_TYPE_BITMASK,
1277 G_GUINT64_CONSTANT (0), NULL);
1278 }
1279 }
1280
1281 memset (&new_spec, 0, sizeof (GstAudioRingBufferSpec));
1282 new_spec.latency_time = GST_SECOND;
1283 if (!gst_audio_ring_buffer_parse_caps (&new_spec, *caps))
1284 goto invalid_caps;
1285
1286 /* Keep the refcount of the caps at 1 to make them writable */
1287 gst_caps_unref (new_spec.caps);
1288
1289 if (!need_channel_layout
1290 && !gst_pulse_gst_to_channel_map (&channel_map, &new_spec)) {
1291 need_channel_layout = TRUE;
1292 gst_structure_set (s, "channel-mask", GST_TYPE_BITMASK,
1293 G_GUINT64_CONSTANT (0), NULL);
1294 for (i = 0; i < G_N_ELEMENTS (new_spec.info.position); i++)
1295 new_spec.info.position[i] = GST_AUDIO_CHANNEL_POSITION_INVALID;
1296 }
1297
1298 spec = &new_spec;
1299 } else {
1300 /* !rspec && !caps */
1301 g_assert_not_reached ();
1302 }
1303
1304 if (!gst_pulse_fill_sample_spec (spec, &pulsesrc->sample_spec))
1305 goto invalid_spec;
1306
1307 pa_threaded_mainloop_lock (pulsesrc->mainloop);
1308
1309 if (!pulsesrc->context)
1310 goto bad_context;
1311
1312 name = "Record Stream";
1313 if (pulsesrc->proplist) {
1314 if (!(pulsesrc->stream = pa_stream_new_with_proplist (pulsesrc->context,
1315 name, &pulsesrc->sample_spec,
1316 (need_channel_layout) ? NULL : &channel_map,
1317 pulsesrc->proplist)))
1318 goto create_failed;
1319
1320 } else if (!(pulsesrc->stream = pa_stream_new (pulsesrc->context,
1321 name, &pulsesrc->sample_spec,
1322 (need_channel_layout) ? NULL : &channel_map)))
1323 goto create_failed;
1324
1325 if (caps) {
1326 m = pa_stream_get_channel_map (pulsesrc->stream);
1327 gst_pulse_channel_map_to_gst (m, &new_spec);
1328 gst_audio_channel_positions_to_valid_order (new_spec.info.position,
1329 new_spec.info.channels);
1330 gst_caps_unref (*caps);
1331 *caps = gst_audio_info_to_caps (&new_spec.info);
1332
1333 GST_DEBUG_OBJECT (pulsesrc, "Caps are %" GST_PTR_FORMAT, *caps);
1334 }
1335
1336
1337 pa_stream_set_state_callback (pulsesrc->stream, gst_pulsesrc_stream_state_cb,
1338 pulsesrc);
1339 pa_stream_set_read_callback (pulsesrc->stream, gst_pulsesrc_stream_request_cb,
1340 pulsesrc);
1341 pa_stream_set_underflow_callback (pulsesrc->stream,
1342 gst_pulsesrc_stream_underflow_cb, pulsesrc);
1343 pa_stream_set_overflow_callback (pulsesrc->stream,
1344 gst_pulsesrc_stream_overflow_cb, pulsesrc);
1345 pa_stream_set_latency_update_callback (pulsesrc->stream,
1346 gst_pulsesrc_stream_latency_update_cb, pulsesrc);
1347
1348 pa_threaded_mainloop_unlock (pulsesrc->mainloop);
1349
1350 return TRUE;
1351
1352 /* ERRORS */
1353 invalid_caps:
1354 {
1355 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, SETTINGS,
1356 ("Can't parse caps."), (NULL));
1357 goto fail;
1358 }
1359 invalid_spec:
1360 {
1361 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, SETTINGS,
1362 ("Invalid sample specification."), (NULL));
1363 goto fail;
1364 }
1365 bad_context:
1366 {
1367 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Bad context"), (NULL));
1368 goto unlock_and_fail;
1369 }
1370 create_failed:
1371 {
1372 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
1373 ("Failed to create stream: %s",
1374 pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
1375 goto unlock_and_fail;
1376 }
1377 unlock_and_fail:
1378 {
1379 gst_pulsesrc_destroy_stream (pulsesrc);
1380
1381 pa_threaded_mainloop_unlock (pulsesrc->mainloop);
1382
1383 fail:
1384 return FALSE;
1385 }
1386 }
1387
1388 static gboolean
gst_pulsesrc_event(GstBaseSrc * basesrc,GstEvent * event)1389 gst_pulsesrc_event (GstBaseSrc * basesrc, GstEvent * event)
1390 {
1391 GST_DEBUG_OBJECT (basesrc, "handle event %" GST_PTR_FORMAT, event);
1392
1393 switch (GST_EVENT_TYPE (event)) {
1394 case GST_EVENT_RECONFIGURE:
1395 gst_pad_check_reconfigure (GST_BASE_SRC_PAD (basesrc));
1396 break;
1397 default:
1398 break;
1399 }
1400 return GST_BASE_SRC_CLASS (parent_class)->event (basesrc, event);
1401 }
1402
1403 /* This is essentially gst_base_src_negotiate_default() but the caps
1404 * are guaranteed to have a channel layout for > 2 channels
1405 */
1406 static gboolean
gst_pulsesrc_negotiate(GstBaseSrc * basesrc)1407 gst_pulsesrc_negotiate (GstBaseSrc * basesrc)
1408 {
1409 GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (basesrc);
1410 GstCaps *thiscaps;
1411 GstCaps *caps = NULL;
1412 GstCaps *peercaps = NULL;
1413 gboolean result = FALSE;
1414
1415 /* first see what is possible on our source pad */
1416 thiscaps = gst_pad_query_caps (GST_BASE_SRC_PAD (basesrc), NULL);
1417 GST_DEBUG_OBJECT (basesrc, "caps of src: %" GST_PTR_FORMAT, thiscaps);
1418 /* nothing or anything is allowed, we're done */
1419 if (thiscaps == NULL || gst_caps_is_any (thiscaps))
1420 goto no_nego_needed;
1421
1422 /* get the peer caps */
1423 peercaps = gst_pad_peer_query_caps (GST_BASE_SRC_PAD (basesrc), NULL);
1424 GST_DEBUG_OBJECT (basesrc, "caps of peer: %" GST_PTR_FORMAT, peercaps);
1425 if (peercaps) {
1426 /* get intersection */
1427 caps = gst_caps_intersect (thiscaps, peercaps);
1428 GST_DEBUG_OBJECT (basesrc, "intersect: %" GST_PTR_FORMAT, caps);
1429 gst_caps_unref (thiscaps);
1430 gst_caps_unref (peercaps);
1431 } else {
1432 /* no peer, work with our own caps then */
1433 caps = thiscaps;
1434 }
1435 if (caps) {
1436 /* take first (and best, since they are sorted) possibility */
1437 caps = gst_caps_truncate (caps);
1438
1439 /* now fixate */
1440 if (!gst_caps_is_empty (caps)) {
1441 caps = GST_BASE_SRC_CLASS (parent_class)->fixate (basesrc, caps);
1442 GST_DEBUG_OBJECT (basesrc, "fixated to: %" GST_PTR_FORMAT, caps);
1443
1444 if (gst_caps_is_any (caps)) {
1445 /* hmm, still anything, so element can do anything and
1446 * nego is not needed */
1447 result = TRUE;
1448 } else if (gst_caps_is_fixed (caps)) {
1449 /* yay, fixed caps, use those then */
1450 result = gst_pulsesrc_create_stream (pulsesrc, &caps, NULL);
1451 if (result)
1452 result = gst_base_src_set_caps (basesrc, caps);
1453 }
1454 }
1455 gst_caps_unref (caps);
1456 }
1457 return result;
1458
1459 no_nego_needed:
1460 {
1461 GST_DEBUG_OBJECT (basesrc, "no negotiation needed");
1462 if (thiscaps)
1463 gst_caps_unref (thiscaps);
1464 return TRUE;
1465 }
1466 }
1467
1468 static gboolean
gst_pulsesrc_prepare(GstAudioSrc * asrc,GstAudioRingBufferSpec * spec)1469 gst_pulsesrc_prepare (GstAudioSrc * asrc, GstAudioRingBufferSpec * spec)
1470 {
1471 pa_buffer_attr wanted;
1472 const pa_buffer_attr *actual;
1473 GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc);
1474 pa_stream_flags_t flags;
1475 pa_operation *o;
1476 GstAudioClock *clock;
1477
1478 pa_threaded_mainloop_lock (pulsesrc->mainloop);
1479
1480 if (!pulsesrc->stream)
1481 gst_pulsesrc_create_stream (pulsesrc, NULL, spec);
1482
1483 {
1484 GstAudioRingBufferSpec s = *spec;
1485 const pa_channel_map *m;
1486
1487 m = pa_stream_get_channel_map (pulsesrc->stream);
1488 gst_pulse_channel_map_to_gst (m, &s);
1489 gst_audio_ring_buffer_set_channel_positions (GST_AUDIO_BASE_SRC
1490 (pulsesrc)->ringbuffer, s.info.position);
1491 }
1492
1493 /* enable event notifications */
1494 GST_LOG_OBJECT (pulsesrc, "subscribing to context events");
1495 if (!(o = pa_context_subscribe (pulsesrc->context,
1496 PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, NULL, NULL))) {
1497 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
1498 ("pa_context_subscribe() failed: %s",
1499 pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
1500 goto unlock_and_fail;
1501 }
1502
1503 pa_operation_unref (o);
1504
1505 /* There's a bit of a disconnect here between the audio ringbuffer and what
1506 * PulseAudio provides. The audio ringbuffer provide a total of buffer_time
1507 * worth of buffering, divided into segments of latency_time size. We're
1508 * asking PulseAudio to provide a total latency of latency_time, which, with
1509 * PA_STREAM_ADJUST_LATENCY, effectively sets itself up as a ringbuffer with
1510 * one segment being the hardware buffer, and the other the software buffer.
1511 * This segment size is returned as the fragsize.
1512 *
1513 * Since the two concepts don't map very well, what we do is keep segsize as
1514 * it is (unless fragsize is even larger, in which case we use that). We'll
1515 * get data from PulseAudio in smaller chunks than we want to pass on as an
1516 * element, and we coalesce those chunks in the ringbuffer memory and pass it
1517 * on in the expected chunk size. */
1518 wanted.maxlength = spec->segsize * spec->segtotal;
1519 wanted.tlength = -1;
1520 wanted.prebuf = 0;
1521 wanted.minreq = -1;
1522 wanted.fragsize = spec->segsize;
1523
1524 GST_INFO_OBJECT (pulsesrc, "maxlength: %d", wanted.maxlength);
1525 GST_INFO_OBJECT (pulsesrc, "tlength: %d", wanted.tlength);
1526 GST_INFO_OBJECT (pulsesrc, "prebuf: %d", wanted.prebuf);
1527 GST_INFO_OBJECT (pulsesrc, "minreq: %d", wanted.minreq);
1528 GST_INFO_OBJECT (pulsesrc, "fragsize: %d", wanted.fragsize);
1529
1530 flags = PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE |
1531 PA_STREAM_NOT_MONOTONIC | PA_STREAM_ADJUST_LATENCY |
1532 PA_STREAM_START_CORKED;
1533
1534 if (pa_stream_connect_record (pulsesrc->stream, pulsesrc->device, &wanted,
1535 flags) < 0) {
1536 goto connect_failed;
1537 }
1538
1539 /* our clock will now start from 0 again */
1540 clock = GST_AUDIO_CLOCK (GST_AUDIO_BASE_SRC (pulsesrc)->clock);
1541 gst_audio_clock_reset (clock, 0);
1542
1543 pulsesrc->corked = TRUE;
1544
1545 for (;;) {
1546 pa_stream_state_t state;
1547
1548 state = pa_stream_get_state (pulsesrc->stream);
1549
1550 if (!PA_STREAM_IS_GOOD (state))
1551 goto stream_is_bad;
1552
1553 if (state == PA_STREAM_READY)
1554 break;
1555
1556 /* Wait until the stream is ready */
1557 pa_threaded_mainloop_wait (pulsesrc->mainloop);
1558 }
1559 pulsesrc->stream_connected = TRUE;
1560
1561 /* store the source output index so it can be accessed via a property */
1562 pulsesrc->source_output_idx = pa_stream_get_index (pulsesrc->stream);
1563 g_object_notify (G_OBJECT (pulsesrc), "source-output-index");
1564
1565 /* Although source output stream muting is supported, there is a bug in
1566 * PulseAudio that doesn't allow us to do this at startup, so we mute
1567 * manually post-connect. This should be moved back pre-connect once things
1568 * are fixed on the PulseAudio side. */
1569 if (pulsesrc->mute_set && pulsesrc->mute) {
1570 gst_pulsesrc_set_stream_mute (pulsesrc, pulsesrc->mute);
1571 pulsesrc->mute_set = FALSE;
1572 }
1573
1574 if (pulsesrc->volume_set) {
1575 gst_pulsesrc_set_stream_volume (pulsesrc, pulsesrc->volume);
1576 pulsesrc->volume_set = FALSE;
1577 }
1578
1579 /* get the actual buffering properties now */
1580 actual = pa_stream_get_buffer_attr (pulsesrc->stream);
1581
1582 GST_INFO_OBJECT (pulsesrc, "maxlength: %d", actual->maxlength);
1583 GST_INFO_OBJECT (pulsesrc, "tlength: %d (wanted: %d)",
1584 actual->tlength, wanted.tlength);
1585 GST_INFO_OBJECT (pulsesrc, "prebuf: %d", actual->prebuf);
1586 GST_INFO_OBJECT (pulsesrc, "minreq: %d (wanted %d)", actual->minreq,
1587 wanted.minreq);
1588 GST_INFO_OBJECT (pulsesrc, "fragsize: %d (wanted %d)",
1589 actual->fragsize, wanted.fragsize);
1590
1591 if (actual->fragsize >= spec->segsize) {
1592 spec->segsize = actual->fragsize;
1593 } else {
1594 /* fragsize is smaller than what we wanted, so let the read function
1595 * coalesce the smaller chunks as they come in */
1596 }
1597
1598 /* Fix up the total ringbuffer size based on what we actually got */
1599 spec->segtotal = actual->maxlength / spec->segsize;
1600 /* Don't buffer less than 2 segments as the ringbuffer can't deal with it */
1601 if (spec->segtotal < 2)
1602 spec->segtotal = 2;
1603
1604 if (!pulsesrc->paused) {
1605 GST_DEBUG_OBJECT (pulsesrc, "uncorking because we are playing");
1606 gst_pulsesrc_set_corked (pulsesrc, FALSE, FALSE);
1607 }
1608 pa_threaded_mainloop_unlock (pulsesrc->mainloop);
1609
1610 return TRUE;
1611
1612 /* ERRORS */
1613 connect_failed:
1614 {
1615 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
1616 ("Failed to connect stream: %s",
1617 pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
1618 goto unlock_and_fail;
1619 }
1620 stream_is_bad:
1621 {
1622 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
1623 ("Failed to connect stream: %s",
1624 pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
1625 goto unlock_and_fail;
1626 }
1627 unlock_and_fail:
1628 {
1629 gst_pulsesrc_destroy_stream (pulsesrc);
1630
1631 pa_threaded_mainloop_unlock (pulsesrc->mainloop);
1632 return FALSE;
1633 }
1634 }
1635
1636 static void
gst_pulsesrc_success_cb(pa_stream * s,int success,void * userdata)1637 gst_pulsesrc_success_cb (pa_stream * s, int success, void *userdata)
1638 {
1639 GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (userdata);
1640
1641 pulsesrc->operation_success = ! !success;
1642 pa_threaded_mainloop_signal (pulsesrc->mainloop, 0);
1643 }
1644
1645 static void
gst_pulsesrc_reset(GstAudioSrc * asrc)1646 gst_pulsesrc_reset (GstAudioSrc * asrc)
1647 {
1648 GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc);
1649 pa_operation *o = NULL;
1650
1651 pa_threaded_mainloop_lock (pulsesrc->mainloop);
1652 GST_DEBUG_OBJECT (pulsesrc, "reset");
1653
1654 if (gst_pulsesrc_is_dead (pulsesrc, TRUE))
1655 goto unlock_and_fail;
1656
1657 if (!(o =
1658 pa_stream_flush (pulsesrc->stream, gst_pulsesrc_success_cb,
1659 pulsesrc))) {
1660 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
1661 ("pa_stream_flush() failed: %s",
1662 pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
1663 goto unlock_and_fail;
1664 }
1665
1666 pulsesrc->paused = TRUE;
1667 /* Inform anyone waiting in _write() call that it shall wakeup */
1668 if (pulsesrc->in_read) {
1669 pa_threaded_mainloop_signal (pulsesrc->mainloop, 0);
1670 }
1671
1672 pulsesrc->operation_success = FALSE;
1673 while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
1674
1675 if (gst_pulsesrc_is_dead (pulsesrc, TRUE))
1676 goto unlock_and_fail;
1677
1678 pa_threaded_mainloop_wait (pulsesrc->mainloop);
1679 }
1680
1681 if (!pulsesrc->operation_success) {
1682 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Flush failed: %s",
1683 pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
1684 goto unlock_and_fail;
1685 }
1686
1687 unlock_and_fail:
1688
1689 if (o) {
1690 pa_operation_cancel (o);
1691 pa_operation_unref (o);
1692 }
1693
1694 pa_threaded_mainloop_unlock (pulsesrc->mainloop);
1695 }
1696
1697 /* update the corked state of a stream, must be called with the mainloop
1698 * lock */
1699 static gboolean
gst_pulsesrc_set_corked(GstPulseSrc * psrc,gboolean corked,gboolean wait)1700 gst_pulsesrc_set_corked (GstPulseSrc * psrc, gboolean corked, gboolean wait)
1701 {
1702 pa_operation *o = NULL;
1703 gboolean res = FALSE;
1704
1705 GST_DEBUG_OBJECT (psrc, "setting corked state to %d", corked);
1706 if (!psrc->stream_connected)
1707 return TRUE;
1708
1709 if (psrc->corked != corked) {
1710 if (!(o = pa_stream_cork (psrc->stream, corked,
1711 gst_pulsesrc_success_cb, psrc)))
1712 goto cork_failed;
1713
1714 while (wait && pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
1715 pa_threaded_mainloop_wait (psrc->mainloop);
1716 if (gst_pulsesrc_is_dead (psrc, TRUE))
1717 goto server_dead;
1718 }
1719 psrc->corked = corked;
1720 } else {
1721 GST_DEBUG_OBJECT (psrc, "skipping, already in requested state");
1722 }
1723 res = TRUE;
1724
1725 cleanup:
1726 if (o)
1727 pa_operation_unref (o);
1728
1729 return res;
1730
1731 /* ERRORS */
1732 server_dead:
1733 {
1734 GST_DEBUG_OBJECT (psrc, "the server is dead");
1735 goto cleanup;
1736 }
1737 cork_failed:
1738 {
1739 GST_ELEMENT_ERROR (psrc, RESOURCE, FAILED,
1740 ("pa_stream_cork() failed: %s",
1741 pa_strerror (pa_context_errno (psrc->context))), (NULL));
1742 goto cleanup;
1743 }
1744 }
1745
1746 /* start/resume playback ASAP */
1747 static gboolean
gst_pulsesrc_play(GstPulseSrc * psrc)1748 gst_pulsesrc_play (GstPulseSrc * psrc)
1749 {
1750 pa_threaded_mainloop_lock (psrc->mainloop);
1751 GST_DEBUG_OBJECT (psrc, "playing");
1752 psrc->paused = FALSE;
1753 gst_pulsesrc_set_corked (psrc, FALSE, FALSE);
1754 pa_threaded_mainloop_unlock (psrc->mainloop);
1755
1756 return TRUE;
1757 }
1758
1759 /* pause/stop playback ASAP */
1760 static gboolean
gst_pulsesrc_pause(GstPulseSrc * psrc)1761 gst_pulsesrc_pause (GstPulseSrc * psrc)
1762 {
1763 pa_threaded_mainloop_lock (psrc->mainloop);
1764 GST_DEBUG_OBJECT (psrc, "pausing");
1765 /* make sure the commit method stops writing */
1766 psrc->paused = TRUE;
1767 if (psrc->in_read) {
1768 /* we are waiting in a read, signal */
1769 GST_DEBUG_OBJECT (psrc, "signal read");
1770 pa_threaded_mainloop_signal (psrc->mainloop, 0);
1771 }
1772 pa_threaded_mainloop_unlock (psrc->mainloop);
1773
1774 return TRUE;
1775 }
1776
1777 static GstStateChangeReturn
gst_pulsesrc_change_state(GstElement * element,GstStateChange transition)1778 gst_pulsesrc_change_state (GstElement * element, GstStateChange transition)
1779 {
1780 GstStateChangeReturn ret;
1781 GstPulseSrc *this = GST_PULSESRC_CAST (element);
1782
1783 switch (transition) {
1784 case GST_STATE_CHANGE_NULL_TO_READY:
1785 if (!(this->mainloop = pa_threaded_mainloop_new ()))
1786 goto mainloop_failed;
1787 if (pa_threaded_mainloop_start (this->mainloop) < 0) {
1788 pa_threaded_mainloop_free (this->mainloop);
1789 this->mainloop = NULL;
1790 goto mainloop_start_failed;
1791 }
1792 break;
1793 case GST_STATE_CHANGE_READY_TO_PAUSED:
1794 gst_element_post_message (element,
1795 gst_message_new_clock_provide (GST_OBJECT_CAST (element),
1796 GST_AUDIO_BASE_SRC (this)->clock, TRUE));
1797 break;
1798 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1799 /* uncork and start recording */
1800 gst_pulsesrc_play (this);
1801 break;
1802 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1803 /* stop recording ASAP by corking */
1804 pa_threaded_mainloop_lock (this->mainloop);
1805 GST_DEBUG_OBJECT (this, "corking");
1806 gst_pulsesrc_set_corked (this, TRUE, FALSE);
1807 pa_threaded_mainloop_unlock (this->mainloop);
1808 break;
1809 default:
1810 break;
1811 }
1812
1813 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1814
1815 switch (transition) {
1816 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1817 /* now make sure we get out of the _read method */
1818 gst_pulsesrc_pause (this);
1819 break;
1820 case GST_STATE_CHANGE_READY_TO_NULL:
1821 if (this->mainloop)
1822 pa_threaded_mainloop_stop (this->mainloop);
1823
1824 gst_pulsesrc_destroy_context (this);
1825
1826 if (this->mainloop) {
1827 pa_threaded_mainloop_free (this->mainloop);
1828 this->mainloop = NULL;
1829 }
1830 break;
1831 case GST_STATE_CHANGE_PAUSED_TO_READY:
1832 /* format_lost is reset in release() in baseaudiosink */
1833 gst_element_post_message (element,
1834 gst_message_new_clock_lost (GST_OBJECT_CAST (element),
1835 GST_AUDIO_BASE_SRC (this)->clock));
1836 break;
1837 default:
1838 break;
1839 }
1840
1841 return ret;
1842
1843 /* ERRORS */
1844 mainloop_failed:
1845 {
1846 GST_ELEMENT_ERROR (this, RESOURCE, FAILED,
1847 ("pa_threaded_mainloop_new() failed"), (NULL));
1848 return GST_STATE_CHANGE_FAILURE;
1849 }
1850 mainloop_start_failed:
1851 {
1852 GST_ELEMENT_ERROR (this, RESOURCE, FAILED,
1853 ("pa_threaded_mainloop_start() failed"), (NULL));
1854 return GST_STATE_CHANGE_FAILURE;
1855 }
1856 }
1857
1858 static GstClockTime
gst_pulsesrc_get_time(GstClock * clock,GstPulseSrc * src)1859 gst_pulsesrc_get_time (GstClock * clock, GstPulseSrc * src)
1860 {
1861 pa_usec_t time = 0;
1862
1863 if (src->mainloop == NULL)
1864 goto out;
1865
1866 pa_threaded_mainloop_lock (src->mainloop);
1867 if (!src->stream)
1868 goto unlock_and_out;
1869
1870 if (gst_pulsesrc_is_dead (src, TRUE))
1871 goto unlock_and_out;
1872
1873 if (pa_stream_get_time (src->stream, &time) < 0) {
1874 GST_DEBUG_OBJECT (src, "could not get time");
1875 time = GST_CLOCK_TIME_NONE;
1876 } else {
1877 time *= 1000;
1878 }
1879
1880
1881 unlock_and_out:
1882 pa_threaded_mainloop_unlock (src->mainloop);
1883
1884 out:
1885 return time;
1886 }
1887