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 *****************************************************************************/
26 #include <sys/types.h>
28 #include <alsa/asoundlib.h>
30 #include <vlc_common.h>
31 #include <vlc_demux.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,
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")
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
)
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
)
69 set_callbacks (Open
, Close
)
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
)
80 if (unlikely(snd_output_buffer_open (&output
)))
83 int val
= cb (p
, output
);
86 msg_Warn (obj
, "cannot get info: %s", snd_strerror (val
));
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)
133 snd_pcm_uframes_t period_size
;
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
);
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
;
162 canc
= vlc_savecancel ();
163 bytes
= snd_pcm_frames_to_bytes (pcm
, sys
->period_size
);
164 val
= snd_pcm_start (pcm
);
167 msg_Err (demux
, "cannot prepare device: %s", snd_strerror (val
));
173 block_t
*block
= block_Alloc (bytes
);
174 if (unlikely(block
== NULL
))
181 snd_pcm_sframes_t frames
, delay
;
184 frames
= snd_pcm_readi (pcm
, block
->p_buffer
, sys
->period_size
);
185 pts
= vlc_tick_now ();
188 block_Release (block
);
189 if (frames
== -EAGAIN
)
192 val
= snd_pcm_recover (pcm
, frames
, 1);
195 msg_Warn (demux
, "cannot read samples: %s",
196 snd_strerror (frames
));
197 snd_pcm_state_t state
= snd_pcm_state (pcm
);
200 case SND_PCM_STATE_PREPARED
:
201 val
= snd_pcm_start (pcm
);
204 msg_Err (demux
, "cannot prepare device: %s",
209 case SND_PCM_STATE_RUNNING
:
215 msg_Err (demux
, "cannot recover record stream: %s",
217 DumpDeviceStatus (demux
, pcm
);
221 /* Compute time stamp */
222 if (snd_pcm_delay (pcm
, &delay
))
225 pts
-= (CLOCK_FREQ
* delay
) / sys
->rate
;
227 block
->i_buffer
= snd_pcm_frames_to_bytes (pcm
, frames
);
228 block
->i_nb_samples
= frames
;
230 block
->i_length
= (CLOCK_FREQ
* frames
) / sys
->rate
;
232 es_out_SetPCR(demux
->out
, block
->i_pts
);
233 es_out_Send (demux
->out
, sys
->es
, block
);
238 static int Control (demux_t
*demux
, int query
, va_list ap
)
240 demux_sys_t
*sys
= demux
->p_sys
;
245 *va_arg (ap
, int64_t *) = vlc_tick_now () - sys
->start
;
248 case DEMUX_GET_PTS_DELAY
:
249 *va_arg (ap
, int64_t *) = sys
->caching
;
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
:
260 *va_arg (ap
, bool *) = false;
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_F32L
,
288 [SND_PCM_FORMAT_FLOAT64_BE
] = VLC_CODEC_F32B
,
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
314 # define C(f) f##LE, f##BE
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
),
329 SND_PCM_FORMAT_MU_LAW
,
330 SND_PCM_FORMAT_A_LAW
,
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
)
348 demux_sys_t
*sys
= vlc_obj_malloc(obj
, sizeof (*sys
));
349 if (unlikely(sys
== NULL
))
352 /* Open the device */
353 const char *device
= demux
->psz_location
;
354 if (device
== NULL
|| !device
[0])
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*/;
362 int val
= snd_pcm_open (&pcm
, device
, SND_PCM_STREAM_CAPTURE
, mode
);
365 msg_Err (demux
, "cannot open ALSA device \"%s\": %s", device
,
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
;
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);
386 msg_Err (demux
, "cannot disable resampling: %s", snd_strerror (val
));
390 val
= snd_pcm_hw_params_set_access (pcm
, hw
,
391 SND_PCM_ACCESS_RW_INTERLEAVED
);
394 msg_Err (demux
, "cannot set access mode: %s", snd_strerror (val
));
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
]);
405 msg_Err (demux
, "cannot set sample format: %s",
413 if (format
== SND_PCM_FORMAT_UNKNOWN
)
415 msg_Err (demux
, "no supported sample format");
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
, ¶m
);
427 msg_Err (demux
, "cannot restrict channels count: %s",
431 val
= snd_pcm_hw_params_set_channels_last (pcm
, hw
, ¶m
);
434 msg_Err (demux
, "cannot set channels count: %s", snd_strerror (val
));
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
, ¶m
, NULL
);
446 msg_Err (demux
, "cannot restrict rate to %u Hz or less: %s", 192000,
450 val
= snd_pcm_hw_params_set_rate_last (pcm
, hw
, ¶m
, &dir
);
453 msg_Err (demux
, "cannot set sample rate: %s", snd_strerror (val
));
457 msg_Warn (demux
, "sample rate is not integral");
458 fmt
.audio
.i_rate
= param
;
461 sys
->start
= vlc_tick_now ();
462 sys
->caching
= INT64_C(1000) * var_InheritInteger (demux
, "live-caching");
463 param
= sys
->caching
;
464 val
= snd_pcm_hw_params_set_buffer_time_near (pcm
, hw
, ¶m
, NULL
);
467 msg_Err (demux
, "cannot set buffer duration: %s", snd_strerror (val
));
472 val
= snd_pcm_hw_params_set_period_time_near (pcm
, hw
, ¶m
, NULL
);
475 msg_Err (demux
, "cannot set period: %s", snd_strerror (val
));
479 val
= snd_pcm_hw_params_get_period_size (hw
, &sys
->period_size
, &dir
);
482 msg_Err (demux
, "cannot get period size: %s", snd_strerror (val
));
488 /* Commit hardware parameters */
489 val
= snd_pcm_hw_params (pcm
, hw
);
492 msg_Err (demux
, "cannot commit hardware parameters: %s",
496 Dump (demux
, "final HW setup:\n", snd_pcm_hw_params_dump
, hw
);
499 aout_FormatPrepare (&fmt
.audio
);
500 sys
->es
= es_out_Add (demux
->out
, &fmt
);
503 if (vlc_clone (&sys
->thread
, Thread
, demux
, VLC_THREAD_PRIORITY_INPUT
))
505 es_out_Del (demux
->out
, sys
->es
);
509 demux
->pf_demux
= NULL
;
510 demux
->pf_control
= Control
;
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
);