audio_format.c revision 2c30fa4582c5d6c659e059e719c5f6163f7ef1e3
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (C) 4Front Technologies 1996-2008.
*
*/
/*
* Purpose: Audio format conversion routines used by audio.c
*/
#include "audio_impl.h"
#include "audio_grc3.h"
extern uint_t audio_intrhz;
/*
* Note: In the function below, the division by the number of channels is
* probably fairly expensive. It turns out that we usually deal with stereo
* or mono data, so perhaps it would be useful to build custom versions of
* this function that only dealt with stereo or mono.
*/
static int
{
/*
* Note that we presume that we are doing sample rate
* conversions on AUDIO_FORMAT_S24_NE, which means that have 4
* byte and 32-bit samples.
*/
}
}
static void
{
}
}
static int
{
/*
* We must be using 24-bit native signed.
*/
return (len);
}
static int
{
/*
* Endian switch works in both directions. We do it in place.
*/
src++;
}
return (len);
}
static int
{
return (len);
}
static int
{
return (len);
}
static int
{
}
return (len);
}
static int
{
}
return (len);
}
static int
{
return (len);
}
static int
{
return (len);
}
static int
{
return (len);
}
static int
{
return (len);
}
static int
{
/* NB: this is a little endian format */
}
return (len);
}
static int
{
/* 32-bit conversions can be done in place */
return (len);
}
static int
{
/* 32-bit conversions can be done in place */
return (len);
}
/*
* NB: All the destination format conversions use the same or fewer
* bytes as the 24-bit unpacked (32-bits used per sample), so we can
* convert all of them in place.
*/
static int
{
return (len);
}
static int
{
return (len);
}
static int
{
idx >>= 10;
}
return (len);
}
static int
{
idx >>= 11;
}
return (len);
}
static int
{
return (len);
}
static int
{
return (len);
}
static int
{
return (len);
}
static int
{
return (len);
}
static int
{
int32_t d;
/* NB: this is a little endian format */
d = *src++;
*dst++ = d & 0xff;
}
return (len);
}
static int
{
return (len);
}
static int
{
return (len);
}
static int
{
/*
* Note that the formats were already preverified during
* select_converter, to ensure that only supported formats are
* used.
*/
/*
* Convert samples to 24 bit (32 bit lsb aligned) if
* necessary.
*/
switch (sp->s_cnv_src_format) {
case AUDIO_FORMAT_U8:
break;
case AUDIO_FORMAT_S8:
break;
case AUDIO_FORMAT_ULAW:
break;
case AUDIO_FORMAT_ALAW:
break;
case AUDIO_FORMAT_S16_NE:
break;
case AUDIO_FORMAT_S16_OE:
break;
case AUDIO_FORMAT_U16_NE:
break;
case AUDIO_FORMAT_U16_OE:
break;
case AUDIO_FORMAT_S32_NE:
break;
case AUDIO_FORMAT_S32_OE:
break;
case AUDIO_FORMAT_S24_OE:
break;
case AUDIO_FORMAT_S24_PACKED:
break;
}
/*
* If we aren't decreasing the number of channels, then do the
* SRC now. (We prefer to do SRC on the smaller number of channels.)
*/
}
/*
* Convert between mono and stereo
*/
int nc;
int i;
if (sc == 1) {
/*
* Mono expansion. We expand into the stereo
* channel, and leave other channels silent.
*/
for (i = len; i; i--) {
for (int j = tc - 2; j > 0; j--) {
*dst++ = 0;
}
}
/*
* Stereo -> mono. We do stereo separately to make
* the division fast (div by const 2 is just shift).
*/
for (i = len; i; i--) {
/*
* Take just the left channel sample,
* discard the right channel.
*/
src++; /* right */
}
} else {
/*
* Multi channel conversions. We just copy the
* minimum number of channels.
*/
/* Calculate number of frames */
/* Clear destination */
for (i = len; i; i--) {
int c;
for (c = 0; c < nc; c++)
}
}
}
/*
* If we didn't do SRC pre-conversion, then do it now.
*/
}
/*
* Finally convert samples from internal 24 bit format to target format
*/
switch (sp->s_cnv_dst_format) {
case AUDIO_FORMAT_U8:
break;
case AUDIO_FORMAT_S8:
break;
case AUDIO_FORMAT_S16_NE:
break;
case AUDIO_FORMAT_S16_OE:
break;
case AUDIO_FORMAT_U16_NE:
break;
case AUDIO_FORMAT_U16_OE:
break;
case AUDIO_FORMAT_S24_OE:
break;
case AUDIO_FORMAT_S24_PACKED:
break;
case AUDIO_FORMAT_S32_NE:
break;
case AUDIO_FORMAT_S32_OE:
break;
case AUDIO_FORMAT_ULAW:
break;
case AUDIO_FORMAT_ALAW:
break;
}
return (len);
}
static const struct audio_format_info {
unsigned format;
int sampsize;
} audio_format_info[] = {
/* 24-bit formats are "special" */
/* sentinel */
};
int
{
const struct audio_format_info *info;
int expand = AUDIO_UNIT_EXPAND;
unsigned cnv_sampsz = sizeof (uint32_t);
unsigned cnv_max;
if (mask & FORMAT_MSK_FMT)
if (mask & FORMAT_MSK_RATE)
if (mask & FORMAT_MSK_CHAN)
} else {
if (mask & FORMAT_MSK_FMT)
if (mask & FORMAT_MSK_RATE)
if (mask & FORMAT_MSK_CHAN)
}
/*
* At least one of the source or target are S24_NE.
*
* optimized converter. While at it, ensure that a valid
* format is selected.
*
* After this function executes, "info" will point to the
* format information for the user parameters.
*/
/* save source frame size */
break;
}
}
} else {
/*
* Target format. Note that this case is also taken
* if we're operating on S24_NE data. In that case
* the converter will be NULL and expand will not be
* altered.
*/
break;
}
}
}
return (EINVAL);
}
/*
* if channels need conversion, then we must use the
* default.
*/
}
}
/*
* Figure out the size of the conversion buffer we need. We
* assume room for two full source fragments, which ought to
* be enough, even with rounding errors.
*/
/*
* If the conversion will cause us to expand fragments, then
* we need to increase cnv_max. Scale by AUDIO_UNIT_EXPAND to
* avoid rouding errors or losing bits when doing reducing
* conversions.
*/
if (expand > AUDIO_UNIT_EXPAND) {
}
/*
* We need to "tune" the buffer and fragment counts for some
* uses... OSS applications may like to configure a low
* latency, and they rely upon write() to block to prevent too
* much data from being queued up.
*/
} else if (sp->s_hintfrags) {
} else {
}
/*
* Now make sure that the hint works -- we need at least 2 fragments,
* and we need to fit within the room allocated to us.
*/
if (nfrags < 2) {
nfrags = 2;
}
nfrags--;
}
/* if the resulting configuration is invalid, note it */
if (nfrags < 2) {
return (EINVAL);
}
/*
* Now we need to allocate space.
*
* NB: Once the allocation succeeds, we must not fail. We are
* modifying the the stream settings and these changes must be
* made atomically.
*/
"failed to allocate audio conversion buffer "
"(%u bytes)", cnv_max);
if (buf0)
if (buf1)
return (ENOMEM);
}
if (sp->s_cnv_buf0)
if (sp->s_cnv_buf1)
}
/* Set up the SRC state if we will be using SRC. */
if (needsrc) {
}
/*
* Ensure that we toss any stale data -- probably wrong format.
* Note that as a consequence of this, all of the offsets and
* counters get reset. Clients should not rely on these values
* being preserved when changing formats.
*
* Its critical that we reset the indices, in particular,
* because not only will the data be the wrong format, but the
* indices themselves are quite possibly going to be invalid.
*/
return (0);
}
int
{
int i;
for (i = 0; i < AUDIO_MAX_CHANNELS; i++) {
sp->s_src_state[i] =
"unable to allocate SRC state structures");
return (ENOMEM);
}
}
return (0);
}
void
{
int i;
for (i = 0; i < AUDIO_MAX_CHANNELS; i++) {
}
}
}