annotate ffmpeg/libavdevice/alsa-audio-common.c @ 13:844d341cf643 tip

Back up before ISMIR
author Yading Song <yading.song@eecs.qmul.ac.uk>
date Thu, 31 Oct 2013 13:17:06 +0000
parents 6840f77b83aa
children
rev   line source
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 }