mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 21:37:44 +00:00
audio r_submix: Suggest configuration from the peer am: 3b732895a8
Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/2886671 Change-Id: I6f7aecbe65da1a4ea555e812c640a2b3b43f7fff Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -43,26 +43,10 @@ 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.
|
||||
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);
|
||||
}
|
||||
mCurrentRoute = SubmixRoute::findOrCreateRoute(mDeviceAddress, mStreamConfig);
|
||||
if (mCurrentRoute == nullptr) {
|
||||
return ::android::NO_INIT;
|
||||
}
|
||||
if (!mCurrentRoute->isStreamConfigValid(mIsInput, mStreamConfig)) {
|
||||
LOG(ERROR) << __func__ << ": invalid stream config";
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <media/nbaio/MonoPipeReader.h>
|
||||
|
||||
#include <aidl/android/media/audio/common/AudioChannelLayout.h>
|
||||
#include <aidl/android/media/audio/common/AudioDeviceAddress.h>
|
||||
#include <aidl/android/media/audio/common/AudioFormatDescription.h>
|
||||
|
||||
using aidl::android::media::audio::common::AudioChannelLayout;
|
||||
@@ -60,7 +61,13 @@ struct AudioConfig {
|
||||
|
||||
class SubmixRoute {
|
||||
public:
|
||||
AudioConfig mPipeConfig;
|
||||
static std::shared_ptr<SubmixRoute> findOrCreateRoute(
|
||||
const ::aidl::android::media::audio::common::AudioDeviceAddress& deviceAddress,
|
||||
const AudioConfig& pipeConfig);
|
||||
static std::shared_ptr<SubmixRoute> findRoute(
|
||||
const ::aidl::android::media::audio::common::AudioDeviceAddress& deviceAddress);
|
||||
static void removeRoute(
|
||||
const ::aidl::android::media::audio::common::AudioDeviceAddress& deviceAddress);
|
||||
|
||||
bool isStreamInOpen() {
|
||||
std::lock_guard guard(mLock);
|
||||
@@ -90,6 +97,10 @@ class SubmixRoute {
|
||||
std::lock_guard guard(mLock);
|
||||
return mSource;
|
||||
}
|
||||
AudioConfig getPipeConfig() {
|
||||
std::lock_guard guard(mLock);
|
||||
return mPipeConfig;
|
||||
}
|
||||
|
||||
bool isStreamConfigValid(bool isInput, const AudioConfig& streamConfig);
|
||||
void closeStream(bool isInput);
|
||||
@@ -98,17 +109,31 @@ class SubmixRoute {
|
||||
bool hasAtleastOneStreamOpen();
|
||||
int notifyReadError();
|
||||
void openStream(bool isInput);
|
||||
void releasePipe();
|
||||
AudioConfig releasePipe();
|
||||
::android::status_t resetPipe();
|
||||
bool shouldBlockWrite();
|
||||
void standby(bool isInput);
|
||||
long updateReadCounterFrames(size_t frameCount);
|
||||
|
||||
private:
|
||||
using RoutesMap = std::map<::aidl::android::media::audio::common::AudioDeviceAddress,
|
||||
std::shared_ptr<r_submix::SubmixRoute>>;
|
||||
class RoutesMonitor {
|
||||
public:
|
||||
RoutesMonitor(std::mutex& mutex, RoutesMap& routes) : mLock(mutex), mRoutes(routes) {}
|
||||
RoutesMap* operator->() { return &mRoutes; }
|
||||
|
||||
private:
|
||||
std::lock_guard<std::mutex> mLock;
|
||||
RoutesMap& mRoutes;
|
||||
};
|
||||
|
||||
static RoutesMonitor getRoutes();
|
||||
|
||||
bool isStreamConfigCompatible(const AudioConfig& streamConfig);
|
||||
|
||||
std::mutex mLock;
|
||||
|
||||
AudioConfig mPipeConfig GUARDED_BY(mLock);
|
||||
bool mStreamInOpen GUARDED_BY(mLock) = false;
|
||||
int mInputRefCount GUARDED_BY(mLock) = 0;
|
||||
bool mStreamInStandby GUARDED_BY(mLock) = true;
|
||||
|
||||
Reference in New Issue
Block a user