4 This file is part of gst-pulse.
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
29 #include <gst/base/gstbasesrc.h>
30 #include <gst/gsttaglist.h>
33 #include "pulseutil.h"
34 #include "pulsemixerctrl.h"
36 GST_DEBUG_CATEGORY_EXTERN(pulse_debug
);
37 #define GST_CAT_DEFAULT pulse_debug
44 static GstAudioSrcClass
*parent_class
= NULL
;
46 GST_IMPLEMENT_PULSEMIXER_CTRL_METHODS(GstPulseSrc
, gst_pulsesrc
)
48 static void gst_pulsesrc_destroy_stream(GstPulseSrc
*pulsesrc
);
49 static void gst_pulsesrc_destroy_context(GstPulseSrc
*pulsesrc
);
51 static void gst_pulsesrc_set_property(GObject
*object
, guint prop_id
, const GValue
*value
, GParamSpec
*pspec
);
52 static void gst_pulsesrc_get_property(GObject
*object
, guint prop_id
, GValue
*value
, GParamSpec
*pspec
);
53 static void gst_pulsesrc_finalize(GObject
*object
);
54 static void gst_pulsesrc_dispose(GObject
*object
);
56 static gboolean
gst_pulsesrc_open(GstAudioSrc
*asrc
);
57 static gboolean
gst_pulsesrc_close(GstAudioSrc
*asrc
);
59 static gboolean
gst_pulsesrc_prepare(GstAudioSrc
*asrc
, GstRingBufferSpec
*spec
);
60 static gboolean
gst_pulsesrc_unprepare(GstAudioSrc
*asrc
);
62 static guint
gst_pulsesrc_read(GstAudioSrc
*asrc
, gpointer data
, guint length
);
63 static guint
gst_pulsesrc_delay(GstAudioSrc
*asrc
);
65 static GstStateChangeReturn
gst_pulsesrc_change_state(GstElement
*element
, GstStateChange transition
);
67 #if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
68 # define ENDIANNESS "LITTLE_ENDIAN, BIG_ENDIAN"
70 # define ENDIANNESS "BIG_ENDIAN, LITTLE_ENDIAN"
73 static gboolean
gst_pulsesrc_interface_supported(GstImplementsInterface
* iface
, GType interface_type
) {
74 GstPulseSrc
*this = GST_PULSESRC(iface
);
76 if (interface_type
== GST_TYPE_MIXER
&& this->mixer
)
82 static void gst_pulsesrc_implements_interface_init(GstImplementsInterfaceClass
* klass
) {
83 klass
->supported
= gst_pulsesrc_interface_supported
;
86 static void gst_pulsesrc_init_interfaces(GType type
) {
87 static const GInterfaceInfo implements_iface_info
= {
88 (GInterfaceInitFunc
) gst_pulsesrc_implements_interface_init
,
92 static const GInterfaceInfo mixer_iface_info
= {
93 (GInterfaceInitFunc
) gst_pulsesrc_mixer_interface_init
,
98 g_type_add_interface_static(type
, GST_TYPE_IMPLEMENTS_INTERFACE
, &implements_iface_info
);
99 g_type_add_interface_static(type
, GST_TYPE_MIXER
, &mixer_iface_info
);
102 static void gst_pulsesrc_base_init(gpointer g_class
) {
104 static GstStaticPadTemplate pad_template
= GST_STATIC_PAD_TEMPLATE(
110 "endianness = (int) { " ENDIANNESS
" }, "
111 "signed = (boolean) TRUE, "
114 "rate = (int) [ 1, MAX ], "
115 "channels = (int) [ 1, 16 ];"
118 "signed = (boolean) FALSE, "
121 "rate = (int) [ 1, MAX ], "
122 "channels = (int) [ 1, 16 ];"
124 "audio/x-raw-float, "
125 "endianness = (int) { " ENDIANNESS
" }, "
127 "rate = (int) [ 1, MAX ], "
128 "channels = (int) [ 1, 16 ];"
131 "rate = (int) [ 1, MAX], "
132 "channels = (int) [ 1, 16 ];"
135 "rate = (int) [ 1, MAX], "
136 "channels = (int) [ 1, 16 ]"
140 static const GstElementDetails details
=
142 "PulseAudio Audio Source",
144 "Captures audio from a PulseAudio server",
145 "Lennart Poettering");
147 GstElementClass
*element_class
= GST_ELEMENT_CLASS(g_class
);
149 gst_element_class_set_details(element_class
, &details
);
150 gst_element_class_add_pad_template(element_class
, gst_static_pad_template_get(&pad_template
));
153 static void gst_pulsesrc_class_init(
155 gpointer class_data
) {
157 GObjectClass
*gobject_class
= G_OBJECT_CLASS(g_class
);
158 GstAudioSrcClass
*gstaudiosrc_class
= GST_AUDIO_SRC_CLASS(g_class
);
159 GstElementClass
*gstelement_class
= GST_ELEMENT_CLASS(g_class
);
160 parent_class
= g_type_class_peek_parent(g_class
);
162 gstelement_class
->change_state
= GST_DEBUG_FUNCPTR(gst_pulsesrc_change_state
);
164 gobject_class
->dispose
= GST_DEBUG_FUNCPTR(gst_pulsesrc_dispose
);
165 gobject_class
->finalize
= GST_DEBUG_FUNCPTR(gst_pulsesrc_finalize
);
166 gobject_class
->set_property
= GST_DEBUG_FUNCPTR(gst_pulsesrc_set_property
);
167 gobject_class
->get_property
= GST_DEBUG_FUNCPTR(gst_pulsesrc_get_property
);
169 gstaudiosrc_class
->open
= GST_DEBUG_FUNCPTR(gst_pulsesrc_open
);
170 gstaudiosrc_class
->close
= GST_DEBUG_FUNCPTR(gst_pulsesrc_close
);
171 gstaudiosrc_class
->prepare
= GST_DEBUG_FUNCPTR(gst_pulsesrc_prepare
);
172 gstaudiosrc_class
->unprepare
= GST_DEBUG_FUNCPTR(gst_pulsesrc_unprepare
);
173 gstaudiosrc_class
->read
= GST_DEBUG_FUNCPTR(gst_pulsesrc_read
);
174 gstaudiosrc_class
->delay
= GST_DEBUG_FUNCPTR(gst_pulsesrc_delay
);
176 /* Overwrite GObject fields */
177 g_object_class_install_property(
180 g_param_spec_string("server", "Server", "The PulseAudio server to connect to", NULL
, G_PARAM_READWRITE
));
181 g_object_class_install_property(
184 g_param_spec_string("device", "Source", "The PulseAudio source device to connect to", NULL
, G_PARAM_READWRITE
));
187 static void gst_pulsesrc_init(
188 GTypeInstance
* instance
,
191 GstPulseSrc
*pulsesrc
= GST_PULSESRC(instance
);
194 pulsesrc
->server
= pulsesrc
->device
= NULL
;
196 pulsesrc
->context
= NULL
;
197 pulsesrc
->stream
= NULL
;
199 pulsesrc
->read_buffer
= NULL
;
200 pulsesrc
->read_buffer_length
= 0;
202 pulsesrc
->mainloop
= pa_threaded_mainloop_new();
203 g_assert(pulsesrc
->mainloop
);
205 e
= pa_threaded_mainloop_start(pulsesrc
->mainloop
);
208 pulsesrc
->mixer
= NULL
;
211 static void gst_pulsesrc_destroy_stream(GstPulseSrc
* pulsesrc
) {
212 if (pulsesrc
->stream
) {
213 pa_stream_disconnect(pulsesrc
->stream
);
214 pa_stream_unref(pulsesrc
->stream
);
215 pulsesrc
->stream
= NULL
;
219 static void gst_pulsesrc_destroy_context(GstPulseSrc
* pulsesrc
) {
221 gst_pulsesrc_destroy_stream(pulsesrc
);
223 if (pulsesrc
->context
) {
224 pa_context_disconnect(pulsesrc
->context
);
225 pa_context_unref(pulsesrc
->context
);
226 pulsesrc
->context
= NULL
;
230 static void gst_pulsesrc_finalize(GObject
* object
) {
231 GstPulseSrc
*pulsesrc
= GST_PULSESRC(object
);
233 pa_threaded_mainloop_stop(pulsesrc
->mainloop
);
235 gst_pulsesrc_destroy_context(pulsesrc
);
237 g_free(pulsesrc
->server
);
238 g_free(pulsesrc
->device
);
240 pa_threaded_mainloop_free(pulsesrc
->mainloop
);
243 gst_pulsemixer_ctrl_free(pulsesrc
->mixer
);
245 G_OBJECT_CLASS(parent_class
)->finalize(object
);
248 static void gst_pulsesrc_dispose(GObject
* object
) {
249 G_OBJECT_CLASS(parent_class
)->dispose(object
);
252 static void gst_pulsesrc_set_property(
255 const GValue
* value
,
256 GParamSpec
* pspec
) {
258 GstPulseSrc
*pulsesrc
= GST_PULSESRC(object
);
262 g_free(pulsesrc
->server
);
263 pulsesrc
->server
= g_value_dup_string(value
);
267 g_free(pulsesrc
->device
);
268 pulsesrc
->device
= g_value_dup_string(value
);
272 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
277 static void gst_pulsesrc_get_property(
281 GParamSpec
* pspec
) {
283 GstPulseSrc
*pulsesrc
= GST_PULSESRC(object
);
287 g_value_set_string(value
, pulsesrc
->server
);
291 g_value_set_string(value
, pulsesrc
->device
);
295 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
300 static void gst_pulsesrc_context_state_cb(pa_context
*c
, void *userdata
) {
301 GstPulseSrc
*pulsesrc
= GST_PULSESRC(userdata
);
303 switch (pa_context_get_state(c
)) {
304 case PA_CONTEXT_READY
:
305 case PA_CONTEXT_TERMINATED
:
306 case PA_CONTEXT_FAILED
:
307 pa_threaded_mainloop_signal(pulsesrc
->mainloop
, 0);
310 case PA_CONTEXT_UNCONNECTED
:
311 case PA_CONTEXT_CONNECTING
:
312 case PA_CONTEXT_AUTHORIZING
:
313 case PA_CONTEXT_SETTING_NAME
:
318 static void gst_pulsesrc_stream_state_cb(pa_stream
*s
, void * userdata
) {
319 GstPulseSrc
*pulsesrc
= GST_PULSESRC(userdata
);
321 switch (pa_stream_get_state(s
)) {
323 case PA_STREAM_READY
:
324 case PA_STREAM_FAILED
:
325 case PA_STREAM_TERMINATED
:
326 pa_threaded_mainloop_signal(pulsesrc
->mainloop
, 0);
329 case PA_STREAM_UNCONNECTED
:
330 case PA_STREAM_CREATING
:
335 static void gst_pulsesrc_stream_request_cb(pa_stream
*s
, size_t length
, void *userdata
) {
336 GstPulseSrc
*pulsesrc
= GST_PULSESRC(userdata
);
338 pa_threaded_mainloop_signal(pulsesrc
->mainloop
, 0);
341 static gboolean
gst_pulsesrc_open(GstAudioSrc
*asrc
) {
342 GstPulseSrc
*pulsesrc
= GST_PULSESRC(asrc
);
343 gchar
*name
= gst_pulse_client_name();
345 pa_threaded_mainloop_lock(pulsesrc
->mainloop
);
347 if (!(pulsesrc
->context
= pa_context_new(pa_threaded_mainloop_get_api(pulsesrc
->mainloop
), name
))) {
348 GST_ELEMENT_ERROR(pulsesrc
, RESOURCE
, FAILED
, ("Failed to create context"), (NULL
));
349 goto unlock_and_fail
;
352 pa_context_set_state_callback(pulsesrc
->context
, gst_pulsesrc_context_state_cb
, pulsesrc
);
354 if (pa_context_connect(pulsesrc
->context
, pulsesrc
->server
, 0, NULL
) < 0) {
355 GST_ELEMENT_ERROR(pulsesrc
, RESOURCE
, FAILED
, ("Failed to connect: %s", pa_strerror(pa_context_errno(pulsesrc
->context
))), (NULL
));
356 goto unlock_and_fail
;
359 /* Wait until the context is ready */
360 pa_threaded_mainloop_wait(pulsesrc
->mainloop
);
362 if (pa_context_get_state(pulsesrc
->context
) != PA_CONTEXT_READY
) {
363 GST_ELEMENT_ERROR(pulsesrc
, RESOURCE
, FAILED
, ("Failed to connect: %s", pa_strerror(pa_context_errno(pulsesrc
->context
))), (NULL
));
364 goto unlock_and_fail
;
367 pa_threaded_mainloop_unlock(pulsesrc
->mainloop
);
374 pa_threaded_mainloop_unlock(pulsesrc
->mainloop
);
380 static gboolean
gst_pulsesrc_close(GstAudioSrc
*asrc
) {
381 GstPulseSrc
*pulsesrc
= GST_PULSESRC(asrc
);
383 pa_threaded_mainloop_lock(pulsesrc
->mainloop
);
384 gst_pulsesrc_destroy_context(pulsesrc
);
385 pa_threaded_mainloop_unlock(pulsesrc
->mainloop
);
389 static gboolean
gst_pulsesrc_prepare(GstAudioSrc
*asrc
, GstRingBufferSpec
*spec
) {
390 pa_buffer_attr buf_attr
;
392 GstPulseSrc
*pulsesrc
= GST_PULSESRC(asrc
);
394 if (!gst_pulse_fill_sample_spec(spec
, &pulsesrc
->sample_spec
)) {
395 GST_ELEMENT_ERROR(pulsesrc
, RESOURCE
, SETTINGS
, ("Invalid sample specification."), (NULL
));
396 goto unlock_and_fail
;
399 pa_threaded_mainloop_lock(pulsesrc
->mainloop
);
401 if (!pulsesrc
->context
|| pa_context_get_state(pulsesrc
->context
) != PA_CONTEXT_READY
) {
402 GST_ELEMENT_ERROR(pulsesrc
, RESOURCE
, FAILED
, ("Bad context state: %s", pulsesrc
->context
? pa_strerror(pa_context_errno(pulsesrc
->context
)) : NULL
), (NULL
));
403 goto unlock_and_fail
;
406 if (!(pulsesrc
->stream
= pa_stream_new(pulsesrc
->context
, "Record Stream", &pulsesrc
->sample_spec
, NULL
))) {
407 GST_ELEMENT_ERROR(pulsesrc
, RESOURCE
, FAILED
, ("Failed to create stream: %s", pa_strerror(pa_context_errno(pulsesrc
->context
))), (NULL
));
408 goto unlock_and_fail
;
411 pa_stream_set_state_callback(pulsesrc
->stream
, gst_pulsesrc_stream_state_cb
, pulsesrc
);
412 pa_stream_set_read_callback(pulsesrc
->stream
, gst_pulsesrc_stream_request_cb
, pulsesrc
);
414 memset(&buf_attr
, 0, sizeof(buf_attr
));
415 buf_attr
.maxlength
= spec
->segtotal
*spec
->segsize
*2;
416 buf_attr
.fragsize
= spec
->segsize
;
418 if (pa_stream_connect_record(pulsesrc
->stream
, pulsesrc
->device
, &buf_attr
, PA_STREAM_INTERPOLATE_TIMING
|PA_STREAM_AUTO_TIMING_UPDATE
|PA_STREAM_NOT_MONOTONOUS
) < 0) {
419 GST_ELEMENT_ERROR(pulsesrc
, RESOURCE
, FAILED
, ("Failed to connect stream: %s", pa_strerror(pa_context_errno(pulsesrc
->context
))), (NULL
));
420 goto unlock_and_fail
;
423 /* Wait until the stream is ready */
424 pa_threaded_mainloop_wait(pulsesrc
->mainloop
);
426 if (pa_stream_get_state(pulsesrc
->stream
) != PA_STREAM_READY
) {
427 GST_ELEMENT_ERROR(pulsesrc
, RESOURCE
, FAILED
, ("Failed to connect stream: %s", pa_strerror(pa_context_errno(pulsesrc
->context
))), (NULL
));
428 goto unlock_and_fail
;
431 pa_threaded_mainloop_unlock(pulsesrc
->mainloop
);
433 spec
->bytes_per_sample
= pa_frame_size(&pulsesrc
->sample_spec
);
434 memset(spec
->silence_sample
, 0, spec
->bytes_per_sample
);
440 pa_threaded_mainloop_unlock(pulsesrc
->mainloop
);
444 static gboolean
gst_pulsesrc_unprepare(GstAudioSrc
* asrc
) {
445 GstPulseSrc
*pulsesrc
= GST_PULSESRC(asrc
);
447 pa_threaded_mainloop_lock(pulsesrc
->mainloop
);
448 gst_pulsesrc_destroy_stream(pulsesrc
);
450 pa_threaded_mainloop_unlock(pulsesrc
->mainloop
);
452 pulsesrc
->read_buffer
= NULL
;
453 pulsesrc
->read_buffer_length
= 0;
458 #define CHECK_DEAD_GOTO(pulsesrc, label) \
459 if (!(pulsesrc)->context || pa_context_get_state((pulsesrc)->context) != PA_CONTEXT_READY || \
460 !(pulsesrc)->stream || pa_stream_get_state((pulsesrc)->stream) != PA_STREAM_READY) { \
461 GST_ELEMENT_ERROR((pulsesrc), RESOURCE, FAILED, ("Disconnected: %s", (pulsesrc)->context ? pa_strerror(pa_context_errno((pulsesrc)->context)) : NULL), (NULL)); \
465 static guint
gst_pulsesrc_read(GstAudioSrc
*asrc
, gpointer data
, guint length
) {
466 GstPulseSrc
*pulsesrc
= GST_PULSESRC(asrc
);
469 pa_threaded_mainloop_lock(pulsesrc
->mainloop
);
471 CHECK_DEAD_GOTO(pulsesrc
, unlock_and_fail
);
476 if (!pulsesrc
->read_buffer
) {
479 if (pa_stream_peek(pulsesrc
->stream
, &pulsesrc
->read_buffer
, &pulsesrc
->read_buffer_length
) < 0) {
480 GST_ELEMENT_ERROR(pulsesrc
, RESOURCE
, FAILED
, ("pa_stream_peek() failed: %s", pa_strerror(pa_context_errno(pulsesrc
->context
))), (NULL
));
481 goto unlock_and_fail
;
484 if (pulsesrc
->read_buffer
)
487 pa_threaded_mainloop_wait(pulsesrc
->mainloop
);
489 CHECK_DEAD_GOTO(pulsesrc
, unlock_and_fail
);
493 g_assert(pulsesrc
->read_buffer
&& pulsesrc
->read_buffer_length
);
495 l
= pulsesrc
->read_buffer_length
> length
? length
: pulsesrc
->read_buffer_length
;
497 memcpy(data
, pulsesrc
->read_buffer
, l
);
499 pulsesrc
->read_buffer
= (const guint8
*) pulsesrc
->read_buffer
+ l
;
500 pulsesrc
->read_buffer_length
-= l
;
502 data
= (guint8
*) data
+ l
;
507 if (pulsesrc
->read_buffer_length
<= 0) {
509 if (pa_stream_drop(pulsesrc
->stream
) < 0) {
510 GST_ELEMENT_ERROR(pulsesrc
, RESOURCE
, FAILED
, ("pa_stream_drop() failed: %s", pa_strerror(pa_context_errno(pulsesrc
->context
))), (NULL
));
511 goto unlock_and_fail
;
514 pulsesrc
->read_buffer
= NULL
;
515 pulsesrc
->read_buffer_length
= 0;
519 pa_threaded_mainloop_unlock(pulsesrc
->mainloop
);
524 pa_threaded_mainloop_unlock(pulsesrc
->mainloop
);
528 static guint
gst_pulsesrc_delay(GstAudioSrc
*asrc
) {
529 GstPulseSrc
*pulsesrc
= GST_PULSESRC(asrc
);
533 pa_threaded_mainloop_lock(pulsesrc
->mainloop
);
535 CHECK_DEAD_GOTO(pulsesrc
, unlock_and_fail
);
537 if (pa_stream_get_latency(pulsesrc
->stream
, &t
, &negative
) < 0) {
539 if (pa_context_errno(pulsesrc
->context
) != PA_ERR_NODATA
) {
540 GST_ELEMENT_ERROR(pulsesrc
, RESOURCE
, FAILED
, ("pa_stream_get_latency() failed: %s", pa_strerror(pa_context_errno(pulsesrc
->context
))), (NULL
));
541 goto unlock_and_fail
;
544 GST_WARNING("Not data while querying latency");
549 pa_threaded_mainloop_unlock(pulsesrc
->mainloop
);
551 return (guint
) ((t
* pulsesrc
->sample_spec
.rate
) / 1000000LL);
555 pa_threaded_mainloop_unlock(pulsesrc
->mainloop
);
559 static GstStateChangeReturn
gst_pulsesrc_change_state(GstElement
*element
, GstStateChange transition
) {
560 GstPulseSrc
*this = GST_PULSESRC(element
);
562 switch (transition
) {
563 case GST_STATE_CHANGE_NULL_TO_READY
:
566 this->mixer
= gst_pulsemixer_ctrl_new(this->server
, this->device
, GST_PULSEMIXER_SOURCE
);
570 case GST_STATE_CHANGE_READY_TO_NULL
:
573 gst_pulsemixer_ctrl_free(this->mixer
);
583 if (GST_ELEMENT_CLASS(parent_class
)->change_state
)
584 return GST_ELEMENT_CLASS(parent_class
)->change_state(element
, transition
);
586 return GST_STATE_CHANGE_SUCCESS
;
589 GType
gst_pulsesrc_get_type(void) {
590 static GType pulsesrc_type
= 0;
592 if (!pulsesrc_type
) {
594 static const GTypeInfo pulsesrc_info
= {
595 sizeof(GstPulseSrcClass
),
596 gst_pulsesrc_base_init
,
598 gst_pulsesrc_class_init
,
606 pulsesrc_type
= g_type_register_static(
612 gst_pulsesrc_init_interfaces(pulsesrc_type
);
615 return pulsesrc_type
;