2 * ALSA input and output
3 * Copyright (c) 2007 Luca Abeni ( lucabe72 email it )
4 * Copyright (c) 2007 Benoit Fouet ( benoit fouet free fr )
6 * This file is part of Libav.
8 * Libav is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * Libav is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with Libav; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 * ALSA input and output: common code
26 * @author Luca Abeni ( lucabe72 email it )
27 * @author Benoit Fouet ( benoit fouet free fr )
28 * @author Nicolas George ( nicolas george normalesup org )
31 #include <alsa/asoundlib.h>
32 #include "libavformat/avformat.h"
33 #include "libavutil/avassert.h"
34 #include "libavutil/channel_layout.h"
36 #include "alsa-audio.h"
38 static av_cold snd_pcm_format_t
codec_id_to_pcm_format(int codec_id
)
41 case AV_CODEC_ID_PCM_F64LE
: return SND_PCM_FORMAT_FLOAT64_LE
;
42 case AV_CODEC_ID_PCM_F64BE
: return SND_PCM_FORMAT_FLOAT64_BE
;
43 case AV_CODEC_ID_PCM_F32LE
: return SND_PCM_FORMAT_FLOAT_LE
;
44 case AV_CODEC_ID_PCM_F32BE
: return SND_PCM_FORMAT_FLOAT_BE
;
45 case AV_CODEC_ID_PCM_S32LE
: return SND_PCM_FORMAT_S32_LE
;
46 case AV_CODEC_ID_PCM_S32BE
: return SND_PCM_FORMAT_S32_BE
;
47 case AV_CODEC_ID_PCM_U32LE
: return SND_PCM_FORMAT_U32_LE
;
48 case AV_CODEC_ID_PCM_U32BE
: return SND_PCM_FORMAT_U32_BE
;
49 case AV_CODEC_ID_PCM_S24LE
: return SND_PCM_FORMAT_S24_3LE
;
50 case AV_CODEC_ID_PCM_S24BE
: return SND_PCM_FORMAT_S24_3BE
;
51 case AV_CODEC_ID_PCM_U24LE
: return SND_PCM_FORMAT_U24_3LE
;
52 case AV_CODEC_ID_PCM_U24BE
: return SND_PCM_FORMAT_U24_3BE
;
53 case AV_CODEC_ID_PCM_S16LE
: return SND_PCM_FORMAT_S16_LE
;
54 case AV_CODEC_ID_PCM_S16BE
: return SND_PCM_FORMAT_S16_BE
;
55 case AV_CODEC_ID_PCM_U16LE
: return SND_PCM_FORMAT_U16_LE
;
56 case AV_CODEC_ID_PCM_U16BE
: return SND_PCM_FORMAT_U16_BE
;
57 case AV_CODEC_ID_PCM_S8
: return SND_PCM_FORMAT_S8
;
58 case AV_CODEC_ID_PCM_U8
: return SND_PCM_FORMAT_U8
;
59 case AV_CODEC_ID_PCM_MULAW
: return SND_PCM_FORMAT_MU_LAW
;
60 case AV_CODEC_ID_PCM_ALAW
: return SND_PCM_FORMAT_A_LAW
;
61 default: return SND_PCM_FORMAT_UNKNOWN
;
65 #define REORDER_OUT_50(NAME, TYPE) \
66 static void alsa_reorder_ ## NAME ## _out_50(const void *in_v, void *out_v, int n) \
68 const TYPE *in = in_v; \
82 #define REORDER_OUT_51(NAME, TYPE) \
83 static void alsa_reorder_ ## NAME ## _out_51(const void *in_v, void *out_v, int n) \
85 const TYPE *in = in_v; \
100 #define REORDER_OUT_71(NAME, TYPE) \
101 static void alsa_reorder_ ## NAME ## _out_71(const void *in_v, void *out_v, int n) \
103 const TYPE *in = in_v; \
120 REORDER_OUT_50(int8
, int8_t)
121 REORDER_OUT_51(int8
, int8_t)
122 REORDER_OUT_71(int8
, int8_t)
123 REORDER_OUT_50(int16
, int16_t)
124 REORDER_OUT_51(int16
, int16_t)
125 REORDER_OUT_71(int16
, int16_t)
126 REORDER_OUT_50(int32
, int32_t)
127 REORDER_OUT_51(int32
, int32_t)
128 REORDER_OUT_71(int32
, int32_t)
129 REORDER_OUT_50(f32
, float)
130 REORDER_OUT_51(f32
, float)
131 REORDER_OUT_71(f32
, float)
138 #define PICK_REORDER(layout)\
140 case FORMAT_I8: s->reorder_func = alsa_reorder_int8_out_ ##layout; break;\
141 case FORMAT_I16: s->reorder_func = alsa_reorder_int16_out_ ##layout; break;\
142 case FORMAT_I32: s->reorder_func = alsa_reorder_int32_out_ ##layout; break;\
143 case FORMAT_F32: s->reorder_func = alsa_reorder_f32_out_ ##layout; break;\
146 static av_cold
int find_reorder_func(AlsaData
*s
, int codec_id
, uint64_t layout
, int out
)
150 /* reordering input is not currently supported */
152 return AVERROR(ENOSYS
);
154 /* reordering is not needed for QUAD or 2_2 layout */
155 if (layout
== AV_CH_LAYOUT_QUAD
|| layout
== AV_CH_LAYOUT_2_2
)
159 case AV_CODEC_ID_PCM_S8
:
160 case AV_CODEC_ID_PCM_U8
:
161 case AV_CODEC_ID_PCM_ALAW
:
162 case AV_CODEC_ID_PCM_MULAW
: format
= FORMAT_I8
; break;
163 case AV_CODEC_ID_PCM_S16LE
:
164 case AV_CODEC_ID_PCM_S16BE
:
165 case AV_CODEC_ID_PCM_U16LE
:
166 case AV_CODEC_ID_PCM_U16BE
: format
= FORMAT_I16
; break;
167 case AV_CODEC_ID_PCM_S32LE
:
168 case AV_CODEC_ID_PCM_S32BE
:
169 case AV_CODEC_ID_PCM_U32LE
:
170 case AV_CODEC_ID_PCM_U32BE
: format
= FORMAT_I32
; break;
171 case AV_CODEC_ID_PCM_F32LE
:
172 case AV_CODEC_ID_PCM_F32BE
: format
= FORMAT_F32
; break;
173 default: return AVERROR(ENOSYS
);
176 if (layout
== AV_CH_LAYOUT_5POINT0_BACK
|| layout
== AV_CH_LAYOUT_5POINT0
)
178 else if (layout
== AV_CH_LAYOUT_5POINT1_BACK
|| layout
== AV_CH_LAYOUT_5POINT1
)
180 else if (layout
== AV_CH_LAYOUT_7POINT1
)
183 return s
->reorder_func
? 0 : AVERROR(ENOSYS
);
186 av_cold
int ff_alsa_open(AVFormatContext
*ctx
, snd_pcm_stream_t mode
,
187 unsigned int *sample_rate
,
188 int channels
, enum AVCodecID
*codec_id
)
190 AlsaData
*s
= ctx
->priv_data
;
191 const char *audio_device
;
193 snd_pcm_format_t format
;
195 snd_pcm_hw_params_t
*hw_params
;
196 snd_pcm_uframes_t buffer_size
, period_size
;
197 uint64_t layout
= ctx
->streams
[0]->codec
->channel_layout
;
199 if (ctx
->filename
[0] == 0) audio_device
= "default";
200 else audio_device
= ctx
->filename
;
202 if (*codec_id
== AV_CODEC_ID_NONE
)
203 *codec_id
= DEFAULT_CODEC_ID
;
204 format
= codec_id_to_pcm_format(*codec_id
);
205 if (format
== SND_PCM_FORMAT_UNKNOWN
) {
206 av_log(ctx
, AV_LOG_ERROR
, "sample format 0x%04x is not supported\n", *codec_id
);
207 return AVERROR(ENOSYS
);
209 s
->frame_size
= av_get_bits_per_sample(*codec_id
) / 8 * channels
;
211 if (ctx
->flags
& AVFMT_FLAG_NONBLOCK
) {
212 flags
= SND_PCM_NONBLOCK
;
214 res
= snd_pcm_open(&h
, audio_device
, mode
, flags
);
216 av_log(ctx
, AV_LOG_ERROR
, "cannot open audio device %s (%s)\n",
217 audio_device
, snd_strerror(res
));
221 res
= snd_pcm_hw_params_malloc(&hw_params
);
223 av_log(ctx
, AV_LOG_ERROR
, "cannot allocate hardware parameter structure (%s)\n",
228 res
= snd_pcm_hw_params_any(h
, hw_params
);
230 av_log(ctx
, AV_LOG_ERROR
, "cannot initialize hardware parameter structure (%s)\n",
235 res
= snd_pcm_hw_params_set_access(h
, hw_params
, SND_PCM_ACCESS_RW_INTERLEAVED
);
237 av_log(ctx
, AV_LOG_ERROR
, "cannot set access type (%s)\n",
242 res
= snd_pcm_hw_params_set_format(h
, hw_params
, format
);
244 av_log(ctx
, AV_LOG_ERROR
, "cannot set sample format 0x%04x %d (%s)\n",
245 *codec_id
, format
, snd_strerror(res
));
249 res
= snd_pcm_hw_params_set_rate_near(h
, hw_params
, sample_rate
, 0);
251 av_log(ctx
, AV_LOG_ERROR
, "cannot set sample rate (%s)\n",
256 res
= snd_pcm_hw_params_set_channels(h
, hw_params
, channels
);
258 av_log(ctx
, AV_LOG_ERROR
, "cannot set channel count to %d (%s)\n",
259 channels
, snd_strerror(res
));
263 snd_pcm_hw_params_get_buffer_size_max(hw_params
, &buffer_size
);
264 buffer_size
= FFMIN(buffer_size
, ALSA_BUFFER_SIZE_MAX
);
265 /* TODO: maybe use ctx->max_picture_buffer somehow */
266 res
= snd_pcm_hw_params_set_buffer_size_near(h
, hw_params
, &buffer_size
);
268 av_log(ctx
, AV_LOG_ERROR
, "cannot set ALSA buffer size (%s)\n",
273 snd_pcm_hw_params_get_period_size_min(hw_params
, &period_size
, NULL
);
275 period_size
= buffer_size
/ 4;
276 res
= snd_pcm_hw_params_set_period_size_near(h
, hw_params
, &period_size
, NULL
);
278 av_log(ctx
, AV_LOG_ERROR
, "cannot set ALSA period size (%s)\n",
282 s
->period_size
= period_size
;
284 res
= snd_pcm_hw_params(h
, hw_params
);
286 av_log(ctx
, AV_LOG_ERROR
, "cannot set parameters (%s)\n",
291 snd_pcm_hw_params_free(hw_params
);
293 if (channels
> 2 && layout
) {
294 if (find_reorder_func(s
, *codec_id
, layout
, mode
== SND_PCM_STREAM_PLAYBACK
) < 0) {
296 av_get_channel_layout_string(name
, sizeof(name
), channels
, layout
);
297 av_log(ctx
, AV_LOG_WARNING
, "ALSA channel layout unknown or unimplemented for %s %s.\n",
298 name
, mode
== SND_PCM_STREAM_PLAYBACK
? "playback" : "capture");
300 if (s
->reorder_func
) {
301 s
->reorder_buf_size
= buffer_size
;
302 s
->reorder_buf
= av_malloc(s
->reorder_buf_size
* s
->frame_size
);
312 snd_pcm_hw_params_free(hw_params
);
318 av_cold
int ff_alsa_close(AVFormatContext
*s1
)
320 AlsaData
*s
= s1
->priv_data
;
322 av_freep(&s
->reorder_buf
);
327 int ff_alsa_xrun_recover(AVFormatContext
*s1
, int err
)
329 AlsaData
*s
= s1
->priv_data
;
330 snd_pcm_t
*handle
= s
->h
;
332 av_log(s1
, AV_LOG_WARNING
, "ALSA buffer xrun.\n");
334 err
= snd_pcm_prepare(handle
);
336 av_log(s1
, AV_LOG_ERROR
, "cannot recover from underrun (snd_pcm_prepare failed: %s)\n", snd_strerror(err
));
340 } else if (err
== -ESTRPIPE
) {
341 av_log(s1
, AV_LOG_ERROR
, "-ESTRPIPE... Unsupported!\n");
348 int ff_alsa_extend_reorder_buf(AlsaData
*s
, int min_size
)
350 int size
= s
->reorder_buf_size
;
353 av_assert0(size
!= 0);
354 while (size
< min_size
)
356 r
= av_realloc(s
->reorder_buf
, size
* s
->frame_size
);
358 return AVERROR(ENOMEM
);
360 s
->reorder_buf_size
= size
;