mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 16:09:42 +00:00
audio: Fix remote submix module device ports handling
- remove the default address "0" for IN_SUBMIX and OUT_SUBMIX; - remove the profiles in the device port and assign profiles when connecting; - make remote submix input to use "virtual" connection type, same as the output; - fix ModuleConfig in VTS to avoid returning devices with virtual connections as "external devices" because they can actually be connected even when connection simulation is disabled; - fix TryConnectMissingDevice VTS test to disconnect the device if the operation has unexpectedly succeeded. Bug: 286914845 Bug: 294976817 Test: atest VtsHalAudioCoreTargetTest Change-Id: Ife11c9c356d1b5dc587d08cef47294e3b29f65c5 Merged-In: Ife11c9c356d1b5dc587d08cef47294e3b29f65c5
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user