Merge "Allow sample rate UNSPECIFIED to mean a route-dependent value" into nyc-dev

am: 642a4f5b66

* commit '642a4f5b66841788ffce5cf1d81ba744265db174':
  Allow sample rate UNSPECIFIED to mean a route-dependent value
This commit is contained in:
Glenn Kasten
2016-02-26 00:28:18 +00:00
committed by android-build-merger
10 changed files with 108 additions and 51 deletions

View File

@@ -19767,6 +19767,7 @@ package android.media {
field public static final int ENCODING_PCM_16BIT = 2; // 0x2 field public static final int ENCODING_PCM_16BIT = 2; // 0x2
field public static final int ENCODING_PCM_8BIT = 3; // 0x3 field public static final int ENCODING_PCM_8BIT = 3; // 0x3
field public static final int ENCODING_PCM_FLOAT = 4; // 0x4 field public static final int ENCODING_PCM_FLOAT = 4; // 0x4
field public static final int SAMPLE_RATE_UNSPECIFIED = 0; // 0x0
} }
public static class AudioFormat.Builder { public static class AudioFormat.Builder {

View File

@@ -21263,6 +21263,7 @@ package android.media {
field public static final int ENCODING_PCM_16BIT = 2; // 0x2 field public static final int ENCODING_PCM_16BIT = 2; // 0x2
field public static final int ENCODING_PCM_8BIT = 3; // 0x3 field public static final int ENCODING_PCM_8BIT = 3; // 0x3
field public static final int ENCODING_PCM_FLOAT = 4; // 0x4 field public static final int ENCODING_PCM_FLOAT = 4; // 0x4
field public static final int SAMPLE_RATE_UNSPECIFIED = 0; // 0x0
} }
public static class AudioFormat.Builder { public static class AudioFormat.Builder {

View File

@@ -19776,6 +19776,7 @@ package android.media {
field public static final int ENCODING_PCM_16BIT = 2; // 0x2 field public static final int ENCODING_PCM_16BIT = 2; // 0x2
field public static final int ENCODING_PCM_8BIT = 3; // 0x3 field public static final int ENCODING_PCM_8BIT = 3; // 0x3
field public static final int ENCODING_PCM_FLOAT = 4; // 0x4 field public static final int ENCODING_PCM_FLOAT = 4; // 0x4
field public static final int SAMPLE_RATE_UNSPECIFIED = 0; // 0x0
} }
public static class AudioFormat.Builder { public static class AudioFormat.Builder {

View File

@@ -180,9 +180,13 @@ static sp<AudioRecord> setAudioRecord(JNIEnv* env, jobject thiz, const sp<AudioR
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
static jint static jint
android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this, android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
jobject jaa, jint sampleRateInHertz, jint channelMask, jint channelIndexMask, jobject jaa, jintArray jSampleRate, jint channelMask, jint channelIndexMask,
jint audioFormat, jint buffSizeInBytes, jintArray jSession, jstring opPackageName) jint audioFormat, jint buffSizeInBytes, jintArray jSession, jstring opPackageName)
{ {
jint elements[1];
env->GetIntArrayRegion(jSampleRate, 0, 1, elements);
int sampleRateInHertz = elements[0];
//ALOGV(">> Entering android_media_AudioRecord_setup"); //ALOGV(">> Entering android_media_AudioRecord_setup");
//ALOGV("sampleRate=%d, audioFormat=%d, channel mask=%x, buffSizeInBytes=%d", //ALOGV("sampleRate=%d, audioFormat=%d, channel mask=%x, buffSizeInBytes=%d",
// sampleRateInHertz, audioFormat, channelMask, buffSizeInBytes); // sampleRateInHertz, audioFormat, channelMask, buffSizeInBytes);
@@ -304,6 +308,11 @@ android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
env->ReleasePrimitiveArrayCritical(jSession, nSession, 0); env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
nSession = NULL; nSession = NULL;
{
const jint elements[1] = { (jint) lpRecorder->getSampleRate() };
env->SetIntArrayRegion(jSampleRate, 0, 1, elements);
}
{ // scope for the lock { // scope for the lock
Mutex::Autolock l(sLock); Mutex::Autolock l(sLock);
sAudioRecordCallBackCookies.add(lpCallbackData); sAudioRecordCallBackCookies.add(lpCallbackData);
@@ -717,7 +726,7 @@ static const JNINativeMethod gMethods[] = {
// name, signature, funcPtr // name, signature, funcPtr
{"native_start", "(II)I", (void *)android_media_AudioRecord_start}, {"native_start", "(II)I", (void *)android_media_AudioRecord_start},
{"native_stop", "()V", (void *)android_media_AudioRecord_stop}, {"native_stop", "()V", (void *)android_media_AudioRecord_stop},
{"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;IIIII[ILjava/lang/String;)I", {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;[IIIII[ILjava/lang/String;)I",
(void *)android_media_AudioRecord_setup}, (void *)android_media_AudioRecord_setup},
{"native_finalize", "()V", (void *)android_media_AudioRecord_finalize}, {"native_finalize", "()V", (void *)android_media_AudioRecord_finalize},
{"native_release", "()V", (void *)android_media_AudioRecord_release}, {"native_release", "()V", (void *)android_media_AudioRecord_release},

View File

@@ -215,9 +215,13 @@ static inline audio_channel_mask_t nativeChannelMaskFromJavaChannelMasks(
static jint static jint
android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this,
jobject jaa, jobject jaa,
jint sampleRateInHertz, jint channelPositionMask, jint channelIndexMask, jintArray jSampleRate, jint channelPositionMask, jint channelIndexMask,
jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession) { jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession) {
jint elements[1];
env->GetIntArrayRegion(jSampleRate, 0, 1, elements);
int sampleRateInHertz = elements[0];
ALOGV("sampleRate=%d, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d", ALOGV("sampleRate=%d, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d",
sampleRateInHertz, channelPositionMask, channelIndexMask, audioFormat, buffSizeInBytes); sampleRateInHertz, channelPositionMask, channelIndexMask, audioFormat, buffSizeInBytes);
@@ -370,6 +374,11 @@ android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this,
env->ReleasePrimitiveArrayCritical(jSession, nSession, 0); env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
nSession = NULL; nSession = NULL;
{
const jint elements[1] = { (jint) lpTrack->getSampleRate() };
env->SetIntArrayRegion(jSampleRate, 0, 1, elements);
}
{ // scope for the lock { // scope for the lock
Mutex::Autolock l(sLock); Mutex::Autolock l(sLock);
sAudioTrackCallBackCookies.add(&lpJniStorage->mCallbackData); sAudioTrackCallBackCookies.add(&lpJniStorage->mCallbackData);
@@ -1114,7 +1123,7 @@ static const JNINativeMethod gMethods[] = {
{"native_stop", "()V", (void *)android_media_AudioTrack_stop}, {"native_stop", "()V", (void *)android_media_AudioTrack_stop},
{"native_pause", "()V", (void *)android_media_AudioTrack_pause}, {"native_pause", "()V", (void *)android_media_AudioTrack_pause},
{"native_flush", "()V", (void *)android_media_AudioTrack_flush}, {"native_flush", "()V", (void *)android_media_AudioTrack_flush},
{"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;IIIIII[I)I", {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[I)I",
(void *)android_media_AudioTrack_setup}, (void *)android_media_AudioTrack_setup},
{"native_finalize", "()V", (void *)android_media_AudioTrack_finalize}, {"native_finalize", "()V", (void *)android_media_AudioTrack_finalize},
{"native_release", "()V", (void *)android_media_AudioTrack_release}, {"native_release", "()V", (void *)android_media_AudioTrack_release},

View File

@@ -335,6 +335,24 @@ public class AudioFormat implements Parcelable {
CHANNEL_OUT_LOW_FREQUENCY); CHANNEL_OUT_LOW_FREQUENCY);
// CHANNEL_OUT_ALL is not yet defined; if added then it should match AUDIO_CHANNEL_OUT_ALL // CHANNEL_OUT_ALL is not yet defined; if added then it should match AUDIO_CHANNEL_OUT_ALL
/** Minimum value for sample rate,
* assuming AudioTrack and AudioRecord share the same limitations.
* @hide
*/
// never unhide
public static final int SAMPLE_RATE_HZ_MIN = 4000;
/** Maximum value for sample rate,
* assuming AudioTrack and AudioRecord share the same limitations.
* @hide
*/
// never unhide
public static final int SAMPLE_RATE_HZ_MAX = 192000;
/** Sample rate will be a route-dependent value.
* For AudioTrack, it is usually the sink sample rate,
* and for AudioRecord it is usually the source sample rate.
*/
public static final int SAMPLE_RATE_UNSPECIFIED = 0;
/** /**
* @hide * @hide
* Return the input channel mask corresponding to an output channel mask. * Return the input channel mask corresponding to an output channel mask.
@@ -561,7 +579,7 @@ public class AudioFormat implements Parcelable {
} }
/** /**
* Constructor used by the JNI * Constructor used by the JNI. Parameters are not checked for validity.
*/ */
// Update sound trigger JNI in core/jni/android_hardware_SoundTrigger.cpp when modifying this // Update sound trigger JNI in core/jni/android_hardware_SoundTrigger.cpp when modifying this
// constructor // constructor
@@ -610,12 +628,9 @@ public class AudioFormat implements Parcelable {
/** /**
* Return the sample rate. * Return the sample rate.
* @return one of the values that can be set in {@link Builder#setSampleRate(int)} or * @return one of the values that can be set in {@link Builder#setSampleRate(int)} or
* 0 if not set. * {@link #SAMPLE_RATE_UNSPECIFIED} if not set.
*/ */
public int getSampleRate() { public int getSampleRate() {
if ((mPropertySetMask & AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE) == 0) {
return 0;
}
return mSampleRate; return mSampleRate;
} }
@@ -687,7 +702,7 @@ public class AudioFormat implements Parcelable {
*/ */
public static class Builder { public static class Builder {
private int mEncoding = ENCODING_INVALID; private int mEncoding = ENCODING_INVALID;
private int mSampleRate = 0; private int mSampleRate = SAMPLE_RATE_UNSPECIFIED;
private int mChannelMask = CHANNEL_INVALID; private int mChannelMask = CHANNEL_INVALID;
private int mChannelIndexMask = 0; private int mChannelIndexMask = 0;
private int mPropertySetMask = AUDIO_FORMAT_HAS_PROPERTY_NONE; private int mPropertySetMask = AUDIO_FORMAT_HAS_PROPERTY_NONE;
@@ -718,6 +733,8 @@ public class AudioFormat implements Parcelable {
public AudioFormat build() { public AudioFormat build() {
AudioFormat af = new AudioFormat(1980/*ignored*/); AudioFormat af = new AudioFormat(1980/*ignored*/);
af.mEncoding = mEncoding; af.mEncoding = mEncoding;
// not calling setSampleRate is equivalent to calling
// setSampleRate(SAMPLE_RATE_UNSPECIFIED)
af.mSampleRate = mSampleRate; af.mSampleRate = mSampleRate;
af.mChannelMask = mChannelMask; af.mChannelMask = mChannelMask;
af.mChannelIndexMask = mChannelIndexMask; af.mChannelIndexMask = mChannelIndexMask;
@@ -795,7 +812,7 @@ public class AudioFormat implements Parcelable {
* are specified but do not have the same channel count. * are specified but do not have the same channel count.
*/ */
public @NonNull Builder setChannelMask(int channelMask) { public @NonNull Builder setChannelMask(int channelMask) {
if (channelMask == 0) { if (channelMask == CHANNEL_INVALID) {
throw new IllegalArgumentException("Invalid zero channel mask"); throw new IllegalArgumentException("Invalid zero channel mask");
} else if (/* channelMask != 0 && */ mChannelIndexMask != 0 && } else if (/* channelMask != 0 && */ mChannelIndexMask != 0 &&
Integer.bitCount(channelMask) != Integer.bitCount(mChannelIndexMask)) { Integer.bitCount(channelMask) != Integer.bitCount(mChannelIndexMask)) {
@@ -867,7 +884,11 @@ public class AudioFormat implements Parcelable {
* @throws java.lang.IllegalArgumentException * @throws java.lang.IllegalArgumentException
*/ */
public Builder setSampleRate(int sampleRate) throws IllegalArgumentException { public Builder setSampleRate(int sampleRate) throws IllegalArgumentException {
if ((sampleRate <= 0) || (sampleRate > 192000)) { // TODO Consider whether to keep the MIN and MAX range checks here.
// It is not necessary and poses the problem of defining the limits independently from
// native implementation or platform capabilities.
if (((sampleRate < SAMPLE_RATE_HZ_MIN) || (sampleRate > SAMPLE_RATE_HZ_MAX)) &&
sampleRate != SAMPLE_RATE_UNSPECIFIED) {
throw new IllegalArgumentException("Invalid sample rate " + sampleRate); throw new IllegalArgumentException("Invalid sample rate " + sampleRate);
} }
mSampleRate = sampleRate; mSampleRate = sampleRate;

View File

@@ -3321,6 +3321,7 @@ public class AudioManager {
* Used as a key for {@link #getProperty} to request the native or optimal output sample rate * Used as a key for {@link #getProperty} to request the native or optimal output sample rate
* for this device's primary output stream, in decimal Hz. * for this device's primary output stream, in decimal Hz.
*/ */
// FIXME Deprecate
public static final String PROPERTY_OUTPUT_SAMPLE_RATE = public static final String PROPERTY_OUTPUT_SAMPLE_RATE =
"android.media.property.OUTPUT_SAMPLE_RATE"; "android.media.property.OUTPUT_SAMPLE_RATE";
@@ -3328,6 +3329,7 @@ public class AudioManager {
* Used as a key for {@link #getProperty} to request the native or optimal output buffer size * Used as a key for {@link #getProperty} to request the native or optimal output buffer size
* for this device's primary output stream, in decimal PCM frames. * for this device's primary output stream, in decimal PCM frames.
*/ */
// FIXME Deprecate
public static final String PROPERTY_OUTPUT_FRAMES_PER_BUFFER = public static final String PROPERTY_OUTPUT_FRAMES_PER_BUFFER =
"android.media.property.OUTPUT_FRAMES_PER_BUFFER"; "android.media.property.OUTPUT_FRAMES_PER_BUFFER";

View File

@@ -57,10 +57,6 @@ public class AudioRecord implements AudioRouting
// Constants // Constants
//-------------------- //--------------------
/** Minimum value for sample rate */
private static final int SAMPLE_RATE_HZ_MIN = 4000;
/** Maximum value for sample rate */
private static final int SAMPLE_RATE_HZ_MAX = 192000;
/** /**
* indicates AudioRecord state is not successfully initialized. * indicates AudioRecord state is not successfully initialized.
@@ -168,8 +164,9 @@ public class AudioRecord implements AudioRouting
//-------------------- //--------------------
/** /**
* The audio data sampling rate in Hz. * The audio data sampling rate in Hz.
* Never {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED}.
*/ */
private int mSampleRate; private int mSampleRate; // initialized by all constructors via audioParamCheck()
/** /**
* The number of input audio channels (1 is mono, 2 is stereo) * The number of input audio channels (1 is mono, 2 is stereo)
*/ */
@@ -251,6 +248,9 @@ public class AudioRecord implements AudioRouting
* @param sampleRateInHz the sample rate expressed in Hertz. 44100Hz is currently the only * @param sampleRateInHz the sample rate expressed in Hertz. 44100Hz is currently the only
* rate that is guaranteed to work on all devices, but other rates such as 22050, * rate that is guaranteed to work on all devices, but other rates such as 22050,
* 16000, and 11025 may work on some devices. * 16000, and 11025 may work on some devices.
* {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} means to use a route-dependent value
* which is usually the sample rate of the source.
* {@link #getSampleRate()} can be used to retrieve the actual sample rate chosen.
* @param channelConfig describes the configuration of the audio channels. * @param channelConfig describes the configuration of the audio channels.
* See {@link AudioFormat#CHANNEL_IN_MONO} and * See {@link AudioFormat#CHANNEL_IN_MONO} and
* {@link AudioFormat#CHANNEL_IN_STEREO}. {@link AudioFormat#CHANNEL_IN_MONO} is guaranteed * {@link AudioFormat#CHANNEL_IN_STEREO}. {@link AudioFormat#CHANNEL_IN_MONO} is guaranteed
@@ -337,16 +337,9 @@ public class AudioRecord implements AudioRouting
mAudioAttributes = attributes; mAudioAttributes = attributes;
} }
int rate = 0; int rate = format.getSampleRate();
if ((format.getPropertySetMask() if (rate == AudioFormat.SAMPLE_RATE_UNSPECIFIED) {
& AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE) != 0) rate = 0;
{
rate = format.getSampleRate();
} else {
rate = AudioSystem.getPrimaryOutputSamplingRate();
if (rate <= 0) {
rate = 44100;
}
} }
int encoding = AudioFormat.ENCODING_DEFAULT; int encoding = AudioFormat.ENCODING_DEFAULT;
@@ -373,12 +366,13 @@ public class AudioRecord implements AudioRouting
audioBuffSizeCheck(bufferSizeInBytes); audioBuffSizeCheck(bufferSizeInBytes);
int[] sampleRate = new int[] {mSampleRate};
int[] session = new int[1]; int[] session = new int[1];
session[0] = sessionId; session[0] = sessionId;
//TODO: update native initialization when information about hardware init failure //TODO: update native initialization when information about hardware init failure
// due to capture device already open is available. // due to capture device already open is available.
int initResult = native_setup( new WeakReference<AudioRecord>(this), int initResult = native_setup( new WeakReference<AudioRecord>(this),
mAudioAttributes, mSampleRate, mChannelMask, mChannelIndexMask, mAudioAttributes, sampleRate, mChannelMask, mChannelIndexMask,
mAudioFormat, mNativeBufferSizeInBytes, mAudioFormat, mNativeBufferSizeInBytes,
session, ActivityThread.currentOpPackageName()); session, ActivityThread.currentOpPackageName());
if (initResult != SUCCESS) { if (initResult != SUCCESS) {
@@ -386,6 +380,7 @@ public class AudioRecord implements AudioRouting
return; // with mState == STATE_UNINITIALIZED return; // with mState == STATE_UNINITIALIZED
} }
mSampleRate = sampleRate[0];
mSessionId = session[0]; mSessionId = session[0];
mState = STATE_INITIALIZED; mState = STATE_INITIALIZED;
@@ -623,6 +618,7 @@ public class AudioRecord implements AudioRouting
return mask; return mask;
} }
// postconditions: // postconditions:
// mRecordSource is valid // mRecordSource is valid
// mAudioFormat is valid // mAudioFormat is valid
@@ -642,7 +638,9 @@ public class AudioRecord implements AudioRouting
//-------------- //--------------
// sample rate // sample rate
if ((sampleRateInHz < SAMPLE_RATE_HZ_MIN) || (sampleRateInHz > SAMPLE_RATE_HZ_MAX)) { if ((sampleRateInHz < AudioFormat.SAMPLE_RATE_HZ_MIN ||
sampleRateInHz > AudioFormat.SAMPLE_RATE_HZ_MAX) &&
sampleRateInHz != AudioFormat.SAMPLE_RATE_UNSPECIFIED) {
throw new IllegalArgumentException(sampleRateInHz throw new IllegalArgumentException(sampleRateInHz
+ "Hz is not a supported sample rate."); + "Hz is not a supported sample rate.");
} }
@@ -714,7 +712,11 @@ public class AudioRecord implements AudioRouting
// Getters // Getters
//-------------------- //--------------------
/** /**
* Returns the configured audio data sample rate in Hz * Returns the configured audio sink sample rate in Hz.
* The sink sample rate never changes after construction.
* If the constructor had a specific sample rate, then the sink sample rate is that value.
* If the constructor had {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED},
* then the sink sample rate is a route-dependent default value based on the source [sic].
*/ */
public int getSampleRate() { public int getSampleRate() {
return mSampleRate; return mSampleRate;
@@ -861,6 +863,7 @@ public class AudioRecord implements AudioRouting
* See {@link #AudioRecord(int, int, int, int, int)} for more information on valid * See {@link #AudioRecord(int, int, int, int, int)} for more information on valid
* configuration values. * configuration values.
* @param sampleRateInHz the sample rate expressed in Hertz. * @param sampleRateInHz the sample rate expressed in Hertz.
* {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} is not permitted.
* @param channelConfig describes the configuration of the audio channels. * @param channelConfig describes the configuration of the audio channels.
* See {@link AudioFormat#CHANNEL_IN_MONO} and * See {@link AudioFormat#CHANNEL_IN_MONO} and
* {@link AudioFormat#CHANNEL_IN_STEREO} * {@link AudioFormat#CHANNEL_IN_STEREO}
@@ -1708,7 +1711,7 @@ public class AudioRecord implements AudioRouting
private native final int native_setup(Object audiorecord_this, private native final int native_setup(Object audiorecord_this,
Object /*AudioAttributes*/ attributes, Object /*AudioAttributes*/ attributes,
int sampleRate, int channelMask, int channelIndexMask, int audioFormat, int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat,
int buffSizeInBytes, int[] sessionId, String opPackageName); int buffSizeInBytes, int[] sessionId, String opPackageName);
// TODO remove: implementation calls directly into implementation of native_release() // TODO remove: implementation calls directly into implementation of native_release()

View File

@@ -91,11 +91,6 @@ public class AudioTrack implements AudioRouting
*/ */
private static final float GAIN_MAX = 1.0f; private static final float GAIN_MAX = 1.0f;
/** Minimum value for sample rate */
private static final int SAMPLE_RATE_HZ_MIN = 4000;
/** Maximum value for sample rate */
private static final int SAMPLE_RATE_HZ_MAX = 192000;
/** Maximum value for AudioTrack channel count /** Maximum value for AudioTrack channel count
* @hide public for MediaCode only, do not un-hide or change to a numeric literal * @hide public for MediaCode only, do not un-hide or change to a numeric literal
*/ */
@@ -254,6 +249,7 @@ public class AudioTrack implements AudioRouting
private final Looper mInitializationLooper; private final Looper mInitializationLooper;
/** /**
* The audio data source sampling rate in Hz. * The audio data source sampling rate in Hz.
* Never {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED}.
*/ */
private int mSampleRate; // initialized by all constructors via audioParamCheck() private int mSampleRate; // initialized by all constructors via audioParamCheck()
/** /**
@@ -340,6 +336,9 @@ public class AudioTrack implements AudioRouting
* {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC}, * {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC},
* {@link AudioManager#STREAM_ALARM}, and {@link AudioManager#STREAM_NOTIFICATION}. * {@link AudioManager#STREAM_ALARM}, and {@link AudioManager#STREAM_NOTIFICATION}.
* @param sampleRateInHz the initial source sample rate expressed in Hz. * @param sampleRateInHz the initial source sample rate expressed in Hz.
* {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} means to use a route-dependent value
* which is usually the sample rate of the sink.
* {@link #getSampleRate()} can be used to retrieve the actual sample rate chosen.
* @param channelConfig describes the configuration of the audio channels. * @param channelConfig describes the configuration of the audio channels.
* See {@link AudioFormat#CHANNEL_OUT_MONO} and * See {@link AudioFormat#CHANNEL_OUT_MONO} and
* {@link AudioFormat#CHANNEL_OUT_STEREO} * {@link AudioFormat#CHANNEL_OUT_STEREO}
@@ -389,6 +388,8 @@ public class AudioTrack implements AudioRouting
* {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC}, * {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC},
* {@link AudioManager#STREAM_ALARM}, and {@link AudioManager#STREAM_NOTIFICATION}. * {@link AudioManager#STREAM_ALARM}, and {@link AudioManager#STREAM_NOTIFICATION}.
* @param sampleRateInHz the initial source sample rate expressed in Hz. * @param sampleRateInHz the initial source sample rate expressed in Hz.
* {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} means to use a route-dependent value
* which is usually the sample rate of the sink.
* @param channelConfig describes the configuration of the audio channels. * @param channelConfig describes the configuration of the audio channels.
* See {@link AudioFormat#CHANNEL_OUT_MONO} and * See {@link AudioFormat#CHANNEL_OUT_MONO} and
* {@link AudioFormat#CHANNEL_OUT_STEREO} * {@link AudioFormat#CHANNEL_OUT_STEREO}
@@ -461,16 +462,11 @@ public class AudioTrack implements AudioRouting
looper = Looper.getMainLooper(); looper = Looper.getMainLooper();
} }
int rate = 0; int rate = format.getSampleRate();
if ((format.getPropertySetMask() & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE) != 0) if (rate == AudioFormat.SAMPLE_RATE_UNSPECIFIED) {
{ rate = 0;
rate = format.getSampleRate();
} else {
rate = AudioSystem.getPrimaryOutputSamplingRate();
if (rate <= 0) {
rate = 44100;
}
} }
int channelIndexMask = 0; int channelIndexMask = 0;
if ((format.getPropertySetMask() if ((format.getPropertySetMask()
& AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_INDEX_MASK) != 0) { & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_INDEX_MASK) != 0) {
@@ -503,17 +499,19 @@ public class AudioTrack implements AudioRouting
throw new IllegalArgumentException("Invalid audio session ID: "+sessionId); throw new IllegalArgumentException("Invalid audio session ID: "+sessionId);
} }
int[] sampleRate = new int[] {mSampleRate};
int[] session = new int[1]; int[] session = new int[1];
session[0] = sessionId; session[0] = sessionId;
// native initialization // native initialization
int initResult = native_setup(new WeakReference<AudioTrack>(this), mAttributes, int initResult = native_setup(new WeakReference<AudioTrack>(this), mAttributes,
mSampleRate, mChannelMask, mChannelIndexMask, mAudioFormat, sampleRate, mChannelMask, mChannelIndexMask, mAudioFormat,
mNativeBufferSizeInBytes, mDataLoadMode, session); mNativeBufferSizeInBytes, mDataLoadMode, session);
if (initResult != SUCCESS) { if (initResult != SUCCESS) {
loge("Error code "+initResult+" when initializing AudioTrack."); loge("Error code "+initResult+" when initializing AudioTrack.");
return; // with mState == STATE_UNINITIALIZED return; // with mState == STATE_UNINITIALIZED
} }
mSampleRate = sampleRate[0];
mSessionId = session[0]; mSessionId = session[0];
if (mDataLoadMode == MODE_STATIC) { if (mDataLoadMode == MODE_STATIC) {
@@ -712,7 +710,7 @@ public class AudioTrack implements AudioRouting
if (mFormat == null) { if (mFormat == null) {
mFormat = new AudioFormat.Builder() mFormat = new AudioFormat.Builder()
.setChannelMask(AudioFormat.CHANNEL_OUT_STEREO) .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
.setSampleRate(AudioSystem.getPrimaryOutputSamplingRate()) //.setSampleRate(AudioFormat.SAMPLE_RATE_UNSPECIFIED)
.setEncoding(AudioFormat.ENCODING_DEFAULT) .setEncoding(AudioFormat.ENCODING_DEFAULT)
.build(); .build();
} }
@@ -762,7 +760,9 @@ public class AudioTrack implements AudioRouting
int audioFormat, int mode) { int audioFormat, int mode) {
//-------------- //--------------
// sample rate, note these values are subject to change // sample rate, note these values are subject to change
if (sampleRateInHz < SAMPLE_RATE_HZ_MIN || sampleRateInHz > SAMPLE_RATE_HZ_MAX) { if ((sampleRateInHz < AudioFormat.SAMPLE_RATE_HZ_MIN ||
sampleRateInHz > AudioFormat.SAMPLE_RATE_HZ_MAX) &&
sampleRateInHz != AudioFormat.SAMPLE_RATE_UNSPECIFIED) {
throw new IllegalArgumentException(sampleRateInHz throw new IllegalArgumentException(sampleRateInHz
+ "Hz is not a supported sample rate."); + "Hz is not a supported sample rate.");
} }
@@ -948,7 +948,13 @@ public class AudioTrack implements AudioRouting
} }
/** /**
* Returns the configured audio data sample rate in Hz * Returns the configured audio source sample rate in Hz.
* The initial source sample rate depends on the constructor parameters,
* but the source sample rate may change if {@link #setPlaybackRate(int)} is called.
* If the constructor had a specific sample rate, then the initial sink sample rate is that
* value.
* If the constructor had {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED},
* then the initial sink sample rate is a route-dependent default value based on the source [sic].
*/ */
public int getSampleRate() { public int getSampleRate() {
return mSampleRate; return mSampleRate;
@@ -1218,6 +1224,7 @@ public class AudioTrack implements AudioRouting
* to a higher value than the initial source sample rate, be sure to configure the buffer size * to a higher value than the initial source sample rate, be sure to configure the buffer size
* based on the highest planned sample rate. * based on the highest planned sample rate.
* @param sampleRateInHz the source sample rate expressed in Hz. * @param sampleRateInHz the source sample rate expressed in Hz.
* {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} is not permitted.
* @param channelConfig describes the configuration of the audio channels. * @param channelConfig describes the configuration of the audio channels.
* See {@link AudioFormat#CHANNEL_OUT_MONO} and * See {@link AudioFormat#CHANNEL_OUT_MONO} and
* {@link AudioFormat#CHANNEL_OUT_STEREO} * {@link AudioFormat#CHANNEL_OUT_STEREO}
@@ -1255,7 +1262,9 @@ public class AudioTrack implements AudioRouting
} }
// sample rate, note these values are subject to change // sample rate, note these values are subject to change
if ( (sampleRateInHz < SAMPLE_RATE_HZ_MIN) || (sampleRateInHz > SAMPLE_RATE_HZ_MAX) ) { // Note: AudioFormat.SAMPLE_RATE_UNSPECIFIED is not allowed
if ( (sampleRateInHz < AudioFormat.SAMPLE_RATE_HZ_MIN) ||
(sampleRateInHz > AudioFormat.SAMPLE_RATE_HZ_MAX) ) {
loge("getMinBufferSize(): " + sampleRateInHz + " Hz is not a supported sample rate."); loge("getMinBufferSize(): " + sampleRateInHz + " Hz is not a supported sample rate.");
return ERROR_BAD_VALUE; return ERROR_BAD_VALUE;
} }
@@ -2763,7 +2772,7 @@ public class AudioTrack implements AudioRouting
// AudioAttributes.USAGE_MEDIA will map to AudioManager.STREAM_MUSIC // AudioAttributes.USAGE_MEDIA will map to AudioManager.STREAM_MUSIC
private native final int native_setup(Object /*WeakReference<AudioTrack>*/ audiotrack_this, private native final int native_setup(Object /*WeakReference<AudioTrack>*/ audiotrack_this,
Object /*AudioAttributes*/ attributes, Object /*AudioAttributes*/ attributes,
int sampleRate, int channelMask, int channelIndexMask, int audioFormat, int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat,
int buffSizeInBytes, int mode, int[] sessionId); int buffSizeInBytes, int mode, int[] sessionId);
private native final void native_finalize(); private native final void native_finalize();

View File

@@ -277,6 +277,7 @@ public class AudioMix {
mRouteFlags = ROUTE_FLAG_RENDER; mRouteFlags = ROUTE_FLAG_RENDER;
} }
if (mFormat == null) { if (mFormat == null) {
// FIXME Can we eliminate this? Will AudioMix work with an unspecified sample rate?
int rate = AudioSystem.getPrimaryOutputSamplingRate(); int rate = AudioSystem.getPrimaryOutputSamplingRate();
if (rate <= 0) { if (rate <= 0) {
rate = 44100; rate = 44100;