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