Signed-off-by: hmz007 <hmz007@gmail.com> Change-Id: Ib87fdbe7a0be7dc961af3500fe9ea4589a127f9f
246 lines
9.3 KiB
C++
246 lines
9.3 KiB
C++
/*
|
|
* Copyright (C) 2015 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "sles_allinclusive.h"
|
|
#include <cutils/bitops.h>
|
|
#include <system/audio.h>
|
|
#include <SLES/OpenSLES_Android.h>
|
|
#include "channels.h"
|
|
|
|
|
|
/*
|
|
* Return the default OpenSL ES output channel mask (as used in SLDataFormat_PCM.channelMask)
|
|
* for the specified channel count.
|
|
*
|
|
* OpenSL ES makes no distinction between input and output channel masks, but
|
|
* Android does. This is the OUTPUT version of this function.
|
|
*/
|
|
SLuint32 sles_channel_out_mask_from_count(unsigned channelCount)
|
|
{
|
|
// FIXME channel mask is not yet implemented by Stagefright, so use a reasonable default
|
|
// that is computed from the channel count
|
|
if (channelCount > FCC_8) {
|
|
return SL_ANDROID_UNKNOWN_CHANNELMASK;
|
|
}
|
|
switch (channelCount) {
|
|
case 1:
|
|
// see explanation in data.c re: default channel mask for mono
|
|
return SL_SPEAKER_FRONT_LEFT;
|
|
case 2:
|
|
return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
|
|
// Android-specific
|
|
case 3:
|
|
return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_FRONT_CENTER;
|
|
case 4:
|
|
return SL_ANDROID_SPEAKER_QUAD;
|
|
case 5:
|
|
return SL_ANDROID_SPEAKER_QUAD | SL_SPEAKER_FRONT_CENTER;
|
|
case 6:
|
|
return SL_ANDROID_SPEAKER_5DOT1;
|
|
case 7:
|
|
return SL_ANDROID_SPEAKER_5DOT1 | SL_SPEAKER_BACK_CENTER;
|
|
case 8:
|
|
return SL_ANDROID_SPEAKER_7DOT1;
|
|
// FIXME FCC_8
|
|
default:
|
|
return SL_ANDROID_UNKNOWN_CHANNELMASK;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Return the default OpenSL ES input channel mask (as used in SLDataFormat_PCM.channelMask)
|
|
* for the specified channel count.
|
|
*
|
|
* OpenSL ES makes no distinction between input and output channel masks, but
|
|
* Android does. This is the INPUT version of this function.
|
|
*/
|
|
SLuint32 sles_channel_in_mask_from_count(unsigned channelCount) {
|
|
switch (channelCount) {
|
|
case 1:
|
|
return SL_SPEAKER_FRONT_LEFT;
|
|
case 2:
|
|
return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
|
|
default: {
|
|
if (channelCount > AUDIO_CHANNEL_COUNT_MAX) {
|
|
return SL_ANDROID_UNKNOWN_CHANNELMASK;
|
|
} else {
|
|
SLuint32 bitfield = (1 << channelCount) - 1;
|
|
return SL_ANDROID_MAKE_INDEXED_CHANNEL_MASK(bitfield);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Get the number of active channels in an OpenSL ES channel mask.
|
|
*
|
|
* This function is valid for both input and output
|
|
* masks.
|
|
*/
|
|
SLuint32 sles_channel_count_from_mask(SLuint32 mask) {
|
|
audio_channel_representation_t rep
|
|
= sles_to_audio_channel_mask_representation(mask);
|
|
|
|
if (rep == AUDIO_CHANNEL_REPRESENTATION_INDEX) {
|
|
mask &= SL_ANDROID_INDEXED_SPEAKER_MASK_ALL;
|
|
return popcount(mask);
|
|
} else if (rep == AUDIO_CHANNEL_REPRESENTATION_POSITION){
|
|
mask &= SL_ANDROID_POSITIONAL_SPEAKER_MASK_ALL;
|
|
return popcount(mask);
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Helper to determine whether a channel mask is indexed or not.
|
|
*
|
|
* This is the OpenSL ES analog to audio_channel_mask_get_representation().
|
|
*/
|
|
audio_channel_representation_t sles_to_audio_channel_mask_representation(SLuint32 mask) {
|
|
if (mask & SL_ANDROID_SPEAKER_NON_POSITIONAL) {
|
|
return AUDIO_CHANNEL_REPRESENTATION_INDEX;
|
|
} else {
|
|
return AUDIO_CHANNEL_REPRESENTATION_POSITION;
|
|
}
|
|
}
|
|
|
|
// helper struct for the two static arrays which follow.
|
|
struct channel_map {
|
|
SLuint32 sles;
|
|
audio_channel_mask_t android;
|
|
};
|
|
|
|
// In practice this map is unnecessary, because the SL definitions just
|
|
// happen to match the android definitions perfectly, but we can't rely
|
|
// on that fact since the two sets of definitions have different API
|
|
// contracts.
|
|
static const struct channel_map output_map[] = {
|
|
{ SL_SPEAKER_FRONT_LEFT, AUDIO_CHANNEL_OUT_FRONT_LEFT },
|
|
{ SL_SPEAKER_FRONT_RIGHT, AUDIO_CHANNEL_OUT_FRONT_RIGHT },
|
|
{ SL_SPEAKER_FRONT_CENTER, AUDIO_CHANNEL_OUT_FRONT_CENTER },
|
|
{ SL_SPEAKER_LOW_FREQUENCY, AUDIO_CHANNEL_OUT_LOW_FREQUENCY },
|
|
{ SL_SPEAKER_BACK_LEFT, AUDIO_CHANNEL_OUT_BACK_LEFT },
|
|
{ SL_SPEAKER_BACK_RIGHT, AUDIO_CHANNEL_OUT_BACK_RIGHT },
|
|
{ SL_SPEAKER_FRONT_LEFT_OF_CENTER, AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER },
|
|
{ SL_SPEAKER_FRONT_RIGHT_OF_CENTER, AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER },
|
|
{ SL_SPEAKER_BACK_CENTER, AUDIO_CHANNEL_OUT_BACK_CENTER },
|
|
{ SL_SPEAKER_SIDE_LEFT, AUDIO_CHANNEL_OUT_SIDE_LEFT },
|
|
{ SL_SPEAKER_SIDE_RIGHT, AUDIO_CHANNEL_OUT_SIDE_RIGHT },
|
|
{ SL_SPEAKER_TOP_CENTER, AUDIO_CHANNEL_OUT_TOP_CENTER },
|
|
{ SL_SPEAKER_TOP_FRONT_LEFT, AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT },
|
|
{ SL_SPEAKER_TOP_FRONT_CENTER, AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER },
|
|
{ SL_SPEAKER_TOP_FRONT_RIGHT, AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT },
|
|
{ SL_SPEAKER_TOP_BACK_LEFT, AUDIO_CHANNEL_OUT_TOP_BACK_LEFT },
|
|
{ SL_SPEAKER_TOP_BACK_CENTER, AUDIO_CHANNEL_OUT_TOP_BACK_CENTER },
|
|
{ SL_SPEAKER_TOP_BACK_RIGHT, AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT },
|
|
};
|
|
static const unsigned int nOutputChannelMappings = sizeof(output_map) / sizeof(output_map[0]);
|
|
|
|
// This map is quite sparse, because there really isn't a reasonable mapping
|
|
// between most of the SL_SPEAKER bits and the android input map. It's probably
|
|
// best to use channel indices instead.
|
|
static const struct channel_map input_map[] = {
|
|
{ SL_SPEAKER_FRONT_LEFT, AUDIO_CHANNEL_IN_LEFT },
|
|
{ SL_SPEAKER_FRONT_RIGHT, AUDIO_CHANNEL_IN_RIGHT },
|
|
};
|
|
static const unsigned int nInputChannelMappings = sizeof(input_map) / sizeof(input_map[0]);
|
|
|
|
// Core channel mask mapper; implementation common to both input and output
|
|
static audio_channel_mask_t sles_to_android_mask_helper(
|
|
SLuint32 mask,
|
|
const struct channel_map* map,
|
|
unsigned int nMappings) {
|
|
if (!sles_is_channel_mask_valid(mask)) {
|
|
SL_LOGW("Channel mask %#x is invalid because it uses bits that are undefined.", mask);
|
|
return AUDIO_CHANNEL_INVALID;
|
|
}
|
|
|
|
// determine whether this mask uses positional or indexed representation
|
|
audio_channel_representation_t rep = sles_to_audio_channel_mask_representation(mask);
|
|
|
|
uint32_t bitsOut = 0;
|
|
uint32_t bitsIn = mask;
|
|
if (rep == AUDIO_CHANNEL_REPRESENTATION_INDEX) {
|
|
// Indexed masks need no mapping
|
|
bitsIn &= SL_ANDROID_INDEXED_SPEAKER_MASK_ALL;
|
|
bitsOut = bitsIn;
|
|
} else if (rep == AUDIO_CHANNEL_REPRESENTATION_POSITION){
|
|
// positional masks get mapped from OpenSLES speaker definitions
|
|
// to the channel definitions we use internally.
|
|
bitsIn &= SL_ANDROID_POSITIONAL_SPEAKER_MASK_ALL;
|
|
for (unsigned int i = 0; i < nMappings; ++i) {
|
|
if (bitsIn & map[i].sles) {
|
|
bitsOut |= map[i].android;
|
|
}
|
|
}
|
|
} else {
|
|
SL_LOGE("Unrecognized channel representation %#x", rep);
|
|
}
|
|
|
|
audio_channel_mask_t result = audio_channel_mask_from_representation_and_bits(
|
|
rep,
|
|
bitsOut);
|
|
|
|
if (popcount(bitsIn) != popcount(bitsOut)) {
|
|
// At this point mask has already been stripped of the
|
|
// representation bitsOut, so its bitcount should equal the number
|
|
// of channels requested. If the bitcount of 'bitsOut' isn't
|
|
// the same, then we're unable to provide the number of
|
|
// channels that the app requested. That will cause an
|
|
// error downstream if the app doesn't correct it, so
|
|
// issue a warning here.
|
|
SL_LOGW("Conversion from OpenSL ES %s channel mask %#x to Android mask %#x %s channels",
|
|
(rep == AUDIO_CHANNEL_REPRESENTATION_POSITION) ? "positional" : "indexed",
|
|
mask,
|
|
result,
|
|
(popcount(bitsIn) < popcount(bitsOut)) ? "gains" : "loses");
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Return an android output channel mask, as used in the AudioTrack constructor.
|
|
*/
|
|
audio_channel_mask_t sles_to_audio_output_channel_mask(SLuint32 mask) {
|
|
return sles_to_android_mask_helper(mask, output_map, nOutputChannelMappings);
|
|
}
|
|
|
|
/*
|
|
* Return an android input channel mask, as used in the AudioRecord constructor.
|
|
*/
|
|
audio_channel_mask_t sles_to_audio_input_channel_mask(SLuint32 mask) {
|
|
return sles_to_android_mask_helper(mask, input_map, nInputChannelMappings);
|
|
}
|
|
|
|
/*
|
|
* Check the mask for undefined bits (that is, set bits that don't correspond to a channel).
|
|
*
|
|
* Returns SL_BOOLEAN_TRUE if no undefined bits are set; SL_BOOLEAN_FALSE otherwise.
|
|
*/
|
|
SLboolean sles_is_channel_mask_valid(SLuint32 mask) {
|
|
SLuint32 undefinedMask;
|
|
if (sles_to_audio_channel_mask_representation(mask) == AUDIO_CHANNEL_REPRESENTATION_POSITION) {
|
|
undefinedMask = ~SL_ANDROID_POSITIONAL_SPEAKER_MASK_ALL;
|
|
} else {
|
|
undefinedMask
|
|
= ~(SL_ANDROID_MAKE_INDEXED_CHANNEL_MASK(SL_ANDROID_INDEXED_SPEAKER_MASK_ALL));
|
|
}
|
|
return (mask & undefinedMask) ? SL_BOOLEAN_FALSE : SL_BOOLEAN_TRUE;
|
|
}
|