Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 422f7e6b authored by Mikhail Naganov's avatar Mikhail Naganov
Browse files

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
parent f12d4a1e
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -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);
}
+35 −24
Original line number Diff line number Diff line
@@ -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;
        }

        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()),
        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*/);
            err != 0) {
            LOG(ERROR) << __func__ << ": fail to prepare for device address=" << device
                       << " error=" << err;
            return ::android::UNKNOWN_ERROR;
        } else {
            proxy = alsa::openProxyForAttachedDevice(
                    device, const_cast<struct pcm_config*>(&mConfig.value()),
                    getContext().getBufferSizeInFrames());
        }
        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()));
        }
    }
+53 −1
Original line number Diff line number Diff line
@@ -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);
+5 −0
Original line number Diff line number Diff line
@@ -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
+1 −0
Original line number Diff line number Diff line
@@ -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;
    }
Loading