fix tabs
[gst-pulse.git] / src / pulseprobe.c
blob0e487e41563208ade228aadc8be637c3aa8ad5d6
1 /* $Id$ */
3 /***
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
19 USA.
20 ***/
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
26 #include "pulseprobe.h"
27 #include "pulseutil.h"
29 GST_DEBUG_CATEGORY_EXTERN(pulse_debug);
30 #define GST_CAT_DEFAULT pulse_debug
32 static void gst_pulseprobe_context_state_cb(pa_context *context, void *userdata) {
33 GstPulseProbe *c = (GstPulseProbe*) userdata;
35 /* Called from the background thread! */
37 switch (pa_context_get_state(context)) {
38 case PA_CONTEXT_READY:
39 case PA_CONTEXT_TERMINATED:
40 case PA_CONTEXT_FAILED:
41 pa_threaded_mainloop_signal(c->mainloop, 0);
42 break;
44 case PA_CONTEXT_UNCONNECTED:
45 case PA_CONTEXT_CONNECTING:
46 case PA_CONTEXT_AUTHORIZING:
47 case PA_CONTEXT_SETTING_NAME:
48 break;
52 static void gst_pulseprobe_sink_info_cb(pa_context *context, const pa_sink_info *i, int eol, void *userdata) {
53 GstPulseProbe *c = (GstPulseProbe*) userdata;
55 /* Called from the background thread! */
57 if (eol || !i) {
58 c->operation_success = eol > 0;
59 pa_threaded_mainloop_signal(c->mainloop, 0);
62 if (i)
63 c->devices = g_list_append(c->devices, g_strdup(i->name));
67 static void gst_pulseprobe_source_info_cb(pa_context *context, const pa_source_info *i, int eol, void *userdata) {
68 GstPulseProbe *c = (GstPulseProbe*) userdata;
70 /* Called from the background thread! */
72 if (eol || !i) {
73 c->operation_success = eol > 0;
74 pa_threaded_mainloop_signal(c->mainloop, 0);
77 if (i)
78 c->devices = g_list_append(c->devices, g_strdup(i->name));
81 static void gst_pulseprobe_invalidate(GstPulseProbe *c) {
82 g_list_foreach(c->devices, (GFunc) g_free, NULL);
83 g_list_free(c->devices);
84 c->devices = NULL;
85 c->devices_valid = 0;
88 static gboolean gst_pulseprobe_open(GstPulseProbe *c) {
89 int e;
90 gchar *name = gst_pulse_client_name();
92 g_assert(c);
94 c->mainloop = pa_threaded_mainloop_new();
95 g_assert(c->mainloop);
97 e = pa_threaded_mainloop_start(c->mainloop);
98 g_assert(e == 0);
100 pa_threaded_mainloop_lock(c->mainloop);
102 if (!(c->context = pa_context_new(pa_threaded_mainloop_get_api(c->mainloop), name))) {
103 GST_WARNING("Failed to create context");
104 goto unlock_and_fail;
107 pa_context_set_state_callback(c->context, gst_pulseprobe_context_state_cb, c);
109 if (pa_context_connect(c->context, c->server, 0, NULL) < 0) {
110 GST_WARNING("Failed to connect context: %s", pa_strerror(pa_context_errno(c->context)));
111 goto unlock_and_fail;
114 /* Wait until the context is ready */
115 pa_threaded_mainloop_wait(c->mainloop);
117 if (pa_context_get_state(c->context) != PA_CONTEXT_READY) {
118 GST_WARNING("Failed to connect context: %s", pa_strerror(pa_context_errno(c->context)));
119 goto unlock_and_fail;
122 pa_threaded_mainloop_unlock(c->mainloop);
123 g_free(name);
125 gst_pulseprobe_invalidate(c);
127 return TRUE;
129 unlock_and_fail:
131 if (c->mainloop)
132 pa_threaded_mainloop_unlock(c->mainloop);
134 g_free(name);
136 return FALSE;
139 #define CHECK_DEAD_GOTO(c, label) do { \
140 if (!(c)->context || pa_context_get_state((c)->context) != PA_CONTEXT_READY) { \
141 GST_WARNING("Not connected: %s", (c)->context ? pa_strerror(pa_context_errno((c)->context)) : "NULL"); \
142 goto label; \
144 } while(0);
146 static gboolean gst_pulseprobe_enumerate(GstPulseProbe *c) {
147 pa_operation *o = NULL;
149 pa_threaded_mainloop_lock(c->mainloop);
151 if (c->enumerate_sinks) {
152 /* Get sink info */
154 if (!(o = pa_context_get_sink_info_list(c->context, gst_pulseprobe_sink_info_cb, c))) {
155 GST_WARNING("Failed to get sink info: %s", pa_strerror(pa_context_errno(c->context)));
156 goto unlock_and_fail;
159 c->operation_success = 0;
160 while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
161 pa_threaded_mainloop_wait(c->mainloop);
162 CHECK_DEAD_GOTO(c, unlock_and_fail);
165 if (!c->operation_success) {
166 GST_WARNING("Failed to get sink info: %s", pa_strerror(pa_context_errno(c->context)));
167 goto unlock_and_fail;
170 pa_operation_unref(o);
171 o = NULL;
174 if (c->enumerate_sources) {
175 /* Get source info */
177 if (!(o = pa_context_get_source_info_list(c->context, gst_pulseprobe_source_info_cb, c))) {
178 GST_WARNING("Failed to get source info: %s", pa_strerror(pa_context_errno(c->context)));
179 goto unlock_and_fail;
182 c->operation_success = 0;
183 while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
184 pa_threaded_mainloop_wait(c->mainloop);
185 CHECK_DEAD_GOTO(c, unlock_and_fail);
188 if (!c->operation_success) {
189 GST_WARNING("Failed to get sink info: %s", pa_strerror(pa_context_errno(c->context)));
190 goto unlock_and_fail;
193 pa_operation_unref(o);
194 o = NULL;
197 c->devices_valid = 1;
199 pa_threaded_mainloop_unlock(c->mainloop);
201 return TRUE;
203 unlock_and_fail:
205 if (o)
206 pa_operation_unref(o);
208 pa_threaded_mainloop_unlock(c->mainloop);
210 return FALSE;
213 static void gst_pulseprobe_close(GstPulseProbe *c) {
214 g_assert(c);
216 if (c->mainloop)
217 pa_threaded_mainloop_stop(c->mainloop);
219 if (c->context) {
220 pa_context_disconnect(c->context);
221 pa_context_unref(c->context);
222 c->context = NULL;
225 if (c->mainloop) {
226 pa_threaded_mainloop_free(c->mainloop);
227 c->mainloop = NULL;
231 GstPulseProbe* gst_pulseprobe_new(GObjectClass *klass, guint prop_id, const gchar *server, gboolean sinks, gboolean sources) {
232 GstPulseProbe *c = NULL;
234 c = g_new(GstPulseProbe, 1);
235 c->server = g_strdup(server);
236 c->enumerate_sinks = sinks;
237 c->enumerate_sources = sources;
239 c->mainloop = NULL;
240 c->context = NULL;
242 c->prop_id = prop_id;
243 c->properties = g_list_append(NULL, g_object_class_find_property(klass, "device"));
244 c->devices = NULL;
245 c->devices_valid = 0;
247 return c;
250 void gst_pulseprobe_free(GstPulseProbe* c) {
251 g_assert(c);
253 gst_pulseprobe_close(c);
255 g_list_free(c->properties);
256 g_free(c->server);
258 g_list_foreach(c->devices, (GFunc) g_free, NULL);
259 g_list_free(c->devices);
261 g_free(c);
264 const GList* gst_pulseprobe_get_properties(GstPulseProbe *c) {
265 return c->properties;
268 gboolean gst_pulseprobe_needs_probe(GstPulseProbe *c, guint prop_id, const GParamSpec *pspec) {
270 if (prop_id == c->prop_id)
271 return !c->devices_valid;
273 G_OBJECT_WARN_INVALID_PROPERTY_ID(c, prop_id, pspec);
274 return FALSE;
277 void gst_pulseprobe_probe_property(GstPulseProbe *c, guint prop_id, const GParamSpec *pspec) {
279 if (prop_id != c->prop_id) {
280 G_OBJECT_WARN_INVALID_PROPERTY_ID(c, prop_id, pspec);
281 return;
284 if (gst_pulseprobe_open(c)) {
285 gst_pulseprobe_enumerate(c);
286 gst_pulseprobe_close(c);
290 GValueArray *gst_pulseprobe_get_values(GstPulseProbe *c, guint prop_id, const GParamSpec *pspec) {
291 GValueArray *array;
292 GValue value = { 0 };
293 GList *item;
295 if (prop_id != c->prop_id) {
296 G_OBJECT_WARN_INVALID_PROPERTY_ID(c, prop_id, pspec);
297 return NULL;
300 if (!c->devices_valid)
301 return NULL;
303 array = g_value_array_new(g_list_length(c->devices));
304 g_value_init(&value, G_TYPE_STRING);
305 for (item = c->devices; item != NULL; item = item->next) {
306 GST_WARNING("device found: %s", (const gchar *) item->data);
307 g_value_set_string(&value, (const gchar *) item->data);
308 g_value_array_append(array, &value);
310 g_value_unset (&value);
312 return array;
315 void gst_pulseprobe_set_server(GstPulseProbe *c, const gchar *server) {
316 g_assert(c);
318 gst_pulseprobe_invalidate(c);
320 g_free(c->server);
321 c->server = g_strdup(server);