af4db6daafebd1b22b08502e3d8a877b53df7f47
[platform/upstream/gst-plugins-good.git] / ext / pulse / pulsedevicemonitor.c
1 /* GStreamer
2  * Copyright (C) 2012 Olivier Crete <olivier.crete@collabora.com>
3  *
4  * gstv4l2devicemonitor.c: V4l2 device probing and monitoring
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "pulsedevicemonitor.h"
27
28 #include <string.h>
29
30 #include <gst/gst.h>
31
32 #include "pulsesrc.h"
33 #include "pulsesink.h"
34 #include "pulseutil.h"
35
36
37 GST_DEBUG_CATEGORY_EXTERN (pulse_debug);
38 #define GST_CAT_DEFAULT pulse_debug
39
40
41 static GstDevice *gst_pulse_device_new (guint id,
42     const gchar * device_name, GstCaps * caps, const gchar * internal_name,
43     GstPulseDeviceType type);
44
45 G_DEFINE_TYPE (GstPulseDeviceMonitor, gst_pulse_device_monitor,
46     GST_TYPE_DEVICE_MONITOR);
47
48 static void gst_pulse_device_monitor_finalize (GObject * object);
49 static void gst_pulse_device_monitor_set_property (GObject * object,
50     guint prop_id, const GValue * value, GParamSpec * pspec);
51 static void gst_pulse_device_monitor_get_property (GObject * object,
52     guint prop_id, GValue * value, GParamSpec * pspec);
53
54
55 static GList *gst_pulse_device_monitor_probe (GstDeviceMonitor * monitor);
56 static gboolean gst_pulse_device_monitor_start (GstDeviceMonitor * monitor);
57 static void gst_pulse_device_monitor_stop (GstDeviceMonitor * monitor);
58
59 enum
60 {
61   PROP_0,
62   PROP_SERVER,
63   PROP_CLIENT_NAME,
64   PROP_LAST
65 };
66
67
68 static void
69 gst_pulse_device_monitor_class_init (GstPulseDeviceMonitorClass * klass)
70 {
71   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
72   GstDeviceMonitorClass *dm_class = GST_DEVICE_MONITOR_CLASS (klass);
73   gchar *client_name;
74
75   gobject_class->set_property = gst_pulse_device_monitor_set_property;
76   gobject_class->get_property = gst_pulse_device_monitor_get_property;
77   gobject_class->finalize = gst_pulse_device_monitor_finalize;
78
79   dm_class->probe = gst_pulse_device_monitor_probe;
80   dm_class->start = gst_pulse_device_monitor_start;
81   dm_class->stop = gst_pulse_device_monitor_stop;
82
83   g_object_class_install_property (gobject_class,
84       PROP_SERVER,
85       g_param_spec_string ("server", "Server",
86           "The PulseAudio server to connect to", NULL,
87           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
88
89   client_name = gst_pulse_client_name ();
90   g_object_class_install_property (gobject_class,
91       PROP_CLIENT_NAME,
92       g_param_spec_string ("client-name", "Client Name",
93           "The PulseAudio client_name_to_use", client_name,
94           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
95           GST_PARAM_MUTABLE_READY));
96   g_free (client_name);
97
98   gst_device_monitor_class_set_static_metadata (dm_class,
99       "PulseAudio Device Monitor", "Sink/Source/Audio",
100       "List and monitor PulseAudio source and sink devices",
101       "Olivier Crete <olivier.crete@collabora.com>");
102 }
103
104 static void
105 gst_pulse_device_monitor_init (GstPulseDeviceMonitor * self)
106 {
107   self->client_name = gst_pulse_client_name ();
108 }
109
110 static void
111 gst_pulse_device_monitor_finalize (GObject * object)
112 {
113   GstPulseDeviceMonitor *self = GST_PULSE_DEVICE_MONITOR (object);
114
115   g_free (self->client_name);
116   g_free (self->server);
117
118   G_OBJECT_CLASS (gst_pulse_device_monitor_parent_class)->finalize (object);
119 }
120
121
122 static void
123 gst_pulse_device_monitor_set_property (GObject * object,
124     guint prop_id, const GValue * value, GParamSpec * pspec)
125 {
126   GstPulseDeviceMonitor *self = GST_PULSE_DEVICE_MONITOR (object);
127
128   switch (prop_id) {
129     case PROP_SERVER:
130       g_free (self->server);
131       self->server = g_value_dup_string (value);
132       break;
133     case PROP_CLIENT_NAME:
134       g_free (self->client_name);
135       if (!g_value_get_string (value)) {
136         GST_WARNING_OBJECT (self,
137             "Empty PulseAudio client name not allowed. "
138             "Resetting to default value");
139         self->client_name = gst_pulse_client_name ();
140       } else
141         self->client_name = g_value_dup_string (value);
142       break;
143     default:
144       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
145       break;
146   }
147 }
148
149 static void
150 gst_pulse_device_monitor_get_property (GObject * object,
151     guint prop_id, GValue * value, GParamSpec * pspec)
152 {
153   GstPulseDeviceMonitor *self = GST_PULSE_DEVICE_MONITOR (object);
154
155   switch (prop_id) {
156     case PROP_SERVER:
157       g_value_set_string (value, self->server);
158       break;
159     case PROP_CLIENT_NAME:
160       g_value_set_string (value, self->client_name);
161       break;
162     default:
163       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
164       break;
165   }
166 }
167
168 static void
169 context_state_cb (pa_context * c, void *userdata)
170 {
171   GstPulseDeviceMonitor *self = userdata;
172
173   switch (pa_context_get_state (c)) {
174     case PA_CONTEXT_READY:
175     case PA_CONTEXT_TERMINATED:
176     case PA_CONTEXT_FAILED:
177       pa_threaded_mainloop_signal (self->mainloop, 0);
178       break;
179
180     case PA_CONTEXT_UNCONNECTED:
181     case PA_CONTEXT_CONNECTING:
182     case PA_CONTEXT_AUTHORIZING:
183     case PA_CONTEXT_SETTING_NAME:
184       break;
185   }
186 }
187
188 static GstDevice *
189 new_source (const pa_source_info * info)
190 {
191   GstCaps *caps;
192   guint i;
193
194   caps = gst_caps_new_empty ();
195
196   for (i = 0; i < info->n_formats; i++)
197     gst_caps_append (caps, gst_pulse_format_info_to_caps (info->formats[i]));
198
199   return gst_pulse_device_new (info->index, info->description,
200       caps, info->name, GST_PULSE_DEVICE_TYPE_SOURCE);
201 }
202
203 static GstDevice *
204 new_sink (const pa_sink_info * info)
205 {
206   GstCaps *caps;
207   guint i;
208
209   caps = gst_caps_new_empty ();
210
211   for (i = 0; i < info->n_formats; i++)
212     gst_caps_append (caps, gst_pulse_format_info_to_caps (info->formats[i]));
213
214   return gst_pulse_device_new (info->index, info->description,
215       caps, info->name, GST_PULSE_DEVICE_TYPE_SINK);
216 }
217
218 static void
219 get_source_info_cb (pa_context * context,
220     const pa_source_info * info, int eol, void *userdata)
221 {
222   GstPulseDeviceMonitor *self = userdata;
223   GstDevice *dev;
224
225   if (eol) {
226     pa_threaded_mainloop_signal (self->mainloop, 0);
227     return;
228   }
229
230   dev = new_source (info);
231
232   if (dev)
233     gst_device_monitor_device_add (GST_DEVICE_MONITOR (self), dev);
234 }
235
236 static void
237 get_sink_info_cb (pa_context * context,
238     const pa_sink_info * info, int eol, void *userdata)
239 {
240   GstPulseDeviceMonitor *self = userdata;
241   GstDevice *dev;
242
243   if (eol) {
244     pa_threaded_mainloop_signal (self->mainloop, 0);
245     return;
246   }
247
248   dev = new_sink (info);
249
250   if (dev)
251     gst_device_monitor_device_add (GST_DEVICE_MONITOR (self), dev);
252 }
253
254 static void
255 context_subscribe_cb (pa_context * context, pa_subscription_event_type_t type,
256     uint32_t idx, void *userdata)
257 {
258   GstPulseDeviceMonitor *self = userdata;
259   GstDeviceMonitor *monitor = userdata;
260   pa_subscription_event_type_t facility =
261       type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK;
262   pa_subscription_event_type_t event_type =
263       type & PA_SUBSCRIPTION_EVENT_TYPE_MASK;
264
265   if (facility != PA_SUBSCRIPTION_EVENT_SOURCE &&
266       facility != PA_SUBSCRIPTION_EVENT_SINK)
267     return;
268
269   if (event_type == PA_SUBSCRIPTION_EVENT_NEW) {
270     /* Microphone in the source output has changed */
271
272     if (facility == PA_SUBSCRIPTION_EVENT_SOURCE)
273       pa_context_get_source_info_by_index (context, idx, get_source_info_cb,
274           self);
275     else if (facility == PA_SUBSCRIPTION_EVENT_SINK)
276       pa_context_get_sink_info_by_index (context, idx, get_sink_info_cb, self);
277   } else if (event_type == PA_SUBSCRIPTION_EVENT_REMOVE) {
278     GstPulseDevice *dev = NULL;
279     GList *item;
280
281     GST_OBJECT_LOCK (self);
282     for (item = monitor->devices; item; item = item->next) {
283       dev = item->data;
284
285       if (dev->device_index == idx) {
286         gst_object_ref (dev);
287         break;
288       }
289       dev = NULL;
290     }
291     GST_OBJECT_UNLOCK (self);
292
293     if (dev) {
294       gst_device_monitor_device_remove (GST_DEVICE_MONITOR (self),
295           GST_DEVICE (dev));
296       gst_object_unref (dev);
297     }
298   }
299 }
300
301 static void
302 get_source_info_list_cb (pa_context * context, const pa_source_info * info,
303     int eol, void *userdata)
304 {
305   GList **devices = userdata;
306
307   if (eol)
308     return;
309
310   *devices = g_list_prepend (*devices, gst_object_ref_sink (new_source (info)));
311 }
312
313 static void
314 get_sink_info_list_cb (pa_context * context, const pa_sink_info * info,
315     int eol, void *userdata)
316 {
317   GList **devices = userdata;
318
319   if (eol)
320     return;
321
322   *devices = g_list_prepend (*devices, gst_object_ref_sink (new_sink (info)));
323 }
324
325 static GList *
326 gst_pulse_device_monitor_probe (GstDeviceMonitor * monitor)
327 {
328   GstPulseDeviceMonitor *self = GST_PULSE_DEVICE_MONITOR (monitor);
329   GList *devices = NULL;
330   pa_mainloop *m = NULL;
331   pa_context *c = NULL;
332   pa_operation *o;
333
334   if (!(m = pa_mainloop_new ()))
335     return NULL;
336
337   if (!(c = pa_context_new (pa_mainloop_get_api (m), self->client_name))) {
338     GST_ERROR_OBJECT (self, "Failed to create context");
339     goto failed;
340   }
341
342   if (pa_context_connect (c, self->server, 0, NULL) < 0) {
343     GST_ERROR_OBJECT (self, "Failed to connect: %s",
344         pa_strerror (pa_context_errno (self->context)));
345     goto failed;
346   }
347
348   for (;;) {
349     pa_context_state_t state;
350
351     state = pa_context_get_state (c);
352
353     if (!PA_CONTEXT_IS_GOOD (state)) {
354       GST_ELEMENT_ERROR (self, RESOURCE, FAILED, ("Failed to connect: %s",
355               pa_strerror (pa_context_errno (c))), (NULL));
356       goto failed;
357     }
358
359     if (state == PA_CONTEXT_READY)
360       break;
361
362     /* Wait until the context is ready */
363     if (pa_mainloop_iterate (m, TRUE, NULL) < 0)
364       goto failed;
365
366   }
367   GST_DEBUG_OBJECT (self, "connected");
368
369   o = pa_context_get_sink_info_list (c, get_sink_info_list_cb, &devices);
370   while (pa_operation_get_state (o) == PA_OPERATION_RUNNING &&
371       pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
372     if (pa_mainloop_iterate (m, TRUE, NULL) < 0)
373       break;
374   }
375   pa_operation_unref (o);
376
377   o = pa_context_get_source_info_list (c, get_source_info_list_cb, &devices);
378   while (pa_operation_get_state (o) == PA_OPERATION_RUNNING &&
379       pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
380     if (pa_mainloop_iterate (m, TRUE, NULL) < 0)
381       break;
382   }
383   pa_operation_unref (o);
384
385   pa_context_disconnect (c);
386   pa_mainloop_free (m);
387
388   return devices;
389
390 failed:
391
392   return NULL;
393 }
394
395 static gboolean
396 gst_pulse_device_monitor_start (GstDeviceMonitor * monitor)
397 {
398   GstPulseDeviceMonitor *self = GST_PULSE_DEVICE_MONITOR (monitor);
399   pa_operation *initial_operation;
400
401   if (!(self->mainloop = pa_threaded_mainloop_new ())) {
402     GST_ERROR_OBJECT (self, "Could not create pulseaudio mainloop");
403     goto mainloop_failed;
404   }
405   if (pa_threaded_mainloop_start (self->mainloop) < 0) {
406     GST_ERROR_OBJECT (self, "Could not start pulseaudio mainloop");
407     pa_threaded_mainloop_free (self->mainloop);
408     self->mainloop = NULL;
409     goto mainloop_failed;
410   }
411
412   pa_threaded_mainloop_lock (self->mainloop);
413
414   if (!(self->context =
415           pa_context_new (pa_threaded_mainloop_get_api (self->mainloop),
416               self->client_name))) {
417     GST_ERROR_OBJECT (self, "Failed to create context");
418     goto unlock_and_fail;
419   }
420
421   pa_context_set_state_callback (self->context, context_state_cb, self);
422   pa_context_set_subscribe_callback (self->context, context_subscribe_cb, self);
423
424
425   GST_DEBUG_OBJECT (self, "connect to server %s", GST_STR_NULL (self->server));
426
427   if (pa_context_connect (self->context, self->server, 0, NULL) < 0) {
428     GST_ERROR_OBJECT (self, "Failed to connect: %s",
429         pa_strerror (pa_context_errno (self->context)));
430     goto unlock_and_fail;
431   }
432
433   for (;;) {
434     pa_context_state_t state;
435
436     state = pa_context_get_state (self->context);
437
438     if (!PA_CONTEXT_IS_GOOD (state)) {
439       GST_ERROR_OBJECT (self, "Failed to connect: %s",
440           pa_strerror (pa_context_errno (self->context)));
441       goto unlock_and_fail;
442     }
443
444     if (state == PA_CONTEXT_READY)
445       break;
446
447     /* Wait until the context is ready */
448     pa_threaded_mainloop_wait (self->mainloop);
449   }
450   GST_DEBUG_OBJECT (self, "connected");
451
452   pa_context_subscribe (self->context,
453       PA_SUBSCRIPTION_MASK_SOURCE | PA_SUBSCRIPTION_MASK_SINK, NULL, NULL);
454
455   initial_operation = pa_context_get_source_info_list (self->context,
456       get_source_info_cb, self);
457   while (pa_operation_get_state (initial_operation) == PA_OPERATION_RUNNING) {
458     if (!PA_CONTEXT_IS_GOOD (pa_context_get_state ((self->context))))
459       goto cancel_and_fail;
460
461     pa_threaded_mainloop_wait (self->mainloop);
462   }
463   pa_operation_unref (initial_operation);
464
465   initial_operation = pa_context_get_sink_info_list (self->context,
466       get_sink_info_cb, self);
467   if (!initial_operation)
468     goto unlock_and_fail;
469   while (pa_operation_get_state (initial_operation) == PA_OPERATION_RUNNING) {
470     if (!PA_CONTEXT_IS_GOOD (pa_context_get_state ((self->context))))
471       goto cancel_and_fail;
472
473     pa_threaded_mainloop_wait (self->mainloop);
474   }
475   pa_operation_unref (initial_operation);
476
477   pa_threaded_mainloop_unlock (self->mainloop);
478
479   return TRUE;
480
481 unlock_and_fail:
482   pa_threaded_mainloop_unlock (self->mainloop);
483   gst_pulse_device_monitor_stop (monitor);
484   return FALSE;
485
486 mainloop_failed:
487   return FALSE;
488
489 cancel_and_fail:
490   pa_operation_cancel (initial_operation);
491   pa_operation_unref (initial_operation);
492   goto unlock_and_fail;
493 }
494
495 static void
496 gst_pulse_device_monitor_stop (GstDeviceMonitor * monitor)
497 {
498   GstPulseDeviceMonitor *self = GST_PULSE_DEVICE_MONITOR (monitor);
499
500   pa_threaded_mainloop_stop (self->mainloop);
501
502   if (self->context) {
503     pa_context_disconnect (self->context);
504
505     /* Make sure we don't get any further callbacks */
506     pa_context_set_state_callback (self->context, NULL, NULL);
507     pa_context_set_subscribe_callback (self->context, NULL, NULL);
508
509     pa_context_unref (self->context);
510     self->context = NULL;
511   }
512
513   pa_threaded_mainloop_free (self->mainloop);
514   self->mainloop = NULL;
515 }
516
517 enum
518 {
519   PROP_INTERNAL_NAME = 1,
520 };
521
522 G_DEFINE_TYPE (GstPulseDevice, gst_pulse_device, GST_TYPE_DEVICE);
523
524 static void gst_pulse_device_get_property (GObject * object, guint prop_id,
525     GValue * value, GParamSpec * pspec);
526 static void gst_pulse_device_set_property (GObject * object, guint prop_id,
527     const GValue * value, GParamSpec * pspec);
528 static void gst_pulse_device_finalize (GObject * object);
529 static GstElement *gst_pulse_device_create_element (GstDevice * device,
530     const gchar * name);
531 static gboolean gst_pulse_device_reconfigure_element (GstDevice * device,
532     GstElement * element);
533
534 static void
535 gst_pulse_device_class_init (GstPulseDeviceClass * klass)
536 {
537   GstDeviceClass *dev_class = GST_DEVICE_CLASS (klass);
538   GObjectClass *object_class = G_OBJECT_CLASS (klass);
539
540   dev_class->create_element = gst_pulse_device_create_element;
541   dev_class->reconfigure_element = gst_pulse_device_reconfigure_element;
542
543   object_class->get_property = gst_pulse_device_get_property;
544   object_class->set_property = gst_pulse_device_set_property;
545   object_class->finalize = gst_pulse_device_finalize;
546
547   g_object_class_install_property (object_class, PROP_INTERNAL_NAME,
548       g_param_spec_string ("internal-name", "Internal PulseAudio device name",
549           "The internal name of the PulseAudio device", "",
550           G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
551 }
552
553 static void
554 gst_pulse_device_init (GstPulseDevice * device)
555 {
556 }
557
558 static void
559 gst_pulse_device_finalize (GObject * object)
560 {
561   GstPulseDevice *device = GST_PULSE_DEVICE (object);
562
563   g_free (device->internal_name);
564
565   G_OBJECT_CLASS (gst_pulse_device_parent_class)->finalize (object);
566 }
567
568 static GstElement *
569 gst_pulse_device_create_element (GstDevice * device, const gchar * name)
570 {
571   GstPulseDevice *pulse_dev = GST_PULSE_DEVICE (device);
572   GstElement *elem;
573
574   elem = gst_element_factory_make (pulse_dev->element, name);
575   g_object_set (elem, "device", pulse_dev->internal_name, NULL);
576
577   return elem;
578 }
579
580 static gboolean
581 gst_pulse_device_reconfigure_element (GstDevice * device, GstElement * element)
582 {
583   GstPulseDevice *pulse_dev = GST_PULSE_DEVICE (device);
584
585   if (!strcmp (pulse_dev->element, "pulsesrc")) {
586     if (!GST_IS_PULSESRC (element))
587       return FALSE;
588   } else if (!strcmp (pulse_dev->element, "pulsesink")) {
589     if (!GST_IS_PULSESINK (element))
590       return FALSE;
591   } else {
592     g_assert_not_reached ();
593   }
594
595   g_object_set (element, "device", pulse_dev->internal_name, NULL);
596
597   return TRUE;
598 }
599
600 static GstDevice *
601 gst_pulse_device_new (guint device_index, const gchar * device_name,
602     GstCaps * caps, const gchar * internal_name, GstPulseDeviceType type)
603 {
604   GstPulseDevice *gstdev;
605   const gchar *element;
606   const gchar *klass;
607
608   g_return_val_if_fail (device_name, NULL);
609   g_return_val_if_fail (internal_name, NULL);
610   g_return_val_if_fail (caps, NULL);
611
612
613   switch (type) {
614     case GST_PULSE_DEVICE_TYPE_SOURCE:
615       element = "pulsesrc";
616       klass = "Audio/Source";
617       break;
618     case GST_PULSE_DEVICE_TYPE_SINK:
619       element = "pulsesink";
620       klass = "Audio/Sink";
621       break;
622     default:
623       g_assert_not_reached ();
624       break;
625   }
626
627
628   gstdev = g_object_new (GST_TYPE_PULSE_DEVICE,
629       "display-name", device_name, "caps", caps, "klass", klass,
630       "internal-name", internal_name, NULL);
631
632   gstdev->device_index = device_index;
633   gstdev->element = element;
634
635   return GST_DEVICE (gstdev);
636 }
637
638
639 static void
640 gst_pulse_device_get_property (GObject * object, guint prop_id,
641     GValue * value, GParamSpec * pspec)
642 {
643   GstPulseDevice *device;
644
645   device = GST_PULSE_DEVICE_CAST (object);
646
647   switch (prop_id) {
648     case PROP_INTERNAL_NAME:
649       g_value_set_string (value, device->internal_name);
650       break;
651     default:
652       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
653       break;
654   }
655 }
656
657
658 static void
659 gst_pulse_device_set_property (GObject * object, guint prop_id,
660     const GValue * value, GParamSpec * pspec)
661 {
662   GstPulseDevice *device;
663
664   device = GST_PULSE_DEVICE_CAST (object);
665
666   switch (prop_id) {
667     case PROP_INTERNAL_NAME:
668       device->internal_name = g_value_dup_string (value);
669       break;
670     default:
671       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
672       break;
673   }
674 }