From 422f7e6b1b36359e5dd1492b17d29afbbe546c87 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Thu, 13 Jul 2023 16:32:08 -0700 Subject: [PATCH] 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 --- audio/aidl/default/Stream.cpp | 12 +++- audio/aidl/default/alsa/StreamAlsa.cpp | 59 +++++++++++-------- audio/aidl/default/alsa/Utils.cpp | 54 ++++++++++++++++- audio/aidl/default/alsa/Utils.h | 5 ++ audio/aidl/default/include/core-impl/Stream.h | 1 + .../default/include/core-impl/StreamAlsa.h | 6 +- .../default/include/core-impl/StreamUsb.h | 3 - audio/aidl/default/usb/StreamUsb.cpp | 17 +----- 8 files changed, 109 insertions(+), 48 deletions(-) diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp index 215de94a31..470b65b749 100644 --- a/audio/aidl/default/Stream.cpp +++ b/audio/aidl/default/Stream.cpp @@ -47,13 +47,19 @@ void StreamContext::fillDescriptor(StreamDescriptor* desc) { 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(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); } diff --git a/audio/aidl/default/alsa/StreamAlsa.cpp b/audio/aidl/default/alsa/StreamAlsa.cpp index 17c7febdd1..bdbe5733b9 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 @@ StreamAlsa::StreamAlsa(const Metadata& metadata, StreamContext&& context) ::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(&mConfig.value()), + true /*require_exact_match*/); + } else { + proxy = alsa::openProxyForAttachedDevice( + device, const_cast(&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(&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 @@ StreamAlsa::StreamAlsa(const Metadata& metadata, StreamContext&& context) 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 162f8529cf..20f77978fd 100644 --- a/audio/aidl/default/alsa/Utils.cpp +++ b/audio/aidl/default/alsa/Utils.cpp @@ -217,7 +217,8 @@ std::optional getDeviceProfile( } 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 getDeviceProfile( @@ -269,6 +270,57 @@ DeviceProxy makeDeviceProxy() { }); } +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 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 c1b9b380c0..615e657064 100644 --- a/audio/aidl/default/alsa/Utils.h +++ b/audio/aidl/default/alsa/Utils.h @@ -40,6 +40,7 @@ struct DeviceProfile { 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; @@ -60,6 +61,10 @@ std::optional getDeviceProfile( std::optional getPcmConfig(const StreamContext& context, bool isInput); std::vector 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 readAlsaDeviceInfo(const DeviceProfile& deviceProfile); ::aidl::android::media::audio::common::AudioFormatDescription diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h index e64c578b68..a1bc9b4b85 100644 --- a/audio/aidl/default/include/core-impl/Stream.h +++ b/audio/aidl/default/include/core-impl/Stream.h @@ -132,6 +132,7 @@ class StreamContext { void fillDescriptor(StreamDescriptor* desc); std::shared_ptr getAsyncCallback() const { return mAsyncCallback; } + size_t getBufferSizeInFrames() const; ::aidl::android::media::audio::common::AudioChannelLayout getChannelLayout() const { return mChannelLayout; } diff --git a/audio/aidl/default/include/core-impl/StreamAlsa.h b/audio/aidl/default/include/core-impl/StreamAlsa.h index 5744d665f3..700573f1da 100644 --- a/audio/aidl/default/include/core-impl/StreamAlsa.h +++ b/audio/aidl/default/include/core-impl/StreamAlsa.h @@ -31,9 +31,12 @@ namespace aidl::android::hardware::audio::core { // provide necessary overrides for all interface methods omitted here. class StreamAlsa : public StreamCommonImpl { public: - StreamAlsa(const Metadata& metadata, StreamContext&& context); + StreamAlsa(const Metadata& metadata, StreamContext&& context, 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 @@ class StreamAlsa : public StreamCommonImpl { const size_t mFrameSizeBytes; const bool mIsInput; const std::optional mConfig; + const int mReadWriteRetries; // All fields below are only used on the worker thread. std::vector mAlsaDeviceProxies; }; diff --git a/audio/aidl/default/include/core-impl/StreamUsb.h b/audio/aidl/default/include/core-impl/StreamUsb.h index 44f742a4dd..0189b6b7ed 100644 --- a/audio/aidl/default/include/core-impl/StreamUsb.h +++ b/audio/aidl/default/include/core-impl/StreamUsb.h @@ -30,9 +30,6 @@ class StreamUsb : public StreamAlsa { public: StreamUsb(const Metadata& metadata, StreamContext&& context); // 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; diff --git a/audio/aidl/default/usb/StreamUsb.cpp b/audio/aidl/default/usb/StreamUsb.cpp index da0ad11be2..f6642450c8 100644 --- a/audio/aidl/default/usb/StreamUsb.cpp +++ b/audio/aidl/default/usb/StreamUsb.cpp @@ -36,7 +36,7 @@ using aidl::android::media::audio::common::MicrophoneInfo; namespace aidl::android::hardware::audio::core { StreamUsb::StreamUsb(const Metadata& metadata, StreamContext&& context) - : StreamAlsa(metadata, std::move(context)) {} + : StreamAlsa(metadata, std::move(context), 1 /*readWriteRetries*/) {} ndk::ScopedAStatus StreamUsb::setConnectedDevices( const std::vector& connectedDevices) { @@ -62,21 +62,6 @@ ndk::ScopedAStatus StreamUsb::setConnectedDevices( 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)) {