Merge changes I19a08bf2,Ibab914e5 into main am: 63f2d84e68 am: f9c141dfb6 am: 806f5fc951

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

Change-Id: I2bc11e660b13f632502d70f79f0f50626c60436f
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Mikhail Naganov 2023-09-12 22:57:05 +00:00 committed by Automerger Merge Worker
commit 1e188f2ca9
4 changed files with 400 additions and 109 deletions

View file

@ -179,7 +179,7 @@ void StreamRemoteSubmix::shutdown() {
LOG(ERROR) << __func__ << ": transfer without a pipe!";
return ::android::UNEXPECTED_NULL;
}
mCurrentRoute->exitStandby(mIsInput);
return (mIsInput ? inRead(buffer, frameCount, actualFrameCount)
: outWrite(buffer, frameCount, actualFrameCount));
}
@ -190,17 +190,14 @@ void StreamRemoteSubmix::shutdown() {
return ::android::NO_INIT;
}
const ssize_t framesInPipe = source->availableToRead();
if (framesInPipe < 0) {
return ::android::INVALID_OPERATION;
if (framesInPipe <= 0) {
// No need to update the position frames
return ::android::OK;
}
if (mIsInput) {
position->frames += framesInPipe;
} else {
if (position->frames > framesInPipe) {
position->frames -= framesInPipe;
} else {
position->frames = 0;
}
} else if (position->frames >= framesInPipe) {
position->frames -= framesInPipe;
}
return ::android::OK;
}
@ -280,18 +277,14 @@ size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() {
size_t* actualFrameCount) {
// about to read from audio source
sp<MonoPipeReader> source = mCurrentRoute->getSource();
if (source == nullptr || source->availableToRead() == 0) {
if (source == nullptr) {
int readErrorCount = mCurrentRoute->notifyReadError();
if (readErrorCount < kMaxReadErrorLogs) {
LOG(ERROR) << __func__
<< ": no audio pipe yet we're trying to read! (not all errors will be "
"logged)";
} else {
LOG(ERROR) << __func__ << ": Read errors " << readErrorCount;
}
if (source == nullptr) {
int readErrorCount = mCurrentRoute->notifyReadError();
if (readErrorCount < kMaxReadErrorLogs) {
LOG(ERROR) << __func__
<< ": no audio pipe yet we're trying to read! (not all errors will be "
"logged)";
} else {
LOG(INFO) << __func__ << ": no data to read yet, providing empty data";
LOG(ERROR) << __func__ << ": Read errors " << readErrorCount;
}
const size_t delayUs = static_cast<size_t>(
std::roundf(frameCount * MICROS_PER_SECOND / mStreamConfig.sampleRate));
@ -306,9 +299,10 @@ size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() {
const size_t delayUs = static_cast<size_t>(std::roundf(kReadAttemptSleepUs));
char* buff = (char*)buffer;
size_t remainingFrames = frameCount;
int availableToRead = source->availableToRead();
while ((remainingFrames > 0) && (attempts < kMaxReadFailureAttempts)) {
LOG(VERBOSE) << __func__ << ": frames available to read " << source->availableToRead();
while ((remainingFrames > 0) && (availableToRead > 0) && (attempts < kMaxReadFailureAttempts)) {
LOG(VERBOSE) << __func__ << ": frames available to read " << availableToRead;
ssize_t framesRead = source->read(buff, remainingFrames);
@ -317,6 +311,7 @@ size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() {
if (framesRead > 0) {
remainingFrames -= framesRead;
buff += framesRead * mStreamConfig.frameSize;
availableToRead -= framesRead;
LOG(VERBOSE) << __func__ << ": (attempts = " << attempts << ") got " << framesRead
<< " frames, remaining=" << remainingFrames;
} else {

View file

@ -66,15 +66,36 @@ std::optional<AudioOffloadInfo> ModuleConfig::generateOffloadInfoIfNeeded(
return {};
}
std::vector<aidl::android::media::audio::common::AudioPort>
ModuleConfig::getAudioPortsForDeviceTypes(const std::vector<AudioDeviceType>& deviceTypes,
const std::string& connection) {
return getAudioPortsForDeviceTypes(mPorts, deviceTypes, connection);
}
// static
std::vector<aidl::android::media::audio::common::AudioPort> ModuleConfig::getBuiltInMicPorts(
const std::vector<aidl::android::media::audio::common::AudioPort>& ports) {
return getAudioPortsForDeviceTypes(
ports, std::vector<AudioDeviceType>{AudioDeviceType::IN_MICROPHONE,
AudioDeviceType::IN_MICROPHONE_BACK});
}
std::vector<aidl::android::media::audio::common::AudioPort>
ModuleConfig::getAudioPortsForDeviceTypes(
const std::vector<aidl::android::media::audio::common::AudioPort>& ports,
const std::vector<AudioDeviceType>& deviceTypes, const std::string& connection) {
std::vector<AudioPort> result;
std::copy_if(ports.begin(), ports.end(), std::back_inserter(result), [](const auto& port) {
const auto type = port.ext.template get<AudioPortExt::Tag::device>().device.type;
return type.connection.empty() && (type.type == AudioDeviceType::IN_MICROPHONE ||
type.type == AudioDeviceType::IN_MICROPHONE_BACK);
});
for (const auto& port : ports) {
if (port.ext.getTag() != AudioPortExt::Tag::device) continue;
const auto type = port.ext.get<AudioPortExt::Tag::device>().device.type;
if (type.connection == connection) {
for (auto deviceType : deviceTypes) {
if (type.type == deviceType) {
result.push_back(port);
}
}
}
}
return result;
}
@ -119,6 +140,31 @@ std::vector<AudioPort> ModuleConfig::getAttachedDevicePorts() const {
return result;
}
std::vector<AudioPort> ModuleConfig::getConnectedExternalDevicePorts() const {
std::vector<AudioPort> result;
std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) {
return mConnectedExternalSinkDevicePorts.count(port.id) != 0 ||
mConnectedExternalSourceDevicePorts.count(port.id) != 0;
});
return result;
}
std::set<int32_t> ModuleConfig::getConnectedSinkDevicePorts() const {
std::set<int32_t> result;
result.insert(mAttachedSinkDevicePorts.begin(), mAttachedSinkDevicePorts.end());
result.insert(mConnectedExternalSinkDevicePorts.begin(),
mConnectedExternalSinkDevicePorts.end());
return result;
}
std::set<int32_t> ModuleConfig::getConnectedSourceDevicePorts() const {
std::set<int32_t> result;
result.insert(mAttachedSourceDevicePorts.begin(), mAttachedSourceDevicePorts.end());
result.insert(mConnectedExternalSourceDevicePorts.begin(),
mConnectedExternalSourceDevicePorts.end());
return result;
}
std::vector<AudioPort> ModuleConfig::getExternalDevicePorts() const {
std::vector<AudioPort> result;
std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result),
@ -126,76 +172,77 @@ std::vector<AudioPort> ModuleConfig::getExternalDevicePorts() const {
return result;
}
std::vector<AudioPort> ModuleConfig::getInputMixPorts(bool attachedOnly) const {
std::vector<AudioPort> ModuleConfig::getInputMixPorts(bool connectedOnly) const {
std::vector<AudioPort> result;
std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) {
return port.ext.getTag() == AudioPortExt::Tag::mix &&
port.flags.getTag() == AudioIoFlags::Tag::input &&
(!attachedOnly || !getAttachedSourceDevicesPortsForMixPort(port).empty());
(!connectedOnly || !getConnectedSourceDevicesPortsForMixPort(port).empty());
});
return result;
}
std::vector<AudioPort> ModuleConfig::getOutputMixPorts(bool attachedOnly) const {
std::vector<AudioPort> ModuleConfig::getOutputMixPorts(bool connectedOnly) const {
std::vector<AudioPort> result;
std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) {
return port.ext.getTag() == AudioPortExt::Tag::mix &&
port.flags.getTag() == AudioIoFlags::Tag::output &&
(!attachedOnly || !getAttachedSinkDevicesPortsForMixPort(port).empty());
(!connectedOnly || !getConnectedSinkDevicesPortsForMixPort(port).empty());
});
return result;
}
std::vector<AudioPort> ModuleConfig::getNonBlockingMixPorts(bool attachedOnly,
std::vector<AudioPort> ModuleConfig::getNonBlockingMixPorts(bool connectedOnly,
bool singlePort) const {
return findMixPorts(false /*isInput*/, attachedOnly, singlePort, [&](const AudioPort& port) {
return findMixPorts(false /*isInput*/, connectedOnly, singlePort, [&](const AudioPort& port) {
return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
AudioOutputFlags::NON_BLOCKING);
});
}
std::vector<AudioPort> ModuleConfig::getOffloadMixPorts(bool attachedOnly, bool singlePort) const {
return findMixPorts(false /*isInput*/, attachedOnly, singlePort, [&](const AudioPort& port) {
std::vector<AudioPort> ModuleConfig::getOffloadMixPorts(bool connectedOnly, bool singlePort) const {
return findMixPorts(false /*isInput*/, connectedOnly, singlePort, [&](const AudioPort& port) {
return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
AudioOutputFlags::COMPRESS_OFFLOAD);
});
}
std::vector<AudioPort> ModuleConfig::getPrimaryMixPorts(bool attachedOnly, bool singlePort) const {
return findMixPorts(false /*isInput*/, attachedOnly, singlePort, [&](const AudioPort& port) {
std::vector<AudioPort> ModuleConfig::getPrimaryMixPorts(bool connectedOnly, bool singlePort) const {
return findMixPorts(false /*isInput*/, connectedOnly, singlePort, [&](const AudioPort& port) {
return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
AudioOutputFlags::PRIMARY);
});
}
std::vector<AudioPort> ModuleConfig::getMmapOutMixPorts(bool attachedOnly, bool singlePort) const {
return findMixPorts(false /*isInput*/, attachedOnly, singlePort, [&](const AudioPort& port) {
std::vector<AudioPort> ModuleConfig::getMmapOutMixPorts(bool connectedOnly, bool singlePort) const {
return findMixPorts(false /*isInput*/, connectedOnly, singlePort, [&](const AudioPort& port) {
return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
AudioOutputFlags::MMAP_NOIRQ);
});
}
std::vector<AudioPort> ModuleConfig::getMmapInMixPorts(bool attachedOnly, bool singlePort) const {
return findMixPorts(true /*isInput*/, attachedOnly, singlePort, [&](const AudioPort& port) {
std::vector<AudioPort> ModuleConfig::getMmapInMixPorts(bool connectedOnly, bool singlePort) const {
return findMixPorts(true /*isInput*/, connectedOnly, singlePort, [&](const AudioPort& port) {
return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::input>(),
AudioInputFlags::MMAP_NOIRQ);
});
}
std::vector<AudioPort> ModuleConfig::getAttachedDevicesPortsForMixPort(
std::vector<AudioPort> ModuleConfig::getConnectedDevicesPortsForMixPort(
bool isInput, const AudioPortConfig& mixPortConfig) const {
const auto mixPortIt = findById<AudioPort>(mPorts, mixPortConfig.portId);
if (mixPortIt != mPorts.end()) {
return getAttachedDevicesPortsForMixPort(isInput, *mixPortIt);
return getConnectedDevicesPortsForMixPort(isInput, *mixPortIt);
}
return {};
}
std::vector<AudioPort> ModuleConfig::getAttachedSinkDevicesPortsForMixPort(
std::vector<AudioPort> ModuleConfig::getConnectedSinkDevicesPortsForMixPort(
const AudioPort& mixPort) const {
std::vector<AudioPort> result;
std::set<int32_t> connectedSinkDevicePorts = getConnectedSinkDevicePorts();
for (const auto& route : mRoutes) {
if (mAttachedSinkDevicePorts.count(route.sinkPortId) != 0 &&
if ((connectedSinkDevicePorts.count(route.sinkPortId) != 0) &&
std::find(route.sourcePortIds.begin(), route.sourcePortIds.end(), mixPort.id) !=
route.sourcePortIds.end()) {
const auto devicePortIt = findById<AudioPort>(mPorts, route.sinkPortId);
@ -205,13 +252,14 @@ std::vector<AudioPort> ModuleConfig::getAttachedSinkDevicesPortsForMixPort(
return result;
}
std::vector<AudioPort> ModuleConfig::getAttachedSourceDevicesPortsForMixPort(
std::vector<AudioPort> ModuleConfig::getConnectedSourceDevicesPortsForMixPort(
const AudioPort& mixPort) const {
std::vector<AudioPort> result;
std::set<int32_t> connectedSourceDevicePorts = getConnectedSourceDevicePorts();
for (const auto& route : mRoutes) {
if (route.sinkPortId == mixPort.id) {
for (const auto srcId : route.sourcePortIds) {
if (mAttachedSourceDevicePorts.count(srcId) != 0) {
if (connectedSourceDevicePorts.count(srcId) != 0) {
const auto devicePortIt = findById<AudioPort>(mPorts, srcId);
if (devicePortIt != mPorts.end()) result.push_back(*devicePortIt);
}
@ -221,9 +269,10 @@ std::vector<AudioPort> ModuleConfig::getAttachedSourceDevicesPortsForMixPort(
return result;
}
std::optional<AudioPort> ModuleConfig::getSourceMixPortForAttachedDevice() const {
std::optional<AudioPort> ModuleConfig::getSourceMixPortForConnectedDevice() const {
std::set<int32_t> connectedSinkDevicePorts = getConnectedSinkDevicePorts();
for (const auto& route : mRoutes) {
if (mAttachedSinkDevicePorts.count(route.sinkPortId) != 0) {
if (connectedSinkDevicePorts.count(route.sinkPortId) != 0) {
const auto mixPortIt = findById<AudioPort>(mPorts, route.sourcePortIds[0]);
if (mixPortIt != mPorts.end()) return *mixPortIt;
}
@ -233,7 +282,7 @@ std::optional<AudioPort> ModuleConfig::getSourceMixPortForAttachedDevice() const
std::optional<ModuleConfig::SrcSinkPair> ModuleConfig::getNonRoutableSrcSinkPair(
bool isInput) const {
const auto mixPorts = getMixPorts(isInput, false /*attachedOnly*/);
const auto mixPorts = getMixPorts(isInput, false /*connectedOnly*/);
std::set<std::pair<int32_t, int32_t>> allowedRoutes;
for (const auto& route : mRoutes) {
for (const auto srcPortId : route.sourcePortIds) {
@ -243,7 +292,8 @@ std::optional<ModuleConfig::SrcSinkPair> ModuleConfig::getNonRoutableSrcSinkPair
auto make_pair = [isInput](auto& device, auto& mix) {
return isInput ? std::make_pair(device, mix) : std::make_pair(mix, device);
};
for (const auto portId : isInput ? mAttachedSourceDevicePorts : mAttachedSinkDevicePorts) {
for (const auto portId :
isInput ? getConnectedSourceDevicePorts() : getConnectedSinkDevicePorts()) {
const auto devicePortIt = findById<AudioPort>(mPorts, portId);
if (devicePortIt == mPorts.end()) continue;
auto devicePortConfig = getSingleConfigForDevicePort(*devicePortIt);
@ -262,10 +312,11 @@ std::optional<ModuleConfig::SrcSinkPair> ModuleConfig::getNonRoutableSrcSinkPair
std::optional<ModuleConfig::SrcSinkPair> ModuleConfig::getRoutableSrcSinkPair(bool isInput) const {
if (isInput) {
std::set<int32_t> connectedSourceDevicePorts = getConnectedSourceDevicePorts();
for (const auto& route : mRoutes) {
auto srcPortIdIt = std::find_if(
route.sourcePortIds.begin(), route.sourcePortIds.end(),
[&](const auto& portId) { return mAttachedSourceDevicePorts.count(portId); });
[&](const auto& portId) { return connectedSourceDevicePorts.count(portId); });
if (srcPortIdIt == route.sourcePortIds.end()) continue;
const auto devicePortIt = findById<AudioPort>(mPorts, *srcPortIdIt);
const auto mixPortIt = findById<AudioPort>(mPorts, route.sinkPortId);
@ -276,8 +327,9 @@ std::optional<ModuleConfig::SrcSinkPair> ModuleConfig::getRoutableSrcSinkPair(bo
return std::make_pair(devicePortConfig, mixPortConfig.value());
}
} else {
std::set<int32_t> connectedSinkDevicePorts = getConnectedSinkDevicePorts();
for (const auto& route : mRoutes) {
if (mAttachedSinkDevicePorts.count(route.sinkPortId) == 0) continue;
if (connectedSinkDevicePorts.count(route.sinkPortId) == 0) continue;
const auto mixPortIt = findById<AudioPort>(mPorts, route.sourcePortIds[0]);
const auto devicePortIt = findById<AudioPort>(mPorts, route.sinkPortId);
if (devicePortIt == mPorts.end() || mixPortIt == mPorts.end()) continue;
@ -293,11 +345,12 @@ std::optional<ModuleConfig::SrcSinkPair> ModuleConfig::getRoutableSrcSinkPair(bo
std::vector<ModuleConfig::SrcSinkGroup> ModuleConfig::getRoutableSrcSinkGroups(bool isInput) const {
std::vector<SrcSinkGroup> result;
if (isInput) {
std::set<int32_t> connectedSourceDevicePorts = getConnectedSourceDevicePorts();
for (const auto& route : mRoutes) {
std::vector<int32_t> srcPortIds;
std::copy_if(route.sourcePortIds.begin(), route.sourcePortIds.end(),
std::back_inserter(srcPortIds), [&](const auto& portId) {
return mAttachedSourceDevicePorts.count(portId);
return connectedSourceDevicePorts.count(portId);
});
if (srcPortIds.empty()) continue;
const auto mixPortIt = findById<AudioPort>(mPorts, route.sinkPortId);
@ -317,8 +370,9 @@ std::vector<ModuleConfig::SrcSinkGroup> ModuleConfig::getRoutableSrcSinkGroups(b
}
}
} else {
std::set<int32_t> connectedSinkDevicePorts = getConnectedSinkDevicePorts();
for (const auto& route : mRoutes) {
if (mAttachedSinkDevicePorts.count(route.sinkPortId) == 0) continue;
if (connectedSinkDevicePorts.count(route.sinkPortId) == 0) continue;
const auto devicePortIt = findById<AudioPort>(mPorts, route.sinkPortId);
if (devicePortIt == mPorts.end()) continue;
auto devicePortConfig = getSingleConfigForDevicePort(*devicePortIt);
@ -352,6 +406,8 @@ std::string ModuleConfig::toString() const {
result.append(android::internal::ToString(mAttachedSourceDevicePorts));
result.append("\nExternal device ports: ");
result.append(android::internal::ToString(mExternalDevicePorts));
result.append("\nConnected external device ports: ");
result.append(android::internal::ToString(getConnectedExternalDevicePorts()));
result.append("\nRoutes: ");
result.append(android::internal::ToString(mRoutes));
return result;
@ -384,10 +440,10 @@ static bool isDynamicProfile(const AudioProfile& profile) {
}
std::vector<AudioPort> ModuleConfig::findMixPorts(
bool isInput, bool attachedOnly, bool singlePort,
bool isInput, bool connectedOnly, bool singlePort,
const std::function<bool(const AudioPort&)>& pred) const {
std::vector<AudioPort> result;
const auto mixPorts = getMixPorts(isInput, attachedOnly);
const auto mixPorts = getMixPorts(isInput, connectedOnly);
for (auto mixPortIt = mixPorts.begin(); mixPortIt != mixPorts.end();) {
mixPortIt = std::find_if(mixPortIt, mixPorts.end(), pred);
if (mixPortIt == mixPorts.end()) break;
@ -401,7 +457,7 @@ std::vector<AudioPortConfig> ModuleConfig::generateAudioMixPortConfigs(
const std::vector<AudioPort>& ports, bool isInput, bool singleProfile) const {
std::vector<AudioPortConfig> result;
for (const auto& mixPort : ports) {
if (getAttachedDevicesPortsForMixPort(isInput, mixPort).empty()) {
if (getConnectedDevicesPortsForMixPort(isInput, mixPort).empty()) {
continue;
}
for (const auto& profile : mixPort.profiles) {
@ -443,10 +499,48 @@ std::vector<AudioPortConfig> ModuleConfig::generateAudioDevicePortConfigs(
return result;
}
const ndk::ScopedAStatus& ModuleConfig::onExternalDeviceConnected(IModule* module,
const AudioPort& port) {
// Update ports and routes
mStatus = module->getAudioPorts(&mPorts);
if (!mStatus.isOk()) return mStatus;
mStatus = module->getAudioRoutes(&mRoutes);
if (!mStatus.isOk()) return mStatus;
// Validate port is present in module
if (std::find(mPorts.begin(), mPorts.end(), port) == mPorts.end()) {
mStatus = ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
return mStatus;
}
if (port.flags.getTag() == aidl::android::media::audio::common::AudioIoFlags::Tag::input) {
mConnectedExternalSourceDevicePorts.insert(port.id);
} else {
mConnectedExternalSinkDevicePorts.insert(port.id);
}
return mStatus;
}
const ndk::ScopedAStatus& ModuleConfig::onExternalDeviceDisconnected(IModule* module,
const AudioPort& port) {
// Update ports and routes
mStatus = module->getAudioPorts(&mPorts);
if (!mStatus.isOk()) return mStatus;
mStatus = module->getAudioRoutes(&mRoutes);
if (!mStatus.isOk()) return mStatus;
if (port.flags.getTag() == aidl::android::media::audio::common::AudioIoFlags::Tag::input) {
mConnectedExternalSourceDevicePorts.erase(port.id);
} else {
mConnectedExternalSinkDevicePorts.erase(port.id);
}
return mStatus;
}
bool ModuleConfig::isMmapSupported() const {
const std::vector<AudioPort> mmapOutMixPorts =
getMmapOutMixPorts(false /*attachedOnly*/, false /*singlePort*/);
getMmapOutMixPorts(false /*connectedOnly*/, false /*singlePort*/);
const std::vector<AudioPort> mmapInMixPorts =
getMmapInMixPorts(false /*attachedOnly*/, false /*singlePort*/);
getMmapInMixPorts(false /*connectedOnly*/, false /*singlePort*/);
return !mmapOutMixPorts.empty() || !mmapInMixPorts.empty();
}

View file

@ -37,6 +37,14 @@ class ModuleConfig {
static std::optional<aidl::android::media::audio::common::AudioOffloadInfo>
generateOffloadInfoIfNeeded(
const aidl::android::media::audio::common::AudioPortConfig& portConfig);
std::vector<aidl::android::media::audio::common::AudioPort> getAudioPortsForDeviceTypes(
const std::vector<aidl::android::media::audio::common::AudioDeviceType>& deviceTypes,
const std::string& connection = "");
static std::vector<aidl::android::media::audio::common::AudioPort> getAudioPortsForDeviceTypes(
const std::vector<aidl::android::media::audio::common::AudioPort>& ports,
const std::vector<aidl::android::media::audio::common::AudioDeviceType>& deviceTypes,
const std::string& connection = "");
static std::vector<aidl::android::media::audio::common::AudioPort> getBuiltInMicPorts(
const std::vector<aidl::android::media::audio::common::AudioPort>& ports);
@ -45,45 +53,55 @@ class ModuleConfig {
std::string getError() const { return mStatus.getMessage(); }
std::vector<aidl::android::media::audio::common::AudioPort> getAttachedDevicePorts() const;
std::vector<aidl::android::media::audio::common::AudioPort> getConnectedExternalDevicePorts()
const;
std::set<int32_t> getConnectedSinkDevicePorts() const;
std::set<int32_t> getConnectedSourceDevicePorts() const;
std::vector<aidl::android::media::audio::common::AudioPort> getAttachedMicrophonePorts() const {
return getBuiltInMicPorts(getAttachedDevicePorts());
}
std::vector<aidl::android::media::audio::common::AudioPort> getExternalDevicePorts() const;
std::vector<aidl::android::media::audio::common::AudioPort> getInputMixPorts(
bool attachedOnly) const;
bool connectedOnly /*Permanently attached and connected external devices*/) const;
std::vector<aidl::android::media::audio::common::AudioPort> getOutputMixPorts(
bool attachedOnly) const;
bool connectedOnly /*Permanently attached and connected external devices*/) const;
std::vector<aidl::android::media::audio::common::AudioPort> getMixPorts(
bool isInput, bool attachedOnly) const {
return isInput ? getInputMixPorts(attachedOnly) : getOutputMixPorts(attachedOnly);
bool isInput,
bool connectedOnly /*Permanently attached and connected external devices*/) const {
return isInput ? getInputMixPorts(connectedOnly) : getOutputMixPorts(connectedOnly);
}
std::vector<aidl::android::media::audio::common::AudioPort> getNonBlockingMixPorts(
bool attachedOnly, bool singlePort) const;
bool connectedOnly /*Permanently attached and connected external devices*/,
bool singlePort) const;
std::vector<aidl::android::media::audio::common::AudioPort> getOffloadMixPorts(
bool attachedOnly, bool singlePort) const;
bool connectedOnly /*Permanently attached and connected external devices*/,
bool singlePort) const;
std::vector<aidl::android::media::audio::common::AudioPort> getPrimaryMixPorts(
bool attachedOnly, bool singlePort) const;
bool connectedOnly /*Permanently attached and connected external devices*/,
bool singlePort) const;
std::vector<aidl::android::media::audio::common::AudioPort> getMmapOutMixPorts(
bool attachedOnly, bool singlePort) const;
bool connectedOnly /*Permanently attached and connected external devices*/,
bool singlePort) const;
std::vector<aidl::android::media::audio::common::AudioPort> getMmapInMixPorts(
bool attachedOnly, bool singlePort) const;
bool connectedOnly /*Permanently attached and connected external devices*/,
bool singlePort) const;
std::vector<aidl::android::media::audio::common::AudioPort> getAttachedDevicesPortsForMixPort(
std::vector<aidl::android::media::audio::common::AudioPort> getConnectedDevicesPortsForMixPort(
bool isInput, const aidl::android::media::audio::common::AudioPort& mixPort) const {
return isInput ? getAttachedSourceDevicesPortsForMixPort(mixPort)
: getAttachedSinkDevicesPortsForMixPort(mixPort);
return isInput ? getConnectedSourceDevicesPortsForMixPort(mixPort)
: getConnectedSinkDevicesPortsForMixPort(mixPort);
}
std::vector<aidl::android::media::audio::common::AudioPort> getAttachedDevicesPortsForMixPort(
std::vector<aidl::android::media::audio::common::AudioPort> getConnectedDevicesPortsForMixPort(
bool isInput,
const aidl::android::media::audio::common::AudioPortConfig& mixPortConfig) const;
std::vector<aidl::android::media::audio::common::AudioPort>
getAttachedSinkDevicesPortsForMixPort(
getConnectedSinkDevicesPortsForMixPort(
const aidl::android::media::audio::common::AudioPort& mixPort) const;
std::vector<aidl::android::media::audio::common::AudioPort>
getAttachedSourceDevicesPortsForMixPort(
getConnectedSourceDevicesPortsForMixPort(
const aidl::android::media::audio::common::AudioPort& mixPort) const;
std::optional<aidl::android::media::audio::common::AudioPort>
getSourceMixPortForAttachedDevice() const;
getSourceMixPortForConnectedDevice() const;
std::optional<SrcSinkPair> getNonRoutableSrcSinkPair(bool isInput) const;
std::optional<SrcSinkPair> getRoutableSrcSinkPair(bool isInput) const;
@ -96,15 +114,15 @@ class ModuleConfig {
std::vector<aidl::android::media::audio::common::AudioPortConfig> getPortConfigsForMixPorts()
const {
auto inputs =
generateAudioMixPortConfigs(getInputMixPorts(false /*attachedOnly*/), true, false);
auto outputs = generateAudioMixPortConfigs(getOutputMixPorts(false /*attachedOnly*/), false,
false);
generateAudioMixPortConfigs(getInputMixPorts(false /*connectedOnly*/), true, false);
auto outputs = generateAudioMixPortConfigs(getOutputMixPorts(false /*connectedOnly*/),
false, false);
inputs.insert(inputs.end(), outputs.begin(), outputs.end());
return inputs;
}
std::vector<aidl::android::media::audio::common::AudioPortConfig> getPortConfigsForMixPorts(
bool isInput) const {
return generateAudioMixPortConfigs(getMixPorts(isInput, false /*attachedOnly*/), isInput,
return generateAudioMixPortConfigs(getMixPorts(isInput, false /*connectedOnly*/), isInput,
false);
}
std::vector<aidl::android::media::audio::common::AudioPortConfig> getPortConfigsForMixPorts(
@ -114,7 +132,7 @@ class ModuleConfig {
std::optional<aidl::android::media::audio::common::AudioPortConfig> getSingleConfigForMixPort(
bool isInput) const {
const auto config = generateAudioMixPortConfigs(
getMixPorts(isInput, false /*attachedOnly*/), isInput, true);
getMixPorts(isInput, false /*connectedOnly*/), isInput, true);
if (!config.empty()) {
return *config.begin();
}
@ -139,13 +157,20 @@ class ModuleConfig {
return *config.begin();
}
const ndk::ScopedAStatus& onExternalDeviceConnected(
aidl::android::hardware::audio::core::IModule* module,
const aidl::android::media::audio::common::AudioPort& port);
const ndk::ScopedAStatus& onExternalDeviceDisconnected(
aidl::android::hardware::audio::core::IModule* module,
const aidl::android::media::audio::common::AudioPort& port);
bool isMmapSupported() const;
std::string toString() const;
private:
std::vector<aidl::android::media::audio::common::AudioPort> findMixPorts(
bool isInput, bool attachedOnly, bool singlePort,
bool isInput, bool connectedOnly, bool singlePort,
const std::function<bool(const aidl::android::media::audio::common::AudioPort&)>& pred)
const;
std::vector<aidl::android::media::audio::common::AudioPortConfig> generateAudioMixPortConfigs(
@ -167,5 +192,7 @@ class ModuleConfig {
std::set<int32_t> mAttachedSinkDevicePorts;
std::set<int32_t> mAttachedSourceDevicePorts;
std::set<int32_t> mExternalDevicePorts;
std::set<int32_t> mConnectedExternalSinkDevicePorts;
std::set<int32_t> mConnectedExternalSourceDevicePorts;
std::vector<aidl::android::hardware::audio::core::AudioRoute> mRoutes;
};

View file

@ -525,13 +525,21 @@ class WithDevicePortConnectedState {
EXPECT_IS_OK(mModule->disconnectExternalDevice(getId()))
<< "when disconnecting device port ID " << getId();
}
if (mModuleConfig != nullptr) {
EXPECT_IS_OK(mModuleConfig->onExternalDeviceDisconnected(mModule, mConnectedPort))
<< "when external device disconnected";
}
}
void SetUp(IModule* module) {
void SetUp(IModule* module, ModuleConfig* moduleConfig) {
ASSERT_IS_OK(module->connectExternalDevice(mIdAndData, &mConnectedPort))
<< "when connecting device port ID & data " << mIdAndData.toString();
ASSERT_NE(mIdAndData.id, getId())
<< "ID of the connected port must not be the same as the ID of the template port";
ASSERT_NE(moduleConfig, nullptr);
ASSERT_IS_OK(moduleConfig->onExternalDeviceConnected(module, mConnectedPort))
<< "when external device connected";
mModule = module;
mModuleConfig = moduleConfig;
}
int32_t getId() const { return mConnectedPort.id; }
const AudioPort& get() { return mConnectedPort; }
@ -539,6 +547,7 @@ class WithDevicePortConnectedState {
private:
const AudioPort mIdAndData;
IModule* mModule = nullptr;
ModuleConfig* mModuleConfig = nullptr;
AudioPort mConnectedPort;
};
@ -1422,7 +1431,7 @@ TEST_P(AudioCoreModule, GetAudioPortWithExternalDevices) {
for (const auto& port : ports) {
AudioPort portWithData = GenerateUniqueDeviceAddress(port);
WithDevicePortConnectedState portConnected(portWithData);
ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get(), moduleConfig.get()));
const int32_t connectedPortId = portConnected.getId();
ASSERT_NE(portWithData.id, connectedPortId);
ASSERT_EQ(portWithData.ext.getTag(), portConnected.get().ext.getTag());
@ -1526,7 +1535,7 @@ TEST_P(AudioCoreModule, ResetAudioPortConfigToInitialValue) {
TEST_P(AudioCoreModule, SetAudioPortConfigSuggestedConfig) {
ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
auto srcMixPort = moduleConfig->getSourceMixPortForAttachedDevice();
auto srcMixPort = moduleConfig->getSourceMixPortForConnectedDevice();
if (!srcMixPort.has_value()) {
GTEST_SKIP() << "No mix port for attached output devices";
}
@ -1578,7 +1587,7 @@ TEST_P(AudioCoreModule, SetAllExternalDevicePortConfigs) {
}
for (const auto& port : ports) {
WithDevicePortConnectedState portConnected(GenerateUniqueDeviceAddress(port));
ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get(), moduleConfig.get()));
ASSERT_NO_FATAL_FAILURE(
ApplyEveryConfig(moduleConfig->getPortConfigsForDevicePort(portConnected.get())));
}
@ -1648,7 +1657,7 @@ TEST_P(AudioCoreModule, TryChangingConnectionSimulationMidway) {
GTEST_SKIP() << "No external devices in the module.";
}
WithDevicePortConnectedState portConnected(GenerateUniqueDeviceAddress(*ports.begin()));
ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get(), moduleConfig.get()));
ModuleDebug midwayDebugChange = debug->flags();
midwayDebugChange.simulateDeviceConnections = false;
EXPECT_STATUS(EX_ILLEGAL_STATE, module->setModuleDebug(midwayDebugChange))
@ -1703,7 +1712,7 @@ TEST_P(AudioCoreModule, ConnectDisconnectExternalDeviceTwice) {
<< "when disconnecting already disconnected device port ID " << port.id;
AudioPort portWithData = GenerateUniqueDeviceAddress(port);
WithDevicePortConnectedState portConnected(portWithData);
ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get(), moduleConfig.get()));
EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
module->connectExternalDevice(portConnected.get(), &ignored))
<< "when trying to connect a connected device port "
@ -1725,7 +1734,7 @@ TEST_P(AudioCoreModule, DisconnectExternalDeviceNonResetPortConfig) {
}
for (const auto& port : ports) {
WithDevicePortConnectedState portConnected(GenerateUniqueDeviceAddress(port));
ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get(), moduleConfig.get()));
const auto portConfig = moduleConfig->getSingleConfigForDevicePort(portConnected.get());
{
WithAudioPortConfig config(portConfig);
@ -1753,7 +1762,7 @@ TEST_P(AudioCoreModule, ExternalDevicePortRoutes) {
int32_t connectedPortId;
{
WithDevicePortConnectedState portConnected(GenerateUniqueDeviceAddress(port));
ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get(), moduleConfig.get()));
connectedPortId = portConnected.getId();
std::vector<AudioRoute> connectedPortRoutes;
ASSERT_IS_OK(module->getAudioRoutesForAudioPort(connectedPortId, &connectedPortRoutes))
@ -1794,7 +1803,7 @@ TEST_P(AudioCoreModule, ExternalDeviceMixPortConfigs) {
}
for (const auto& port : externalDevicePorts) {
WithDevicePortConnectedState portConnected(GenerateUniqueDeviceAddress(port));
ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get(), moduleConfig.get()));
std::vector<AudioRoute> routes;
ASSERT_IS_OK(module->getAudioRoutesForAudioPort(portConnected.getId(), &routes));
std::vector<AudioPort> allPorts;
@ -2459,7 +2468,7 @@ class AudioStream : public AudioCoreModule {
void OpenOverMaxCount() {
constexpr bool isInput = IOTraits<Stream>::is_input;
auto ports = moduleConfig->getMixPorts(isInput, true /*attachedOnly*/);
auto ports = moduleConfig->getMixPorts(isInput, true /*connectedOnly*/);
bool hasSingleRun = false;
for (const auto& port : ports) {
const size_t maxStreamCount = port.ext.get<AudioPortExt::Tag::mix>().maxOpenStreamCount;
@ -2580,7 +2589,7 @@ class AudioStream : public AudioCoreModule {
void HwGainHwVolume() {
const auto ports =
moduleConfig->getMixPorts(IOTraits<Stream>::is_input, true /*attachedOnly*/);
moduleConfig->getMixPorts(IOTraits<Stream>::is_input, true /*connectedOnly*/);
if (ports.empty()) {
GTEST_SKIP() << "No mix ports";
}
@ -2619,7 +2628,7 @@ class AudioStream : public AudioCoreModule {
// it as an invalid argument, or say that offloaded effects are not supported.
void AddRemoveEffectInvalidArguments() {
const auto ports =
moduleConfig->getMixPorts(IOTraits<Stream>::is_input, true /*attachedOnly*/);
moduleConfig->getMixPorts(IOTraits<Stream>::is_input, true /*connectedOnly*/);
if (ports.empty()) {
GTEST_SKIP() << "No mix ports";
}
@ -2742,7 +2751,7 @@ TEST_P(AudioStreamIn, ActiveMicrophones) {
if (!status.isOk()) {
GTEST_SKIP() << "Microphone info is not supported";
}
const auto ports = moduleConfig->getInputMixPorts(true /*attachedOnly*/);
const auto ports = moduleConfig->getInputMixPorts(true /*connectedOnly*/);
if (ports.empty()) {
GTEST_SKIP() << "No input mix ports for attached devices";
}
@ -2759,7 +2768,7 @@ TEST_P(AudioStreamIn, ActiveMicrophones) {
"non-empty list of active microphones";
}
if (auto micDevicePorts = ModuleConfig::getBuiltInMicPorts(
moduleConfig->getAttachedSourceDevicesPortsForMixPort(port));
moduleConfig->getConnectedSourceDevicesPortsForMixPort(port));
!micDevicePorts.empty()) {
auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(micDevicePorts[0]);
WithAudioPatch patch(true /*isInput*/, stream.getPortConfig(), devicePortConfig);
@ -2791,7 +2800,7 @@ TEST_P(AudioStreamIn, ActiveMicrophones) {
TEST_P(AudioStreamIn, MicrophoneDirection) {
using MD = IStreamIn::MicrophoneDirection;
const auto ports = moduleConfig->getInputMixPorts(true /*attachedOnly*/);
const auto ports = moduleConfig->getInputMixPorts(true /*connectedOnly*/);
if (ports.empty()) {
GTEST_SKIP() << "No input mix ports for attached devices";
}
@ -2814,7 +2823,7 @@ TEST_P(AudioStreamIn, MicrophoneDirection) {
}
TEST_P(AudioStreamIn, MicrophoneFieldDimension) {
const auto ports = moduleConfig->getInputMixPorts(true /*attachedOnly*/);
const auto ports = moduleConfig->getInputMixPorts(true /*connectedOnly*/);
if (ports.empty()) {
GTEST_SKIP() << "No input mix ports for attached devices";
}
@ -2846,7 +2855,7 @@ TEST_P(AudioStreamIn, MicrophoneFieldDimension) {
TEST_P(AudioStreamOut, OpenTwicePrimary) {
const auto mixPorts =
moduleConfig->getPrimaryMixPorts(true /*attachedOnly*/, true /*singlePort*/);
moduleConfig->getPrimaryMixPorts(true /*connectedOnly*/, true /*singlePort*/);
if (mixPorts.empty()) {
GTEST_SKIP() << "No primary mix port which could be routed to attached devices";
}
@ -2857,7 +2866,7 @@ TEST_P(AudioStreamOut, OpenTwicePrimary) {
TEST_P(AudioStreamOut, RequireOffloadInfo) {
const auto offloadMixPorts =
moduleConfig->getOffloadMixPorts(true /*attachedOnly*/, true /*singlePort*/);
moduleConfig->getOffloadMixPorts(true /*connectedOnly*/, true /*singlePort*/);
if (offloadMixPorts.empty()) {
GTEST_SKIP()
<< "No mix port for compressed offload that could be routed to attached devices";
@ -2879,7 +2888,7 @@ TEST_P(AudioStreamOut, RequireOffloadInfo) {
TEST_P(AudioStreamOut, RequireAsyncCallback) {
const auto nonBlockingMixPorts =
moduleConfig->getNonBlockingMixPorts(true /*attachedOnly*/, true /*singlePort*/);
moduleConfig->getNonBlockingMixPorts(true /*connectedOnly*/, true /*singlePort*/);
if (nonBlockingMixPorts.empty()) {
GTEST_SKIP()
<< "No mix port for non-blocking output that could be routed to attached devices";
@ -2902,7 +2911,7 @@ TEST_P(AudioStreamOut, RequireAsyncCallback) {
}
TEST_P(AudioStreamOut, AudioDescriptionMixLevel) {
const auto ports = moduleConfig->getOutputMixPorts(true /*attachedOnly*/);
const auto ports = moduleConfig->getOutputMixPorts(true /*connectedOnly*/);
if (ports.empty()) {
GTEST_SKIP() << "No output mix ports";
}
@ -2930,7 +2939,7 @@ TEST_P(AudioStreamOut, AudioDescriptionMixLevel) {
}
TEST_P(AudioStreamOut, DualMonoMode) {
const auto ports = moduleConfig->getOutputMixPorts(true /*attachedOnly*/);
const auto ports = moduleConfig->getOutputMixPorts(true /*connectedOnly*/);
if (ports.empty()) {
GTEST_SKIP() << "No output mix ports";
}
@ -2954,7 +2963,7 @@ TEST_P(AudioStreamOut, DualMonoMode) {
}
TEST_P(AudioStreamOut, LatencyMode) {
const auto ports = moduleConfig->getOutputMixPorts(true /*attachedOnly*/);
const auto ports = moduleConfig->getOutputMixPorts(true /*connectedOnly*/);
if (ports.empty()) {
GTEST_SKIP() << "No output mix ports";
}
@ -2996,7 +3005,7 @@ TEST_P(AudioStreamOut, LatencyMode) {
TEST_P(AudioStreamOut, PlaybackRate) {
static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION};
const auto offloadMixPorts =
moduleConfig->getOffloadMixPorts(true /*attachedOnly*/, false /*singlePort*/);
moduleConfig->getOffloadMixPorts(true /*connectedOnly*/, false /*singlePort*/);
if (offloadMixPorts.empty()) {
GTEST_SKIP()
<< "No mix port for compressed offload that could be routed to attached devices";
@ -3066,7 +3075,7 @@ TEST_P(AudioStreamOut, PlaybackRate) {
TEST_P(AudioStreamOut, SelectPresentation) {
static const auto kStatuses = {EX_ILLEGAL_ARGUMENT, EX_UNSUPPORTED_OPERATION};
const auto offloadMixPorts =
moduleConfig->getOffloadMixPorts(true /*attachedOnly*/, false /*singlePort*/);
moduleConfig->getOffloadMixPorts(true /*connectedOnly*/, false /*singlePort*/);
if (offloadMixPorts.empty()) {
GTEST_SKIP()
<< "No mix port for compressed offload that could be routed to attached devices";
@ -3088,7 +3097,7 @@ TEST_P(AudioStreamOut, SelectPresentation) {
TEST_P(AudioStreamOut, UpdateOffloadMetadata) {
const auto offloadMixPorts =
moduleConfig->getOffloadMixPorts(true /*attachedOnly*/, false /*singlePort*/);
moduleConfig->getOffloadMixPorts(true /*connectedOnly*/, false /*singlePort*/);
if (offloadMixPorts.empty()) {
GTEST_SKIP()
<< "No mix port for compressed offload that could be routed to attached devices";
@ -3301,7 +3310,7 @@ class AudioStreamIo : public AudioCoreModuleBase,
void RunStreamIoCommandsImplSeq1(const AudioPortConfig& portConfig,
std::shared_ptr<StateSequence> commandsAndStates,
bool validatePositionIncrease) {
auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
auto devicePorts = moduleConfig->getConnectedDevicesPortsForMixPort(
IOTraits<Stream>::is_input, portConfig);
ASSERT_FALSE(devicePorts.empty());
auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
@ -3341,7 +3350,7 @@ class AudioStreamIo : public AudioCoreModuleBase,
typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver,
stream.getEventReceiver());
auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
auto devicePorts = moduleConfig->getConnectedDevicesPortsForMixPort(
IOTraits<Stream>::is_input, portConfig);
ASSERT_FALSE(devicePorts.empty());
auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
@ -4006,6 +4015,172 @@ INSTANTIATE_TEST_SUITE_P(AudioPatchTest, AudioModulePatch,
android::PrintInstanceNameToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioModulePatch);
static std::vector<std::string> getRemoteSubmixModuleInstance() {
auto instances = android::getAidlHalInstanceNames(IModule::descriptor);
for (auto instance : instances) {
if (instance.find("r_submix") != std::string::npos)
return (std::vector<std::string>{instance});
}
return {};
}
template <typename Stream>
class WithRemoteSubmix {
public:
WithRemoteSubmix() = default;
WithRemoteSubmix(AudioDeviceAddress address) : mAddress(address) {}
WithRemoteSubmix(const WithRemoteSubmix&) = delete;
WithRemoteSubmix& operator=(const WithRemoteSubmix&) = delete;
std::optional<AudioPort> getAudioPort() {
AudioDeviceType deviceType = IOTraits<Stream>::is_input ? AudioDeviceType::IN_SUBMIX
: AudioDeviceType::OUT_SUBMIX;
auto ports = mModuleConfig->getAudioPortsForDeviceTypes(
std::vector<AudioDeviceType>{deviceType},
AudioDeviceDescription::CONNECTION_VIRTUAL);
if (!ports.empty()) return ports.front();
return {};
}
/* Connect remote submix external device */
void SetUpPortConnection() {
auto port = getAudioPort();
ASSERT_TRUE(port.has_value()) << "Device AudioPort for remote submix not found";
if (mAddress.has_value()) {
port.value().ext.template get<AudioPortExt::Tag::device>().device.address =
mAddress.value();
} else {
port = GenerateUniqueDeviceAddress(port.value());
}
mConnectedPort = std::make_unique<WithDevicePortConnectedState>(port.value());
ASSERT_NO_FATAL_FAILURE(mConnectedPort->SetUp(mModule, mModuleConfig));
}
AudioDeviceAddress getAudioDeviceAddress() {
if (!mAddress.has_value()) {
mAddress = mConnectedPort->get()
.ext.template get<AudioPortExt::Tag::device>()
.device.address;
}
return mAddress.value();
}
/* Get mix port config for stream and setup patch for it. */
void SetupPatch() {
const auto portConfig =
mModuleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
if (!portConfig.has_value()) {
LOG(DEBUG) << __func__ << ": portConfig not found";
mSkipTest = true;
return;
}
auto devicePortConfig = mModuleConfig->getSingleConfigForDevicePort(mConnectedPort->get());
mPatch = std::make_unique<WithAudioPatch>(IOTraits<Stream>::is_input, portConfig.value(),
devicePortConfig);
ASSERT_NO_FATAL_FAILURE(mPatch->SetUp(mModule));
}
void SetUp(IModule* module, ModuleConfig* moduleConfig) {
mModule = module;
mModuleConfig = moduleConfig;
ASSERT_NO_FATAL_FAILURE(SetUpPortConnection());
ASSERT_NO_FATAL_FAILURE(SetupPatch());
if (!mSkipTest) {
// open stream
mStream = std::make_unique<WithStream<Stream>>(
mPatch->getPortConfig(IOTraits<Stream>::is_input));
ASSERT_NO_FATAL_FAILURE(
mStream->SetUp(mModule, AudioCoreModuleBase::kDefaultBufferSizeFrames));
}
}
void sendBurstCommands() {
const StreamContext* context = mStream->getContext();
StreamLogicDefaultDriver driver(makeBurstCommands(true), context->getFrameSizeBytes());
typename IOTraits<Stream>::Worker worker(*context, &driver, mStream->getEventReceiver());
LOG(DEBUG) << __func__ << ": starting worker...";
ASSERT_TRUE(worker.start());
LOG(DEBUG) << __func__ << ": joining worker...";
worker.join();
EXPECT_FALSE(worker.hasError()) << worker.getError();
EXPECT_EQ("", driver.getUnexpectedStateTransition());
if (IOTraits<Stream>::is_input) {
EXPECT_TRUE(driver.hasObservablePositionIncrease());
}
EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
}
bool skipTest() { return mSkipTest; }
private:
bool mSkipTest = false;
IModule* mModule = nullptr;
ModuleConfig* mModuleConfig = nullptr;
std::optional<AudioDeviceAddress> mAddress;
std::unique_ptr<WithDevicePortConnectedState> mConnectedPort;
std::unique_ptr<WithAudioPatch> mPatch;
std::unique_ptr<WithStream<Stream>> mStream;
};
class AudioModuleRemoteSubmix : public AudioCoreModule {
public:
void SetUp() override {
ASSERT_NO_FATAL_FAILURE(AudioCoreModule::SetUp());
ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
}
void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
};
TEST_P(AudioModuleRemoteSubmix, OutputDoesNotBlockWhenNoInput) {
// open output stream
WithRemoteSubmix<IStreamOut> streamOut;
ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get()));
if (streamOut.skipTest()) {
GTEST_SKIP() << "No mix port for attached devices";
}
// write something to stream
ASSERT_NO_FATAL_FAILURE(streamOut.sendBurstCommands());
}
TEST_P(AudioModuleRemoteSubmix, OutputDoesNotBlockWhenInputStuck) {
// open output stream
WithRemoteSubmix<IStreamOut> streamOut;
ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get()));
if (streamOut.skipTest()) {
GTEST_SKIP() << "No mix port for attached devices";
}
// open input stream
WithRemoteSubmix<IStreamIn> streamIn(streamOut.getAudioDeviceAddress());
ASSERT_NO_FATAL_FAILURE(streamIn.SetUp(module.get(), moduleConfig.get()));
if (streamIn.skipTest()) {
GTEST_SKIP() << "No mix port for attached devices";
}
// write something to stream
ASSERT_NO_FATAL_FAILURE(streamOut.sendBurstCommands());
}
TEST_P(AudioModuleRemoteSubmix, OutputAndInput) {
// open output stream
WithRemoteSubmix<IStreamOut> streamOut;
ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get()));
if (streamOut.skipTest()) {
GTEST_SKIP() << "No mix port for attached devices";
}
// open input stream
WithRemoteSubmix<IStreamIn> streamIn(streamOut.getAudioDeviceAddress());
ASSERT_NO_FATAL_FAILURE(streamIn.SetUp(module.get(), moduleConfig.get()));
if (streamIn.skipTest()) {
GTEST_SKIP() << "No mix port for attached devices";
}
// write something to stream
ASSERT_NO_FATAL_FAILURE(streamOut.sendBurstCommands());
// read from input stream
ASSERT_NO_FATAL_FAILURE(streamIn.sendBurstCommands());
}
INSTANTIATE_TEST_SUITE_P(AudioModuleRemoteSubmixTest, AudioModuleRemoteSubmix,
::testing::ValuesIn(getRemoteSubmixModuleInstance()));
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioModuleRemoteSubmix);
class TestExecutionTracer : public ::testing::EmptyTestEventListener {
public:
void OnTestStart(const ::testing::TestInfo& test_info) override {