|
Packit Service |
cd2a00 |
/*
|
|
Packit Service |
cd2a00 |
* A52 Output Plugin
|
|
Packit Service |
cd2a00 |
*
|
|
Packit Service |
cd2a00 |
* Copyright (c) 2006 by Takashi Iwai <tiwai@suse.de>
|
|
Packit Service |
cd2a00 |
*
|
|
Packit Service |
cd2a00 |
* This library is free software; you can redistribute it and/or modify
|
|
Packit Service |
cd2a00 |
* it under the terms of the GNU Lesser General Public License as
|
|
Packit Service |
cd2a00 |
* published by the Free Software Foundation; either version 2.1 of
|
|
Packit Service |
cd2a00 |
* the License, or (at your option) any later version.
|
|
Packit Service |
cd2a00 |
*
|
|
Packit Service |
cd2a00 |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
cd2a00 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
cd2a00 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
cd2a00 |
* GNU Lesser General Public License for more details.
|
|
Packit Service |
cd2a00 |
*
|
|
Packit Service |
cd2a00 |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit Service |
cd2a00 |
* License along with this library; if not, write to the Free Software
|
|
Packit Service |
cd2a00 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit Service |
cd2a00 |
*/
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
#include <stdio.h>
|
|
Packit Service |
cd2a00 |
#include <string.h>
|
|
Packit Service |
cd2a00 |
#define __USE_XOPEN
|
|
Packit Service |
cd2a00 |
#include <unistd.h>
|
|
Packit Service |
cd2a00 |
#include <alsa/asoundlib.h>
|
|
Packit Service |
cd2a00 |
#include <alsa/pcm_external.h>
|
|
Packit Service |
cd2a00 |
#include <alsa/pcm_plugin.h>
|
|
Packit Service |
cd2a00 |
#include <libavcodec/avcodec.h>
|
|
Packit Service |
cd2a00 |
#include <libavutil/avutil.h>
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
/* some compatibility wrappers */
|
|
Packit Service |
cd2a00 |
#ifndef AV_VERSION_INT
|
|
Packit Service |
cd2a00 |
#define AV_VERSION_INT(a, b, c) (((a) << 16) | ((b) << 8) | (c))
|
|
Packit Service |
cd2a00 |
#endif
|
|
Packit Service |
cd2a00 |
#ifndef LIBAVCODEC_VERSION_INT
|
|
Packit Service |
cd2a00 |
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
|
|
Packit Service |
cd2a00 |
LIBAVCODEC_VERSION_MINOR, \
|
|
Packit Service |
cd2a00 |
LIBAVCODEC_VERSION_MICRO)
|
|
Packit Service |
cd2a00 |
#endif
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 34, 0)
|
|
Packit Service |
cd2a00 |
#include <libavutil/channel_layout.h>
|
|
Packit Service |
cd2a00 |
#include <libavutil/mem.h>
|
|
Packit Service |
cd2a00 |
#define USE_AVCODEC_FRAME
|
|
Packit Service |
cd2a00 |
#endif
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 0, 0)
|
|
Packit Service |
cd2a00 |
#ifndef AV_CH_LAYOUT_STEREO
|
|
Packit Service |
cd2a00 |
#define AV_CH_LAYOUT_STEREO CH_LAYOUT_STEREO
|
|
Packit Service |
cd2a00 |
#define AV_CH_LAYOUT_QUAD CH_LAYOUT_QUAD
|
|
Packit Service |
cd2a00 |
#define AV_CH_LAYOUT_5POINT1 CH_LAYOUT_5POINT1
|
|
Packit Service |
cd2a00 |
#endif
|
|
Packit Service |
cd2a00 |
#endif
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(52, 95, 0)
|
|
Packit Service |
cd2a00 |
#ifndef AV_SAMPLE_FMT_S16
|
|
Packit Service |
cd2a00 |
#define AV_SAMPLE_FMT_S16 SAMPLE_FMT_S16
|
|
Packit Service |
cd2a00 |
#endif
|
|
Packit Service |
cd2a00 |
#endif
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 25, 0)
|
|
Packit Service |
cd2a00 |
#define AV_CODEC_ID_AC3 CODEC_ID_AC3
|
|
Packit Service |
cd2a00 |
#endif
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
#if LIBAVCODEC_VERSION_INT < 0x371c01
|
|
Packit Service |
cd2a00 |
#define av_frame_alloc avcodec_alloc_frame
|
|
Packit Service |
cd2a00 |
#define av_frame_free avcodec_free_frame
|
|
Packit Service |
cd2a00 |
#endif
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
struct a52_ctx {
|
|
Packit Service |
cd2a00 |
snd_pcm_ioplug_t io;
|
|
Packit Service |
cd2a00 |
snd_pcm_t *slave;
|
|
Packit Service |
cd2a00 |
AVCodec *codec;
|
|
Packit Service |
cd2a00 |
AVCodecContext *avctx;
|
|
Packit Service |
cd2a00 |
snd_pcm_format_t format;
|
|
Packit Service |
cd2a00 |
int av_format;
|
|
Packit Service |
cd2a00 |
unsigned int channels;
|
|
Packit Service |
cd2a00 |
unsigned int rate;
|
|
Packit Service |
cd2a00 |
unsigned int bitrate;
|
|
Packit Service |
cd2a00 |
short *inbuf;
|
|
Packit Service |
cd2a00 |
unsigned char *outbuf;
|
|
Packit Service |
cd2a00 |
int outbuf_size;
|
|
Packit Service |
cd2a00 |
snd_pcm_uframes_t transfer;
|
|
Packit Service |
cd2a00 |
int remain;
|
|
Packit Service |
cd2a00 |
int filled;
|
|
Packit Service |
cd2a00 |
unsigned int slave_period_size;
|
|
Packit Service |
cd2a00 |
unsigned int slave_buffer_size;
|
|
Packit Service |
cd2a00 |
snd_pcm_hw_params_t *hw_params;
|
|
Packit Service |
cd2a00 |
#ifdef USE_AVCODEC_FRAME
|
|
Packit Service |
cd2a00 |
AVFrame *frame;
|
|
Packit Service |
cd2a00 |
int is_planar;
|
|
Packit Service |
cd2a00 |
#endif
|
|
Packit Service |
cd2a00 |
};
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
#ifdef USE_AVCODEC_FRAME
|
|
Packit Service |
cd2a00 |
#define use_planar(rec) (rec)->is_planar
|
|
Packit Service |
cd2a00 |
#else
|
|
Packit Service |
cd2a00 |
#define use_planar(rec) 0
|
|
Packit Service |
cd2a00 |
#endif
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 34, 0)
|
|
Packit Service |
cd2a00 |
static int do_encode(struct a52_ctx *rec)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
AVPacket pkt = {
|
|
Packit Service |
cd2a00 |
.data = rec->outbuf + 8,
|
|
Packit Service |
cd2a00 |
.size = rec->outbuf_size - 8
|
|
Packit Service |
cd2a00 |
};
|
|
Packit Service |
cd2a00 |
int got_frame;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
avcodec_encode_audio2(rec->avctx, &pkt, rec->frame, &got_frame);
|
|
Packit Service |
cd2a00 |
return pkt.size;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
#else
|
|
Packit Service |
cd2a00 |
static int do_encode(struct a52_ctx *rec)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
return avcodec_encode_audio(rec->avctx, rec->outbuf + 8,
|
|
Packit Service |
cd2a00 |
rec->outbuf_size - 8,
|
|
Packit Service |
cd2a00 |
rec->inbuf);
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
#endif
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
/* convert the PCM data to A52 stream in IEC958 */
|
|
Packit Service |
cd2a00 |
static void convert_data(struct a52_ctx *rec)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
int out_bytes = do_encode(rec);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
rec->outbuf[0] = 0xf8; /* sync words */
|
|
Packit Service |
cd2a00 |
rec->outbuf[1] = 0x72;
|
|
Packit Service |
cd2a00 |
rec->outbuf[2] = 0x4e;
|
|
Packit Service |
cd2a00 |
rec->outbuf[3] = 0x1f;
|
|
Packit Service |
cd2a00 |
rec->outbuf[4] = rec->outbuf[13] & 7; /* bsmod */
|
|
Packit Service |
cd2a00 |
rec->outbuf[5] = 0x01; /* data type */
|
|
Packit Service |
cd2a00 |
rec->outbuf[6] = ((out_bytes * 8) >> 8) & 0xff;
|
|
Packit Service |
cd2a00 |
rec->outbuf[7] = (out_bytes * 8) & 0xff;
|
|
Packit Service |
cd2a00 |
/* swap bytes for little-endian 16bit */
|
|
Packit Service |
cd2a00 |
if (rec->format == SND_PCM_FORMAT_S16_LE)
|
|
Packit Service |
cd2a00 |
swab(rec->outbuf, rec->outbuf, out_bytes + 8);
|
|
Packit Service |
cd2a00 |
memset(rec->outbuf + 8 + out_bytes, 0,
|
|
Packit Service |
cd2a00 |
rec->outbuf_size - 8 - out_bytes);
|
|
Packit Service |
cd2a00 |
rec->remain = rec->outbuf_size / 4;
|
|
Packit Service |
cd2a00 |
rec->filled = 0;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
/* write pending encoded data to the slave pcm */
|
|
Packit Service |
cd2a00 |
static int write_out_pending(snd_pcm_ioplug_t *io, struct a52_ctx *rec)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
int err, ofs = 0;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (! rec->remain)
|
|
Packit Service |
cd2a00 |
return 0;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
while (rec->remain) {
|
|
Packit Service |
cd2a00 |
err = snd_pcm_writei(rec->slave, rec->outbuf + ofs, rec->remain);
|
|
Packit Service |
cd2a00 |
if (err < 0) {
|
|
Packit Service |
cd2a00 |
if (err == -EPIPE)
|
|
Packit Service |
cd2a00 |
io->state = SND_PCM_STATE_XRUN;
|
|
Packit Service |
cd2a00 |
return err;
|
|
Packit Service |
cd2a00 |
} else if (! err)
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
if (err < rec->remain)
|
|
Packit Service |
cd2a00 |
ofs += (rec->remain - err) * 4;
|
|
Packit Service |
cd2a00 |
rec->remain -= err;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
if (rec->remain && ofs)
|
|
Packit Service |
cd2a00 |
memmove(rec->outbuf, rec->outbuf + ofs, rec->remain * 4);
|
|
Packit Service |
cd2a00 |
return 0;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
/*
|
|
Packit Service |
cd2a00 |
* drain callback
|
|
Packit Service |
cd2a00 |
*/
|
|
Packit Service |
cd2a00 |
#ifdef USE_AVCODEC_FRAME
|
|
Packit Service |
cd2a00 |
static void clear_remaining_planar_data(snd_pcm_ioplug_t *io)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
struct a52_ctx *rec = io->private_data;
|
|
Packit Service |
cd2a00 |
unsigned int i;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
for (i = 0; i < io->channels; i++)
|
|
Packit Service |
cd2a00 |
memset(rec->frame->data[i] + rec->filled * 2, 0,
|
|
Packit Service |
cd2a00 |
(rec->avctx->frame_size - rec->filled) * 2);
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
#else
|
|
Packit Service |
cd2a00 |
#define clear_remaining_planar_data(io) /*NOP*/
|
|
Packit Service |
cd2a00 |
#endif
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static int a52_drain(snd_pcm_ioplug_t *io)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
struct a52_ctx *rec = io->private_data;
|
|
Packit Service |
cd2a00 |
int err;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (rec->filled) {
|
|
Packit Service |
cd2a00 |
if ((err = write_out_pending(io, rec)) < 0)
|
|
Packit Service |
cd2a00 |
return err;
|
|
Packit Service |
cd2a00 |
/* remaining data must be converted and sent out */
|
|
Packit Service |
cd2a00 |
if (use_planar(rec))
|
|
Packit Service |
cd2a00 |
clear_remaining_planar_data(io);
|
|
Packit Service |
cd2a00 |
else {
|
|
Packit Service |
cd2a00 |
memset(rec->inbuf + rec->filled * io->channels, 0,
|
|
Packit Service |
cd2a00 |
(rec->avctx->frame_size - rec->filled) * io->channels * 2);
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
convert_data(rec);
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
err = write_out_pending(io, rec);
|
|
Packit Service |
cd2a00 |
if (err < 0)
|
|
Packit Service |
cd2a00 |
return err;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
return snd_pcm_drain(rec->slave);
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
/* check whether the areas consist of a continuous interleaved stream */
|
|
Packit Service |
cd2a00 |
static int check_interleaved(const snd_pcm_channel_area_t *areas,
|
|
Packit Service |
cd2a00 |
unsigned int channels)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
unsigned int ch;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (channels > 4) /* we need re-routing for 6 channels */
|
|
Packit Service |
cd2a00 |
return 0;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
for (ch = 0; ch < channels; ch++) {
|
|
Packit Service |
cd2a00 |
if (areas[ch].addr != areas[0].addr ||
|
|
Packit Service |
cd2a00 |
areas[ch].first != ch * 16 ||
|
|
Packit Service |
cd2a00 |
areas[ch].step != channels * 16)
|
|
Packit Service |
cd2a00 |
return 0;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
return 1;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
/* Fill the input PCM to the internal buffer until a52 frames,
|
|
Packit Service |
cd2a00 |
* then covert and write it out.
|
|
Packit Service |
cd2a00 |
*
|
|
Packit Service |
cd2a00 |
* Returns the number of processed frames.
|
|
Packit Service |
cd2a00 |
*/
|
|
Packit Service |
cd2a00 |
static int fill_data(snd_pcm_ioplug_t *io,
|
|
Packit Service |
cd2a00 |
const snd_pcm_channel_area_t *areas,
|
|
Packit Service |
cd2a00 |
unsigned int offset, unsigned int size,
|
|
Packit Service |
cd2a00 |
int interleaved)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
struct a52_ctx *rec = io->private_data;
|
|
Packit Service |
cd2a00 |
unsigned int len = rec->avctx->frame_size - rec->filled;
|
|
Packit Service |
cd2a00 |
short *src, *dst;
|
|
Packit Service |
cd2a00 |
unsigned int src_step;
|
|
Packit Service |
cd2a00 |
int err;
|
|
Packit Service |
cd2a00 |
static unsigned int ch_index[3][6] = {
|
|
Packit Service |
cd2a00 |
{ 0, 1 },
|
|
Packit Service |
cd2a00 |
{ 0, 1, 2, 3 },
|
|
Packit Service |
cd2a00 |
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 26, 0)
|
|
Packit Service |
cd2a00 |
/* current libavcodec expects SMPTE order */
|
|
Packit Service |
cd2a00 |
{ 0, 1, 4, 5, 2, 3 },
|
|
Packit Service |
cd2a00 |
#else
|
|
Packit Service |
cd2a00 |
/* libavcodec older than r18540 expects A52 order */
|
|
Packit Service |
cd2a00 |
{ 0, 4, 1, 2, 3, 5 },
|
|
Packit Service |
cd2a00 |
#endif
|
|
Packit Service |
cd2a00 |
};
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if ((err = write_out_pending(io, rec)) < 0)
|
|
Packit Service |
cd2a00 |
return err;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (size > len)
|
|
Packit Service |
cd2a00 |
size = len;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
dst = rec->inbuf + rec->filled * io->channels;
|
|
Packit Service |
cd2a00 |
if (!use_planar(rec) && interleaved) {
|
|
Packit Service |
cd2a00 |
memcpy(dst, areas->addr + offset * io->channels * 2,
|
|
Packit Service |
cd2a00 |
size * io->channels * 2);
|
|
Packit Service |
cd2a00 |
} else {
|
|
Packit Service |
cd2a00 |
unsigned int i, ch, dst_step;
|
|
Packit Service |
cd2a00 |
short *dst1;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
/* flatten copy to n-channel interleaved */
|
|
Packit Service |
cd2a00 |
dst_step = io->channels;
|
|
Packit Service |
cd2a00 |
for (ch = 0; ch < io->channels; ch++, dst++) {
|
|
Packit Service |
cd2a00 |
const snd_pcm_channel_area_t *ap;
|
|
Packit Service |
cd2a00 |
ap = &areas[ch_index[io->channels / 2 - 1][ch]];
|
|
Packit Service |
cd2a00 |
src = (short *)(ap->addr +
|
|
Packit Service |
cd2a00 |
(ap->first + offset * ap->step) / 8);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
#ifdef USE_AVCODEC_FRAME
|
|
Packit Service |
cd2a00 |
if (use_planar(rec)) {
|
|
Packit Service |
cd2a00 |
memcpy(rec->frame->data[ch], src, size * 2);
|
|
Packit Service |
cd2a00 |
continue;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
#endif
|
|
Packit Service |
cd2a00 |
dst1 = dst;
|
|
Packit Service |
cd2a00 |
src_step = ap->step / 16; /* in word */
|
|
Packit Service |
cd2a00 |
for (i = 0; i < size; i++) {
|
|
Packit Service |
cd2a00 |
*dst1 = *src;
|
|
Packit Service |
cd2a00 |
src += src_step;
|
|
Packit Service |
cd2a00 |
dst1 += dst_step;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
rec->filled += size;
|
|
Packit Service |
cd2a00 |
if (rec->filled == rec->avctx->frame_size) {
|
|
Packit Service |
cd2a00 |
convert_data(rec);
|
|
Packit Service |
cd2a00 |
write_out_pending(io, rec);
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
return (int)size;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
/*
|
|
Packit Service |
cd2a00 |
* transfer callback
|
|
Packit Service |
cd2a00 |
*/
|
|
Packit Service |
cd2a00 |
static snd_pcm_sframes_t a52_transfer(snd_pcm_ioplug_t *io,
|
|
Packit Service |
cd2a00 |
const snd_pcm_channel_area_t *areas,
|
|
Packit Service |
cd2a00 |
snd_pcm_uframes_t offset,
|
|
Packit Service |
cd2a00 |
snd_pcm_uframes_t size)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
struct a52_ctx *rec = io->private_data;
|
|
Packit Service |
cd2a00 |
snd_pcm_sframes_t result = 0;
|
|
Packit Service |
cd2a00 |
int err = 0;
|
|
Packit Service |
cd2a00 |
int interleaved = check_interleaved(areas, io->channels);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
do {
|
|
Packit Service |
cd2a00 |
err = fill_data(io, areas, offset, size, interleaved);
|
|
Packit Service |
cd2a00 |
if (err < 0)
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
offset += (unsigned int)err;
|
|
Packit Service |
cd2a00 |
size -= (unsigned int)err;
|
|
Packit Service |
cd2a00 |
result += err;
|
|
Packit Service |
cd2a00 |
rec->transfer += err;
|
|
Packit Service |
cd2a00 |
} while (size);
|
|
Packit Service |
cd2a00 |
return result > 0 ? result : err;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
/*
|
|
Packit Service |
cd2a00 |
* pointer callback
|
|
Packit Service |
cd2a00 |
*
|
|
Packit Service |
cd2a00 |
* Calculate the current position from the delay of slave PCM
|
|
Packit Service |
cd2a00 |
*/
|
|
Packit Service |
cd2a00 |
static snd_pcm_sframes_t a52_pointer(snd_pcm_ioplug_t *io)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
struct a52_ctx *rec = io->private_data;
|
|
Packit Service |
cd2a00 |
snd_pcm_sframes_t delay;
|
|
Packit Service |
cd2a00 |
snd_pcm_state_t state;
|
|
Packit Service |
cd2a00 |
int err;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
state = snd_pcm_state(rec->slave);
|
|
Packit Service |
cd2a00 |
switch (state) {
|
|
Packit Service |
cd2a00 |
case SND_PCM_STATE_RUNNING:
|
|
Packit Service |
cd2a00 |
case SND_PCM_STATE_DRAINING:
|
|
Packit Service |
cd2a00 |
if ((err = snd_pcm_delay(rec->slave, &delay)) < 0)
|
|
Packit Service |
cd2a00 |
return err;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
case SND_PCM_STATE_XRUN:
|
|
Packit Service |
cd2a00 |
case SND_PCM_STATE_SUSPENDED:
|
|
Packit Service |
cd2a00 |
return -EPIPE;
|
|
Packit Service |
cd2a00 |
default:
|
|
Packit Service |
cd2a00 |
return 0;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (delay < 0 || delay >= (snd_pcm_sframes_t)rec->slave_buffer_size)
|
|
Packit Service |
cd2a00 |
delay = 0;
|
|
Packit Service |
cd2a00 |
delay = (snd_pcm_sframes_t)io->appl_ptr - delay;
|
|
Packit Service |
cd2a00 |
if (delay < 0) {
|
|
Packit Service |
cd2a00 |
delay += io->buffer_size;
|
|
Packit Service |
cd2a00 |
if (delay < 0)
|
|
Packit Service |
cd2a00 |
delay = 0;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
delay %= io->buffer_size;
|
|
Packit Service |
cd2a00 |
return delay;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
/* set up the fixed parameters of slave PCM hw_parmas */
|
|
Packit Service |
cd2a00 |
static int a52_slave_hw_params_half(struct a52_ctx *rec)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
int err;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if ((err = snd_pcm_hw_params_malloc(&rec->hw_params)) < 0)
|
|
Packit Service |
cd2a00 |
return err;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if ((err = snd_pcm_hw_params_any(rec->slave, rec->hw_params)) < 0) {
|
|
Packit Service |
cd2a00 |
SNDERR("Cannot get slave hw_params");
|
|
Packit Service |
cd2a00 |
goto out;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
if ((err = snd_pcm_hw_params_set_access(rec->slave, rec->hw_params,
|
|
Packit Service |
cd2a00 |
SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
|
|
Packit Service |
cd2a00 |
SNDERR("Cannot set slave access RW_INTERLEAVED");
|
|
Packit Service |
cd2a00 |
goto out;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
if ((err = snd_pcm_hw_params_set_channels(rec->slave, rec->hw_params, 2)) < 0) {
|
|
Packit Service |
cd2a00 |
SNDERR("Cannot set slave channels 2");
|
|
Packit Service |
cd2a00 |
goto out;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
if ((err = snd_pcm_hw_params_set_format(rec->slave, rec->hw_params,
|
|
Packit Service |
cd2a00 |
rec->format)) < 0) {
|
|
Packit Service |
cd2a00 |
SNDERR("Cannot set slave format");
|
|
Packit Service |
cd2a00 |
goto out;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
if ((err = snd_pcm_hw_params_set_rate(rec->slave, rec->hw_params, rec->rate, 0)) < 0) {
|
|
Packit Service |
cd2a00 |
SNDERR("Cannot set slave rate %d", rec->rate);
|
|
Packit Service |
cd2a00 |
goto out;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
return 0;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
out:
|
|
Packit Service |
cd2a00 |
free(rec->hw_params);
|
|
Packit Service |
cd2a00 |
rec->hw_params = NULL;
|
|
Packit Service |
cd2a00 |
return err;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
/*
|
|
Packit Service |
cd2a00 |
* hw_params callback
|
|
Packit Service |
cd2a00 |
*
|
|
Packit Service |
cd2a00 |
* Set up slave PCM according to the current parameters
|
|
Packit Service |
cd2a00 |
*/
|
|
Packit Service |
cd2a00 |
static int a52_hw_params(snd_pcm_ioplug_t *io,
|
|
Packit Service |
cd2a00 |
snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
struct a52_ctx *rec = io->private_data;
|
|
Packit Service |
cd2a00 |
snd_pcm_uframes_t period_size;
|
|
Packit Service |
cd2a00 |
snd_pcm_uframes_t buffer_size;
|
|
Packit Service |
cd2a00 |
int err;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (! rec->hw_params) {
|
|
Packit Service |
cd2a00 |
err = a52_slave_hw_params_half(rec);
|
|
Packit Service |
cd2a00 |
if (err < 0)
|
|
Packit Service |
cd2a00 |
return err;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
period_size = io->period_size;
|
|
Packit Service |
cd2a00 |
if ((err = snd_pcm_hw_params_set_period_size_near(rec->slave, rec->hw_params,
|
|
Packit Service |
cd2a00 |
&period_size, NULL)) < 0) {
|
|
Packit Service |
cd2a00 |
SNDERR("Cannot set slave period size %ld", period_size);
|
|
Packit Service |
cd2a00 |
return err;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
buffer_size = io->buffer_size;
|
|
Packit Service |
cd2a00 |
if ((err = snd_pcm_hw_params_set_buffer_size_near(rec->slave, rec->hw_params,
|
|
Packit Service |
cd2a00 |
&buffer_size)) < 0) {
|
|
Packit Service |
cd2a00 |
SNDERR("Cannot set slave buffer size %ld", buffer_size);
|
|
Packit Service |
cd2a00 |
return err;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
if ((err = snd_pcm_hw_params(rec->slave, rec->hw_params)) < 0) {
|
|
Packit Service |
cd2a00 |
SNDERR("Cannot set slave hw_params");
|
|
Packit Service |
cd2a00 |
return err;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
rec->slave_period_size = period_size;
|
|
Packit Service |
cd2a00 |
rec->slave_buffer_size = buffer_size;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
return 0;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
/*
|
|
Packit Service |
cd2a00 |
* hw_free callback
|
|
Packit Service |
cd2a00 |
*/
|
|
Packit Service |
cd2a00 |
static int a52_hw_free(snd_pcm_ioplug_t *io)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
struct a52_ctx *rec = io->private_data;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
free(rec->hw_params);
|
|
Packit Service |
cd2a00 |
rec->hw_params = NULL;
|
|
Packit Service |
cd2a00 |
return snd_pcm_hw_free(rec->slave);
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
/*
|
|
Packit Service |
cd2a00 |
* sw_params callback
|
|
Packit Service |
cd2a00 |
*
|
|
Packit Service |
cd2a00 |
* Set up slave PCM sw_params
|
|
Packit Service |
cd2a00 |
*/
|
|
Packit Service |
cd2a00 |
static int a52_sw_params(snd_pcm_ioplug_t *io, snd_pcm_sw_params_t *params)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
struct a52_ctx *rec = io->private_data;
|
|
Packit Service |
cd2a00 |
snd_pcm_sw_params_t *sparams;
|
|
Packit Service |
cd2a00 |
snd_pcm_uframes_t avail_min, start_threshold;
|
|
Packit Service |
cd2a00 |
int len;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
snd_pcm_sw_params_get_avail_min(params, &avail_min);
|
|
Packit Service |
cd2a00 |
snd_pcm_sw_params_get_start_threshold(params, &start_threshold);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
len = avail_min;
|
|
Packit Service |
cd2a00 |
len += (int)rec->slave_buffer_size - (int)io->buffer_size;
|
|
Packit Service |
cd2a00 |
if (len < 0)
|
|
Packit Service |
cd2a00 |
avail_min = 1;
|
|
Packit Service |
cd2a00 |
else
|
|
Packit Service |
cd2a00 |
avail_min = len;
|
|
Packit Service |
cd2a00 |
snd_pcm_sw_params_alloca(&sparams);
|
|
Packit Service |
cd2a00 |
snd_pcm_sw_params_current(rec->slave, sparams);
|
|
Packit Service |
cd2a00 |
snd_pcm_sw_params_set_avail_min(rec->slave, sparams, avail_min);
|
|
Packit Service |
cd2a00 |
snd_pcm_sw_params_set_start_threshold(rec->slave, sparams,
|
|
Packit Service |
cd2a00 |
start_threshold);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
return snd_pcm_sw_params(rec->slave, sparams);
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
/*
|
|
Packit Service |
cd2a00 |
* start and stop callbacks - just trigger slave PCM
|
|
Packit Service |
cd2a00 |
*/
|
|
Packit Service |
cd2a00 |
static int a52_start(snd_pcm_ioplug_t *io)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
struct a52_ctx *rec = io->private_data;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
/* When trying to start a PCM that's already running, the result is
|
|
Packit Service |
cd2a00 |
EBADFD. We might have implicitly started the buffer by filling it
|
|
Packit Service |
cd2a00 |
up, so just ignore this request if we're already running. */
|
|
Packit Service |
cd2a00 |
if (snd_pcm_state(rec->slave) == SND_PCM_STATE_RUNNING)
|
|
Packit Service |
cd2a00 |
return 0;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
return snd_pcm_start(rec->slave);
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static int a52_stop(snd_pcm_ioplug_t *io)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
struct a52_ctx *rec = io->private_data;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
return snd_pcm_drop(rec->slave);
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
/* release resources */
|
|
Packit Service |
cd2a00 |
static void a52_free(struct a52_ctx *rec)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
if (rec->avctx) {
|
|
Packit Service |
cd2a00 |
avcodec_close(rec->avctx);
|
|
Packit Service |
cd2a00 |
av_free(rec->avctx);
|
|
Packit Service |
cd2a00 |
rec->avctx = NULL;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
#ifdef USE_AVCODEC_FRAME
|
|
Packit Service |
cd2a00 |
if (rec->frame) {
|
|
Packit Service |
cd2a00 |
av_freep(&rec->frame->data[0]);
|
|
Packit Service |
cd2a00 |
rec->inbuf = NULL;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 28, 0)
|
|
Packit Service |
cd2a00 |
av_frame_free(&rec->frame);
|
|
Packit Service |
cd2a00 |
#else
|
|
Packit Service |
cd2a00 |
av_freep(&rec->frame);
|
|
Packit Service |
cd2a00 |
#endif
|
|
Packit Service |
cd2a00 |
#endif
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
free(rec->inbuf);
|
|
Packit Service |
cd2a00 |
rec->inbuf = NULL;
|
|
Packit Service |
cd2a00 |
free(rec->outbuf);
|
|
Packit Service |
cd2a00 |
rec->outbuf = NULL;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
/*
|
|
Packit Service |
cd2a00 |
* prepare callback
|
|
Packit Service |
cd2a00 |
*
|
|
Packit Service |
cd2a00 |
* Allocate internal buffers and set up libavcodec
|
|
Packit Service |
cd2a00 |
*/
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 3, 0)
|
|
Packit Service |
cd2a00 |
static void set_channel_layout(snd_pcm_ioplug_t *io)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
struct a52_ctx *rec = io->private_data;
|
|
Packit Service |
cd2a00 |
switch (io->channels) {
|
|
Packit Service |
cd2a00 |
case 2:
|
|
Packit Service |
cd2a00 |
rec->avctx->channel_layout = AV_CH_LAYOUT_STEREO;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
case 4:
|
|
Packit Service |
cd2a00 |
rec->avctx->channel_layout = AV_CH_LAYOUT_QUAD;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
case 6:
|
|
Packit Service |
cd2a00 |
rec->avctx->channel_layout = AV_CH_LAYOUT_5POINT1;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
default:
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
#else
|
|
Packit Service |
cd2a00 |
#define set_channel_layout(io) /* NOP */
|
|
Packit Service |
cd2a00 |
#endif
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static int alloc_input_buffer(snd_pcm_ioplug_t *io)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
struct a52_ctx *rec = io->private_data;
|
|
Packit Service |
cd2a00 |
#ifdef USE_AVCODEC_FRAME
|
|
Packit Service |
cd2a00 |
rec->frame = av_frame_alloc();
|
|
Packit Service |
cd2a00 |
if (!rec->frame)
|
|
Packit Service |
cd2a00 |
return -ENOMEM;
|
|
Packit Service |
cd2a00 |
if (av_samples_alloc(rec->frame->data, rec->frame->linesize,
|
|
Packit Service |
cd2a00 |
io->channels, rec->avctx->frame_size,
|
|
Packit Service |
cd2a00 |
rec->avctx->sample_fmt, 0) < 0)
|
|
Packit Service |
cd2a00 |
return -ENOMEM;
|
|
Packit Service |
cd2a00 |
rec->frame->nb_samples = rec->avctx->frame_size;
|
|
Packit Service |
cd2a00 |
rec->inbuf = (short *)rec->frame->data[0];
|
|
Packit Service |
cd2a00 |
#else
|
|
Packit Service |
cd2a00 |
rec->inbuf = malloc(rec->avctx->frame_size * 2 * io->channels);
|
|
Packit Service |
cd2a00 |
#endif
|
|
Packit Service |
cd2a00 |
if (!rec->inbuf)
|
|
Packit Service |
cd2a00 |
return -ENOMEM;
|
|
Packit Service |
cd2a00 |
return 0;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static int a52_prepare(snd_pcm_ioplug_t *io)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
struct a52_ctx *rec = io->private_data;
|
|
Packit Service |
cd2a00 |
int err;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
a52_free(rec);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
#ifdef USE_AVCODEC_FRAME
|
|
Packit Service |
cd2a00 |
rec->avctx = avcodec_alloc_context3(rec->codec);
|
|
Packit Service |
cd2a00 |
#else
|
|
Packit Service |
cd2a00 |
rec->avctx = avcodec_alloc_context();
|
|
Packit Service |
cd2a00 |
#endif
|
|
Packit Service |
cd2a00 |
if (!rec->avctx)
|
|
Packit Service |
cd2a00 |
return -ENOMEM;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
rec->avctx->bit_rate = rec->bitrate * 1000;
|
|
Packit Service |
cd2a00 |
rec->avctx->sample_rate = io->rate;
|
|
Packit Service |
cd2a00 |
rec->avctx->channels = io->channels;
|
|
Packit Service |
cd2a00 |
rec->avctx->sample_fmt = rec->av_format;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
set_channel_layout(io);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
#ifdef USE_AVCODEC_FRAME
|
|
Packit Service |
cd2a00 |
err = avcodec_open2(rec->avctx, rec->codec, NULL);
|
|
Packit Service |
cd2a00 |
#else
|
|
Packit Service |
cd2a00 |
err = avcodec_open(rec->avctx, rec->codec);
|
|
Packit Service |
cd2a00 |
#endif
|
|
Packit Service |
cd2a00 |
if (err < 0)
|
|
Packit Service |
cd2a00 |
return -EINVAL;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
rec->outbuf_size = rec->avctx->frame_size * 4;
|
|
Packit Service |
cd2a00 |
rec->outbuf = malloc(rec->outbuf_size);
|
|
Packit Service |
cd2a00 |
if (! rec->outbuf)
|
|
Packit Service |
cd2a00 |
return -ENOMEM;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (alloc_input_buffer(io))
|
|
Packit Service |
cd2a00 |
return -ENOMEM;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
rec->transfer = 0;
|
|
Packit Service |
cd2a00 |
rec->remain = 0;
|
|
Packit Service |
cd2a00 |
rec->filled = 0;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
return snd_pcm_prepare(rec->slave);
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
/*
|
|
Packit Service |
cd2a00 |
* poll-related callbacks - just pass to slave PCM
|
|
Packit Service |
cd2a00 |
*/
|
|
Packit Service |
cd2a00 |
static int a52_poll_descriptors_count(snd_pcm_ioplug_t *io)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
struct a52_ctx *rec = io->private_data;
|
|
Packit Service |
cd2a00 |
return snd_pcm_poll_descriptors_count(rec->slave);
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static int a52_poll_descriptors(snd_pcm_ioplug_t *io, struct pollfd *pfd,
|
|
Packit Service |
cd2a00 |
unsigned int space)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
struct a52_ctx *rec = io->private_data;
|
|
Packit Service |
cd2a00 |
return snd_pcm_poll_descriptors(rec->slave, pfd, space);
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static int a52_poll_revents(snd_pcm_ioplug_t *io, struct pollfd *pfd,
|
|
Packit Service |
cd2a00 |
unsigned int nfds, unsigned short *revents)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
struct a52_ctx *rec = io->private_data;
|
|
Packit Service |
cd2a00 |
return snd_pcm_poll_descriptors_revents(rec->slave, pfd, nfds, revents);
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
/*
|
|
Packit Service |
cd2a00 |
* close callback
|
|
Packit Service |
cd2a00 |
*/
|
|
Packit Service |
cd2a00 |
static int a52_close(snd_pcm_ioplug_t *io)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
struct a52_ctx *rec = io->private_data;
|
|
Packit Service |
cd2a00 |
snd_pcm_t *slave = rec->slave;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
a52_free(rec);
|
|
Packit Service |
cd2a00 |
if (slave) {
|
|
Packit Service |
cd2a00 |
rec->slave = NULL;
|
|
Packit Service |
cd2a00 |
return snd_pcm_close(slave);
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
return 0;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
#if SND_PCM_IOPLUG_VERSION >= 0x10002
|
|
Packit Service |
cd2a00 |
static unsigned int chmap4[4] = {
|
|
Packit Service |
cd2a00 |
SND_CHMAP_FL, SND_CHMAP_FR,
|
|
Packit Service |
cd2a00 |
SND_CHMAP_RL, SND_CHMAP_RR,
|
|
Packit Service |
cd2a00 |
};
|
|
Packit Service |
cd2a00 |
static unsigned int chmap6[6] = {
|
|
Packit Service |
cd2a00 |
SND_CHMAP_FL, SND_CHMAP_FR,
|
|
Packit Service |
cd2a00 |
SND_CHMAP_RL, SND_CHMAP_RR,
|
|
Packit Service |
cd2a00 |
SND_CHMAP_FC, SND_CHMAP_LFE,
|
|
Packit Service |
cd2a00 |
};
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static snd_pcm_chmap_query_t **a52_query_chmaps(snd_pcm_ioplug_t *io ATTRIBUTE_UNUSED)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
snd_pcm_chmap_query_t **maps;
|
|
Packit Service |
cd2a00 |
int i;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
maps = calloc(4, sizeof(void *));
|
|
Packit Service |
cd2a00 |
if (!maps)
|
|
Packit Service |
cd2a00 |
return NULL;
|
|
Packit Service |
cd2a00 |
for (i = 0; i < 3; i++) {
|
|
Packit Service |
cd2a00 |
snd_pcm_chmap_query_t *p;
|
|
Packit Service |
cd2a00 |
p = maps[i] = calloc((i + 1) * 2 + 2, sizeof(int));
|
|
Packit Service |
cd2a00 |
if (!p) {
|
|
Packit Service |
cd2a00 |
snd_pcm_free_chmaps(maps);
|
|
Packit Service |
cd2a00 |
return NULL;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
p->type = SND_CHMAP_TYPE_FIXED;
|
|
Packit Service |
cd2a00 |
p->map.channels = (i + 1) * 2;
|
|
Packit Service |
cd2a00 |
memcpy(p->map.pos, i < 2 ? chmap4 : chmap6,
|
|
Packit Service |
cd2a00 |
(i + 1) * 2 * sizeof(int));
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
return maps;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static snd_pcm_chmap_t *a52_get_chmap(snd_pcm_ioplug_t *io)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
snd_pcm_chmap_t *map;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if ((io->channels % 2) || io->channels < 2 || io->channels > 6)
|
|
Packit Service |
cd2a00 |
return NULL;
|
|
Packit Service |
cd2a00 |
map = malloc((io->channels + 1) * sizeof(int));
|
|
Packit Service |
cd2a00 |
if (!map)
|
|
Packit Service |
cd2a00 |
return NULL;
|
|
Packit Service |
cd2a00 |
map->channels = io->channels;
|
|
Packit Service |
cd2a00 |
memcpy(map->pos, io->channels < 6 ? chmap4 : chmap6,
|
|
Packit Service |
cd2a00 |
io->channels * sizeof(int));
|
|
Packit Service |
cd2a00 |
return map;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
#endif /* SND_PCM_IOPLUG_VERSION >= 0x10002 */
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
/*
|
|
Packit Service |
cd2a00 |
* callback table
|
|
Packit Service |
cd2a00 |
*/
|
|
Packit Service |
cd2a00 |
static snd_pcm_ioplug_callback_t a52_ops = {
|
|
Packit Service |
cd2a00 |
.start = a52_start,
|
|
Packit Service |
cd2a00 |
.stop = a52_stop,
|
|
Packit Service |
cd2a00 |
.pointer = a52_pointer,
|
|
Packit Service |
cd2a00 |
.transfer = a52_transfer,
|
|
Packit Service |
cd2a00 |
.close = a52_close,
|
|
Packit Service |
cd2a00 |
.hw_params = a52_hw_params,
|
|
Packit Service |
cd2a00 |
.hw_free = a52_hw_free,
|
|
Packit Service |
cd2a00 |
.sw_params = a52_sw_params,
|
|
Packit Service |
cd2a00 |
.prepare = a52_prepare,
|
|
Packit Service |
cd2a00 |
.drain = a52_drain,
|
|
Packit Service |
cd2a00 |
.poll_descriptors_count = a52_poll_descriptors_count,
|
|
Packit Service |
cd2a00 |
.poll_descriptors = a52_poll_descriptors,
|
|
Packit Service |
cd2a00 |
.poll_revents = a52_poll_revents,
|
|
Packit Service |
cd2a00 |
#if SND_PCM_IOPLUG_VERSION >= 0x10002
|
|
Packit Service |
cd2a00 |
.query_chmaps = a52_query_chmaps,
|
|
Packit Service |
cd2a00 |
.get_chmap = a52_get_chmap,
|
|
Packit Service |
cd2a00 |
#endif /* SND_PCM_IOPLUG_VERSION >= 0x10002 */
|
|
Packit Service |
cd2a00 |
};
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
/*
|
|
Packit Service |
cd2a00 |
* set up h/w constraints
|
|
Packit Service |
cd2a00 |
*
|
|
Packit Service |
cd2a00 |
* set the period size identical with A52 frame size.
|
|
Packit Service |
cd2a00 |
* the max buffer size is calculated from the max buffer size
|
|
Packit Service |
cd2a00 |
* of the slave PCM
|
|
Packit Service |
cd2a00 |
*/
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
#define A52_FRAME_SIZE 1536
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
#define ARRAY_SIZE(ary) (sizeof(ary)/sizeof(ary[0]))
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static int a52_set_hw_constraint(struct a52_ctx *rec)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
static unsigned int accesses[] = {
|
|
Packit Service |
cd2a00 |
SND_PCM_ACCESS_MMAP_INTERLEAVED,
|
|
Packit Service |
cd2a00 |
SND_PCM_ACCESS_MMAP_NONINTERLEAVED,
|
|
Packit Service |
cd2a00 |
SND_PCM_ACCESS_RW_INTERLEAVED,
|
|
Packit Service |
cd2a00 |
SND_PCM_ACCESS_RW_NONINTERLEAVED
|
|
Packit Service |
cd2a00 |
};
|
|
Packit Service |
cd2a00 |
static unsigned int accesses_planar[] = {
|
|
Packit Service |
cd2a00 |
SND_PCM_ACCESS_MMAP_NONINTERLEAVED,
|
|
Packit Service |
cd2a00 |
SND_PCM_ACCESS_RW_NONINTERLEAVED
|
|
Packit Service |
cd2a00 |
};
|
|
Packit Service |
cd2a00 |
unsigned int formats[] = { SND_PCM_FORMAT_S16 };
|
|
Packit Service |
cd2a00 |
int err;
|
|
Packit Service |
cd2a00 |
snd_pcm_uframes_t buffer_max;
|
|
Packit Service |
cd2a00 |
unsigned int period_bytes, max_periods;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (use_planar(rec))
|
|
Packit Service |
cd2a00 |
err = snd_pcm_ioplug_set_param_list(&rec->io,
|
|
Packit Service |
cd2a00 |
SND_PCM_IOPLUG_HW_ACCESS,
|
|
Packit Service |
cd2a00 |
ARRAY_SIZE(accesses_planar),
|
|
Packit Service |
cd2a00 |
accesses_planar);
|
|
Packit Service |
cd2a00 |
else
|
|
Packit Service |
cd2a00 |
err = snd_pcm_ioplug_set_param_list(&rec->io,
|
|
Packit Service |
cd2a00 |
SND_PCM_IOPLUG_HW_ACCESS,
|
|
Packit Service |
cd2a00 |
ARRAY_SIZE(accesses),
|
|
Packit Service |
cd2a00 |
accesses);
|
|
Packit Service |
cd2a00 |
if (err < 0)
|
|
Packit Service |
cd2a00 |
return err;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if ((err = snd_pcm_ioplug_set_param_list(&rec->io, SND_PCM_IOPLUG_HW_FORMAT,
|
|
Packit Service |
cd2a00 |
ARRAY_SIZE(formats), formats)) < 0 ||
|
|
Packit Service |
cd2a00 |
(err = snd_pcm_ioplug_set_param_minmax(&rec->io, SND_PCM_IOPLUG_HW_CHANNELS,
|
|
Packit Service |
cd2a00 |
rec->channels, rec->channels)) < 0 ||
|
|
Packit Service |
cd2a00 |
(err = snd_pcm_ioplug_set_param_minmax(&rec->io, SND_PCM_IOPLUG_HW_RATE,
|
|
Packit Service |
cd2a00 |
rec->rate, rec->rate)) < 0)
|
|
Packit Service |
cd2a00 |
return err;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if ((err = a52_slave_hw_params_half(rec)) < 0)
|
|
Packit Service |
cd2a00 |
return err;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
snd_pcm_hw_params_get_buffer_size_max(rec->hw_params, &buffer_max);
|
|
Packit Service |
cd2a00 |
period_bytes = A52_FRAME_SIZE * 2 * rec->channels;
|
|
Packit Service |
cd2a00 |
max_periods = buffer_max / A52_FRAME_SIZE;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if ((err = snd_pcm_ioplug_set_param_minmax(&rec->io, SND_PCM_IOPLUG_HW_PERIOD_BYTES,
|
|
Packit Service |
cd2a00 |
period_bytes, period_bytes)) < 0 ||
|
|
Packit Service |
cd2a00 |
(err = snd_pcm_ioplug_set_param_minmax(&rec->io, SND_PCM_IOPLUG_HW_PERIODS,
|
|
Packit Service |
cd2a00 |
2, max_periods)) < 0)
|
|
Packit Service |
cd2a00 |
return err;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
return 0;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
/*
|
|
Packit Service |
cd2a00 |
* Main entry point
|
|
Packit Service |
cd2a00 |
*/
|
|
Packit Service |
cd2a00 |
SND_PCM_PLUGIN_DEFINE_FUNC(a52)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
snd_config_iterator_t i, next;
|
|
Packit Service |
cd2a00 |
int err;
|
|
Packit Service |
cd2a00 |
const char *card = NULL;
|
|
Packit Service |
cd2a00 |
const char *pcm_string = NULL;
|
|
Packit Service |
cd2a00 |
unsigned int rate = 48000;
|
|
Packit Service |
cd2a00 |
unsigned int bitrate = 448;
|
|
Packit Service |
cd2a00 |
unsigned int channels = 6;
|
|
Packit Service |
cd2a00 |
snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
|
|
Packit Service |
cd2a00 |
char devstr[128], tmpcard[8];
|
|
Packit Service |
cd2a00 |
struct a52_ctx *rec;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (stream != SND_PCM_STREAM_PLAYBACK) {
|
|
Packit Service |
cd2a00 |
SNDERR("a52 is only for playback");
|
|
Packit Service |
cd2a00 |
return -EINVAL;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
snd_config_for_each(i, next, conf) {
|
|
Packit Service |
cd2a00 |
snd_config_t *n = snd_config_iterator_entry(i);
|
|
Packit Service |
cd2a00 |
const char *id;
|
|
Packit Service |
cd2a00 |
if (snd_config_get_id(n, &id) < 0)
|
|
Packit Service |
cd2a00 |
continue;
|
|
Packit Service |
cd2a00 |
if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0 || strcmp(id, "hint") == 0)
|
|
Packit Service |
cd2a00 |
continue;
|
|
Packit Service |
cd2a00 |
if (strcmp(id, "card") == 0) {
|
|
Packit Service |
cd2a00 |
if (snd_config_get_string(n, &card) < 0) {
|
|
Packit Service |
cd2a00 |
long val;
|
|
Packit Service |
cd2a00 |
err = snd_config_get_integer(n, &val;;
|
|
Packit Service |
cd2a00 |
if (err < 0) {
|
|
Packit Service |
cd2a00 |
SNDERR("Invalid type for %s", id);
|
|
Packit Service |
cd2a00 |
return -EINVAL;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
snprintf(tmpcard, sizeof(tmpcard), "%ld", val);
|
|
Packit Service |
cd2a00 |
card = tmpcard;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
continue;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
if (strcmp(id, "slavepcm") == 0) {
|
|
Packit Service |
cd2a00 |
if (snd_config_get_string(n, &pcm_string) < 0) {
|
|
Packit Service |
cd2a00 |
SNDERR("a52 slavepcm must be a string");
|
|
Packit Service |
cd2a00 |
return -EINVAL;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
continue;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
if (strcmp(id, "rate") == 0) {
|
|
Packit Service |
cd2a00 |
long val;
|
|
Packit Service |
cd2a00 |
if (snd_config_get_integer(n, &val) < 0) {
|
|
Packit Service |
cd2a00 |
SNDERR("Invalid type for %s", id);
|
|
Packit Service |
cd2a00 |
return -EINVAL;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
rate = val;
|
|
Packit Service |
cd2a00 |
if (rate != 44100 && rate != 48000) {
|
|
Packit Service |
cd2a00 |
SNDERR("rate must be 44100 or 48000");
|
|
Packit Service |
cd2a00 |
return -EINVAL;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
continue;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
if (strcmp(id, "bitrate") == 0) {
|
|
Packit Service |
cd2a00 |
long val;
|
|
Packit Service |
cd2a00 |
if (snd_config_get_integer(n, &val) < 0) {
|
|
Packit Service |
cd2a00 |
SNDERR("Invalid type for %s", id);
|
|
Packit Service |
cd2a00 |
return -EINVAL;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
bitrate = val;
|
|
Packit Service |
cd2a00 |
if (bitrate < 128 || bitrate > 1000) {
|
|
Packit Service |
cd2a00 |
SNDERR("Invalid bitrate value %d", bitrate);
|
|
Packit Service |
cd2a00 |
return -EINVAL;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
continue;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
if (strcmp(id, "channels") == 0) {
|
|
Packit Service |
cd2a00 |
long val;
|
|
Packit Service |
cd2a00 |
if (snd_config_get_integer(n, &val) < 0) {
|
|
Packit Service |
cd2a00 |
SNDERR("Invalid type for %s", id);
|
|
Packit Service |
cd2a00 |
return -EINVAL;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
channels = val;
|
|
Packit Service |
cd2a00 |
if (channels != 2 && channels != 4 && channels != 6) {
|
|
Packit Service |
cd2a00 |
SNDERR("channels must be 2, 4 or 6");
|
|
Packit Service |
cd2a00 |
return -EINVAL;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
continue;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
if (strcmp(id, "format") == 0) {
|
|
Packit Service |
cd2a00 |
const char *str;
|
|
Packit Service |
cd2a00 |
err = snd_config_get_string(n, &str);
|
|
Packit Service |
cd2a00 |
if (err < 0) {
|
|
Packit Service |
cd2a00 |
SNDERR("invalid type for %s", id);
|
|
Packit Service |
cd2a00 |
return -EINVAL;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
format = snd_pcm_format_value(str);
|
|
Packit Service |
cd2a00 |
if (format == SND_PCM_FORMAT_UNKNOWN) {
|
|
Packit Service |
cd2a00 |
SNDERR("unknown format %s", str);
|
|
Packit Service |
cd2a00 |
return -EINVAL;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
if (format != SND_PCM_FORMAT_S16_LE &&
|
|
Packit Service |
cd2a00 |
format != SND_PCM_FORMAT_S16_BE) {
|
|
Packit Service |
cd2a00 |
SNDERR("Only S16_LE/BE formats are allowed");
|
|
Packit Service |
cd2a00 |
return -EINVAL;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
continue;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
SNDERR("Unknown field %s", id);
|
|
Packit Service |
cd2a00 |
return -EINVAL;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
rec = calloc(1, sizeof(*rec));
|
|
Packit Service |
cd2a00 |
if (! rec) {
|
|
Packit Service |
cd2a00 |
SNDERR("cannot allocate");
|
|
Packit Service |
cd2a00 |
return -ENOMEM;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
rec->rate = rate;
|
|
Packit Service |
cd2a00 |
rec->bitrate = bitrate;
|
|
Packit Service |
cd2a00 |
rec->channels = channels;
|
|
Packit Service |
cd2a00 |
rec->format = format;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
#ifndef USE_AVCODEC_FRAME
|
|
Packit Service |
cd2a00 |
avcodec_init();
|
|
Packit Service |
cd2a00 |
#endif
|
|
Packit Service |
cd2a00 |
avcodec_register_all();
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
rec->codec = avcodec_find_encoder_by_name("ac3_fixed");
|
|
Packit Service |
cd2a00 |
if (rec->codec == NULL)
|
|
Packit Service |
cd2a00 |
rec->codec = avcodec_find_encoder_by_name("ac3");
|
|
Packit Service |
cd2a00 |
if (rec->codec == NULL)
|
|
Packit Service |
cd2a00 |
rec->codec = avcodec_find_encoder(AV_CODEC_ID_AC3);
|
|
Packit Service |
cd2a00 |
if (rec->codec == NULL) {
|
|
Packit Service |
cd2a00 |
SNDERR("Cannot find codec engine");
|
|
Packit Service |
cd2a00 |
err = -EINVAL;
|
|
Packit Service |
cd2a00 |
goto error;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (! pcm_string || pcm_string[0] == '\0') {
|
|
Packit Service |
cd2a00 |
snprintf(devstr, sizeof(devstr),
|
|
Packit Service |
cd2a00 |
"iec958:{AES0 0x%x AES1 0x%x AES2 0x%x AES3 0x%x %s%s}",
|
|
Packit Service |
cd2a00 |
IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO |
|
|
Packit Service |
cd2a00 |
IEC958_AES0_CON_NOT_COPYRIGHT,
|
|
Packit Service |
cd2a00 |
IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
|
|
Packit Service |
cd2a00 |
0, rate == 48000 ? IEC958_AES3_CON_FS_48000 : IEC958_AES3_CON_FS_44100,
|
|
Packit Service |
cd2a00 |
card ? " CARD " : "",
|
|
Packit Service |
cd2a00 |
card ? card : "");
|
|
Packit Service |
cd2a00 |
err = snd_pcm_open(&rec->slave, devstr, stream, mode);
|
|
Packit Service |
cd2a00 |
if (err < 0)
|
|
Packit Service |
cd2a00 |
goto error;
|
|
Packit Service |
cd2a00 |
/* in case the slave doesn't support S16 format */
|
|
Packit Service |
cd2a00 |
err = snd_pcm_linear_open(&rec->slave, NULL, SND_PCM_FORMAT_S16,
|
|
Packit Service |
cd2a00 |
rec->slave, 1);
|
|
Packit Service |
cd2a00 |
if (err < 0)
|
|
Packit Service |
cd2a00 |
goto error;
|
|
Packit Service |
cd2a00 |
} else {
|
|
Packit Service |
cd2a00 |
err = snd_pcm_open(&rec->slave, pcm_string, stream, mode);
|
|
Packit Service |
cd2a00 |
if (err < 0)
|
|
Packit Service |
cd2a00 |
goto error;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
rec->io.version = SND_PCM_IOPLUG_VERSION;
|
|
Packit Service |
cd2a00 |
rec->io.name = "A52 Output Plugin";
|
|
Packit Service |
cd2a00 |
rec->io.mmap_rw = 0;
|
|
Packit Service |
cd2a00 |
rec->io.callback = &a52_ops;
|
|
Packit Service |
cd2a00 |
rec->io.private_data = rec;
|
|
Packit Service |
cd2a00 |
#ifdef USE_AVCODEC_FRAME
|
|
Packit Service |
cd2a00 |
rec->av_format = rec->codec->sample_fmts[0];
|
|
Packit Service |
cd2a00 |
rec->is_planar = av_sample_fmt_is_planar(rec->av_format);
|
|
Packit Service |
cd2a00 |
#else
|
|
Packit Service |
cd2a00 |
rec->av_format = AV_SAMPLE_FMT_S16;
|
|
Packit Service |
cd2a00 |
#endif
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
err = snd_pcm_ioplug_create(&rec->io, name, stream, mode);
|
|
Packit Service |
cd2a00 |
if (err < 0)
|
|
Packit Service |
cd2a00 |
goto error;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if ((err = a52_set_hw_constraint(rec)) < 0) {
|
|
Packit Service |
cd2a00 |
snd_pcm_ioplug_delete(&rec->io);
|
|
Packit Service |
cd2a00 |
goto error;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
*pcmp = rec->io.pcm;
|
|
Packit Service |
cd2a00 |
return 0;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
error:
|
|
Packit Service |
cd2a00 |
if (rec->slave)
|
|
Packit Service |
cd2a00 |
snd_pcm_close(rec->slave);
|
|
Packit Service |
cd2a00 |
free(rec);
|
|
Packit Service |
cd2a00 |
return err;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
SND_PCM_PLUGIN_SYMBOL(a52);
|