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