1
1
/* GStreamer
2
2
* Copyright (C) 2018 Nirbheek Chauhan <[email protected] >
3
+ * Copyright (C) 2021 Seungha Yang <[email protected] >
3
4
*
4
5
* This library is free software; you can redistribute it and/or
5
6
* modify it under the terms of the GNU Library General Public
23
24
24
25
#include "gstwasapidevice.h"
25
26
27
+ GST_DEBUG_CATEGORY_EXTERN (gst_wasapi_debug );
28
+ #define GST_CAT_DEFAULT gst_wasapi_debug
29
+
26
30
G_DEFINE_TYPE (GstWasapiDeviceProvider , gst_wasapi_device_provider ,
27
31
GST_TYPE_DEVICE_PROVIDER );
28
32
29
33
static void gst_wasapi_device_provider_finalize (GObject * object );
30
34
static GList * gst_wasapi_device_provider_probe (GstDeviceProvider * provider );
35
+ static gboolean gst_wasapi_device_provider_start (GstDeviceProvider * provider );
36
+ static void gst_wasapi_device_provider_stop (GstDeviceProvider * provider );
37
+
38
+ static HRESULT
39
+ gst_wasapi_device_provider_device_added (GstMMDeviceEnumerator * enumerator ,
40
+ LPCWSTR device_id , gpointer user_data );
41
+ static HRESULT
42
+ gst_wasapi_device_provider_device_removed (GstMMDeviceEnumerator * enumerator ,
43
+ LPCWSTR device_id , gpointer user_data );
44
+ static HRESULT
45
+ gst_wasapi_device_provider_default_device_changed (GstMMDeviceEnumerator *
46
+ enumerator , EDataFlow flow , ERole role , LPCWSTR device_id ,
47
+ gpointer user_data );
31
48
32
49
static void
33
50
gst_wasapi_device_provider_class_init (GstWasapiDeviceProviderClass * klass )
@@ -38,6 +55,8 @@ gst_wasapi_device_provider_class_init (GstWasapiDeviceProviderClass * klass)
38
55
gobject_class -> finalize = gst_wasapi_device_provider_finalize ;
39
56
40
57
dm_class -> probe = gst_wasapi_device_provider_probe ;
58
+ dm_class -> start = gst_wasapi_device_provider_start ;
59
+ dm_class -> stop = gst_wasapi_device_provider_stop ;
41
60
42
61
gst_device_provider_class_set_static_metadata (dm_class ,
43
62
"WASAPI (Windows Audio Session API) Device Provider" ,
@@ -46,15 +65,68 @@ gst_wasapi_device_provider_class_init (GstWasapiDeviceProviderClass * klass)
46
65
}
47
66
48
67
static void
49
- gst_wasapi_device_provider_init (GstWasapiDeviceProvider * provider )
68
+ gst_wasapi_device_provider_init (GstWasapiDeviceProvider * self )
50
69
{
51
- CoInitializeEx (NULL , COINIT_MULTITHREADED );
70
+ self -> enumerator = gst_mm_device_enumerator_new ();
71
+ }
72
+
73
+ static gboolean
74
+ gst_wasapi_device_provider_start (GstDeviceProvider * provider )
75
+ {
76
+ GstWasapiDeviceProvider * self = GST_WASAPI_DEVICE_PROVIDER (provider );
77
+ GstMMNotificationClientCallbacks callbacks = { NULL , };
78
+ GList * devices = NULL ;
79
+ GList * iter ;
80
+
81
+ if (!self -> enumerator ) {
82
+ GST_WARNING_OBJECT (self , "Enumerator wasn't configured" );
83
+ return FALSE;
84
+ }
85
+
86
+ callbacks .device_added = gst_wasapi_device_provider_device_added ;
87
+ callbacks .device_removed = gst_wasapi_device_provider_device_removed ;
88
+ callbacks .default_device_changed =
89
+ gst_wasapi_device_provider_default_device_changed ;
90
+
91
+ if (!gst_mm_device_enumerator_set_notification_callback (self -> enumerator ,
92
+ & callbacks , self )) {
93
+ GST_WARNING_OBJECT (self , "Failed to set callbacks" );
94
+ return FALSE;
95
+ }
96
+
97
+ /* baseclass will not call probe() once it's started, but we can get
98
+ * notification only add/remove or change case. To this manually */
99
+ devices = gst_wasapi_device_provider_probe (provider );
100
+ if (devices ) {
101
+ for (iter = devices ; iter ; iter = g_list_next (iter )) {
102
+ gst_device_provider_device_add (provider , GST_DEVICE (iter -> data ));
103
+ }
104
+
105
+ g_list_free (devices );
106
+ }
107
+
108
+ return TRUE;
109
+ }
110
+
111
+ static void
112
+ gst_wasapi_device_provider_stop (GstDeviceProvider * provider )
113
+ {
114
+ GstWasapiDeviceProvider * self = GST_WASAPI_DEVICE_PROVIDER (provider );
115
+
116
+ if (self -> enumerator ) {
117
+ gst_mm_device_enumerator_set_notification_callback (self -> enumerator ,
118
+ NULL , NULL );
119
+ }
52
120
}
53
121
54
122
static void
55
123
gst_wasapi_device_provider_finalize (GObject * object )
56
124
{
57
- CoUninitialize ();
125
+ GstWasapiDeviceProvider * self = GST_WASAPI_DEVICE_PROVIDER (object );
126
+
127
+ gst_clear_object (& self -> enumerator );
128
+
129
+ G_OBJECT_CLASS (gst_wasapi_device_provider_parent_class )-> finalize (object );
58
130
}
59
131
60
132
static GList *
@@ -63,12 +135,137 @@ gst_wasapi_device_provider_probe (GstDeviceProvider * provider)
63
135
GstWasapiDeviceProvider * self = GST_WASAPI_DEVICE_PROVIDER (provider );
64
136
GList * devices = NULL ;
65
137
66
- if (!gst_wasapi_util_get_devices (GST_OBJECT ( self ) , TRUE, & devices ))
138
+ if (!gst_wasapi_util_get_devices (self -> enumerator , TRUE, & devices ))
67
139
GST_ERROR_OBJECT (self , "Failed to enumerate devices" );
68
140
69
141
return devices ;
70
142
}
71
143
144
+ static gboolean
145
+ gst_wasapi_device_is_in_list (GList * list , GstDevice * device )
146
+ {
147
+ GList * iter ;
148
+ GstStructure * s ;
149
+ const gchar * device_id ;
150
+ gboolean found = FALSE;
151
+
152
+ s = gst_device_get_properties (device );
153
+ g_assert (s );
154
+
155
+ device_id = gst_structure_get_string (s , "device.strid" );
156
+ g_assert (device_id );
157
+
158
+ for (iter = list ; iter ; iter = g_list_next (iter )) {
159
+ GstStructure * other_s ;
160
+ const gchar * other_id ;
161
+
162
+ other_s = gst_device_get_properties (GST_DEVICE (iter -> data ));
163
+ g_assert (other_s );
164
+
165
+ other_id = gst_structure_get_string (other_s , "device.strid" );
166
+ g_assert (other_id );
167
+
168
+ if (g_ascii_strcasecmp (device_id , other_id ) == 0 ) {
169
+ found = TRUE;
170
+ }
171
+
172
+ gst_structure_free (other_s );
173
+ if (found )
174
+ break ;
175
+ }
176
+
177
+ gst_structure_free (s );
178
+
179
+ return found ;
180
+ }
181
+
182
+ static void
183
+ gst_wasapi_device_provider_update_devices (GstWasapiDeviceProvider * self )
184
+ {
185
+ GstDeviceProvider * provider = GST_DEVICE_PROVIDER_CAST (self );
186
+ GList * prev_devices = NULL ;
187
+ GList * new_devices = NULL ;
188
+ GList * to_add = NULL ;
189
+ GList * to_remove = NULL ;
190
+ GList * iter ;
191
+
192
+ GST_OBJECT_LOCK (self );
193
+ prev_devices = g_list_copy_deep (provider -> devices ,
194
+ (GCopyFunc ) gst_object_ref , NULL );
195
+ GST_OBJECT_UNLOCK (self );
196
+
197
+ new_devices = gst_wasapi_device_provider_probe (provider );
198
+
199
+ /* Ownership of GstDevice for gst_device_provider_device_add()
200
+ * and gst_device_provider_device_remove() is a bit complicated.
201
+ * Remove floating reference here for things to be clear */
202
+ for (iter = new_devices ; iter ; iter = g_list_next (iter ))
203
+ gst_object_ref_sink (iter -> data );
204
+
205
+ /* Check newly added devices */
206
+ for (iter = new_devices ; iter ; iter = g_list_next (iter )) {
207
+ if (!gst_wasapi_device_is_in_list (prev_devices , GST_DEVICE (iter -> data ))) {
208
+ to_add = g_list_prepend (to_add , gst_object_ref (iter -> data ));
209
+ }
210
+ }
211
+
212
+ /* Check removed device */
213
+ for (iter = prev_devices ; iter ; iter = g_list_next (iter )) {
214
+ if (!gst_wasapi_device_is_in_list (new_devices , GST_DEVICE (iter -> data ))) {
215
+ to_remove = g_list_prepend (to_remove , gst_object_ref (iter -> data ));
216
+ }
217
+ }
218
+
219
+ for (iter = to_remove ; iter ; iter = g_list_next (iter ))
220
+ gst_device_provider_device_remove (provider , GST_DEVICE (iter -> data ));
221
+
222
+ for (iter = to_add ; iter ; iter = g_list_next (iter ))
223
+ gst_device_provider_device_add (provider , GST_DEVICE (iter -> data ));
224
+
225
+ if (prev_devices )
226
+ g_list_free_full (prev_devices , (GDestroyNotify ) gst_object_unref );
227
+
228
+ if (to_add )
229
+ g_list_free_full (to_add , (GDestroyNotify ) gst_object_unref );
230
+
231
+ if (to_remove )
232
+ g_list_free_full (to_remove , (GDestroyNotify ) gst_object_unref );
233
+ }
234
+
235
+ static HRESULT
236
+ gst_wasapi_device_provider_device_added (GstMMDeviceEnumerator * enumerator ,
237
+ LPCWSTR device_id , gpointer user_data )
238
+ {
239
+ GstWasapiDeviceProvider * self = GST_WASAPI_DEVICE_PROVIDER (user_data );
240
+
241
+ gst_wasapi_device_provider_update_devices (self );
242
+
243
+ return S_OK ;
244
+ }
245
+
246
+ static HRESULT
247
+ gst_wasapi_device_provider_device_removed (GstMMDeviceEnumerator * enumerator ,
248
+ LPCWSTR device_id , gpointer user_data )
249
+ {
250
+ GstWasapiDeviceProvider * self = GST_WASAPI_DEVICE_PROVIDER (user_data );
251
+
252
+ gst_wasapi_device_provider_update_devices (self );
253
+
254
+ return S_OK ;
255
+ }
256
+
257
+ static HRESULT
258
+ gst_wasapi_device_provider_default_device_changed (GstMMDeviceEnumerator *
259
+ enumerator , EDataFlow flow , ERole role , LPCWSTR device_id ,
260
+ gpointer user_data )
261
+ {
262
+ GstWasapiDeviceProvider * self = GST_WASAPI_DEVICE_PROVIDER (user_data );
263
+
264
+ gst_wasapi_device_provider_update_devices (self );
265
+
266
+ return S_OK ;
267
+ }
268
+
72
269
/* GstWasapiDevice begins */
73
270
74
271
enum
0 commit comments