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

Commit eafa78c9 authored by Mikhail Naganov's avatar Mikhail Naganov Committed by Gerrit Code Review
Browse files

Merge changes from topic "fix-aidl-mix-ports-and-bt" into main

* changes:
  audio: Fix BT AIDL HAL module implementation
  audio r_submix: Suggest configuration from the peer
  audio: Refactor configuration population
parents 8ef6a817 a88cf60b
Loading
Loading
Loading
Loading
+48 −36
Original line number Diff line number Diff line
@@ -93,32 +93,6 @@ bool hasDynamicProfilesOnly(const std::vector<AudioProfile>& profiles) {
    return std::all_of(profiles.begin(), profiles.end(), isDynamicProfile);
}

// Note: does not assign an ID to the config.
bool generateDefaultPortConfig(const AudioPort& port, AudioPortConfig* config) {
    const bool allowDynamicConfig = port.ext.getTag() == AudioPortExt::device;
    *config = {};
    config->portId = port.id;
    for (const auto& profile : port.profiles) {
        if (isDynamicProfile(profile)) continue;
        config->format = profile.format;
        config->channelMask = *profile.channelMasks.begin();
        config->sampleRate = Int{.value = *profile.sampleRates.begin()};
        config->flags = port.flags;
        config->ext = port.ext;
        return true;
    }
    if (allowDynamicConfig) {
        config->format = AudioFormatDescription{};
        config->channelMask = AudioChannelLayout{};
        config->sampleRate = Int{.value = 0};
        config->flags = port.flags;
        config->ext = port.ext;
        return true;
    }
    LOG(ERROR) << __func__ << ": port " << port.id << " only has dynamic profiles";
    return false;
}

bool findAudioProfile(const AudioPort& port, const AudioFormatDescription& format,
                      AudioProfile* profile) {
    if (auto profilesIt =
@@ -204,10 +178,11 @@ ndk::ScopedAStatus Module::createStreamContext(
    }
    auto& configs = getConfig().portConfigs;
    auto portConfigIt = findById<AudioPortConfig>(configs, in_portConfigId);
    const int32_t nominalLatencyMs = getNominalLatencyMs(*portConfigIt);
    // Since this is a private method, it is assumed that
    // validity of the portConfigId has already been checked.
    const int32_t minimumStreamBufferSizeFrames = calculateBufferSizeFrames(
            getNominalLatencyMs(*portConfigIt), portConfigIt->sampleRate.value().value);
    const int32_t minimumStreamBufferSizeFrames =
            calculateBufferSizeFrames(nominalLatencyMs, portConfigIt->sampleRate.value().value);
    if (in_bufferSizeFrames < minimumStreamBufferSizeFrames) {
        LOG(ERROR) << __func__ << ": insufficient buffer size " << in_bufferSizeFrames
                   << ", must be at least " << minimumStreamBufferSizeFrames;
@@ -241,7 +216,7 @@ ndk::ScopedAStatus Module::createStreamContext(
                std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
                std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
                portConfigIt->format.value(), portConfigIt->channelMask.value(),
                portConfigIt->sampleRate.value().value, flags, getNominalLatencyMs(*portConfigIt),
                portConfigIt->sampleRate.value().value, flags, nominalLatencyMs,
                portConfigIt->ext.get<AudioPortExt::mix>().handle,
                std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames),
                asyncCallback, outEventCallback,
@@ -328,6 +303,29 @@ ndk::ScopedAStatus Module::findPortIdForNewStream(int32_t in_portConfigId, Audio
    return ndk::ScopedAStatus::ok();
}

bool Module::generateDefaultPortConfig(const AudioPort& port, AudioPortConfig* config) {
    const bool allowDynamicConfig = port.ext.getTag() == AudioPortExt::device;
    for (const auto& profile : port.profiles) {
        if (isDynamicProfile(profile)) continue;
        config->format = profile.format;
        config->channelMask = *profile.channelMasks.begin();
        config->sampleRate = Int{.value = *profile.sampleRates.begin()};
        config->flags = port.flags;
        config->ext = port.ext;
        return true;
    }
    if (allowDynamicConfig) {
        config->format = AudioFormatDescription{};
        config->channelMask = AudioChannelLayout{};
        config->sampleRate = Int{.value = 0};
        config->flags = port.flags;
        config->ext = port.ext;
        return true;
    }
    LOG(ERROR) << __func__ << ": port " << port.id << " only has dynamic profiles";
    return false;
}

void Module::populateConnectedProfiles() {
    Configuration& config = getConfig();
    for (const AudioPort& port : config.ports) {
@@ -617,10 +615,11 @@ ndk::ScopedAStatus Module::connectExternalDevice(const AudioPort& in_templateIdA

    std::vector<AudioRoute*> routesToMixPorts = getAudioRoutesForAudioPortImpl(templateId);
    std::set<int32_t> routableMixPortIds = getRoutableAudioPortIds(templateId, &routesToMixPorts);
    const int32_t nextPortId = getConfig().nextPortId++;
    if (!mDebug.simulateDeviceConnections) {
        // Even if the device port has static profiles, the HAL module might need to update
        // them, or abort the connection process.
        RETURN_STATUS_IF_ERROR(populateConnectedDevicePort(&connectedPort));
        RETURN_STATUS_IF_ERROR(populateConnectedDevicePort(&connectedPort, nextPortId));
    } else if (hasDynamicProfilesOnly(connectedPort.profiles)) {
        auto& connectedProfiles = getConfig().connectedProfiles;
        if (auto connectedProfilesIt = connectedProfiles.find(templateId);
@@ -644,7 +643,7 @@ ndk::ScopedAStatus Module::connectExternalDevice(const AudioPort& in_templateIdA
        }
    }

    connectedPort.id = getConfig().nextPortId++;
    connectedPort.id = nextPortId;
    auto [connectedPortsIt, _] =
            mConnectedDevicePorts.insert(std::pair(connectedPort.id, std::set<int32_t>()));
    LOG(DEBUG) << __func__ << ": template port " << templateId << " external device connected, "
@@ -1035,6 +1034,18 @@ ndk::ScopedAStatus Module::setAudioPatch(const AudioPatch& in_requested, AudioPa

ndk::ScopedAStatus Module::setAudioPortConfig(const AudioPortConfig& in_requested,
                                              AudioPortConfig* out_suggested, bool* _aidl_return) {
    auto generate = [this](const AudioPort& port, AudioPortConfig* config) {
        return generateDefaultPortConfig(port, config);
    };
    return setAudioPortConfigImpl(in_requested, generate, out_suggested, _aidl_return);
}

ndk::ScopedAStatus Module::setAudioPortConfigImpl(
        const AudioPortConfig& in_requested,
        const std::function<bool(const ::aidl::android::media::audio::common::AudioPort& port,
                                 ::aidl::android::media::audio::common::AudioPortConfig* config)>&
                fillPortConfig,
        AudioPortConfig* out_suggested, bool* applied) {
    LOG(DEBUG) << __func__ << ": requested " << in_requested.toString();
    auto& configs = getConfig().portConfigs;
    auto existing = configs.end();
@@ -1063,7 +1074,8 @@ ndk::ScopedAStatus Module::setAudioPortConfig(const AudioPortConfig& in_requeste
        *out_suggested = *existing;
    } else {
        AudioPortConfig newConfig;
        if (generateDefaultPortConfig(*portIt, &newConfig)) {
        newConfig.portId = portIt->id;
        if (fillPortConfig(*portIt, &newConfig)) {
            *out_suggested = newConfig;
        } else {
            LOG(ERROR) << __func__ << ": unable generate a default config for port " << portId;
@@ -1168,17 +1180,17 @@ ndk::ScopedAStatus Module::setAudioPortConfig(const AudioPortConfig& in_requeste
    if (existing == configs.end() && requestedIsValid && requestedIsFullySpecified) {
        out_suggested->id = getConfig().nextPortId++;
        configs.push_back(*out_suggested);
        *_aidl_return = true;
        *applied = true;
        LOG(DEBUG) << __func__ << ": created new port config " << out_suggested->toString();
    } else if (existing != configs.end() && requestedIsValid) {
        *existing = *out_suggested;
        *_aidl_return = true;
        *applied = true;
        LOG(DEBUG) << __func__ << ": updated port config " << out_suggested->toString();
    } else {
        LOG(DEBUG) << __func__ << ": not applied; existing config ? " << (existing != configs.end())
                   << "; requested is valid? " << requestedIsValid << ", fully specified? "
                   << requestedIsFullySpecified;
        *_aidl_return = false;
        *applied = false;
    }
    return ndk::ScopedAStatus::ok();
}
@@ -1530,7 +1542,7 @@ bool Module::isMmapSupported() {
    return mIsMmapSupported.value();
}

ndk::ScopedAStatus Module::populateConnectedDevicePort(AudioPort* audioPort) {
ndk::ScopedAStatus Module::populateConnectedDevicePort(AudioPort* audioPort, int32_t) {
    if (audioPort->ext.getTag() != AudioPortExt::device) {
        LOG(ERROR) << __func__ << ": not a device port: " << audioPort->toString();
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+1 −1
Original line number Diff line number Diff line
@@ -34,7 +34,7 @@ using aidl::android::media::audio::common::AudioProfile;

namespace aidl::android::hardware::audio::core {

ndk::ScopedAStatus ModuleAlsa::populateConnectedDevicePort(AudioPort* audioPort) {
ndk::ScopedAStatus ModuleAlsa::populateConnectedDevicePort(AudioPort* audioPort, int32_t) {
    auto deviceProfile = alsa::getDeviceProfile(*audioPort);
    if (!deviceProfile.has_value()) {
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+19 −18
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@
 * limitations under the License.
 */

#define LOG_TAG "AHAL_BluetoothPortProxy"
#define LOG_TAG "AHAL_BluetoothAudioPort"

#include <android-base/logging.h>
#include <android-base/stringprintf.h>
@@ -254,12 +254,7 @@ bool BluetoothAudioPortAidl::inUse() const {
    return (mCookie != ::aidl::android::hardware::bluetooth::audio::kObserversCookieUndefined);
}

bool BluetoothAudioPortAidl::getPreferredDataIntervalUs(size_t* interval_us) const {
    if (!interval_us) {
        LOG(ERROR) << __func__ << ": bad input arg";
        return false;
    }

bool BluetoothAudioPortAidl::getPreferredDataIntervalUs(size_t& interval_us) const {
    if (!inUse()) {
        LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
        return false;
@@ -272,16 +267,11 @@ bool BluetoothAudioPortAidl::getPreferredDataIntervalUs(size_t* interval_us) con
        return false;
    }

    *interval_us = hal_audio_cfg.get<AudioConfiguration::pcmConfig>().dataIntervalUs;
    interval_us = hal_audio_cfg.get<AudioConfiguration::pcmConfig>().dataIntervalUs;
    return true;
}

bool BluetoothAudioPortAidl::loadAudioConfig(PcmConfiguration* audio_cfg) const {
    if (!audio_cfg) {
        LOG(ERROR) << __func__ << ": bad input arg";
        return false;
    }

bool BluetoothAudioPortAidl::loadAudioConfig(PcmConfiguration& audio_cfg) {
    if (!inUse()) {
        LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
        return false;
@@ -293,15 +283,26 @@ bool BluetoothAudioPortAidl::loadAudioConfig(PcmConfiguration* audio_cfg) const
        LOG(ERROR) << __func__ << ": unsupported audio cfg tag";
        return false;
    }
    *audio_cfg = hal_audio_cfg.get<AudioConfiguration::pcmConfig>();
    audio_cfg = hal_audio_cfg.get<AudioConfiguration::pcmConfig>();
    LOG(VERBOSE) << __func__ << debugMessage() << ", state*=" << getState() << ", PcmConfig=["
                 << audio_cfg->toString() << "]";
    if (audio_cfg->channelMode == ChannelMode::UNKNOWN) {
                 << audio_cfg.toString() << "]";
    if (audio_cfg.channelMode == ChannelMode::UNKNOWN) {
        return false;
    }
    return true;
}

bool BluetoothAudioPortAidlOut::loadAudioConfig(PcmConfiguration& audio_cfg) {
    if (!BluetoothAudioPortAidl::loadAudioConfig(audio_cfg)) return false;
    // WAR to support Mono / 16 bits per sample as the Bluetooth stack requires
    if (audio_cfg.channelMode == ChannelMode::MONO && audio_cfg.bitsPerSample == 16) {
        mIsStereoToMono = true;
        audio_cfg.channelMode = ChannelMode::STEREO;
        LOG(INFO) << __func__ << ": force channels = to be AUDIO_CHANNEL_OUT_STEREO";
    }
    return true;
}

bool BluetoothAudioPortAidl::standby() {
    if (!inUse()) {
        LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
@@ -435,7 +436,7 @@ bool BluetoothAudioPortAidl::suspend() {
                retval = condWaitState(BluetoothStreamState::SUSPENDING);
            } else {
                LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState()
                           << " Hal fails";
                           << " failure to suspend stream";
            }
        }
    }
+205 −27

File changed.

Preview size limit exceeded, changes collapsed.

+103 −163

File changed.

Preview size limit exceeded, changes collapsed.

Loading