contrib: cargo: use cargo/vendored-openssl if needed
[vlc.git] / modules / access / alsa.c
bloba92cf3e2c0bcb8b1f521ec1418dd856a1e1ddd5f
1 /*****************************************************************************
2 * alsa.c: ALSA capture module for VLC
3 *****************************************************************************
4 * Copyright (C) 2012 RĂ©mi Denis-Courmont
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
25 #include <assert.h>
26 #include <sys/types.h>
27 #include <poll.h>
28 #include <alsa/asoundlib.h>
30 #include <vlc_common.h>
31 #include <vlc_demux.h>
32 #include <vlc_aout.h>
33 #include <vlc_plugin.h>
35 #define HELP_TEXT N_( \
36 "Pass alsa:// to open the default ALSA capture device, " \
37 "or alsa://SOURCE to open a specific device named SOURCE.")
38 #define STEREO_TEXT N_("Stereo")
39 #define RATE_TEXT N_("Sample rate")
41 static int Open (vlc_object_t *);
42 static void Close (vlc_object_t *);
44 static const int rate_values[] = { 192000, 176400,
45 96000, 88200, 48000, 44100,
46 32000, 22050, 24000, 16000,
47 11025, 8000, 4000
49 static const char *const rate_names[] = { N_("192000 Hz"), N_("176400 Hz"),
50 N_("96000 Hz"), N_("88200 Hz"), N_("48000 Hz"), N_("44100 Hz"),
51 N_("32000 Hz"), N_("22050 Hz"), N_("24000 Hz"), N_("16000 Hz"),
52 N_("11025 Hz"), N_("8000 Hz"), N_("4000 Hz")
55 vlc_module_begin ()
56 set_shortname (N_("ALSA"))
57 set_description (N_("ALSA audio capture"))
58 set_capability ("access", 0)
59 set_category (CAT_INPUT)
60 set_subcategory (SUBCAT_INPUT_ACCESS)
61 set_help (HELP_TEXT)
63 add_obsolete_string ("alsa-format") /* since 2.1.0 */
64 add_bool ("alsa-stereo", true, STEREO_TEXT, STEREO_TEXT, true)
65 add_integer ("alsa-samplerate", 48000, RATE_TEXT, RATE_TEXT, true)
66 change_integer_list (rate_values, rate_names)
68 add_shortcut ("alsa")
69 set_callbacks (Open, Close)
70 vlc_module_end ()
72 /** Helper for ALSA -> VLC debugging output */
73 /** XXX: duplicated from ALSA output */
74 static void Dump (vlc_object_t *obj, const char *msg,
75 int (*cb)(void *, snd_output_t *), void *p)
77 snd_output_t *output;
78 char *str;
80 if (unlikely(snd_output_buffer_open (&output)))
81 return;
83 int val = cb (p, output);
84 if (val)
86 msg_Warn (obj, "cannot get info: %s", snd_strerror (val));
87 return;
90 size_t len = snd_output_buffer_string (output, &str);
91 if (len > 0 && str[len - 1])
92 len--; /* strip trailing newline */
93 msg_Dbg (obj, "%s%.*s", msg, (int)len, str);
94 snd_output_close (output);
96 #define Dump(o, m, cb, p) \
97 Dump(VLC_OBJECT(o), m, (int (*)(void *, snd_output_t *))(cb), p)
99 static void DumpDevice (vlc_object_t *obj, snd_pcm_t *pcm)
101 snd_pcm_info_t *info;
103 Dump (obj, " ", snd_pcm_dump, pcm);
104 snd_pcm_info_alloca (&info);
105 if (snd_pcm_info (pcm, info) == 0)
107 msg_Dbg (obj, " device name : %s", snd_pcm_info_get_name (info));
108 msg_Dbg (obj, " device ID : %s", snd_pcm_info_get_id (info));
109 msg_Dbg (obj, " subdevice name: %s",
110 snd_pcm_info_get_subdevice_name (info));
114 static void DumpDeviceStatus (vlc_object_t *obj, snd_pcm_t *pcm)
116 snd_pcm_status_t *status;
118 snd_pcm_status_alloca (&status);
119 snd_pcm_status (pcm, status);
120 Dump (obj, "current status:\n", snd_pcm_status_dump, status);
122 #define DumpDeviceStatus(o, p) DumpDeviceStatus(VLC_OBJECT(o), p)
125 typedef struct
127 snd_pcm_t *pcm;
128 es_out_id_t *es;
129 vlc_thread_t thread;
131 vlc_tick_t start;
132 vlc_tick_t caching;
133 snd_pcm_uframes_t period_size;
134 unsigned rate;
135 } demux_sys_t;
137 static void Poll (snd_pcm_t *pcm, int canc)
139 int n = snd_pcm_poll_descriptors_count (pcm);
140 struct pollfd ufd[n];
141 unsigned short revents;
143 snd_pcm_poll_descriptors (pcm, ufd, n);
146 vlc_restorecancel (canc);
147 while (poll (ufd, n, -1) == -1);
148 canc = vlc_savecancel ();
149 snd_pcm_poll_descriptors_revents (pcm, ufd, n, &revents);
151 while (!revents);
154 static void *Thread (void *data)
156 demux_t *demux = data;
157 demux_sys_t *sys = demux->p_sys;
158 snd_pcm_t *pcm = sys->pcm;
159 size_t bytes;
160 int canc, val;
162 canc = vlc_savecancel ();
163 bytes = snd_pcm_frames_to_bytes (pcm, sys->period_size);
164 val = snd_pcm_start (pcm);
165 if (val)
167 msg_Err (demux, "cannot prepare device: %s", snd_strerror (val));
168 return NULL;
171 for (;;)
173 block_t *block = block_Alloc (bytes);
174 if (unlikely(block == NULL))
175 break;
177 /* Wait for data */
178 Poll (pcm, canc);
180 /* Read data */
181 snd_pcm_sframes_t frames, delay;
182 vlc_tick_t pts;
184 frames = snd_pcm_readi (pcm, block->p_buffer, sys->period_size);
185 pts = vlc_tick_now ();
186 if (frames < 0)
188 block_Release (block);
189 if (frames == -EAGAIN)
190 continue;
192 val = snd_pcm_recover (pcm, frames, 1);
193 if (val == 0)
195 msg_Warn (demux, "cannot read samples: %s",
196 snd_strerror (frames));
197 snd_pcm_state_t state = snd_pcm_state (pcm);
198 switch (state)
200 case SND_PCM_STATE_PREPARED:
201 val = snd_pcm_start (pcm);
202 if (val < 0)
204 msg_Err (demux, "cannot prepare device: %s",
205 snd_strerror (val));
206 return NULL;
208 continue;
209 case SND_PCM_STATE_RUNNING:
210 continue;
211 default:
212 break;
215 msg_Err (demux, "cannot recover record stream: %s",
216 snd_strerror (val));
217 DumpDeviceStatus (demux, pcm);
218 break;
221 /* Compute time stamp */
222 if (snd_pcm_delay (pcm, &delay))
223 delay = 0;
224 delay += frames;
225 pts -= vlc_tick_from_samples(delay, sys->rate);
227 block->i_buffer = snd_pcm_frames_to_bytes (pcm, frames);
228 block->i_nb_samples = frames;
229 block->i_pts = pts;
230 block->i_length = vlc_tick_from_samples(frames, sys->rate);
232 es_out_SetPCR(demux->out, block->i_pts);
233 es_out_Send (demux->out, sys->es, block);
235 return NULL;
238 static int Control (demux_t *demux, int query, va_list ap)
240 demux_sys_t *sys = demux->p_sys;
242 switch (query)
244 case DEMUX_GET_TIME:
245 *va_arg (ap, vlc_tick_t *) = vlc_tick_now () - sys->start;
246 break;
248 case DEMUX_GET_PTS_DELAY:
249 *va_arg (ap, vlc_tick_t *) = sys->caching;
250 break;
252 //case DEMUX_SET_NEXT_DEMUX_TIME: still needed?
254 case DEMUX_HAS_UNSUPPORTED_META:
255 case DEMUX_CAN_RECORD:
256 case DEMUX_CAN_PAUSE:
257 case DEMUX_CAN_CONTROL_PACE:
258 case DEMUX_CAN_CONTROL_RATE:
259 case DEMUX_CAN_SEEK:
260 *va_arg (ap, bool *) = false;
261 break;;
263 default:
264 return VLC_EGENERIC;
267 return VLC_SUCCESS;
270 static const vlc_fourcc_t formats[] = {
271 [SND_PCM_FORMAT_S8] = VLC_CODEC_S8,
272 [SND_PCM_FORMAT_U8] = VLC_CODEC_U8,
273 [SND_PCM_FORMAT_S16_LE] = VLC_CODEC_S16L,
274 [SND_PCM_FORMAT_S16_BE] = VLC_CODEC_S16B,
275 [SND_PCM_FORMAT_U16_LE] = VLC_CODEC_U16L,
276 [SND_PCM_FORMAT_U16_BE] = VLC_CODEC_U16B,
277 [SND_PCM_FORMAT_S24_LE] = VLC_CODEC_S24L32,
278 [SND_PCM_FORMAT_S24_BE] = VLC_CODEC_S24B32,
279 [SND_PCM_FORMAT_U24_LE] = VLC_CODEC_U32L, // TODO: replay gain
280 [SND_PCM_FORMAT_U24_BE] = VLC_CODEC_U32B, // ^
281 [SND_PCM_FORMAT_S32_LE] = VLC_CODEC_S32L,
282 [SND_PCM_FORMAT_S32_BE] = VLC_CODEC_S32B,
283 [SND_PCM_FORMAT_U32_LE] = VLC_CODEC_U32L,
284 [SND_PCM_FORMAT_U32_BE] = VLC_CODEC_U32B,
285 [SND_PCM_FORMAT_FLOAT_LE] = VLC_CODEC_F32L,
286 [SND_PCM_FORMAT_FLOAT_BE] = VLC_CODEC_F32B,
287 [SND_PCM_FORMAT_FLOAT64_LE] = VLC_CODEC_F64L,
288 [SND_PCM_FORMAT_FLOAT64_BE] = VLC_CODEC_F64B,
289 //[SND_PCM_FORMAT_IEC958_SUBFRAME_LE] = VLC_CODEC_SPDIFL,
290 //[SND_PCM_FORMAT_IEC958_SUBFRAME_BE] = VLC_CODEC_SPDIFB,
291 [SND_PCM_FORMAT_MU_LAW] = VLC_CODEC_MULAW,
292 [SND_PCM_FORMAT_A_LAW] = VLC_CODEC_ALAW,
293 //[SND_PCM_FORMAT_IMA_ADPCM] = VLC_CODEC_ADPCM_?, // XXX: which one?
294 [SND_PCM_FORMAT_MPEG] = VLC_CODEC_MPGA,
295 [SND_PCM_FORMAT_GSM] = VLC_CODEC_GSM,
296 //[SND_PCM_FORMAT_SPECIAL] = VLC_CODEC_?
297 [SND_PCM_FORMAT_S24_3LE] = VLC_CODEC_S24L,
298 [SND_PCM_FORMAT_S24_3BE] = VLC_CODEC_S24B,
299 [SND_PCM_FORMAT_U24_3LE] = VLC_CODEC_U24L,
300 [SND_PCM_FORMAT_U24_3BE] = VLC_CODEC_U24B,
301 [SND_PCM_FORMAT_S20_3LE] = VLC_CODEC_S24L, // TODO: replay gain
302 [SND_PCM_FORMAT_S20_3BE] = VLC_CODEC_S24B, // ^
303 [SND_PCM_FORMAT_U20_3LE] = VLC_CODEC_U24L, // ^
304 [SND_PCM_FORMAT_U20_3BE] = VLC_CODEC_U24B, // ^
305 [SND_PCM_FORMAT_S18_3LE] = VLC_CODEC_S24L, // ^
306 [SND_PCM_FORMAT_S18_3BE] = VLC_CODEC_S24B, // ^
307 [SND_PCM_FORMAT_U18_3LE] = VLC_CODEC_U24L, // ^
308 [SND_PCM_FORMAT_U18_3BE] = VLC_CODEC_U24B, // ^
311 #ifdef WORDS_BIGENDIAN
312 # define C(f) f##BE, f##LE
313 #else
314 # define C(f) f##LE, f##BE
315 #endif
317 /* Formats in order of decreasing preference */
318 static const uint8_t choices[] = {
319 C(SND_PCM_FORMAT_FLOAT_),
320 C(SND_PCM_FORMAT_S32_),
321 C(SND_PCM_FORMAT_U32_),
322 C(SND_PCM_FORMAT_S16_),
323 C(SND_PCM_FORMAT_U16_),
324 C(SND_PCM_FORMAT_FLOAT64_),
325 C(SND_PCM_FORMAT_S24_3),
326 C(SND_PCM_FORMAT_U24_3),
327 SND_PCM_FORMAT_MPEG,
328 SND_PCM_FORMAT_GSM,
329 SND_PCM_FORMAT_MU_LAW,
330 SND_PCM_FORMAT_A_LAW,
331 SND_PCM_FORMAT_S8,
332 SND_PCM_FORMAT_U8,
335 static uint16_t channel_maps[] = {
336 AOUT_CHAN_CENTER, AOUT_CHANS_2_0, AOUT_CHANS_3_0 /* ? */,
337 AOUT_CHANS_4_0, AOUT_CHANS_5_0 /* ? */, AOUT_CHANS_5_1,
338 /* TODO: support 7-8 channels - need channels reodering */
341 static int Open (vlc_object_t *obj)
343 demux_t *demux = (demux_t *)obj;
345 if (demux->out == NULL)
346 return VLC_EGENERIC;
348 demux_sys_t *sys = vlc_obj_malloc(obj, sizeof (*sys));
349 if (unlikely(sys == NULL))
350 return VLC_ENOMEM;
352 /* Open the device */
353 const char *device = demux->psz_location;
354 if (device == NULL || !device[0])
355 device = "default";
357 const int mode = SND_PCM_NONBLOCK
358 /*| SND_PCM_NO_AUTO_RESAMPLE*/
359 | SND_PCM_NO_AUTO_CHANNELS
360 /*| SND_PCM_NO_AUTO_FORMAT*/;
361 snd_pcm_t *pcm;
362 int val = snd_pcm_open (&pcm, device, SND_PCM_STREAM_CAPTURE, mode);
363 if (val != 0)
365 msg_Err (demux, "cannot open ALSA device \"%s\": %s", device,
366 snd_strerror (val));
367 return VLC_EGENERIC;
369 sys->pcm = pcm;
370 msg_Dbg (demux, "using ALSA device: %s", device);
371 DumpDevice (VLC_OBJECT(demux), pcm);
373 /* Negotiate capture parameters */
374 snd_pcm_hw_params_t *hw;
375 es_format_t fmt;
376 unsigned param;
377 int dir;
379 snd_pcm_hw_params_alloca (&hw);
380 snd_pcm_hw_params_any (pcm, hw);
381 Dump (demux, "initial hardware setup:\n", snd_pcm_hw_params_dump, hw);
383 val = snd_pcm_hw_params_set_rate_resample (pcm, hw, 0);
384 if (val)
386 msg_Err (demux, "cannot disable resampling: %s", snd_strerror (val));
387 goto error;
390 val = snd_pcm_hw_params_set_access (pcm, hw,
391 SND_PCM_ACCESS_RW_INTERLEAVED);
392 if (val)
394 msg_Err (demux, "cannot set access mode: %s", snd_strerror (val));
395 goto error;
398 snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN;
399 for (size_t i = 0; i < sizeof (choices) / sizeof (choices[0]); i++)
400 if (snd_pcm_hw_params_test_format (pcm, hw, choices[i]) == 0)
402 val = snd_pcm_hw_params_set_format (pcm, hw, choices[i]);
403 if (val)
405 msg_Err (demux, "cannot set sample format: %s",
406 snd_strerror (val));
407 goto error;
409 format = choices[i];
410 break;
413 if (format == SND_PCM_FORMAT_UNKNOWN)
415 msg_Err (demux, "no supported sample format");
416 goto error;
419 assert ((size_t)format < (sizeof (formats) / sizeof (formats[0])));
420 es_format_Init (&fmt, AUDIO_ES, formats[format]);
421 fmt.audio.i_format = fmt.i_codec;
423 param = 1 + var_InheritBool (demux, "alsa-stereo");
424 val = snd_pcm_hw_params_set_channels_max (pcm, hw, &param);
425 if (val)
427 msg_Err (demux, "cannot restrict channels count: %s",
428 snd_strerror (val));
429 goto error;
431 val = snd_pcm_hw_params_set_channels_last (pcm, hw, &param);
432 if (val)
434 msg_Err (demux, "cannot set channels count: %s", snd_strerror (val));
435 goto error;
437 assert (param > 0);
438 assert (param < (sizeof (channel_maps) / sizeof (channel_maps[0])));
439 fmt.audio.i_channels = param;
440 fmt.audio.i_physical_channels = channel_maps[param - 1];
442 param = var_InheritInteger (demux, "alsa-samplerate");
443 val = snd_pcm_hw_params_set_rate_max (pcm, hw, &param, NULL);
444 if (val)
446 msg_Err (demux, "cannot restrict rate to %u Hz or less: %s", 192000,
447 snd_strerror (val));
448 goto error;
450 val = snd_pcm_hw_params_set_rate_last (pcm, hw, &param, &dir);
451 if (val)
453 msg_Err (demux, "cannot set sample rate: %s", snd_strerror (val));
454 goto error;
456 if (dir)
457 msg_Warn (demux, "sample rate is not integral");
458 fmt.audio.i_rate = param;
459 sys->rate = param;
461 sys->start = vlc_tick_now ();
462 sys->caching = VLC_TICK_FROM_MS(var_InheritInteger (demux, "live-caching"));
463 param = sys->caching;
464 val = snd_pcm_hw_params_set_buffer_time_near (pcm, hw, &param, NULL);
465 if (val)
467 msg_Err (demux, "cannot set buffer duration: %s", snd_strerror (val));
468 goto error;
471 param /= 4;
472 val = snd_pcm_hw_params_set_period_time_near (pcm, hw, &param, NULL);
473 if (val)
475 msg_Err (demux, "cannot set period: %s", snd_strerror (val));
476 goto error;
479 val = snd_pcm_hw_params_get_period_size (hw, &sys->period_size, &dir);
480 if (val)
482 msg_Err (demux, "cannot get period size: %s", snd_strerror (val));
483 goto error;
485 if (dir > 0)
486 sys->period_size++;
488 /* Commit hardware parameters */
489 val = snd_pcm_hw_params (pcm, hw);
490 if (val)
492 msg_Err (demux, "cannot commit hardware parameters: %s",
493 snd_strerror (val));
494 goto error;
496 Dump (demux, "final HW setup:\n", snd_pcm_hw_params_dump, hw);
498 /* Kick recording */
499 aout_FormatPrepare (&fmt.audio);
500 sys->es = es_out_Add (demux->out, &fmt);
501 demux->p_sys = sys;
503 if (vlc_clone (&sys->thread, Thread, demux, VLC_THREAD_PRIORITY_INPUT))
505 es_out_Del (demux->out, sys->es);
506 goto error;
509 demux->pf_demux = NULL;
510 demux->pf_control = Control;
511 return VLC_SUCCESS;
512 error:
513 snd_pcm_close (pcm);
514 return VLC_EGENERIC;
517 static void Close (vlc_object_t *obj)
519 demux_t *demux = (demux_t *)obj;
520 demux_sys_t *sys = demux->p_sys;
522 vlc_cancel (sys->thread);
523 vlc_join (sys->thread, NULL);
525 snd_pcm_close (sys->pcm);