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/Stream.cpp b/audio/aidl/default/Stream.cpp
index 215de94..470b65b 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);
}
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
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index e64c578..a1bc9b4 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -132,6 +132,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;
}
diff --git a/audio/aidl/default/include/core-impl/StreamAlsa.h b/audio/aidl/default/include/core-impl/StreamAlsa.h
index 5744d66..700573f 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 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 @@
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/StreamUsb.h b/audio/aidl/default/include/core-impl/StreamUsb.h
index 44f742a..0189b6b 100644
--- a/audio/aidl/default/include/core-impl/StreamUsb.h
+++ b/audio/aidl/default/include/core-impl/StreamUsb.h
@@ -30,9 +30,6 @@
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 da0ad11..f664245 100644
--- a/audio/aidl/default/usb/StreamUsb.cpp
+++ b/audio/aidl/default/usb/StreamUsb.cpp
@@ -36,7 +36,7 @@
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<AudioDevice>& connectedDevices) {
@@ -62,21 +62,6 @@
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)) {