yading@10
|
1 /*
|
yading@10
|
2 * ALSA input and output
|
yading@10
|
3 * Copyright (c) 2007 Luca Abeni ( lucabe72 email it )
|
yading@10
|
4 * Copyright (c) 2007 Benoit Fouet ( benoit fouet free fr )
|
yading@10
|
5 *
|
yading@10
|
6 * This file is part of FFmpeg.
|
yading@10
|
7 *
|
yading@10
|
8 * FFmpeg is free software; you can redistribute it and/or
|
yading@10
|
9 * modify it under the terms of the GNU Lesser General Public
|
yading@10
|
10 * License as published by the Free Software Foundation; either
|
yading@10
|
11 * version 2.1 of the License, or (at your option) any later version.
|
yading@10
|
12 *
|
yading@10
|
13 * FFmpeg is distributed in the hope that it will be useful,
|
yading@10
|
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
yading@10
|
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
yading@10
|
16 * Lesser General Public License for more details.
|
yading@10
|
17 *
|
yading@10
|
18 * You should have received a copy of the GNU Lesser General Public
|
yading@10
|
19 * License along with FFmpeg; if not, write to the Free Software
|
yading@10
|
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
yading@10
|
21 */
|
yading@10
|
22
|
yading@10
|
23 /**
|
yading@10
|
24 * @file
|
yading@10
|
25 * ALSA input and output: common code
|
yading@10
|
26 * @author Luca Abeni ( lucabe72 email it )
|
yading@10
|
27 * @author Benoit Fouet ( benoit fouet free fr )
|
yading@10
|
28 * @author Nicolas George ( nicolas george normalesup org )
|
yading@10
|
29 */
|
yading@10
|
30
|
yading@10
|
31 #include <alsa/asoundlib.h>
|
yading@10
|
32 #include "avdevice.h"
|
yading@10
|
33 #include "libavutil/avassert.h"
|
yading@10
|
34 #include "libavutil/channel_layout.h"
|
yading@10
|
35
|
yading@10
|
36 #include "alsa-audio.h"
|
yading@10
|
37
|
yading@10
|
38 static av_cold snd_pcm_format_t codec_id_to_pcm_format(int codec_id)
|
yading@10
|
39 {
|
yading@10
|
40 switch(codec_id) {
|
yading@10
|
41 case AV_CODEC_ID_PCM_F64LE: return SND_PCM_FORMAT_FLOAT64_LE;
|
yading@10
|
42 case AV_CODEC_ID_PCM_F64BE: return SND_PCM_FORMAT_FLOAT64_BE;
|
yading@10
|
43 case AV_CODEC_ID_PCM_F32LE: return SND_PCM_FORMAT_FLOAT_LE;
|
yading@10
|
44 case AV_CODEC_ID_PCM_F32BE: return SND_PCM_FORMAT_FLOAT_BE;
|
yading@10
|
45 case AV_CODEC_ID_PCM_S32LE: return SND_PCM_FORMAT_S32_LE;
|
yading@10
|
46 case AV_CODEC_ID_PCM_S32BE: return SND_PCM_FORMAT_S32_BE;
|
yading@10
|
47 case AV_CODEC_ID_PCM_U32LE: return SND_PCM_FORMAT_U32_LE;
|
yading@10
|
48 case AV_CODEC_ID_PCM_U32BE: return SND_PCM_FORMAT_U32_BE;
|
yading@10
|
49 case AV_CODEC_ID_PCM_S24LE: return SND_PCM_FORMAT_S24_3LE;
|
yading@10
|
50 case AV_CODEC_ID_PCM_S24BE: return SND_PCM_FORMAT_S24_3BE;
|
yading@10
|
51 case AV_CODEC_ID_PCM_U24LE: return SND_PCM_FORMAT_U24_3LE;
|
yading@10
|
52 case AV_CODEC_ID_PCM_U24BE: return SND_PCM_FORMAT_U24_3BE;
|
yading@10
|
53 case AV_CODEC_ID_PCM_S16LE: return SND_PCM_FORMAT_S16_LE;
|
yading@10
|
54 case AV_CODEC_ID_PCM_S16BE: return SND_PCM_FORMAT_S16_BE;
|
yading@10
|
55 case AV_CODEC_ID_PCM_U16LE: return SND_PCM_FORMAT_U16_LE;
|
yading@10
|
56 case AV_CODEC_ID_PCM_U16BE: return SND_PCM_FORMAT_U16_BE;
|
yading@10
|
57 case AV_CODEC_ID_PCM_S8: return SND_PCM_FORMAT_S8;
|
yading@10
|
58 case AV_CODEC_ID_PCM_U8: return SND_PCM_FORMAT_U8;
|
yading@10
|
59 case AV_CODEC_ID_PCM_MULAW: return SND_PCM_FORMAT_MU_LAW;
|
yading@10
|
60 case AV_CODEC_ID_PCM_ALAW: return SND_PCM_FORMAT_A_LAW;
|
yading@10
|
61 default: return SND_PCM_FORMAT_UNKNOWN;
|
yading@10
|
62 }
|
yading@10
|
63 }
|
yading@10
|
64
|
yading@10
|
65 #define MAKE_REORDER_FUNC(NAME, TYPE, CHANNELS, LAYOUT, MAP) \
|
yading@10
|
66 static void alsa_reorder_ ## NAME ## _ ## LAYOUT(const void *in_v, \
|
yading@10
|
67 void *out_v, \
|
yading@10
|
68 int n) \
|
yading@10
|
69 { \
|
yading@10
|
70 const TYPE *in = in_v; \
|
yading@10
|
71 TYPE *out = out_v; \
|
yading@10
|
72 \
|
yading@10
|
73 while (n-- > 0) { \
|
yading@10
|
74 MAP \
|
yading@10
|
75 in += CHANNELS; \
|
yading@10
|
76 out += CHANNELS; \
|
yading@10
|
77 } \
|
yading@10
|
78 }
|
yading@10
|
79
|
yading@10
|
80 #define MAKE_REORDER_FUNCS(CHANNELS, LAYOUT, MAP) \
|
yading@10
|
81 MAKE_REORDER_FUNC(int8, int8_t, CHANNELS, LAYOUT, MAP) \
|
yading@10
|
82 MAKE_REORDER_FUNC(int16, int16_t, CHANNELS, LAYOUT, MAP) \
|
yading@10
|
83 MAKE_REORDER_FUNC(int32, int32_t, CHANNELS, LAYOUT, MAP) \
|
yading@10
|
84 MAKE_REORDER_FUNC(f32, float, CHANNELS, LAYOUT, MAP)
|
yading@10
|
85
|
yading@10
|
86 MAKE_REORDER_FUNCS(5, out_50, \
|
yading@10
|
87 out[0] = in[0]; \
|
yading@10
|
88 out[1] = in[1]; \
|
yading@10
|
89 out[2] = in[3]; \
|
yading@10
|
90 out[3] = in[4]; \
|
yading@10
|
91 out[4] = in[2]; \
|
yading@10
|
92 );
|
yading@10
|
93
|
yading@10
|
94 MAKE_REORDER_FUNCS(6, out_51, \
|
yading@10
|
95 out[0] = in[0]; \
|
yading@10
|
96 out[1] = in[1]; \
|
yading@10
|
97 out[2] = in[4]; \
|
yading@10
|
98 out[3] = in[5]; \
|
yading@10
|
99 out[4] = in[2]; \
|
yading@10
|
100 out[5] = in[3]; \
|
yading@10
|
101 );
|
yading@10
|
102
|
yading@10
|
103 MAKE_REORDER_FUNCS(8, out_71, \
|
yading@10
|
104 out[0] = in[0]; \
|
yading@10
|
105 out[1] = in[1]; \
|
yading@10
|
106 out[2] = in[4]; \
|
yading@10
|
107 out[3] = in[5]; \
|
yading@10
|
108 out[4] = in[2]; \
|
yading@10
|
109 out[5] = in[3]; \
|
yading@10
|
110 out[6] = in[6]; \
|
yading@10
|
111 out[7] = in[7]; \
|
yading@10
|
112 );
|
yading@10
|
113
|
yading@10
|
114 #define FORMAT_I8 0
|
yading@10
|
115 #define FORMAT_I16 1
|
yading@10
|
116 #define FORMAT_I32 2
|
yading@10
|
117 #define FORMAT_F32 3
|
yading@10
|
118
|
yading@10
|
119 #define PICK_REORDER(layout)\
|
yading@10
|
120 switch(format) {\
|
yading@10
|
121 case FORMAT_I8: s->reorder_func = alsa_reorder_int8_out_ ##layout; break;\
|
yading@10
|
122 case FORMAT_I16: s->reorder_func = alsa_reorder_int16_out_ ##layout; break;\
|
yading@10
|
123 case FORMAT_I32: s->reorder_func = alsa_reorder_int32_out_ ##layout; break;\
|
yading@10
|
124 case FORMAT_F32: s->reorder_func = alsa_reorder_f32_out_ ##layout; break;\
|
yading@10
|
125 }
|
yading@10
|
126
|
yading@10
|
127 static av_cold int find_reorder_func(AlsaData *s, int codec_id, uint64_t layout, int out)
|
yading@10
|
128 {
|
yading@10
|
129 int format;
|
yading@10
|
130
|
yading@10
|
131 /* reordering input is not currently supported */
|
yading@10
|
132 if (!out)
|
yading@10
|
133 return AVERROR(ENOSYS);
|
yading@10
|
134
|
yading@10
|
135 /* reordering is not needed for QUAD or 2_2 layout */
|
yading@10
|
136 if (layout == AV_CH_LAYOUT_QUAD || layout == AV_CH_LAYOUT_2_2)
|
yading@10
|
137 return 0;
|
yading@10
|
138
|
yading@10
|
139 switch (codec_id) {
|
yading@10
|
140 case AV_CODEC_ID_PCM_S8:
|
yading@10
|
141 case AV_CODEC_ID_PCM_U8:
|
yading@10
|
142 case AV_CODEC_ID_PCM_ALAW:
|
yading@10
|
143 case AV_CODEC_ID_PCM_MULAW: format = FORMAT_I8; break;
|
yading@10
|
144 case AV_CODEC_ID_PCM_S16LE:
|
yading@10
|
145 case AV_CODEC_ID_PCM_S16BE:
|
yading@10
|
146 case AV_CODEC_ID_PCM_U16LE:
|
yading@10
|
147 case AV_CODEC_ID_PCM_U16BE: format = FORMAT_I16; break;
|
yading@10
|
148 case AV_CODEC_ID_PCM_S32LE:
|
yading@10
|
149 case AV_CODEC_ID_PCM_S32BE:
|
yading@10
|
150 case AV_CODEC_ID_PCM_U32LE:
|
yading@10
|
151 case AV_CODEC_ID_PCM_U32BE: format = FORMAT_I32; break;
|
yading@10
|
152 case AV_CODEC_ID_PCM_F32LE:
|
yading@10
|
153 case AV_CODEC_ID_PCM_F32BE: format = FORMAT_F32; break;
|
yading@10
|
154 default: return AVERROR(ENOSYS);
|
yading@10
|
155 }
|
yading@10
|
156
|
yading@10
|
157 if (layout == AV_CH_LAYOUT_5POINT0_BACK || layout == AV_CH_LAYOUT_5POINT0)
|
yading@10
|
158 PICK_REORDER(50)
|
yading@10
|
159 else if (layout == AV_CH_LAYOUT_5POINT1_BACK || layout == AV_CH_LAYOUT_5POINT1)
|
yading@10
|
160 PICK_REORDER(51)
|
yading@10
|
161 else if (layout == AV_CH_LAYOUT_7POINT1)
|
yading@10
|
162 PICK_REORDER(71)
|
yading@10
|
163
|
yading@10
|
164 return s->reorder_func ? 0 : AVERROR(ENOSYS);
|
yading@10
|
165 }
|
yading@10
|
166
|
yading@10
|
167 av_cold int ff_alsa_open(AVFormatContext *ctx, snd_pcm_stream_t mode,
|
yading@10
|
168 unsigned int *sample_rate,
|
yading@10
|
169 int channels, enum AVCodecID *codec_id)
|
yading@10
|
170 {
|
yading@10
|
171 AlsaData *s = ctx->priv_data;
|
yading@10
|
172 const char *audio_device;
|
yading@10
|
173 int res, flags = 0;
|
yading@10
|
174 snd_pcm_format_t format;
|
yading@10
|
175 snd_pcm_t *h;
|
yading@10
|
176 snd_pcm_hw_params_t *hw_params;
|
yading@10
|
177 snd_pcm_uframes_t buffer_size, period_size;
|
yading@10
|
178 uint64_t layout = ctx->streams[0]->codec->channel_layout;
|
yading@10
|
179
|
yading@10
|
180 if (ctx->filename[0] == 0) audio_device = "default";
|
yading@10
|
181 else audio_device = ctx->filename;
|
yading@10
|
182
|
yading@10
|
183 if (*codec_id == AV_CODEC_ID_NONE)
|
yading@10
|
184 *codec_id = DEFAULT_CODEC_ID;
|
yading@10
|
185 format = codec_id_to_pcm_format(*codec_id);
|
yading@10
|
186 if (format == SND_PCM_FORMAT_UNKNOWN) {
|
yading@10
|
187 av_log(ctx, AV_LOG_ERROR, "sample format 0x%04x is not supported\n", *codec_id);
|
yading@10
|
188 return AVERROR(ENOSYS);
|
yading@10
|
189 }
|
yading@10
|
190 s->frame_size = av_get_bits_per_sample(*codec_id) / 8 * channels;
|
yading@10
|
191
|
yading@10
|
192 if (ctx->flags & AVFMT_FLAG_NONBLOCK) {
|
yading@10
|
193 flags = SND_PCM_NONBLOCK;
|
yading@10
|
194 }
|
yading@10
|
195 res = snd_pcm_open(&h, audio_device, mode, flags);
|
yading@10
|
196 if (res < 0) {
|
yading@10
|
197 av_log(ctx, AV_LOG_ERROR, "cannot open audio device %s (%s)\n",
|
yading@10
|
198 audio_device, snd_strerror(res));
|
yading@10
|
199 return AVERROR(EIO);
|
yading@10
|
200 }
|
yading@10
|
201
|
yading@10
|
202 res = snd_pcm_hw_params_malloc(&hw_params);
|
yading@10
|
203 if (res < 0) {
|
yading@10
|
204 av_log(ctx, AV_LOG_ERROR, "cannot allocate hardware parameter structure (%s)\n",
|
yading@10
|
205 snd_strerror(res));
|
yading@10
|
206 goto fail1;
|
yading@10
|
207 }
|
yading@10
|
208
|
yading@10
|
209 res = snd_pcm_hw_params_any(h, hw_params);
|
yading@10
|
210 if (res < 0) {
|
yading@10
|
211 av_log(ctx, AV_LOG_ERROR, "cannot initialize hardware parameter structure (%s)\n",
|
yading@10
|
212 snd_strerror(res));
|
yading@10
|
213 goto fail;
|
yading@10
|
214 }
|
yading@10
|
215
|
yading@10
|
216 res = snd_pcm_hw_params_set_access(h, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
|
yading@10
|
217 if (res < 0) {
|
yading@10
|
218 av_log(ctx, AV_LOG_ERROR, "cannot set access type (%s)\n",
|
yading@10
|
219 snd_strerror(res));
|
yading@10
|
220 goto fail;
|
yading@10
|
221 }
|
yading@10
|
222
|
yading@10
|
223 res = snd_pcm_hw_params_set_format(h, hw_params, format);
|
yading@10
|
224 if (res < 0) {
|
yading@10
|
225 av_log(ctx, AV_LOG_ERROR, "cannot set sample format 0x%04x %d (%s)\n",
|
yading@10
|
226 *codec_id, format, snd_strerror(res));
|
yading@10
|
227 goto fail;
|
yading@10
|
228 }
|
yading@10
|
229
|
yading@10
|
230 res = snd_pcm_hw_params_set_rate_near(h, hw_params, sample_rate, 0);
|
yading@10
|
231 if (res < 0) {
|
yading@10
|
232 av_log(ctx, AV_LOG_ERROR, "cannot set sample rate (%s)\n",
|
yading@10
|
233 snd_strerror(res));
|
yading@10
|
234 goto fail;
|
yading@10
|
235 }
|
yading@10
|
236
|
yading@10
|
237 res = snd_pcm_hw_params_set_channels(h, hw_params, channels);
|
yading@10
|
238 if (res < 0) {
|
yading@10
|
239 av_log(ctx, AV_LOG_ERROR, "cannot set channel count to %d (%s)\n",
|
yading@10
|
240 channels, snd_strerror(res));
|
yading@10
|
241 goto fail;
|
yading@10
|
242 }
|
yading@10
|
243
|
yading@10
|
244 snd_pcm_hw_params_get_buffer_size_max(hw_params, &buffer_size);
|
yading@10
|
245 buffer_size = FFMIN(buffer_size, ALSA_BUFFER_SIZE_MAX);
|
yading@10
|
246 /* TODO: maybe use ctx->max_picture_buffer somehow */
|
yading@10
|
247 res = snd_pcm_hw_params_set_buffer_size_near(h, hw_params, &buffer_size);
|
yading@10
|
248 if (res < 0) {
|
yading@10
|
249 av_log(ctx, AV_LOG_ERROR, "cannot set ALSA buffer size (%s)\n",
|
yading@10
|
250 snd_strerror(res));
|
yading@10
|
251 goto fail;
|
yading@10
|
252 }
|
yading@10
|
253
|
yading@10
|
254 snd_pcm_hw_params_get_period_size_min(hw_params, &period_size, NULL);
|
yading@10
|
255 if (!period_size)
|
yading@10
|
256 period_size = buffer_size / 4;
|
yading@10
|
257 res = snd_pcm_hw_params_set_period_size_near(h, hw_params, &period_size, NULL);
|
yading@10
|
258 if (res < 0) {
|
yading@10
|
259 av_log(ctx, AV_LOG_ERROR, "cannot set ALSA period size (%s)\n",
|
yading@10
|
260 snd_strerror(res));
|
yading@10
|
261 goto fail;
|
yading@10
|
262 }
|
yading@10
|
263 s->period_size = period_size;
|
yading@10
|
264
|
yading@10
|
265 res = snd_pcm_hw_params(h, hw_params);
|
yading@10
|
266 if (res < 0) {
|
yading@10
|
267 av_log(ctx, AV_LOG_ERROR, "cannot set parameters (%s)\n",
|
yading@10
|
268 snd_strerror(res));
|
yading@10
|
269 goto fail;
|
yading@10
|
270 }
|
yading@10
|
271
|
yading@10
|
272 snd_pcm_hw_params_free(hw_params);
|
yading@10
|
273
|
yading@10
|
274 if (channels > 2 && layout) {
|
yading@10
|
275 if (find_reorder_func(s, *codec_id, layout, mode == SND_PCM_STREAM_PLAYBACK) < 0) {
|
yading@10
|
276 char name[128];
|
yading@10
|
277 av_get_channel_layout_string(name, sizeof(name), channels, layout);
|
yading@10
|
278 av_log(ctx, AV_LOG_WARNING, "ALSA channel layout unknown or unimplemented for %s %s.\n",
|
yading@10
|
279 name, mode == SND_PCM_STREAM_PLAYBACK ? "playback" : "capture");
|
yading@10
|
280 }
|
yading@10
|
281 if (s->reorder_func) {
|
yading@10
|
282 s->reorder_buf_size = buffer_size;
|
yading@10
|
283 s->reorder_buf = av_malloc(s->reorder_buf_size * s->frame_size);
|
yading@10
|
284 if (!s->reorder_buf)
|
yading@10
|
285 goto fail1;
|
yading@10
|
286 }
|
yading@10
|
287 }
|
yading@10
|
288
|
yading@10
|
289 s->h = h;
|
yading@10
|
290 return 0;
|
yading@10
|
291
|
yading@10
|
292 fail:
|
yading@10
|
293 snd_pcm_hw_params_free(hw_params);
|
yading@10
|
294 fail1:
|
yading@10
|
295 snd_pcm_close(h);
|
yading@10
|
296 return AVERROR(EIO);
|
yading@10
|
297 }
|
yading@10
|
298
|
yading@10
|
299 av_cold int ff_alsa_close(AVFormatContext *s1)
|
yading@10
|
300 {
|
yading@10
|
301 AlsaData *s = s1->priv_data;
|
yading@10
|
302
|
yading@10
|
303 av_freep(&s->reorder_buf);
|
yading@10
|
304 if (CONFIG_ALSA_INDEV)
|
yading@10
|
305 ff_timefilter_destroy(s->timefilter);
|
yading@10
|
306 snd_pcm_close(s->h);
|
yading@10
|
307 return 0;
|
yading@10
|
308 }
|
yading@10
|
309
|
yading@10
|
310 int ff_alsa_xrun_recover(AVFormatContext *s1, int err)
|
yading@10
|
311 {
|
yading@10
|
312 AlsaData *s = s1->priv_data;
|
yading@10
|
313 snd_pcm_t *handle = s->h;
|
yading@10
|
314
|
yading@10
|
315 av_log(s1, AV_LOG_WARNING, "ALSA buffer xrun.\n");
|
yading@10
|
316 if (err == -EPIPE) {
|
yading@10
|
317 err = snd_pcm_prepare(handle);
|
yading@10
|
318 if (err < 0) {
|
yading@10
|
319 av_log(s1, AV_LOG_ERROR, "cannot recover from underrun (snd_pcm_prepare failed: %s)\n", snd_strerror(err));
|
yading@10
|
320
|
yading@10
|
321 return AVERROR(EIO);
|
yading@10
|
322 }
|
yading@10
|
323 } else if (err == -ESTRPIPE) {
|
yading@10
|
324 av_log(s1, AV_LOG_ERROR, "-ESTRPIPE... Unsupported!\n");
|
yading@10
|
325
|
yading@10
|
326 return -1;
|
yading@10
|
327 }
|
yading@10
|
328 return err;
|
yading@10
|
329 }
|
yading@10
|
330
|
yading@10
|
331 int ff_alsa_extend_reorder_buf(AlsaData *s, int min_size)
|
yading@10
|
332 {
|
yading@10
|
333 int size = s->reorder_buf_size;
|
yading@10
|
334 void *r;
|
yading@10
|
335
|
yading@10
|
336 av_assert0(size != 0);
|
yading@10
|
337 while (size < min_size)
|
yading@10
|
338 size *= 2;
|
yading@10
|
339 r = av_realloc(s->reorder_buf, size * s->frame_size);
|
yading@10
|
340 if (!r)
|
yading@10
|
341 return AVERROR(ENOMEM);
|
yading@10
|
342 s->reorder_buf = r;
|
yading@10
|
343 s->reorder_buf_size = size;
|
yading@10
|
344 return 0;
|
yading@10
|
345 }
|