Patch by Nicolas George: name surname normalesup org Original thread: [FFmpeg-devel] [PATCH] ALSA for libavdevice Date: 12/09/2008 07:17 PM Originally committed as revision 16800 to svn://svn.ffmpeg.org/ffmpeg/trunktags/v0.5
@@ -838,6 +838,7 @@ ARCH_EXT_LIST=' | |||||
HAVE_LIST=" | HAVE_LIST=" | ||||
$ARCH_EXT_LIST | $ARCH_EXT_LIST | ||||
$THREADS_LIST | $THREADS_LIST | ||||
alsa_asoundlib_h | |||||
altivec_h | altivec_h | ||||
arpa_inet_h | arpa_inet_h | ||||
bswap | bswap | ||||
@@ -1069,6 +1070,10 @@ vdpau_deps="vdpau_vdpau_h vdpau_vdpau_x11_h" | |||||
# demuxers / muxers | # demuxers / muxers | ||||
ac3_demuxer_deps="ac3_parser" | ac3_demuxer_deps="ac3_parser" | ||||
alsa_demuxer_deps="alsa_asoundlib_h snd_pcm_htimestamp" | |||||
alsa_demuxer_extralibs="-lasound" | |||||
alsa_muxer_deps="alsa_asoundlib_h" | |||||
alsa_muxer_extralibs="-lasound" | |||||
audio_beos_demuxer_deps="audio_beos" | audio_beos_demuxer_deps="audio_beos" | ||||
audio_beos_demuxer_extralibs="-lmedia -lbe" | audio_beos_demuxer_extralibs="-lmedia -lbe" | ||||
audio_beos_muxer_deps="audio_beos" | audio_beos_muxer_deps="audio_beos" | ||||
@@ -2044,6 +2049,9 @@ check_header dev/ic/bt8xx.h | |||||
check_header sys/soundcard.h | check_header sys/soundcard.h | ||||
check_header soundcard.h | check_header soundcard.h | ||||
check_header alsa/asoundlib.h && | |||||
check_lib2 alsa/asoundlib.h snd_pcm_htimestamp -lasound | |||||
# deal with the X11 frame grabber | # deal with the X11 frame grabber | ||||
enabled x11grab && | enabled x11grab && | ||||
check_header X11/Xlib.h && | check_header X11/Xlib.h && | ||||
@@ -8,6 +8,8 @@ HEADERS = avdevice.h | |||||
OBJS = alldevices.o | OBJS = alldevices.o | ||||
# input/output devices | # input/output devices | ||||
OBJS-$(CONFIG_ALSA_DEMUXER) += alsa-audio-common.o alsa-audio-dec.o | |||||
OBJS-$(CONFIG_ALSA_MUXER) += alsa-audio-common.o alsa-audio-enc.o | |||||
OBJS-$(CONFIG_BKTR_DEMUXER) += bktr.o | OBJS-$(CONFIG_BKTR_DEMUXER) += bktr.o | ||||
OBJS-$(CONFIG_DV1394_DEMUXER) += dv1394.o | OBJS-$(CONFIG_DV1394_DEMUXER) += dv1394.o | ||||
OBJS-$(CONFIG_OSS_DEMUXER) += oss_audio.o | OBJS-$(CONFIG_OSS_DEMUXER) += oss_audio.o | ||||
@@ -44,6 +44,7 @@ void avdevice_register_all(void) | |||||
initialized = 1; | initialized = 1; | ||||
/* devices */ | /* devices */ | ||||
REGISTER_MUXDEMUX (ALSA, alsa); | |||||
REGISTER_MUXDEMUX (AUDIO_BEOS, audio_beos); | REGISTER_MUXDEMUX (AUDIO_BEOS, audio_beos); | ||||
REGISTER_DEMUXER (BKTR, bktr); | REGISTER_DEMUXER (BKTR, bktr); | ||||
REGISTER_DEMUXER (DV1394, dv1394); | REGISTER_DEMUXER (DV1394, dv1394); | ||||
@@ -0,0 +1,186 @@ | |||||
/* | |||||
* ALSA input and output | |||||
* Copyright (c) 2007 Luca Abeni ( lucabe72 email it ) | |||||
* Copyright (c) 2007 Benoit Fouet ( benoit fouet free fr ) | |||||
* | |||||
* This file is part of FFmpeg. | |||||
* | |||||
* FFmpeg is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation; either | |||||
* version 2.1 of the License, or (at your option) any later version. | |||||
* | |||||
* FFmpeg is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
* Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public | |||||
* License along with FFmpeg; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||||
*/ | |||||
/** | |||||
* @file alsa-audio-common.c | |||||
* ALSA input and output: common code | |||||
* @author Luca Abeni ( lucabe72 email it ) | |||||
* @author Benoit Fouet ( benoit fouet free fr ) | |||||
* @author Nicolas George ( nicolas george normalesup org ) | |||||
*/ | |||||
#include "libavformat/avformat.h" | |||||
#include <alsa/asoundlib.h> | |||||
#include "alsa-audio.h" | |||||
static av_cold snd_pcm_format_t codec_id_to_pcm_format(int codec_id) | |||||
{ | |||||
switch(codec_id) { | |||||
case CODEC_ID_PCM_S16LE: return SND_PCM_FORMAT_S16_LE; | |||||
case CODEC_ID_PCM_S16BE: return SND_PCM_FORMAT_S16_BE; | |||||
case CODEC_ID_PCM_S8: return SND_PCM_FORMAT_S8; | |||||
default: return SND_PCM_FORMAT_UNKNOWN; | |||||
} | |||||
} | |||||
av_cold int ff_alsa_open(AVFormatContext *ctx, int mode, | |||||
unsigned int *sample_rate, | |||||
int channels, int *codec_id) | |||||
{ | |||||
AlsaData *s = ctx->priv_data; | |||||
const char *audio_device; | |||||
int res, flags = 0; | |||||
snd_pcm_format_t format; | |||||
snd_pcm_t *h; | |||||
snd_pcm_hw_params_t *hw_params; | |||||
snd_pcm_uframes_t buffer_size, period_size; | |||||
if (ctx->filename[0] == 0) audio_device = "default"; | |||||
else audio_device = ctx->filename; | |||||
if (*codec_id == CODEC_ID_NONE) | |||||
*codec_id = DEFAULT_CODEC_ID; | |||||
format = codec_id_to_pcm_format(*codec_id); | |||||
if (format == SND_PCM_FORMAT_UNKNOWN) { | |||||
av_log(ctx, AV_LOG_ERROR, "sample format 0x%04x is not supported\n", *codec_id); | |||||
return AVERROR(ENOSYS); | |||||
} | |||||
s->frame_size = av_get_bits_per_sample(*codec_id) / 8 * channels; | |||||
if (ctx->flags & AVFMT_FLAG_NONBLOCK) { | |||||
flags = O_NONBLOCK; | |||||
} | |||||
res = snd_pcm_open(&h, audio_device, mode, flags); | |||||
if (res < 0) { | |||||
av_log(ctx, AV_LOG_ERROR, "cannot open audio device %s (%s)\n", | |||||
audio_device, snd_strerror(res)); | |||||
return AVERROR_IO; | |||||
} | |||||
res = snd_pcm_hw_params_malloc(&hw_params); | |||||
if (res < 0) { | |||||
av_log(ctx, AV_LOG_ERROR, "cannot allocate hardware parameter structure (%s)\n", | |||||
snd_strerror(res)); | |||||
goto fail1; | |||||
} | |||||
res = snd_pcm_hw_params_any(h, hw_params); | |||||
if (res < 0) { | |||||
av_log(ctx, AV_LOG_ERROR, "cannot initialize hardware parameter structure (%s)\n", | |||||
snd_strerror(res)); | |||||
goto fail; | |||||
} | |||||
res = snd_pcm_hw_params_set_access(h, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); | |||||
if (res < 0) { | |||||
av_log(ctx, AV_LOG_ERROR, "cannot set access type (%s)\n", | |||||
snd_strerror(res)); | |||||
goto fail; | |||||
} | |||||
res = snd_pcm_hw_params_set_format(h, hw_params, format); | |||||
if (res < 0) { | |||||
av_log(ctx, AV_LOG_ERROR, "cannot set sample format 0x%04x %d (%s)\n", | |||||
*codec_id, format, snd_strerror(res)); | |||||
goto fail; | |||||
} | |||||
res = snd_pcm_hw_params_set_rate_near(h, hw_params, sample_rate, 0); | |||||
if (res < 0) { | |||||
av_log(ctx, AV_LOG_ERROR, "cannot set sample rate (%s)\n", | |||||
snd_strerror(res)); | |||||
goto fail; | |||||
} | |||||
res = snd_pcm_hw_params_set_channels(h, hw_params, channels); | |||||
if (res < 0) { | |||||
av_log(ctx, AV_LOG_ERROR, "cannot set channel count to %d (%s)\n", | |||||
channels, snd_strerror(res)); | |||||
goto fail; | |||||
} | |||||
snd_pcm_hw_params_get_buffer_size_max(hw_params, &buffer_size); | |||||
/* TODO: maybe use ctx->max_picture_buffer somehow */ | |||||
res = snd_pcm_hw_params_set_buffer_size_near(h, hw_params, &buffer_size); | |||||
if (res < 0) { | |||||
av_log(ctx, AV_LOG_ERROR, "cannot set ALSA buffer size (%s)\n", | |||||
snd_strerror(res)); | |||||
goto fail; | |||||
} | |||||
snd_pcm_hw_params_get_period_size_min(hw_params, &period_size, NULL); | |||||
res = snd_pcm_hw_params_set_period_size_near(h, hw_params, &period_size, NULL); | |||||
if (res < 0) { | |||||
av_log(ctx, AV_LOG_ERROR, "cannot set ALSA period size (%s)\n", | |||||
snd_strerror(res)); | |||||
goto fail; | |||||
} | |||||
s->period_size = period_size; | |||||
res = snd_pcm_hw_params(h, hw_params); | |||||
if (res < 0) { | |||||
av_log(ctx, AV_LOG_ERROR, "cannot set parameters (%s)\n", | |||||
snd_strerror(res)); | |||||
goto fail; | |||||
} | |||||
snd_pcm_hw_params_free(hw_params); | |||||
s->h = h; | |||||
return 0; | |||||
fail: | |||||
snd_pcm_hw_params_free(hw_params); | |||||
fail1: | |||||
snd_pcm_close(h); | |||||
return AVERROR_IO; | |||||
} | |||||
av_cold int ff_alsa_close(AVFormatContext *s1) | |||||
{ | |||||
AlsaData *s = s1->priv_data; | |||||
snd_pcm_close(s->h); | |||||
return 0; | |||||
} | |||||
int ff_alsa_xrun_recover(AVFormatContext *s1, int err) | |||||
{ | |||||
AlsaData *s = s1->priv_data; | |||||
snd_pcm_t *handle = s->h; | |||||
av_log(s1, AV_LOG_WARNING, "ALSA buffer xrun.\n"); | |||||
if (err == -EPIPE) { | |||||
err = snd_pcm_prepare(handle); | |||||
if (err < 0) { | |||||
av_log(s1, AV_LOG_ERROR, "cannot recover from underrun (snd_pcm_prepare failed: %s)\n", snd_strerror(err)); | |||||
return AVERROR_IO; | |||||
} | |||||
} else if (err == -ESTRPIPE) { | |||||
av_log(s1, AV_LOG_ERROR, "-ESTRPIPE... Unsupported!\n"); | |||||
return -1; | |||||
} | |||||
return err; | |||||
} |
@@ -0,0 +1,175 @@ | |||||
/* | |||||
* ALSA input and output | |||||
* Copyright (c) 2007 Luca Abeni ( lucabe72 email it ) | |||||
* Copyright (c) 2007 Benoit Fouet ( benoit fouet free fr ) | |||||
* | |||||
* This file is part of FFmpeg. | |||||
* | |||||
* FFmpeg is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation; either | |||||
* version 2.1 of the License, or (at your option) any later version. | |||||
* | |||||
* FFmpeg is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
* Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public | |||||
* License along with FFmpeg; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||||
*/ | |||||
/** | |||||
* @file alsa-audio-dec.c | |||||
* ALSA input and output: input | |||||
* @author Luca Abeni ( lucabe72 email it ) | |||||
* @author Benoit Fouet ( benoit fouet free fr ) | |||||
* @author Nicolas George ( nicolas george normalesup org ) | |||||
* | |||||
* This avdevice decoder allows to capture audio from an ALSA (Advanced | |||||
* Linux Sound Architecture) device. | |||||
* | |||||
* The filename parameter is the name of an ALSA PCM device capable of | |||||
* capture, for example "default" or "plughw:1"; see the ALSA documentation | |||||
* for naming conventions. The empty string is equivalent to "default". | |||||
* | |||||
* The capture period is set to the lower value available for the device, | |||||
* which gives a low latency suitable for real-time capture. | |||||
* | |||||
* The PTS are an Unix time in microsecond. | |||||
* | |||||
* Due to a bug in the ALSA library | |||||
* (https://bugtrack.alsa-project.org/alsa-bug/view.php?id=4308), this | |||||
* decoder does not work with certain ALSA plugins, especially the dsnoop | |||||
* plugin. | |||||
*/ | |||||
#include "libavformat/avformat.h" | |||||
#include <alsa/asoundlib.h> | |||||
#include "alsa-audio.h" | |||||
av_cold static int audio_read_header(AVFormatContext *s1, | |||||
AVFormatParameters *ap) | |||||
{ | |||||
AlsaData *s = s1->priv_data; | |||||
AVStream *st; | |||||
int ret; | |||||
unsigned int sample_rate; | |||||
int codec_id; | |||||
snd_pcm_sw_params_t *sw_params; | |||||
if (ap->sample_rate <= 0) { | |||||
av_log(s1, AV_LOG_ERROR, "Bad sample rate %d\n", ap->sample_rate); | |||||
return AVERROR(EIO); | |||||
} | |||||
if (ap->channels <= 0) { | |||||
av_log(s1, AV_LOG_ERROR, "Bad channels number %d\n", ap->channels); | |||||
return AVERROR(EIO); | |||||
} | |||||
st = av_new_stream(s1, 0); | |||||
if (!st) { | |||||
av_log(s1, AV_LOG_ERROR, "Cannot add stream\n"); | |||||
return AVERROR(ENOMEM); | |||||
} | |||||
sample_rate = ap->sample_rate; | |||||
codec_id = ap->audio_codec_id; | |||||
ret = ff_alsa_open(s1, SND_PCM_STREAM_CAPTURE, &sample_rate, ap->channels, | |||||
&codec_id); | |||||
if (ret < 0) { | |||||
return AVERROR(EIO); | |||||
} | |||||
if (snd_pcm_type(s->h) != SND_PCM_TYPE_HW) | |||||
av_log(s1, AV_LOG_WARNING, | |||||
"capture with some ALSA plugins, especially dsnoop, " | |||||
"may hang.\n"); | |||||
ret = snd_pcm_sw_params_malloc(&sw_params); | |||||
if (ret < 0) { | |||||
av_log(s1, AV_LOG_ERROR, "cannot allocate software parameters structure (%s)\n", | |||||
snd_strerror(ret)); | |||||
goto fail; | |||||
} | |||||
snd_pcm_sw_params_current(s->h, sw_params); | |||||
snd_pcm_sw_params_set_tstamp_mode(s->h, sw_params, SND_PCM_TSTAMP_ENABLE); | |||||
ret = snd_pcm_sw_params(s->h, sw_params); | |||||
snd_pcm_sw_params_free(sw_params); | |||||
if (ret < 0) { | |||||
av_log(s1, AV_LOG_ERROR, "cannot install ALSA software parameters (%s)\n", | |||||
snd_strerror(ret)); | |||||
goto fail; | |||||
} | |||||
/* take real parameters */ | |||||
st->codec->codec_type = CODEC_TYPE_AUDIO; | |||||
st->codec->codec_id = codec_id; | |||||
st->codec->sample_rate = sample_rate; | |||||
st->codec->channels = ap->channels; | |||||
av_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */ | |||||
return 0; | |||||
fail: | |||||
snd_pcm_close(s->h); | |||||
return AVERROR(EIO); | |||||
} | |||||
static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt) | |||||
{ | |||||
AlsaData *s = s1->priv_data; | |||||
AVStream *st = s1->streams[0]; | |||||
int res; | |||||
snd_htimestamp_t timestamp; | |||||
snd_pcm_uframes_t ts_delay; | |||||
if (av_new_packet(pkt, s->period_size) < 0) { | |||||
return AVERROR(EIO); | |||||
} | |||||
while ((res = snd_pcm_readi(s->h, pkt->data, pkt->size / s->frame_size)) < 0) { | |||||
if (res == -EAGAIN) { | |||||
av_free_packet(pkt); | |||||
return AVERROR(EAGAIN); | |||||
} | |||||
if (ff_alsa_xrun_recover(s1, res) < 0) { | |||||
av_log(s1, AV_LOG_ERROR, "ALSA read error: %s\n", | |||||
snd_strerror(res)); | |||||
av_free_packet(pkt); | |||||
return AVERROR(EIO); | |||||
} | |||||
} | |||||
snd_pcm_htimestamp(s->h, &ts_delay, ×tamp); | |||||
ts_delay += res; | |||||
pkt->pts = timestamp.tv_sec * 1000000LL | |||||
+ (timestamp.tv_nsec * st->codec->sample_rate | |||||
- ts_delay * 1000000000LL + st->codec->sample_rate * 500LL) | |||||
/ (st->codec->sample_rate * 1000LL); | |||||
pkt->size = res * s->frame_size; | |||||
return 0; | |||||
} | |||||
AVInputFormat alsa_demuxer = { | |||||
"alsa", | |||||
NULL_IF_CONFIG_SMALL("ALSA audio input"), | |||||
sizeof(AlsaData), | |||||
NULL, | |||||
audio_read_header, | |||||
audio_read_packet, | |||||
ff_alsa_close, | |||||
.flags = AVFMT_NOFILE, | |||||
}; |
@@ -0,0 +1,108 @@ | |||||
/* | |||||
* ALSA input and output | |||||
* Copyright (c) 2007 Luca Abeni ( lucabe72 email it ) | |||||
* Copyright (c) 2007 Benoit Fouet ( benoit fouet free fr ) | |||||
* | |||||
* This file is part of FFmpeg. | |||||
* | |||||
* FFmpeg is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation; either | |||||
* version 2.1 of the License, or (at your option) any later version. | |||||
* | |||||
* FFmpeg is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
* Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public | |||||
* License along with FFmpeg; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||||
*/ | |||||
/** | |||||
* @file alsa-audio-enc.c | |||||
* ALSA input and output: output | |||||
* @author Luca Abeni ( lucabe72 email it ) | |||||
* @author Benoit Fouet ( benoit fouet free fr ) | |||||
* | |||||
* This avdevice encoder allows to play audio to an ALSA (Advanced Linux | |||||
* Sound Architecture) device. | |||||
* | |||||
* The filename parameter is the name of an ALSA PCM device capable of | |||||
* capture, for example "default" or "plughw:1"; see the ALSA documentation | |||||
* for naming conventions. The empty string is equivalent to "default". | |||||
* | |||||
* The playback period is set to the lower value available for the device, | |||||
* which gives a low latency suitable for real-time playback. | |||||
*/ | |||||
#include "libavformat/avformat.h" | |||||
#include <alsa/asoundlib.h> | |||||
#include "alsa-audio.h" | |||||
av_cold static int audio_write_header(AVFormatContext *s1) | |||||
{ | |||||
AlsaData *s = s1->priv_data; | |||||
AVStream *st; | |||||
unsigned int sample_rate; | |||||
int codec_id; | |||||
int res; | |||||
st = s1->streams[0]; | |||||
sample_rate = st->codec->sample_rate; | |||||
codec_id = st->codec->codec_id; | |||||
res = ff_alsa_open(s1, SND_PCM_STREAM_PLAYBACK, &sample_rate, | |||||
st->codec->channels, &codec_id); | |||||
if (sample_rate != st->codec->sample_rate) { | |||||
av_log(s1, AV_LOG_ERROR, | |||||
"sample rate %d not available, nearest is %d\n", | |||||
st->codec->sample_rate, sample_rate); | |||||
goto fail; | |||||
} | |||||
return res; | |||||
fail: | |||||
snd_pcm_close(s->h); | |||||
return AVERROR(EIO); | |||||
} | |||||
static int audio_write_packet(AVFormatContext *s1, AVPacket *pkt) | |||||
{ | |||||
AlsaData *s = s1->priv_data; | |||||
int res; | |||||
int size = pkt->size; | |||||
uint8_t *buf = pkt->data; | |||||
while((res = snd_pcm_writei(s->h, buf, size / s->frame_size)) < 0) { | |||||
if (res == -EAGAIN) { | |||||
return AVERROR(EAGAIN); | |||||
} | |||||
if (ff_alsa_xrun_recover(s1, res) < 0) { | |||||
av_log(s1, AV_LOG_ERROR, "ALSA write error: %s\n", | |||||
snd_strerror(res)); | |||||
return AVERROR(EIO); | |||||
} | |||||
} | |||||
return 0; | |||||
} | |||||
AVOutputFormat alsa_muxer = { | |||||
"alsa", | |||||
NULL_IF_CONFIG_SMALL("ALSA audio output"), | |||||
"", | |||||
"", | |||||
sizeof(AlsaData), | |||||
DEFAULT_CODEC_ID, | |||||
CODEC_ID_NONE, | |||||
audio_write_header, | |||||
audio_write_packet, | |||||
ff_alsa_close, | |||||
.flags = AVFMT_NOFILE, | |||||
}; |
@@ -0,0 +1,84 @@ | |||||
/* | |||||
* ALSA input and output | |||||
* Copyright (c) 2007 Luca Abeni ( lucabe72 email it ) | |||||
* Copyright (c) 2007 Benoit Fouet ( benoit fouet free fr ) | |||||
* | |||||
* This file is part of FFmpeg. | |||||
* | |||||
* FFmpeg is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation; either | |||||
* version 2.1 of the License, or (at your option) any later version. | |||||
* | |||||
* FFmpeg is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
* Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public | |||||
* License along with FFmpeg; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||||
*/ | |||||
/** | |||||
* @file alsa-audio.h | |||||
* ALSA input and output: definitions and structures | |||||
* @author Luca Abeni ( lucabe72 email it ) | |||||
* @author Benoit Fouet ( benoit fouet free fr ) | |||||
*/ | |||||
#ifndef AVDEVICE_ALSA_AUDIO_H | |||||
#define AVDEVICE_ALSA_AUDIO_H | |||||
/* XXX: we make the assumption that the soundcard accepts this format */ | |||||
/* XXX: find better solution with "preinit" method, needed also in | |||||
other formats */ | |||||
#ifdef WORDS_BIGENDIAN | |||||
#define DEFAULT_CODEC_ID CODEC_ID_PCM_S16BE | |||||
#else | |||||
#define DEFAULT_CODEC_ID CODEC_ID_PCM_S16LE | |||||
#endif | |||||
typedef struct { | |||||
snd_pcm_t *h; | |||||
int frame_size; ///< preferred size for reads and writes | |||||
int period_size; ///< bytes per sample * channels | |||||
} AlsaData; | |||||
/** | |||||
* Opens an ALSA PCM. | |||||
* | |||||
* @param s media file handle | |||||
* @param mode either SND_PCM_STREAM_CAPTURE or SND_PCM_STREAM_PLAYBACK | |||||
* @param sample_rate in: requested sample rate; | |||||
* out: actually selected sample rate | |||||
* @param channels number of channels | |||||
* @param codec_id in: requested CodecID or CODEC_ID_NONE; | |||||
* out: actually selected CodecID, changed only if | |||||
* CODEC_ID_NONE was requested | |||||
* | |||||
* @return 0 if OK, AVERROR_xxx on error | |||||
*/ | |||||
int ff_alsa_open(AVFormatContext *s, int mode, unsigned int *sample_rate, | |||||
int channels, int *codec_id); | |||||
/** | |||||
* Closes the ALSA PCM. | |||||
* | |||||
* @param s1 media file handle | |||||
* | |||||
* @return 0 | |||||
*/ | |||||
int ff_alsa_close(AVFormatContext *s1); | |||||
/** | |||||
* Tries to recover from ALSA buffer underrun. | |||||
* | |||||
* @param s1 media file handle | |||||
* @param err error code reported by the previous ALSA call | |||||
* | |||||
* @return 0 if OK, AVERROR_xxx on error | |||||
*/ | |||||
int ff_alsa_xrun_recover(AVFormatContext *s1, int err); | |||||
#endif /* AVDEVICE_ALSA_AUDIO_H */ |