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