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