globaldevicemonitor: update for new message API
[platform/upstream/gstreamer.git] / gst / gstglobaldevicemonitor.c
1 /* GStreamer
2  * Copyright (C) 2013 Olivier Crete <olivier.crete@collabora.com>
3  *
4  * gstglobaldevicemonitor.c: Global device monitor
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 <gst/gstglobaldevicemonitor.h>
27
28 #include "gst/gst_private.h"
29 #include <gst/gst.h>
30
31 struct _GstGlobalDeviceMonitorPrivate
32 {
33   gboolean started;
34
35   GstBus *bus;
36
37   GPtrArray *monitors;
38   guint cookie;
39
40   GstCaps *caps;
41   GstDeviceMonitorFactoryListType type;
42 };
43
44
45 G_DEFINE_TYPE (GstGlobalDeviceMonitor, gst_global_device_monitor,
46     GST_TYPE_OBJECT);
47
48 static void gst_global_device_monitor_dispose (GObject * object);
49
50 static void
51 gst_global_device_monitor_class_init (GstGlobalDeviceMonitorClass * klass)
52 {
53   GObjectClass *object_class = G_OBJECT_CLASS (klass);
54
55   g_type_class_add_private (klass, sizeof (GstGlobalDeviceMonitorPrivate));
56
57   object_class->dispose = gst_global_device_monitor_dispose;
58 }
59
60 static void
61 bus_sync_message (GstBus * bus, GstMessage * message,
62     GstGlobalDeviceMonitor * monitor)
63 {
64   GstMessageType type = GST_MESSAGE_TYPE (message);
65
66   if (type == GST_MESSAGE_DEVICE_ADDED || type == GST_MESSAGE_DEVICE_REMOVED) {
67     gboolean intersects;
68     GstCaps *caps;
69     GstDevice *device;
70
71     if (type == GST_MESSAGE_DEVICE_ADDED)
72       gst_message_parse_device_added (message, &device);
73     else
74       gst_message_parse_device_removed (message, &device);
75
76     GST_OBJECT_LOCK (monitor);
77     caps = gst_device_get_caps (device);
78     intersects = gst_caps_can_intersect (monitor->priv->caps, caps);
79     gst_caps_unref (caps);
80     GST_OBJECT_UNLOCK (monitor);
81
82     if (intersects)
83       gst_bus_post (monitor->priv->bus, gst_message_ref (message));
84   }
85 }
86
87
88 static void
89 gst_global_device_monitor_init (GstGlobalDeviceMonitor * self)
90 {
91   GList *factories;
92
93   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
94       GST_TYPE_GLOBAL_DEVICE_MONITOR, GstGlobalDeviceMonitorPrivate);
95
96   self->priv->bus = gst_bus_new ();
97   gst_bus_set_flushing (self->priv->bus, TRUE);
98
99   self->priv->monitors = g_ptr_array_new ();
100   self->priv->caps = gst_caps_new_any ();
101   self->priv->type = GST_DEVICE_MONITOR_FACTORY_TYPE_SINK |
102       GST_DEVICE_MONITOR_FACTORY_TYPE_SRC;
103
104   factories =
105       gst_device_monitor_factory_list_get_device_monitors (self->priv->type, 1);
106
107   while (factories) {
108     GstDeviceMonitorFactory *factory = factories->data;
109     GstDeviceMonitor *monitor;
110
111     factories = g_list_remove (factories, factory);
112
113     monitor = gst_device_monitor_factory_get (factory);
114     if (monitor) {
115       GstBus *bus = gst_device_monitor_get_bus (monitor);
116
117       gst_bus_enable_sync_message_emission (bus);
118       g_signal_connect (monitor, "sync-message",
119           G_CALLBACK (bus_sync_message), self);
120       g_ptr_array_add (self->priv->monitors, monitor);
121     }
122
123     gst_object_unref (factory);
124   }
125 }
126
127
128 static void
129 gst_global_device_monitor_remove (GstGlobalDeviceMonitor * self, guint i)
130 {
131   GstDeviceMonitor *monitor = g_ptr_array_index (self->priv->monitors, i);
132   GstBus *bus;
133
134   g_ptr_array_remove_index_fast (self->priv->monitors, i);
135
136   bus = gst_device_monitor_get_bus (monitor);
137   g_signal_handlers_disconnect_by_func (bus, bus_sync_message, self);
138   gst_object_unref (bus);
139
140   gst_object_unref (monitor);
141 }
142
143 static void
144 gst_global_device_monitor_dispose (GObject * object)
145 {
146   GstGlobalDeviceMonitor *self = GST_GLOBAL_DEVICE_MONITOR (object);
147
148   g_return_if_fail (self->priv->started == FALSE);
149
150   if (self->priv->monitors) {
151     while (self->priv->monitors->len)
152       gst_global_device_monitor_remove (self, self->priv->monitors->len - 1);
153     g_ptr_array_unref (self->priv->monitors);
154     self->priv->monitors = NULL;
155   }
156
157   gst_caps_replace (&self->priv->caps, NULL);
158   gst_object_replace ((GstObject **) & self->priv->bus, NULL);
159
160   G_OBJECT_CLASS (gst_global_device_monitor_parent_class)->dispose (object);
161 }
162
163 /**
164  * gst_global_device_monitor_get_devices:
165  * @monitor: A #GstDeviceMonitor
166  *
167  * Gets a list of devices from all of the relevant monitors. This may actually
168  * probe the hardware if the global monitor is not currently started.
169  *
170  * Returns: (transfer full) (element-type GstDevice): a #GList of
171  *   #GstDevice
172  */
173
174 GList *
175 gst_global_device_monitor_get_devices (GstGlobalDeviceMonitor * self)
176 {
177   GList *devices = NULL;
178   guint i;
179   guint cookie;
180
181   g_return_val_if_fail (GST_IS_GLOBAL_DEVICE_MONITOR (self), NULL);
182
183   GST_OBJECT_LOCK (self);
184
185 again:
186
187   g_list_free_full (devices, gst_object_unref);
188   devices = NULL;
189
190   cookie = self->priv->cookie;
191
192   for (i = 0; i < self->priv->monitors->len; i++) {
193     GList *tmpdev;
194     GstDeviceMonitor *monitor =
195         gst_object_ref (g_ptr_array_index (self->priv->monitors, i));
196     GList *item;
197
198     GST_OBJECT_UNLOCK (self);
199
200     tmpdev = gst_device_monitor_get_devices (monitor);
201
202     for (item = tmpdev; item; item = item->next) {
203       GstDevice *dev = GST_DEVICE (item->data);
204       GstCaps *caps = gst_device_get_caps (dev);
205
206       if (gst_caps_can_intersect (self->priv->caps, caps))
207         devices = g_list_prepend (devices, gst_object_ref (dev));
208       gst_caps_unref (caps);
209     }
210
211     g_list_free_full (tmpdev, gst_object_unref);
212     gst_object_unref (monitor);
213
214     GST_OBJECT_LOCK (self);
215
216     if (self->priv->cookie != cookie)
217       goto again;
218   }
219
220   GST_OBJECT_UNLOCK (self);
221
222   return devices;
223 }
224
225 /**
226  * gst_global_device_monitor_start:
227  * @monitor: A #GstGlobalDeviceMonitor
228  *
229  * Starts monitoring the devices, one this has succeeded, the
230  * #GstGlobalDeviceMonitor:added and #GstGlobalDeviceMonitor:removed
231  * signals will be emitted when the list of devices changes.
232  *
233  * Returns: %TRUE if the device monitoring could be started
234  */
235
236 gboolean
237 gst_global_device_monitor_start (GstGlobalDeviceMonitor * self)
238 {
239   guint i;
240
241   g_return_val_if_fail (GST_IS_GLOBAL_DEVICE_MONITOR (self), FALSE);
242
243   GST_OBJECT_LOCK (self);
244
245   if (self->priv->monitors->len == 0) {
246     GST_OBJECT_UNLOCK (self);
247     return FALSE;
248   }
249
250   gst_bus_set_flushing (self->priv->bus, FALSE);
251
252   for (i = 0; i < self->priv->monitors->len; i++) {
253     if (!gst_device_monitor_start (g_ptr_array_index (self->priv->monitors, i))) {
254       gst_bus_set_flushing (self->priv->bus, TRUE);
255
256       for (; i != 0; i--)
257         gst_device_monitor_stop (g_ptr_array_index (self->priv->monitors,
258                 i - 1));
259
260       GST_OBJECT_UNLOCK (self);
261       return FALSE;
262     }
263   }
264
265   self->priv->started = TRUE;
266   GST_OBJECT_UNLOCK (self);
267
268   return TRUE;
269 }
270
271 /**
272  * gst_global_device_monitor_stop:
273  * @monitor: A #GstDeviceMonitor
274  *
275  * Stops monitoring the devices.
276  */
277
278 void
279 gst_global_device_monitor_stop (GstGlobalDeviceMonitor * self)
280 {
281   guint i;
282
283   g_return_if_fail (GST_IS_GLOBAL_DEVICE_MONITOR (self));
284
285   gst_bus_set_flushing (self->priv->bus, TRUE);
286
287   GST_OBJECT_LOCK (self);
288   for (i = 0; i < self->priv->monitors->len; i++)
289     gst_device_monitor_stop (g_ptr_array_index (self->priv->monitors, i));
290   self->priv->started = FALSE;
291   GST_OBJECT_UNLOCK (self);
292
293 }
294
295 void
296 gst_global_device_monitor_set_type_filter (GstGlobalDeviceMonitor * self,
297     GstDeviceMonitorFactoryListType type)
298 {
299   GList *factories = NULL;
300   guint i;
301
302   g_return_if_fail (GST_IS_GLOBAL_DEVICE_MONITOR (self));
303   g_return_if_fail (!self->priv->started);
304   g_return_if_fail (type &
305       (GST_DEVICE_MONITOR_FACTORY_TYPE_SINK |
306           GST_DEVICE_MONITOR_FACTORY_TYPE_SRC));
307
308   GST_OBJECT_LOCK (self);
309   if (self->priv->type == type) {
310     GST_OBJECT_UNLOCK (self);
311     return;
312   }
313
314   self->priv->type = type;
315
316   factories =
317       gst_device_monitor_factory_list_get_device_monitors (self->priv->type, 1);
318
319   for (i = 0; i < self->priv->monitors->len; i++) {
320     GstDeviceMonitor *monitor = g_ptr_array_index (self->priv->monitors, i);
321     GstDeviceMonitorFactory *f = gst_device_monitor_get_factory (monitor);
322     GList *item;
323
324     item = g_list_find (factories, f);
325
326     if (item) {
327       /* If the item is in our list, then remove it from the list of factories,
328        * we don't have it to re-create it later
329        */
330       factories = g_list_remove_link (factories, item);
331       gst_object_unref (f);
332     } else {
333       /* If it's not in our list, them remove it from the list of monitors.
334        */
335
336       self->priv->cookie++;
337       gst_global_device_monitor_remove (self, i);
338       i--;
339     }
340   }
341
342   while (factories) {
343     GstDeviceMonitorFactory *factory = factories->data;
344     GstDeviceMonitor *monitor;
345
346     factories = g_list_remove (factories, factory);
347
348     monitor = gst_device_monitor_factory_get (factory);
349     if (monitor) {
350       GstBus *bus = gst_device_monitor_get_bus (monitor);
351
352       gst_bus_enable_sync_message_emission (bus);
353       g_signal_connect (bus, "sync-message",
354           G_CALLBACK (bus_sync_message), self);
355       gst_object_unref (bus);
356       g_ptr_array_add (self->priv->monitors, monitor);
357       self->priv->cookie++;
358     }
359
360     gst_object_unref (factory);
361   }
362
363   GST_OBJECT_UNLOCK (self);
364 }
365
366 GstDeviceMonitorFactoryListType
367 gst_global_device_monitor_get_type_filter (GstGlobalDeviceMonitor * self)
368 {
369   GstDeviceMonitorFactoryListType res;
370
371   g_return_val_if_fail (GST_IS_GLOBAL_DEVICE_MONITOR (self), 0);
372
373   GST_OBJECT_LOCK (self);
374   res = self->priv->type;
375   GST_OBJECT_UNLOCK (self);
376
377   return res;
378 }
379
380 void
381 gst_global_device_monitor_set_caps_filter (GstGlobalDeviceMonitor * self,
382     GstCaps * caps)
383 {
384   g_return_if_fail (GST_IS_GLOBAL_DEVICE_MONITOR (self));
385   g_return_if_fail (GST_IS_CAPS (caps));
386
387   GST_OBJECT_LOCK (self);
388   gst_caps_replace (&self->priv->caps, caps);
389   GST_OBJECT_UNLOCK (self);
390 }
391
392 GstCaps *
393 gst_global_device_monitor_get_caps_filter (GstGlobalDeviceMonitor * self)
394 {
395   GstCaps *res;
396
397   g_return_val_if_fail (GST_IS_GLOBAL_DEVICE_MONITOR (self), NULL);
398
399   GST_OBJECT_LOCK (self);
400   res = gst_caps_ref (self->priv->caps);
401   GST_OBJECT_UNLOCK (self);
402
403   return res;
404 }
405
406 GstGlobalDeviceMonitor *
407 gst_global_device_monitor_new (void)
408 {
409   return g_object_new (GST_TYPE_GLOBAL_DEVICE_MONITOR, NULL);
410 }
411
412 /**
413  * gst_global_device_monitor_get_bus:
414  * @monitor: a #GstDeviceMonitor
415  *
416  * Gets the #GstBus of this #GstGlobalDeviceMonitor
417  *
418  * Returns: (transfer full): a #GstBus
419  */
420 GstBus *
421 gst_global_device_monitor_get_bus (GstGlobalDeviceMonitor * monitor)
422 {
423   g_return_val_if_fail (GST_IS_GLOBAL_DEVICE_MONITOR (monitor), NULL);
424
425   return gst_object_ref (monitor->priv->bus);
426 }