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:
commit
ed49e9068b
8 changed files with 67 additions and 143 deletions
|
@ -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",
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue