Merge remote-tracking branch 'origin/0.10'
[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_pad_template (element_class,
73       gst_static_pad_template_get (&src_template));
74   gst_element_class_set_details_simple (element_class, "WasapiSrc",
75       "Source/Audio",
76       "Stream audio from an audio capture device through WASAPI",
77       "Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>");
78 }
79
80 static void
81 gst_wasapi_src_class_init (GstWasapiSrcClass * klass)
82 {
83   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
84   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
85   GstBaseSrcClass *gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
86   GstPushSrcClass *gstpushsrc_class = GST_PUSH_SRC_CLASS (klass);
87
88   gobject_class->dispose = gst_wasapi_src_dispose;
89   gobject_class->finalize = gst_wasapi_src_finalize;
90
91   gstelement_class->provide_clock = gst_wasapi_src_provide_clock;
92
93   gstbasesrc_class->start = gst_wasapi_src_start;
94   gstbasesrc_class->stop = gst_wasapi_src_stop;
95   gstbasesrc_class->query = gst_wasapi_src_query;
96
97   gstpushsrc_class->create = gst_wasapi_src_create;
98
99   GST_DEBUG_CATEGORY_INIT (gst_wasapi_src_debug, "wasapisrc",
100       0, "Windows audio session API source");
101 }
102
103 static void
104 gst_wasapi_src_init (GstWasapiSrc * self, GstWasapiSrcClass * gclass)
105 {
106   GstBaseSrc *basesrc = GST_BASE_SRC (self);
107
108   gst_base_src_set_format (basesrc, GST_FORMAT_TIME);
109   gst_base_src_set_live (basesrc, TRUE);
110
111   self->rate = 8000;
112   self->buffer_time = 20 * GST_MSECOND;
113   self->period_time = 20 * GST_MSECOND;
114   self->latency = GST_CLOCK_TIME_NONE;
115   self->samples_per_buffer = self->rate / (GST_SECOND / self->period_time);
116
117   self->start_time = GST_CLOCK_TIME_NONE;
118   self->next_time = GST_CLOCK_TIME_NONE;
119
120 #if GST_CHECK_VERSION(0, 10, 31) || (GST_CHECK_VERSION(0, 10, 30) && GST_VERSION_NANO > 0)
121   self->clock = gst_audio_clock_new_full ("GstWasapiSrcClock",
122       gst_wasapi_src_get_time, gst_object_ref (self),
123       (GDestroyNotify) gst_object_unref);
124 #else
125   self->clock = gst_audio_clock_new ("GstWasapiSrcClock",
126       gst_wasapi_src_get_time, self);
127 #endif
128
129   CoInitialize (NULL);
130 }
131
132 static void
133 gst_wasapi_src_dispose (GObject * object)
134 {
135   GstWasapiSrc *self = GST_WASAPI_SRC (object);
136
137   if (self->clock != NULL) {
138     gst_object_unref (self->clock);
139     self->clock = NULL;
140   }
141
142   G_OBJECT_CLASS (parent_class)->dispose (object);
143 }
144
145 static void
146 gst_wasapi_src_finalize (GObject * object)
147 {
148   GstWasapiSrc *self = GST_WASAPI_SRC (object);
149
150   CoUninitialize ();
151
152   G_OBJECT_CLASS (parent_class)->finalize (object);
153 }
154
155 static GstClock *
156 gst_wasapi_src_provide_clock (GstElement * element)
157 {
158   GstWasapiSrc *self = GST_WASAPI_SRC (element);
159   GstClock *clock;
160
161   GST_OBJECT_LOCK (self);
162
163   if (self->client_clock == NULL)
164     goto wrong_state;
165
166   clock = GST_CLOCK (gst_object_ref (self->clock));
167
168   GST_OBJECT_UNLOCK (self);
169   return clock;
170
171   /* ERRORS */
172 wrong_state:
173   {
174     GST_OBJECT_UNLOCK (self);
175     GST_DEBUG_OBJECT (self, "IAudioClock not acquired");
176     return NULL;
177   }
178 }
179
180 static gboolean
181 gst_wasapi_src_start (GstBaseSrc * src)
182 {
183   GstWasapiSrc *self = GST_WASAPI_SRC (src);
184   gboolean res = FALSE;
185   IAudioClient *client = NULL;
186   IAudioClock *client_clock = NULL;
187   guint64 client_clock_freq = 0;
188   IAudioCaptureClient *capture_client = NULL;
189   HRESULT hr;
190
191   if (!gst_wasapi_util_get_default_device_client (GST_ELEMENT (self),
192           TRUE, self->rate, self->buffer_time, self->period_time, 0, &client,
193           &self->latency))
194     goto beach;
195
196   hr = IAudioClient_GetService (client, &IID_IAudioClock, &client_clock);
197   if (hr != S_OK) {
198     GST_ERROR_OBJECT (self, "IAudioClient::GetService (IID_IAudioClock) "
199         "failed");
200     goto beach;
201   }
202
203   hr = IAudioClock_GetFrequency (client_clock, &client_clock_freq);
204   if (hr != S_OK) {
205     GST_ERROR_OBJECT (self, "IAudioClock::GetFrequency () failed");
206     goto beach;
207   }
208
209   hr = IAudioClient_GetService (client, &IID_IAudioCaptureClient,
210       &capture_client);
211   if (hr != S_OK) {
212     GST_ERROR_OBJECT (self, "IAudioClient::GetService "
213         "(IID_IAudioCaptureClient) failed");
214     goto beach;
215   }
216
217   hr = IAudioClient_Start (client);
218   if (hr != S_OK) {
219     GST_ERROR_OBJECT (self, "IAudioClient::Start failed");
220     goto beach;
221   }
222
223   self->client = client;
224   self->client_clock = client_clock;
225   self->client_clock_freq = client_clock_freq;
226   self->capture_client = capture_client;
227
228   res = TRUE;
229
230 beach:
231   if (!res) {
232     if (capture_client != NULL)
233       IUnknown_Release (capture_client);
234
235     if (client_clock != NULL)
236       IUnknown_Release (client_clock);
237
238     if (client != NULL)
239       IUnknown_Release (client);
240   }
241
242   return res;
243 }
244
245 static gboolean
246 gst_wasapi_src_stop (GstBaseSrc * src)
247 {
248   GstWasapiSrc *self = GST_WASAPI_SRC (src);
249
250   if (self->client != NULL) {
251     IAudioClient_Stop (self->client);
252   }
253
254   if (self->capture_client != NULL) {
255     IUnknown_Release (self->capture_client);
256     self->capture_client = NULL;
257   }
258
259   if (self->client_clock != NULL) {
260     IUnknown_Release (self->client_clock);
261     self->client_clock = NULL;
262   }
263
264   if (self->client != NULL) {
265     IUnknown_Release (self->client);
266     self->client = NULL;
267   }
268
269   return TRUE;
270 }
271
272 static gboolean
273 gst_wasapi_src_query (GstBaseSrc * src, GstQuery * query)
274 {
275   GstWasapiSrc *self = GST_WASAPI_SRC (src);
276   gboolean ret = FALSE;
277
278   GST_DEBUG_OBJECT (self, "query for %s",
279       gst_query_type_get_name (GST_QUERY_TYPE (query)));
280
281   switch (GST_QUERY_TYPE (query)) {
282     case GST_QUERY_LATENCY:{
283       GstClockTime min_latency, max_latency;
284
285       min_latency = self->latency + self->period_time;
286       max_latency = min_latency;
287
288       GST_DEBUG_OBJECT (self, "reporting latency of min %" GST_TIME_FORMAT
289           " max %" GST_TIME_FORMAT,
290           GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
291
292       gst_query_set_latency (query, TRUE, min_latency, max_latency);
293       ret = TRUE;
294       break;
295     }
296
297     default:
298       ret = GST_BASE_SRC_CLASS (parent_class)->query (src, query);
299       break;
300   }
301
302   return ret;
303 }
304
305 static GstFlowReturn
306 gst_wasapi_src_create (GstPushSrc * src, GstBuffer ** buf)
307 {
308   GstWasapiSrc *self = GST_WASAPI_SRC (src);
309   GstFlowReturn ret = GST_FLOW_OK;
310   GstClock *clock;
311   GstClockTime timestamp, duration = self->period_time;
312   HRESULT hr;
313   gint16 *samples = NULL;
314   guint32 nsamples_read = 0, nsamples;
315   DWORD flags = 0;
316   guint64 devpos;
317
318   GST_OBJECT_LOCK (self);
319   clock = GST_ELEMENT_CLOCK (self);
320   if (clock != NULL)
321     gst_object_ref (clock);
322   GST_OBJECT_UNLOCK (self);
323
324   if (clock != NULL && GST_CLOCK_TIME_IS_VALID (self->next_time)) {
325     GstClockID id;
326
327     id = gst_clock_new_single_shot_id (clock, self->next_time);
328     gst_clock_id_wait (id, NULL);
329     gst_clock_id_unref (id);
330   }
331
332   do {
333     hr = IAudioCaptureClient_GetBuffer (self->capture_client,
334         (BYTE **) & samples, &nsamples_read, &flags, &devpos, NULL);
335   }
336   while (hr == AUDCLNT_S_BUFFER_EMPTY);
337
338   if (hr != S_OK) {
339     GST_ERROR_OBJECT (self, "IAudioCaptureClient::GetBuffer () failed: %s",
340         gst_wasapi_util_hresult_to_string (hr));
341     ret = GST_FLOW_ERROR;
342     goto beach;
343   }
344
345   if (flags != 0) {
346     GST_WARNING_OBJECT (self, "devpos %" G_GUINT64_FORMAT ": flags=0x%08x",
347         devpos, flags);
348   }
349
350   /* FIXME: Why do we get 1024 sometimes and not a multiple of
351    *        samples_per_buffer? Shouldn't WASAPI provide a DISCONT
352    *        flag if we read too slow?
353    */
354   nsamples = nsamples_read;
355   g_assert (nsamples >= self->samples_per_buffer);
356   if (nsamples > self->samples_per_buffer) {
357     GST_WARNING_OBJECT (self,
358         "devpos %" G_GUINT64_FORMAT ": got %d samples, expected %d, clipping!",
359         devpos, nsamples, self->samples_per_buffer);
360
361     nsamples = self->samples_per_buffer;
362   }
363
364   if (clock == NULL || clock == self->clock) {
365     timestamp =
366         gst_util_uint64_scale (devpos, GST_SECOND, self->client_clock_freq);
367   } else {
368     GstClockTime base_time;
369
370     timestamp = gst_clock_get_time (clock);
371
372     base_time = GST_ELEMENT_CAST (self)->base_time;
373     if (timestamp > base_time)
374       timestamp -= base_time;
375     else
376       timestamp = 0;
377
378     if (timestamp > duration)
379       timestamp -= duration;
380     else
381       timestamp = 0;
382   }
383
384   ret = gst_pad_alloc_buffer_and_set_caps (GST_BASE_SRC_PAD (self),
385       devpos,
386       nsamples * sizeof (gint16), GST_PAD_CAPS (GST_BASE_SRC_PAD (self)), buf);
387
388   if (ret == GST_FLOW_OK) {
389     guint i;
390     gint16 *dst;
391
392     GST_BUFFER_OFFSET_END (*buf) = devpos + self->samples_per_buffer;
393     GST_BUFFER_TIMESTAMP (*buf) = timestamp;
394     GST_BUFFER_DURATION (*buf) = duration;
395
396     dst = (gint16 *) GST_BUFFER_DATA (*buf);
397     for (i = 0; i < nsamples; i++) {
398       *dst = *samples;
399
400       samples += 2;
401       dst++;
402     }
403   }
404
405   hr = IAudioCaptureClient_ReleaseBuffer (self->capture_client, nsamples_read);
406   if (hr != S_OK) {
407     GST_ERROR_OBJECT (self, "IAudioCaptureClient::ReleaseBuffer () failed: %s",
408         gst_wasapi_util_hresult_to_string (hr));
409     ret = GST_FLOW_ERROR;
410     goto beach;
411   }
412
413 beach:
414   if (clock != NULL)
415     gst_object_unref (clock);
416
417   return ret;
418 }
419
420 static GstClockTime
421 gst_wasapi_src_get_time (GstClock * clock, gpointer user_data)
422 {
423   GstWasapiSrc *self = GST_WASAPI_SRC (user_data);
424   HRESULT hr;
425   guint64 devpos;
426   GstClockTime result;
427
428   if (G_UNLIKELY (self->client_clock == NULL))
429     return GST_CLOCK_TIME_NONE;
430
431   hr = IAudioClock_GetPosition (self->client_clock, &devpos, NULL);
432   if (G_UNLIKELY (hr != S_OK))
433     return GST_CLOCK_TIME_NONE;
434
435   result = gst_util_uint64_scale_int (devpos, GST_SECOND,
436       self->client_clock_freq);
437
438   /*
439      GST_DEBUG_OBJECT (self, "devpos = %" G_GUINT64_FORMAT
440      " frequency = %" G_GUINT64_FORMAT
441      " result = %" G_GUINT64_FORMAT " ms",
442      devpos, self->client_clock_freq, GST_TIME_AS_MSECONDS (result));
443    */
444
445   return result;
446 }