Merge changes from topic "fix-b-264712385-primary-module" into main

* changes:
  audio: Move StreamContext ownership out from StreamCommonImpl
  audio: Use ChildInterface in StreamCommonImpl
  audio: Update StreamAlsa and alsa utils for built-in devices
  audio: Simplify and extend alsa::Mixer
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index 5478633..eb9cbc3 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -675,7 +675,7 @@
                                                nullptr, nullptr, &context));
     context.fillDescriptor(&_aidl_return->desc);
     std::shared_ptr<StreamIn> stream;
-    RETURN_STATUS_IF_ERROR(createInputStream(in_args.sinkMetadata, std::move(context),
+    RETURN_STATUS_IF_ERROR(createInputStream(std::move(context), in_args.sinkMetadata,
                                              mConfig->microphones, &stream));
     StreamWrapper streamWrapper(stream);
     if (auto patchIt = mPatches.find(in_args.portConfigId); patchIt != mPatches.end()) {
@@ -721,7 +721,7 @@
                                                in_args.eventCallback, &context));
     context.fillDescriptor(&_aidl_return->desc);
     std::shared_ptr<StreamOut> stream;
-    RETURN_STATUS_IF_ERROR(createOutputStream(in_args.sourceMetadata, std::move(context),
+    RETURN_STATUS_IF_ERROR(createOutputStream(std::move(context), in_args.sourceMetadata,
                                               in_args.offloadInfo, &stream));
     StreamWrapper streamWrapper(stream);
     if (auto patchIt = mPatches.find(in_args.portConfigId); patchIt != mPatches.end()) {
diff --git a/audio/aidl/default/ModulePrimary.cpp b/audio/aidl/default/ModulePrimary.cpp
index cbb6730..d8ea9e7 100644
--- a/audio/aidl/default/ModulePrimary.cpp
+++ b/audio/aidl/default/ModulePrimary.cpp
@@ -38,22 +38,23 @@
         mTelephony = ndk::SharedRefBase::make<Telephony>();
     }
     *_aidl_return = mTelephony.getPtr();
-    LOG(DEBUG) << __func__ << ": returning instance of ITelephony: " << _aidl_return->get();
+    LOG(DEBUG) << __func__
+               << ": returning instance of ITelephony: " << _aidl_return->get()->asBinder().get();
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus ModulePrimary::createInputStream(const SinkMetadata& sinkMetadata,
-                                                    StreamContext&& context,
+ndk::ScopedAStatus ModulePrimary::createInputStream(StreamContext&& context,
+                                                    const SinkMetadata& sinkMetadata,
                                                     const std::vector<MicrophoneInfo>& microphones,
                                                     std::shared_ptr<StreamIn>* result) {
-    return createStreamInstance<StreamInStub>(result, sinkMetadata, std::move(context),
+    return createStreamInstance<StreamInStub>(result, std::move(context), sinkMetadata,
                                               microphones);
 }
 
 ndk::ScopedAStatus ModulePrimary::createOutputStream(
-        const SourceMetadata& sourceMetadata, StreamContext&& context,
+        StreamContext&& context, const SourceMetadata& sourceMetadata,
         const std::optional<AudioOffloadInfo>& offloadInfo, std::shared_ptr<StreamOut>* result) {
-    return createStreamInstance<StreamOutStub>(result, sourceMetadata, std::move(context),
+    return createStreamInstance<StreamOutStub>(result, std::move(context), sourceMetadata,
                                                offloadInfo);
 }
 
diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp
index 215de94..f4194d2 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -47,13 +47,19 @@
         desc->reply = mReplyMQ->dupeDesc();
     }
     if (mDataMQ) {
-        const size_t frameSize = getFrameSize();
-        desc->frameSizeBytes = frameSize;
-        desc->bufferSizeFrames = mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize() / frameSize;
+        desc->frameSizeBytes = getFrameSize();
+        desc->bufferSizeFrames = getBufferSizeInFrames();
         desc->audio.set<StreamDescriptor::AudioBuffer::Tag::fmq>(mDataMQ->dupeDesc());
     }
 }
 
+size_t StreamContext::getBufferSizeInFrames() const {
+    if (mDataMQ) {
+        return mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize() / getFrameSize();
+    }
+    return 0;
+}
+
 size_t StreamContext::getFrameSize() const {
     return getFrameSizeInBytes(mFormat, mChannelLayout);
 }
@@ -597,18 +603,16 @@
 ndk::ScopedAStatus StreamCommonImpl::initInstance(
         const std::shared_ptr<StreamCommonInterface>& delegate) {
     mCommon = ndk::SharedRefBase::make<StreamCommonDelegator>(delegate);
-    mCommonBinder = mCommon->asBinder();
-    AIBinder_setMinSchedulerPolicy(mCommonBinder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
     return mWorker->start() ? ndk::ScopedAStatus::ok()
                             : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
 }
 
 ndk::ScopedAStatus StreamCommonImpl::getStreamCommonCommon(
         std::shared_ptr<IStreamCommon>* _aidl_return) {
-    if (mCommon == nullptr) {
+    if (!mCommon) {
         LOG(FATAL) << __func__ << ": the common interface was not created";
     }
-    *_aidl_return = mCommon;
+    *_aidl_return = mCommon.getPtr();
     LOG(DEBUG) << __func__ << ": returning " << _aidl_return->get()->asBinder().get();
     return ndk::ScopedAStatus::ok();
 }
@@ -659,7 +663,7 @@
         LOG(DEBUG) << __func__ << ": joining the worker thread...";
         mWorker->stop();
         LOG(DEBUG) << __func__ << ": worker thread joined";
-        mContext.reset();
+        onClose();
         mWorker->setClosed();
         return ndk::ScopedAStatus::ok();
     } else {
@@ -723,11 +727,15 @@
 }
 }  // namespace
 
-StreamIn::StreamIn(const std::vector<MicrophoneInfo>& microphones)
-    : mMicrophones(transformMicrophones(microphones)) {
+StreamIn::StreamIn(StreamContext&& context, const std::vector<MicrophoneInfo>& microphones)
+    : mContext(std::move(context)), mMicrophones(transformMicrophones(microphones)) {
     LOG(DEBUG) << __func__;
 }
 
+void StreamIn::defaultOnClose() {
+    mContext.reset();
+}
+
 ndk::ScopedAStatus StreamIn::getActiveMicrophones(
         std::vector<MicrophoneDynamicInfo>* _aidl_return) {
     std::vector<MicrophoneDynamicInfo> result;
@@ -780,11 +788,15 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
-StreamOut::StreamOut(const std::optional<AudioOffloadInfo>& offloadInfo)
-    : mOffloadInfo(offloadInfo) {
+StreamOut::StreamOut(StreamContext&& context, const std::optional<AudioOffloadInfo>& offloadInfo)
+    : mContext(std::move(context)), mOffloadInfo(offloadInfo) {
     LOG(DEBUG) << __func__;
 }
 
+void StreamOut::defaultOnClose() {
+    mContext.reset();
+}
+
 ndk::ScopedAStatus StreamOut::updateOffloadMetadata(
         const AudioOffloadMetadata& in_offloadMetadata) {
     LOG(DEBUG) << __func__;
diff --git a/audio/aidl/default/alsa/Mixer.cpp b/audio/aidl/default/alsa/Mixer.cpp
index f0393e3..126c033 100644
--- a/audio/aidl/default/alsa/Mixer.cpp
+++ b/audio/aidl/default/alsa/Mixer.cpp
@@ -14,44 +14,17 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AHAL_AlsaMixer"
-#include <android-base/logging.h>
-
+#include <algorithm>
 #include <cmath>
 
+#define LOG_TAG "AHAL_AlsaMixer"
+#include <android-base/logging.h>
 #include <android/binder_status.h>
 
 #include "Mixer.h"
 
 namespace aidl::android::hardware::audio::core::alsa {
 
-//-----------------------------------------------------------------------------
-
-MixerControl::MixerControl(struct mixer_ctl* ctl)
-    : mCtl(ctl),
-      mNumValues(mixer_ctl_get_num_values(ctl)),
-      mMinValue(mixer_ctl_get_range_min(ctl)),
-      mMaxValue(mixer_ctl_get_range_max(ctl)) {}
-
-unsigned int MixerControl::getNumValues() const {
-    return mNumValues;
-}
-
-int MixerControl::getMaxValue() const {
-    return mMaxValue;
-}
-
-int MixerControl::getMinValue() const {
-    return mMinValue;
-}
-
-int MixerControl::setArray(const void* array, size_t count) {
-    const std::lock_guard guard(mLock);
-    return mixer_ctl_set_array(mCtl, array, count);
-}
-
-//-----------------------------------------------------------------------------
-
 // static
 const std::map<Mixer::Control, std::vector<Mixer::ControlNamesAndExpectedCtlType>>
         Mixer::kPossibleControls = {
@@ -60,18 +33,20 @@
                 {Mixer::HW_VOLUME,
                  {{"Headphone Playback Volume", MIXER_CTL_TYPE_INT},
                   {"Headset Playback Volume", MIXER_CTL_TYPE_INT},
-                  {"PCM Playback Volume", MIXER_CTL_TYPE_INT}}}};
+                  {"PCM Playback Volume", MIXER_CTL_TYPE_INT}}},
+                {Mixer::MIC_SWITCH, {{"Capture Switch", MIXER_CTL_TYPE_BOOL}}},
+                {Mixer::MIC_GAIN, {{"Capture Volume", MIXER_CTL_TYPE_INT}}}};
 
 // static
-std::map<Mixer::Control, std::shared_ptr<MixerControl>> Mixer::initializeMixerControls(
-        struct mixer* mixer) {
-    std::map<Mixer::Control, std::shared_ptr<MixerControl>> mixerControls;
+Mixer::Controls Mixer::initializeMixerControls(struct mixer* mixer) {
+    if (mixer == nullptr) return {};
+    Controls mixerControls;
     std::string mixerCtlNames;
     for (const auto& [control, possibleCtls] : kPossibleControls) {
         for (const auto& [ctlName, expectedCtlType] : possibleCtls) {
             struct mixer_ctl* ctl = mixer_get_ctl_by_name(mixer, ctlName.c_str());
             if (ctl != nullptr && mixer_ctl_get_type(ctl) == expectedCtlType) {
-                mixerControls.emplace(control, std::make_unique<MixerControl>(ctl));
+                mixerControls.emplace(control, ctl);
                 if (!mixerCtlNames.empty()) {
                     mixerCtlNames += ",";
                 }
@@ -84,71 +59,141 @@
     return mixerControls;
 }
 
-Mixer::Mixer(struct mixer* mixer)
-    : mMixer(mixer), mMixerControls(initializeMixerControls(mMixer)) {}
+std::ostream& operator<<(std::ostream& s, Mixer::Control c) {
+    switch (c) {
+        case Mixer::Control::MASTER_SWITCH:
+            s << "master mute";
+            break;
+        case Mixer::Control::MASTER_VOLUME:
+            s << "master volume";
+            break;
+        case Mixer::Control::HW_VOLUME:
+            s << "volume";
+            break;
+        case Mixer::Control::MIC_SWITCH:
+            s << "mic mute";
+            break;
+        case Mixer::Control::MIC_GAIN:
+            s << "mic gain";
+            break;
+    }
+    return s;
+}
+
+Mixer::Mixer(int card) : mMixer(mixer_open(card)), mMixerControls(initializeMixerControls(mMixer)) {
+    if (!isValid()) {
+        PLOG(ERROR) << __func__ << ": failed to open mixer for card=" << card;
+    }
+}
 
 Mixer::~Mixer() {
-    mixer_close(mMixer);
+    if (isValid()) {
+        std::lock_guard l(mMixerAccess);
+        mixer_close(mMixer);
+    }
 }
 
-namespace {
-
-int volumeFloatToInteger(float fValue, int maxValue, int minValue) {
-    return minValue + std::ceil((maxValue - minValue) * fValue);
-}
-
-}  // namespace
-
 ndk::ScopedAStatus Mixer::setMasterMute(bool muted) {
-    auto it = mMixerControls.find(Mixer::MASTER_SWITCH);
-    if (it == mMixerControls.end()) {
-        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
-    }
-    const int numValues = it->second->getNumValues();
-    std::vector<int> values(numValues, muted ? 0 : 1);
-    if (int err = it->second->setArray(values.data(), numValues); err != 0) {
-        LOG(ERROR) << __func__ << ": failed to set master mute, err=" << err;
-        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
-    }
-    return ndk::ScopedAStatus::ok();
+    return setMixerControlMute(MASTER_SWITCH, muted);
 }
 
 ndk::ScopedAStatus Mixer::setMasterVolume(float volume) {
-    auto it = mMixerControls.find(Mixer::MASTER_VOLUME);
-    if (it == mMixerControls.end()) {
-        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
-    }
-    const int numValues = it->second->getNumValues();
-    std::vector<int> values(numValues, volumeFloatToInteger(volume, it->second->getMaxValue(),
-                                                            it->second->getMinValue()));
-    if (int err = it->second->setArray(values.data(), numValues); err != 0) {
-        LOG(ERROR) << __func__ << ": failed to set master volume, err=" << err;
-        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
-    }
-    return ndk::ScopedAStatus::ok();
+    return setMixerControlVolume(MASTER_VOLUME, volume);
+}
+
+ndk::ScopedAStatus Mixer::setMicGain(float gain) {
+    return setMixerControlVolume(MIC_GAIN, gain);
+}
+
+ndk::ScopedAStatus Mixer::setMicMute(bool muted) {
+    return setMixerControlMute(MIC_SWITCH, muted);
 }
 
 ndk::ScopedAStatus Mixer::setVolumes(const std::vector<float>& volumes) {
+    if (!isValid()) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
     auto it = mMixerControls.find(Mixer::HW_VOLUME);
     if (it == mMixerControls.end()) {
         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
     }
-    const int numValues = it->second->getNumValues();
-    if (numValues < 0) {
-        LOG(FATAL) << __func__ << ": negative number of values: " << numValues;
-    }
-    const int maxValue = it->second->getMaxValue();
-    const int minValue = it->second->getMinValue();
-    std::vector<int> values;
-    size_t i = 0;
-    for (; i < static_cast<size_t>(numValues) && i < values.size(); ++i) {
-        values.emplace_back(volumeFloatToInteger(volumes[i], maxValue, minValue));
-    }
-    if (int err = it->second->setArray(values.data(), values.size()); err != 0) {
+    std::vector<int> percents;
+    std::transform(
+            volumes.begin(), volumes.end(), std::back_inserter(percents),
+            [](float volume) -> int { return std::floor(std::clamp(volume, 0.0f, 1.0f) * 100); });
+    std::lock_guard l(mMixerAccess);
+    if (int err = setMixerControlPercent(it->second, percents); err != 0) {
         LOG(ERROR) << __func__ << ": failed to set volume, err=" << err;
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
     }
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Mixer::setMixerControlMute(Mixer::Control ctl, bool muted) {
+    if (!isValid()) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    auto it = mMixerControls.find(ctl);
+    if (it == mMixerControls.end()) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+    std::lock_guard l(mMixerAccess);
+    if (int err = setMixerControlValue(it->second, muted ? 0 : 1); err != 0) {
+        LOG(ERROR) << __func__ << ": failed to set " << ctl << " to " << muted << ", err=" << err;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Mixer::setMixerControlVolume(Control ctl, float volume) {
+    if (!isValid()) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    auto it = mMixerControls.find(ctl);
+    if (it == mMixerControls.end()) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+    volume = std::clamp(volume, 0.0f, 1.0f);
+    std::lock_guard l(mMixerAccess);
+    if (int err = setMixerControlPercent(it->second, std::floor(volume * 100)); err != 0) {
+        LOG(ERROR) << __func__ << ": failed to set " << ctl << " to " << volume << ", err=" << err;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+int Mixer::setMixerControlPercent(struct mixer_ctl* ctl, int percent) {
+    int ret = 0;
+    const unsigned int n = mixer_ctl_get_num_values(ctl);
+    for (unsigned int id = 0; id < n; id++) {
+        if (int error = mixer_ctl_set_percent(ctl, id, percent); error != 0) {
+            ret = error;
+        }
+    }
+    return ret;
+}
+
+int Mixer::setMixerControlPercent(struct mixer_ctl* ctl, const std::vector<int>& percents) {
+    int ret = 0;
+    const unsigned int n = mixer_ctl_get_num_values(ctl);
+    for (unsigned int id = 0; id < n; id++) {
+        if (int error = mixer_ctl_set_percent(ctl, id, id < percents.size() ? percents[id] : 0);
+            error != 0) {
+            ret = error;
+        }
+    }
+    return ret;
+}
+
+int Mixer::setMixerControlValue(struct mixer_ctl* ctl, int value) {
+    int ret = 0;
+    const unsigned int n = mixer_ctl_get_num_values(ctl);
+    for (unsigned int id = 0; id < n; id++) {
+        if (int error = mixer_ctl_set_value(ctl, id, value); error != 0) {
+            ret = error;
+        }
+    }
+    return ret;
+}
+
 }  // namespace aidl::android::hardware::audio::core::alsa
diff --git a/audio/aidl/default/alsa/Mixer.h b/audio/aidl/default/alsa/Mixer.h
index de9e6f4..78728c2 100644
--- a/audio/aidl/default/alsa/Mixer.h
+++ b/audio/aidl/default/alsa/Mixer.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <iostream>
 #include <map>
 #include <memory>
 #include <mutex>
@@ -31,34 +32,17 @@
 
 namespace aidl::android::hardware::audio::core::alsa {
 
-class MixerControl {
-  public:
-    explicit MixerControl(struct mixer_ctl* ctl);
-
-    unsigned int getNumValues() const;
-    int getMaxValue() const;
-    int getMinValue() const;
-    int setArray(const void* array, size_t count);
-
-  private:
-    std::mutex mLock;
-    // The mixer_ctl object is owned by ALSA and will be released when the mixer is closed.
-    struct mixer_ctl* mCtl GUARDED_BY(mLock);
-    const unsigned int mNumValues;
-    const int mMinValue;
-    const int mMaxValue;
-};
-
 class Mixer {
   public:
-    explicit Mixer(struct mixer* mixer);
-
+    explicit Mixer(int card);
     ~Mixer();
 
     bool isValid() const { return mMixer != nullptr; }
 
     ndk::ScopedAStatus setMasterMute(bool muted);
     ndk::ScopedAStatus setMasterVolume(float volume);
+    ndk::ScopedAStatus setMicGain(float gain);
+    ndk::ScopedAStatus setMicMute(bool muted);
     ndk::ScopedAStatus setVolumes(const std::vector<float>& volumes);
 
   private:
@@ -66,17 +50,32 @@
         MASTER_SWITCH,
         MASTER_VOLUME,
         HW_VOLUME,
+        MIC_SWITCH,
+        MIC_GAIN,
     };
     using ControlNamesAndExpectedCtlType = std::pair<std::string, enum mixer_ctl_type>;
-    static const std::map<Control, std::vector<ControlNamesAndExpectedCtlType>> kPossibleControls;
-    static std::map<Control, std::shared_ptr<MixerControl>> initializeMixerControls(
-            struct mixer* mixer);
+    using Controls = std::map<Control, struct mixer_ctl*>;
 
+    friend std::ostream& operator<<(std::ostream&, Control);
+    static const std::map<Control, std::vector<ControlNamesAndExpectedCtlType>> kPossibleControls;
+    static Controls initializeMixerControls(struct mixer* mixer);
+
+    ndk::ScopedAStatus setMixerControlMute(Control ctl, bool muted);
+    ndk::ScopedAStatus setMixerControlVolume(Control ctl, float volume);
+
+    int setMixerControlPercent(struct mixer_ctl* ctl, int percent) REQUIRES(mMixerAccess);
+    int setMixerControlPercent(struct mixer_ctl* ctl, const std::vector<int>& percents)
+            REQUIRES(mMixerAccess);
+    int setMixerControlValue(struct mixer_ctl* ctl, int value) REQUIRES(mMixerAccess);
+
+    // Since ALSA functions do not use internal locking, enforce thread safety at our level.
+    std::mutex mMixerAccess;
     // The mixer object is owned by ALSA and will be released when the mixer is closed.
-    struct mixer* mMixer;
+    struct mixer* const mMixer;
     // `mMixerControls` will only be initialized in constructor. After that, it wil only be
-    // read but not be modified.
-    const std::map<Control, std::shared_ptr<MixerControl>> mMixerControls;
+    // read but not be modified. Each mixer_ctl object is owned by ALSA, it's life span is
+    // the same as of the mixer itself.
+    const Controls mMixerControls;
 };
 
 }  // namespace aidl::android::hardware::audio::core::alsa
diff --git a/audio/aidl/default/alsa/StreamAlsa.cpp b/audio/aidl/default/alsa/StreamAlsa.cpp
index 17c7feb..c7fb022 100644
--- a/audio/aidl/default/alsa/StreamAlsa.cpp
+++ b/audio/aidl/default/alsa/StreamAlsa.cpp
@@ -27,16 +27,32 @@
 
 namespace aidl::android::hardware::audio::core {
 
-StreamAlsa::StreamAlsa(const Metadata& metadata, StreamContext&& context)
-    : StreamCommonImpl(metadata, std::move(context)),
+StreamAlsa::StreamAlsa(const StreamContext& context, const Metadata& metadata, int readWriteRetries)
+    : StreamCommonImpl(context, metadata),
       mFrameSizeBytes(getContext().getFrameSize()),
       mIsInput(isInput(metadata)),
-      mConfig(alsa::getPcmConfig(getContext(), mIsInput)) {}
+      mConfig(alsa::getPcmConfig(getContext(), mIsInput)),
+      mReadWriteRetries(readWriteRetries) {}
 
 ::android::status_t StreamAlsa::init() {
     return mConfig.has_value() ? ::android::OK : ::android::NO_INIT;
 }
 
+::android::status_t StreamAlsa::drain(StreamDescriptor::DrainMode) {
+    usleep(1000);
+    return ::android::OK;
+}
+
+::android::status_t StreamAlsa::flush() {
+    usleep(1000);
+    return ::android::OK;
+}
+
+::android::status_t StreamAlsa::pause() {
+    usleep(1000);
+    return ::android::OK;
+}
+
 ::android::status_t StreamAlsa::standby() {
     mAlsaDeviceProxies.clear();
     return ::android::OK;
@@ -45,27 +61,21 @@
 ::android::status_t StreamAlsa::start() {
     decltype(mAlsaDeviceProxies) alsaDeviceProxies;
     for (const auto& device : getDeviceProfiles()) {
-        auto profile = alsa::readAlsaDeviceInfo(device);
-        if (!profile.has_value()) {
-            LOG(ERROR) << __func__ << ": unable to read device info, device address=" << device;
-            return ::android::UNKNOWN_ERROR;
+        alsa::DeviceProxy proxy;
+        if (device.isExternal) {
+            // Always ask alsa configure as required since the configuration should be supported
+            // by the connected device. That is guaranteed by `setAudioPortConfig` and
+            // `setAudioPatch`.
+            proxy = alsa::openProxyForExternalDevice(
+                    device, const_cast<struct pcm_config*>(&mConfig.value()),
+                    true /*require_exact_match*/);
+        } else {
+            proxy = alsa::openProxyForAttachedDevice(
+                    device, const_cast<struct pcm_config*>(&mConfig.value()),
+                    getContext().getBufferSizeInFrames());
         }
-
-        auto proxy = alsa::makeDeviceProxy();
-        // Always ask for alsa configure as required since the configuration should be supported
-        // by the connected device. That is guaranteed by `setAudioPortConfig` and `setAudioPatch`.
-        if (int err = proxy_prepare(proxy.get(), &profile.value(),
-                                    const_cast<struct pcm_config*>(&mConfig.value()),
-                                    true /*require_exact_match*/);
-            err != 0) {
-            LOG(ERROR) << __func__ << ": fail to prepare for device address=" << device
-                       << " error=" << err;
-            return ::android::UNKNOWN_ERROR;
-        }
-        if (int err = proxy_open(proxy.get()); err != 0) {
-            LOG(ERROR) << __func__ << ": failed to open device, address=" << device
-                       << " error=" << err;
-            return ::android::UNKNOWN_ERROR;
+        if (!proxy) {
+            return ::android::NO_INIT;
         }
         alsaDeviceProxies.push_back(std::move(proxy));
     }
@@ -83,11 +93,12 @@
             return ::android::NO_INIT;
         }
         // For input case, only support single device.
-        proxy_read(mAlsaDeviceProxies[0].get(), buffer, bytesToTransfer);
+        proxy_read_with_retries(mAlsaDeviceProxies[0].get(), buffer, bytesToTransfer,
+                                mReadWriteRetries);
         maxLatency = proxy_get_latency(mAlsaDeviceProxies[0].get());
     } else {
         for (auto& proxy : mAlsaDeviceProxies) {
-            proxy_write(proxy.get(), buffer, bytesToTransfer);
+            proxy_write_with_retries(proxy.get(), buffer, bytesToTransfer, mReadWriteRetries);
             maxLatency = std::max(maxLatency, proxy_get_latency(proxy.get()));
         }
     }
diff --git a/audio/aidl/default/alsa/Utils.cpp b/audio/aidl/default/alsa/Utils.cpp
index 162f852..20f7797 100644
--- a/audio/aidl/default/alsa/Utils.cpp
+++ b/audio/aidl/default/alsa/Utils.cpp
@@ -217,7 +217,8 @@
     }
     return DeviceProfile{.card = alsaAddress[0],
                          .device = alsaAddress[1],
-                         .direction = isInput ? PCM_IN : PCM_OUT};
+                         .direction = isInput ? PCM_IN : PCM_OUT,
+                         .isExternal = !audioDevice.type.connection.empty()};
 }
 
 std::optional<DeviceProfile> getDeviceProfile(
@@ -269,6 +270,57 @@
     });
 }
 
+DeviceProxy openProxyForAttachedDevice(const DeviceProfile& deviceProfile,
+                                       struct pcm_config* pcmConfig, size_t bufferFrameCount) {
+    if (deviceProfile.isExternal) {
+        LOG(FATAL) << __func__ << ": called for an external device, address=" << deviceProfile;
+    }
+    alsa_device_profile profile;
+    profile_init(&profile, deviceProfile.direction);
+    profile.card = deviceProfile.card;
+    profile.device = deviceProfile.device;
+    if (!profile_fill_builtin_device_info(&profile, pcmConfig, bufferFrameCount)) {
+        LOG(FATAL) << __func__ << ": failed to init for built-in device, address=" << deviceProfile;
+    }
+    auto proxy = makeDeviceProxy();
+    if (int err = proxy_prepare_from_default_config(proxy.get(), &profile); err != 0) {
+        LOG(FATAL) << __func__ << ": fail to prepare for device address=" << deviceProfile
+                   << " error=" << err;
+        return nullptr;
+    }
+    if (int err = proxy_open(proxy.get()); err != 0) {
+        LOG(ERROR) << __func__ << ": failed to open device, address=" << deviceProfile
+                   << " error=" << err;
+        return nullptr;
+    }
+    return proxy;
+}
+
+DeviceProxy openProxyForExternalDevice(const DeviceProfile& deviceProfile,
+                                       struct pcm_config* pcmConfig, bool requireExactMatch) {
+    if (!deviceProfile.isExternal) {
+        LOG(FATAL) << __func__ << ": called for an attached device, address=" << deviceProfile;
+    }
+    auto profile = readAlsaDeviceInfo(deviceProfile);
+    if (!profile.has_value()) {
+        LOG(ERROR) << __func__ << ": unable to read device info, device address=" << deviceProfile;
+        return nullptr;
+    }
+    auto proxy = makeDeviceProxy();
+    if (int err = proxy_prepare(proxy.get(), &profile.value(), pcmConfig, requireExactMatch);
+        err != 0) {
+        LOG(ERROR) << __func__ << ": fail to prepare for device address=" << deviceProfile
+                   << " error=" << err;
+        return nullptr;
+    }
+    if (int err = proxy_open(proxy.get()); err != 0) {
+        LOG(ERROR) << __func__ << ": failed to open device, address=" << deviceProfile
+                   << " error=" << err;
+        return nullptr;
+    }
+    return proxy;
+}
+
 std::optional<alsa_device_profile> readAlsaDeviceInfo(const DeviceProfile& deviceProfile) {
     alsa_device_profile profile;
     profile_init(&profile, deviceProfile.direction);
diff --git a/audio/aidl/default/alsa/Utils.h b/audio/aidl/default/alsa/Utils.h
index c1b9b38..615e657 100644
--- a/audio/aidl/default/alsa/Utils.h
+++ b/audio/aidl/default/alsa/Utils.h
@@ -40,6 +40,7 @@
     int card;
     int device;
     int direction; /* PCM_OUT or PCM_IN */
+    bool isExternal;
 };
 std::ostream& operator<<(std::ostream& os, const DeviceProfile& device);
 using DeviceProxyDeleter = std::function<void(alsa_device_proxy*)>;
@@ -60,6 +61,10 @@
 std::optional<struct pcm_config> getPcmConfig(const StreamContext& context, bool isInput);
 std::vector<int> getSampleRatesFromProfile(const alsa_device_profile* profile);
 DeviceProxy makeDeviceProxy();
+DeviceProxy openProxyForAttachedDevice(const DeviceProfile& deviceProfile,
+                                       struct pcm_config* pcmConfig, size_t bufferFrameCount);
+DeviceProxy openProxyForExternalDevice(const DeviceProfile& deviceProfile,
+                                       struct pcm_config* pcmConfig, bool requireExactMatch);
 std::optional<alsa_device_profile> readAlsaDeviceInfo(const DeviceProfile& deviceProfile);
 
 ::aidl::android::media::audio::common::AudioFormatDescription
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index 294cc0e..539221d 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -159,13 +159,13 @@
     // The following virtual functions are intended for vendor extension via inheritance.
 
     virtual ndk::ScopedAStatus createInputStream(
-            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
             std::shared_ptr<StreamIn>* result) = 0;
     virtual ndk::ScopedAStatus createOutputStream(
-            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
             StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
             const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
                     offloadInfo,
             std::shared_ptr<StreamOut>* result) = 0;
diff --git a/audio/aidl/default/include/core-impl/ModulePrimary.h b/audio/aidl/default/include/core-impl/ModulePrimary.h
index bc808ab..6264237 100644
--- a/audio/aidl/default/include/core-impl/ModulePrimary.h
+++ b/audio/aidl/default/include/core-impl/ModulePrimary.h
@@ -28,13 +28,13 @@
     ndk::ScopedAStatus getTelephony(std::shared_ptr<ITelephony>* _aidl_return) override;
 
     ndk::ScopedAStatus createInputStream(
-            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
             std::shared_ptr<StreamIn>* result) override;
     ndk::ScopedAStatus createOutputStream(
-            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
             StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
             const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
                     offloadInfo,
             std::shared_ptr<StreamOut>* result) override;
diff --git a/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h b/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h
index ccfcdd9..e87be3d 100644
--- a/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h
+++ b/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h
@@ -33,13 +33,13 @@
 
     // Module interfaces
     ndk::ScopedAStatus createInputStream(
-            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
             std::shared_ptr<StreamIn>* result) override;
     ndk::ScopedAStatus createOutputStream(
-            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
             StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
             const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
                     offloadInfo,
             std::shared_ptr<StreamOut>* result) override;
diff --git a/audio/aidl/default/include/core-impl/ModuleStub.h b/audio/aidl/default/include/core-impl/ModuleStub.h
index 59c343f..4f77161 100644
--- a/audio/aidl/default/include/core-impl/ModuleStub.h
+++ b/audio/aidl/default/include/core-impl/ModuleStub.h
@@ -30,13 +30,13 @@
     ndk::ScopedAStatus getBluetoothLe(std::shared_ptr<IBluetoothLe>* _aidl_return) override;
 
     ndk::ScopedAStatus createInputStream(
-            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
             std::shared_ptr<StreamIn>* result) override;
     ndk::ScopedAStatus createOutputStream(
-            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
             StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
             const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
                     offloadInfo,
             std::shared_ptr<StreamOut>* result) override;
diff --git a/audio/aidl/default/include/core-impl/ModuleUsb.h b/audio/aidl/default/include/core-impl/ModuleUsb.h
index e6b3e66..a296b8c 100644
--- a/audio/aidl/default/include/core-impl/ModuleUsb.h
+++ b/audio/aidl/default/include/core-impl/ModuleUsb.h
@@ -33,13 +33,13 @@
 
     // Module interfaces
     ndk::ScopedAStatus createInputStream(
-            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
             std::shared_ptr<StreamIn>* result) override;
     ndk::ScopedAStatus createOutputStream(
-            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
             StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
             const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
                     offloadInfo,
             std::shared_ptr<StreamOut>* result) override;
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index e64c578..355d3b4 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -43,6 +43,7 @@
 #include <system/thread_defs.h>
 #include <utils/Errors.h>
 
+#include "core-impl/ChildInterface.h"
 #include "core-impl/utils.h"
 
 namespace aidl::android::hardware::audio::core {
@@ -132,6 +133,7 @@
 
     void fillDescriptor(StreamDescriptor* desc);
     std::shared_ptr<IStreamCallback> getAsyncCallback() const { return mAsyncCallback; }
+    size_t getBufferSizeInFrames() const;
     ::aidl::android::media::audio::common::AudioChannelLayout getChannelLayout() const {
         return mChannelLayout;
     }
@@ -409,16 +411,17 @@
 };
 
 // The implementation of DriverInterface must be provided by each concrete stream implementation.
+// Note that StreamCommonImpl does not own the context. This is to support swapping on the fly
+// implementations of the stream while keeping the same IStreamIn/Out instance. It's that instance
+// who must be owner of the context.
 class StreamCommonImpl : virtual public StreamCommonInterface, virtual public DriverInterface {
   public:
-    StreamCommonImpl(const Metadata& metadata, StreamContext&& context,
+    StreamCommonImpl(const StreamContext& context, const Metadata& metadata,
                      const StreamWorkerInterface::CreateInstance& createWorker)
-        : mMetadata(metadata),
-          mContext(std::move(context)),
-          mWorker(createWorker(mContext, this)) {}
-    StreamCommonImpl(const Metadata& metadata, StreamContext&& context)
+        : mContext(context), mMetadata(metadata), mWorker(createWorker(mContext, this)) {}
+    StreamCommonImpl(const StreamContext& context, const Metadata& metadata)
         : StreamCommonImpl(
-                  metadata, std::move(context),
+                  context, metadata,
                   isInput(metadata) ? getDefaultInWorkerCreator() : getDefaultOutWorkerCreator()) {}
     ~StreamCommonImpl();
 
@@ -460,13 +463,13 @@
         };
     }
 
+    virtual void onClose() = 0;
     void stopWorker();
 
+    const StreamContext& mContext;
     Metadata mMetadata;
-    StreamContext mContext;
     std::unique_ptr<StreamWorkerInterface> mWorker;
-    std::shared_ptr<StreamCommonDelegator> mCommon;
-    ndk::SpAIBinder mCommonBinder;
+    ChildInterface<StreamCommonDelegator> mCommon;
     ConnectedDevices mConnectedDevices;
 };
 
@@ -474,6 +477,8 @@
 // concrete input/output stream implementations.
 class StreamIn : virtual public StreamCommonInterface, public BnStreamIn {
   protected:
+    void defaultOnClose();
+
     ndk::ScopedAStatus getStreamCommon(std::shared_ptr<IStreamCommon>* _aidl_return) override {
         return getStreamCommonCommon(_aidl_return);
     }
@@ -493,14 +498,17 @@
 
     friend class ndk::SharedRefBase;
 
-    explicit StreamIn(
-            const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
+    StreamIn(StreamContext&& context,
+             const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
 
+    StreamContext mContext;
     const std::map<::aidl::android::media::audio::common::AudioDevice, std::string> mMicrophones;
 };
 
 class StreamOut : virtual public StreamCommonInterface, public BnStreamOut {
   protected:
+    void defaultOnClose();
+
     ndk::ScopedAStatus getStreamCommon(std::shared_ptr<IStreamCommon>* _aidl_return) override {
         return getStreamCommonCommon(_aidl_return);
     }
@@ -534,10 +542,12 @@
 
     friend class ndk::SharedRefBase;
 
-    explicit StreamOut(const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
-                               offloadInfo);
+    StreamOut(StreamContext&& context,
+              const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
+                      offloadInfo);
 
-    std::optional<::aidl::android::media::audio::common::AudioOffloadInfo> mOffloadInfo;
+    StreamContext mContext;
+    const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo> mOffloadInfo;
     std::optional<::aidl::android::hardware::audio::common::AudioOffloadMetadata> mOffloadMetadata;
 };
 
diff --git a/audio/aidl/default/include/core-impl/StreamAlsa.h b/audio/aidl/default/include/core-impl/StreamAlsa.h
index 5744d66..90d2e36 100644
--- a/audio/aidl/default/include/core-impl/StreamAlsa.h
+++ b/audio/aidl/default/include/core-impl/StreamAlsa.h
@@ -31,9 +31,12 @@
 // provide necessary overrides for all interface methods omitted here.
 class StreamAlsa : public StreamCommonImpl {
   public:
-    StreamAlsa(const Metadata& metadata, StreamContext&& context);
+    StreamAlsa(const StreamContext& context, const Metadata& metadata, int readWriteRetries);
     // Methods of 'DriverInterface'.
     ::android::status_t init() override;
+    ::android::status_t drain(StreamDescriptor::DrainMode) override;
+    ::android::status_t flush() override;
+    ::android::status_t pause() override;
     ::android::status_t standby() override;
     ::android::status_t start() override;
     ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
@@ -48,6 +51,7 @@
     const size_t mFrameSizeBytes;
     const bool mIsInput;
     const std::optional<struct pcm_config> mConfig;
+    const int mReadWriteRetries;
     // All fields below are only used on the worker thread.
     std::vector<alsa::DeviceProxy> mAlsaDeviceProxies;
 };
diff --git a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
index 1bca910..4c984af 100644
--- a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
+++ b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
@@ -29,7 +29,7 @@
 
 class StreamRemoteSubmix : public StreamCommonImpl {
   public:
-    StreamRemoteSubmix(const Metadata& metadata, StreamContext&& context);
+    StreamRemoteSubmix(const StreamContext& context, const Metadata& metadata);
 
     ::android::status_t init() override;
     ::android::status_t drain(StreamDescriptor::DrainMode) override;
@@ -72,28 +72,32 @@
     static constexpr int kReadAttemptSleepUs = 5000;
 };
 
-class StreamInRemoteSubmix final : public StreamRemoteSubmix, public StreamIn {
+class StreamInRemoteSubmix final : public StreamIn, public StreamRemoteSubmix {
   public:
     friend class ndk::SharedRefBase;
     StreamInRemoteSubmix(
-            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
 
   private:
+    void onClose() override { defaultOnClose(); }
     ndk::ScopedAStatus getActiveMicrophones(
             std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return)
             override;
 };
 
-class StreamOutRemoteSubmix final : public StreamRemoteSubmix, public StreamOut {
+class StreamOutRemoteSubmix final : public StreamOut, public StreamRemoteSubmix {
   public:
     friend class ndk::SharedRefBase;
     StreamOutRemoteSubmix(
-            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
             StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
             const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
                     offloadInfo);
+
+  private:
+    void onClose() override { defaultOnClose(); }
 };
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/StreamStub.h b/audio/aidl/default/include/core-impl/StreamStub.h
index 6b1b2dd..2a92deb 100644
--- a/audio/aidl/default/include/core-impl/StreamStub.h
+++ b/audio/aidl/default/include/core-impl/StreamStub.h
@@ -22,7 +22,7 @@
 
 class StreamStub : public StreamCommonImpl {
   public:
-    StreamStub(const Metadata& metadata, StreamContext&& context);
+    StreamStub(const StreamContext& context, const Metadata& metadata);
     // Methods of 'DriverInterface'.
     ::android::status_t init() override;
     ::android::status_t drain(StreamDescriptor::DrainMode) override;
@@ -43,22 +43,28 @@
     bool mIsStandby = true;       // Used for validating the state machine logic.
 };
 
-class StreamInStub final : public StreamStub, public StreamIn {
+class StreamInStub final : public StreamIn, public StreamStub {
   public:
     friend class ndk::SharedRefBase;
     StreamInStub(
-            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
+
+  private:
+    void onClose() override { defaultOnClose(); }
 };
 
-class StreamOutStub final : public StreamStub, public StreamOut {
+class StreamOutStub final : public StreamOut, public StreamStub {
   public:
     friend class ndk::SharedRefBase;
-    StreamOutStub(const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
-                  StreamContext&& context,
+    StreamOutStub(StreamContext&& context,
+                  const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
                   const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
                           offloadInfo);
+
+  private:
+    void onClose() override { defaultOnClose(); }
 };
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/StreamUsb.h b/audio/aidl/default/include/core-impl/StreamUsb.h
index 44f742a..7dc7296 100644
--- a/audio/aidl/default/include/core-impl/StreamUsb.h
+++ b/audio/aidl/default/include/core-impl/StreamUsb.h
@@ -28,11 +28,8 @@
 
 class StreamUsb : public StreamAlsa {
   public:
-    StreamUsb(const Metadata& metadata, StreamContext&& context);
+    StreamUsb(const StreamContext& context, const Metadata& metadata);
     // Methods of 'DriverInterface'.
-    ::android::status_t drain(StreamDescriptor::DrainMode) override;
-    ::android::status_t flush() override;
-    ::android::status_t pause() override;
     ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
                                  int32_t* latencyMs) override;
 
@@ -47,29 +44,31 @@
     std::atomic<bool> mConnectedDevicesUpdated = false;
 };
 
-class StreamInUsb final : public StreamUsb, public StreamIn {
+class StreamInUsb final : public StreamIn, public StreamUsb {
   public:
     friend class ndk::SharedRefBase;
     StreamInUsb(
-            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
 
   private:
+    void onClose() override { defaultOnClose(); }
     ndk::ScopedAStatus getActiveMicrophones(
             std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return)
             override;
 };
 
-class StreamOutUsb final : public StreamUsb, public StreamOut {
+class StreamOutUsb final : public StreamOut, public StreamUsb {
   public:
     friend class ndk::SharedRefBase;
-    StreamOutUsb(const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
-                 StreamContext&& context,
+    StreamOutUsb(StreamContext&& context,
+                 const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
                  const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
                          offloadInfo);
 
   private:
+    void onClose() override { defaultOnClose(); }
     ndk::ScopedAStatus getHwVolume(std::vector<float>* _aidl_return) override;
     ndk::ScopedAStatus setHwVolume(const std::vector<float>& in_channelVolumes) override;
 
diff --git a/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp b/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp
index 2b79f51..9be7837 100644
--- a/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp
+++ b/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp
@@ -56,16 +56,16 @@
 }
 
 ndk::ScopedAStatus ModuleRemoteSubmix::createInputStream(
-        const SinkMetadata& sinkMetadata, StreamContext&& context,
+        StreamContext&& context, const SinkMetadata& sinkMetadata,
         const std::vector<MicrophoneInfo>& microphones, std::shared_ptr<StreamIn>* result) {
-    return createStreamInstance<StreamInRemoteSubmix>(result, sinkMetadata, std::move(context),
+    return createStreamInstance<StreamInRemoteSubmix>(result, std::move(context), sinkMetadata,
                                                       microphones);
 }
 
 ndk::ScopedAStatus ModuleRemoteSubmix::createOutputStream(
-        const SourceMetadata& sourceMetadata, StreamContext&& context,
+        StreamContext&& context, const SourceMetadata& sourceMetadata,
         const std::optional<AudioOffloadInfo>& offloadInfo, std::shared_ptr<StreamOut>* result) {
-    return createStreamInstance<StreamOutRemoteSubmix>(result, sourceMetadata, std::move(context),
+    return createStreamInstance<StreamOutRemoteSubmix>(result, std::move(context), sourceMetadata,
                                                        offloadInfo);
 }
 
diff --git a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
index 6d5185b..53d4aa6 100644
--- a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
+++ b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
@@ -29,8 +29,8 @@
 
 namespace aidl::android::hardware::audio::core {
 
-StreamRemoteSubmix::StreamRemoteSubmix(const Metadata& metadata, StreamContext&& context)
-    : StreamCommonImpl(metadata, std::move(context)),
+StreamRemoteSubmix::StreamRemoteSubmix(const StreamContext& context, const Metadata& metadata)
+    : StreamCommonImpl(context, metadata),
       mPortId(context.getPortId()),
       mIsInput(isInput(metadata)) {
     mStreamConfig.frameSize = context.getFrameSize();
@@ -353,10 +353,11 @@
     return ::android::OK;
 }
 
-StreamInRemoteSubmix::StreamInRemoteSubmix(const SinkMetadata& sinkMetadata,
-                                           StreamContext&& context,
+StreamInRemoteSubmix::StreamInRemoteSubmix(StreamContext&& context,
+                                           const SinkMetadata& sinkMetadata,
                                            const std::vector<MicrophoneInfo>& microphones)
-    : StreamRemoteSubmix(sinkMetadata, std::move(context)), StreamIn(microphones) {}
+    : StreamIn(std::move(context), microphones),
+      StreamRemoteSubmix(StreamIn::mContext, sinkMetadata) {}
 
 ndk::ScopedAStatus StreamInRemoteSubmix::getActiveMicrophones(
         std::vector<MicrophoneDynamicInfo>* _aidl_return) {
@@ -365,9 +366,10 @@
     return ndk::ScopedAStatus::ok();
 }
 
-StreamOutRemoteSubmix::StreamOutRemoteSubmix(const SourceMetadata& sourceMetadata,
-                                             StreamContext&& context,
+StreamOutRemoteSubmix::StreamOutRemoteSubmix(StreamContext&& context,
+                                             const SourceMetadata& sourceMetadata,
                                              const std::optional<AudioOffloadInfo>& offloadInfo)
-    : StreamRemoteSubmix(sourceMetadata, std::move(context)), StreamOut(offloadInfo) {}
+    : StreamOut(std::move(context), offloadInfo),
+      StreamRemoteSubmix(StreamOut::mContext, sourceMetadata) {}
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/stub/ModuleStub.cpp b/audio/aidl/default/stub/ModuleStub.cpp
index a600752..5e4cd88 100644
--- a/audio/aidl/default/stub/ModuleStub.cpp
+++ b/audio/aidl/default/stub/ModuleStub.cpp
@@ -38,7 +38,8 @@
         mBluetooth = ndk::SharedRefBase::make<Bluetooth>();
     }
     *_aidl_return = mBluetooth.getPtr();
-    LOG(DEBUG) << __func__ << ": returning instance of IBluetooth: " << _aidl_return->get();
+    LOG(DEBUG) << __func__
+               << ": returning instance of IBluetooth: " << _aidl_return->get()->asBinder().get();
     return ndk::ScopedAStatus::ok();
 }
 
@@ -47,7 +48,8 @@
         mBluetoothA2dp = ndk::SharedRefBase::make<BluetoothA2dp>();
     }
     *_aidl_return = mBluetoothA2dp.getPtr();
-    LOG(DEBUG) << __func__ << ": returning instance of IBluetoothA2dp: " << _aidl_return->get();
+    LOG(DEBUG) << __func__ << ": returning instance of IBluetoothA2dp: "
+               << _aidl_return->get()->asBinder().get();
     return ndk::ScopedAStatus::ok();
 }
 
@@ -56,22 +58,23 @@
         mBluetoothLe = ndk::SharedRefBase::make<BluetoothLe>();
     }
     *_aidl_return = mBluetoothLe.getPtr();
-    LOG(DEBUG) << __func__ << ": returning instance of IBluetoothLe: " << _aidl_return->get();
+    LOG(DEBUG) << __func__
+               << ": returning instance of IBluetoothLe: " << _aidl_return->get()->asBinder().get();
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus ModuleStub::createInputStream(const SinkMetadata& sinkMetadata,
-                                                 StreamContext&& context,
+ndk::ScopedAStatus ModuleStub::createInputStream(StreamContext&& context,
+                                                 const SinkMetadata& sinkMetadata,
                                                  const std::vector<MicrophoneInfo>& microphones,
                                                  std::shared_ptr<StreamIn>* result) {
-    return createStreamInstance<StreamInStub>(result, sinkMetadata, std::move(context),
+    return createStreamInstance<StreamInStub>(result, std::move(context), sinkMetadata,
                                               microphones);
 }
 
 ndk::ScopedAStatus ModuleStub::createOutputStream(
-        const SourceMetadata& sourceMetadata, StreamContext&& context,
+        StreamContext&& context, const SourceMetadata& sourceMetadata,
         const std::optional<AudioOffloadInfo>& offloadInfo, std::shared_ptr<StreamOut>* result) {
-    return createStreamInstance<StreamOutStub>(result, sourceMetadata, std::move(context),
+    return createStreamInstance<StreamOutStub>(result, std::move(context), sourceMetadata,
                                                offloadInfo);
 }
 
diff --git a/audio/aidl/default/stub/StreamStub.cpp b/audio/aidl/default/stub/StreamStub.cpp
index 2dcf4d4..e916fea 100644
--- a/audio/aidl/default/stub/StreamStub.cpp
+++ b/audio/aidl/default/stub/StreamStub.cpp
@@ -31,8 +31,8 @@
 
 namespace aidl::android::hardware::audio::core {
 
-StreamStub::StreamStub(const Metadata& metadata, StreamContext&& context)
-    : StreamCommonImpl(metadata, std::move(context)),
+StreamStub::StreamStub(const StreamContext& context, const Metadata& metadata)
+    : StreamCommonImpl(context, metadata),
       mFrameSizeBytes(getContext().getFrameSize()),
       mSampleRate(getContext().getSampleRate()),
       mIsAsynchronous(!!getContext().getAsyncCallback()),
@@ -118,12 +118,12 @@
     mIsInitialized = false;
 }
 
-StreamInStub::StreamInStub(const SinkMetadata& sinkMetadata, StreamContext&& context,
+StreamInStub::StreamInStub(StreamContext&& context, const SinkMetadata& sinkMetadata,
                            const std::vector<MicrophoneInfo>& microphones)
-    : StreamStub(sinkMetadata, std::move(context)), StreamIn(microphones) {}
+    : StreamIn(std::move(context), microphones), StreamStub(StreamIn::mContext, sinkMetadata) {}
 
-StreamOutStub::StreamOutStub(const SourceMetadata& sourceMetadata, StreamContext&& context,
+StreamOutStub::StreamOutStub(StreamContext&& context, const SourceMetadata& sourceMetadata,
                              const std::optional<AudioOffloadInfo>& offloadInfo)
-    : StreamStub(sourceMetadata, std::move(context)), StreamOut(offloadInfo) {}
+    : StreamOut(std::move(context), offloadInfo), StreamStub(StreamOut::mContext, sourceMetadata) {}
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/usb/ModuleUsb.cpp b/audio/aidl/default/usb/ModuleUsb.cpp
index a812e4d..f926e09 100644
--- a/audio/aidl/default/usb/ModuleUsb.cpp
+++ b/audio/aidl/default/usb/ModuleUsb.cpp
@@ -68,22 +68,22 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
-ndk::ScopedAStatus ModuleUsb::createInputStream(const SinkMetadata& sinkMetadata,
-                                                StreamContext&& context,
+ndk::ScopedAStatus ModuleUsb::createInputStream(StreamContext&& context,
+                                                const SinkMetadata& sinkMetadata,
                                                 const std::vector<MicrophoneInfo>& microphones,
                                                 std::shared_ptr<StreamIn>* result) {
-    return createStreamInstance<StreamInUsb>(result, sinkMetadata, std::move(context), microphones);
+    return createStreamInstance<StreamInUsb>(result, std::move(context), sinkMetadata, microphones);
 }
 
-ndk::ScopedAStatus ModuleUsb::createOutputStream(const SourceMetadata& sourceMetadata,
-                                                 StreamContext&& context,
+ndk::ScopedAStatus ModuleUsb::createOutputStream(StreamContext&& context,
+                                                 const SourceMetadata& sourceMetadata,
                                                  const std::optional<AudioOffloadInfo>& offloadInfo,
                                                  std::shared_ptr<StreamOut>* result) {
     if (offloadInfo.has_value()) {
         LOG(ERROR) << __func__ << ": offload is not supported";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
-    return createStreamInstance<StreamOutUsb>(result, sourceMetadata, std::move(context),
+    return createStreamInstance<StreamOutUsb>(result, std::move(context), sourceMetadata,
                                               offloadInfo);
 }
 
diff --git a/audio/aidl/default/usb/StreamUsb.cpp b/audio/aidl/default/usb/StreamUsb.cpp
index da0ad11..def12e0 100644
--- a/audio/aidl/default/usb/StreamUsb.cpp
+++ b/audio/aidl/default/usb/StreamUsb.cpp
@@ -35,8 +35,8 @@
 
 namespace aidl::android::hardware::audio::core {
 
-StreamUsb::StreamUsb(const Metadata& metadata, StreamContext&& context)
-    : StreamAlsa(metadata, std::move(context)) {}
+StreamUsb::StreamUsb(const StreamContext& context, const Metadata& metadata)
+    : StreamAlsa(context, metadata, 1 /*readWriteRetries*/) {}
 
 ndk::ScopedAStatus StreamUsb::setConnectedDevices(
         const std::vector<AudioDevice>& connectedDevices) {
@@ -55,28 +55,13 @@
         }
         connectedDeviceProfiles.push_back(*profile);
     }
-    RETURN_STATUS_IF_ERROR(StreamCommonImpl::setConnectedDevices(connectedDevices));
+    RETURN_STATUS_IF_ERROR(setConnectedDevices(connectedDevices));
     std::lock_guard guard(mLock);
     mConnectedDeviceProfiles = std::move(connectedDeviceProfiles);
     mConnectedDevicesUpdated.store(true, std::memory_order_release);
     return ndk::ScopedAStatus::ok();
 }
 
-::android::status_t StreamUsb::drain(StreamDescriptor::DrainMode) {
-    usleep(1000);
-    return ::android::OK;
-}
-
-::android::status_t StreamUsb::flush() {
-    usleep(1000);
-    return ::android::OK;
-}
-
-::android::status_t StreamUsb::pause() {
-    usleep(1000);
-    return ::android::OK;
-}
-
 ::android::status_t StreamUsb::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
                                         int32_t* latencyMs) {
     if (mConnectedDevicesUpdated.load(std::memory_order_acquire)) {
@@ -98,9 +83,9 @@
     return connectedDevices;
 }
 
-StreamInUsb::StreamInUsb(const SinkMetadata& sinkMetadata, StreamContext&& context,
+StreamInUsb::StreamInUsb(StreamContext&& context, const SinkMetadata& sinkMetadata,
                          const std::vector<MicrophoneInfo>& microphones)
-    : StreamUsb(sinkMetadata, std::move(context)), StreamIn(microphones) {}
+    : StreamIn(std::move(context), microphones), StreamUsb(StreamIn::mContext, sinkMetadata) {}
 
 ndk::ScopedAStatus StreamInUsb::getActiveMicrophones(
         std::vector<MicrophoneDynamicInfo>* _aidl_return __unused) {
@@ -108,10 +93,10 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
-StreamOutUsb::StreamOutUsb(const SourceMetadata& sourceMetadata, StreamContext&& context,
+StreamOutUsb::StreamOutUsb(StreamContext&& context, const SourceMetadata& sourceMetadata,
                            const std::optional<AudioOffloadInfo>& offloadInfo)
-    : StreamUsb(sourceMetadata, std::move(context)),
-      StreamOut(offloadInfo),
+    : StreamOut(std::move(context), offloadInfo),
+      StreamUsb(StreamOut::mContext, sourceMetadata),
       mChannelCount(getChannelCount(getContext().getChannelLayout())) {}
 
 ndk::ScopedAStatus StreamOutUsb::getHwVolume(std::vector<float>* _aidl_return) {
diff --git a/audio/aidl/default/usb/UsbAlsaMixerControl.cpp b/audio/aidl/default/usb/UsbAlsaMixerControl.cpp
index 769d739..0a49446 100644
--- a/audio/aidl/default/usb/UsbAlsaMixerControl.cpp
+++ b/audio/aidl/default/usb/UsbAlsaMixerControl.cpp
@@ -33,12 +33,10 @@
                                                    bool connected) {
     LOG(DEBUG) << __func__ << ": card=" << card << ", connected=" << connected;
     if (connected) {
-        struct mixer* mixer = mixer_open(card);
-        if (mixer == nullptr) {
-            PLOG(ERROR) << __func__ << ": failed to open mixer for card=" << card;
+        auto alsaMixer = std::make_shared<alsa::Mixer>(card);
+        if (!alsaMixer->isValid()) {
             return;
         }
-        auto alsaMixer = std::make_shared<alsa::Mixer>(mixer);
         alsaMixer->setMasterMute(masterMuted);
         alsaMixer->setMasterVolume(masterVolume);
         const std::lock_guard guard(mLock);