audio: Update StreamAlsa and alsa utils for built-in devices

Use new functions added to alsa proxy layer for opening
attached (built-in) devices.

Bug: 264712385
Test: atest VtsHalAudioCoreTargetTest
Change-Id: Ia2a47ff96fa62f99ce4ec4a0993ca3fd86f82c9d
diff --git a/audio/aidl/default/alsa/StreamAlsa.cpp b/audio/aidl/default/alsa/StreamAlsa.cpp
index 17c7feb..bdbe573 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)
+StreamAlsa::StreamAlsa(const Metadata& metadata, StreamContext&& context, int readWriteRetries)
     : StreamCommonImpl(metadata, std::move(context)),
       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