audio: Add DriverInterface::start method am: 49712b56d8 am: d8e545d9d8 am: 4eb39af463 am: 5e9873805d am: 9a652231e0

Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/2647304

Change-Id: I9d9e70d7f5a78675f2ca7833dadc0bbf65d1e6be
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp
index 73f1293..251dea0 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -166,10 +166,15 @@
         case Tag::start:
             if (mState == StreamDescriptor::State::STANDBY ||
                 mState == StreamDescriptor::State::DRAINING) {
-                populateReply(&reply, mIsConnected);
-                mState = mState == StreamDescriptor::State::STANDBY
-                                 ? StreamDescriptor::State::IDLE
-                                 : StreamDescriptor::State::ACTIVE;
+                if (::android::status_t status = mDriver->start(); status == ::android::OK) {
+                    populateReply(&reply, mIsConnected);
+                    mState = mState == StreamDescriptor::State::STANDBY
+                                     ? StreamDescriptor::State::IDLE
+                                     : StreamDescriptor::State::ACTIVE;
+                } else {
+                    LOG(ERROR) << __func__ << ": start failed: " << status;
+                    mState = StreamDescriptor::State::ERROR;
+                }
             } else {
                 populateReplyWrongState(&reply, command);
             }
@@ -377,26 +382,36 @@
             populateReply(&reply, mIsConnected);
             break;
         case Tag::start: {
-            bool commandAccepted = true;
+            std::optional<StreamDescriptor::State> nextState;
             switch (mState) {
                 case StreamDescriptor::State::STANDBY:
-                    mState = StreamDescriptor::State::IDLE;
+                    nextState = StreamDescriptor::State::IDLE;
                     break;
                 case StreamDescriptor::State::PAUSED:
-                    mState = StreamDescriptor::State::ACTIVE;
+                    nextState = StreamDescriptor::State::ACTIVE;
                     break;
                 case StreamDescriptor::State::DRAIN_PAUSED:
-                    switchToTransientState(StreamDescriptor::State::DRAINING);
+                    nextState = StreamDescriptor::State::DRAINING;
                     break;
                 case StreamDescriptor::State::TRANSFER_PAUSED:
-                    switchToTransientState(StreamDescriptor::State::TRANSFERRING);
+                    nextState = StreamDescriptor::State::TRANSFERRING;
                     break;
                 default:
                     populateReplyWrongState(&reply, command);
-                    commandAccepted = false;
             }
-            if (commandAccepted) {
-                populateReply(&reply, mIsConnected);
+            if (nextState.has_value()) {
+                if (::android::status_t status = mDriver->start(); status == ::android::OK) {
+                    populateReply(&reply, mIsConnected);
+                    if (*nextState == StreamDescriptor::State::IDLE ||
+                        *nextState == StreamDescriptor::State::ACTIVE) {
+                        mState = *nextState;
+                    } else {
+                        switchToTransientState(*nextState);
+                    }
+                } else {
+                    LOG(ERROR) << __func__ << ": start failed: " << status;
+                    mState = StreamDescriptor::State::ERROR;
+                }
             }
         } break;
         case Tag::burst:
diff --git a/audio/aidl/default/StreamStub.cpp b/audio/aidl/default/StreamStub.cpp
index d88dfbc..2dcf4d4 100644
--- a/audio/aidl/default/StreamStub.cpp
+++ b/audio/aidl/default/StreamStub.cpp
@@ -33,33 +33,67 @@
 
 StreamStub::StreamStub(const Metadata& metadata, StreamContext&& context)
     : StreamCommonImpl(metadata, std::move(context)),
-      mFrameSizeBytes(context.getFrameSize()),
-      mSampleRate(context.getSampleRate()),
-      mIsAsynchronous(!!context.getAsyncCallback()),
+      mFrameSizeBytes(getContext().getFrameSize()),
+      mSampleRate(getContext().getSampleRate()),
+      mIsAsynchronous(!!getContext().getAsyncCallback()),
       mIsInput(isInput(metadata)) {}
 
 ::android::status_t StreamStub::init() {
+    mIsInitialized = true;
     usleep(500);
     return ::android::OK;
 }
 
 ::android::status_t StreamStub::drain(StreamDescriptor::DrainMode) {
+    if (!mIsInitialized) {
+        LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
+    }
     usleep(500);
     return ::android::OK;
 }
 
 ::android::status_t StreamStub::flush() {
+    if (!mIsInitialized) {
+        LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
+    }
     usleep(500);
     return ::android::OK;
 }
 
 ::android::status_t StreamStub::pause() {
+    if (!mIsInitialized) {
+        LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
+    }
     usleep(500);
     return ::android::OK;
 }
 
+::android::status_t StreamStub::standby() {
+    if (!mIsInitialized) {
+        LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
+    }
+    usleep(500);
+    mIsStandby = true;
+    return ::android::OK;
+}
+
+::android::status_t StreamStub::start() {
+    if (!mIsInitialized) {
+        LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
+    }
+    usleep(500);
+    mIsStandby = false;
+    return ::android::OK;
+}
+
 ::android::status_t StreamStub::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
                                          int32_t* latencyMs) {
+    if (!mIsInitialized) {
+        LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
+    }
+    if (mIsStandby) {
+        LOG(FATAL) << __func__ << ": must not happen while in standby";
+    }
     static constexpr float kMicrosPerSecond = MICROS_PER_SECOND;
     static constexpr float kScaleFactor = .8f;
     if (mIsAsynchronous) {
@@ -80,13 +114,10 @@
     return ::android::OK;
 }
 
-::android::status_t StreamStub::standby() {
-    usleep(500);
-    return ::android::OK;
+void StreamStub::shutdown() {
+    mIsInitialized = false;
 }
 
-void StreamStub::shutdown() {}
-
 StreamInStub::StreamInStub(const SinkMetadata& sinkMetadata, StreamContext&& context,
                            const std::vector<MicrophoneInfo>& microphones)
     : StreamStub(sinkMetadata, std::move(context)), StreamIn(microphones) {}
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index e9f4fd4..aaf5860 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -180,9 +180,10 @@
     virtual ::android::status_t drain(StreamDescriptor::DrainMode mode) = 0;
     virtual ::android::status_t flush() = 0;
     virtual ::android::status_t pause() = 0;
+    virtual ::android::status_t standby() = 0;
+    virtual ::android::status_t start() = 0;
     virtual ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
                                          int32_t* latencyMs) = 0;
-    virtual ::android::status_t standby() = 0;
     virtual void shutdown() = 0;  // This function is only called once.
 };
 
diff --git a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
index c1194ab..2253ec7 100644
--- a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
+++ b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
@@ -35,9 +35,10 @@
     ::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,
                                  int32_t* latencyMs) override;
-    ::android::status_t standby() override;
     void shutdown() override;
 
     // Overridden methods of 'StreamCommonImpl', called on a Binder thread.
@@ -53,7 +54,6 @@
     const bool mIsInput;
     AudioConfig mStreamConfig;
     std::shared_ptr<SubmixRoute> mCurrentRoute = nullptr;
-    ::android::status_t mStatus = ::android::NO_INIT;
 
     // Mutex lock to protect vector of submix routes, each of these submix routes have their mutex
     // locks and none of the mutex locks should be taken together.
diff --git a/audio/aidl/default/include/core-impl/StreamStub.h b/audio/aidl/default/include/core-impl/StreamStub.h
index c8900f3..6b1b2dd 100644
--- a/audio/aidl/default/include/core-impl/StreamStub.h
+++ b/audio/aidl/default/include/core-impl/StreamStub.h
@@ -28,9 +28,10 @@
     ::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,
                                  int32_t* latencyMs) override;
-    ::android::status_t standby() override;
     void shutdown() override;
 
   private:
@@ -38,6 +39,8 @@
     const int mSampleRate;
     const bool mIsAsynchronous;
     const bool mIsInput;
+    bool mIsInitialized = false;  // Used for validating the state machine logic.
+    bool mIsStandby = true;       // Used for validating the state machine logic.
 };
 
 class StreamInStub final : public StreamStub, public StreamIn {
diff --git a/audio/aidl/default/include/core-impl/StreamUsb.h b/audio/aidl/default/include/core-impl/StreamUsb.h
index 5e55cd8..8c40782 100644
--- a/audio/aidl/default/include/core-impl/StreamUsb.h
+++ b/audio/aidl/default/include/core-impl/StreamUsb.h
@@ -16,7 +16,10 @@
 
 #pragma once
 
+#include <atomic>
+#include <functional>
 #include <mutex>
+#include <optional>
 #include <vector>
 
 #include <aidl/android/media/audio/common/AudioChannelLayout.h>
@@ -38,9 +41,10 @@
     ::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,
                                  int32_t* latencyMs) override;
-    ::android::status_t standby() override;
     void shutdown() override;
 
     // Overridden methods of 'StreamCommonImpl', called on a Binder thread.
@@ -48,15 +52,20 @@
     ndk::ScopedAStatus setConnectedDevices(const ConnectedDevices& devices) override;
 
   private:
-    ::android::status_t exitStandby();
+    using AlsaDeviceProxyDeleter = std::function<void(alsa_device_proxy*)>;
+    using AlsaDeviceProxy = std::unique_ptr<alsa_device_proxy, AlsaDeviceProxyDeleter>;
+
+    static std::optional<struct pcm_config> maybePopulateConfig(const StreamContext& context,
+                                                                bool isInput);
 
     mutable std::mutex mLock;
 
     const size_t mFrameSizeBytes;
-    std::optional<struct pcm_config> mConfig;
     const bool mIsInput;
-    std::vector<std::shared_ptr<alsa_device_proxy>> mAlsaDeviceProxies GUARDED_BY(mLock);
-    bool mIsStandby = true;
+    const std::optional<struct pcm_config> mConfig;
+    std::atomic<bool> mConnectedDevicesUpdated = false;
+    // All fields below are only used on the worker thread.
+    std::vector<AlsaDeviceProxy> mAlsaDeviceProxies;
 };
 
 class StreamInUsb final : public StreamUsb, public StreamIn {
diff --git a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
index 9cc6fb8..5af0d91 100644
--- a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
+++ b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
@@ -55,7 +55,7 @@
         mCurrentRoute = std::make_shared<SubmixRoute>();
         if (::android::OK != mCurrentRoute->createPipe(mStreamConfig)) {
             LOG(ERROR) << __func__ << ": create pipe failed";
-            return mStatus;
+            return ::android::NO_INIT;
         }
         {
             std::lock_guard guard(sSubmixRoutesLock);
@@ -64,12 +64,12 @@
     } else {
         if (!mCurrentRoute->isStreamConfigValid(mIsInput, mStreamConfig)) {
             LOG(ERROR) << __func__ << ": invalid stream config";
-            return mStatus;
+            return ::android::NO_INIT;
         }
         sp<MonoPipe> sink = mCurrentRoute->getSink();
         if (sink == nullptr) {
             LOG(ERROR) << __func__ << ": nullptr sink when opening stream";
-            return mStatus;
+            return ::android::NO_INIT;
         }
         // If the sink has been shutdown or pipe recreation is forced, delete the pipe and
         // recreate it.
@@ -77,14 +77,13 @@
             LOG(DEBUG) << __func__ << ": Non-nullptr shut down sink when opening stream";
             if (::android::OK != mCurrentRoute->resetPipe()) {
                 LOG(ERROR) << __func__ << ": reset pipe failed";
-                return mStatus;
+                return ::android::NO_INIT;
             }
         }
     }
 
     mCurrentRoute->openStream(mIsInput);
-    mStatus = ::android::OK;
-    return mStatus;
+    return ::android::OK;
 }
 
 ::android::status_t StreamRemoteSubmix::drain(StreamDescriptor::DrainMode) {
@@ -102,6 +101,16 @@
     return ::android::OK;
 }
 
+::android::status_t StreamRemoteSubmix::standby() {
+    mCurrentRoute->standby(mIsInput);
+    return ::android::OK;
+}
+
+::android::status_t StreamRemoteSubmix::start() {
+    mCurrentRoute->exitStandby(mIsInput);
+    return ::android::OK;
+}
+
 ndk::ScopedAStatus StreamRemoteSubmix::prepareToClose() {
     if (!mIsInput) {
         std::shared_ptr<SubmixRoute> route = nullptr;
@@ -138,17 +147,12 @@
 
         std::lock_guard guard(sSubmixRoutesLock);
         sSubmixRoutes.erase(mPortId);
-        mStatus = ::android::NO_INIT;
     }
+    mCurrentRoute.reset();
 }
 
 ::android::status_t StreamRemoteSubmix::transfer(void* buffer, size_t frameCount,
                                                  size_t* actualFrameCount, int32_t* latencyMs) {
-    if (mStatus != ::android::OK) {
-        LOG(ERROR) << __func__ << ": failed, not configured";
-        return ::android::NO_INIT;
-    }
-
     *latencyMs = (getStreamPipeSizeInFrames() * MILLIS_PER_SECOND) / mStreamConfig.sampleRate;
     LOG(VERBOSE) << __func__ << ": Latency " << *latencyMs << "ms";
 
@@ -171,7 +175,6 @@
         return ::android::UNEXPECTED_NULL;
     }
 
-    mCurrentRoute->exitStandby(mIsInput);
     return (mIsInput ? inRead(buffer, frameCount, actualFrameCount)
                      : outWrite(buffer, frameCount, actualFrameCount));
 }
@@ -329,11 +332,6 @@
     return ::android::OK;
 }
 
-::android::status_t StreamRemoteSubmix::standby() {
-    mCurrentRoute->standby(mIsInput);
-    return ::android::OK;
-}
-
 StreamInRemoteSubmix::StreamInRemoteSubmix(const SinkMetadata& sinkMetadata,
                                            StreamContext&& context,
                                            const std::vector<MicrophoneInfo>& microphones)
diff --git a/audio/aidl/default/usb/StreamUsb.cpp b/audio/aidl/default/usb/StreamUsb.cpp
index 49bc1d6..17e1ab4 100644
--- a/audio/aidl/default/usb/StreamUsb.cpp
+++ b/audio/aidl/default/usb/StreamUsb.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <limits>
+
 #define LOG_TAG "AHAL_StreamUsb"
 #include <android-base/logging.h>
 
@@ -45,25 +47,30 @@
 
 StreamUsb::StreamUsb(const Metadata& metadata, StreamContext&& context)
     : StreamCommonImpl(metadata, std::move(context)),
-      mFrameSizeBytes(context.getFrameSize()),
-      mIsInput(isInput(metadata)) {
+      mFrameSizeBytes(getContext().getFrameSize()),
+      mIsInput(isInput(metadata)),
+      mConfig(maybePopulateConfig(getContext(), mIsInput)) {}
+
+// static
+std::optional<struct pcm_config> StreamUsb::maybePopulateConfig(const StreamContext& context,
+                                                                bool isInput) {
     struct pcm_config config;
-    config.channels = usb::getChannelCountFromChannelMask(context.getChannelLayout(), mIsInput);
+    config.channels = usb::getChannelCountFromChannelMask(context.getChannelLayout(), isInput);
     if (config.channels == 0) {
         LOG(ERROR) << __func__ << ": invalid channel=" << context.getChannelLayout().toString();
-        return;
+        return std::nullopt;
     }
     config.format = usb::aidl2legacy_AudioFormatDescription_pcm_format(context.getFormat());
     if (config.format == PCM_FORMAT_INVALID) {
         LOG(ERROR) << __func__ << ": invalid format=" << context.getFormat().toString();
-        return;
+        return std::nullopt;
     }
     config.rate = context.getSampleRate();
     if (config.rate == 0) {
         LOG(ERROR) << __func__ << ": invalid sample rate=" << config.rate;
-        return;
+        return std::nullopt;
     }
-    mConfig = config;
+    return config;
 }
 
 ::android::status_t StreamUsb::init() {
@@ -89,8 +96,8 @@
         }
     }
     std::lock_guard guard(mLock);
-    mAlsaDeviceProxies.clear();
     RETURN_STATUS_IF_ERROR(StreamCommonImpl::setConnectedDevices(connectedDevices));
+    mConnectedDevicesUpdated.store(true, std::memory_order_release);
     return ndk::ScopedAStatus::ok();
 }
 
@@ -111,59 +118,53 @@
 
 ::android::status_t StreamUsb::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
                                         int32_t* latencyMs) {
-    {
-        std::lock_guard guard(mLock);
-        if (!mConfig.has_value() || mConnectedDevices.empty()) {
-            LOG(ERROR) << __func__ << ": failed, has config: " << mConfig.has_value()
-                       << ", has connected devices: " << mConnectedDevices.empty();
-            return ::android::NO_INIT;
-        }
-    }
-    if (mIsStandby) {
-        if (::android::status_t status = exitStandby(); status != ::android::OK) {
-            LOG(ERROR) << __func__ << ": failed to exit standby, status=" << status;
-            return status;
-        }
-    }
-    std::vector<std::shared_ptr<alsa_device_proxy>> alsaDeviceProxies;
-    {
-        std::lock_guard guard(mLock);
-        alsaDeviceProxies = mAlsaDeviceProxies;
+    if (mConnectedDevicesUpdated.load(std::memory_order_acquire)) {
+        // 'setConnectedDevices' has been called. I/O will be restarted.
+        *actualFrameCount = 0;
+        *latencyMs = StreamDescriptor::LATENCY_UNKNOWN;
+        return ::android::OK;
     }
     const size_t bytesToTransfer = frameCount * mFrameSizeBytes;
+    unsigned maxLatency = 0;
     if (mIsInput) {
+        if (mAlsaDeviceProxies.empty()) {
+            LOG(FATAL) << __func__ << ": no input devices";
+            return ::android::NO_INIT;
+        }
         // For input case, only support single device.
-        proxy_read(alsaDeviceProxies[0].get(), buffer, bytesToTransfer);
+        proxy_read(mAlsaDeviceProxies[0].get(), buffer, bytesToTransfer);
+        maxLatency = proxy_get_latency(mAlsaDeviceProxies[0].get());
     } else {
-        for (auto& proxy : alsaDeviceProxies) {
+        for (auto& proxy : mAlsaDeviceProxies) {
             proxy_write(proxy.get(), buffer, bytesToTransfer);
+            maxLatency = std::max(maxLatency, proxy_get_latency(proxy.get()));
         }
     }
     *actualFrameCount = frameCount;
-    *latencyMs = Module::kLatencyMs;
+    maxLatency = std::min(maxLatency, static_cast<unsigned>(std::numeric_limits<int32_t>::max()));
+    *latencyMs = maxLatency;
     return ::android::OK;
 }
 
 ::android::status_t StreamUsb::standby() {
-    if (!mIsStandby) {
-        std::lock_guard guard(mLock);
-        mAlsaDeviceProxies.clear();
-        mIsStandby = true;
-    }
+    mAlsaDeviceProxies.clear();
     return ::android::OK;
 }
 
-void StreamUsb::shutdown() {}
+void StreamUsb::shutdown() {
+    mAlsaDeviceProxies.clear();
+}
 
-::android::status_t StreamUsb::exitStandby() {
+::android::status_t StreamUsb::start() {
     std::vector<AudioDeviceAddress> connectedDevices;
     {
         std::lock_guard guard(mLock);
         std::transform(mConnectedDevices.begin(), mConnectedDevices.end(),
                        std::back_inserter(connectedDevices),
                        [](const auto& device) { return device.address; });
+        mConnectedDevicesUpdated.store(false, std::memory_order_release);
     }
-    std::vector<std::shared_ptr<alsa_device_proxy>> alsaDeviceProxies;
+    decltype(mAlsaDeviceProxies) alsaDeviceProxies;
     for (const auto& device : connectedDevices) {
         alsa_device_profile profile;
         profile_init(&profile, mIsInput ? PCM_IN : PCM_OUT);
@@ -175,16 +176,16 @@
             return ::android::UNKNOWN_ERROR;
         }
 
-        auto proxy = std::shared_ptr<alsa_device_proxy>(new alsa_device_proxy(),
-                                                        [](alsa_device_proxy* proxy) {
-                                                            proxy_close(proxy);
-                                                            free(proxy);
-                                                        });
+        AlsaDeviceProxy proxy(new alsa_device_proxy, [](alsa_device_proxy* proxy) {
+            proxy_close(proxy);
+            free(proxy);
+        });
         // 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, &mConfig.value(), true /*is_bit_perfect*/);
+        if (int err = proxy_prepare(proxy.get(), &profile,
+                                    const_cast<struct pcm_config*>(&mConfig.value()),
+                                    true /*is_bit_perfect*/);
             err != 0) {
             LOG(ERROR) << __func__ << ": fail to prepare for device address=" << device.toString()
                        << " error=" << err;
@@ -197,11 +198,7 @@
         }
         alsaDeviceProxies.push_back(std::move(proxy));
     }
-    {
-        std::lock_guard guard(mLock);
-        mAlsaDeviceProxies = alsaDeviceProxies;
-    }
-    mIsStandby = false;
+    mAlsaDeviceProxies = std::move(alsaDeviceProxies);
     return ::android::OK;
 }