various: fix pad template ref leaks
[platform/upstream/gstreamer.git] / sys / wasapi / gstwasapisrc.c
1 /*
2  * Copyright (C) 2008 Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /**
21  * SECTION:element-wasapisrc
22  *
23  * Provides audio capture from the Windows Audio Session API available with
24  * Vista and newer.
25  *
26  * <refsect2>
27  * <title>Example pipelines</title>
28  * |[
29  * gst-launch-0.10 -v wasapisrc ! fakesink
30  * ]| Capture from the default audio device and render to fakesink.
31  * </refsect2>
32  */
33
34 #include "gstwasapisrc.h"
35 #include <gst/audio/gstaudioclock.h>
36
37 GST_DEBUG_CATEGORY_STATIC (gst_wasapi_src_debug);
38 #define GST_CAT_DEFAULT gst_wasapi_src_debug
39
40 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
41     GST_PAD_SRC,
42     GST_PAD_ALWAYS,
43     GST_STATIC_CAPS ("audio/x-raw-int, "
44         "width = (int) 16, "
45         "depth = (int) 16, "
46         "rate = (int) 8000, "
47         "channels = (int) 1, "
48         "signed = (boolean) TRUE, "
49         "endianness = (int) " G_STRINGIFY (G_BYTE_ORDER)));
50
51 static void gst_wasapi_src_dispose (GObject * object);
52 static void gst_wasapi_src_finalize (GObject * object);
53
54 static GstClock *gst_wasapi_src_provide_clock (GstElement * element);
55
56 static gboolean gst_wasapi_src_start (GstBaseSrc * src);
57 static gboolean gst_wasapi_src_stop (GstBaseSrc * src);
58 static gboolean gst_wasapi_src_query (GstBaseSrc * src, GstQuery * query);
59
60 static GstFlowReturn gst_wasapi_src_create (GstPushSrc * src, GstBuffer ** buf);
61
62 static GstClockTime gst_wasapi_src_get_time (GstClock * clock,
63     gpointer user_data);
64
65 GST_BOILERPLATE (GstWasapiSrc, gst_wasapi_src, GstPushSrc, GST_TYPE_PUSH_SRC);
66
67 static void
68 gst_wasapi_src_base_init (gpointer gclass)
69 {
70   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
71
72   gst_element_class_add_static_pad_template (element_class, &src_template);
73   gst_element_class_set_details_simple (element_class, "WasapiSrc",
74       "Source/Audio",
75       "Stream audio from an audio capture device through WASAPI",
76       "Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>");
77 }
78
79 static void
80 gst_wasapi_src_class_init (GstWasapiSrcClass * klass)
81 {
82   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
83   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
84   GstBaseSrcClass *gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
85   GstPushSrcClass *gstpushsrc_class = GST_PUSH_SRC_CLASS (klass);
86
87   gobject_class->dispose = gst_wasapi_src_dispose;
88   gobject_class->finalize = gst_wasapi_src_finalize;
89
90   gstelement_class->provide_clock = gst_wasapi_src_provide_clock;
91
92   gstbasesrc_class->start = gst_wasapi_src_start;
93   gstbasesrc_class->stop = gst_wasapi_src_stop;
94   gstbasesrc_class->query = gst_wasapi_src_query;
95
96   gstpushsrc_class->create = gst_wasapi_src_create;
97
98   GST_DEBUG_CATEGORY_INIT (gst_wasapi_src_debug, "wasapisrc",
99       0, "Windows audio session API source");
100 }
101
102 static void
103 gst_wasapi_src_init (GstWasapiSrc * self, GstWasapiSrcClass * gclass)
104 {
105   GstBaseSrc *basesrc = GST_BASE_SRC (self);
106
107   gst_base_src_set_format (basesrc, GST_FORMAT_TIME);
108   gst_base_src_set_live (basesrc, TRUE);
109
110   self->rate = 8000;
111   self->buffer_time = 20 * GST_MSECOND;
112   self->period_time = 20 * GST_MSECOND;
113   self->latency = GST_CLOCK_TIME_NONE;
114   self->samples_per_buffer = self->rate / (GST_SECOND / self->period_time);
115
116   self->start_time = GST_CLOCK_TIME_NONE;
117   self->next_time = GST_CLOCK_TIME_NONE;
118
119 #if GST_CHECK_VERSION(0, 10, 31) || (GST_CHECK_VERSION(0, 10, 30) && GST_VERSION_NANO > 0)
120   self->clock = gst_audio_clock_new_full ("GstWasapiSrcClock",
121       gst_wasapi_src_get_time, gst_object_ref (self),
122       (GDestroyNotify) gst_object_unref);
123 #else
124   self->clock = gst_audio_clock_new ("GstWasapiSrcClock",
125       gst_wasapi_src_get_time, self);
126 #endif
127
128   CoInitialize (NULL);
129 }
130
131 static void
132 gst_wasapi_src_dispose (GObject * object)
133 {
134   GstWasapiSrc *self = GST_WASAPI_SRC (object);
135
136   if (self->clock != NULL) {
137     gst_object_unref (self->clock);
138     self->clock = NULL;
139   }
140
141   G_OBJECT_CLASS (parent_class)->dispose (object);
142 }
143
144 static void
145 gst_wasapi_src_finalize (GObject * object)
146 {
147   GstWasapiSrc *self = GST_WASAPI_SRC (object);
148
149   CoUninitialize ();
150
151   G_OBJECT_CLASS (parent_class)->finalize (object);
152 }
153
154 static GstClock *
155 gst_wasapi_src_provide_clock (GstElement * element)
156 {
157   GstWasapiSrc *self = GST_WASAPI_SRC (element);
158   GstClock *clock;
159
160   GST_OBJECT_LOCK (self);
161
162   if (self->client_clock == NULL)
163     goto wrong_state;
164
165   clock = GST_CLOCK (gst_object_ref (self->clock));
166
167   GST_OBJECT_UNLOCK (self);
168   return clock;
169
170   /* ERRORS */
171 wrong_state:
172   {
173     GST_OBJECT_UNLOCK (self);
174     GST_DEBUG_OBJECT (self, "IAudioClock not acquired");
175     return NULL;
176   }
177 }
178
179 static gboolean
180 gst_wasapi_src_start (GstBaseSrc * src)
181 {
182   GstWasapiSrc *self = GST_WASAPI_SRC (src);
183   gboolean res = FALSE;
184   IAudioClient *client = NULL;
185   IAudioClock *client_clock = NULL;
186   guint64 client_clock_freq = 0;
187   IAudioCaptureClient *capture_client = NULL;
188   HRESULT hr;
189
190   if (!gst_wasapi_util_get_default_device_client (GST_ELEMENT (self),
191           TRUE, self->rate, self->buffer_time, self->period_time, 0, &client,
192           &self->latency))
193     goto beach;
194
195   hr = IAudioClient_GetService (client, &IID_IAudioClock, &client_clock);
196   if (hr != S_OK) {
197     GST_ERROR_OBJECT (self, "IAudioClient::GetService (IID_IAudioClock) "
198         "failed");
199     goto beach;
200   }
201
202   hr = IAudioClock_GetFrequency (client_clock, &client_clock_freq);
203   if (hr != S_OK) {
204     GST_ERROR_OBJECT (self, "IAudioClock::GetFrequency () failed");
205     goto beach;
206   }
207
208   hr = IAudioClient_GetService (client, &IID_IAudioCaptureClient,
209       &capture_client);
210   if (hr != S_OK) {
211     GST_ERROR_OBJECT (self, "IAudioClient::GetService "
212         "(IID_IAudioCaptureClient) failed");
213     goto beach;
214   }
215
216   hr = IAudioClient_Start (client);
217   if (hr != S_OK) {
218     GST_ERROR_OBJECT (self, "IAudioClient::Start failed");
219     goto beach;
220   }
221
222   self->client = client;
223   self->client_clock = client_clock;
224   self->client_clock_freq = client_clock_freq;
225   self->capture_client = capture_client;
226
227   res = TRUE;
228
229 beach:
230   if (!res) {
231     if (capture_client != NULL)
232       IUnknown_Release (capture_client);
233
234     if (client_clock != NULL)
235       IUnknown_Release (client_clock);
236
237     if (client != NULL)
238       IUnknown_Release (client);
239   }
240
241   return res;
242 }
243
244 static gboolean
245 gst_wasapi_src_stop (GstBaseSrc * src)
246 {
247   GstWasapiSrc *self = GST_WASAPI_SRC (src);
248
249   if (self->client != NULL) {
250     IAudioClient_Stop (self->client);
251   }
252
253   if (self->capture_client != NULL) {
254     IUnknown_Release (self->capture_client);
255     self->capture_client = NULL;
256   }
257
258   if (self->client_clock != NULL) {
259     IUnknown_Release (self->client_clock);
260     self->client_clock = NULL;
261   }
262
263   if (self->client != NULL) {
264     IUnknown_Release (self->client);
265     self->client = NULL;
266   }
267
268   return TRUE;
269 }
270
271 static gboolean
272 gst_wasapi_src_query (GstBaseSrc * src, GstQuery * query)
273 {
274   GstWasapiSrc *self = GST_WASAPI_SRC (src);
275   gboolean ret = FALSE;
276
277   GST_DEBUG_OBJECT (self, "query for %s",
278       gst_query_type_get_name (GST_QUERY_TYPE (query)));
279
280   switch (GST_QUERY_TYPE (query)) {
281     case GST_QUERY_LATENCY:{
282       GstClockTime min_latency, max_latency;
283
284       min_latency = self->latency + self->period_time;
285       max_latency = min_latency;
286
287       GST_DEBUG_OBJECT (self, "reporting latency of min %" GST_TIME_FORMAT
288           " max %" GST_TIME_FORMAT,
289           GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
290
291       gst_query_set_latency (query, TRUE, min_latency, max_latency);
292       ret = TRUE;
293       break;
294     }
295
296     default:
297       ret = GST_BASE_SRC_CLASS (parent_class)->query (src, query);
298       break;
299   }
300
301   return ret;
302 }
303
304 static GstFlowReturn
305 gst_wasapi_src_create (GstPushSrc * src, GstBuffer ** buf)
306 {
307   GstWasapiSrc *self = GST_WASAPI_SRC (src);
308   GstFlowReturn ret = GST_FLOW_OK;
309   GstClock *clock;
310   GstClockTime timestamp, duration = self->period_time;
311   HRESULT hr;
312   gint16 *samples = NULL;
313   guint32 nsamples_read = 0, nsamples;
314   DWORD flags = 0;
315   guint64 devpos;
316
317   GST_OBJECT_LOCK (self);
318   clock = GST_ELEMENT_CLOCK (self);
319   if (clock != NULL)
320     gst_object_ref (clock);
321   GST_OBJECT_UNLOCK (self);
322
323   if (clock != NULL && GST_CLOCK_TIME_IS_VALID (self->next_time)) {
324     GstClockID id;
325
326     id = gst_clock_new_single_shot_id (clock, self->next_time);
327     gst_clock_id_wait (id, NULL);
328     gst_clock_id_unref (id);
329   }
330
331   do {
332     hr = IAudioCaptureClient_GetBuffer (self->capture_client,
333         (BYTE **) & samples, &nsamples_read, &flags, &devpos, NULL);
334   }
335   while (hr == AUDCLNT_S_BUFFER_EMPTY);
336
337   if (hr != S_OK) {
338     GST_ERROR_OBJECT (self, "IAudioCaptureClient::GetBuffer () failed: %s",
339         gst_wasapi_util_hresult_to_string (hr));
340     ret = GST_FLOW_ERROR;
341     goto beach;
342   }
343
344   if (flags != 0) {
345     GST_WARNING_OBJECT (self, "devpos %" G_GUINT64_FORMAT ": flags=0x%08x",
346         devpos, flags);
347   }
348
349   /* FIXME: Why do we get 1024 sometimes and not a multiple of
350    *        samples_per_buffer? Shouldn't WASAPI provide a DISCONT
351    *        flag if we read too slow?
352    */
353   nsamples = nsamples_read;
354   g_assert (nsamples >= self->samples_per_buffer);
355   if (nsamples > self->samples_per_buffer) {
356     GST_WARNING_OBJECT (self,
357         "devpos %" G_GUINT64_FORMAT ": got %d samples, expected %d, clipping!",
358         devpos, nsamples, self->samples_per_buffer);
359
360     nsamples = self->samples_per_buffer;
361   }
362
363   if (clock == NULL || clock == self->clock) {
364     timestamp =
365         gst_util_uint64_scale (devpos, GST_SECOND, self->client_clock_freq);
366   } else {
367     GstClockTime base_time;
368
369     timestamp = gst_clock_get_time (clock);
370
371     base_time = GST_ELEMENT_CAST (self)->base_time;
372     if (timestamp > base_time)
373       timestamp -= base_time;
374     else
375       timestamp = 0;
376
377     if (timestamp > duration)
378       timestamp -= duration;
379     else
380       timestamp = 0;
381   }
382
383   ret = gst_pad_alloc_buffer_and_set_caps (GST_BASE_SRC_PAD (self),
384       devpos,
385       nsamples * sizeof (gint16), GST_PAD_CAPS (GST_BASE_SRC_PAD (self)), buf);
386
387   if (ret == GST_FLOW_OK) {
388     guint i;
389     gint16 *dst;
390
391     GST_BUFFER_OFFSET_END (*buf) = devpos + self->samples_per_buffer;
392     GST_BUFFER_TIMESTAMP (*buf) = timestamp;
393     GST_BUFFER_DURATION (*buf) = duration;
394
395     dst = (gint16 *) GST_BUFFER_DATA (*buf);
396     for (i = 0; i < nsamples; i++) {
397       *dst = *samples;
398
399       samples += 2;
400       dst++;
401     }
402   }
403
404   hr = IAudioCaptureClient_ReleaseBuffer (self->capture_client, nsamples_read);
405   if (hr != S_OK) {
406     GST_ERROR_OBJECT (self, "IAudioCaptureClient::ReleaseBuffer () failed: %s",
407         gst_wasapi_util_hresult_to_string (hr));
408     ret = GST_FLOW_ERROR;
409     goto beach;
410   }
411
412 beach:
413   if (clock != NULL)
414     gst_object_unref (clock);
415
416   return ret;
417 }
418
419 static GstClockTime
420 gst_wasapi_src_get_time (GstClock * clock, gpointer user_data)
421 {
422   GstWasapiSrc *self = GST_WASAPI_SRC (user_data);
423   HRESULT hr;
424   guint64 devpos;
425   GstClockTime result;
426
427   if (G_UNLIKELY (self->client_clock == NULL))
428     return GST_CLOCK_TIME_NONE;
429
430   hr = IAudioClock_GetPosition (self->client_clock, &devpos, NULL);
431   if (G_UNLIKELY (hr != S_OK))
432     return GST_CLOCK_TIME_NONE;
433
434   result = gst_util_uint64_scale_int (devpos, GST_SECOND,
435       self->client_clock_freq);
436
437   /*
438      GST_DEBUG_OBJECT (self, "devpos = %" G_GUINT64_FORMAT
439      " frequency = %" G_GUINT64_FORMAT
440      " result = %" G_GUINT64_FORMAT " ms",
441      devpos, self->client_clock_freq, GST_TIME_AS_MSECONDS (result));
442    */
443
444   return result;
445 }