summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Andy Hung <hunga@google.com> 2020-01-14 17:29:03 -0800
committer Andy Hung <hunga@google.com> 2020-01-16 12:30:26 -0800
commit59dffec3f16bdfad8c882fbabfa907eb1b2f875c (patch)
tree008e3b3cdc9c1fd80fdc3a124e59829c78b96f56
parent72973ef6e87cc960e0568833147f954bd0f33871 (diff)
AudioTrack: Add Tuner Configuration methods
Test: atest AudioTrackTest#testTunerConfiguration Bug: 133526565 Change-Id: I0cc8e9e8b780e1a87c38656c8dfc67dac03969d8
-rw-r--r--api/current.txt17
-rw-r--r--core/jni/android_media_AudioTrack.cpp221
-rw-r--r--media/java/android/media/AudioTrack.java193
3 files changed, 340 insertions, 91 deletions
diff --git a/api/current.txt b/api/current.txt
index 16a9e49da032..77de35f66fc4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -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);
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index c979133d2493..041019ec4841 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -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;
}
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 0ced68ef8695..4dbc79b54199 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -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
@@ -758,6 +794,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
* attributes and audio format parameters, you indicate which of those vary from the default
@@ -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.
@@ -869,6 +1000,34 @@ public class AudioTrack extends PlayerBase
}
/**
+ * 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.
* @param mode one of {@link AudioTrack#MODE_STREAM}, {@link AudioTrack#MODE_STATIC}.
@@ -949,6 +1108,25 @@ public class AudioTrack extends PlayerBase
}
/**
+ * 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>.
* @return a new successfully initialized {@link AudioTrack} instance.
@@ -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();