mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 11:36:00 +00:00
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
(cherry picked from commit 422f7e6b1b)
Merged-In: Ia2a47ff96fa62f99ce4ec4a0993ca3fd86f82c9d
This commit is contained in:
@@ -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<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);
|
||||
}
|
||||
|
||||
@@ -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<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 @@ 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()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,7 +217,8 @@ std::optional<DeviceProfile> 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<DeviceProfile> 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<alsa_device_profile> readAlsaDeviceInfo(const DeviceProfile& deviceProfile) {
|
||||
alsa_device_profile profile;
|
||||
profile_init(&profile, deviceProfile.direction);
|
||||
|
||||
@@ -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<void(alsa_device_proxy*)>;
|
||||
@@ -60,6 +61,10 @@ std::optional<DeviceProfile> getDeviceProfile(
|
||||
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
|
||||
|
||||
@@ -132,6 +132,7 @@ class StreamContext {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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<struct pcm_config> mConfig;
|
||||
const int mReadWriteRetries;
|
||||
// All fields below are only used on the worker thread.
|
||||
std::vector<alsa::DeviceProxy> mAlsaDeviceProxies;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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<AudioDevice>& 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)) {
|
||||
|
||||
Reference in New Issue
Block a user