aaudio: fix problems with PlayerBase and ref counting

CTS test was crashing because of a multiple inheritance
problem involving PlayerBase.
We now implement separate PlayerBase class that sits between
AudioStream and the system.

Bug: 65450109
Test: CTS nativemedia/aaudio
Change-Id: I424663acc1eeacc9544769991495cb48f4110359
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index bbbd439..5d7733c 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -23,7 +23,6 @@
 #define ATRACE_TAG ATRACE_TAG_AUDIO
 
 #include <stdint.h>
-#include <assert.h>
 
 #include <binder/IServiceManager.h>
 
@@ -63,7 +62,6 @@
         , mAudioEndpoint()
         , mServiceStreamHandle(AAUDIO_HANDLE_INVALID)
         , mFramesPerBurst(16)
-        , mStreamVolume(1.0f)
         , mInService(inService)
         , mServiceInterface(serviceInterface)
         , mAtomicTimestamp()
@@ -196,10 +194,6 @@
     }
 
     setState(AAUDIO_STREAM_STATE_OPEN);
-    // Only connect to AudioManager if this is a playback stream running in client process.
-    if (!mInService && getDirection() == AAUDIO_DIRECTION_OUTPUT) {
-        init(android::PLAYER_TYPE_AAUDIO, AUDIO_USAGE_MEDIA);
-    }
 
     return result;
 
@@ -209,7 +203,8 @@
 }
 
 aaudio_result_t AudioStreamInternal::close() {
-    ALOGD("AudioStreamInternal::close(): mServiceStreamHandle = 0x%08X",
+    aaudio_result_t result = AAUDIO_OK;
+    ALOGD("close(): mServiceStreamHandle = 0x%08X",
              mServiceStreamHandle);
     if (mServiceStreamHandle != AAUDIO_HANDLE_INVALID) {
         // Don't close a stream while it is running.
@@ -218,10 +213,10 @@
             requestStop();
             aaudio_stream_state_t nextState;
             int64_t timeoutNanoseconds = MIN_TIMEOUT_NANOS;
-            aaudio_result_t result = waitForStateChange(currentState, &nextState,
+            result = waitForStateChange(currentState, &nextState,
                                                        timeoutNanoseconds);
             if (result != AAUDIO_OK) {
-                ALOGE("AudioStreamInternal::close() waitForStateChange() returned %d %s",
+                ALOGE("close() waitForStateChange() returned %d %s",
                 result, AAudio_convertResultToText(result));
             }
         }
@@ -232,8 +227,11 @@
         mServiceInterface.closeStream(serviceStreamHandle);
         delete[] mCallbackBuffer;
         mCallbackBuffer = nullptr;
+
         setState(AAUDIO_STREAM_STATE_CLOSED);
-        return mEndPointParcelable.close();
+        result = mEndPointParcelable.close();
+        aaudio_result_t result2 = AudioStream::close();
+        return (result != AAUDIO_OK) ? result : result2;
     } else {
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
@@ -283,13 +281,13 @@
     // Clear any stale timestamps from the previous run.
     drainTimestampsFromService();
 
-    status_t status = startWithStatus(); // Call PlayerBase, which will start the device stream.
-    aaudio_result_t result = AAudioConvert_androidToAAudioResult(status);
+    aaudio_result_t result = mServiceInterface.startStream(mServiceStreamHandle);
 
     startTime = AudioClock::getNanoseconds();
     mClockModel.start(startTime);
     mNeedCatchUp.request();  // Ask data processing code to catch up when first timestamp received.
 
+    // Start data callback thread.
     if (result == AAUDIO_OK && getDataCallbackProc() != nullptr) {
         // Launch the callback loop thread.
         int64_t periodNanos = mCallbackFrames
@@ -342,7 +340,8 @@
     mClockModel.stop(AudioClock::getNanoseconds());
     setState(AAUDIO_STREAM_STATE_STOPPING);
     mAtomicTimestamp.clear();
-    return AAudioConvert_androidToAAudioResult(stopWithStatus());
+
+    return mServiceInterface.stopStream(mServiceStreamHandle);
 }
 
 aaudio_result_t AudioStreamInternal::requestStop()
@@ -687,32 +686,3 @@
 aaudio_result_t AudioStreamInternal::joinThread(void** returnArg) {
     return AudioStream::joinThread(returnArg, calculateReasonableTimeout(getFramesPerBurst()));
 }
-
-void AudioStreamInternal::doSetVolume() {
-    // No pan and only left volume is taken into account from IPLayer interface
-    mVolumeRamp.setTarget(mStreamVolume * mVolumeMultiplierL /* * mPanMultiplierL */);
-}
-
-
-//------------------------------------------------------------------------------
-// Implementation of PlayerBase
-status_t AudioStreamInternal::playerStart() {
-    return AAudioConvert_aaudioToAndroidStatus(mServiceInterface.startStream(mServiceStreamHandle));
-}
-
-status_t AudioStreamInternal::playerPause() {
-    return AAudioConvert_aaudioToAndroidStatus(mServiceInterface.pauseStream(mServiceStreamHandle));
-}
-
-status_t AudioStreamInternal::playerStop() {
-    return AAudioConvert_aaudioToAndroidStatus(mServiceInterface.stopStream(mServiceStreamHandle));
-}
-
-status_t AudioStreamInternal::playerSetVolume() {
-    doSetVolume();
-    return NO_ERROR;
-}
-
-void AudioStreamInternal::destroy() {
-    baseDestroy();
-}
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index 899d455..47024c0 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -18,7 +18,6 @@
 #define ANDROID_AAUDIO_AUDIO_STREAM_INTERNAL_H
 
 #include <stdint.h>
-#include <media/PlayerBase.h>
 #include <aaudio/AAudio.h>
 
 #include "binding/IAAudioService.h"
@@ -36,7 +35,7 @@
 namespace aaudio {
 
 // A stream that talks to the AAudioService or directly to a HAL.
-class AudioStreamInternal : public AudioStream, public android::PlayerBase  {
+class AudioStreamInternal : public AudioStream {
 
 public:
     AudioStreamInternal(AAudioServiceInterface  &serviceInterface, bool inService);
@@ -85,9 +84,6 @@
     // Calculate timeout based on framesPerBurst
     int64_t calculateReasonableTimeout();
 
-    //PlayerBase virtuals
-    virtual void destroy();
-
     aaudio_result_t startClient(const android::AudioClient& client,
                                 audio_port_handle_t *clientHandle);
 
@@ -138,14 +134,6 @@
     // Calculate timeout for an operation involving framesPerOperation.
     int64_t calculateReasonableTimeout(int32_t framesPerOperation);
 
-    void doSetVolume();
-
-    //PlayerBase virtuals
-    virtual status_t playerStart();
-    virtual status_t playerPause();
-    virtual status_t playerStop();
-    virtual status_t playerSetVolume();
-
     aaudio_format_t          mDeviceFormat = AAUDIO_FORMAT_UNSPECIFIED;
 
     IsochronousClockModel    mClockModel;      // timing model for chasing the HAL
@@ -156,9 +144,6 @@
     int32_t                  mFramesPerBurst;     // frames per HAL transfer
     int32_t                  mXRunCount = 0;      // how many underrun events?
 
-    LinearRamp               mVolumeRamp;
-    float                    mStreamVolume;
-
     // Offset from underlying frame position.
     int64_t                  mFramesOffsetFromService = 0; // offset for timestamps
 
@@ -174,6 +159,8 @@
 
     AtomicRequestor          mNeedCatchUp;   // Ask read() or write() to sync on first timestamp.
 
+    float                    mStreamVolume = 1.0f;
+
 private:
     /*
      * Asynchronous write with data conversion.
@@ -196,7 +183,6 @@
     EndpointDescriptor       mEndpointDescriptor; // buffer description with resolved addresses
 
     int64_t                  mServiceLatencyNanos = 0;
-
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index f2e40a2..1e02eee 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -49,7 +49,7 @@
     mClockModel.stop(AudioClock::getNanoseconds());
     setState(AAUDIO_STREAM_STATE_PAUSING);
     mAtomicTimestamp.clear();
-    return AAudioConvert_androidToAAudioResult(pauseWithStatus());
+    return mServiceInterface.pauseStream(mServiceStreamHandle);
 }
 
 aaudio_result_t AudioStreamInternalPlay::requestPause()
@@ -290,7 +290,6 @@
     return framesWritten;
 }
 
-
 int64_t AudioStreamInternalPlay::getFramesRead()
 {
     int64_t framesReadHardware;
@@ -364,3 +363,10 @@
           result, (int) isActive());
     return NULL;
 }
+
+//------------------------------------------------------------------------------
+// Implementation of PlayerBase
+status_t AudioStreamInternalPlay::doSetVolume() {
+    mVolumeRamp.setTarget(mStreamVolume * getDuckAndMuteVolume());
+    return android::NO_ERROR;
+}
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.h b/media/libaaudio/src/client/AudioStreamInternalPlay.h
index fdb1fd7..98783de 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.h
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.h
@@ -50,6 +50,9 @@
         return AAUDIO_DIRECTION_OUTPUT;
     }
 
+    // Only register client side streams.
+    bool needsSystemRegistration() override { return !mInService; }
+
 protected:
 
     aaudio_result_t requestPauseInternal();
@@ -58,6 +61,8 @@
 
     void onFlushFromServer() override;
 
+    android::status_t doSetVolume() override;
+
 /**
  * Low level write that will not block. It will just write as much as it can.
  *
@@ -80,6 +85,9 @@
                                            int32_t numFrames);
 
     int64_t                  mLastFramesRead = 0; // used to prevent retrograde motion
+
+    LinearRamp               mVolumeRamp;
+
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index 5089b00..63569ad 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -219,6 +219,7 @@
     ALOGD("AAudioStreamBuilder_openStream() returns %d = %s for (%p) ----------------",
           result, AAudio_convertResultToText(result), audioStream);
     if (result == AAUDIO_OK) {
+        audioStream->systemRegister();
         *streamPtr = (AAudioStream*) audioStream;
     } else {
         *streamPtr = nullptr;
@@ -242,6 +243,7 @@
     ALOGD("AAudioStream_close(%p)", stream);
     if (audioStream != nullptr) {
         audioStream->close();
+        audioStream->systemUnRegister();
         delete audioStream;
         return AAUDIO_OK;
     }
@@ -252,7 +254,7 @@
 {
     AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
     ALOGD("AAudioStream_requestStart(%p) called --------------", stream);
-    aaudio_result_t result = audioStream->requestStart();
+    aaudio_result_t result = audioStream->systemStart();
     ALOGD("AAudioStream_requestStart(%p) returned %d ---------", stream, result);
     return result;
 }
@@ -261,7 +263,7 @@
 {
     AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
     ALOGD("AAudioStream_requestPause(%p)", stream);
-    return audioStream->requestPause();
+    return audioStream->systemPause();
 }
 
 AAUDIO_API aaudio_result_t  AAudioStream_requestFlush(AAudioStream* stream)
@@ -275,7 +277,7 @@
 {
     AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
     ALOGD("AAudioStream_requestStop(%p)", stream);
-    return audioStream->requestStop();
+    return audioStream->systemStop();
 }
 
 AAUDIO_API aaudio_result_t AAudioStream_waitForStateChange(AAudioStream* stream,
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index 4f1cc37..35a1c6a 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AAudioStream"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -29,13 +29,24 @@
 using namespace aaudio;
 
 AudioStream::AudioStream()
-        : mCallbackEnabled(false)
+        : mPlayerBase(new MyPlayerBase(this))
 {
     // mThread is a pthread_t of unknown size so we need memset.
     memset(&mThread, 0, sizeof(mThread));
     setPeriodNanoseconds(0);
 }
 
+AudioStream::~AudioStream() {
+    ALOGD("destroying %p, state = %s", this, AAudio_convertStreamStateToText(getState()));
+    // If the stream is deleted when OPEN or in use then audio resources will leak.
+    // This would indicate an internal error. So we want to find this ASAP.
+    LOG_ALWAYS_FATAL_IF(!(getState() == AAUDIO_STREAM_STATE_CLOSED
+                          || getState() == AAUDIO_STREAM_STATE_UNINITIALIZED
+                          || getState() == AAUDIO_STREAM_STATE_DISCONNECTED),
+                        "aaudio stream still in use, state = %s",
+                        AAudio_convertStreamStateToText(getState()));
+}
+
 static const char *AudioStream_convertSharingModeToShortText(aaudio_sharing_mode_t sharingMode) {
     const char *result;
     switch (sharingMode) {
@@ -90,9 +101,6 @@
     return AAUDIO_OK;
 }
 
-AudioStream::~AudioStream() {
-    close();
-}
 
 aaudio_result_t AudioStream::waitForStateChange(aaudio_stream_state_t currentState,
                                                 aaudio_stream_state_t *nextState,
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index ad18751..5800fa2 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -21,10 +21,18 @@
 #include <mutex>
 #include <stdint.h>
 #include <aaudio/AAudio.h>
+#include <binder/IServiceManager.h>
+#include <binder/Status.h>
+#include <utils/StrongPointer.h>
 
+#include "media/VolumeShaper.h"
+#include "media/PlayerBase.h"
 #include "utility/AAudioUtilities.h"
 #include "utility/MonotonicCounter.h"
 
+// Cannot get android::media::VolumeShaper to compile!
+#define AAUDIO_USE_VOLUME_SHAPER  0
+
 namespace aaudio {
 
 typedef void *(*aaudio_audio_thread_proc_t)(void *);
@@ -234,8 +242,122 @@
         return AAUDIO_ERROR_UNIMPLEMENTED;
     }
 
+    // This is used by the AudioManager to duck and mute the stream when changing audio focus.
+    void setDuckAndMuteVolume(float duckAndMuteVolume) {
+        mDuckAndMuteVolume = duckAndMuteVolume;
+        doSetVolume(); // apply this change
+    }
+
+    float getDuckAndMuteVolume() {
+        return mDuckAndMuteVolume;
+    }
+
+    // Implement this in the output subclasses.
+    virtual android::status_t doSetVolume() { return android::NO_ERROR; }
+
+#if AAUDIO_USE_VOLUME_SHAPER
+    virtual android::binder::Status applyVolumeShaper(
+            const ::android::media::VolumeShaper::Configuration& configuration __unused,
+            const ::android::media::VolumeShaper::Operation& operation __unused) {
+        ALOGW("applyVolumeShaper() is not supported");
+        return android::binder::Status::ok();
+    }
+#endif
+
+    // Should this object be registered with the AudioManager?
+    virtual bool needsSystemRegistration() { return false; }
+
+    // Register this stream's PlayerBase with the AudioManager
+    void systemRegister() {
+        if (needsSystemRegistration()) {
+            mPlayerBase->registerWithAudioManager();
+        }
+    }
+
+    // UnRegister this stream's PlayerBase with the AudioManager
+    void systemUnRegister() {
+        if (needsSystemRegistration()) {
+            mPlayerBase->destroy();
+        }
+    }
+
+    // Pass start request through PlayerBase for tracking.
+    aaudio_result_t systemStart() {
+        mPlayerBase->start();
+        // Pass aaudio_result_t around the PlayerBase interface, which uses status__t.
+        return mPlayerBase->getResult();
+    }
+
+    aaudio_result_t systemPause() {
+        mPlayerBase->pause();
+        return mPlayerBase->getResult();
+    }
+
+    aaudio_result_t systemStop() {
+        mPlayerBase->stop();
+        return mPlayerBase->getResult();
+    }
+
 protected:
 
+    // PlayerBase allows the system to control the stream.
+    // Calling through PlayerBase->start() notifies the AudioManager of the player state.
+    // The AudioManager also can start/stop a stream by calling mPlayerBase->playerStart().
+    // systemStart() ==> mPlayerBase->start()   mPlayerBase->playerStart() ==> requestStart()
+    //                        \                           /
+    //                         ------ AudioManager -------
+    class MyPlayerBase : public android::PlayerBase {
+    public:
+        MyPlayerBase(AudioStream *parent) : mParent(parent) {}
+        virtual ~MyPlayerBase() {}
+
+        void registerWithAudioManager() {
+            init(android::PLAYER_TYPE_AAUDIO, AUDIO_USAGE_MEDIA);
+        }
+
+        void destroy() override {
+            // FIXME what else should this do? close()? disconnect()?
+            baseDestroy();
+        }
+
+        virtual android::status_t playerStart() {
+            mResult = mParent->requestStart();
+            return AAudioConvert_aaudioToAndroidStatus(mResult);
+        }
+
+        virtual android::status_t playerPause() {
+            mResult = mParent->requestPause();
+            return AAudioConvert_aaudioToAndroidStatus(mResult);
+        }
+
+        virtual android::status_t playerStop() {
+            mResult = mParent->requestStop();
+            return AAudioConvert_aaudioToAndroidStatus(mResult);
+        }
+
+        virtual android::status_t playerSetVolume() {
+            // No pan and only left volume is taken into account from IPLayer interface
+            mParent->setDuckAndMuteVolume(mVolumeMultiplierL  /* * mPanMultiplierL */);
+            return android::NO_ERROR;
+        }
+
+#if AAUDIO_USE_VOLUME_SHAPER
+        android::binder::Status applyVolumeShaper(
+                const android::media::VolumeShaper::Configuration& configuration,
+                const android::media::VolumeShaper::Operation& operation) {
+            return mParent->applyVolumeShaper(configuration, operation);
+        }
+#endif
+
+        aaudio_result_t getResult() {
+            return mResult;
+        }
+
+        AudioStream *mParent;
+        aaudio_result_t       mResult = AAUDIO_OK;
+    };
+
+
 
     /**
      * This should not be called after the open() call.
@@ -275,7 +397,9 @@
 
     std::mutex           mStreamMutex;
 
-    std::atomic<bool>    mCallbackEnabled;
+    std::atomic<bool>    mCallbackEnabled{false};
+
+    float                mDuckAndMuteVolume = 1.0f;
 
 protected:
 
@@ -288,6 +412,8 @@
     }
 
 private:
+    const android::sp<MyPlayerBase>   mPlayerBase;
+
     // These do not change after open().
     int32_t                mSamplesPerFrame = AAUDIO_UNSPECIFIED;
     int32_t                mSampleRate = AAUDIO_UNSPECIFIED;
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index c8b94ae..d0a3e47 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AudioStreamRecord"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -181,11 +181,12 @@
 {
     // TODO add close() or release() to AudioRecord API then call it from here
     if (getState() != AAUDIO_STREAM_STATE_CLOSED) {
+        mAudioRecord->removeAudioDeviceCallback(mDeviceCallback);
         mAudioRecord.clear();
         setState(AAUDIO_STREAM_STATE_CLOSED);
     }
     mFixedBlockWriter.close();
-    return AAUDIO_OK;
+    return AudioStream::close();
 }
 
 void AudioStreamRecord::processCallback(int event, void *info) {
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 702b12a..d38fe46 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AudioStreamTrack"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -115,7 +115,7 @@
 
     ALOGD("AudioStreamTrack::open(), request notificationFrames = %d, frameCount = %u",
           notificationFrames, (uint)frameCount);
-    mAudioTrack = new AudioTrack();
+    mAudioTrack = new AudioTrack(); // TODO review
     if (getDeviceId() != AAUDIO_UNSPECIFIED) {
         mAudioTrack->setOutputDevice(getDeviceId());
     }
@@ -143,8 +143,7 @@
         return AAudioConvert_androidToAAudioResult(status);
     }
 
-    //TrackPlayerBase init
-    init(mAudioTrack.get(), PLAYER_TYPE_AAUDIO, AUDIO_USAGE_MEDIA);
+    doSetVolume();
 
     // Get the actual values from the AudioTrack.
     setSamplesPerFrame(mAudioTrack->channelCount());
@@ -199,7 +198,7 @@
 aaudio_result_t AudioStreamTrack::close()
 {
     if (getState() != AAUDIO_STREAM_STATE_CLOSED) {
-        destroy();
+        mAudioTrack->removeAudioDeviceCallback(mDeviceCallback);
         setState(AAUDIO_STREAM_STATE_CLOSED);
     }
     mFixedBlockReader.close();
@@ -224,8 +223,7 @@
     return;
 }
 
-aaudio_result_t AudioStreamTrack::requestStart()
-{
+aaudio_result_t AudioStreamTrack::requestStart() {
     std::lock_guard<std::mutex> lock(mStreamMutex);
 
     if (mAudioTrack.get() == nullptr) {
@@ -238,7 +236,7 @@
         return AAudioConvert_androidToAAudioResult(err);
     }
 
-    err = startWithStatus();
+    err = mAudioTrack->start();
     if (err != OK) {
         return AAudioConvert_androidToAAudioResult(err);
     } else {
@@ -248,12 +246,11 @@
     return AAUDIO_OK;
 }
 
-aaudio_result_t AudioStreamTrack::requestPause()
-{
+aaudio_result_t AudioStreamTrack::requestPause() {
     std::lock_guard<std::mutex> lock(mStreamMutex);
 
     if (mAudioTrack.get() == nullptr) {
-        ALOGE("AudioStreamTrack::requestPause() no AudioTrack");
+        ALOGE("requestPause() no AudioTrack");
         return AAUDIO_ERROR_INVALID_STATE;
     } else if (getState() != AAUDIO_STREAM_STATE_STARTING
             && getState() != AAUDIO_STREAM_STATE_STARTED) {
@@ -263,7 +260,7 @@
     }
     onStop();
     setState(AAUDIO_STREAM_STATE_PAUSING);
-    pause();
+    mAudioTrack->pause();
     status_t err = mAudioTrack->getPosition(&mPositionWhenPausing);
     if (err != OK) {
         return AAudioConvert_androidToAAudioResult(err);
@@ -300,9 +297,9 @@
     setState(AAUDIO_STREAM_STATE_STOPPING);
     incrementFramesRead(getFramesWritten() - getFramesRead()); // TODO review
     mTimestampPosition.set(getFramesWritten());
-    stop();
     mFramesWritten.reset32();
     mTimestampPosition.reset32();
+    mAudioTrack->stop();
     return AAUDIO_OK;
 }
 
@@ -465,3 +462,36 @@
     }
     return result;
 }
+
+status_t AudioStreamTrack::doSetVolume() {
+    status_t status = NO_INIT;
+    if (mAudioTrack.get() != nullptr) {
+        float volume = getDuckAndMuteVolume();
+        mAudioTrack->setVolume(volume, volume);
+        status = NO_ERROR;
+    }
+    return status;
+}
+
+#if AAUDIO_USE_VOLUME_SHAPER
+binder::Status AudioStreamTrack::applyVolumeShaper(
+        const VolumeShaper::Configuration& configuration,
+        const VolumeShaper::Operation& operation) {
+
+    sp<VolumeShaper::Configuration> spConfiguration = new VolumeShaper::Configuration(configuration);
+    sp<VolumeShaper::Operation> spOperation = new VolumeShaper::Operation(operation);
+
+    if (mAudioTrack.get() != nullptr) {
+        ALOGD("applyVolumeShaper() from IPlayer");
+        VolumeShaper::Status status = mAudioTrack->applyVolumeShaper(spConfiguration, spOperation);
+        if (status < 0) { // a non-negative value is the volume shaper id.
+            ALOGE("applyVolumeShaper() failed with status %d", status);
+        }
+        return binder::Status::fromStatusT(status);
+    } else {
+        ALOGD("applyVolumeShaper()"
+                      " no AudioTrack for volume control from IPlayer");
+        return binder::Status::ok();
+    }
+}
+#endif
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.h b/media/libaaudio/src/legacy/AudioStreamTrack.h
index 3230ac8..dbcb94e 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.h
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.h
@@ -19,6 +19,7 @@
 
 #include <math.h>
 #include <media/TrackPlayerBase.h>
+#include <media/AudioTrack.h>
 #include <aaudio/AAudio.h>
 
 #include "AudioStreamBuilder.h"
@@ -32,7 +33,7 @@
 /**
  * Internal stream that uses the legacy AudioTrack path.
  */
-class AudioStreamTrack : public AudioStreamLegacy, public android::TrackPlayerBase {
+class AudioStreamTrack : public AudioStreamLegacy {
 public:
     AudioStreamTrack();
 
@@ -76,8 +77,20 @@
         return incrementFramesWritten(frames);
     }
 
+    bool needsSystemRegistration() override { return true; }
+
+    android::status_t doSetVolume() override;
+
+#if AAUDIO_USE_VOLUME_SHAPER
+    virtual android::binder::Status applyVolumeShaper(
+            const android::media::VolumeShaper::Configuration& configuration,
+            const android::media::VolumeShaper::Operation& operation) override;
+#endif
+
 private:
 
+    android::sp<android::AudioTrack> mAudioTrack;
+
     // adapts between variable sized blocks and fixed size blocks
     FixedBlockReader                 mFixedBlockReader;