Merge "audio: Fix remote submix module device ports handling" into main am: 7f2619ddff am: b1a26c5fa6

Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/2703156

Change-Id: I76e24d76665c1e3909e1f38ea6e4d658145f7afc
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Treehugger Robot 2023-08-19 05:05:09 +00:00 committed by Automerger Merge Worker
commit ed49e9068b
8 changed files with 67 additions and 143 deletions

View file

@ -88,7 +88,6 @@ cc_library {
"primary/PrimaryMixer.cpp",
"primary/StreamPrimary.cpp",
"r_submix/ModuleRemoteSubmix.cpp",
"r_submix/RemoteSubmixUtils.cpp",
"r_submix/SubmixRoute.cpp",
"r_submix/StreamRemoteSubmix.cpp",
"stub/ModuleStub.cpp",

View file

@ -81,8 +81,6 @@ static AudioPortExt createDeviceExt(AudioDeviceType devType, int32_t flags,
deviceExt.device.address = "bottom";
} else if (devType == AudioDeviceType::IN_MICROPHONE_BACK && connection.empty()) {
deviceExt.device.address = "back";
} else if (devType == AudioDeviceType::IN_SUBMIX || devType == AudioDeviceType::OUT_SUBMIX) {
deviceExt.device.address = "0";
}
deviceExt.device.type.connection = std::move(connection);
deviceExt.flags = flags;
@ -291,15 +289,21 @@ std::unique_ptr<Configuration> getPrimaryConfiguration() {
//
// Device ports:
// * "Remote Submix Out", OUT_SUBMIX
// - profile PCM 16-bit; STEREO; 48000
// - no profiles specified
// * "Remote Submix In", IN_SUBMIX
// - profile PCM 16-bit; STEREO; 48000
// - no profiles specified
//
// Mix ports:
// * "r_submix output", 1 max open, 1 max active stream
// - profile PCM 16-bit; STEREO; 48000
// * "r_submix input", 1 max open, 1 max active stream
// - profile PCM 16-bit; STEREO; 48000
// * "r_submix output", unlimited max open, unlimited max active stream
// - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
// - profile PCM 32-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
// - profile PCM 32-bit float; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
// * "r_submix input", unlimited max open, unlimited max active stream
// - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
// - profile PCM 32-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
// - profile PCM 32-bit float; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
//
// Routes:
// "r_submix output" -> "Remote Submix Out"
@ -308,6 +312,19 @@ std::unique_ptr<Configuration> getPrimaryConfiguration() {
std::unique_ptr<Configuration> getRSubmixConfiguration() {
static const Configuration configuration = []() {
Configuration c;
const std::vector<AudioProfile> standardPcmAudioProfiles{
createProfile(PcmType::FLOAT_32_BIT,
{AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
{8000, 11025, 16000, 32000, 44100, 48000}),
createProfile(PcmType::INT_32_BIT,
{AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
{8000, 11025, 16000, 32000, 44100, 48000}),
createProfile(PcmType::INT_24_BIT,
{AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
{8000, 11025, 16000, 32000, 44100, 48000}),
createProfile(PcmType::INT_16_BIT,
{AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
{8000, 11025, 16000, 32000, 44100, 48000})};
// Device ports
@ -315,28 +332,26 @@ std::unique_ptr<Configuration> getRSubmixConfiguration() {
createPort(c.nextPortId++, "Remote Submix Out", 0, false,
createDeviceExt(AudioDeviceType::OUT_SUBMIX, 0,
AudioDeviceDescription::CONNECTION_VIRTUAL));
rsubmixOutDevice.profiles.push_back(
createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
c.ports.push_back(rsubmixOutDevice);
c.connectedProfiles[rsubmixOutDevice.id] = standardPcmAudioProfiles;
AudioPort rsubmixInDevice = createPort(c.nextPortId++, "Remote Submix In", 0, true,
createDeviceExt(AudioDeviceType::IN_SUBMIX, 0));
rsubmixInDevice.profiles.push_back(
createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
AudioPort rsubmixInDevice =
createPort(c.nextPortId++, "Remote Submix In", 0, true,
createDeviceExt(AudioDeviceType::IN_SUBMIX, 0,
AudioDeviceDescription::CONNECTION_VIRTUAL));
c.ports.push_back(rsubmixInDevice);
c.connectedProfiles[rsubmixInDevice.id] = standardPcmAudioProfiles;
// Mix ports
AudioPort rsubmixOutMix =
createPort(c.nextPortId++, "r_submix output", 0, false, createPortMixExt(1, 1));
rsubmixOutMix.profiles.push_back(
createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
createPort(c.nextPortId++, "r_submix output", 0, false, createPortMixExt(0, 0));
rsubmixOutMix.profiles = standardPcmAudioProfiles;
c.ports.push_back(rsubmixOutMix);
AudioPort rsubmixInMix =
createPort(c.nextPortId++, "r_submix input", 0, true, createPortMixExt(1, 1));
rsubmixInMix.profiles.push_back(
createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
createPort(c.nextPortId++, "r_submix input", 0, true, createPortMixExt(0, 0));
rsubmixInMix.profiles = standardPcmAudioProfiles;
c.ports.push_back(rsubmixInMix);
c.routes.push_back(createRoute({rsubmixOutMix}, rsubmixOutDevice));

View file

@ -26,8 +26,6 @@ class ModuleRemoteSubmix : public Module {
private:
// IModule interfaces
ndk::ScopedAStatus getTelephony(std::shared_ptr<ITelephony>* _aidl_return) override;
ndk::ScopedAStatus getBluetooth(std::shared_ptr<IBluetooth>* _aidl_return) override;
ndk::ScopedAStatus getMicMute(bool* _aidl_return) override;
ndk::ScopedAStatus setMicMute(bool in_mute) override;
@ -49,9 +47,6 @@ class ModuleRemoteSubmix : public Module {
const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sources,
const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sinks)
override;
void onExternalDeviceConnectionChanged(
const ::aidl::android::media::audio::common::AudioPort& audioPort,
bool connected) override;
ndk::ScopedAStatus onMasterMuteChanged(bool mute) override;
ndk::ScopedAStatus onMasterVolumeChanged(float volume) override;
};

View file

@ -19,8 +19,8 @@
#include <vector>
#include <android-base/logging.h>
#include <error/expected_utils.h>
#include "RemoteSubmixUtils.h"
#include "core-impl/ModuleRemoteSubmix.h"
#include "core-impl/StreamRemoteSubmix.h"
@ -33,18 +33,6 @@ using aidl::android::media::audio::common::MicrophoneInfo;
namespace aidl::android::hardware::audio::core {
ndk::ScopedAStatus ModuleRemoteSubmix::getTelephony(std::shared_ptr<ITelephony>* _aidl_return) {
*_aidl_return = nullptr;
LOG(DEBUG) << __func__ << ": returning null";
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus ModuleRemoteSubmix::getBluetooth(std::shared_ptr<IBluetooth>* _aidl_return) {
*_aidl_return = nullptr;
LOG(DEBUG) << __func__ << ": returning null";
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus ModuleRemoteSubmix::getMicMute(bool* _aidl_return __unused) {
LOG(DEBUG) << __func__ << ": is not supported";
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
@ -70,23 +58,26 @@ ndk::ScopedAStatus ModuleRemoteSubmix::createOutputStream(
}
ndk::ScopedAStatus ModuleRemoteSubmix::populateConnectedDevicePort(AudioPort* audioPort) {
LOG(VERBOSE) << __func__ << ": Profiles already populated by Configuration";
for (auto profile : audioPort->profiles) {
for (auto channelMask : profile.channelMasks) {
if (!r_submix::isChannelMaskSupported(channelMask)) {
LOG(ERROR) << __func__ << ": the profile " << profile.name
<< " has unsupported channel mask : " << channelMask.toString();
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
}
for (auto sampleRate : profile.sampleRates) {
if (!r_submix::isSampleRateSupported(sampleRate)) {
LOG(ERROR) << __func__ << ": the profile " << profile.name
<< " has unsupported sample rate : " << sampleRate;
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
}
// Find the corresponding mix port and copy its profiles.
std::vector<AudioRoute> routes;
// At this moment, the port has the same ID as the template port, see connectExternalDevice.
RETURN_STATUS_IF_ERROR(getAudioRoutesForAudioPort(audioPort->id, &routes));
if (routes.empty()) {
LOG(ERROR) << __func__ << ": no routes found for the port " << audioPort->toString();
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
const auto& route = *routes.begin();
AudioPort mixPort;
if (route.sinkPortId == audioPort->id) {
if (route.sourcePortIds.empty()) {
LOG(ERROR) << __func__ << ": invalid route " << route.toString();
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
RETURN_STATUS_IF_ERROR(getAudioPort(*route.sourcePortIds.begin(), &mixPort));
} else {
RETURN_STATUS_IF_ERROR(getAudioPort(route.sinkPortId, &mixPort));
}
audioPort->profiles = mixPort.profiles;
return ndk::ScopedAStatus::ok();
}
@ -106,12 +97,6 @@ ndk::ScopedAStatus ModuleRemoteSubmix::checkAudioPatchEndpointsMatch(
return ndk::ScopedAStatus::ok();
}
void ModuleRemoteSubmix::onExternalDeviceConnectionChanged(
const ::aidl::android::media::audio::common::AudioPort& audioPort __unused,
bool connected __unused) {
LOG(DEBUG) << __func__ << ": do nothing and return";
}
ndk::ScopedAStatus ModuleRemoteSubmix::onMasterMuteChanged(bool __unused) {
LOG(DEBUG) << __func__ << ": is not supported";
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);

View file

@ -1,47 +0,0 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <vector>
#include "RemoteSubmixUtils.h"
namespace aidl::android::hardware::audio::core::r_submix {
bool isChannelMaskSupported(const AudioChannelLayout& channelMask) {
const static std::vector<AudioChannelLayout> kSupportedChannelMask = {
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::LAYOUT_MONO),
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::LAYOUT_STEREO)};
if (std::find(kSupportedChannelMask.begin(), kSupportedChannelMask.end(), channelMask) !=
kSupportedChannelMask.end()) {
return true;
}
return false;
}
bool isSampleRateSupported(int sampleRate) {
const static std::vector<int> kSupportedSampleRates = {8000, 11025, 12000, 16000, 22050,
24000, 32000, 44100, 48000};
if (std::find(kSupportedSampleRates.begin(), kSupportedSampleRates.end(), sampleRate) !=
kSupportedSampleRates.end()) {
return true;
}
return false;
}
} // namespace aidl::android::hardware::audio::core::r_submix

View file

@ -1,30 +0,0 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <aidl/android/media/audio/common/AudioChannelLayout.h>
#include <aidl/android/media/audio/common/AudioFormatDescription.h>
using aidl::android::media::audio::common::AudioChannelLayout;
namespace aidl::android::hardware::audio::core::r_submix {
bool isChannelMaskSupported(const AudioChannelLayout& channelMask);
bool isSampleRateSupported(int sampleRate);
} // namespace aidl::android::hardware::audio::core::r_submix

View file

@ -30,6 +30,7 @@ using namespace std::chrono_literals;
using aidl::android::hardware::audio::common::isBitPositionFlagSet;
using aidl::android::hardware::audio::core::IModule;
using aidl::android::media::audio::common::AudioChannelLayout;
using aidl::android::media::audio::common::AudioDeviceDescription;
using aidl::android::media::audio::common::AudioDeviceType;
using aidl::android::media::audio::common::AudioEncapsulationMode;
using aidl::android::media::audio::common::AudioFormatDescription;
@ -96,7 +97,10 @@ ModuleConfig::ModuleConfig(IModule* module) {
} else {
mAttachedSinkDevicePorts.insert(port.id);
}
} else if (port.profiles.empty()) {
} else if (devicePort.device.type.connection != AudioDeviceDescription::CONNECTION_VIRTUAL
// The "virtual" connection is used for remote submix which is a dynamic
// device but it can be connected and used w/o external hardware.
&& port.profiles.empty()) {
mExternalDevicePorts.insert(port.id);
}
}

View file

@ -1627,14 +1627,17 @@ TEST_P(AudioCoreModule, TryConnectMissingDevice) {
if (ports.empty()) {
GTEST_SKIP() << "No external devices in the module.";
}
AudioPort ignored;
WithDebugFlags doNotSimulateConnections = WithDebugFlags::createNested(*debug);
doNotSimulateConnections.flags().simulateDeviceConnections = false;
ASSERT_NO_FATAL_FAILURE(doNotSimulateConnections.SetUp(module.get()));
for (const auto& port : ports) {
AudioPort portWithData = GenerateUniqueDeviceAddress(port);
EXPECT_STATUS(EX_ILLEGAL_STATE, module->connectExternalDevice(portWithData, &ignored))
<< "static port " << portWithData.toString();
AudioPort portWithData = GenerateUniqueDeviceAddress(port), connectedPort;
ScopedAStatus status = module->connectExternalDevice(portWithData, &connectedPort);
EXPECT_STATUS(EX_ILLEGAL_STATE, status) << "static port " << portWithData.toString();
if (status.isOk()) {
EXPECT_IS_OK(module->disconnectExternalDevice(connectedPort.id))
<< "when disconnecting device port ID " << connectedPort.id;
}
}
}