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

Commit f48e129f authored by Mikhail Naganov's avatar Mikhail Naganov Committed by Automerger Merge Worker
Browse files

audio r_submix: Suggest configuration from the peer am: 3b732895 am: de6a93d4

parents a667344e de6a93d4
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -29,6 +29,10 @@ class ModuleRemoteSubmix : public Module {
    // IModule interfaces
    ndk::ScopedAStatus getMicMute(bool* _aidl_return) override;
    ndk::ScopedAStatus setMicMute(bool in_mute) override;
    ndk::ScopedAStatus setAudioPortConfig(
            const ::aidl::android::media::audio::common::AudioPortConfig& in_requested,
            ::aidl::android::media::audio::common::AudioPortConfig* out_suggested,
            bool* _aidl_return) override;

    // Module interfaces
    ndk::ScopedAStatus createInputStream(
+0 −8
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

#pragma once

#include <mutex>
#include <vector>

#include "core-impl/Stream.h"
@@ -56,13 +55,6 @@ class StreamRemoteSubmix : public StreamCommonImpl {
    r_submix::AudioConfig mStreamConfig;
    std::shared_ptr<r_submix::SubmixRoute> mCurrentRoute = nullptr;

    // Mutex lock to protect vector of submix routes, each of these submix routes have their mutex
    // locks and none of the mutex locks should be taken together.
    static std::mutex sSubmixRoutesLock;
    static std::map<::aidl::android::media::audio::common::AudioDeviceAddress,
                    std::shared_ptr<r_submix::SubmixRoute>>
            sSubmixRoutes GUARDED_BY(sSubmixRoutesLock);

    // limit for number of read error log entries to avoid spamming the logs
    static constexpr int kMaxReadErrorLogs = 5;
    // The duration of kMaxReadFailureAttempts * READ_ATTEMPT_SLEEP_MS must be strictly inferior
+59 −1
Original line number Diff line number Diff line
@@ -27,14 +27,36 @@

using aidl::android::hardware::audio::common::SinkMetadata;
using aidl::android::hardware::audio::common::SourceMetadata;
using aidl::android::media::audio::common::AudioDeviceAddress;
using aidl::android::media::audio::common::AudioFormatType;
using aidl::android::media::audio::common::AudioIoFlags;
using aidl::android::media::audio::common::AudioOffloadInfo;
using aidl::android::media::audio::common::AudioPort;
using aidl::android::media::audio::common::AudioPortConfig;
using aidl::android::media::audio::common::AudioPortExt;
using aidl::android::media::audio::common::AudioProfile;
using aidl::android::media::audio::common::Int;
using aidl::android::media::audio::common::MicrophoneInfo;

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

namespace {

std::optional<r_submix::AudioConfig> getRemoteEndConfig(const AudioPort& audioPort) {
    const auto& deviceAddress = audioPort.ext.get<AudioPortExt::device>().device.address;
    const bool isInput = audioPort.flags.getTag() == AudioIoFlags::input;
    if (auto submixRoute = r_submix::SubmixRoute::findRoute(deviceAddress);
        submixRoute != nullptr) {
        if ((isInput && submixRoute->isStreamOutOpen()) ||
            (!isInput && submixRoute->isStreamInOpen())) {
            return submixRoute->getPipeConfig();
        }
    }
    return {};
}

}  // namespace

ndk::ScopedAStatus ModuleRemoteSubmix::getMicMute(bool* _aidl_return __unused) {
    LOG(DEBUG) << __func__ << ": is not supported";
    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
@@ -45,6 +67,26 @@ ndk::ScopedAStatus ModuleRemoteSubmix::setMicMute(bool in_mute __unused) {
    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}

ndk::ScopedAStatus ModuleRemoteSubmix::setAudioPortConfig(const AudioPortConfig& in_requested,
                                                          AudioPortConfig* out_suggested,
                                                          bool* _aidl_return) {
    auto fillConfig = [this](const AudioPort& port, AudioPortConfig* config) {
        if (port.ext.getTag() == AudioPortExt::device) {
            if (auto pipeConfig = getRemoteEndConfig(port); pipeConfig.has_value()) {
                LOG(DEBUG) << "setAudioPortConfig: suggesting port config from the remote end.";
                config->format = pipeConfig->format;
                config->channelMask = pipeConfig->channelLayout;
                config->sampleRate = Int{.value = pipeConfig->sampleRate};
                config->flags = port.flags;
                config->ext = port.ext;
                return true;
            }
        }
        return generateDefaultPortConfig(port, config);
    };
    return Module::setAudioPortConfigImpl(in_requested, fillConfig, out_suggested, _aidl_return);
}

ndk::ScopedAStatus ModuleRemoteSubmix::createInputStream(
        StreamContext&& context, const SinkMetadata& sinkMetadata,
        const std::vector<MicrophoneInfo>& microphones, std::shared_ptr<StreamIn>* result) {
@@ -68,7 +110,22 @@ ndk::ScopedAStatus ModuleRemoteSubmix::createOutputStream(
}

ndk::ScopedAStatus ModuleRemoteSubmix::populateConnectedDevicePort(AudioPort* audioPort, int32_t) {
    // Find the corresponding mix port and copy its profiles.
    if (audioPort->ext.getTag() != AudioPortExt::device) {
        LOG(ERROR) << __func__ << ": not a device port: " << audioPort->toString();
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
    }
    // If there is already a pipe with a stream for the port address, provide its configuration as
    // the only option. Otherwise, find the corresponding mix port and copy its profiles.
    if (auto pipeConfig = getRemoteEndConfig(*audioPort); pipeConfig.has_value()) {
        audioPort->profiles.clear();
        audioPort->profiles.push_back(AudioProfile{
                .format = pipeConfig->format,
                .channelMasks = std::vector<AudioChannelLayout>({pipeConfig->channelLayout}),
                .sampleRates = std::vector<int>({pipeConfig->sampleRate})});
        LOG(DEBUG) << __func__ << ": populated from remote end as: " << audioPort->toString();
        return ndk::ScopedAStatus::ok();
    }

    // At this moment, the port has the same ID as the template port, see connectExternalDevice.
    std::vector<AudioRoute*> routes = getAudioRoutesForAudioPortImpl(audioPort->id);
    if (routes.empty()) {
@@ -87,6 +144,7 @@ ndk::ScopedAStatus ModuleRemoteSubmix::populateConnectedDevicePort(AudioPort* au
        RETURN_STATUS_IF_ERROR(getAudioPort(route->sinkPortId, &mixPort));
    }
    audioPort->profiles = mixPort.profiles;
    LOG(DEBUG) << __func__ << ": populated from the mix port as: " << audioPort->toString();
    return ndk::ScopedAStatus::ok();
}

+6 −32
Original line number Diff line number Diff line
@@ -43,27 +43,11 @@ StreamRemoteSubmix::StreamRemoteSubmix(StreamContext* context, const Metadata& m
    mStreamConfig.sampleRate = context->getSampleRate();
}

std::mutex StreamRemoteSubmix::sSubmixRoutesLock;
std::map<AudioDeviceAddress, std::shared_ptr<SubmixRoute>> StreamRemoteSubmix::sSubmixRoutes;

::android::status_t StreamRemoteSubmix::init() {
    {
        std::lock_guard guard(sSubmixRoutesLock);
        auto routeItr = sSubmixRoutes.find(mDeviceAddress);
        if (routeItr != sSubmixRoutes.end()) {
            mCurrentRoute = routeItr->second;
        }
        // If route is not available for this port, add it.
    mCurrentRoute = SubmixRoute::findOrCreateRoute(mDeviceAddress, mStreamConfig);
    if (mCurrentRoute == nullptr) {
            // Initialize the pipe.
            mCurrentRoute = std::make_shared<SubmixRoute>();
            if (::android::OK != mCurrentRoute->createPipe(mStreamConfig)) {
                LOG(ERROR) << __func__ << ": create pipe failed";
        return ::android::NO_INIT;
    }
            sSubmixRoutes.emplace(mDeviceAddress, mCurrentRoute);
        }
    }
    if (!mCurrentRoute->isStreamConfigValid(mIsInput, mStreamConfig)) {
        LOG(ERROR) << __func__ << ": invalid stream config";
        return ::android::NO_INIT;
@@ -80,7 +64,6 @@ std::map<AudioDeviceAddress, std::shared_ptr<SubmixRoute>> StreamRemoteSubmix::s
            return ::android::NO_INIT;
        }
    }

    mCurrentRoute->openStream(mIsInput);
    return ::android::OK;
}
@@ -114,14 +97,7 @@ std::map<AudioDeviceAddress, std::shared_ptr<SubmixRoute>> StreamRemoteSubmix::s

ndk::ScopedAStatus StreamRemoteSubmix::prepareToClose() {
    if (!mIsInput) {
        std::shared_ptr<SubmixRoute> route = nullptr;
        {
            std::lock_guard guard(sSubmixRoutesLock);
            auto routeItr = sSubmixRoutes.find(mDeviceAddress);
            if (routeItr != sSubmixRoutes.end()) {
                route = routeItr->second;
            }
        }
        std::shared_ptr<SubmixRoute> route = SubmixRoute::findRoute(mDeviceAddress);
        if (route != nullptr) {
            sp<MonoPipe> sink = route->getSink();
            if (sink == nullptr) {
@@ -148,9 +124,7 @@ void StreamRemoteSubmix::shutdown() {
    if (!mCurrentRoute->hasAtleastOneStreamOpen()) {
        mCurrentRoute->releasePipe();
        LOG(DEBUG) << __func__ << ": pipe destroyed";

        std::lock_guard guard(sSubmixRoutesLock);
        sSubmixRoutes.erase(mDeviceAddress);
        SubmixRoute::removeRoute(mDeviceAddress);
    }
    mCurrentRoute.reset();
}
@@ -201,7 +175,7 @@ long StreamRemoteSubmix::getDelayInUsForFrameCount(size_t frameCount) {

// Calculate the maximum size of the pipe buffer in frames for the specified stream.
size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() {
    auto pipeConfig = mCurrentRoute->mPipeConfig;
    auto pipeConfig = mCurrentRoute->getPipeConfig();
    const size_t maxFrameSize = std::max(mStreamConfig.frameSize, pipeConfig.frameSize);
    return (pipeConfig.frameCount * pipeConfig.frameSize) / maxFrameSize;
}
+48 −10
Original line number Diff line number Diff line
@@ -23,9 +23,49 @@
#include "SubmixRoute.h"

using aidl::android::hardware::audio::common::getChannelCount;
using aidl::android::media::audio::common::AudioDeviceAddress;

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

// static
SubmixRoute::RoutesMonitor SubmixRoute::getRoutes() {
    static std::mutex submixRoutesLock;
    static RoutesMap submixRoutes;
    return RoutesMonitor(submixRoutesLock, submixRoutes);
}

// static
std::shared_ptr<SubmixRoute> SubmixRoute::findOrCreateRoute(const AudioDeviceAddress& deviceAddress,
                                                            const AudioConfig& pipeConfig) {
    auto routes = getRoutes();
    auto routeItr = routes->find(deviceAddress);
    if (routeItr != routes->end()) {
        return routeItr->second;
    }
    auto route = std::make_shared<SubmixRoute>();
    if (::android::OK != route->createPipe(pipeConfig)) {
        LOG(ERROR) << __func__ << ": create pipe failed";
        return nullptr;
    }
    routes->emplace(deviceAddress, route);
    return route;
}

// static
std::shared_ptr<SubmixRoute> SubmixRoute::findRoute(const AudioDeviceAddress& deviceAddress) {
    auto routes = getRoutes();
    auto routeItr = routes->find(deviceAddress);
    if (routeItr != routes->end()) {
        return routeItr->second;
    }
    return nullptr;
}

// static
void SubmixRoute::removeRoute(const AudioDeviceAddress& deviceAddress) {
    getRoutes()->erase(deviceAddress);
}

// Verify a submix input or output stream can be opened.
bool SubmixRoute::isStreamConfigValid(bool isInput, const AudioConfig& streamConfig) {
    // If the stream is already open, don't open it again.
@@ -44,6 +84,7 @@ bool SubmixRoute::isStreamConfigValid(bool isInput, const AudioConfig& streamCon
// Compare this stream config with existing pipe config, returning false if they do *not*
// match, true otherwise.
bool SubmixRoute::isStreamConfigCompatible(const AudioConfig& streamConfig) {
    std::lock_guard guard(mLock);
    if (streamConfig.channelLayout != mPipeConfig.channelLayout) {
        LOG(ERROR) << __func__ << ": channel count mismatch, stream channels = "
                   << streamConfig.channelLayout.toString()
@@ -162,17 +203,14 @@ void SubmixRoute::closeStream(bool isInput) {
        LOG(FATAL) << __func__ << ": Negotiation for the source failed, index = " << index;
        return ::android::BAD_INDEX;
    }
    LOG(VERBOSE) << __func__ << ": created pipe";

    mPipeConfig = streamConfig;
    mPipeConfig.frameCount = sink->maxFrames();

    LOG(VERBOSE) << __func__ << ": Pipe frame size : " << mPipeConfig.frameSize
                 << ", pipe frames : " << mPipeConfig.frameCount;
    LOG(VERBOSE) << __func__ << ": Pipe frame size : " << streamConfig.frameSize
                 << ", pipe frames : " << sink->maxFrames();

    // Save references to the source and sink.
    {
        std::lock_guard guard(mLock);
        mPipeConfig = streamConfig;
        mPipeConfig.frameCount = sink->maxFrames();
        mSink = std::move(sink);
        mSource = std::move(source);
    }
@@ -181,15 +219,15 @@ void SubmixRoute::closeStream(bool isInput) {
}

// Release references to the sink and source.
void SubmixRoute::releasePipe() {
AudioConfig SubmixRoute::releasePipe() {
    std::lock_guard guard(mLock);
    mSink.clear();
    mSource.clear();
    return mPipeConfig;
}

::android::status_t SubmixRoute::resetPipe() {
    releasePipe();
    return createPipe(mPipeConfig);
    return createPipe(releasePipe());
}

void SubmixRoute::standby(bool isInput) {
Loading