AudioTrack: Add Tuner Configuration methods

Test: atest AudioTrackTest#testTunerConfiguration
Bug: 133526565
Change-Id: I0cc8e9e8b780e1a87c38656c8dfc67dac03969d8
This commit is contained in:
Andy Hung
2020-01-14 17:29:03 -08:00
parent 72973ef6e8
commit 59dffec3f1
3 changed files with 340 additions and 91 deletions

View File

@@ -24248,6 +24248,9 @@ package android.media {
method public int write(@NonNull float[], int, int, int);
method public int write(@NonNull java.nio.ByteBuffer, int, int);
method public int write(@NonNull java.nio.ByteBuffer, int, int, long);
field public static final int ENCAPSULATION_MODE_ELEMENTARY_STREAM = 1; // 0x1
field public static final int ENCAPSULATION_MODE_HANDLE = 2; // 0x2
field public static final int ENCAPSULATION_MODE_NONE = 0; // 0x0
field public static final int ERROR = -1; // 0xffffffff
field public static final int ERROR_BAD_VALUE = -2; // 0xfffffffe
field public static final int ERROR_DEAD_OBJECT = -6; // 0xfffffffa
@@ -24274,10 +24277,12 @@ package android.media {
method @NonNull public android.media.AudioTrack.Builder setAudioAttributes(@NonNull android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
method @NonNull public android.media.AudioTrack.Builder setAudioFormat(@NonNull android.media.AudioFormat) throws java.lang.IllegalArgumentException;
method @NonNull public android.media.AudioTrack.Builder setBufferSizeInBytes(@IntRange(from=0) int) throws java.lang.IllegalArgumentException;
method @NonNull public android.media.AudioTrack.Builder setEncapsulationMode(int);
method @NonNull public android.media.AudioTrack.Builder setOffloadedPlayback(boolean);
method @NonNull public android.media.AudioTrack.Builder setPerformanceMode(int);
method @NonNull public android.media.AudioTrack.Builder setSessionId(@IntRange(from=1) int) throws java.lang.IllegalArgumentException;
method @NonNull public android.media.AudioTrack.Builder setTransferMode(int) throws java.lang.IllegalArgumentException;
method @NonNull public android.media.AudioTrack.Builder setTunerConfiguration(@NonNull android.media.AudioTrack.TunerConfiguration);
}
public static final class AudioTrack.MetricsConstants {
@@ -24305,6 +24310,18 @@ package android.media {
method public void onTearDown(@NonNull android.media.AudioTrack);
}
public static class AudioTrack.TunerConfiguration {
method public int getContentId();
method public int getSyncId();
}
public static class AudioTrack.TunerConfiguration.Builder {
ctor public AudioTrack.TunerConfiguration.Builder();
method @NonNull public android.media.AudioTrack.TunerConfiguration build();
method @NonNull public android.media.AudioTrack.TunerConfiguration.Builder setContentId(@IntRange(from=1) int);
method @NonNull public android.media.AudioTrack.TunerConfiguration.Builder setSyncId(@IntRange(from=1) int);
}
public class CamcorderProfile {
method public static android.media.CamcorderProfile get(int);
method public static android.media.CamcorderProfile get(int, int);

View File

@@ -102,6 +102,47 @@ class AudioTrackJniStorage {
}
};
class TunerConfigurationHelper {
JNIEnv *const mEnv;
jobject const mTunerConfiguration;
struct Ids {
Ids(JNIEnv *env)
: mClass(FindClassOrDie(env, "android/media/AudioTrack$TunerConfiguration")),
mContentId(GetFieldIDOrDie(env, mClass, "mContentId", "I")),
mSyncId(GetFieldIDOrDie(env, mClass, "mSyncId", "I")) {}
const jclass mClass;
const jfieldID mContentId;
const jfieldID mSyncId;
};
static const Ids &getIds(JNIEnv *env) {
// Meyer's singleton, initializes first time control passes through
// declaration in a block and is thread-safe per ISO/IEC 14882:2011 6.7.4.
static Ids ids(env);
return ids;
}
public:
TunerConfigurationHelper(JNIEnv *env, jobject tunerConfiguration)
: mEnv(env), mTunerConfiguration(tunerConfiguration) {}
int32_t getContentId() const {
if (mEnv == nullptr || mTunerConfiguration == nullptr) return 0;
const Ids &ids = getIds(mEnv);
return (int32_t)mEnv->GetIntField(mTunerConfiguration, ids.mContentId);
}
int32_t getSyncId() const {
if (mEnv == nullptr || mTunerConfiguration == nullptr) return 0;
const Ids &ids = getIds(mEnv);
return (int32_t)mEnv->GetIntField(mTunerConfiguration, ids.mSyncId);
}
// optional check to confirm class and field ids can be found.
static void initCheckOrDie(JNIEnv *env) { (void)getIds(env); }
};
static Mutex sLock;
static SortedVector <audiotrack_callback_cookie *> sAudioTrackCallBackCookies;
@@ -213,24 +254,36 @@ sp<AudioTrack> android_media_AudioTrack_getAudioTrack(JNIEnv* env, jobject audio
}
// ----------------------------------------------------------------------------
static jint
android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, jobject jaa,
jintArray jSampleRate, jint channelPositionMask, jint channelIndexMask,
jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession,
jlong nativeAudioTrack, jboolean offload) {
static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this,
jobject jaa, jintArray jSampleRate,
jint channelPositionMask, jint channelIndexMask,
jint audioFormat, jint buffSizeInBytes, jint memoryMode,
jintArray jSession, jlong nativeAudioTrack,
jboolean offload, jint encapsulationMode,
jobject tunerConfiguration) {
ALOGV("sampleRates=%p, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d,"
" nativeAudioTrack=0x%" PRIX64 ", offload=%d",
jSampleRate, channelPositionMask, channelIndexMask, audioFormat, buffSizeInBytes,
nativeAudioTrack, offload);
sp<AudioTrack> lpTrack = 0;
" nativeAudioTrack=0x%" PRIX64 ", offload=%d encapsulationMode=%d tuner=%p",
jSampleRate, channelPositionMask, channelIndexMask, audioFormat, buffSizeInBytes,
nativeAudioTrack, offload, encapsulationMode, tunerConfiguration);
if (jSession == NULL) {
ALOGE("Error creating AudioTrack: invalid session ID pointer");
return (jint) AUDIO_JAVA_ERROR;
}
// TODO: replace when we land matching AudioTrack::set() in frameworks/av in r or r-tv-dev.
if (tunerConfiguration != nullptr) {
const TunerConfigurationHelper tunerHelper(env, tunerConfiguration);
ALOGE("Error creating AudioTrack: unsupported tuner contentId:%d syncId:%d",
tunerHelper.getContentId(), tunerHelper.getSyncId());
return (jint)AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
}
// TODO: replace when we land matching AudioTrack::set() in frameworks/av in r or r-tv-dev.
if (encapsulationMode != 0 /* ENCAPSULATION_MODE_NONE */) {
ALOGE("Error creating AudioTrack: unsupported encapsulationMode %d", encapsulationMode);
return (jint)AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
}
jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
if (nSession == NULL) {
ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
@@ -249,6 +302,7 @@ android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, job
}
// if we pass in an existing *Native* AudioTrack, we don't need to create/initialize one.
sp<AudioTrack> lpTrack;
if (nativeAudioTrack == 0) {
if (jaa == 0) {
ALOGE("Error creating AudioTrack: invalid audio attributes");
@@ -1304,82 +1358,75 @@ static void android_media_AudioTrack_set_delay_padding(JNIEnv *env, jobject thi
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
static const JNINativeMethod gMethods[] = {
// name, signature, funcPtr
{"native_is_direct_output_supported",
"(IIIIIII)Z",
(void *)android_media_AudioTrack_is_direct_output_supported},
{"native_start", "()V", (void *)android_media_AudioTrack_start},
{"native_stop", "()V", (void *)android_media_AudioTrack_stop},
{"native_pause", "()V", (void *)android_media_AudioTrack_pause},
{"native_flush", "()V", (void *)android_media_AudioTrack_flush},
{"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[IJZ)I",
(void *)android_media_AudioTrack_setup},
{"native_finalize", "()V", (void *)android_media_AudioTrack_finalize},
{"native_release", "()V", (void *)android_media_AudioTrack_release},
{"native_write_byte", "([BIIIZ)I",(void *)android_media_AudioTrack_writeArray<jbyteArray>},
{"native_write_native_bytes",
"(Ljava/nio/ByteBuffer;IIIZ)I",
(void *)android_media_AudioTrack_write_native_bytes},
{"native_write_short", "([SIIIZ)I",(void *)android_media_AudioTrack_writeArray<jshortArray>},
{"native_write_float", "([FIIIZ)I",(void *)android_media_AudioTrack_writeArray<jfloatArray>},
{"native_setVolume", "(FF)V", (void *)android_media_AudioTrack_set_volume},
{"native_get_buffer_size_frames",
"()I", (void *)android_media_AudioTrack_get_buffer_size_frames},
{"native_set_buffer_size_frames",
"(I)I", (void *)android_media_AudioTrack_set_buffer_size_frames},
{"native_get_buffer_capacity_frames",
"()I", (void *)android_media_AudioTrack_get_buffer_capacity_frames},
{"native_set_playback_rate",
"(I)I", (void *)android_media_AudioTrack_set_playback_rate},
{"native_get_playback_rate",
"()I", (void *)android_media_AudioTrack_get_playback_rate},
{"native_set_playback_params",
"(Landroid/media/PlaybackParams;)V",
(void *)android_media_AudioTrack_set_playback_params},
{"native_get_playback_params",
"()Landroid/media/PlaybackParams;",
(void *)android_media_AudioTrack_get_playback_params},
{"native_set_marker_pos","(I)I", (void *)android_media_AudioTrack_set_marker_pos},
{"native_get_marker_pos","()I", (void *)android_media_AudioTrack_get_marker_pos},
{"native_set_pos_update_period",
"(I)I", (void *)android_media_AudioTrack_set_pos_update_period},
{"native_get_pos_update_period",
"()I", (void *)android_media_AudioTrack_get_pos_update_period},
{"native_set_position", "(I)I", (void *)android_media_AudioTrack_set_position},
{"native_get_position", "()I", (void *)android_media_AudioTrack_get_position},
{"native_get_latency", "()I", (void *)android_media_AudioTrack_get_latency},
{"native_get_underrun_count", "()I", (void *)android_media_AudioTrack_get_underrun_count},
{"native_get_flags", "()I", (void *)android_media_AudioTrack_get_flags},
{"native_get_timestamp", "([J)I", (void *)android_media_AudioTrack_get_timestamp},
{"native_getMetrics", "()Landroid/os/PersistableBundle;",
(void *)android_media_AudioTrack_native_getMetrics},
{"native_set_loop", "(III)I", (void *)android_media_AudioTrack_set_loop},
{"native_reload_static", "()I", (void *)android_media_AudioTrack_reload},
{"native_get_output_sample_rate",
"(I)I", (void *)android_media_AudioTrack_get_output_sample_rate},
{"native_get_min_buff_size",
"(III)I", (void *)android_media_AudioTrack_get_min_buff_size},
{"native_setAuxEffectSendLevel",
"(F)I", (void *)android_media_AudioTrack_setAuxEffectSendLevel},
{"native_attachAuxEffect",
"(I)I", (void *)android_media_AudioTrack_attachAuxEffect},
{"native_setOutputDevice", "(I)Z",
(void *)android_media_AudioTrack_setOutputDevice},
{"native_getRoutedDeviceId", "()I", (void *)android_media_AudioTrack_getRoutedDeviceId},
{"native_enableDeviceCallback", "()V", (void *)android_media_AudioTrack_enableDeviceCallback},
{"native_disableDeviceCallback", "()V", (void *)android_media_AudioTrack_disableDeviceCallback},
{"native_applyVolumeShaper",
"(Landroid/media/VolumeShaper$Configuration;Landroid/media/VolumeShaper$Operation;)I",
(void *)android_media_AudioTrack_apply_volume_shaper},
{"native_getVolumeShaperState",
"(I)Landroid/media/VolumeShaper$State;",
(void *)android_media_AudioTrack_get_volume_shaper_state},
{"native_setPresentation", "(II)I", (void *)android_media_AudioTrack_setPresentation},
{"native_getPortId", "()I", (void *)android_media_AudioTrack_get_port_id},
{"native_set_delay_padding", "(II)V", (void *)android_media_AudioTrack_set_delay_padding},
// name, signature, funcPtr
{"native_is_direct_output_supported", "(IIIIIII)Z",
(void *)android_media_AudioTrack_is_direct_output_supported},
{"native_start", "()V", (void *)android_media_AudioTrack_start},
{"native_stop", "()V", (void *)android_media_AudioTrack_stop},
{"native_pause", "()V", (void *)android_media_AudioTrack_pause},
{"native_flush", "()V", (void *)android_media_AudioTrack_flush},
{"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[IJZILjava/lang/Object;)I",
(void *)android_media_AudioTrack_setup},
{"native_finalize", "()V", (void *)android_media_AudioTrack_finalize},
{"native_release", "()V", (void *)android_media_AudioTrack_release},
{"native_write_byte", "([BIIIZ)I", (void *)android_media_AudioTrack_writeArray<jbyteArray>},
{"native_write_native_bytes", "(Ljava/nio/ByteBuffer;IIIZ)I",
(void *)android_media_AudioTrack_write_native_bytes},
{"native_write_short", "([SIIIZ)I",
(void *)android_media_AudioTrack_writeArray<jshortArray>},
{"native_write_float", "([FIIIZ)I",
(void *)android_media_AudioTrack_writeArray<jfloatArray>},
{"native_setVolume", "(FF)V", (void *)android_media_AudioTrack_set_volume},
{"native_get_buffer_size_frames", "()I",
(void *)android_media_AudioTrack_get_buffer_size_frames},
{"native_set_buffer_size_frames", "(I)I",
(void *)android_media_AudioTrack_set_buffer_size_frames},
{"native_get_buffer_capacity_frames", "()I",
(void *)android_media_AudioTrack_get_buffer_capacity_frames},
{"native_set_playback_rate", "(I)I", (void *)android_media_AudioTrack_set_playback_rate},
{"native_get_playback_rate", "()I", (void *)android_media_AudioTrack_get_playback_rate},
{"native_set_playback_params", "(Landroid/media/PlaybackParams;)V",
(void *)android_media_AudioTrack_set_playback_params},
{"native_get_playback_params", "()Landroid/media/PlaybackParams;",
(void *)android_media_AudioTrack_get_playback_params},
{"native_set_marker_pos", "(I)I", (void *)android_media_AudioTrack_set_marker_pos},
{"native_get_marker_pos", "()I", (void *)android_media_AudioTrack_get_marker_pos},
{"native_set_pos_update_period", "(I)I",
(void *)android_media_AudioTrack_set_pos_update_period},
{"native_get_pos_update_period", "()I",
(void *)android_media_AudioTrack_get_pos_update_period},
{"native_set_position", "(I)I", (void *)android_media_AudioTrack_set_position},
{"native_get_position", "()I", (void *)android_media_AudioTrack_get_position},
{"native_get_latency", "()I", (void *)android_media_AudioTrack_get_latency},
{"native_get_underrun_count", "()I", (void *)android_media_AudioTrack_get_underrun_count},
{"native_get_flags", "()I", (void *)android_media_AudioTrack_get_flags},
{"native_get_timestamp", "([J)I", (void *)android_media_AudioTrack_get_timestamp},
{"native_getMetrics", "()Landroid/os/PersistableBundle;",
(void *)android_media_AudioTrack_native_getMetrics},
{"native_set_loop", "(III)I", (void *)android_media_AudioTrack_set_loop},
{"native_reload_static", "()I", (void *)android_media_AudioTrack_reload},
{"native_get_output_sample_rate", "(I)I",
(void *)android_media_AudioTrack_get_output_sample_rate},
{"native_get_min_buff_size", "(III)I", (void *)android_media_AudioTrack_get_min_buff_size},
{"native_setAuxEffectSendLevel", "(F)I",
(void *)android_media_AudioTrack_setAuxEffectSendLevel},
{"native_attachAuxEffect", "(I)I", (void *)android_media_AudioTrack_attachAuxEffect},
{"native_setOutputDevice", "(I)Z", (void *)android_media_AudioTrack_setOutputDevice},
{"native_getRoutedDeviceId", "()I", (void *)android_media_AudioTrack_getRoutedDeviceId},
{"native_enableDeviceCallback", "()V",
(void *)android_media_AudioTrack_enableDeviceCallback},
{"native_disableDeviceCallback", "()V",
(void *)android_media_AudioTrack_disableDeviceCallback},
{"native_applyVolumeShaper",
"(Landroid/media/VolumeShaper$Configuration;Landroid/media/VolumeShaper$Operation;)I",
(void *)android_media_AudioTrack_apply_volume_shaper},
{"native_getVolumeShaperState", "(I)Landroid/media/VolumeShaper$State;",
(void *)android_media_AudioTrack_get_volume_shaper_state},
{"native_setPresentation", "(II)I", (void *)android_media_AudioTrack_setPresentation},
{"native_getPortId", "()I", (void *)android_media_AudioTrack_get_port_id},
{"native_set_delay_padding", "(II)V", (void *)android_media_AudioTrack_set_delay_padding},
};
// field names found in android/media/AudioTrack.java
#define JAVA_POSTEVENT_CALLBACK_NAME "postEventFromNative"
#define JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME "mNativeTrackInJavaObj"
@@ -1436,6 +1483,10 @@ int register_android_media_AudioTrack(JNIEnv *env)
gPlaybackParamsFields.init(env);
gVolumeShaperFields.init(env);
// optional check that the TunerConfiguration class and fields exist.
TunerConfigurationHelper::initCheckOrDie(env);
return res;
}

View File

@@ -213,6 +213,36 @@ public class AudioTrack extends PlayerBase
private final static String TAG = "android.media.AudioTrack";
/** @hide */
@IntDef({
ENCAPSULATION_MODE_NONE,
ENCAPSULATION_MODE_ELEMENTARY_STREAM,
ENCAPSULATION_MODE_HANDLE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface EncapsulationMode {}
// Important: The ENCAPSULATION_MODE values must be kept in sync with native header files.
/**
* This mode indicates no metadata encapsulation,
* which is the default mode for sending audio data
* through {@code AudioTrack}.
*/
public static final int ENCAPSULATION_MODE_NONE = 0;
/**
* This mode indicates metadata encapsulation with an elementary stream payload.
* Both compressed and PCM format is allowed.
*
* TODO(b/147778408) Link: See the Android developers guide for more information.
*/
public static final int ENCAPSULATION_MODE_ELEMENTARY_STREAM = 1;
/**
* This mode indicates metadata encapsulation with a handle payload.
* The handle is a 64 bit long, provided by the Tuner API.
*
* TODO(b/147778408) Link: Fill in Tuner API to obtain the handle.
*/
public static final int ENCAPSULATION_MODE_HANDLE = 2;
/** @hide */
@IntDef({
@@ -592,11 +622,13 @@ public class AudioTrack extends PlayerBase
public AudioTrack(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,
int mode, int sessionId)
throws IllegalArgumentException {
this(attributes, format, bufferSizeInBytes, mode, sessionId, false /*offload*/);
this(attributes, format, bufferSizeInBytes, mode, sessionId, false /*offload*/,
ENCAPSULATION_MODE_NONE, null /* tunerConfiguration */);
}
private AudioTrack(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,
int mode, int sessionId, boolean offload)
int mode, int sessionId, boolean offload, int encapsulationMode,
@Nullable TunerConfiguration tunerConfiguration)
throws IllegalArgumentException {
super(attributes, AudioPlaybackConfiguration.PLAYER_TYPE_JAM_AUDIOTRACK);
// mState already == STATE_UNINITIALIZED
@@ -663,7 +695,7 @@ public class AudioTrack extends PlayerBase
int initResult = native_setup(new WeakReference<AudioTrack>(this), mAttributes,
sampleRate, mChannelMask, mChannelIndexMask, mAudioFormat,
mNativeBufferSizeInBytes, mDataLoadMode, session, 0 /*nativeTrackInJavaObj*/,
offload);
offload, encapsulationMode, tunerConfiguration);
if (initResult != SUCCESS) {
loge("Error code "+initResult+" when initializing AudioTrack.");
return; // with mState == STATE_UNINITIALIZED
@@ -672,6 +704,8 @@ public class AudioTrack extends PlayerBase
mSampleRate = sampleRate[0];
mSessionId = session[0];
// TODO: consider caching encapsulationMode and tunerConfiguration in the Java object.
if ((mAttributes.getFlags() & AudioAttributes.FLAG_HW_AV_SYNC) != 0) {
int frameSizeInBytes;
if (AudioFormat.isEncodingLinearFrames(mAudioFormat)) {
@@ -745,7 +779,9 @@ public class AudioTrack extends PlayerBase
0 /*mDataLoadMode - NA*/,
session,
nativeTrackInJavaObj,
false /*offload*/);
false /*offload*/,
ENCAPSULATION_MODE_NONE,
null /* tunerConfiguration */);
if (initResult != SUCCESS) {
loge("Error code "+initResult+" when initializing AudioTrack.");
return; // with mState == STATE_UNINITIALIZED
@@ -757,6 +793,99 @@ public class AudioTrack extends PlayerBase
}
}
/**
* TunerConfiguration is used to convey tuner information
* from the android.media.tv.Tuner API to AudioTrack construction.
*
* Use the Builder to construct the TunerConfiguration object,
* which is then used by the {@link AudioTrack.Builder} to create an AudioTrack.
*/
public static class TunerConfiguration {
private final int mContentId;
private final int mSyncId;
private TunerConfiguration(int contentId, int syncId) {
mContentId = contentId;
mSyncId = syncId;
}
/**
* Returns the contentId.
*/
public int getContentId() {
return mContentId;
}
/**
* Returns the syncId.
*/
public int getSyncId() {
return mSyncId;
}
/**
* Builder class for {@link AudioTrack.TunerConfiguration} objects.
*/
public static class Builder {
private int mContentId;
private int mSyncId;
/**
* Sets the contentId from the Tuner filter.
*
* @param contentId selects the audio stream to use.
* See android.media.tv.tuner.filter.Filter#getId().
* This is always a positive number.
* TODO(b/147778408) Link to tuner filter doc when unhidden.
* @return the same Builder instance.
*/
public @NonNull Builder setContentId(@IntRange(from = 1) int contentId) {
if (contentId < 1) {
throw new IllegalArgumentException(
"contentId " + contentId + " must be positive");
}
mContentId = contentId;
return this;
}
/**
* Sets the syncId from the Tuner filter.
*
* @param syncId selects the clock to use for synchronization
* of audio with other streams such as video.
* See android.media.tv.tuner.Tuner#getAvSyncHwId().
* This is always a positive number.
* TODO(b/147778408) Link to tuner filter doc when unhidden.
* @return the same Builder instance.
*/
public @NonNull Builder setSyncId(@IntRange(from = 1) int syncId) {
if (syncId < 1) {
throw new IllegalArgumentException("syncId " + syncId + " must be positive");
}
mSyncId = syncId;
return this;
}
/**
* Builds a {@link AudioTrack.TunerConfiguration} instance initialized with
* the parameters set on this {@code Builder}.
*
* @return a new successfully initialized {@link AudioTrack.TunerConfiguration}.
* @throws UnsupportedOperationException if the parameters set on the
* {@code Builder} are incompatible.
*/
public @NonNull TunerConfiguration build() {
if (mContentId < 1 || mSyncId < 1) {
throw new UnsupportedOperationException(
"contentId " + mContentId
+ " syncId " + mSyncId
+ " must be set");
}
return new TunerConfiguration(mContentId, mSyncId);
}
}
}
/**
* Builder class for {@link AudioTrack} objects.
* Use this class to configure and create an <code>AudioTrack</code> instance. By setting audio
@@ -799,10 +928,12 @@ public class AudioTrack extends PlayerBase
private AudioAttributes mAttributes;
private AudioFormat mFormat;
private int mBufferSizeInBytes;
private int mEncapsulationMode = ENCAPSULATION_MODE_NONE;
private int mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE;
private int mMode = MODE_STREAM;
private int mPerformanceMode = PERFORMANCE_MODE_NONE;
private boolean mOffload = false;
private TunerConfiguration mTunerConfiguration;
/**
* Constructs a new Builder with the default values as described above.
@@ -868,6 +999,34 @@ public class AudioTrack extends PlayerBase
return this;
}
/**
* Sets the encapsulation mode.
*
* Encapsulation mode allows metadata to be sent together with
* the audio data payload in a {@code ByteBuffer}.
* The data format is specified in the Android developers site.
*
* TODO(b/147778408) Link to doc page.
*
* @param encapsulationMode one of {@link AudioTrack#ENCAPSULATION_MODE_NONE},
* {@link AudioTrack#ENCAPSULATION_MODE_ELEMENTARY_STREAM},
* {@link AudioTrack#ENCAPSULATION_MODE_HANDLE}.
* @return the same Builder instance.
*/
public @NonNull Builder setEncapsulationMode(@EncapsulationMode int encapsulationMode) {
switch (encapsulationMode) {
case ENCAPSULATION_MODE_NONE:
case ENCAPSULATION_MODE_ELEMENTARY_STREAM:
case ENCAPSULATION_MODE_HANDLE:
mEncapsulationMode = encapsulationMode;
break;
default:
throw new IllegalArgumentException(
"Invalid encapsulation mode " + encapsulationMode);
}
return this;
}
/**
* Sets the mode under which buffers of audio data are transferred from the
* {@link AudioTrack} to the framework.
@@ -948,6 +1107,25 @@ public class AudioTrack extends PlayerBase
return this;
}
/**
* Sets the tuner configuration for the {@code AudioTrack}.
*
* The {@link AudioTrack.TunerConfiguration} consists of parameters obtained from
* the Android TV tuner API which indicate the audio content stream id and the
* synchronization id for the {@code AudioTrack}.
*
* @param tunerConfiguration obtained by {@link AudioTrack.TunerConfiguration.Builder}.
* @return the same Builder instance.
*/
public @NonNull Builder setTunerConfiguration(
@NonNull TunerConfiguration tunerConfiguration) {
if (tunerConfiguration == null) {
throw new IllegalArgumentException("tunerConfiguration is null");
}
mTunerConfiguration = tunerConfiguration;
return this;
}
/**
* Builds an {@link AudioTrack} instance initialized with all the parameters set
* on this <code>Builder</code>.
@@ -1003,6 +1181,8 @@ public class AudioTrack extends PlayerBase
}
}
// TODO: Check mEncapsulationMode compatibility with MODE_STATIC, etc?
try {
// If the buffer size is not specified in streaming mode,
// use a single frame for the buffer size and let the
@@ -1012,7 +1192,8 @@ public class AudioTrack extends PlayerBase
* mFormat.getBytesPerSample(mFormat.getEncoding());
}
final AudioTrack track = new AudioTrack(
mAttributes, mFormat, mBufferSizeInBytes, mMode, mSessionId, mOffload);
mAttributes, mFormat, mBufferSizeInBytes, mMode, mSessionId, mOffload,
mEncapsulationMode, mTunerConfiguration);
if (track.getState() == STATE_UNINITIALIZED) {
// release is not necessary
throw new UnsupportedOperationException("Cannot create AudioTrack");
@@ -3595,7 +3776,7 @@ public class AudioTrack extends PlayerBase
Object /*AudioAttributes*/ attributes,
int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat,
int buffSizeInBytes, int mode, int[] sessionId, long nativeAudioTrack,
boolean offload);
boolean offload, int encapsulationMode, Object tunerConfiguration);
private native final void native_finalize();