Imported Upstream version 0.10.23
[profile/ivi/gst-plugins-bad.git] / ext / openal / gstopenalsrc.c
1 /*
2  * GStreamer
3  * Copyright (C) 2005 Thomas Vander Stichele <thomas@apestaart.org>
4  * Copyright (C) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
5  * Copyright (C) 2008 Victor Lin <bornstub@gmail.com>
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23  * DEALINGS IN THE SOFTWARE.
24  *
25  * Alternatively, the contents of this file may be used under the
26  * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
27  * which case the following provisions apply instead of the ones
28  * mentioned above:
29  *
30  * This library is free software; you can redistribute it and/or
31  * modify it under the terms of the GNU Library General Public
32  * License as published by the Free Software Foundation; either
33  * version 2 of the License, or (at your option) any later version.
34  *
35  * This library is distributed in the hope that it will be useful,
36  * but WITHOUT ANY WARRANTY; without even the implied warranty of
37  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
38  * Library General Public License for more details.
39  *
40  * You should have received a copy of the GNU Library General Public
41  * License along with this library; if not, write to the
42  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
43  * Boston, MA 02111-1307, USA.
44  */
45
46  /**
47  * SECTION:element-openalsrc
48  * @short_description: record sound from your sound card using OpenAL
49  *
50  * <refsect2>
51  * <para>
52  * This element lets you record sound using the OpenAL
53  * </para>
54  * <title>Example pipelines</title>
55  * <para>
56  * <programlisting>
57  * gst-launch -v openalsrc ! audioconvert ! vorbisenc ! oggmux ! filesink location=mymusic.ogg
58  * </programlisting>
59  * will record sound from your sound card using OpenAL and encode it to an Ogg/Vorbis file
60  * </para>
61  * </refsect2>
62  */
63
64 #ifdef HAVE_CONFIG_H
65 #  include <config.h>
66 #endif
67
68 #include <gst/gst.h>
69 #include <gst/gsterror.h>
70
71 #include "gstopenalsrc.h"
72
73 GST_DEBUG_CATEGORY_STATIC (openalsrc_debug);
74
75 #define GST_CAT_DEFAULT openalsrc_debug
76
77 #define DEFAULT_DEVICE              NULL
78 #define DEFAULT_DEVICE_NAME         NULL
79
80 /**
81     Filter signals and args
82 **/
83 enum
84 {
85   /* FILL ME */
86   LAST_SIGNAL
87 };
88
89
90 /**
91     Properties
92 **/
93 enum
94 {
95   PROP_0,
96   PROP_DEVICE,
97   PROP_DEVICE_NAME
98 };
99
100 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
101     GST_PAD_SRC,
102     GST_PAD_ALWAYS,
103     GST_STATIC_CAPS ("audio/x-raw-int, "
104         "endianness = (int) BYTE_ORDER, "
105         "signed = (boolean) TRUE, "
106         "width = (int) 16, "
107         "depth = (int) 16, "
108         "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]; "
109         "audio/x-raw-int, "
110         "signed = (boolean) TRUE, "
111         "width = (int) 8, "
112         "depth = (int) 8, "
113         "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]")
114     );
115
116 GST_BOILERPLATE (GstOpenalSrc, gst_openal_src, GstAudioSrc, GST_TYPE_AUDIO_SRC);
117
118 static void gst_openal_src_set_property (GObject * object, guint prop_id,
119     const GValue * value, GParamSpec * pspec);
120 static void gst_openal_src_get_property (GObject * object, guint prop_id,
121     GValue * value, GParamSpec * pspec);
122 static gboolean gst_openal_src_open (GstAudioSrc * src);
123 static gboolean
124 gst_openal_src_prepare (GstAudioSrc * src, GstRingBufferSpec * spec);
125 static gboolean gst_openal_src_unprepare (GstAudioSrc * src);
126 static gboolean gst_openal_src_close (GstAudioSrc * src);
127 static guint
128 gst_openal_src_read (GstAudioSrc * src, gpointer data, guint length);
129 static guint gst_openal_src_delay (GstAudioSrc * src);
130 static void gst_openal_src_reset (GstAudioSrc * src);
131
132 static void gst_openal_src_finalize (GObject * object);
133
134 static void
135 gst_openal_src_base_init (gpointer gclass)
136 {
137
138   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
139
140   gst_element_class_set_details_simple (element_class, "OpenAL src",
141       "Source/Audio",
142       "OpenAL source capture audio from device",
143       "Victor Lin <bornstub@gmail.com>");
144
145   gst_element_class_add_static_pad_template (element_class, &src_factory);
146 }
147
148 static void
149 gst_openal_src_class_init (GstOpenalSrcClass * klass)
150 {
151   GObjectClass *gobject_class;
152   GstAudioSrcClass *gstaudio_src_class;
153
154   gobject_class = G_OBJECT_CLASS (klass);
155   gstaudio_src_class = GST_AUDIO_SRC_CLASS (klass);
156
157   GST_DEBUG_CATEGORY_INIT (openalsrc_debug, "openalsrc",
158       0, "OpenAL source capture audio from device");
159
160   gobject_class->set_property = gst_openal_src_set_property;
161   gobject_class->get_property = gst_openal_src_get_property;
162   gobject_class->finalize = gst_openal_src_finalize;
163
164   gstaudio_src_class->open = GST_DEBUG_FUNCPTR (gst_openal_src_open);
165   gstaudio_src_class->prepare = GST_DEBUG_FUNCPTR (gst_openal_src_prepare);
166   gstaudio_src_class->unprepare = GST_DEBUG_FUNCPTR (gst_openal_src_unprepare);
167   gstaudio_src_class->close = GST_DEBUG_FUNCPTR (gst_openal_src_close);
168   gstaudio_src_class->read = GST_DEBUG_FUNCPTR (gst_openal_src_read);
169   gstaudio_src_class->delay = GST_DEBUG_FUNCPTR (gst_openal_src_delay);
170   gstaudio_src_class->reset = GST_DEBUG_FUNCPTR (gst_openal_src_reset);
171
172   g_object_class_install_property (gobject_class,
173       PROP_DEVICE,
174       g_param_spec_string ("device",
175           "Device",
176           "Specific capture device to open, NULL indicate default device",
177           DEFAULT_DEVICE, G_PARAM_READWRITE)
178       );
179
180   g_object_class_install_property (gobject_class,
181       PROP_DEVICE_NAME,
182       g_param_spec_string ("device-name",
183           "Device name",
184           "Readable name of device", DEFAULT_DEVICE_NAME, G_PARAM_READABLE)
185       );
186 }
187
188 static void
189 gst_openal_src_init (GstOpenalSrc * osrc, GstOpenalSrcClass * gclass)
190 {
191   osrc->deviceName = g_strdup (DEFAULT_DEVICE_NAME);
192   osrc->device = DEFAULT_DEVICE;
193   osrc->deviceHandle = NULL;
194 }
195
196 static void
197 gst_openal_src_set_property (GObject * object, guint prop_id,
198     const GValue * value, GParamSpec * pspec)
199 {
200   GstOpenalSrc *osrc = GST_OPENAL_SRC (object);
201
202   switch (prop_id) {
203     case PROP_DEVICE:
204       osrc->device = g_value_dup_string (value);
205       break;
206     case PROP_DEVICE_NAME:
207       osrc->deviceName = g_value_dup_string (value);
208       break;
209     default:
210       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
211       break;
212   }
213 }
214
215 static void
216 gst_openal_src_get_property (GObject * object, guint prop_id, GValue * value,
217     GParamSpec * pspec)
218 {
219   GstOpenalSrc *osrc = GST_OPENAL_SRC (object);
220
221   switch (prop_id) {
222     case PROP_DEVICE:
223       g_value_set_string (value, osrc->device);
224       break;
225     case PROP_DEVICE_NAME:
226       g_value_set_string (value, osrc->deviceName);
227       break;
228     default:
229       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
230       break;
231   }
232 }
233
234 static gboolean
235 gst_openal_src_open (GstAudioSrc * asrc)
236 {
237   /* We don't do anything here */
238   return TRUE;
239 }
240
241 static gboolean
242 gst_openal_src_prepare (GstAudioSrc * asrc, GstRingBufferSpec * spec)
243 {
244
245   GstOpenalSrc *osrc = GST_OPENAL_SRC (asrc);
246   ALenum format;
247   guint64 bufferSize;
248
249   switch (spec->width) {
250     case 8:
251       format = AL_FORMAT_STEREO8;
252       break;
253     case 16:
254       format = AL_FORMAT_STEREO16;
255       break;
256     default:
257       g_assert_not_reached ();
258   }
259
260   bufferSize =
261       spec->buffer_time * spec->rate * spec->bytes_per_sample / 1000000;
262
263   GST_INFO_OBJECT (osrc, "Open device : %s", osrc->deviceName);
264   osrc->deviceHandle =
265       alcCaptureOpenDevice (osrc->device, spec->rate, format, bufferSize);
266
267   if (!osrc->deviceHandle) {
268     GST_ELEMENT_ERROR (osrc,
269         RESOURCE,
270         FAILED,
271         ("Can't open device \"%s\"", osrc->device),
272         ("Can't open device \"%s\"", osrc->device)
273         );
274     return FALSE;
275   }
276
277   osrc->deviceName =
278       g_strdup (alcGetString (osrc->deviceHandle, ALC_DEVICE_SPECIFIER));
279   osrc->bytes_per_sample = spec->bytes_per_sample;
280
281   GST_INFO_OBJECT (osrc, "Start capture");
282   alcCaptureStart (osrc->deviceHandle);
283
284   return TRUE;
285 }
286
287 static gboolean
288 gst_openal_src_unprepare (GstAudioSrc * asrc)
289 {
290
291   GstOpenalSrc *osrc = GST_OPENAL_SRC (asrc);
292
293   GST_INFO_OBJECT (osrc, "Close device : %s", osrc->deviceName);
294   if (osrc->deviceHandle) {
295     alcCaptureStop (osrc->deviceHandle);
296     alcCaptureCloseDevice (osrc->deviceHandle);
297   }
298
299   return TRUE;
300 }
301
302 static gboolean
303 gst_openal_src_close (GstAudioSrc * asrc)
304 {
305   /* We don't do anything here */
306   return TRUE;
307 }
308
309 static guint
310 gst_openal_src_read (GstAudioSrc * asrc, gpointer data, guint length)
311 {
312   GstOpenalSrc *osrc = GST_OPENAL_SRC (asrc);
313   gint samples;
314
315   alcGetIntegerv (osrc->deviceHandle, ALC_CAPTURE_SAMPLES, sizeof (samples),
316       &samples);
317
318   if (samples * osrc->bytes_per_sample > length) {
319     samples = length / osrc->bytes_per_sample;
320   }
321
322   if (samples) {
323     GST_DEBUG_OBJECT (osrc, "Read samples : %d", samples);
324     alcCaptureSamples (osrc->deviceHandle, data, samples);
325   }
326
327   return samples * osrc->bytes_per_sample;
328 }
329
330 static guint
331 gst_openal_src_delay (GstAudioSrc * asrc)
332 {
333   GstOpenalSrc *osrc = GST_OPENAL_SRC (asrc);
334   gint samples;
335
336   alcGetIntegerv (osrc->deviceHandle, ALC_CAPTURE_SAMPLES, sizeof (samples),
337       &samples);
338
339   return samples;
340 }
341
342 static void
343 gst_openal_src_reset (GstAudioSrc * asrc)
344 {
345   /* We don't do anything here */
346 }
347
348 static void
349 gst_openal_src_finalize (GObject * object)
350 {
351   GstOpenalSrc *osrc = GST_OPENAL_SRC (object);
352
353   g_free (osrc->deviceName);
354   g_free (osrc->device);
355
356   G_OBJECT_CLASS (parent_class)->finalize (object);
357 }