1/* 2 * ALSA input and output 3 * Copyright (c) 2007 Luca Abeni ( lucabe72 email it ) 4 * Copyright (c) 2007 Benoit Fouet ( benoit fouet free fr ) 5 * 6 * This file is part of FFmpeg. 7 * 8 * FFmpeg is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * FFmpeg is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with FFmpeg; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 */ 22 23/** 24 * @file 25 * ALSA input and output: input 26 * @author Luca Abeni ( lucabe72 email it ) 27 * @author Benoit Fouet ( benoit fouet free fr ) 28 * @author Nicolas George ( nicolas george normalesup org ) 29 * 30 * This avdevice decoder allows to capture audio from an ALSA (Advanced 31 * Linux Sound Architecture) device. 32 * 33 * The filename parameter is the name of an ALSA PCM device capable of 34 * capture, for example "default" or "plughw:1"; see the ALSA documentation 35 * for naming conventions. The empty string is equivalent to "default". 36 * 37 * The capture period is set to the lower value available for the device, 38 * which gives a low latency suitable for real-time capture. 39 * 40 * The PTS are an Unix time in microsecond. 41 * 42 * Due to a bug in the ALSA library 43 * (https://bugtrack.alsa-project.org/alsa-bug/view.php?id=4308), this 44 * decoder does not work with certain ALSA plugins, especially the dsnoop 45 * plugin. 46 */ 47 48#include <alsa/asoundlib.h> 49#include "libavformat/avformat.h" 50 51#include "alsa-audio.h" 52 53static av_cold int audio_read_header(AVFormatContext *s1, 54 AVFormatParameters *ap) 55{ 56 AlsaData *s = s1->priv_data; 57 AVStream *st; 58 int ret; 59 unsigned int sample_rate; 60 enum CodecID codec_id; 61 snd_pcm_sw_params_t *sw_params; 62 63 if (ap->sample_rate <= 0) { 64 av_log(s1, AV_LOG_ERROR, "Bad sample rate %d\n", ap->sample_rate); 65 66 return AVERROR(EIO); 67 } 68 69 if (ap->channels <= 0) { 70 av_log(s1, AV_LOG_ERROR, "Bad channels number %d\n", ap->channels); 71 72 return AVERROR(EIO); 73 } 74 75 st = av_new_stream(s1, 0); 76 if (!st) { 77 av_log(s1, AV_LOG_ERROR, "Cannot add stream\n"); 78 79 return AVERROR(ENOMEM); 80 } 81 sample_rate = ap->sample_rate; 82 codec_id = s1->audio_codec_id; 83 84 ret = ff_alsa_open(s1, SND_PCM_STREAM_CAPTURE, &sample_rate, ap->channels, 85 &codec_id); 86 if (ret < 0) { 87 return AVERROR(EIO); 88 } 89 90 if (snd_pcm_type(s->h) != SND_PCM_TYPE_HW) 91 av_log(s1, AV_LOG_WARNING, 92 "capture with some ALSA plugins, especially dsnoop, " 93 "may hang.\n"); 94 95 ret = snd_pcm_sw_params_malloc(&sw_params); 96 if (ret < 0) { 97 av_log(s1, AV_LOG_ERROR, "cannot allocate software parameters structure (%s)\n", 98 snd_strerror(ret)); 99 goto fail; 100 } 101 102 snd_pcm_sw_params_current(s->h, sw_params); 103 snd_pcm_sw_params_set_tstamp_mode(s->h, sw_params, SND_PCM_TSTAMP_ENABLE); 104 105 ret = snd_pcm_sw_params(s->h, sw_params); 106 snd_pcm_sw_params_free(sw_params); 107 if (ret < 0) { 108 av_log(s1, AV_LOG_ERROR, "cannot install ALSA software parameters (%s)\n", 109 snd_strerror(ret)); 110 goto fail; 111 } 112 113 /* take real parameters */ 114 st->codec->codec_type = AVMEDIA_TYPE_AUDIO; 115 st->codec->codec_id = codec_id; 116 st->codec->sample_rate = sample_rate; 117 st->codec->channels = ap->channels; 118 av_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */ 119 120 return 0; 121 122fail: 123 snd_pcm_close(s->h); 124 return AVERROR(EIO); 125} 126 127static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt) 128{ 129 AlsaData *s = s1->priv_data; 130 AVStream *st = s1->streams[0]; 131 int res; 132 snd_htimestamp_t timestamp; 133 snd_pcm_uframes_t ts_delay; 134 135 if (av_new_packet(pkt, s->period_size) < 0) { 136 return AVERROR(EIO); 137 } 138 139 while ((res = snd_pcm_readi(s->h, pkt->data, pkt->size / s->frame_size)) < 0) { 140 if (res == -EAGAIN) { 141 av_free_packet(pkt); 142 143 return AVERROR(EAGAIN); 144 } 145 if (ff_alsa_xrun_recover(s1, res) < 0) { 146 av_log(s1, AV_LOG_ERROR, "ALSA read error: %s\n", 147 snd_strerror(res)); 148 av_free_packet(pkt); 149 150 return AVERROR(EIO); 151 } 152 } 153 154 snd_pcm_htimestamp(s->h, &ts_delay, ×tamp); 155 ts_delay += res; 156 pkt->pts = timestamp.tv_sec * 1000000LL 157 + (timestamp.tv_nsec * st->codec->sample_rate 158 - ts_delay * 1000000000LL + st->codec->sample_rate * 500LL) 159 / (st->codec->sample_rate * 1000LL); 160 161 pkt->size = res * s->frame_size; 162 163 return 0; 164} 165 166AVInputFormat alsa_demuxer = { 167 "alsa", 168 NULL_IF_CONFIG_SMALL("ALSA audio input"), 169 sizeof(AlsaData), 170 NULL, 171 audio_read_header, 172 audio_read_packet, 173 ff_alsa_close, 174 .flags = AVFMT_NOFILE, 175}; 176