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: output 26cabdff1aSopenharmony_ci * @author Luca Abeni ( lucabe72 email it ) 27cabdff1aSopenharmony_ci * @author Benoit Fouet ( benoit fouet free fr ) 28cabdff1aSopenharmony_ci * 29cabdff1aSopenharmony_ci * This avdevice encoder can play audio to an ALSA (Advanced Linux 30cabdff1aSopenharmony_ci * Sound Architecture) device. 31cabdff1aSopenharmony_ci * 32cabdff1aSopenharmony_ci * The filename parameter is the name of an ALSA PCM device capable of 33cabdff1aSopenharmony_ci * capture, for example "default" or "plughw:1"; see the ALSA documentation 34cabdff1aSopenharmony_ci * for naming conventions. The empty string is equivalent to "default". 35cabdff1aSopenharmony_ci * 36cabdff1aSopenharmony_ci * The playback period is set to the lower value available for the device, 37cabdff1aSopenharmony_ci * which gives a low latency suitable for real-time playback. 38cabdff1aSopenharmony_ci */ 39cabdff1aSopenharmony_ci 40cabdff1aSopenharmony_ci#include <alsa/asoundlib.h> 41cabdff1aSopenharmony_ci 42cabdff1aSopenharmony_ci#include "libavutil/internal.h" 43cabdff1aSopenharmony_ci#include "libavutil/time.h" 44cabdff1aSopenharmony_ci 45cabdff1aSopenharmony_ci 46cabdff1aSopenharmony_ci#include "libavformat/internal.h" 47cabdff1aSopenharmony_ci#include "libavformat/mux.h" 48cabdff1aSopenharmony_ci#include "avdevice.h" 49cabdff1aSopenharmony_ci#include "alsa.h" 50cabdff1aSopenharmony_ci 51cabdff1aSopenharmony_cistatic av_cold int audio_write_header(AVFormatContext *s1) 52cabdff1aSopenharmony_ci{ 53cabdff1aSopenharmony_ci AlsaData *s = s1->priv_data; 54cabdff1aSopenharmony_ci AVStream *st = NULL; 55cabdff1aSopenharmony_ci unsigned int sample_rate; 56cabdff1aSopenharmony_ci enum AVCodecID codec_id; 57cabdff1aSopenharmony_ci int res; 58cabdff1aSopenharmony_ci 59cabdff1aSopenharmony_ci if (s1->nb_streams != 1 || s1->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_AUDIO) { 60cabdff1aSopenharmony_ci av_log(s1, AV_LOG_ERROR, "Only a single audio stream is supported.\n"); 61cabdff1aSopenharmony_ci return AVERROR(EINVAL); 62cabdff1aSopenharmony_ci } 63cabdff1aSopenharmony_ci st = s1->streams[0]; 64cabdff1aSopenharmony_ci 65cabdff1aSopenharmony_ci sample_rate = st->codecpar->sample_rate; 66cabdff1aSopenharmony_ci codec_id = st->codecpar->codec_id; 67cabdff1aSopenharmony_ci res = ff_alsa_open(s1, SND_PCM_STREAM_PLAYBACK, &sample_rate, 68cabdff1aSopenharmony_ci st->codecpar->ch_layout.nb_channels, &codec_id); 69cabdff1aSopenharmony_ci if (sample_rate != st->codecpar->sample_rate) { 70cabdff1aSopenharmony_ci av_log(s1, AV_LOG_ERROR, 71cabdff1aSopenharmony_ci "sample rate %d not available, nearest is %d\n", 72cabdff1aSopenharmony_ci st->codecpar->sample_rate, sample_rate); 73cabdff1aSopenharmony_ci goto fail; 74cabdff1aSopenharmony_ci } 75cabdff1aSopenharmony_ci avpriv_set_pts_info(st, 64, 1, sample_rate); 76cabdff1aSopenharmony_ci 77cabdff1aSopenharmony_ci return res; 78cabdff1aSopenharmony_ci 79cabdff1aSopenharmony_cifail: 80cabdff1aSopenharmony_ci snd_pcm_close(s->h); 81cabdff1aSopenharmony_ci return AVERROR(EIO); 82cabdff1aSopenharmony_ci} 83cabdff1aSopenharmony_ci 84cabdff1aSopenharmony_cistatic int audio_write_packet(AVFormatContext *s1, AVPacket *pkt) 85cabdff1aSopenharmony_ci{ 86cabdff1aSopenharmony_ci AlsaData *s = s1->priv_data; 87cabdff1aSopenharmony_ci int res; 88cabdff1aSopenharmony_ci int size = pkt->size; 89cabdff1aSopenharmony_ci const uint8_t *buf = pkt->data; 90cabdff1aSopenharmony_ci 91cabdff1aSopenharmony_ci size /= s->frame_size; 92cabdff1aSopenharmony_ci if (pkt->dts != AV_NOPTS_VALUE) 93cabdff1aSopenharmony_ci s->timestamp = pkt->dts; 94cabdff1aSopenharmony_ci s->timestamp += pkt->duration ? pkt->duration : size; 95cabdff1aSopenharmony_ci 96cabdff1aSopenharmony_ci if (s->reorder_func) { 97cabdff1aSopenharmony_ci if (size > s->reorder_buf_size) 98cabdff1aSopenharmony_ci if (ff_alsa_extend_reorder_buf(s, size)) 99cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 100cabdff1aSopenharmony_ci s->reorder_func(buf, s->reorder_buf, size); 101cabdff1aSopenharmony_ci buf = s->reorder_buf; 102cabdff1aSopenharmony_ci } 103cabdff1aSopenharmony_ci while ((res = snd_pcm_writei(s->h, buf, size)) < 0) { 104cabdff1aSopenharmony_ci if (res == -EAGAIN) { 105cabdff1aSopenharmony_ci 106cabdff1aSopenharmony_ci return AVERROR(EAGAIN); 107cabdff1aSopenharmony_ci } 108cabdff1aSopenharmony_ci 109cabdff1aSopenharmony_ci if (ff_alsa_xrun_recover(s1, res) < 0) { 110cabdff1aSopenharmony_ci av_log(s1, AV_LOG_ERROR, "ALSA write error: %s\n", 111cabdff1aSopenharmony_ci snd_strerror(res)); 112cabdff1aSopenharmony_ci 113cabdff1aSopenharmony_ci return AVERROR(EIO); 114cabdff1aSopenharmony_ci } 115cabdff1aSopenharmony_ci } 116cabdff1aSopenharmony_ci 117cabdff1aSopenharmony_ci return 0; 118cabdff1aSopenharmony_ci} 119cabdff1aSopenharmony_ci 120cabdff1aSopenharmony_cistatic int audio_write_frame(AVFormatContext *s1, int stream_index, 121cabdff1aSopenharmony_ci AVFrame **frame, unsigned flags) 122cabdff1aSopenharmony_ci{ 123cabdff1aSopenharmony_ci AlsaData *s = s1->priv_data; 124cabdff1aSopenharmony_ci AVPacket pkt; 125cabdff1aSopenharmony_ci 126cabdff1aSopenharmony_ci /* ff_alsa_open() should have accepted only supported formats */ 127cabdff1aSopenharmony_ci if ((flags & AV_WRITE_UNCODED_FRAME_QUERY)) 128cabdff1aSopenharmony_ci return av_sample_fmt_is_planar(s1->streams[stream_index]->codecpar->format) ? 129cabdff1aSopenharmony_ci AVERROR(EINVAL) : 0; 130cabdff1aSopenharmony_ci /* set only used fields */ 131cabdff1aSopenharmony_ci pkt.data = (*frame)->data[0]; 132cabdff1aSopenharmony_ci pkt.size = (*frame)->nb_samples * s->frame_size; 133cabdff1aSopenharmony_ci pkt.dts = (*frame)->pkt_dts; 134cabdff1aSopenharmony_ci pkt.duration = (*frame)->pkt_duration; 135cabdff1aSopenharmony_ci return audio_write_packet(s1, &pkt); 136cabdff1aSopenharmony_ci} 137cabdff1aSopenharmony_ci 138cabdff1aSopenharmony_cistatic void 139cabdff1aSopenharmony_ciaudio_get_output_timestamp(AVFormatContext *s1, int stream, 140cabdff1aSopenharmony_ci int64_t *dts, int64_t *wall) 141cabdff1aSopenharmony_ci{ 142cabdff1aSopenharmony_ci AlsaData *s = s1->priv_data; 143cabdff1aSopenharmony_ci snd_pcm_sframes_t delay = 0; 144cabdff1aSopenharmony_ci *wall = av_gettime(); 145cabdff1aSopenharmony_ci snd_pcm_delay(s->h, &delay); 146cabdff1aSopenharmony_ci *dts = s->timestamp - delay; 147cabdff1aSopenharmony_ci} 148cabdff1aSopenharmony_ci 149cabdff1aSopenharmony_cistatic int audio_get_device_list(AVFormatContext *h, AVDeviceInfoList *device_list) 150cabdff1aSopenharmony_ci{ 151cabdff1aSopenharmony_ci return ff_alsa_get_device_list(device_list, SND_PCM_STREAM_PLAYBACK); 152cabdff1aSopenharmony_ci} 153cabdff1aSopenharmony_ci 154cabdff1aSopenharmony_cistatic const AVClass alsa_muxer_class = { 155cabdff1aSopenharmony_ci .class_name = "ALSA outdev", 156cabdff1aSopenharmony_ci .item_name = av_default_item_name, 157cabdff1aSopenharmony_ci .version = LIBAVUTIL_VERSION_INT, 158cabdff1aSopenharmony_ci .category = AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT, 159cabdff1aSopenharmony_ci}; 160cabdff1aSopenharmony_ci 161cabdff1aSopenharmony_ciconst AVOutputFormat ff_alsa_muxer = { 162cabdff1aSopenharmony_ci .name = "alsa", 163cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("ALSA audio output"), 164cabdff1aSopenharmony_ci .priv_data_size = sizeof(AlsaData), 165cabdff1aSopenharmony_ci .audio_codec = DEFAULT_CODEC_ID, 166cabdff1aSopenharmony_ci .video_codec = AV_CODEC_ID_NONE, 167cabdff1aSopenharmony_ci .write_header = audio_write_header, 168cabdff1aSopenharmony_ci .write_packet = audio_write_packet, 169cabdff1aSopenharmony_ci .write_trailer = ff_alsa_close, 170cabdff1aSopenharmony_ci .write_uncoded_frame = audio_write_frame, 171cabdff1aSopenharmony_ci .get_device_list = audio_get_device_list, 172cabdff1aSopenharmony_ci .get_output_timestamp = audio_get_output_timestamp, 173cabdff1aSopenharmony_ci .flags = AVFMT_NOFILE, 174cabdff1aSopenharmony_ci .priv_class = &alsa_muxer_class, 175cabdff1aSopenharmony_ci}; 176