Enable JAudioTrack.

MediaPlayer2 AudioOutput using public APIs.

Bug: 112549970
Test: android.media.cts.MediaPlayer2Test, android.media.cts.RoutingTest
Change-Id: Id76d80c040a52fd2ab724999697e222495906aec
diff --git a/media/libmedia/include/media/JAudioAttributes.h b/media/libmedia/include/media/JAudioAttributes.h
index fb11435..ea0aaa3 100644
--- a/media/libmedia/include/media/JAudioAttributes.h
+++ b/media/libmedia/include/media/JAudioAttributes.h
@@ -26,8 +26,7 @@
 public:
     /* Creates a Java AudioAttributes object. */
     static jobject createAudioAttributesObj(JNIEnv *env,
-                                            const audio_attributes_t* pAttributes,
-                                            audio_stream_type_t streamType) {
+                                            const audio_attributes_t* pAttributes) {
 
         jclass jBuilderCls = env->FindClass("android/media/AudioAttributes$Builder");
         jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
@@ -58,11 +57,6 @@
             // TODO: Handle the 'tags' (char[] to HashSet<String>).
             // How to parse the char[]? Is there any example of it?
             // Also, the addTags() method is hidden.
-        } else {
-            // Call AudioAttributes.Builder.setLegacyStreamType().build()
-            jmethodID jSetLegacyStreamType = env->GetMethodID(jBuilderCls, "setLegacyStreamType",
-                    "(I)Landroid/media/AudioAttributes$Builder;");
-            jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetLegacyStreamType, streamType);
         }
 
         jmethodID jBuild = env->GetMethodID(jBuilderCls, "build",
diff --git a/media/libmediaplayer2/Android.bp b/media/libmediaplayer2/Android.bp
index 75d1df0..2109ad1 100644
--- a/media/libmediaplayer2/Android.bp
+++ b/media/libmediaplayer2/Android.bp
@@ -59,6 +59,7 @@
         "libstagefright_player2",
         "libstagefright_rtsp",
         "libstagefright_timedtext2",
+        "libmedia2_jni_core",
     ],
 
     export_include_dirs: [
diff --git a/media/libmediaplayer2/JAudioTrack.cpp b/media/libmediaplayer2/JAudioTrack.cpp
index 778ae1b..5c0c6ea 100644
--- a/media/libmediaplayer2/JAudioTrack.cpp
+++ b/media/libmediaplayer2/JAudioTrack.cpp
@@ -28,7 +28,6 @@
 // TODO: Store Java class/methodID as a member variable in the class.
 // TODO: Add NULL && Exception checks after every JNI call.
 JAudioTrack::JAudioTrack(                             // < Usages of the arguments are below >
-        audio_stream_type_t streamType,               // AudioAudioAttributes
         uint32_t sampleRate,                          // AudioFormat && bufferSizeInBytes
         audio_format_t format,                        // AudioFormat && bufferSizeInBytes
         audio_channel_mask_t channelMask,             // AudioFormat && bufferSizeInBytes
@@ -40,8 +39,10 @@
         float maxRequiredSpeed) {                     // bufferSizeInBytes
 
     JNIEnv *env = JavaVMHelper::getJNIEnv();
+
     jclass jAudioTrackCls = env->FindClass("android/media/AudioTrack");
-    mAudioTrackCls = (jclass) env->NewGlobalRef(jAudioTrackCls);
+    mAudioTrackCls = reinterpret_cast<jclass>(env->NewGlobalRef(jAudioTrackCls));
+    env->DeleteLocalRef(jAudioTrackCls);
 
     maxRequiredSpeed = std::min(std::max(maxRequiredSpeed, 1.0f), AUDIO_TIMESTRETCH_SPEED_MAX);
 
@@ -64,10 +65,13 @@
     jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
     jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
 
+    jobject jAudioAttributesObj = JAudioAttributes::createAudioAttributesObj(env, pAttributes);
+    mAudioAttributesObj = reinterpret_cast<jobject>(env->NewGlobalRef(jAudioAttributesObj));
+    env->DeleteLocalRef(jAudioAttributesObj);
+
     jmethodID jSetAudioAttributes = env->GetMethodID(jBuilderCls, "setAudioAttributes",
             "(Landroid/media/AudioAttributes;)Landroid/media/AudioTrack$Builder;");
-    jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetAudioAttributes,
-            JAudioAttributes::createAudioAttributesObj(env, pAttributes, streamType));
+    jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetAudioAttributes, mAudioAttributesObj);
 
     jmethodID jSetAudioFormat = env->GetMethodID(jBuilderCls, "setAudioFormat",
             "(Landroid/media/AudioFormat;)Landroid/media/AudioTrack$Builder;");
@@ -100,7 +104,9 @@
     }
 
     jmethodID jBuild = env->GetMethodID(jBuilderCls, "build", "()Landroid/media/AudioTrack;");
-    mAudioTrackObj = env->CallObjectMethod(jBuilderObj, jBuild);
+    jobject jAudioTrackObj = env->CallObjectMethod(jBuilderObj, jBuild);
+    mAudioTrackObj = reinterpret_cast<jobject>(env->NewGlobalRef(jAudioTrackObj));
+    env->DeleteLocalRef(jBuilderObj);
 
     if (cbf != NULL) {
         // Set offload mode callback
@@ -118,6 +124,8 @@
 JAudioTrack::~JAudioTrack() {
     JNIEnv *env = JavaVMHelper::getJNIEnv();
     env->DeleteGlobalRef(mAudioTrackCls);
+    env->DeleteGlobalRef(mAudioTrackObj);
+    env->DeleteGlobalRef(mAudioAttributesObj);
 }
 
 size_t JAudioTrack::frameCount() {
@@ -151,21 +159,21 @@
     return NO_ERROR;
 }
 
-bool JAudioTrack::getTimestamp(AudioTimestamp& timestamp) {
+status_t JAudioTrack::getTimestamp(AudioTimestamp& timestamp) {
     JNIEnv *env = JavaVMHelper::getJNIEnv();
 
     jclass jAudioTimeStampCls = env->FindClass("android/media/AudioTimestamp");
     jobject jAudioTimeStampObj = env->AllocObject(jAudioTimeStampCls);
 
-    jfieldID jFramePosition = env->GetFieldID(jAudioTimeStampCls, "framePosition", "L");
-    jfieldID jNanoTime = env->GetFieldID(jAudioTimeStampCls, "nanoTime", "L");
+    jfieldID jFramePosition = env->GetFieldID(jAudioTimeStampCls, "framePosition", "J");
+    jfieldID jNanoTime = env->GetFieldID(jAudioTimeStampCls, "nanoTime", "J");
 
     jmethodID jGetTimestamp = env->GetMethodID(mAudioTrackCls,
-            "getTimestamp", "(Landroid/media/AudioTimestamp)B");
+            "getTimestamp", "(Landroid/media/AudioTimestamp;)Z");
     bool success = env->CallBooleanMethod(mAudioTrackObj, jGetTimestamp, jAudioTimeStampObj);
 
     if (!success) {
-        return false;
+        return NO_INIT;
     }
 
     long long framePosition = env->GetLongField(jAudioTimeStampObj, jFramePosition);
@@ -178,7 +186,7 @@
     timestamp.mTime = ts;
     timestamp.mPosition = (uint32_t) framePosition;
 
-    return true;
+    return NO_ERROR;
 }
 
 status_t JAudioTrack::getTimestamp(ExtendedTimestamp *timestamp __unused) {
@@ -423,6 +431,35 @@
     return audioFormatToNative(javaFormat);
 }
 
+size_t JAudioTrack::frameSize() {
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
+
+    // TODO: Calculated here implementing the logic in AudioTrack.java
+    // wait for AudioTrack.java exposing this parameter (i.e. getFrameSizeInBtytes())
+    jmethodID jGetAudioFormat = env->GetMethodID(mAudioTrackCls, "getAudioFormat", "()I");
+    int javaFormat = env->CallIntMethod(mAudioTrackObj, jGetAudioFormat);
+
+    jclass jAudioFormatCls = env->FindClass("android/media/AudioFormat");
+    jmethodID jIsEncodingLinearFrames = env->GetStaticMethodID(
+            jAudioFormatCls, "isEncodingLinearFrames", "(I)Z");
+    jboolean javaIsEncodingLinearFrames = env->CallStaticBooleanMethod(
+            jAudioFormatCls, jIsEncodingLinearFrames, javaFormat);
+
+    if (javaIsEncodingLinearFrames == false) {
+        return 1;
+    }
+
+    jmethodID jGetBytesPerSample = env->GetStaticMethodID(jAudioFormatCls,
+            "getBytesPerSample", "(I)I");
+    int javaBytesPerSample = env->CallStaticIntMethod(jAudioFormatCls,
+            jGetBytesPerSample, javaFormat);
+
+    jmethodID jGetChannelCount = env->GetMethodID(mAudioTrackCls, "getChannelCount", "()I");
+    int javaChannelCount = env->CallIntMethod(mAudioTrackObj, jGetChannelCount);
+
+    return javaChannelCount * javaBytesPerSample;
+}
+
 status_t JAudioTrack::dump(int fd, const Vector<String16>& args __unused) const
 {
     String8 result;
@@ -432,10 +469,6 @@
     // TODO: Remove logs that includes unavailable information from below.
 //    result.appendFormat("  status(%d), state(%d), session Id(%d), flags(%#x)\n",
 //                        mStatus, mState, mSessionId, mFlags);
-//    result.appendFormat("  stream type(%d), left - right volume(%f, %f)\n",
-//                        (mStreamType == AUDIO_STREAM_DEFAULT) ?
-//                                audio_attributes_to_stream_type(&mAttributes) : mStreamType,
-//                        mVolume[AUDIO_INTERLEAVE_LEFT], mVolume[AUDIO_INTERLEAVE_RIGHT]);
 //    result.appendFormat("  format(%#x), channel mask(%#x), channel count(%u)\n",
 //                  format(), mChannelMask, channelCount());
 //    result.appendFormat("  sample rate(%u), original sample rate(%u), speed(%f)\n",
@@ -462,7 +495,7 @@
         return AUDIO_PORT_HANDLE_NONE;
     }
 
-    jclass jAudioDeviceInfoCls = env->FindClass("Landroid/media/AudioDeviceInfo");
+    jclass jAudioDeviceInfoCls = env->FindClass("android/media/AudioDeviceInfo");
     jmethodID jGetId = env->GetMethodID(jAudioDeviceInfoCls, "getId", "()I");
     jint routedDeviceId = env->CallIntMethod(jAudioDeviceInfoObj, jGetId);
     return routedDeviceId;
@@ -478,13 +511,22 @@
 status_t JAudioTrack::setOutputDevice(audio_port_handle_t deviceId) {
     JNIEnv *env = JavaVMHelper::getJNIEnv();
     jclass jMP2ImplCls = env->FindClass("android/media/MediaPlayer2Impl");
-    jmethodID jSetAudioOutputDeviceById = env->GetMethodID(
+    jmethodID jSetAudioOutputDeviceById = env->GetStaticMethodID(
             jMP2ImplCls, "setAudioOutputDeviceById", "(Landroid/media/AudioTrack;I)Z");
     jboolean result = env->CallStaticBooleanMethod(
             jMP2ImplCls, jSetAudioOutputDeviceById, mAudioTrackObj, deviceId);
     return result == true ? NO_ERROR : BAD_VALUE;
 }
 
+audio_stream_type_t JAudioTrack::getAudioStreamType() {
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
+    jclass jAudioAttributesCls = env->FindClass("android/media/AudioAttributes");
+    jmethodID jGetVolumeControlStream = env->GetMethodID(jAudioAttributesCls,
+                                        "getVolumeControlStream", "()I");
+    int javaAudioStreamType = env->CallIntMethod(mAudioAttributesObj, jGetVolumeControlStream);
+    return (audio_stream_type_t)javaAudioStreamType;
+}
+
 status_t JAudioTrack::pendingDuration(int32_t *msec) {
     if (msec == nullptr) {
         return BAD_VALUE;
@@ -526,18 +568,85 @@
     return NO_ERROR;
 }
 
-status_t JAudioTrack::addAudioDeviceCallback(
-        const sp<AudioSystem::AudioDeviceCallback>& callback __unused) {
-    // TODO: Implement this after appropriate Java AudioTrack method is available.
+status_t JAudioTrack::addAudioDeviceCallback(jobject listener, jobject handler) {
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
+    jmethodID jAddOnRoutingChangedListener = env->GetMethodID(mAudioTrackCls,
+            "addOnRoutingChangedListener",
+            "(Landroid/media/AudioRouting$OnRoutingChangedListener;Landroid/os/Handler;)V");
+    env->CallVoidMethod(mAudioTrackObj, jAddOnRoutingChangedListener, listener, handler);
     return NO_ERROR;
 }
 
-status_t JAudioTrack::removeAudioDeviceCallback(
-        const sp<AudioSystem::AudioDeviceCallback>& callback __unused) {
-    // TODO: Implement this after appropriate Java AudioTrack method is available.
+status_t JAudioTrack::removeAudioDeviceCallback(jobject listener) {
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
+    jmethodID jRemoveOnRoutingChangedListener = env->GetMethodID(mAudioTrackCls,
+            "removeOnRoutingChangedListener",
+            "(Landroid/media/AudioRouting$OnRoutingChangedListener;)V");
+    env->CallVoidMethod(mAudioTrackObj, jRemoveOnRoutingChangedListener, listener);
     return NO_ERROR;
 }
 
+void JAudioTrack::registerRoutingDelegates(
+        std::vector<std::pair<jobject, jobject>>& routingDelegates) {
+    for (std::vector<std::pair<jobject, jobject>>::iterator it = routingDelegates.begin();
+            it != routingDelegates.end(); it++) {
+        addAudioDeviceCallback(it->second, getHandler(it->second));
+    }
+}
+
+/////////////////////////////////////////////////////////////
+///                Static methods begin                   ///
+/////////////////////////////////////////////////////////////
+jobject JAudioTrack::getListener(const jobject routingDelegateObj) {
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
+    jclass jRoutingDelegateCls = env->FindClass("android/media/RoutingDelegate");
+    jmethodID jGetListener = env->GetMethodID(jRoutingDelegateCls,
+            "getListener", "()Landroid/media/AudioRouting$OnRoutingChangedListener;");
+    return env->CallObjectMethod(routingDelegateObj, jGetListener);
+}
+
+jobject JAudioTrack::getHandler(const jobject routingDelegateObj) {
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
+    jclass jRoutingDelegateCls = env->FindClass("android/media/RoutingDelegate");
+    jmethodID jGetHandler = env->GetMethodID(jRoutingDelegateCls,
+        "getHandler", "()Landroid/os/Handler;");
+    return env->CallObjectMethod(routingDelegateObj, jGetHandler);
+}
+
+jobject JAudioTrack::addGlobalRef(const jobject obj) {
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
+    return reinterpret_cast<jobject>(env->NewGlobalRef(obj));
+}
+
+status_t JAudioTrack::removeGlobalRef(const jobject obj) {
+    if (obj == NULL) {
+        return BAD_VALUE;
+    }
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
+    env->DeleteGlobalRef(obj);
+    return NO_ERROR;
+}
+
+jobject JAudioTrack::findByKey(std::vector<std::pair<jobject, jobject>>& mp, const jobject key) {
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
+    for (std::vector<std::pair<jobject, jobject>>::iterator it = mp.begin(); it != mp.end(); it++) {
+        if (env->IsSameObject(it->first, key)) {
+            return it->second;
+        }
+    }
+    return nullptr;
+}
+
+void JAudioTrack::eraseByKey(std::vector<std::pair<jobject, jobject>>& mp, const jobject key) {
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
+    for (std::vector<std::pair<jobject, jobject>>::iterator it = mp.begin(); it != mp.end(); it++) {
+        if (env->IsSameObject(it->first, key)) {
+            mp.erase(it);
+            return;
+        }
+    }
+}
+
 /////////////////////////////////////////////////////////////
 ///                Private method begins                  ///
 /////////////////////////////////////////////////////////////
diff --git a/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp b/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
index 6b27ca7..9218fce 100644
--- a/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
+++ b/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
@@ -23,7 +23,6 @@
 #include <utils/Log.h>
 
 #include <media/AudioPolicyHelper.h>
-#include <media/AudioTrack.h>
 #include <media/stagefright/foundation/ADebug.h>
 
 namespace {
@@ -44,29 +43,27 @@
     String8 result;
 
     result.append(" MediaPlayer2AudioOutput\n");
-    snprintf(buffer, 255, "  stream type(%d), volume(%f)\n",
-            mStreamType, mVolume);
+    snprintf(buffer, 255, "  volume(%f)\n", mVolume);
     result.append(buffer);
     snprintf(buffer, 255, "  msec per frame(%f), latency (%d)\n",
-            mMsecsPerFrame, (mTrack != 0) ? mTrack->latency() : -1);
+            mMsecsPerFrame, (mJAudioTrack != nullptr) ? mJAudioTrack->latency() : -1);
     result.append(buffer);
     snprintf(buffer, 255, "  aux effect id(%d), send level (%f)\n",
             mAuxEffectId, mSendLevel);
     result.append(buffer);
 
     ::write(fd, result.string(), result.size());
-    if (mTrack != 0) {
-        mTrack->dump(fd, args);
+    if (mJAudioTrack != nullptr) {
+        mJAudioTrack->dump(fd, args);
     }
     return NO_ERROR;
 }
 
 MediaPlayer2AudioOutput::MediaPlayer2AudioOutput(audio_session_t sessionId, uid_t uid, int pid,
-        const audio_attributes_t* attr, const sp<AudioSystem::AudioDeviceCallback>& deviceCallback)
-    : mCallback(NULL),
-      mCallbackCookie(NULL),
-      mCallbackData(NULL),
-      mStreamType(AUDIO_STREAM_MUSIC),
+        const audio_attributes_t* attr, std::vector<jobject>& routingDelegatesBackup)
+    : mCallback(nullptr),
+      mCallbackCookie(nullptr),
+      mCallbackData(nullptr),
       mVolume(1.0),
       mPlaybackRate(AUDIO_PLAYBACK_RATE_DEFAULT),
       mSampleRateHz(0),
@@ -79,24 +76,30 @@
       mAuxEffectId(0),
       mFlags(AUDIO_OUTPUT_FLAG_NONE),
       mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
-      mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
-      mDeviceCallbackEnabled(false),
-      mDeviceCallback(deviceCallback) {
+      mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE) {
     ALOGV("MediaPlayer2AudioOutput(%d)", sessionId);
-    if (attr != NULL) {
+    if (attr != nullptr) {
         mAttributes = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
-        if (mAttributes != NULL) {
+        if (mAttributes != nullptr) {
             memcpy(mAttributes, attr, sizeof(audio_attributes_t));
-            mStreamType = audio_attributes_to_stream_type(attr);
         }
     } else {
-        mAttributes = NULL;
+        mAttributes = nullptr;
     }
 
     setMinBufferCount();
+    mRoutingDelegates.clear();
+    for (auto routingDelegate : routingDelegatesBackup) {
+        mRoutingDelegates.push_back(std::pair<jobject, jobject>(
+                JAudioTrack::getListener(routingDelegate), routingDelegate));
+    }
+    routingDelegatesBackup.clear();
 }
 
 MediaPlayer2AudioOutput::~MediaPlayer2AudioOutput() {
+    for (auto routingDelegate : mRoutingDelegates) {
+        JAudioTrack::removeGlobalRef(routingDelegate.second);
+    }
     close();
     free(mAttributes);
     delete mCallbackData;
@@ -125,31 +128,31 @@
 
 ssize_t MediaPlayer2AudioOutput::bufferSize() const {
     Mutex::Autolock lock(mLock);
-    if (mTrack == 0) {
+    if (mJAudioTrack == nullptr) {
         return NO_INIT;
     }
-    return mTrack->frameCount() * mFrameSize;
+    return mJAudioTrack->frameCount() * mFrameSize;
 }
 
 ssize_t MediaPlayer2AudioOutput::frameCount() const {
     Mutex::Autolock lock(mLock);
-    if (mTrack == 0) {
+    if (mJAudioTrack == nullptr) {
         return NO_INIT;
     }
-    return mTrack->frameCount();
+    return mJAudioTrack->frameCount();
 }
 
 ssize_t MediaPlayer2AudioOutput::channelCount() const {
     Mutex::Autolock lock(mLock);
-    if (mTrack == 0) {
+    if (mJAudioTrack == nullptr) {
         return NO_INIT;
     }
-    return mTrack->channelCount();
+    return mJAudioTrack->channelCount();
 }
 
 ssize_t MediaPlayer2AudioOutput::frameSize() const {
     Mutex::Autolock lock(mLock);
-    if (mTrack == 0) {
+    if (mJAudioTrack == nullptr) {
         return NO_INIT;
     }
     return mFrameSize;
@@ -157,10 +160,10 @@
 
 uint32_t MediaPlayer2AudioOutput::latency () const {
     Mutex::Autolock lock(mLock);
-    if (mTrack == 0) {
+    if (mJAudioTrack == nullptr) {
         return 0;
     }
-    return mTrack->latency();
+    return mJAudioTrack->latency();
 }
 
 float MediaPlayer2AudioOutput::msecsPerFrame() const {
@@ -170,18 +173,18 @@
 
 status_t MediaPlayer2AudioOutput::getPosition(uint32_t *position) const {
     Mutex::Autolock lock(mLock);
-    if (mTrack == 0) {
+    if (mJAudioTrack == nullptr) {
         return NO_INIT;
     }
-    return mTrack->getPosition(position);
+    return mJAudioTrack->getPosition(position);
 }
 
 status_t MediaPlayer2AudioOutput::getTimestamp(AudioTimestamp &ts) const {
     Mutex::Autolock lock(mLock);
-    if (mTrack == 0) {
+    if (mJAudioTrack == nullptr) {
         return NO_INIT;
     }
-    return mTrack->getTimestamp(ts);
+    return mJAudioTrack->getTimestamp(ts);
 }
 
 // TODO: Remove unnecessary calls to getPlayedOutDurationUs()
@@ -194,7 +197,7 @@
 // Calculate duration of played samples if played at normal rate (i.e., 1.0).
 int64_t MediaPlayer2AudioOutput::getPlayedOutDurationUs(int64_t nowUs) const {
     Mutex::Autolock lock(mLock);
-    if (mTrack == 0 || mSampleRateHz == 0) {
+    if (mJAudioTrack == nullptr || mSampleRateHz == 0) {
         return 0;
     }
 
@@ -202,22 +205,18 @@
     int64_t numFramesPlayedAtUs;
     AudioTimestamp ts;
 
-    status_t res = mTrack->getTimestamp(ts);
+    status_t res = mJAudioTrack->getTimestamp(ts);
+
     if (res == OK) {                 // case 1: mixing audio tracks and offloaded tracks.
         numFramesPlayed = ts.mPosition;
         numFramesPlayedAtUs = ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000;
         //ALOGD("getTimestamp: OK %d %lld", numFramesPlayed, (long long)numFramesPlayedAtUs);
-    } else if (res == WOULD_BLOCK) { // case 2: transitory state on start of a new track
+    } else {                         // case 2: transitory state on start of a new track
+                                     // case 3: transitory at new track or audio fast tracks.
         numFramesPlayed = 0;
         numFramesPlayedAtUs = nowUs;
         //ALOGD("getTimestamp: WOULD_BLOCK %d %lld",
         //        numFramesPlayed, (long long)numFramesPlayedAtUs);
-    } else {                         // case 3: transitory at new track or audio fast tracks.
-        res = mTrack->getPosition(&numFramesPlayed);
-        CHECK_EQ(res, (status_t)OK);
-        numFramesPlayedAtUs = nowUs;
-        numFramesPlayedAtUs += 1000LL * mTrack->latency() / 2; /* XXX */
-        //ALOGD("getPosition: %u %lld", numFramesPlayed, (long long)numFramesPlayedAtUs);
     }
 
     // CHECK_EQ(numFramesPlayed & (1 << 31), 0);  // can't be negative until 12.4 hrs, test
@@ -243,57 +242,41 @@
 
 status_t MediaPlayer2AudioOutput::getFramesWritten(uint32_t *frameswritten) const {
     Mutex::Autolock lock(mLock);
-    if (mTrack == 0) {
+    if (mJAudioTrack == nullptr) {
         return NO_INIT;
     }
     ExtendedTimestamp ets;
-    status_t status = mTrack->getTimestamp(&ets);
+    status_t status = mJAudioTrack->getTimestamp(&ets);
     if (status == OK || status == WOULD_BLOCK) {
         *frameswritten = (uint32_t)ets.mPosition[ExtendedTimestamp::LOCATION_CLIENT];
     }
     return status;
 }
 
-status_t MediaPlayer2AudioOutput::setParameters(const String8& keyValuePairs) {
-    Mutex::Autolock lock(mLock);
-    if (mTrack == 0) {
-        return NO_INIT;
-    }
-    return mTrack->setParameters(keyValuePairs);
-}
-
-String8  MediaPlayer2AudioOutput::getParameters(const String8& keys) {
-    Mutex::Autolock lock(mLock);
-    if (mTrack == 0) {
-        return String8::empty();
-    }
-    return mTrack->getParameters(keys);
-}
-
 void MediaPlayer2AudioOutput::setAudioAttributes(const audio_attributes_t * attributes) {
     Mutex::Autolock lock(mLock);
-    if (attributes == NULL) {
+    if (attributes == nullptr) {
         free(mAttributes);
-        mAttributes = NULL;
+        mAttributes = nullptr;
     } else {
-        if (mAttributes == NULL) {
+        if (mAttributes == nullptr) {
             mAttributes = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
         }
         memcpy(mAttributes, attributes, sizeof(audio_attributes_t));
-        mStreamType = audio_attributes_to_stream_type(attributes);
     }
 }
 
-void MediaPlayer2AudioOutput::setAudioStreamType(audio_stream_type_t streamType) {
+audio_stream_type_t MediaPlayer2AudioOutput::getAudioStreamType() const {
+    ALOGV("getAudioStreamType");
     Mutex::Autolock lock(mLock);
-    // do not allow direct stream type modification if attributes have been set
-    if (mAttributes == NULL) {
-        mStreamType = streamType;
+    if (mJAudioTrack == nullptr) {
+        return AUDIO_STREAM_DEFAULT;
     }
+    return mJAudioTrack->getAudioStreamType();
 }
 
 void MediaPlayer2AudioOutput::close_l() {
-    mTrack.clear();
+    mJAudioTrack.clear();
 }
 
 status_t MediaPlayer2AudioOutput::open(
@@ -302,7 +285,6 @@
         AudioCallback cb, void *cookie,
         audio_output_flags_t flags,
         const audio_offload_info_t *offloadInfo,
-        bool doNotReconnect,
         uint32_t suggestedFrameCount) {
     ALOGV("open(%u, %d, 0x%x, 0x%x, %d 0x%x)", sampleRate, channelCount, channelMask,
                 format, mSessionId, flags);
@@ -310,7 +292,7 @@
     // offloading is only supported in callback mode for now.
     // offloadInfo must be present if offload flag is set
     if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) &&
-            ((cb == NULL) || (offloadInfo == NULL))) {
+            ((cb == nullptr) || (offloadInfo == nullptr))) {
         return BAD_VALUE;
     }
 
@@ -330,32 +312,23 @@
     mCallback = cb;
     mCallbackCookie = cookie;
 
-    sp<AudioTrack> t;
-    CallbackData *newcbd = NULL;
+    sp<JAudioTrack> jT;
+    CallbackData *newcbd = nullptr;
 
-    ALOGV("creating new AudioTrack");
+    ALOGV("creating new JAudioTrack");
 
-    if (mCallback != NULL) {
+    if (mCallback != nullptr) {
         newcbd = new CallbackData(this);
-        t = new AudioTrack(
-                mStreamType,
-                sampleRate,
-                format,
-                channelMask,
-                frameCount,
-                flags,
-                CallbackWrapper,
-                newcbd,
-                0,  // notification frames
-                mSessionId,
-                AudioTrack::TRANSFER_CALLBACK,
-                offloadInfo,
-                mUid,
-                mPid,
-                mAttributes,
-                doNotReconnect,
-                1.0f,  // default value for maxRequiredSpeed
-                mSelectedDeviceId);
+        jT = new JAudioTrack(
+                 sampleRate,
+                 format,
+                 channelMask,
+                 CallbackWrapper,
+                 newcbd,
+                 frameCount,
+                 mSessionId,
+                 mAttributes,
+                 1.0f);  // default value for maxRequiredSpeed
     } else {
         // TODO: Due to buffer memory concerns, we use a max target playback speed
         // based on mPlaybackRate at the time of open (instead of kMaxRequiredSpeed),
@@ -365,73 +338,60 @@
         ALOGW_IF(targetSpeed != mPlaybackRate.mSpeed,
                 "track target speed:%f clamped from playback speed:%f",
                 targetSpeed, mPlaybackRate.mSpeed);
-        t = new AudioTrack(
-                mStreamType,
-                sampleRate,
-                format,
-                channelMask,
-                frameCount,
-                flags,
-                NULL, // callback
-                NULL, // user data
-                0, // notification frames
-                mSessionId,
-                AudioTrack::TRANSFER_DEFAULT,
-                NULL, // offload info
-                mUid,
-                mPid,
-                mAttributes,
-                doNotReconnect,
-                targetSpeed,
-                mSelectedDeviceId);
+        jT = new JAudioTrack(
+                 sampleRate,
+                 format,
+                 channelMask,
+                 nullptr,
+                 nullptr,
+                 frameCount,
+                 mSessionId,
+                 mAttributes,
+                 targetSpeed);
     }
 
-    if ((t == 0) || (t->initCheck() != NO_ERROR)) {
+    if (jT == 0) {
         ALOGE("Unable to create audio track");
         delete newcbd;
         // t goes out of scope, so reference count drops to zero
         return NO_INIT;
-    } else {
-        // successful AudioTrack initialization implies a legacy stream type was generated
-        // from the audio attributes
-        mStreamType = t->streamType();
     }
 
-    CHECK((t != NULL) && ((mCallback == NULL) || (newcbd != NULL)));
+    CHECK((jT != nullptr) && ((mCallback == nullptr) || (newcbd != nullptr)));
 
     mCallbackData = newcbd;
     ALOGV("setVolume");
-    t->setVolume(mVolume);
+    jT->setVolume(mVolume);
 
     mSampleRateHz = sampleRate;
     mFlags = flags;
     mMsecsPerFrame = 1E3f / (mPlaybackRate.mSpeed * sampleRate);
-    mFrameSize = t->frameSize();
-    mTrack = t;
+    mFrameSize = jT->frameSize();
+    mJAudioTrack = jT;
 
     return updateTrack_l();
 }
 
 status_t MediaPlayer2AudioOutput::updateTrack_l() {
-    if (mTrack == NULL) {
+    if (mJAudioTrack == nullptr) {
         return NO_ERROR;
     }
 
     status_t res = NO_ERROR;
     // Note some output devices may give us a direct track even though we don't specify it.
     // Example: Line application b/17459982.
-    if ((mTrack->getFlags()
+    if ((mJAudioTrack->getFlags()
             & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD | AUDIO_OUTPUT_FLAG_DIRECT)) == 0) {
-        res = mTrack->setPlaybackRate(mPlaybackRate);
+        res = mJAudioTrack->setPlaybackRate(mPlaybackRate);
         if (res == NO_ERROR) {
-            mTrack->setAuxEffectSendLevel(mSendLevel);
-            res = mTrack->attachAuxEffect(mAuxEffectId);
+            mJAudioTrack->setAuxEffectSendLevel(mSendLevel);
+            res = mJAudioTrack->attachAuxEffect(mAuxEffectId);
         }
     }
-    mTrack->setOutputDevice(mSelectedDeviceId);
-    if (mDeviceCallbackEnabled) {
-        mTrack->addAudioDeviceCallback(mDeviceCallback.promote());
-    }
+    mJAudioTrack->setOutputDevice(mSelectedDeviceId);
+
+    mJAudioTrack->registerRoutingDelegates(mRoutingDelegates);
+
     ALOGV("updateTrack_l() DONE status %d", res);
     return res;
 }
@@ -439,13 +399,13 @@
 status_t MediaPlayer2AudioOutput::start() {
     ALOGV("start");
     Mutex::Autolock lock(mLock);
-    if (mCallbackData != NULL) {
+    if (mCallbackData != nullptr) {
         mCallbackData->endTrackSwitch();
     }
-    if (mTrack != 0) {
-        mTrack->setVolume(mVolume);
-        mTrack->setAuxEffectSendLevel(mSendLevel);
-        status_t status = mTrack->start();
+    if (mJAudioTrack != nullptr) {
+        mJAudioTrack->setVolume(mVolume);
+        mJAudioTrack->setAuxEffectSendLevel(mSendLevel);
+        status_t status = mJAudioTrack->start();
         return status;
     }
     return NO_INIT;
@@ -453,11 +413,11 @@
 
 ssize_t MediaPlayer2AudioOutput::write(const void* buffer, size_t size, bool blocking) {
     Mutex::Autolock lock(mLock);
-    LOG_ALWAYS_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback.");
+    LOG_ALWAYS_FATAL_IF(mCallback != nullptr, "Don't call write if supplying a callback.");
 
     //ALOGV("write(%p, %u)", buffer, size);
-    if (mTrack != 0) {
-        return mTrack->write(buffer, size, blocking);
+    if (mJAudioTrack != nullptr) {
+        return mJAudioTrack->write(buffer, size, blocking);
     }
     return NO_INIT;
 }
@@ -465,34 +425,34 @@
 void MediaPlayer2AudioOutput::stop() {
     ALOGV("stop");
     Mutex::Autolock lock(mLock);
-    if (mTrack != 0) {
-        mTrack->stop();
+    if (mJAudioTrack != nullptr) {
+        mJAudioTrack->stop();
     }
 }
 
 void MediaPlayer2AudioOutput::flush() {
     ALOGV("flush");
     Mutex::Autolock lock(mLock);
-    if (mTrack != 0) {
-        mTrack->flush();
+    if (mJAudioTrack != nullptr) {
+        mJAudioTrack->flush();
     }
 }
 
 void MediaPlayer2AudioOutput::pause() {
     ALOGV("pause");
     Mutex::Autolock lock(mLock);
-    if (mTrack != 0) {
-        mTrack->pause();
+    if (mJAudioTrack != nullptr) {
+        mJAudioTrack->pause();
     }
 }
 
 void MediaPlayer2AudioOutput::close() {
     ALOGV("close");
-    sp<AudioTrack> track;
+    sp<JAudioTrack> track;
     {
         Mutex::Autolock lock(mLock);
-        track = mTrack;
-        close_l(); // clears mTrack
+        track = mJAudioTrack;
+        close_l(); // clears mJAudioTrack
     }
     // destruction of the track occurs outside of mutex.
 }
@@ -501,8 +461,8 @@
     ALOGV("setVolume(%f)", volume);
     Mutex::Autolock lock(mLock);
     mVolume = volume;
-    if (mTrack != 0) {
-        mTrack->setVolume(volume);
+    if (mJAudioTrack != nullptr) {
+        mJAudioTrack->setVolume(volume);
     }
 }
 
@@ -510,12 +470,12 @@
     ALOGV("setPlaybackRate(%f %f %d %d)",
                 rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode);
     Mutex::Autolock lock(mLock);
-    if (mTrack == 0) {
+    if (mJAudioTrack == 0) {
         // remember rate so that we can set it when the track is opened
         mPlaybackRate = rate;
         return OK;
     }
-    status_t res = mTrack->setPlaybackRate(rate);
+    status_t res = mJAudioTrack->setPlaybackRate(rate);
     if (res != NO_ERROR) {
         return res;
     }
@@ -531,10 +491,10 @@
 status_t MediaPlayer2AudioOutput::getPlaybackRate(AudioPlaybackRate *rate) {
     ALOGV("getPlaybackRate");
     Mutex::Autolock lock(mLock);
-    if (mTrack == 0) {
+    if (mJAudioTrack == 0) {
         return NO_INIT;
     }
-    *rate = mTrack->getPlaybackRate();
+    *rate = mJAudioTrack->getPlaybackRate();
     return NO_ERROR;
 }
 
@@ -542,8 +502,8 @@
     ALOGV("setAuxEffectSendLevel(%f)", level);
     Mutex::Autolock lock(mLock);
     mSendLevel = level;
-    if (mTrack != 0) {
-        return mTrack->setAuxEffectSendLevel(level);
+    if (mJAudioTrack != nullptr) {
+        return mJAudioTrack->setAuxEffectSendLevel(level);
     }
     return NO_ERROR;
 }
@@ -552,8 +512,8 @@
     ALOGV("attachAuxEffect(%d)", effectId);
     Mutex::Autolock lock(mLock);
     mAuxEffectId = effectId;
-    if (mTrack != 0) {
-        return mTrack->attachAuxEffect(effectId);
+    if (mJAudioTrack != nullptr) {
+        return mJAudioTrack->attachAuxEffect(effectId);
     }
     return NO_ERROR;
 }
@@ -562,8 +522,8 @@
     ALOGV("setOutputDevice(%d)", deviceId);
     Mutex::Autolock lock(mLock);
     mSelectedDeviceId = deviceId;
-    if (mTrack != 0) {
-        return mTrack->setOutputDevice(deviceId);
+    if (mJAudioTrack != nullptr) {
+        return mJAudioTrack->setOutputDevice(deviceId);
     }
     return NO_ERROR;
 }
@@ -571,29 +531,51 @@
 status_t MediaPlayer2AudioOutput::getRoutedDeviceId(audio_port_handle_t* deviceId) {
     ALOGV("getRoutedDeviceId");
     Mutex::Autolock lock(mLock);
-    if (mTrack != 0) {
-        mRoutedDeviceId = mTrack->getRoutedDeviceId();
+    if (mJAudioTrack != nullptr) {
+        mRoutedDeviceId = mJAudioTrack->getRoutedDeviceId();
     }
     *deviceId = mRoutedDeviceId;
     return NO_ERROR;
 }
 
-status_t MediaPlayer2AudioOutput::enableAudioDeviceCallback(bool enabled) {
-    ALOGV("enableAudioDeviceCallback, %d", enabled);
+status_t MediaPlayer2AudioOutput::addAudioDeviceCallback(jobject jRoutingDelegate) {
+    ALOGV("addAudioDeviceCallback");
     Mutex::Autolock lock(mLock);
-    mDeviceCallbackEnabled = enabled;
-    if (mTrack != 0) {
-        status_t status;
-        if (enabled) {
-            status = mTrack->addAudioDeviceCallback(mDeviceCallback.promote());
-        } else {
-            status = mTrack->removeAudioDeviceCallback(mDeviceCallback.promote());
-        }
-        return status;
+    jobject listener = JAudioTrack::getListener(jRoutingDelegate);
+    if (mJAudioTrack != nullptr &&
+        JAudioTrack::findByKey(mRoutingDelegates, listener) == nullptr) {
+        jobject handler = JAudioTrack::getHandler(jRoutingDelegate);
+        jobject routingDelegate = JAudioTrack::addGlobalRef(jRoutingDelegate);
+        mRoutingDelegates.push_back(std::pair<jobject, jobject>(listener, routingDelegate));
+        return mJAudioTrack->addAudioDeviceCallback(routingDelegate, handler);
     }
     return NO_ERROR;
 }
 
+status_t MediaPlayer2AudioOutput::removeAudioDeviceCallback(jobject listener) {
+    ALOGV("removeAudioDeviceCallback");
+    Mutex::Autolock lock(mLock);
+    jobject routingDelegate = nullptr;
+    if (mJAudioTrack != nullptr &&
+        (routingDelegate = JAudioTrack::findByKey(mRoutingDelegates, listener)) != nullptr) {
+        mJAudioTrack->removeAudioDeviceCallback(routingDelegate);
+        JAudioTrack::eraseByKey(mRoutingDelegates, listener);
+        if (JAudioTrack::removeGlobalRef(routingDelegate) != NO_ERROR) {
+            return BAD_VALUE;
+        }
+    }
+    return NO_ERROR;
+}
+
+void MediaPlayer2AudioOutput::copyAudioDeviceCallback(
+        std::vector<jobject>& routingDelegateTarget) {
+    ALOGV("copyAudioDeviceCallback");
+    for (std::vector<std::pair<jobject, jobject>>::iterator it = mRoutingDelegates.begin();
+            it != mRoutingDelegates.end(); it++) {
+        routingDelegateTarget.push_back(it->second);
+    }
+}
+
 // static
 void MediaPlayer2AudioOutput::CallbackWrapper(
         int event, void *cookie, void *info) {
@@ -602,21 +584,21 @@
     // lock to ensure we aren't caught in the middle of a track switch.
     data->lock();
     MediaPlayer2AudioOutput *me = data->getOutput();
-    AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
-    if (me == NULL) {
+    JAudioTrack::Buffer *buffer = (JAudioTrack::Buffer *)info;
+    if (me == nullptr) {
         // no output set, likely because the track was scheduled to be reused
         // by another player, but the format turned out to be incompatible.
         data->unlock();
-        if (buffer != NULL) {
-            buffer->size = 0;
+        if (buffer != nullptr) {
+            buffer->mSize = 0;
         }
         return;
     }
 
     switch(event) {
-    case AudioTrack::EVENT_MORE_DATA: {
+    case JAudioTrack::EVENT_MORE_DATA: {
         size_t actualSize = (*me->mCallback)(
-                me, buffer->raw, buffer->size, me->mCallbackCookie,
+                me, buffer->mData, buffer->mSize, me->mCallbackCookie,
                 CB_EVENT_FILL_BUFFER);
 
         // Log when no data is returned from the callback.
@@ -628,25 +610,25 @@
         // This is a benign busy-wait, with the next data request generated 10 ms or more later;
         // nevertheless for power reasons, we don't want to see too many of these.
 
-        ALOGV_IF(actualSize == 0 && buffer->size > 0, "callbackwrapper: empty buffer returned");
+        ALOGV_IF(actualSize == 0 && buffer->mSize > 0, "callbackwrapper: empty buffer returned");
 
-        buffer->size = actualSize;
+        buffer->mSize = actualSize;
         } break;
 
-    case AudioTrack::EVENT_STREAM_END:
+    case JAudioTrack::EVENT_STREAM_END:
         // currently only occurs for offloaded callbacks
         ALOGV("callbackwrapper: deliver EVENT_STREAM_END");
-        (*me->mCallback)(me, NULL /* buffer */, 0 /* size */,
+        (*me->mCallback)(me, nullptr /* buffer */, 0 /* size */,
                 me->mCallbackCookie, CB_EVENT_STREAM_END);
         break;
 
-    case AudioTrack::EVENT_NEW_IAUDIOTRACK :
+    case JAudioTrack::EVENT_NEW_IAUDIOTRACK :
         ALOGV("callbackwrapper: deliver EVENT_TEAR_DOWN");
-        (*me->mCallback)(me,  NULL /* buffer */, 0 /* size */,
+        (*me->mCallback)(me,  nullptr /* buffer */, 0 /* size */,
                 me->mCallbackCookie, CB_EVENT_TEAR_DOWN);
         break;
 
-    case AudioTrack::EVENT_UNDERRUN:
+    case JAudioTrack::EVENT_UNDERRUN:
         // This occurs when there is no data available, typically
         // when there is a failure to supply data to the AudioTrack.  It can also
         // occur in non-offloaded mode when the audio device comes out of standby.
@@ -666,29 +648,26 @@
     data->unlock();
 }
 
-audio_session_t MediaPlayer2AudioOutput::getSessionId() const
-{
+audio_session_t MediaPlayer2AudioOutput::getSessionId() const {
     Mutex::Autolock lock(mLock);
     return mSessionId;
 }
 
-uint32_t MediaPlayer2AudioOutput::getSampleRate() const
-{
+uint32_t MediaPlayer2AudioOutput::getSampleRate() const {
     Mutex::Autolock lock(mLock);
-    if (mTrack == 0) {
+    if (mJAudioTrack == 0) {
         return 0;
     }
-    return mTrack->getSampleRate();
+    return mJAudioTrack->getSampleRate();
 }
 
-int64_t MediaPlayer2AudioOutput::getBufferDurationInUs() const
-{
+int64_t MediaPlayer2AudioOutput::getBufferDurationInUs() const {
     Mutex::Autolock lock(mLock);
-    if (mTrack == 0) {
+    if (mJAudioTrack == 0) {
         return 0;
     }
     int64_t duration;
-    if (mTrack->getBufferDurationInUs(&duration) != OK) {
+    if (mJAudioTrack->getBufferDurationInUs(&duration) != OK) {
         return 0;
     }
     return duration;
diff --git a/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h b/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h
index 301825b..629968f 100644
--- a/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h
+++ b/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_JAUDIOTRACK_H
 #define ANDROID_JAUDIOTRACK_H
 
+#include <vector>
+#include <utility>
 #include <jni.h>
 #include <media/AudioResamplerPublic.h>
 #include <media/AudioSystem.h>
@@ -29,7 +31,7 @@
 
 namespace android {
 
-class JAudioTrack {
+class JAudioTrack : public RefBase {
 public:
 
     /* Events used by AudioTrack callback function (callback_t).
@@ -37,6 +39,8 @@
      */
     enum event_type {
         EVENT_MORE_DATA = 0,        // Request to write more data to buffer.
+        EVENT_UNDERRUN = 1,         // Buffer underrun occurred. This will not occur for
+                                    // static tracks.
         EVENT_NEW_IAUDIOTRACK = 6,  // IAudioTrack was re-created, either due to re-routing and
                                     // voluntary invalidation by mediaserver, or mediaserver crash.
         EVENT_STREAM_END = 7,       // Sent after all the buffers queued in AF and HW are played
@@ -104,8 +108,7 @@
      *
      * TODO: Revive removed arguments after offload mode is supported.
      */
-    JAudioTrack(audio_stream_type_t streamType,
-                uint32_t sampleRate,
+    JAudioTrack(uint32_t sampleRate,
                 audio_format_t format,
                 audio_channel_mask_t channelMask,
                 callback_t cbf,
@@ -158,10 +161,10 @@
      * Caution: calling this method too often may be inefficient;
      * if you need a high resolution mapping between frame position and presentation time,
      * consider implementing that at application level, based on the low resolution timestamps.
-     * Returns true if timestamp is valid.
-     * The timestamp parameter is undefined on return, if false is returned.
+     * Returns NO_ERROR if timestamp is valid.
+     *         NO_INIT if finds error, and timestamp parameter will be undefined on return.
      */
-    bool getTimestamp(AudioTimestamp& timestamp);
+    status_t getTimestamp(AudioTimestamp& timestamp);
 
     // TODO: This doc is just copied from AudioTrack.h. Revise it after implemenation.
     /* Return the extended timestamp, with additional timebase info and improved drain behavior.
@@ -324,6 +327,8 @@
 
     audio_format_t format();
 
+    size_t frameSize();
+
     /*
      * Dumps the state of an audio track.
      * Not a general-purpose API; intended only for use by media player service to dump its tracks.
@@ -355,6 +360,11 @@
     /* Returns the flags */
     audio_output_flags_t getFlags() const { return mFlags; }
 
+    /* We don't keep stream type here,
+     * instead, we keep attributes and call getVolumeControlStream() to get stream type
+     */
+    audio_stream_type_t getAudioStreamType();
+
     /* Obtain the pending duration in milliseconds for playback of pure PCM data remaining in
      * AudioTrack.
      *
@@ -369,33 +379,75 @@
      * Replaces any previously installed callback.
      *
      * Parameters:
-     *
-     * callback: The callback interface
+     * Listener: the listener to receive notification of rerouting events.
+     * Handler: the handler to handler the rerouting events.
      *
      * Returns NO_ERROR if successful.
-     *         INVALID_OPERATION if the same callback is already installed.
-     *         NO_INIT or PREMISSION_DENIED if AudioFlinger service is not reachable
-     *         BAD_VALUE if the callback is NULL
+     *         (TODO) INVALID_OPERATION if the same callback is already installed.
+     *         (TODO) NO_INIT or PREMISSION_DENIED if AudioFlinger service is not reachable
+     *         (TODO) BAD_VALUE if the callback is NULL
      */
-    status_t addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback);
+    status_t addAudioDeviceCallback(jobject listener, jobject rd);
 
     /* Removes an AudioDeviceCallback.
      *
      * Parameters:
-     *
-     * callback: The callback interface
+     * Listener: the listener to receive notification of rerouting events.
      *
      * Returns NO_ERROR if successful.
-     *         INVALID_OPERATION if the callback is not installed
-     *         BAD_VALUE if the callback is NULL
+     *         (TODO) INVALID_OPERATION if the callback is not installed
+     *         (TODO) BAD_VALUE if the callback is NULL
      */
-    status_t removeAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback);
+    status_t removeAudioDeviceCallback(jobject listener);
+
+    /* Register all backed-up routing delegates.
+     *
+     * Parameters:
+     * routingDelegates: backed-up routing delegates
+     *
+     */
+    void registerRoutingDelegates(std::vector<std::pair<jobject, jobject>>& routingDelegates);
+
+    /* get listener from RoutingDelegate object
+     */
+    static jobject getListener(const jobject routingDelegateObj);
+
+    /* get handler from RoutingDelegate object
+     */
+    static jobject getHandler(const jobject routingDelegateObj);
+
+    /* convert local reference to global reference.
+     */
+    static jobject addGlobalRef(const jobject obj);
+
+    /* erase global reference.
+     *
+     * Returns NO_ERROR if succeeds
+     *         BAD_VALUE if obj is NULL
+     */
+    static status_t removeGlobalRef(const jobject obj);
+
+    /*
+     * Parameters:
+     * map and key
+     *
+     * Returns value if key is in the map
+     *         nullptr if key is not in the map
+     */
+    static jobject findByKey(std::vector<std::pair<jobject, jobject>>& mp, const jobject key);
+
+    /*
+     * Parameters:
+     * map and key
+     */
+    static void eraseByKey(std::vector<std::pair<jobject, jobject>>& mp, const jobject key);
 
 private:
     audio_output_flags_t mFlags;
 
     jclass mAudioTrackCls;
     jobject mAudioTrackObj;
+    jobject mAudioAttributesObj;
 
     /* Creates a Java VolumeShaper.Configuration object from VolumeShaper::Configuration */
     jobject createVolumeShaperConfigurationObj(
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
index fe1005b..9fca641 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
@@ -19,7 +19,10 @@
 #define ANDROID_MEDIAPLAYER2AUDIOOUTPUT_H
 
 #include <mediaplayer2/MediaPlayer2Interface.h>
+#include <mediaplayer2/JAudioTrack.h>
 
+#include <vector>
+#include <utility>
 #include <utils/String16.h>
 #include <utils/Vector.h>
 
@@ -36,11 +39,11 @@
                             uid_t uid,
                             int pid,
                             const audio_attributes_t * attr,
-                            const sp<AudioSystem::AudioDeviceCallback>& deviceCallback);
+                            std::vector<jobject>& routingDelegatesBackup);
     virtual ~MediaPlayer2AudioOutput();
 
     virtual bool ready() const {
-        return mTrack != 0;
+        return mJAudioTrack != nullptr;
     }
     virtual ssize_t bufferSize() const;
     virtual ssize_t frameCount() const;
@@ -62,7 +65,6 @@
             AudioCallback cb, void *cookie,
             audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
             const audio_offload_info_t *offloadInfo = NULL,
-            bool doNotReconnect = false,
             uint32_t suggestedFrameCount = 0);
 
     virtual status_t start();
@@ -71,11 +73,8 @@
     virtual void flush();
     virtual void pause();
     virtual void close();
-    void setAudioStreamType(audio_stream_type_t streamType);
-    virtual audio_stream_type_t getAudioStreamType() const {
-        return mStreamType;
-    }
     void setAudioAttributes(const audio_attributes_t * attributes);
+    virtual audio_stream_type_t getAudioStreamType() const;
 
     void setVolume(float volume);
     virtual status_t setPlaybackRate(const AudioPlaybackRate& rate);
@@ -92,13 +91,12 @@
         // TODO: return correct value.
         //return mNextOutput == NULL;
     }
-    virtual status_t setParameters(const String8& keyValuePairs);
-    virtual String8 getParameters(const String8& keys);
-
     // AudioRouting
     virtual status_t setOutputDevice(audio_port_handle_t deviceId);
     virtual status_t getRoutedDeviceId(audio_port_handle_t* deviceId);
-    virtual status_t enableAudioDeviceCallback(bool enabled);
+    virtual status_t addAudioDeviceCallback(jobject routingDelegate);
+    virtual status_t removeAudioDeviceCallback(jobject listener);
+    virtual void copyAudioDeviceCallback(std::vector<jobject>& routingDelegateTarget);
 
 private:
     static void setMinBufferCount();
@@ -107,11 +105,10 @@
     void close_l();
     status_t updateTrack_l();
 
-    sp<AudioTrack>          mTrack;
+    sp<JAudioTrack>         mJAudioTrack;
     AudioCallback           mCallback;
     void *                  mCallbackCookie;
     CallbackData *          mCallbackData;
-    audio_stream_type_t     mStreamType;
     audio_attributes_t *    mAttributes;
     float                   mVolume;
     AudioPlaybackRate       mPlaybackRate;
@@ -126,9 +123,8 @@
     audio_output_flags_t    mFlags;
     audio_port_handle_t     mSelectedDeviceId;
     audio_port_handle_t     mRoutedDeviceId;
-    bool                    mDeviceCallbackEnabled;
-    wp<AudioSystem::AudioDeviceCallback>        mDeviceCallback;
     mutable Mutex           mLock;
+    std::vector<std::pair<jobject, jobject>> mRoutingDelegates; // <listener, routingDelegate>
 
     // static variables below not protected by mutex
     static bool             mIsOnEmulator;
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
index 846441e..9a35ed9 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
@@ -23,6 +23,7 @@
 #include <utils/Errors.h>
 #include <utils/String8.h>
 #include <utils/RefBase.h>
+#include <jni.h>
 
 #include <media/AVSyncSettings.h>
 #include <media/AudioResamplerPublic.h>
@@ -106,7 +107,6 @@
                 void *cookie = NULL,
                 audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
                 const audio_offload_info_t *offloadInfo = NULL,
-                bool doNotReconnect = false,
                 uint32_t suggestedFrameCount = 0) = 0;
 
         virtual status_t start() = 0;
@@ -144,7 +144,8 @@
         // AudioRouting
         virtual status_t    setOutputDevice(audio_port_handle_t deviceId);
         virtual status_t    getRoutedDeviceId(audio_port_handle_t* deviceId);
-        virtual status_t    enableAudioDeviceCallback(bool enabled);
+        virtual status_t    addAudioDeviceCallback(jobject routingDelegate);
+        virtual status_t    removeAudioDeviceCallback(jobject listener);
     };
 
     MediaPlayer2Interface() : mListener(NULL) { }
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
index 10e07ea..2430289 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
@@ -42,7 +42,6 @@
     MEDIA2_SUBTITLE_DATA     = 201,
     MEDIA2_META_DATA         = 202,
     MEDIA2_DRM_INFO          = 210,
-    MEDIA2_AUDIO_ROUTING_CHANGED = 10000,
 };
 
 // Generic error codes for the media player framework.  Errors are fatal, the
diff --git a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
index 4f73ad3..a1908e6 100644
--- a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
+++ b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
@@ -25,6 +25,8 @@
 #include <mediaplayer2/MediaPlayer2Interface.h>
 #include <mediaplayer2/MediaPlayer2Types.h>
 
+#include <vector>
+#include <jni.h>
 #include <utils/Errors.h>
 #include <utils/Mutex.h>
 #include <utils/RefBase.h>
@@ -105,7 +107,8 @@
             // AudioRouting
             status_t        setOutputDevice(audio_port_handle_t deviceId);
             audio_port_handle_t getRoutedDeviceId();
-            status_t        enableAudioDeviceCallback(bool enabled);
+            status_t        addAudioDeviceCallback(jobject routingDelegate);
+            status_t        removeAudioDeviceCallback(jobject listener);
 
             status_t        dump(int fd, const Vector<String16>& args);
 
@@ -148,7 +151,7 @@
     audio_session_t             mAudioSessionId;
     audio_attributes_t *        mAudioAttributes;
     float                       mSendLevel;
-
+    std::vector<jobject>        mRoutingDelegates;
     sp<ANativeWindowWrapper>    mConnectedWindow;
 };
 
diff --git a/media/libmediaplayer2/mediaplayer2.cpp b/media/libmediaplayer2/mediaplayer2.cpp
index 480a630..4960694 100644
--- a/media/libmediaplayer2/mediaplayer2.cpp
+++ b/media/libmediaplayer2/mediaplayer2.cpp
@@ -104,27 +104,6 @@
     }
 }
 
-class AudioDeviceUpdatedNotifier: public AudioSystem::AudioDeviceCallback {
-public:
-    AudioDeviceUpdatedNotifier(const sp<MediaPlayer2Interface>& listener)
-        : mListener(listener) { }
-
-    ~AudioDeviceUpdatedNotifier() { }
-
-    virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
-                                     audio_port_handle_t deviceId) override {
-        sp<MediaPlayer2Interface> listener = mListener.promote();
-        if (listener != NULL) {
-            listener->sendEvent(0, MEDIA2_AUDIO_ROUTING_CHANGED, audioIo, deviceId);
-        } else {
-            ALOGW("listener for process %d death is gone", MEDIA2_AUDIO_ROUTING_CHANGED);
-        }
-    }
-
-private:
-    wp<MediaPlayer2Interface> mListener;
-};
-
 class proxyListener : public MediaPlayer2InterfaceListener {
 public:
     proxyListener(const wp<MediaPlayer2> &player)
@@ -433,9 +412,13 @@
 
         clear_l();
 
+        if (mAudioOutput != NULL) {
+            mAudioOutput->copyAudioDeviceCallback(mRoutingDelegates);
+        }
+
         player->setListener(new proxyListener(this));
         mAudioOutput = new MediaPlayer2AudioOutput(mAudioSessionId, mUid,
-                mPid, mAudioAttributes, new AudioDeviceUpdatedNotifier(player));
+                mPid, mAudioAttributes, mRoutingDelegates);
         player->setAudioSink(mAudioOutput);
 
         err = player->setDataSource(dsd);
@@ -614,8 +597,6 @@
             if (err != OK) {
                 return err;
             }
-        } else if (mAudioOutput != 0) {
-            mAudioOutput->setAudioStreamType(mStreamType);
         }
         mCurrentState = MEDIA_PLAYER2_PREPARING;
         return mPlayer->prepareAsync();
@@ -1306,13 +1287,23 @@
     return deviceId;
 }
 
-status_t MediaPlayer2::enableAudioDeviceCallback(bool enabled) {
+status_t MediaPlayer2::addAudioDeviceCallback(jobject routingDelegate) {
+    Mutex::Autolock _l(mLock);
+    if (mAudioOutput == NULL) {
+        ALOGV("addAudioDeviceCallback: player not init");
+        mRoutingDelegates.push_back(routingDelegate);
+        return NO_INIT;
+    }
+    return mAudioOutput->addAudioDeviceCallback(routingDelegate);
+}
+
+status_t MediaPlayer2::removeAudioDeviceCallback(jobject listener) {
     Mutex::Autolock _l(mLock);
     if (mAudioOutput == NULL) {
         ALOGV("addAudioDeviceCallback: player not init");
         return NO_INIT;
     }
-    return mAudioOutput->enableAudioDeviceCallback(enabled);
+    return mAudioOutput->removeAudioDeviceCallback(listener);
 }
 
 status_t MediaPlayer2::dump(int fd, const Vector<String16>& args) {
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
index bc17d13..c37460b 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
@@ -643,6 +643,7 @@
 }
 
 void NuPlayer2::onMessageReceived(const sp<AMessage> &msg) {
+
     switch (msg->what()) {
         case kWhatSetDataSource:
         {
@@ -1717,7 +1718,7 @@
     mRenderer = new Renderer(mAudioSink, mMediaClock, notify, flags);
     mRendererLooper = new ALooper;
     mRendererLooper->setName("NuPlayerRenderer");
-    mRendererLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
+    mRendererLooper->start(false, true, ANDROID_PRIORITY_AUDIO);
     mRendererLooper->registerHandler(mRenderer);
 
     status_t err = mRenderer->setPlaybackSettings(mPlaybackSettings);
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
index 652cc89..7db78c1 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
@@ -1848,6 +1848,7 @@
         bool isStreaming) {
     ALOGV("openAudioSink: offloadOnly(%d) offloadingAudio(%d)",
             offloadOnly, offloadingAudio());
+
     bool audioSinkChanged = false;
 
     int32_t numChannels;
@@ -1989,13 +1990,6 @@
         const uint32_t frameCount =
                 (unsigned long long)sampleRate * getAudioSinkPcmMsSetting() / 1000;
 
-        // The doNotReconnect means AudioSink will signal back and let NuPlayer2 to re-construct
-        // AudioSink. We don't want this when there's video because it will cause a video seek to
-        // the previous I frame. But we do want this when there's only audio because it will give
-        // NuPlayer2 a chance to switch from non-offload mode to offload mode.
-        // So we only set doNotReconnect when there's no video.
-        const bool doNotReconnect = !hasVideo;
-
         // We should always be able to set our playback settings if the sink is closed.
         LOG_ALWAYS_FATAL_IF(mAudioSink->setPlaybackRate(mPlaybackSettings) != OK,
                 "onOpenAudioSink: can't set playback rate on closed sink");
@@ -2008,7 +2002,6 @@
                     mUseAudioCallback ? this : NULL,
                     (audio_output_flags_t)pcmFlags,
                     NULL,
-                    doNotReconnect,
                     frameCount);
         if (err != OK) {
             ALOGW("openAudioSink: non offloaded open failed status: %d", err);