Blame a52/pcm_a52.c

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