Blame src/pcm/pcm_iec958.c

Packit 4a16fb
/**
Packit 4a16fb
 * \file pcm/pcm_iec958.c
Packit 4a16fb
 * \ingroup PCM_Plugins
Packit 4a16fb
 * \brief PCM IEC958 Subframe Conversion Plugin Interface
Packit 4a16fb
 * \author Takashi Iwai <tiwai@suse.de>
Packit 4a16fb
 * \date 2004
Packit 4a16fb
 */
Packit 4a16fb
/*
Packit 4a16fb
 *  PCM - IEC958 Subframe Conversion Plugin
Packit 4a16fb
 *  Copyright (c) 2004 by Takashi Iwai <tiwai@suse.de>
Packit 4a16fb
 *
Packit 4a16fb
 *
Packit 4a16fb
 *   This library is free software; you can redistribute it and/or modify
Packit 4a16fb
 *   it under the terms of the GNU Lesser General Public License as
Packit 4a16fb
 *   published by the Free Software Foundation; either version 2.1 of
Packit 4a16fb
 *   the License, or (at your option) any later version.
Packit 4a16fb
 *
Packit 4a16fb
 *   This program is distributed in the hope that it will be useful,
Packit 4a16fb
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 4a16fb
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 4a16fb
 *   GNU Lesser General Public License for more details.
Packit 4a16fb
 *
Packit 4a16fb
 *   You should have received a copy of the GNU Lesser General Public
Packit 4a16fb
 *   License along with this library; if not, write to the Free Software
Packit 4a16fb
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Packit 4a16fb
 *
Packit 4a16fb
 */
Packit 4a16fb
  
Packit 4a16fb
#include "bswap.h"
Packit 4a16fb
#include "pcm_local.h"
Packit 4a16fb
#include "pcm_plugin.h"
Packit 4a16fb
Packit 4a16fb
#include "plugin_ops.h"
Packit 4a16fb
Packit 4a16fb
#ifndef PIC
Packit 4a16fb
/* entry for static linking */
Packit 4a16fb
const char *_snd_module_pcm_iec958 = "";
Packit 4a16fb
#endif
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 */
Packit 4a16fb
Packit 4a16fb
#ifndef DOC_HIDDEN
Packit 4a16fb
Packit 4a16fb
typedef struct snd_pcm_iec958 snd_pcm_iec958_t;
Packit 4a16fb
Packit 4a16fb
typedef void (*iec958_f)(snd_pcm_iec958_t *iec,
Packit 4a16fb
			 const snd_pcm_channel_area_t *dst_areas,
Packit 4a16fb
			 snd_pcm_uframes_t dst_offset,
Packit 4a16fb
			 const snd_pcm_channel_area_t *src_areas,
Packit 4a16fb
			 snd_pcm_uframes_t src_offset,
Packit 4a16fb
			 unsigned int channels, snd_pcm_uframes_t frames);
Packit 4a16fb
Packit 4a16fb
struct snd_pcm_iec958 {
Packit 4a16fb
	/* This field need to be the first */
Packit 4a16fb
	snd_pcm_plugin_t plug;
Packit 4a16fb
	unsigned int getput_idx;
Packit 4a16fb
	iec958_f func;
Packit 4a16fb
	snd_pcm_format_t sformat;
Packit 4a16fb
	snd_pcm_format_t format;
Packit 4a16fb
	unsigned int counter;
Packit 4a16fb
	unsigned char status[24];
Packit 4a16fb
	unsigned int byteswap;
Packit 4a16fb
	unsigned char preamble[3];	/* B/M/W or Z/X/Y */
Packit 4a16fb
	snd_pcm_fast_ops_t fops;
Packit 4a16fb
};
Packit 4a16fb
Packit 4a16fb
enum { PREAMBLE_Z, PREAMBLE_X, PREAMBLE_Y };
Packit 4a16fb
Packit 4a16fb
#endif /* DOC_HIDDEN */
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * Determine parity for time slots 4 upto 30
Packit 4a16fb
 * to be sure that bit 4 upt 31 will carry
Packit 4a16fb
 * an even number of ones and zeros.
Packit 4a16fb
 */
Packit 4a16fb
static unsigned int iec958_parity(unsigned int data)
Packit 4a16fb
{
Packit 4a16fb
	unsigned int parity;
Packit 4a16fb
	int bit;
Packit 4a16fb
Packit 4a16fb
	data >>= 4;     /* start from bit 4 */
Packit 4a16fb
	parity = 0;
Packit 4a16fb
	for (bit = 4; bit <= 30; bit++) {
Packit 4a16fb
		if (data & 1)
Packit 4a16fb
			parity++;
Packit 4a16fb
		data >>= 1;
Packit 4a16fb
	}
Packit 4a16fb
	return (parity & 1);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * Compose 32bit IEC958 subframe, two sub frames
Packit 4a16fb
 * build one frame with two channels.
Packit 4a16fb
 *
Packit 4a16fb
 * bit 0-3  = preamble
Packit 4a16fb
 *     4-7  = AUX (=0)
Packit 4a16fb
 *     8-27 = data (12-27 for 16bit, 8-27 for 20bit, and 24bit without AUX)
Packit 4a16fb
 *     28   = validity (0 for valid data, else 'in error')
Packit 4a16fb
 *     29   = user data (0)
Packit 4a16fb
 *     30   = channel status (24 bytes for 192 frames)
Packit 4a16fb
 *     31   = parity
Packit 4a16fb
 */
Packit 4a16fb
Packit 4a16fb
static inline uint32_t iec958_subframe(snd_pcm_iec958_t *iec, uint32_t data, int channel)
Packit 4a16fb
{
Packit 4a16fb
	unsigned int byte = iec->counter >> 3;
Packit 4a16fb
	unsigned int mask = 1 << (iec->counter - (byte << 3));
Packit 4a16fb
Packit 4a16fb
	/* bit 4-27 */
Packit 4a16fb
	data >>= 4;
Packit 4a16fb
	data &= ~0xf;
Packit 4a16fb
Packit 4a16fb
	/* set IEC status bits (up to 192 bits) */
Packit 4a16fb
	if (iec->status[byte] & mask)
Packit 4a16fb
		data |= 0x40000000;
Packit 4a16fb
Packit 4a16fb
	if (iec958_parity(data))	/* parity bit 4-30 */
Packit 4a16fb
		data |= 0x80000000;
Packit 4a16fb
Packit 4a16fb
	/* Preamble */
Packit 4a16fb
	if (channel)
Packit 4a16fb
		data |= iec->preamble[PREAMBLE_Y];	/* odd sub frame, 'Y' */
Packit 4a16fb
	else if (! iec->counter)
Packit 4a16fb
		data |= iec->preamble[PREAMBLE_Z];	/* Block start, 'Z' */
Packit 4a16fb
	else
Packit 4a16fb
		data |= iec->preamble[PREAMBLE_X];	/* even sub frame, 'X' */
Packit 4a16fb
Packit 4a16fb
	if (iec->byteswap)
Packit 4a16fb
		data = bswap_32(data);
Packit 4a16fb
Packit 4a16fb
	return data;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static inline int32_t iec958_to_s32(snd_pcm_iec958_t *iec, uint32_t data)
Packit 4a16fb
{
Packit 4a16fb
	if (iec->byteswap)
Packit 4a16fb
		data = bswap_32(data);
Packit 4a16fb
	data &= ~0xf;
Packit 4a16fb
	data <<= 4;
Packit 4a16fb
	return (int32_t)data;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
#ifndef DOC_HIDDEN
Packit 4a16fb
static void snd_pcm_iec958_decode(snd_pcm_iec958_t *iec,
Packit 4a16fb
				  const snd_pcm_channel_area_t *dst_areas,
Packit 4a16fb
				  snd_pcm_uframes_t dst_offset,
Packit 4a16fb
				  const snd_pcm_channel_area_t *src_areas,
Packit 4a16fb
				  snd_pcm_uframes_t src_offset,
Packit 4a16fb
				  unsigned int channels, snd_pcm_uframes_t frames)
Packit 4a16fb
{
Packit 4a16fb
#define PUT32_LABELS
Packit 4a16fb
#include "plugin_ops.h"
Packit 4a16fb
#undef PUT32_LABELS
Packit 4a16fb
	void *put = put32_labels[iec->getput_idx];
Packit 4a16fb
	unsigned int channel;
Packit 4a16fb
	for (channel = 0; channel < channels; ++channel) {
Packit 4a16fb
		const uint32_t *src;
Packit 4a16fb
		char *dst;
Packit 4a16fb
		int src_step, dst_step;
Packit 4a16fb
		snd_pcm_uframes_t frames1;
Packit 4a16fb
		const snd_pcm_channel_area_t *src_area = &src_areas[channel];
Packit 4a16fb
		const snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
Packit 4a16fb
		src = snd_pcm_channel_area_addr(src_area, src_offset);
Packit 4a16fb
		dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
Packit 4a16fb
		src_step = snd_pcm_channel_area_step(src_area) / sizeof(uint32_t);
Packit 4a16fb
		dst_step = snd_pcm_channel_area_step(dst_area);
Packit 4a16fb
		frames1 = frames;
Packit 4a16fb
		while (frames1-- > 0) {
Packit 4a16fb
			int32_t sample = iec958_to_s32(iec, *src);
Packit 4a16fb
			goto *put;
Packit 4a16fb
#define PUT32_END after
Packit 4a16fb
#include "plugin_ops.h"
Packit 4a16fb
#undef PUT32_END
Packit 4a16fb
		after:
Packit 4a16fb
			src += src_step;
Packit 4a16fb
			dst += dst_step;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static void snd_pcm_iec958_encode(snd_pcm_iec958_t *iec,
Packit 4a16fb
				  const snd_pcm_channel_area_t *dst_areas,
Packit 4a16fb
				  snd_pcm_uframes_t dst_offset,
Packit 4a16fb
				  const snd_pcm_channel_area_t *src_areas,
Packit 4a16fb
				  snd_pcm_uframes_t src_offset,
Packit 4a16fb
				  unsigned int channels, snd_pcm_uframes_t frames)
Packit 4a16fb
{
Packit 4a16fb
#define GET32_LABELS
Packit 4a16fb
#include "plugin_ops.h"
Packit 4a16fb
#undef GET32_LABELS
Packit 4a16fb
	void *get = get32_labels[iec->getput_idx];
Packit 4a16fb
	unsigned int channel;
Packit 4a16fb
	int32_t sample = 0;
Packit 4a16fb
	int counter = iec->counter;
Packit 4a16fb
	for (channel = 0; channel < channels; ++channel) {
Packit 4a16fb
		const char *src;
Packit 4a16fb
		uint32_t *dst;
Packit 4a16fb
		int src_step, dst_step;
Packit 4a16fb
		snd_pcm_uframes_t frames1;
Packit 4a16fb
		const snd_pcm_channel_area_t *src_area = &src_areas[channel];
Packit 4a16fb
		const snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
Packit 4a16fb
		src = snd_pcm_channel_area_addr(src_area, src_offset);
Packit 4a16fb
		dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
Packit 4a16fb
		src_step = snd_pcm_channel_area_step(src_area);
Packit 4a16fb
		dst_step = snd_pcm_channel_area_step(dst_area) / sizeof(uint32_t);
Packit 4a16fb
		frames1 = frames;
Packit 4a16fb
		iec->counter = counter;
Packit 4a16fb
		while (frames1-- > 0) {
Packit 4a16fb
			goto *get;
Packit 4a16fb
#define GET32_END after
Packit 4a16fb
#include "plugin_ops.h"
Packit 4a16fb
#undef GET32_END
Packit 4a16fb
		after:
Packit 4a16fb
			sample = iec958_subframe(iec, sample, channel);
Packit 4a16fb
			// fprintf(stderr, "%d:%08x\n", frames1, sample);
Packit 4a16fb
			*dst = sample;
Packit 4a16fb
			src += src_step;
Packit 4a16fb
			dst += dst_step;
Packit 4a16fb
			iec->counter++;
Packit 4a16fb
			iec->counter %= 192;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
}
Packit 4a16fb
#endif /* DOC_HIDDEN */
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_iec958_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_iec958_t *iec = pcm->private_data;
Packit 4a16fb
	int err;
Packit 4a16fb
	snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM };
Packit 4a16fb
	err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS,
Packit 4a16fb
					 &access_mask);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	if (iec->sformat == SND_PCM_FORMAT_IEC958_SUBFRAME_LE ||
Packit 4a16fb
	    iec->sformat == SND_PCM_FORMAT_IEC958_SUBFRAME_BE) {
Packit 4a16fb
		snd_pcm_format_mask_t format_mask = { SND_PCM_FMTBIT_LINEAR };
Packit 4a16fb
		err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_FORMAT,
Packit 4a16fb
						 &format_mask);
Packit 4a16fb
	} else {
Packit 4a16fb
		snd_pcm_format_mask_t format_mask = {
Packit 4a16fb
			{ (1U << SND_PCM_FORMAT_IEC958_SUBFRAME_LE) |
Packit 4a16fb
			  (1U << SND_PCM_FORMAT_IEC958_SUBFRAME_BE) }
Packit 4a16fb
		};
Packit 4a16fb
		err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_FORMAT,
Packit 4a16fb
						 &format_mask);
Packit 4a16fb
	}
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	err = _snd_pcm_hw_params_set_subformat(params, SND_PCM_SUBFORMAT_STD);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_iec958_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_iec958_t *iec = pcm->private_data;
Packit 4a16fb
	snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP };
Packit 4a16fb
	_snd_pcm_hw_params_any(sparams);
Packit 4a16fb
	_snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
Packit 4a16fb
				   &saccess_mask);
Packit 4a16fb
	_snd_pcm_hw_params_set_format(sparams, iec->sformat);
Packit 4a16fb
	_snd_pcm_hw_params_set_subformat(sparams, SND_PCM_SUBFORMAT_STD);
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_iec958_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
Packit 4a16fb
					    snd_pcm_hw_params_t *sparams)
Packit 4a16fb
{
Packit 4a16fb
	int err;
Packit 4a16fb
	unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_RATE |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_PERIOD_SIZE |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_BUFFER_SIZE |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_PERIODS |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_PERIOD_TIME |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_BUFFER_TIME |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_TICK_TIME);
Packit 4a16fb
	err = _snd_pcm_hw_params_refine(sparams, links, params);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
	
Packit 4a16fb
static int snd_pcm_iec958_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
Packit 4a16fb
					    snd_pcm_hw_params_t *sparams)
Packit 4a16fb
{
Packit 4a16fb
	int err;
Packit 4a16fb
	unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_RATE |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_PERIOD_SIZE |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_BUFFER_SIZE |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_PERIODS |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_PERIOD_TIME |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_BUFFER_TIME |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_TICK_TIME);
Packit 4a16fb
	err = _snd_pcm_hw_params_refine(params, links, sparams);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_iec958_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
Packit 4a16fb
{
Packit 4a16fb
	return snd_pcm_hw_refine_slave(pcm, params,
Packit 4a16fb
				       snd_pcm_iec958_hw_refine_cprepare,
Packit 4a16fb
				       snd_pcm_iec958_hw_refine_cchange,
Packit 4a16fb
				       snd_pcm_iec958_hw_refine_sprepare,
Packit 4a16fb
				       snd_pcm_iec958_hw_refine_schange,
Packit 4a16fb
				       snd_pcm_generic_hw_refine);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_iec958_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_iec958_t *iec = pcm->private_data;
Packit 4a16fb
	snd_pcm_format_t format;
Packit 4a16fb
	int err = snd_pcm_hw_params_slave(pcm, params,
Packit 4a16fb
					  snd_pcm_iec958_hw_refine_cchange,
Packit 4a16fb
					  snd_pcm_iec958_hw_refine_sprepare,
Packit 4a16fb
					  snd_pcm_iec958_hw_refine_schange,
Packit 4a16fb
					  snd_pcm_generic_hw_params);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
Packit 4a16fb
	err = INTERNAL(snd_pcm_hw_params_get_format)(params, &format);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
Packit 4a16fb
	iec->format = format;
Packit 4a16fb
	if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
Packit 4a16fb
		if (iec->sformat == SND_PCM_FORMAT_IEC958_SUBFRAME_LE ||
Packit 4a16fb
		    iec->sformat == SND_PCM_FORMAT_IEC958_SUBFRAME_BE) {
Packit 4a16fb
			iec->getput_idx = snd_pcm_linear_get_index(format, SND_PCM_FORMAT_S32);
Packit 4a16fb
			iec->func = snd_pcm_iec958_encode;
Packit 4a16fb
			iec->byteswap = iec->sformat != SND_PCM_FORMAT_IEC958_SUBFRAME;
Packit 4a16fb
		} else {
Packit 4a16fb
			iec->getput_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S32, iec->sformat);
Packit 4a16fb
			iec->func = snd_pcm_iec958_decode;
Packit 4a16fb
			iec->byteswap = format != SND_PCM_FORMAT_IEC958_SUBFRAME;
Packit 4a16fb
		}
Packit 4a16fb
	} else {
Packit 4a16fb
		if (iec->sformat == SND_PCM_FORMAT_IEC958_SUBFRAME_LE ||
Packit 4a16fb
		    iec->sformat == SND_PCM_FORMAT_IEC958_SUBFRAME_BE) {
Packit 4a16fb
			iec->getput_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S32, format);
Packit 4a16fb
			iec->func = snd_pcm_iec958_decode;
Packit 4a16fb
			iec->byteswap = iec->sformat != SND_PCM_FORMAT_IEC958_SUBFRAME;
Packit 4a16fb
		} else {
Packit 4a16fb
			iec->getput_idx = snd_pcm_linear_get_index(iec->sformat, SND_PCM_FORMAT_S32);
Packit 4a16fb
			iec->func = snd_pcm_iec958_encode;
Packit 4a16fb
			iec->byteswap = format != SND_PCM_FORMAT_IEC958_SUBFRAME;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
	/* FIXME: needs to adjust status_bits according to the format
Packit 4a16fb
	 *        and sample rate
Packit 4a16fb
	 */
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_uframes_t
Packit 4a16fb
snd_pcm_iec958_write_areas(snd_pcm_t *pcm,
Packit 4a16fb
			   const snd_pcm_channel_area_t *areas,
Packit 4a16fb
			   snd_pcm_uframes_t offset,
Packit 4a16fb
			   snd_pcm_uframes_t size,
Packit 4a16fb
			   const snd_pcm_channel_area_t *slave_areas,
Packit 4a16fb
			   snd_pcm_uframes_t slave_offset,
Packit 4a16fb
			   snd_pcm_uframes_t *slave_sizep)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_iec958_t *iec = pcm->private_data;
Packit 4a16fb
	if (size > *slave_sizep)
Packit 4a16fb
		size = *slave_sizep;
Packit 4a16fb
	iec->func(iec, slave_areas, slave_offset,
Packit 4a16fb
		  areas, offset, 
Packit 4a16fb
		  pcm->channels, size);
Packit 4a16fb
	*slave_sizep = size;
Packit 4a16fb
	return size;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_uframes_t
Packit 4a16fb
snd_pcm_iec958_read_areas(snd_pcm_t *pcm,
Packit 4a16fb
			  const snd_pcm_channel_area_t *areas,
Packit 4a16fb
			  snd_pcm_uframes_t offset,
Packit 4a16fb
			  snd_pcm_uframes_t size,
Packit 4a16fb
			  const snd_pcm_channel_area_t *slave_areas,
Packit 4a16fb
			  snd_pcm_uframes_t slave_offset,
Packit 4a16fb
			  snd_pcm_uframes_t *slave_sizep)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_iec958_t *iec = pcm->private_data;
Packit 4a16fb
	if (size > *slave_sizep)
Packit 4a16fb
		size = *slave_sizep;
Packit 4a16fb
	iec->func(iec, areas, offset, 
Packit 4a16fb
		  slave_areas, slave_offset,
Packit 4a16fb
		  pcm->channels, size);
Packit 4a16fb
	*slave_sizep = size;
Packit 4a16fb
	return size;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_iec958_init(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_iec958_t *iec = pcm->private_data;
Packit 4a16fb
	iec->counter = 0;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static void snd_pcm_iec958_dump(snd_pcm_t *pcm, snd_output_t *out)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_iec958_t *iec = pcm->private_data;
Packit 4a16fb
	snd_output_printf(out, "IEC958 subframe conversion PCM (%s)\n", 
Packit 4a16fb
			  snd_pcm_format_name(iec->sformat));
Packit 4a16fb
	if (pcm->setup) {
Packit 4a16fb
		snd_output_printf(out, "Its setup is:\n");
Packit 4a16fb
		snd_pcm_dump_setup(pcm, out);
Packit 4a16fb
	}
Packit 4a16fb
	snd_output_printf(out, "Slave: ");
Packit 4a16fb
	snd_pcm_dump(iec->plug.gen.slave, out);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t snd_pcm_iec958_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
Packit 4a16fb
{
Packit 4a16fb
	unsigned int counter_decrement;
Packit 4a16fb
	snd_pcm_iec958_t *iec = pcm->private_data;
Packit 4a16fb
	snd_pcm_sframes_t result = snd_pcm_plugin_rewind(pcm, frames);
Packit 4a16fb
	if (result <= 0)
Packit 4a16fb
		return result;
Packit 4a16fb
Packit 4a16fb
	counter_decrement = result % 192;
Packit 4a16fb
	iec->counter += 192 - counter_decrement;
Packit 4a16fb
	iec->counter %= 192;
Packit 4a16fb
	return result;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t snd_pcm_iec958_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
Packit 4a16fb
Packit 4a16fb
{
Packit 4a16fb
	unsigned int counter_increment;
Packit 4a16fb
	snd_pcm_iec958_t *iec = pcm->private_data;
Packit 4a16fb
	snd_pcm_sframes_t result = snd_pcm_plugin_rewind(pcm, frames);
Packit 4a16fb
	if (result <= 0)
Packit 4a16fb
		return result;
Packit 4a16fb
Packit 4a16fb
	counter_increment = result % 192;
Packit 4a16fb
	iec->counter += counter_increment;
Packit 4a16fb
	iec->counter %= 192;
Packit 4a16fb
	return result;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static const snd_pcm_ops_t snd_pcm_iec958_ops = {
Packit 4a16fb
	.close = snd_pcm_generic_close,
Packit 4a16fb
	.info = snd_pcm_generic_info,
Packit 4a16fb
	.hw_refine = snd_pcm_iec958_hw_refine,
Packit 4a16fb
	.hw_params = snd_pcm_iec958_hw_params,
Packit 4a16fb
	.hw_free = snd_pcm_generic_hw_free,
Packit 4a16fb
	.sw_params = snd_pcm_generic_sw_params,
Packit 4a16fb
	.channel_info = snd_pcm_generic_channel_info,
Packit 4a16fb
	.dump = snd_pcm_iec958_dump,
Packit 4a16fb
	.nonblock = snd_pcm_generic_nonblock,
Packit 4a16fb
	.async = snd_pcm_generic_async,
Packit 4a16fb
	.mmap = snd_pcm_generic_mmap,
Packit 4a16fb
	.munmap = snd_pcm_generic_munmap,
Packit 4a16fb
	.query_chmaps = snd_pcm_generic_query_chmaps,
Packit 4a16fb
	.get_chmap = snd_pcm_generic_get_chmap,
Packit 4a16fb
	.set_chmap = snd_pcm_generic_set_chmap,
Packit 4a16fb
};
Packit 4a16fb
Packit 4a16fb
/**
Packit 4a16fb
 * \brief Creates a new IEC958 subframe conversion PCM
Packit 4a16fb
 * \param pcmp Returns created PCM handle
Packit 4a16fb
 * \param name Name of PCM
Packit 4a16fb
 * \param sformat Slave (destination) format
Packit 4a16fb
 * \param slave Slave PCM handle
Packit 4a16fb
 * \param close_slave When set, the slave PCM handle is closed with copy PCM
Packit 4a16fb
 * \param status_bits The IEC958 status bits
Packit 4a16fb
 * \param preamble_vals The preamble byte values
Packit 4a16fb
 * \retval zero on success otherwise a negative error code
Packit 4a16fb
 * \warning Using of this function might be dangerous in the sense
Packit 4a16fb
 *          of compatibility reasons. The prototype might be freely
Packit 4a16fb
 *          changed in future.
Packit 4a16fb
 */           
Packit 4a16fb
int snd_pcm_iec958_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sformat,
Packit 4a16fb
			snd_pcm_t *slave, int close_slave,
Packit 4a16fb
			const unsigned char *status_bits,
Packit 4a16fb
			const unsigned char *preamble_vals)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_t *pcm;
Packit 4a16fb
	snd_pcm_iec958_t *iec;
Packit 4a16fb
	int err;
Packit 4a16fb
	static const unsigned char default_status_bits[] = {
Packit 4a16fb
		IEC958_AES0_CON_EMPHASIS_NONE,
Packit 4a16fb
		IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
Packit 4a16fb
		0,
Packit 4a16fb
		IEC958_AES3_CON_FS_48000
Packit 4a16fb
	};
Packit 4a16fb
Packit 4a16fb
	assert(pcmp && slave);
Packit 4a16fb
	if (snd_pcm_format_linear(sformat) != 1 &&
Packit 4a16fb
	    sformat != SND_PCM_FORMAT_IEC958_SUBFRAME_LE &&
Packit 4a16fb
	    sformat != SND_PCM_FORMAT_IEC958_SUBFRAME_BE)
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	iec = calloc(1, sizeof(snd_pcm_iec958_t));
Packit 4a16fb
	if (!iec) {
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
	}
Packit 4a16fb
	snd_pcm_plugin_init(&iec->plug);
Packit 4a16fb
	iec->sformat = sformat;
Packit 4a16fb
	iec->plug.read = snd_pcm_iec958_read_areas;
Packit 4a16fb
	iec->plug.write = snd_pcm_iec958_write_areas;
Packit 4a16fb
	iec->plug.init = snd_pcm_iec958_init;
Packit 4a16fb
	iec->plug.undo_read = snd_pcm_plugin_undo_read_generic;
Packit 4a16fb
	iec->plug.undo_write = snd_pcm_plugin_undo_write_generic;
Packit 4a16fb
	iec->plug.gen.slave = slave;
Packit 4a16fb
	iec->plug.gen.close_slave = close_slave;
Packit 4a16fb
Packit 4a16fb
	if (status_bits)
Packit 4a16fb
		memcpy(iec->status, status_bits, sizeof(iec->status));
Packit 4a16fb
	else
Packit 4a16fb
		memcpy(iec->status, default_status_bits, sizeof(default_status_bits));
Packit 4a16fb
Packit 4a16fb
	memcpy(iec->preamble, preamble_vals, 3);
Packit 4a16fb
Packit 4a16fb
	err = snd_pcm_new(&pcm, SND_PCM_TYPE_IEC958, name, slave->stream, slave->mode);
Packit 4a16fb
	if (err < 0) {
Packit 4a16fb
		free(iec);
Packit 4a16fb
		return err;
Packit 4a16fb
	}
Packit 4a16fb
	pcm->ops = &snd_pcm_iec958_ops;
Packit 4a16fb
Packit 4a16fb
	iec->fops = snd_pcm_plugin_fast_ops;
Packit 4a16fb
	iec->fops.rewind = snd_pcm_iec958_rewind;
Packit 4a16fb
	iec->fops.forward = snd_pcm_iec958_forward;
Packit 4a16fb
	pcm->fast_ops = &iec->fops;
Packit 4a16fb
Packit 4a16fb
	pcm->private_data = iec;
Packit 4a16fb
	pcm->poll_fd = slave->poll_fd;
Packit 4a16fb
	pcm->poll_events = slave->poll_events;
Packit 4a16fb
	pcm->tstamp_type = slave->tstamp_type;
Packit 4a16fb
	snd_pcm_set_hw_ptr(pcm, &iec->plug.hw_ptr, -1, 0);
Packit 4a16fb
	snd_pcm_set_appl_ptr(pcm, &iec->plug.appl_ptr, -1, 0);
Packit 4a16fb
	*pcmp = pcm;
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/*! \page pcm_plugins
Packit 4a16fb
Packit 4a16fb
\section pcm_plugins_iec958 Plugin: IEC958
Packit 4a16fb
Packit 4a16fb
This plugin converts 32bit IEC958 subframe samples to linear, or linear to
Packit 4a16fb
32bit IEC958 subframe samples.
Packit 4a16fb
Packit 4a16fb
\code
Packit 4a16fb
pcm.name {
Packit 4a16fb
        type iec958             # IEC958 subframe conversion PCM
Packit 4a16fb
        slave STR               # Slave name
Packit 4a16fb
        # or
Packit 4a16fb
        slave {                 # Slave definition
Packit 4a16fb
                pcm STR         # Slave PCM name
Packit 4a16fb
                # or
Packit 4a16fb
                pcm { }         # Slave PCM definition
Packit 4a16fb
        }
Packit 4a16fb
	[status status-bytes]	# IEC958 status bits (given in byte array)
Packit 4a16fb
	# IEC958 preamble bits definitions
Packit 4a16fb
	# B/M/W or Z/X/Y, B = block start, M = even subframe, W = odd subframe
Packit 4a16fb
	# As default, Z = 0x08, Y = 0x04, X = 0x02
Packit 4a16fb
	[preamble.z or preamble.b val]
Packit 4a16fb
	[preamble.x or preamble.m val]
Packit 4a16fb
	[preamble.y or preamble.w val]
Packit 4a16fb
}
Packit 4a16fb
\endcode
Packit 4a16fb
Packit 4a16fb
\subsection pcm_plugins_iec958_funcref Function reference
Packit 4a16fb
Packit 4a16fb
    Packit 4a16fb
      
  • snd_pcm_iec958_open()
  • Packit 4a16fb
      
  • _snd_pcm_iec958_open()
  • Packit 4a16fb
    Packit 4a16fb
    Packit 4a16fb
    */
    Packit 4a16fb
    Packit 4a16fb
    /**
    Packit 4a16fb
     * \brief Creates a new IEC958 subframe conversion PCM
    Packit 4a16fb
     * \param pcmp Returns created PCM handle
    Packit 4a16fb
     * \param name Name of PCM
    Packit 4a16fb
     * \param root Root configuration node
    Packit 4a16fb
     * \param conf Configuration node with copy PCM description
    Packit 4a16fb
     * \param stream Stream type
    Packit 4a16fb
     * \param mode Stream mode
    Packit 4a16fb
     * \retval zero on success otherwise a negative error code
    Packit 4a16fb
     * \warning Using of this function might be dangerous in the sense
    Packit 4a16fb
     *          of compatibility reasons. The prototype might be freely
    Packit 4a16fb
     *          changed in future.
    Packit 4a16fb
     */
    Packit 4a16fb
    int _snd_pcm_iec958_open(snd_pcm_t **pcmp, const char *name,
    Packit 4a16fb
    			 snd_config_t *root, snd_config_t *conf, 
    Packit 4a16fb
    			 snd_pcm_stream_t stream, int mode)
    Packit 4a16fb
    {
    Packit 4a16fb
    	snd_config_iterator_t i, next;
    Packit 4a16fb
    	int err;
    Packit 4a16fb
    	snd_pcm_t *spcm;
    Packit 4a16fb
    	snd_config_t *slave = NULL, *sconf;
    Packit 4a16fb
    	snd_config_t *status = NULL, *preamble = NULL;
    Packit 4a16fb
    	snd_pcm_format_t sformat;
    Packit 4a16fb
    	unsigned char status_bits[24];
    Packit 4a16fb
    	unsigned char preamble_vals[3] = {
    Packit 4a16fb
    		0x08, 0x02, 0x04 /* Z, X, Y */
    Packit 4a16fb
    	};
    Packit 4a16fb
    Packit 4a16fb
    	snd_config_for_each(i, next, conf) {
    Packit 4a16fb
    		snd_config_t *n = snd_config_iterator_entry(i);
    Packit 4a16fb
    		const char *id;
    Packit 4a16fb
    		if (snd_config_get_id(n, &id) < 0)
    Packit 4a16fb
    			continue;
    Packit 4a16fb
    		if (snd_pcm_conf_generic_id(id))
    Packit 4a16fb
    			continue;
    Packit 4a16fb
    		if (strcmp(id, "slave") == 0) {
    Packit 4a16fb
    			slave = n;
    Packit 4a16fb
    			continue;
    Packit 4a16fb
    		}
    Packit 4a16fb
    		if (strcmp(id, "status") == 0) {
    Packit 4a16fb
    			if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
    Packit 4a16fb
    				SNDERR("Invalid type for %s", id);
    Packit 4a16fb
    				return -EINVAL;
    Packit 4a16fb
    			}
    Packit 4a16fb
    			status = n;
    Packit 4a16fb
    			continue;
    Packit 4a16fb
    		}
    Packit 4a16fb
    		if (strcmp(id, "preamble") == 0) {
    Packit 4a16fb
    			if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
    Packit 4a16fb
    				SNDERR("Invalid type for %s", id);
    Packit 4a16fb
    				return -EINVAL;
    Packit 4a16fb
    			}
    Packit 4a16fb
    			preamble = n;
    Packit 4a16fb
    			continue;
    Packit 4a16fb
    		}
    Packit 4a16fb
    		SNDERR("Unknown field %s", id);
    Packit 4a16fb
    		return -EINVAL;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	memset(status_bits, 0, sizeof(status_bits));
    Packit 4a16fb
    	if (status) {
    Packit 4a16fb
    		snd_config_iterator_t i, inext;
    Packit 4a16fb
    		int bytes = 0;
    Packit 4a16fb
    		snd_config_for_each(i, inext, status) {
    Packit 4a16fb
    			long val;
    Packit 4a16fb
    			snd_config_t *n = snd_config_iterator_entry(i);
    Packit 4a16fb
    			if (snd_config_get_type(n) != SND_CONFIG_TYPE_INTEGER) {
    Packit 4a16fb
    				SNDERR("invalid IEC958 status bits");
    Packit 4a16fb
    				return -EINVAL;
    Packit 4a16fb
    			}
    Packit 4a16fb
    			err = snd_config_get_integer(n, &val;;
    Packit 4a16fb
    			if (err < 0) {
    Packit 4a16fb
    				SNDERR("invalid IEC958 status bits");
    Packit 4a16fb
    				return err;
    Packit 4a16fb
    			}
    Packit 4a16fb
    			status_bits[bytes] = val;
    Packit 4a16fb
    			bytes++;
    Packit 4a16fb
    			if (bytes >= (int)sizeof(status_bits))
    Packit 4a16fb
    				break;
    Packit 4a16fb
    		}
    Packit 4a16fb
    		// fprintf(stderr, "STATUS bits: %02x %02x %02x %02x\n", status_bits[0], status_bits[1], status_bits[2], status_bits[3]);
    Packit 4a16fb
    	}
    Packit 4a16fb
    	if (preamble) {
    Packit 4a16fb
    		snd_config_iterator_t i, inext;
    Packit 4a16fb
    		snd_config_for_each(i, inext, preamble) {
    Packit 4a16fb
    			long val;
    Packit 4a16fb
    			snd_config_t *n = snd_config_iterator_entry(i);
    Packit 4a16fb
    			const char *id;
    Packit 4a16fb
    			int idx;
    Packit 4a16fb
    			if (snd_config_get_id(n, &id) < 0)
    Packit 4a16fb
    				continue;
    Packit 4a16fb
    			if (strcmp(id, "b") == 0 || strcmp(id, "z") == 0)
    Packit 4a16fb
    				idx = PREAMBLE_Z;
    Packit 4a16fb
    			else if (strcmp(id, "m") == 0 || strcmp(id, "x") == 0)
    Packit 4a16fb
    				idx = PREAMBLE_X;
    Packit 4a16fb
    			else if (strcmp(id, "w") == 0 || strcmp(id, "y") == 0)
    Packit 4a16fb
    				idx = PREAMBLE_Y;
    Packit 4a16fb
    			else {
    Packit 4a16fb
    				SNDERR("invalid IEC958 preamble type %s", id);
    Packit 4a16fb
    				return -EINVAL;
    Packit 4a16fb
    			}
    Packit 4a16fb
    			err = snd_config_get_integer(n, &val;;
    Packit 4a16fb
    			if (err < 0) {
    Packit 4a16fb
    				SNDERR("invalid IEC958 preamble value");
    Packit 4a16fb
    				return err;
    Packit 4a16fb
    			}
    Packit 4a16fb
    			preamble_vals[idx] = val;
    Packit 4a16fb
    		}
    Packit 4a16fb
    	}
    Packit 4a16fb
    	if (!slave) {
    Packit 4a16fb
    		SNDERR("slave is not defined");
    Packit 4a16fb
    		return -EINVAL;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	err = snd_pcm_slave_conf(root, slave, &sconf, 1,
    Packit 4a16fb
    				 SND_PCM_HW_PARAM_FORMAT, SCONF_MANDATORY, &sformat);
    Packit 4a16fb
    	if (err < 0)
    Packit 4a16fb
    		return err;
    Packit 4a16fb
    	if (snd_pcm_format_linear(sformat) != 1 &&
    Packit 4a16fb
    	    sformat != SND_PCM_FORMAT_IEC958_SUBFRAME_LE &&
    Packit 4a16fb
    	    sformat != SND_PCM_FORMAT_IEC958_SUBFRAME_BE) {
    Packit 4a16fb
    	    	snd_config_delete(sconf);
    Packit 4a16fb
    		SNDERR("invalid slave format");
    Packit 4a16fb
    		return -EINVAL;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
    Packit 4a16fb
    	snd_config_delete(sconf);
    Packit 4a16fb
    	if (err < 0)
    Packit 4a16fb
    		return err;
    Packit 4a16fb
    	err = snd_pcm_iec958_open(pcmp, name, sformat, spcm, 1,
    Packit 4a16fb
    				  status ? status_bits : NULL,
    Packit 4a16fb
    				  preamble_vals);
    Packit 4a16fb
    	if (err < 0)
    Packit 4a16fb
    		snd_pcm_close(spcm);
    Packit 4a16fb
    	return err;
    Packit 4a16fb
    }
    Packit 4a16fb
    #ifndef DOC_HIDDEN
    Packit 4a16fb
    SND_DLSYM_BUILD_VERSION(_snd_pcm_iec958_open, SND_PCM_DLSYM_VERSION);
    Packit 4a16fb
    #endif