88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CDDL HEADER START
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * The contents of this file are subject to the terms of the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Common Development and Distribution License (the "License").
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * You may not use this file except in compliance with the License.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * or http://www.opensolaris.org/os/licensing.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * See the License for the specific language governing permissions
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * and limitations under the License.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * If applicable, add the following below this CDDL HEADER, with the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner]
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CDDL HEADER END
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Copyright (C) 4Front Technologies 1996-2008.
2c30fa4582c5d6c659e059e719c5f6163f7ef1e3Garrett D'Amore * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Purpose: Audio format conversion routines used by audio.c
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Note: In the function below, the division by the number of channels is
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * probably fairly expensive. It turns out that we usually deal with stereo
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * or mono data, so perhaps it would be useful to build custom versions of
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * this function that only dealt with stereo or mono.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoredo_src(audio_stream_t *sp, void *p1, void *p2, int len, int nchan)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Note that we presume that we are doing sample rate
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * conversions on AUDIO_FORMAT_S24_NE, which means that have 4
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * byte and 32-bit samples.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore size = sp->s_cnv_max / 4; /* sample size is 4 */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore grc3_convert(sp->s_src_state[ch], sp->s_src_quality,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (((grc3state_t *)sp->s_src_state[0])->outsz);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoresetup_src(audio_stream_t *sp, int srate, int trate, int sch, int tch)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore grc3_setup(sp->s_src_state[ch], srate, trate);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * We must be using 24-bit native signed.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore len = do_src(sp, src, dst, len, sp->s_cnv_src_nchan);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Endian switch works in both directions. We do it in place.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = len * sp->s_cnv_src_nchan; i; i--) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = len * sp->s_cnv_src_nchan; i; i--)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = len * sp->s_cnv_src_nchan; i; i--)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = len * sp->s_cnv_src_nchan; i; i--) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = len * sp->s_cnv_src_nchan; i; i--) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = len * sp->s_cnv_src_nchan; i; i--)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = len * sp->s_cnv_src_nchan; i; i--)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *dst++ = (int16_t)(ddi_swap16(*src++)) << 8;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = len * sp->s_cnv_src_nchan; i; i--)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = len * sp->s_cnv_src_nchan; i; i--)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *dst++ = (int16_t)(ddi_swap16((*src++) ^ 0x8000)) << 8;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = len * sp->s_cnv_src_nchan; i; i--) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* NB: this is a little endian format */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* 32-bit conversions can be done in place */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = len * sp->s_cnv_src_nchan; i; i--, src++)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* 32-bit conversions can be done in place */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = len * sp->s_cnv_src_nchan; i; i--, src++)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * NB: All the destination format conversions use the same or fewer
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * bytes as the 24-bit unpacked (32-bits used per sample), so we can
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * convert all of them in place.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = len * sp->s_cnv_dst_nchan; i; i--)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = len * sp->s_cnv_dst_nchan; i; i--)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = len * sp->s_cnv_dst_nchan; i; i--) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = len * sp->s_cnv_dst_nchan; i; i--) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = len * sp->s_cnv_dst_nchan; i; i--)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = len * sp->s_cnv_dst_nchan; i; i--)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = len * sp->s_cnv_dst_nchan; i; i--)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = len * sp->s_cnv_dst_nchan; i; i--)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = len * sp->s_cnv_dst_nchan; i; i--) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* NB: this is a little endian format */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = len * sp->s_cnv_dst_nchan; i; i--, src++)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = len * sp->s_cnv_dst_nchan; i; i--, src++)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Note that the formats were already preverified during
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * select_converter, to ensure that only supported formats are
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Convert samples to 24 bit (32 bit lsb aligned) if
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * If we aren't decreasing the number of channels, then do the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * SRC now. (We prefer to do SRC on the smaller number of channels.)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (sp->s_cnv_src_rate != sp->s_cnv_dst_rate &&
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore sp->s_cnv_src_nchan <= sp->s_cnv_dst_nchan) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore len = do_src(sp, src, dst, len, sp->s_cnv_src_nchan);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Convert between mono and stereo
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (sp->s_cnv_src_nchan != sp->s_cnv_dst_nchan) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Mono expansion. We expand into the stereo
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * channel, and leave other channels silent.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = len; i; i--) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Stereo -> mono. We do stereo separately to make
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * the division fast (div by const 2 is just shift).
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = len; i; i--) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Take just the left channel sample,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * discard the right channel.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Multi channel conversions. We just copy the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * minimum number of channels.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Calculate number of frames */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Clear destination */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = len; i; i--) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (c = 0; c < nc; c++)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * If we didn't do SRC pre-conversion, then do it now.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (sp->s_cnv_src_rate != sp->s_cnv_dst_rate &&
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore sp->s_cnv_src_nchan > sp->s_cnv_dst_nchan) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore len = do_src(sp, src, dst, len, sp->s_cnv_dst_nchan);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Finally convert samples from internal 24 bit format to target format
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AUDIO_FORMAT_S8, 1, cnv_from_s8, cnv_to_s8 },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AUDIO_FORMAT_U8, 1, cnv_from_u8, cnv_to_u8 },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AUDIO_FORMAT_ULAW, 1, cnv_from_ulaw, cnv_to_ulaw },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AUDIO_FORMAT_ALAW, 1, cnv_from_alaw, cnv_to_alaw },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AUDIO_FORMAT_S16_NE, 2, cnv_from_s16ne, cnv_to_s16ne },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AUDIO_FORMAT_S16_OE, 2, cnv_from_s16oe, cnv_to_s16oe },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AUDIO_FORMAT_U16_NE, 2, cnv_from_u16ne, cnv_to_u16ne },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AUDIO_FORMAT_U16_OE, 2, cnv_from_u16oe, cnv_to_u16oe },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AUDIO_FORMAT_S32_NE, 4, cnv_from_s32ne, cnv_to_s32ne },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AUDIO_FORMAT_S32_OE, 4, cnv_from_s32oe, cnv_to_s32oe },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* 24-bit formats are "special" */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AUDIO_FORMAT_S24_OE, 4, cnv_s24oe, cnv_s24oe },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AUDIO_FORMAT_S24_PACKED, 3, cnv_from_s24p, cnv_to_s24p },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* sentinel */
2c30fa4582c5d6c659e059e719c5f6163f7ef1e3Garrett D'Amoreauimpl_format_setup(audio_stream_t *sp, audio_parms_t *parms, uint_t mask)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * At least one of the source or target are S24_NE.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * If we have a signed/native endian format, then pick an
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * optimized converter. While at it, ensure that a valid
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * format is selected.
2c30fa4582c5d6c659e059e719c5f6163f7ef1e3Garrett D'Amore * After this function executes, "info" will point to the
2c30fa4582c5d6c659e059e719c5f6163f7ef1e3Garrett D'Amore * format information for the user parameters.
2c30fa4582c5d6c659e059e719c5f6163f7ef1e3Garrett D'Amore if (source.p_format != AUDIO_FORMAT_S24_NE) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (info = &audio_format_info[0]; info->sampsize; info++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* save source frame size */
2c30fa4582c5d6c659e059e719c5f6163f7ef1e3Garrett D'Amore * Target format. Note that this case is also taken
2c30fa4582c5d6c659e059e719c5f6163f7ef1e3Garrett D'Amore * if we're operating on S24_NE data. In that case
2c30fa4582c5d6c659e059e719c5f6163f7ef1e3Garrett D'Amore * the converter will be NULL and expand will not be
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (info = &audio_format_info[0]; info->sampsize; info++) {
2c30fa4582c5d6c659e059e719c5f6163f7ef1e3Garrett D'Amore audio_dev_warn(sp->s_client->c_dev, "invalid format selected");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * if channels need conversion, then we must use the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore converter = (converter == NULL) ? cnv_srconly : cnv_default;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Figure out the size of the conversion buffer we need. We
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * assume room for two full source fragments, which ought to
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * be enough, even with rounding errors.
2c30fa4582c5d6c659e059e719c5f6163f7ef1e3Garrett D'Amore cnv_max = 2 * (source.p_rate / audio_intrhz) *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * If the conversion will cause us to expand fragments, then
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * we need to increase cnv_max. Scale by AUDIO_UNIT_EXPAND to
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * avoid rouding errors or losing bits when doing reducing
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * conversions.
2c30fa4582c5d6c659e059e719c5f6163f7ef1e3Garrett D'Amore * We need to "tune" the buffer and fragment counts for some
2c30fa4582c5d6c659e059e719c5f6163f7ef1e3Garrett D'Amore * uses... OSS applications may like to configure a low
2c30fa4582c5d6c659e059e719c5f6163f7ef1e3Garrett D'Amore * latency, and they rely upon write() to block to prevent too
2c30fa4582c5d6c659e059e719c5f6163f7ef1e3Garrett D'Amore * much data from being queued up.
2c30fa4582c5d6c659e059e719c5f6163f7ef1e3Garrett D'Amore * Now make sure that the hint works -- we need at least 2 fragments,
2c30fa4582c5d6c659e059e719c5f6163f7ef1e3Garrett D'Amore * and we need to fit within the room allocated to us.
2c30fa4582c5d6c659e059e719c5f6163f7ef1e3Garrett D'Amore while ((nfrags * fragbytes) > sp->s_allocsz) {
2c30fa4582c5d6c659e059e719c5f6163f7ef1e3Garrett D'Amore /* if the resulting configuration is invalid, note it */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Now we need to allocate space.
2c30fa4582c5d6c659e059e719c5f6163f7ef1e3Garrett D'Amore * NB: Once the allocation succeeds, we must not fail. We are
2c30fa4582c5d6c659e059e719c5f6163f7ef1e3Garrett D'Amore * modifying the the stream settings and these changes must be
2c30fa4582c5d6c659e059e719c5f6163f7ef1e3Garrett D'Amore * made atomically.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "failed to allocate audio conversion buffer "
2c30fa4582c5d6c659e059e719c5f6163f7ef1e3Garrett D'Amore /* Set up the SRC state if we will be using SRC. */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Ensure that we toss any stale data -- probably wrong format.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Note that as a consequence of this, all of the offsets and
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * counters get reset. Clients should not rely on these values
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * being preserved when changing formats.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Its critical that we reset the indices, in particular,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * because not only will the data be the wrong format, but the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * indices themselves are quite possibly going to be invalid.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = 0; i < AUDIO_MAX_CHANNELS; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore kmem_zalloc(sizeof (grc3state_t), KM_NOSLEEP);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "unable to allocate SRC state structures");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = 0; i < AUDIO_MAX_CHANNELS; i++) {