audio_format.c revision 88447a05f537aabe9a1bc3d5313f22581ec992a7
/*
* 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.
*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Purpose: Audio format conversion routines used by audio.c
*/
#include "audio_impl.h"
#include "audio_grc3.h"
/*
* 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;
} else {
}
/*
* At least one of the source or target are S24_NE.
*
* optimized converter. While at it, ensure that a valid
* format is selected.
*/
/* save source frame size */
break;
}
}
"invalid source format selected");
return (EINVAL);
}
break;
}
}
"invalid target format selected");
return (EINVAL);
}
}
/*
* if channels need conversion, then we must use the
* default.
*/
}
/*
* We need SRC; if we can avoid data conversion, do so.
*/
}
/*
* 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) {
}
/*
* Now we need to allocate space.
*/
"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)
}
/*
* NB: From here on, we must not fail.
*/
/*
* Configure default fragment setup.
*/
break;
}
}
/*
* 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++) {
}
}
}