Add channel index mask to AudioTrack and AudioFormat
Change-Id: Ia5faa56360edcbbdeae8838ec0f82386f4e5e640
This commit is contained in:
@@ -14406,6 +14406,8 @@ package android.media {
|
||||
}
|
||||
|
||||
public class AudioFormat {
|
||||
method public int getChannelCount();
|
||||
method public int getChannelIndexMask();
|
||||
method public int getChannelMask();
|
||||
method public int getEncoding();
|
||||
method public int getSampleRate();
|
||||
@@ -14464,7 +14466,8 @@ package android.media {
|
||||
ctor public AudioFormat.Builder();
|
||||
ctor public AudioFormat.Builder(android.media.AudioFormat);
|
||||
method public android.media.AudioFormat build();
|
||||
method public android.media.AudioFormat.Builder setChannelMask(int);
|
||||
method public android.media.AudioFormat.Builder setChannelIndexMask(int) throws java.lang.IllegalArgumentException;
|
||||
method public android.media.AudioFormat.Builder setChannelMask(int) throws java.lang.IllegalArgumentException;
|
||||
method public android.media.AudioFormat.Builder setEncoding(int) throws java.lang.IllegalArgumentException;
|
||||
method public android.media.AudioFormat.Builder setSampleRate(int) throws java.lang.IllegalArgumentException;
|
||||
}
|
||||
|
||||
@@ -15603,6 +15603,8 @@ package android.media {
|
||||
}
|
||||
|
||||
public class AudioFormat {
|
||||
method public int getChannelCount();
|
||||
method public int getChannelIndexMask();
|
||||
method public int getChannelMask();
|
||||
method public int getEncoding();
|
||||
method public int getSampleRate();
|
||||
@@ -15661,7 +15663,8 @@ package android.media {
|
||||
ctor public AudioFormat.Builder();
|
||||
ctor public AudioFormat.Builder(android.media.AudioFormat);
|
||||
method public android.media.AudioFormat build();
|
||||
method public android.media.AudioFormat.Builder setChannelMask(int);
|
||||
method public android.media.AudioFormat.Builder setChannelIndexMask(int) throws java.lang.IllegalArgumentException;
|
||||
method public android.media.AudioFormat.Builder setChannelMask(int) throws java.lang.IllegalArgumentException;
|
||||
method public android.media.AudioFormat.Builder setEncoding(int) throws java.lang.IllegalArgumentException;
|
||||
method public android.media.AudioFormat.Builder setSampleRate(int) throws java.lang.IllegalArgumentException;
|
||||
}
|
||||
|
||||
@@ -890,7 +890,7 @@ int register_android_hardware_SoundTrigger(JNIEnv *env)
|
||||
|
||||
jclass audioFormatClass = FindClassOrDie(env, kAudioFormatClassPathName);
|
||||
gAudioFormatClass = MakeGlobalRefOrDie(env, audioFormatClass);
|
||||
gAudioFormatCstor = GetMethodIDOrDie(env, audioFormatClass, "<init>", "(III)V");
|
||||
gAudioFormatCstor = GetMethodIDOrDie(env, audioFormatClass, "<init>", "(IIII)V");
|
||||
|
||||
jclass soundModelEventClass = FindClassOrDie(env, kSoundModelEventClassPathName);
|
||||
gSoundModelEventClass = MakeGlobalRefOrDie(env, soundModelEventClass);
|
||||
|
||||
@@ -204,9 +204,14 @@ android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this,
|
||||
return (jint) AUDIO_JAVA_ERROR;
|
||||
}
|
||||
|
||||
// Java channel masks don't map directly to the native definition, but it's a simple shift
|
||||
// to skip the two deprecated channel configurations "default" and "mono".
|
||||
audio_channel_mask_t nativeChannelMask = ((uint32_t)javaChannelMask) >> 2;
|
||||
// Java channel masks don't map directly to the native definition for positional
|
||||
// channel masks: it's a shift by 2 to skip the two deprecated channel
|
||||
// configurations "default" and "mono".
|
||||
// Invalid channel representations are caught by !audio_is_output_channel() below.
|
||||
audio_channel_mask_t nativeChannelMask =
|
||||
audio_channel_mask_get_representation(javaChannelMask)
|
||||
== AUDIO_CHANNEL_REPRESENTATION_POSITION
|
||||
? javaChannelMask >> 2 : javaChannelMask;
|
||||
|
||||
if (!audio_is_output_channel(nativeChannelMask)) {
|
||||
ALOGE("Error creating AudioTrack: invalid channel mask %#x.", javaChannelMask);
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package android.media;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@@ -286,13 +286,15 @@ public class AudioFormat {
|
||||
*/
|
||||
// Update sound trigger JNI in core/jni/android_hardware_SoundTrigger.cpp when modifying this
|
||||
// constructor
|
||||
private AudioFormat(int encoding, int sampleRate, int channelMask) {
|
||||
private AudioFormat(int encoding, int sampleRate, int channelMask, int channelIndexMask) {
|
||||
mEncoding = encoding;
|
||||
mSampleRate = sampleRate;
|
||||
mChannelMask = channelMask;
|
||||
mChannelIndexMask = channelIndexMask;
|
||||
mPropertySetMask = AUDIO_FORMAT_HAS_PROPERTY_ENCODING |
|
||||
AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE |
|
||||
AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_MASK;
|
||||
AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_MASK |
|
||||
AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_INDEX_MASK;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@@ -303,10 +305,13 @@ public class AudioFormat {
|
||||
public final static int AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE = 0x1 << 1;
|
||||
/** @hide */
|
||||
public final static int AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_MASK = 0x1 << 2;
|
||||
/** @hide */
|
||||
public final static int AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_INDEX_MASK = 0x1 << 3;
|
||||
|
||||
private int mEncoding;
|
||||
private int mSampleRate;
|
||||
private int mChannelMask;
|
||||
private int mChannelIndexMask;
|
||||
private int mPropertySetMask;
|
||||
|
||||
/**
|
||||
@@ -345,6 +350,34 @@ public class AudioFormat {
|
||||
return mChannelMask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the channel index mask.
|
||||
* @return one of the values that can be set in {@link Builder#setChannelIndexMask(int)} or
|
||||
* {@link AudioFormat#CHANNEL_INVALID} if not set or an invalid mask was used.
|
||||
*/
|
||||
public int getChannelIndexMask() {
|
||||
if ((mPropertySetMask & AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_INDEX_MASK) == 0) {
|
||||
return CHANNEL_INVALID;
|
||||
}
|
||||
return mChannelIndexMask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the channel count.
|
||||
* @return the channel count derived from the channel position mask or the channel index mask.
|
||||
* Zero is returned if both the channel position mask and the channel index mask are not set.
|
||||
*/
|
||||
public int getChannelCount() {
|
||||
final int channelIndexCount = Integer.bitCount(getChannelIndexMask());
|
||||
int channelCount = channelCountFromOutChannelMask(getChannelMask());
|
||||
if (channelCount == 0) {
|
||||
channelCount = channelIndexCount;
|
||||
} else if (channelCount != channelIndexCount && channelIndexCount != 0) {
|
||||
channelCount = 0; // position and index channel count mismatch
|
||||
}
|
||||
return channelCount;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public int getPropertySetMask() {
|
||||
return mPropertySetMask;
|
||||
@@ -368,6 +401,7 @@ public class AudioFormat {
|
||||
private int mEncoding = ENCODING_INVALID;
|
||||
private int mSampleRate = 0;
|
||||
private int mChannelMask = CHANNEL_INVALID;
|
||||
private int mChannelIndexMask = 0;
|
||||
private int mPropertySetMask = AUDIO_FORMAT_HAS_PROPERTY_NONE;
|
||||
|
||||
/**
|
||||
@@ -384,6 +418,7 @@ public class AudioFormat {
|
||||
mEncoding = af.mEncoding;
|
||||
mSampleRate = af.mSampleRate;
|
||||
mChannelMask = af.mChannelMask;
|
||||
mChannelIndexMask = af.mChannelIndexMask;
|
||||
mPropertySetMask = af.mPropertySetMask;
|
||||
}
|
||||
|
||||
@@ -397,6 +432,7 @@ public class AudioFormat {
|
||||
af.mEncoding = mEncoding;
|
||||
af.mSampleRate = mSampleRate;
|
||||
af.mChannelMask = mChannelMask;
|
||||
af.mChannelIndexMask = mChannelIndexMask;
|
||||
af.mPropertySetMask = mPropertySetMask;
|
||||
return af;
|
||||
}
|
||||
@@ -437,28 +473,103 @@ public class AudioFormat {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the channel mask.
|
||||
* Sets the channel position mask.
|
||||
* The channel position mask specifies the association between audio samples in a frame
|
||||
* with named endpoint channels. The samples in the frame correspond to the
|
||||
* named set bits in the channel position mask, in ascending bit order.
|
||||
* See {@link #setChannelIndexMask(int)} to specify channels
|
||||
* based on endpoint numbered channels.
|
||||
* @param channelMask describes the configuration of the audio channels.
|
||||
* <p>For output, the mask should be a combination of
|
||||
* <p> For output, the channelMask can be an OR-ed combination of
|
||||
* channel position masks, e.g.
|
||||
* {@link AudioFormat#CHANNEL_OUT_FRONT_LEFT},
|
||||
* {@link AudioFormat#CHANNEL_OUT_FRONT_CENTER},
|
||||
* {@link AudioFormat#CHANNEL_OUT_FRONT_RIGHT},
|
||||
* {@link AudioFormat#CHANNEL_OUT_SIDE_LEFT},
|
||||
* {@link AudioFormat#CHANNEL_OUT_SIDE_RIGHT},
|
||||
* {@link AudioFormat#CHANNEL_OUT_FRONT_CENTER},
|
||||
* {@link AudioFormat#CHANNEL_OUT_LOW_FREQUENCY}
|
||||
* {@link AudioFormat#CHANNEL_OUT_BACK_LEFT},
|
||||
* {@link AudioFormat#CHANNEL_OUT_BACK_RIGHT}.
|
||||
* <p>for input, the mask should be {@link AudioFormat#CHANNEL_IN_MONO} or
|
||||
* {@link AudioFormat#CHANNEL_OUT_BACK_RIGHT},
|
||||
* {@link AudioFormat#CHANNEL_OUT_BACK_CENTER},
|
||||
* {@link AudioFormat#CHANNEL_OUT_SIDE_LEFT},
|
||||
* {@link AudioFormat#CHANNEL_OUT_SIDE_RIGHT}.
|
||||
* <p> For a valid {@link AudioTrack} channel position mask,
|
||||
* the following conditions apply:
|
||||
* <br> (1) at most eight channel positions may be used;
|
||||
* <br> (2) right/left pairs should be matched.
|
||||
* <p> For input or {@link AudioRecord}, the mask should be
|
||||
* {@link AudioFormat#CHANNEL_IN_MONO} or
|
||||
* {@link AudioFormat#CHANNEL_IN_STEREO}. {@link AudioFormat#CHANNEL_IN_MONO} is
|
||||
* guaranteed to work on all devices.
|
||||
* @return the same Builder instance.
|
||||
* @return the same <code>Builder</code> instance.
|
||||
* @throws IllegalArgumentException if the channel mask is invalid or
|
||||
* if both channel index mask and channel position mask
|
||||
* are specified but do not have the same channel count.
|
||||
*/
|
||||
public Builder setChannelMask(int channelMask) {
|
||||
// only validated when used, with input or output context
|
||||
public @NonNull Builder setChannelMask(int channelMask) throws IllegalArgumentException {
|
||||
if (channelMask == 0) {
|
||||
throw new IllegalArgumentException("Invalid zero channel mask");
|
||||
} else if (/* channelMask != 0 && */ mChannelIndexMask != 0 &&
|
||||
Integer.bitCount(channelMask) != Integer.bitCount(mChannelIndexMask)) {
|
||||
throw new IllegalArgumentException("Mismatched channel count for mask " +
|
||||
Integer.toHexString(channelMask).toUpperCase());
|
||||
}
|
||||
mChannelMask = channelMask;
|
||||
mPropertySetMask |= AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_MASK;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the channel index mask.
|
||||
* A channel index mask specifies the association of audio samples in the frame
|
||||
* with numbered endpoint channels. The i-th bit in the channel index
|
||||
* mask corresponds to the i-th endpoint channel.
|
||||
* For example, an endpoint with four channels is represented
|
||||
* as index mask bits 0 through 3.
|
||||
* See {@link #setChannelMask(int)} for a positional mask interpretation.
|
||||
* <p> Both {@link AudioTrack} and {@link AudioRecord} support
|
||||
* a channel index mask.
|
||||
* If a channel index mask is specified it is used,
|
||||
* otherwise the channel position mask specified
|
||||
* by <code>setChannelMask</code> is used.
|
||||
* For <code>AudioTrack</code> and <code>AudioRecord</code>,
|
||||
* a channel position mask is not required if a channel index mask is specified.
|
||||
*
|
||||
* @param channelIndexMask describes the configuration of the audio channels.
|
||||
* <p> For output, the <code>channelIndexMask</code> is an OR-ed combination of
|
||||
* bits representing the mapping of <code>AudioTrack</code> write samples
|
||||
* to output sink channels.
|
||||
* For example, a mask of <code>0xa</code>, or binary <code>1010</code>,
|
||||
* means the <code>AudioTrack</code> write frame consists of two samples,
|
||||
* which are routed to the second and the fourth channels of the output sink.
|
||||
* Unmatched output sink channels are zero filled and unmatched
|
||||
* <code>AudioTrack</code> write samples are dropped.
|
||||
* <p> For input, the <code>channelIndexMask</code> is an OR-ed combination of
|
||||
* bits representing the mapping of input source channels to
|
||||
* <code>AudioRecord</code> read samples.
|
||||
* For example, a mask of <code>0x5</code>, or binary
|
||||
* <code>101</code>, will read from the first and third channel of the input
|
||||
* source device and store them in the first and second sample of the
|
||||
* <code>AudioRecord</code> read frame.
|
||||
* Unmatched input source channels are dropped and
|
||||
* unmatched <code>AudioRecord</code> read samples are zero filled.
|
||||
* @return the same <code>Builder</code> instance.
|
||||
* @throws IllegalArgumentException if the channel index mask is invalid or
|
||||
* if both channel index mask and channel position mask
|
||||
* are specified but do not have the same channel count.
|
||||
*/
|
||||
public @NonNull Builder setChannelIndexMask(int channelIndexMask)
|
||||
throws IllegalArgumentException {
|
||||
if (channelIndexMask == 0) {
|
||||
throw new IllegalArgumentException("Invalid zero channel index mask");
|
||||
} else if (/* channelIndexMask != 0 && */ mChannelMask != 0 &&
|
||||
Integer.bitCount(channelIndexMask) != Integer.bitCount(mChannelMask)) {
|
||||
throw new IllegalArgumentException("Mismatched channel count for index mask " +
|
||||
Integer.toHexString(channelIndexMask).toUpperCase());
|
||||
}
|
||||
mChannelIndexMask = channelIndexMask;
|
||||
mPropertySetMask |= AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_INDEX_MASK;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the sample rate.
|
||||
* @param sampleRate the sample rate expressed in Hz
|
||||
@@ -480,7 +591,8 @@ public class AudioFormat {
|
||||
return new String("AudioFormat:"
|
||||
+ " props=" + mPropertySetMask
|
||||
+ " enc=" + mEncoding
|
||||
+ " chan=0x" + Integer.toHexString(mChannelMask)
|
||||
+ " chan=0x" + Integer.toHexString(mChannelMask).toUpperCase()
|
||||
+ " chan_index=0x" + Integer.toHexString(mChannelIndexMask).toUpperCase()
|
||||
+ " rate=" + mSampleRate);
|
||||
}
|
||||
|
||||
|
||||
@@ -234,7 +234,7 @@ public class AudioTrack
|
||||
*/
|
||||
private int mChannelCount = 1;
|
||||
/**
|
||||
* The audio channel mask.
|
||||
* The audio channel mask used for calling native AudioTrack
|
||||
*/
|
||||
private int mChannels = AudioFormat.CHANNEL_OUT_MONO;
|
||||
|
||||
@@ -253,9 +253,15 @@ public class AudioTrack
|
||||
*/
|
||||
private int mDataLoadMode = MODE_STREAM;
|
||||
/**
|
||||
* The current audio channel configuration.
|
||||
* The current channel position mask, as specified on AudioTrack creation.
|
||||
* Can be set simultaneously with channel index mask {@link #mChannelIndexMask}.
|
||||
* May be set to {@link AudioFormat#CHANNEL_INVALID} if a channel index mask is specified.
|
||||
*/
|
||||
private int mChannelConfiguration = AudioFormat.CHANNEL_OUT_MONO;
|
||||
/**
|
||||
* The current audio channel index configuration (if specified).
|
||||
*/
|
||||
private int mChannelIndexMask = 0;
|
||||
/**
|
||||
* The encoding of the audio samples.
|
||||
* @see AudioFormat#ENCODING_PCM_8BIT
|
||||
@@ -424,16 +430,24 @@ public class AudioTrack
|
||||
rate = 44100;
|
||||
}
|
||||
}
|
||||
int channelMask = AudioFormat.CHANNEL_OUT_FRONT_LEFT | AudioFormat.CHANNEL_OUT_FRONT_RIGHT;
|
||||
if ((format.getPropertySetMask() & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_MASK) != 0)
|
||||
{
|
||||
int channelIndexMask = 0;
|
||||
if ((format.getPropertySetMask()
|
||||
& AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_INDEX_MASK) != 0) {
|
||||
channelIndexMask = format.getChannelIndexMask();
|
||||
}
|
||||
int channelMask = 0;
|
||||
if ((format.getPropertySetMask()
|
||||
& AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_MASK) != 0) {
|
||||
channelMask = format.getChannelMask();
|
||||
} else if (channelIndexMask == 0) { // if no masks at all, use stereo
|
||||
channelMask = AudioFormat.CHANNEL_OUT_FRONT_LEFT
|
||||
| AudioFormat.CHANNEL_OUT_FRONT_RIGHT;
|
||||
}
|
||||
int encoding = AudioFormat.ENCODING_DEFAULT;
|
||||
if ((format.getPropertySetMask() & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_ENCODING) != 0) {
|
||||
encoding = format.getEncoding();
|
||||
}
|
||||
audioParamCheck(rate, channelMask, encoding, mode);
|
||||
audioParamCheck(rate, channelMask, channelIndexMask, encoding, mode);
|
||||
mStreamType = AudioSystem.STREAM_DEFAULT;
|
||||
|
||||
audioBuffSizeCheck(bufferSizeInBytes);
|
||||
@@ -653,6 +667,48 @@ public class AudioTrack
|
||||
AudioFormat.CHANNEL_OUT_SIDE_LEFT |
|
||||
AudioFormat.CHANNEL_OUT_SIDE_RIGHT;
|
||||
|
||||
// Java channel mask definitions below match those
|
||||
// in /system/core/include/system/audio.h in the JNI code of AudioTrack.
|
||||
|
||||
// internal maximum size for bits parameter, not part of public API
|
||||
private static final int AUDIO_CHANNEL_BITS_LOG2 = 30;
|
||||
|
||||
// log(2) of maximum number of representations, not part of public API
|
||||
private static final int AUDIO_CHANNEL_REPRESENTATION_LOG2 = 2;
|
||||
|
||||
// used to create a channel index mask or channel position mask
|
||||
// with getChannelMaskFromRepresentationAndBits();
|
||||
private static final int CHANNEL_OUT_REPRESENTATION_POSITION = 0;
|
||||
private static final int CHANNEL_OUT_REPRESENTATION_INDEX = 2;
|
||||
|
||||
/**
|
||||
* Return the channel mask from its representation and bits.
|
||||
*
|
||||
* This creates a channel mask for mChannels which combines a
|
||||
* representation field and a bits field. This is for internal
|
||||
* communication to native code, not part of the public API.
|
||||
*
|
||||
* @param representation the type of channel mask,
|
||||
* either CHANNEL_OUT_REPRESENTATION_POSITION
|
||||
* or CHANNEL_OUT_REPRESENTATION_INDEX
|
||||
* @param bits is the channel bits specifying occupancy
|
||||
* @return the channel mask
|
||||
* @throws java.lang.IllegalArgumentException if representation is not recognized or
|
||||
* the bits field is not acceptable for that representation
|
||||
*/
|
||||
private static int getChannelMaskFromRepresentationAndBits(int representation, int bits) {
|
||||
switch (representation) {
|
||||
case CHANNEL_OUT_REPRESENTATION_POSITION:
|
||||
case CHANNEL_OUT_REPRESENTATION_INDEX:
|
||||
if ((bits & ~((1 << AUDIO_CHANNEL_BITS_LOG2) - 1)) != 0) {
|
||||
throw new IllegalArgumentException("invalid bits " + bits);
|
||||
}
|
||||
return representation << AUDIO_CHANNEL_BITS_LOG2 | bits;
|
||||
default:
|
||||
throw new IllegalArgumentException("invalid representation " + representation);
|
||||
}
|
||||
}
|
||||
|
||||
// Convenience method for the constructor's parameter checks.
|
||||
// This is where constructor IllegalArgumentException-s are thrown
|
||||
// postconditions:
|
||||
@@ -661,8 +717,8 @@ public class AudioTrack
|
||||
// mAudioFormat is valid
|
||||
// mSampleRate is valid
|
||||
// mDataLoadMode is valid
|
||||
private void audioParamCheck(int sampleRateInHz,
|
||||
int channelConfig, int audioFormat, int mode) {
|
||||
private void audioParamCheck(int sampleRateInHz, int channelConfig, int channelIndexMask,
|
||||
int audioFormat, int mode) {
|
||||
//--------------
|
||||
// sample rate, note these values are subject to change
|
||||
if (sampleRateInHz < SAMPLE_RATE_HZ_MIN || sampleRateInHz > SAMPLE_RATE_HZ_MAX) {
|
||||
@@ -688,6 +744,10 @@ public class AudioTrack
|
||||
mChannels = AudioFormat.CHANNEL_OUT_STEREO;
|
||||
break;
|
||||
default:
|
||||
if (channelConfig == AudioFormat.CHANNEL_INVALID && channelIndexMask != 0) {
|
||||
mChannelCount = 0;
|
||||
break; // channel index configuration only
|
||||
}
|
||||
if (!isMultichannelConfigSupported(channelConfig)) {
|
||||
// input channel configuration features unsupported channels
|
||||
throw new IllegalArgumentException("Unsupported channel configuration.");
|
||||
@@ -695,6 +755,27 @@ public class AudioTrack
|
||||
mChannels = channelConfig;
|
||||
mChannelCount = AudioFormat.channelCountFromOutChannelMask(channelConfig);
|
||||
}
|
||||
// check the channel index configuration (if present)
|
||||
mChannelIndexMask = channelIndexMask;
|
||||
if (mChannelIndexMask != 0) {
|
||||
// restrictive: indexMask could allow up to AUDIO_CHANNEL_BITS_LOG2
|
||||
final int indexMask = (1 << CHANNEL_COUNT_MAX) - 1;
|
||||
if ((channelIndexMask & ~indexMask) != 0) {
|
||||
throw new IllegalArgumentException("Unsupported channel index configuration "
|
||||
+ channelIndexMask);
|
||||
}
|
||||
int channelIndexCount = Integer.bitCount(channelIndexMask);
|
||||
if (mChannelCount == 0) {
|
||||
mChannelCount = channelIndexCount;
|
||||
} else if (mChannelCount != channelIndexCount) {
|
||||
throw new IllegalArgumentException("Channel count must match");
|
||||
}
|
||||
|
||||
// AudioTrack prefers to use the channel index configuration
|
||||
// over the channel position configuration if both are specified.
|
||||
mChannels = getChannelMaskFromRepresentationAndBits(
|
||||
CHANNEL_OUT_REPRESENTATION_INDEX, mChannelIndexMask);
|
||||
}
|
||||
|
||||
//--------------
|
||||
// audio format
|
||||
@@ -865,9 +946,9 @@ public class AudioTrack
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configured channel configuration.
|
||||
* See {@link AudioFormat#CHANNEL_OUT_MONO}
|
||||
* and {@link AudioFormat#CHANNEL_OUT_STEREO}.
|
||||
* Returns the configured channel position mask.
|
||||
* For example, refer to {@link AudioFormat#CHANNEL_OUT_MONO},
|
||||
* {@link AudioFormat#CHANNEL_OUT_STEREO}, {@link AudioFormat#CHANNEL_OUT_5POINT1}.
|
||||
*/
|
||||
public int getChannelConfiguration() {
|
||||
return mChannelConfiguration;
|
||||
@@ -1004,8 +1085,7 @@ public class AudioTrack
|
||||
channelCount = 2;
|
||||
break;
|
||||
default:
|
||||
if ((channelConfig & SUPPORTED_OUT_CHANNELS) != channelConfig) {
|
||||
// input channel configuration features unsupported channels
|
||||
if (!isMultichannelConfigSupported(channelConfig)) {
|
||||
loge("getMinBufferSize(): Invalid channel configuration.");
|
||||
return ERROR_BAD_VALUE;
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user