libavdevice/alsa-audio-dec.c
Go to the documentation of this file.
00001 /*
00002  * ALSA input and output
00003  * Copyright (c) 2007 Luca Abeni ( lucabe72 email it )
00004  * Copyright (c) 2007 Benoit Fouet ( benoit fouet free fr )
00005  *
00006  * This file is part of Libav.
00007  *
00008  * Libav is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2.1 of the License, or (at your option) any later version.
00012  *
00013  * Libav is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with Libav; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00021  */
00022 
00048 #include <alsa/asoundlib.h>
00049 #include "libavformat/avformat.h"
00050 #include "libavformat/internal.h"
00051 #include "libavutil/opt.h"
00052 
00053 #include "alsa-audio.h"
00054 
00055 static av_cold int audio_read_header(AVFormatContext *s1,
00056                                      AVFormatParameters *ap)
00057 {
00058     AlsaData *s = s1->priv_data;
00059     AVStream *st;
00060     int ret;
00061     enum CodecID codec_id;
00062     snd_pcm_sw_params_t *sw_params;
00063 
00064     st = avformat_new_stream(s1, NULL);
00065     if (!st) {
00066         av_log(s1, AV_LOG_ERROR, "Cannot add stream\n");
00067 
00068         return AVERROR(ENOMEM);
00069     }
00070     codec_id    = s1->audio_codec_id;
00071 
00072     ret = ff_alsa_open(s1, SND_PCM_STREAM_CAPTURE, &s->sample_rate, s->channels,
00073         &codec_id);
00074     if (ret < 0) {
00075         return AVERROR(EIO);
00076     }
00077 
00078     if (snd_pcm_type(s->h) != SND_PCM_TYPE_HW)
00079         av_log(s1, AV_LOG_WARNING,
00080                "capture with some ALSA plugins, especially dsnoop, "
00081                "may hang.\n");
00082 
00083     ret = snd_pcm_sw_params_malloc(&sw_params);
00084     if (ret < 0) {
00085         av_log(s1, AV_LOG_ERROR, "cannot allocate software parameters structure (%s)\n",
00086                snd_strerror(ret));
00087         goto fail;
00088     }
00089 
00090     snd_pcm_sw_params_current(s->h, sw_params);
00091     snd_pcm_sw_params_set_tstamp_mode(s->h, sw_params, SND_PCM_TSTAMP_ENABLE);
00092 
00093     ret = snd_pcm_sw_params(s->h, sw_params);
00094     snd_pcm_sw_params_free(sw_params);
00095     if (ret < 0) {
00096         av_log(s1, AV_LOG_ERROR, "cannot install ALSA software parameters (%s)\n",
00097                snd_strerror(ret));
00098         goto fail;
00099     }
00100 
00101     /* take real parameters */
00102     st->codec->codec_type  = AVMEDIA_TYPE_AUDIO;
00103     st->codec->codec_id    = codec_id;
00104     st->codec->sample_rate = s->sample_rate;
00105     st->codec->channels    = s->channels;
00106     avpriv_set_pts_info(st, 64, 1, 1000000);  /* 64 bits pts in us */
00107 
00108     return 0;
00109 
00110 fail:
00111     snd_pcm_close(s->h);
00112     return AVERROR(EIO);
00113 }
00114 
00115 static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt)
00116 {
00117     AlsaData *s  = s1->priv_data;
00118     AVStream *st = s1->streams[0];
00119     int res;
00120     snd_htimestamp_t timestamp;
00121     snd_pcm_uframes_t ts_delay;
00122 
00123     if (av_new_packet(pkt, s->period_size) < 0) {
00124         return AVERROR(EIO);
00125     }
00126 
00127     while ((res = snd_pcm_readi(s->h, pkt->data, pkt->size / s->frame_size)) < 0) {
00128         if (res == -EAGAIN) {
00129             av_free_packet(pkt);
00130 
00131             return AVERROR(EAGAIN);
00132         }
00133         if (ff_alsa_xrun_recover(s1, res) < 0) {
00134             av_log(s1, AV_LOG_ERROR, "ALSA read error: %s\n",
00135                    snd_strerror(res));
00136             av_free_packet(pkt);
00137 
00138             return AVERROR(EIO);
00139         }
00140     }
00141 
00142     snd_pcm_htimestamp(s->h, &ts_delay, &timestamp);
00143     ts_delay += res;
00144     pkt->pts = timestamp.tv_sec * 1000000LL
00145                + (timestamp.tv_nsec * st->codec->sample_rate
00146                   - ts_delay * 1000000000LL + st->codec->sample_rate * 500LL)
00147                / (st->codec->sample_rate * 1000LL);
00148 
00149     pkt->size = res * s->frame_size;
00150 
00151     return 0;
00152 }
00153 
00154 static const AVOption options[] = {
00155     { "sample_rate", "", offsetof(AlsaData, sample_rate), AV_OPT_TYPE_INT, {.dbl = 48000}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
00156     { "channels",    "", offsetof(AlsaData, channels),    AV_OPT_TYPE_INT, {.dbl = 2},     1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
00157     { NULL },
00158 };
00159 
00160 static const AVClass alsa_demuxer_class = {
00161     .class_name     = "ALSA demuxer",
00162     .item_name      = av_default_item_name,
00163     .option         = options,
00164     .version        = LIBAVUTIL_VERSION_INT,
00165 };
00166 
00167 AVInputFormat ff_alsa_demuxer = {
00168     .name           = "alsa",
00169     .long_name      = NULL_IF_CONFIG_SMALL("ALSA audio input"),
00170     .priv_data_size = sizeof(AlsaData),
00171     .read_header    = audio_read_header,
00172     .read_packet    = audio_read_packet,
00173     .read_close     = ff_alsa_close,
00174     .flags          = AVFMT_NOFILE,
00175     .priv_class     = &alsa_demuxer_class,
00176 };