Merge "Remove the volume flag if no volume support for any sub-effect in proxy" into main
diff --git a/media/codec2/hal/client/output.cpp b/media/codec2/hal/client/output.cpp
index f86e048..7f4f86b 100644
--- a/media/codec2/hal/client/output.cpp
+++ b/media/codec2/hal/client/output.cpp
@@ -141,11 +141,14 @@
"status = " << INVALID_OPERATION << ".";
return INVALID_OPERATION;
}
- result = igbp->attachBuffer(bqSlot, graphicBuffer);
- if (result == OK) {
- syncVar->notifyDequeuedLocked();
- }
+ syncVar->notifyDequeuedLocked();
syncVar->unlock();
+ result = igbp->attachBuffer(bqSlot, graphicBuffer);
+ if (result != OK) {
+ syncVar->lock();
+ syncVar->notifyQueuedLocked();
+ syncVar->unlock();
+ }
} else {
result = igbp->attachBuffer(bqSlot, graphicBuffer);
}
@@ -435,13 +438,13 @@
auto syncVar = syncMem ? syncMem->mem() : nullptr;
if(syncVar) {
- syncVar->lock();
status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
input, output);
if (status == OK) {
+ syncVar->lock();
syncVar->notifyQueuedLocked();
+ syncVar->unlock();
}
- syncVar->unlock();
} else {
status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
input, output);
@@ -490,13 +493,13 @@
auto syncVar = syncMem ? syncMem->mem() : nullptr;
status_t status = OK;
if (syncVar) {
- syncVar->lock();
status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
input, output);
if (status == OK) {
+ syncVar->lock();
syncVar->notifyQueuedLocked();
+ syncVar->unlock();
}
- syncVar->unlock();
} else {
status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
input, output);
diff --git a/media/codec2/sfplugin/utils/Codec2CommonUtils.cpp b/media/codec2/sfplugin/utils/Codec2CommonUtils.cpp
index 7492cab..ff72b1f 100644
--- a/media/codec2/sfplugin/utils/Codec2CommonUtils.cpp
+++ b/media/codec2/sfplugin/utils/Codec2CommonUtils.cpp
@@ -47,35 +47,12 @@
}
static bool isP010Allowed() {
- // The first SDK the device shipped with.
- static const int32_t kProductFirstApiLevel =
- base::GetIntProperty<int32_t>("ro.product.first_api_level", 0);
+ // The Vendor API level which is min(ro.product.first_api_level, ro.board.[first_]api_level).
+ // This is the api level to which VSR requirement the device conform.
+ static const int32_t kVendorApiLevel =
+ base::GetIntProperty<int32_t>("ro.vendor.api_level", 0);
- // GRF devices (introduced in Android 11) list the first and possibly the current api levels
- // to signal which VSR requirements they conform to even if the first device SDK was higher.
- static const int32_t kBoardFirstApiLevel =
- base::GetIntProperty<int32_t>("ro.board.first_api_level", 0);
-
- // Some devices that launched prior to Android S may not support P010 correctly, even
- // though they may advertise it as supported.
- if (kProductFirstApiLevel != 0 && kProductFirstApiLevel < __ANDROID_API_S__) {
- return false;
- }
-
- if (kBoardFirstApiLevel != 0 && kBoardFirstApiLevel < __ANDROID_API_S__) {
- return false;
- }
-
- static const int32_t kBoardApiLevel =
- base::GetIntProperty<int32_t>("ro.board.api_level", 0);
-
- // For non-GRF devices, use the first SDK version by the product.
- static const int32_t kFirstApiLevel =
- kBoardApiLevel != 0 ? kBoardApiLevel :
- kBoardFirstApiLevel != 0 ? kBoardFirstApiLevel :
- kProductFirstApiLevel;
-
- return kFirstApiLevel >= __ANDROID_API_T__;
+ return kVendorApiLevel >= __ANDROID_API_T__;
}
bool isHalPixelFormatSupported(AHardwareBuffer_Format format) {
diff --git a/media/codec2/tests/Android.bp b/media/codec2/tests/Android.bp
index 2217235..02c356c 100644
--- a/media/codec2/tests/Android.bp
+++ b/media/codec2/tests/Android.bp
@@ -27,6 +27,7 @@
static_libs: [
],
+ cpp_std: "gnu++17",
cflags: [
"-Werror",
"-Wall",
diff --git a/media/codec2/vndk/Android.bp b/media/codec2/vndk/Android.bp
index bbe228c..265d87d 100644
--- a/media/codec2/vndk/Android.bp
+++ b/media/codec2/vndk/Android.bp
@@ -171,6 +171,7 @@
// public dependency for implementing Codec 2 components
cc_defaults {
name: "libcodec2-impl-defaults",
+ cpp_std: "gnu++17",
shared_libs: [
"libbase", // for C2_LOG
diff --git a/media/libaudiohal/impl/Android.bp b/media/libaudiohal/impl/Android.bp
index 1689365..fb1cc34 100644
--- a/media/libaudiohal/impl/Android.bp
+++ b/media/libaudiohal/impl/Android.bp
@@ -319,6 +319,7 @@
"ConversionHelperAidl.cpp",
"DeviceHalAidl.cpp",
"DevicesFactoryHalAidl.cpp",
+ "Hal2AidlMapper.cpp",
"StreamHalAidl.cpp",
],
}
diff --git a/media/libaudiohal/impl/Cleanups.h b/media/libaudiohal/impl/Cleanups.h
new file mode 100644
index 0000000..a313da1
--- /dev/null
+++ b/media/libaudiohal/impl/Cleanups.h
@@ -0,0 +1,107 @@
+/*
+ * 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 <forward_list>
+#include <mutex>
+#include <utility>
+
+namespace android {
+
+// This class implements the "monitor" idiom for providing locked access to a class instance.
+// This is how it is intended to be used. Let's assume there is a "Main" class which owns
+// an instance of a "Resource" class, which is protected by a mutex. We add an instance of
+// "LockedAccessor<Resource>" as a member of "Main":
+//
+// class Resource;
+//
+// class Main {
+// Main() : mAccessor(mResource, mLock) {}
+// private:
+// std::mutex mLock;
+// Resource mResource GUARDED_BY(mLock); // owns the resource
+// LockedAccessor<Resource> mAccessor;
+// };
+//
+// The accessor is initialized in the constructor when no locking is needed. The accessor
+// defers locking until the resource is accessed.
+//
+// Although "mAccessor" can be used by the methods of "Main" for scoped access to the resource,
+// its main role is for granting access to the resource to other classes. This is achieved by
+// making a copy of "mAccessor" and giving it away to another class. This obviously does not
+// transfer ownership of the resource. The intent is to allow another class to use the resource
+// with proper locking in a "lazy" fashion:
+//
+// class Another {
+// public:
+// Another(const LockedAccessor<Resource>& accessor) : mAccessor(accessor) {}
+// void doItLater() { // Use explicit 'lock' / 'unlock'
+// auto resource = mAccessor.lock();
+// resource.use();
+// mAccessor.unlock();
+// }
+// void doItLaterScoped() { // Rely on the scoped accessor do perform unlocking.
+// LockedAccessor<Resource> scopedAccessor(mAccessor);
+// auto resource = scopedAccessor.lock();
+// resource.use();
+// }
+// private:
+// LockedAccessor<Resource> mAccessor;
+// };
+//
+template<class C>
+class LockedAccessor {
+ public:
+ LockedAccessor(C& instance, std::mutex& mutex)
+ : mInstance(instance), mMutex(mutex), mLock(mMutex, std::defer_lock) {}
+ LockedAccessor(const LockedAccessor& other)
+ : mInstance(other.mInstance), mMutex(other.mMutex), mLock(mMutex, std::defer_lock) {}
+ ~LockedAccessor() { if (mLock.owns_lock()) mLock.unlock(); }
+ C& lock() { mLock.lock(); return mInstance; }
+ void unlock() { mLock.unlock(); }
+ private:
+ C& mInstance;
+ std::mutex& mMutex;
+ std::unique_lock<std::mutex> mLock;
+};
+
+// This class implements scoped cleanups. A "cleanup" is a call to a method of class "C" which
+// takes an integer parameter. Cleanups are executed in the reverse order to how they were added.
+// For executing cleanups, the instance of "C" is retrieved via the provided "LockedAccessor".
+template<class C>
+class Cleanups {
+ public:
+ typedef void (C::*Cleaner)(int32_t); // A member function of "C" performing a cleanup action.
+ explicit Cleanups(const LockedAccessor<C>& accessor) : mAccessor(accessor) {}
+ ~Cleanups() {
+ if (!mCleanups.empty()) {
+ C& c = mAccessor.lock();
+ for (auto& cleanup : mCleanups) (c.*cleanup.first)(cleanup.second);
+ mAccessor.unlock();
+ }
+ }
+ void add(Cleaner cleaner, int32_t id) {
+ mCleanups.emplace_front(cleaner, id);
+ }
+ void disarmAll() { mCleanups.clear(); }
+ private:
+ using Cleanup = std::pair<Cleaner, int32_t>;
+ LockedAccessor<C> mAccessor;
+ std::forward_list<Cleanup> mCleanups;
+};
+
+} // namespace android
diff --git a/media/libaudiohal/impl/DeviceHalAidl.cpp b/media/libaudiohal/impl/DeviceHalAidl.cpp
index 5bc25ae..8a843ed 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalAidl.cpp
@@ -18,7 +18,6 @@
// #define LOG_NDEBUG 0
#include <algorithm>
-#include <forward_list>
#include <aidl/android/hardware/audio/core/BnStreamCallback.h>
#include <aidl/android/hardware/audio/core/BnStreamOutEventCallback.h>
@@ -38,15 +37,9 @@
using aidl::android::aidl_utils::statusTFromBinderStatus;
using aidl::android::media::audio::common::Boolean;
-using aidl::android::media::audio::common::AudioChannelLayout;
using aidl::android::media::audio::common::AudioConfig;
using aidl::android::media::audio::common::AudioDevice;
-using aidl::android::media::audio::common::AudioDeviceAddress;
-using aidl::android::media::audio::common::AudioDeviceDescription;
using aidl::android::media::audio::common::AudioDeviceType;
-using aidl::android::media::audio::common::AudioFormatDescription;
-using aidl::android::media::audio::common::AudioFormatType;
-using aidl::android::media::audio::common::AudioInputFlags;
using aidl::android::media::audio::common::AudioIoFlags;
using aidl::android::media::audio::common::AudioLatencyMode;
using aidl::android::media::audio::common::AudioMMapPolicy;
@@ -56,11 +49,7 @@
using aidl::android::media::audio::common::AudioOutputFlags;
using aidl::android::media::audio::common::AudioPort;
using aidl::android::media::audio::common::AudioPortConfig;
-using aidl::android::media::audio::common::AudioPortDeviceExt;
using aidl::android::media::audio::common::AudioPortExt;
-using aidl::android::media::audio::common::AudioPortMixExt;
-using aidl::android::media::audio::common::AudioPortMixExtUseCase;
-using aidl::android::media::audio::common::AudioProfile;
using aidl::android::media::audio::common::AudioSource;
using aidl::android::media::audio::common::Float;
using aidl::android::media::audio::common::Int;
@@ -69,9 +58,8 @@
using aidl::android::media::audio::IHalAdapterVendorExtension;
using aidl::android::hardware::audio::common::getFrameSizeInBytes;
using aidl::android::hardware::audio::common::isBitPositionFlagSet;
-using aidl::android::hardware::audio::common::isDefaultAudioFormat;
-using aidl::android::hardware::audio::common::makeBitPositionFlagMask;
using aidl::android::hardware::audio::common::RecordTrackMetadata;
+using aidl::android::hardware::audio::core::sounddose::ISoundDose;
using aidl::android::hardware::audio::core::AudioPatch;
using aidl::android::hardware::audio::core::AudioRoute;
using aidl::android::hardware::audio::core::IBluetooth;
@@ -80,37 +68,12 @@
using aidl::android::hardware::audio::core::IModule;
using aidl::android::hardware::audio::core::ITelephony;
using aidl::android::hardware::audio::core::ModuleDebug;
-using aidl::android::hardware::audio::core::StreamDescriptor;
using aidl::android::hardware::audio::core::VendorParameter;
namespace android {
namespace {
-bool isConfigEqualToPortConfig(const AudioConfig& config, const AudioPortConfig& portConfig) {
- return portConfig.sampleRate.value().value == config.base.sampleRate &&
- portConfig.channelMask.value() == config.base.channelMask &&
- portConfig.format.value() == config.base.format;
-}
-
-void setConfigFromPortConfig(AudioConfig* config, const AudioPortConfig& portConfig) {
- config->base.sampleRate = portConfig.sampleRate.value().value;
- config->base.channelMask = portConfig.channelMask.value();
- config->base.format = portConfig.format.value();
-}
-
-void setPortConfigFromConfig(AudioPortConfig* portConfig, const AudioConfig& config) {
- if (config.base.sampleRate != 0) {
- portConfig->sampleRate = Int{ .value = config.base.sampleRate };
- }
- if (config.base.channelMask != AudioChannelLayout{}) {
- portConfig->channelMask = config.base.channelMask;
- }
- if (config.base.format != AudioFormatDescription{}) {
- portConfig->format = config.base.format;
- }
-}
-
// Note: these converters are for types defined in different AIDL files. Although these
// AIDL files are copies of each other, however formally these are different types
// thus we don't use a conversion via a parcelable.
@@ -144,28 +107,29 @@
mTelephony(retrieveSubInterface<ITelephony>(module, &IModule::getTelephony)),
mBluetooth(retrieveSubInterface<IBluetooth>(module, &IModule::getBluetooth)),
mBluetoothA2dp(retrieveSubInterface<IBluetoothA2dp>(module, &IModule::getBluetoothA2dp)),
- mBluetoothLe(retrieveSubInterface<IBluetoothLe>(module, &IModule::getBluetoothLe)) {
+ mBluetoothLe(retrieveSubInterface<IBluetoothLe>(module, &IModule::getBluetoothLe)),
+ mSoundDose(retrieveSubInterface<ISoundDose>(module, &IModule::getSoundDose)),
+ mMapper(instance, module), mMapperAccessor(mMapper, mLock) {
}
status_t DeviceHalAidl::getAudioPorts(std::vector<media::audio::common::AudioPort> *ports) {
- return ::aidl::android::convertContainer(mPorts, ports,
- [](const Ports::value_type& pair) { return ndk2cpp_AudioPort(pair.second); });
+ std::lock_guard l(mLock);
+ return mMapper.getAudioPorts(ports, ndk2cpp_AudioPort);
}
status_t DeviceHalAidl::getAudioRoutes(std::vector<media::AudioRoute> *routes) {
- *routes = VALUE_OR_RETURN_STATUS(
- ::aidl::android::convertContainer<std::vector<media::AudioRoute>>(
- mRoutes, ndk2cpp_AudioRoute));
- return OK;
+ std::lock_guard l(mLock);
+ return mMapper.getAudioRoutes(routes, ndk2cpp_AudioRoute);
}
status_t DeviceHalAidl::getSupportedModes(std::vector<media::audio::common::AudioMode> *modes) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
+ if (mModule == nullptr) return NO_INIT;
+ if (mTelephony == nullptr) return INVALID_OPERATION;
if (modes == nullptr) {
return BAD_VALUE;
}
- if (mModule == nullptr) return NO_INIT;
- if (mTelephony == nullptr) return INVALID_OPERATION;
std::vector<AudioMode> aidlModes;
RETURN_STATUS_IF_ERROR(
statusTFromBinderStatus(mTelephony->getSupportedAudioModes(&aidlModes)));
@@ -181,105 +145,17 @@
}
status_t DeviceHalAidl::initCheck() {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
if (mModule == nullptr) return NO_INIT;
- std::vector<AudioPort> ports;
- RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->getAudioPorts(&ports)));
- ALOGW_IF(ports.empty(), "%s: module %s returned an empty list of audio ports",
- __func__, mInstance.c_str());
- mDefaultInputPortId = mDefaultOutputPortId = -1;
- const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
- for (auto it = ports.begin(); it != ports.end(); ) {
- const auto& port = *it;
- if (port.ext.getTag() != AudioPortExt::Tag::device) {
- ++it;
- continue;
- }
- const AudioPortDeviceExt& deviceExt = port.ext.get<AudioPortExt::Tag::device>();
- if ((deviceExt.flags & defaultDeviceFlag) != 0) {
- if (port.flags.getTag() == AudioIoFlags::Tag::input) {
- mDefaultInputPortId = port.id;
- } else if (port.flags.getTag() == AudioIoFlags::Tag::output) {
- mDefaultOutputPortId = port.id;
- }
- }
- // For compatibility with HIDL, hide "template" remote submix ports from ports list.
- if (const auto& devDesc = deviceExt.device;
- (devDesc.type.type == AudioDeviceType::IN_SUBMIX ||
- devDesc.type.type == AudioDeviceType::OUT_SUBMIX) &&
- devDesc.type.connection == AudioDeviceDescription::CONNECTION_VIRTUAL) {
- if (devDesc.type.type == AudioDeviceType::IN_SUBMIX) {
- mRemoteSubmixIn = port;
- } else {
- mRemoteSubmixOut = port;
- }
- it = ports.erase(it);
- } else {
- ++it;
- }
- }
- if (mRemoteSubmixIn.has_value() != mRemoteSubmixOut.has_value()) {
- ALOGE("%s: The configuration only has input or output remote submix device, must have both",
- __func__);
- mRemoteSubmixIn.reset();
- mRemoteSubmixOut.reset();
- }
- if (mRemoteSubmixIn.has_value()) {
- AudioPort connectedRSubmixIn = *mRemoteSubmixIn;
- connectedRSubmixIn.ext.get<AudioPortExt::Tag::device>().device.address =
- AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS;
- ALOGD("%s: connecting remote submix input", __func__);
- RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
- connectedRSubmixIn, &connectedRSubmixIn)));
- // The template port for the remote submix input couldn't be "default" because it is not
- // attached. The connected port can now be made default because we never disconnect it.
- if (mDefaultInputPortId == -1) {
- mDefaultInputPortId = connectedRSubmixIn.id;
- }
- ports.push_back(std::move(connectedRSubmixIn));
-
- // Remote submix output must not be connected until the framework actually starts
- // using it, however for legacy compatibility we need to provide an "augmented template"
- // port with an address and profiles. It is obtained by connecting the output and then
- // immediately disconnecting it. This is a cheap operation as we don't open any streams.
- AudioPort tempConnectedRSubmixOut = *mRemoteSubmixOut;
- tempConnectedRSubmixOut.ext.get<AudioPortExt::Tag::device>().device.address =
- AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS;
- ALOGD("%s: temporarily connecting and disconnecting remote submix output", __func__);
- RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
- tempConnectedRSubmixOut, &tempConnectedRSubmixOut)));
- RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->disconnectExternalDevice(
- tempConnectedRSubmixOut.id)));
- tempConnectedRSubmixOut.id = mRemoteSubmixOut->id;
- ports.push_back(std::move(tempConnectedRSubmixOut));
- }
-
- ALOGI("%s: module %s default port ids: input %d, output %d",
- __func__, mInstance.c_str(), mDefaultInputPortId, mDefaultOutputPortId);
- std::transform(ports.begin(), ports.end(), std::inserter(mPorts, mPorts.end()),
- [](const auto& p) { return std::make_pair(p.id, p); });
- RETURN_STATUS_IF_ERROR(updateRoutes());
- std::vector<AudioPortConfig> portConfigs;
- RETURN_STATUS_IF_ERROR(
- statusTFromBinderStatus(mModule->getAudioPortConfigs(&portConfigs))); // OK if empty
- std::transform(portConfigs.begin(), portConfigs.end(),
- std::inserter(mPortConfigs, mPortConfigs.end()),
- [](const auto& p) { return std::make_pair(p.id, p); });
- std::transform(mPortConfigs.begin(), mPortConfigs.end(),
- std::inserter(mInitialPortConfigIds, mInitialPortConfigIds.end()),
- [](const auto& pcPair) { return pcPair.first; });
- std::vector<AudioPatch> patches;
- RETURN_STATUS_IF_ERROR(
- statusTFromBinderStatus(mModule->getAudioPatches(&patches))); // OK if empty
- std::transform(patches.begin(), patches.end(),
- std::inserter(mPatches, mPatches.end()),
- [](const auto& p) { return std::make_pair(p.id, p); });
- return OK;
+ std::lock_guard l(mLock);
+ return mMapper.initialize();
}
status_t DeviceHalAidl::setVoiceVolume(float volume) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
- if (!mModule) return NO_INIT;
+ if (mModule == nullptr) return NO_INIT;
if (mTelephony == nullptr) return INVALID_OPERATION;
ITelephony::TelecomConfig inConfig{ .voiceVolume = Float{volume} }, outConfig;
RETURN_STATUS_IF_ERROR(
@@ -291,20 +167,26 @@
}
status_t DeviceHalAidl::setMasterVolume(float volume) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
- if (!mModule) return NO_INIT;
+ if (mModule == nullptr) return NO_INIT;
return statusTFromBinderStatus(mModule->setMasterVolume(volume));
}
status_t DeviceHalAidl::getMasterVolume(float *volume) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
- if (!mModule) return NO_INIT;
+ if (mModule == nullptr) return NO_INIT;
+ if (volume == nullptr) {
+ return BAD_VALUE;
+ }
return statusTFromBinderStatus(mModule->getMasterVolume(volume));
}
status_t DeviceHalAidl::setMode(audio_mode_t mode) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
- if (!mModule) return NO_INIT;
+ if (mModule == nullptr) return NO_INIT;
AudioMode audioMode = VALUE_OR_FATAL(::aidl::android::legacy2aidl_audio_mode_t_AudioMode(mode));
if (mTelephony != nullptr) {
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mTelephony->switchAudioMode(audioMode)));
@@ -313,31 +195,43 @@
}
status_t DeviceHalAidl::setMicMute(bool state) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
- if (!mModule) return NO_INIT;
+ if (mModule == nullptr) return NO_INIT;
return statusTFromBinderStatus(mModule->setMicMute(state));
}
status_t DeviceHalAidl::getMicMute(bool *state) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
- if (!mModule) return NO_INIT;
+ if (mModule == nullptr) return NO_INIT;
+ if (state == nullptr) {
+ return BAD_VALUE;
+ }
return statusTFromBinderStatus(mModule->getMicMute(state));
}
status_t DeviceHalAidl::setMasterMute(bool state) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
- if (!mModule) return NO_INIT;
+ if (mModule == nullptr) return NO_INIT;
return statusTFromBinderStatus(mModule->setMasterMute(state));
}
status_t DeviceHalAidl::getMasterMute(bool *state) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
- if (!mModule) return NO_INIT;
+ if (mModule == nullptr) return NO_INIT;
+ if (state == nullptr) {
+ return BAD_VALUE;
+ }
return statusTFromBinderStatus(mModule->getMasterMute(state));
}
status_t DeviceHalAidl::setParameters(const String8& kvPairs) {
- if (!mModule) return NO_INIT;
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ TIME_CHECK();
+ if (mModule == nullptr) return NO_INIT;
AudioParameter parameters(kvPairs);
ALOGD("%s: parameters: \"%s\"", __func__, parameters.toString().c_str());
@@ -363,8 +257,9 @@
}
status_t DeviceHalAidl::getParameters(const String8& keys, String8 *values) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
- if (!mModule) return NO_INIT;
+ if (mModule == nullptr) return NO_INIT;
if (values == nullptr) {
return BAD_VALUE;
}
@@ -376,44 +271,13 @@
return parseAndGetVendorParameters(mVendorExt, mModule, parameterKeys, values);
}
-namespace {
-
-class Cleanup {
- public:
- typedef void (DeviceHalAidl::*Cleaner)(int32_t);
-
- Cleanup(DeviceHalAidl* device, Cleaner cleaner, int32_t id) :
- mDevice(device), mCleaner(cleaner), mId(id) {}
- ~Cleanup() { clean(); }
- void clean() {
- if (mDevice != nullptr) (mDevice->*mCleaner)(mId);
- disarm();
- }
- void disarm() { mDevice = nullptr; }
-
- private:
- DeviceHalAidl* mDevice;
- const Cleaner mCleaner;
- const int32_t mId;
-};
-
-} // namespace
-
-// Since the order of container elements destruction is unspecified,
-// ensure that cleanups are performed from the most recent one and upwards.
-// This is the same as if there were individual Cleanup instances on the stack,
-// however the bonus is that we can disarm all of them with just one statement.
-class DeviceHalAidl::Cleanups : public std::forward_list<Cleanup> {
- public:
- ~Cleanups() { for (auto& c : *this) c.clean(); }
- void disarmAll() { for (auto& c : *this) c.disarm(); }
-};
-
status_t DeviceHalAidl::getInputBufferSize(const struct audio_config* config, size_t* size) {
ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
- if (size == nullptr) return BAD_VALUE;
TIME_CHECK();
- if (!mModule) return NO_INIT;
+ if (mModule == nullptr) return NO_INIT;
+ if (config == nullptr || size == nullptr) {
+ return BAD_VALUE;
+ }
AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
AudioDevice aidlDevice;
@@ -421,61 +285,20 @@
AudioSource aidlSource = AudioSource::DEFAULT;
AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(0);
AudioPortConfig mixPortConfig;
- Cleanups cleanups;
- audio_config writableConfig = *config;
+ Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
AudioPatch aidlPatch;
- RETURN_STATUS_IF_ERROR(prepareToOpenStream(0 /*handle*/, aidlDevice, aidlFlags, aidlSource,
- &writableConfig, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
+ {
+ std::lock_guard l(mLock);
+ RETURN_STATUS_IF_ERROR(mMapper.prepareToOpenStream(
+ 0 /*handle*/, aidlDevice, aidlFlags, aidlSource,
+ &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
+ }
*size = aidlConfig.frameCount *
getFrameSizeInBytes(aidlConfig.base.format, aidlConfig.base.channelMask);
// Do not disarm cleanups to release temporary port configs.
return OK;
}
-status_t DeviceHalAidl::prepareToOpenStream(
- int32_t aidlHandle, const AudioDevice& aidlDevice, const AudioIoFlags& aidlFlags,
- AudioSource aidlSource, struct audio_config* config,
- Cleanups* cleanups, AudioConfig* aidlConfig, AudioPortConfig* mixPortConfig,
- AudioPatch* aidlPatch) {
- ALOGD("%p %s::%s: handle %d, device %s, flags %s, source %s, config %s, mix port config %s",
- this, getClassName().c_str(), __func__, aidlHandle, aidlDevice.toString().c_str(),
- aidlFlags.toString().c_str(), toString(aidlSource).c_str(),
- aidlConfig->toString().c_str(), mixPortConfig->toString().c_str());
- resetUnusedPatchesAndPortConfigs();
- const bool isInput = aidlFlags.getTag() == AudioIoFlags::Tag::input;
- // Find / create AudioPortConfigs for the device port and the mix port,
- // then find / create a patch between them, and open a stream on the mix port.
- AudioPortConfig devicePortConfig;
- bool created = false;
- RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(aidlDevice, aidlConfig,
- &devicePortConfig, &created));
- if (created) {
- cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
- }
- RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(*aidlConfig, aidlFlags, aidlHandle, aidlSource,
- std::set<int32_t>{devicePortConfig.portId}, mixPortConfig, &created));
- if (created) {
- cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, mixPortConfig->id);
- }
- setConfigFromPortConfig(aidlConfig, *mixPortConfig);
- if (isInput) {
- RETURN_STATUS_IF_ERROR(findOrCreatePatch(
- {devicePortConfig.id}, {mixPortConfig->id}, aidlPatch, &created));
- } else {
- RETURN_STATUS_IF_ERROR(findOrCreatePatch(
- {mixPortConfig->id}, {devicePortConfig.id}, aidlPatch, &created));
- }
- if (created) {
- cleanups->emplace_front(this, &DeviceHalAidl::resetPatch, aidlPatch->id);
- }
- if (aidlConfig->frameCount <= 0) {
- aidlConfig->frameCount = aidlPatch->minimumStreamBufferSizeFrames;
- }
- *config = VALUE_OR_RETURN_STATUS(
- ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(*aidlConfig, isInput));
- return OK;
-}
-
namespace {
class StreamCallbackBase {
@@ -599,26 +422,32 @@
const char* address,
sp<StreamOutHalInterface>* outStream) {
ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
- if (!outStream || !config) {
+ TIME_CHECK();
+ if (mModule == nullptr) return NO_INIT;
+ if (outStream == nullptr || config == nullptr) {
return BAD_VALUE;
}
- TIME_CHECK();
- if (!mModule) return NO_INIT;
+ constexpr bool isInput = false;
int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
- ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, false /*isInput*/));
+ ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, isInput));
AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
int32_t aidlOutputFlags = VALUE_OR_RETURN_STATUS(
::aidl::android::legacy2aidl_audio_output_flags_t_int32_t_mask(flags));
AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::output>(aidlOutputFlags);
AudioPortConfig mixPortConfig;
- Cleanups cleanups;
AudioPatch aidlPatch;
- RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags,
- AudioSource::SYS_RESERVED_INVALID /*only needed for input*/,
- config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
+ Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
+ {
+ std::lock_guard l(mLock);
+ RETURN_STATUS_IF_ERROR(mMapper.prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags,
+ AudioSource::SYS_RESERVED_INVALID /*only needed for input*/,
+ &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
+ }
+ *config = VALUE_OR_RETURN_STATUS(
+ ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(aidlConfig, isInput));
::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
args.portConfigId = mixPortConfig.id;
const bool isOffload = isBitPositionFlagSet(
@@ -644,11 +473,11 @@
}
*outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
std::move(ret.stream), mVendorExt, this /*callbackBroker*/);
- mStreams.insert(std::pair(*outStream, aidlPatch.id));
void* cbCookie = (*outStream).get();
{
std::lock_guard l(mLock);
mCallbacks.emplace(cbCookie, Callbacks{});
+ mMapper.addStream(*outStream, mixPortConfig.id, aidlPatch.id);
}
if (streamCb) streamCb->setCookie(cbCookie);
eventCb->setCookie(cbCookie);
@@ -663,15 +492,16 @@
audio_devices_t outputDevice, const char* outputDeviceAddress,
sp<StreamInHalInterface>* inStream) {
ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
- if (!inStream || !config) {
+ TIME_CHECK();
+ if (mModule == nullptr) return NO_INIT;
+ if (inStream == nullptr || config == nullptr) {
return BAD_VALUE;
}
- TIME_CHECK();
- if (!mModule) return NO_INIT;
+ constexpr bool isInput = true;
int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
- ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
+ ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, isInput));
AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
int32_t aidlInputFlags = VALUE_OR_RETURN_STATUS(
@@ -680,10 +510,16 @@
AudioSource aidlSource = VALUE_OR_RETURN_STATUS(
::aidl::android::legacy2aidl_audio_source_t_AudioSource(source));
AudioPortConfig mixPortConfig;
- Cleanups cleanups;
AudioPatch aidlPatch;
- RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags, aidlSource,
- config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
+ Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
+ {
+ std::lock_guard l(mLock);
+ RETURN_STATUS_IF_ERROR(mMapper.prepareToOpenStream(
+ aidlHandle, aidlDevice, aidlFlags, aidlSource,
+ &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
+ }
+ *config = VALUE_OR_RETURN_STATUS(
+ ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(aidlConfig, isInput));
::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
args.portConfigId = mixPortConfig.id;
RecordTrackMetadata aidlTrackMetadata{
@@ -705,12 +541,18 @@
}
*inStream = sp<StreamInHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
std::move(ret.stream), mVendorExt, this /*micInfoProvider*/);
- mStreams.insert(std::pair(*inStream, aidlPatch.id));
+ {
+ std::lock_guard l(mLock);
+ mMapper.addStream(*inStream, mixPortConfig.id, aidlPatch.id);
+ }
cleanups.disarmAll();
return OK;
}
status_t DeviceHalAidl::supportsAudioPatches(bool* supportsPatches) {
+ if (supportsPatches == nullptr) {
+ return BAD_VALUE;
+ }
*supportsPatches = true;
return OK;
}
@@ -722,7 +564,7 @@
audio_patch_handle_t* patch) {
ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
- if (!mModule) return NO_INIT;
+ if (mModule == nullptr) return NO_INIT;
if (num_sinks > AUDIO_PATCH_PORTS_MAX || num_sources > AUDIO_PATCH_PORTS_MAX ||
sources == nullptr || sinks == nullptr || patch == nullptr) {
return BAD_VALUE;
@@ -739,7 +581,7 @@
// that the HAL module uses `int32_t` for patch IDs. The following assert ensures
// that both the framework and the HAL use the same value for "no ID":
static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
- int32_t halPatchId = static_cast<int32_t>(*patch);
+ int32_t aidlPatchId = static_cast<int32_t>(*patch);
// Upon conversion, mix port configs contain audio configuration, while
// device port configs contain device address. This data is used to find
@@ -761,68 +603,13 @@
::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
sinks[i], isInput, 0)));
}
- Cleanups cleanups;
- auto existingPatchIt = halPatchId != 0 ? mPatches.find(halPatchId): mPatches.end();
- AudioPatch aidlPatch;
- if (existingPatchIt != mPatches.end()) {
- aidlPatch = existingPatchIt->second;
- aidlPatch.sourcePortConfigIds.clear();
- aidlPatch.sinkPortConfigIds.clear();
+ Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
+ {
+ std::lock_guard l(mLock);
+ RETURN_STATUS_IF_ERROR(mMapper.createOrUpdatePatch(
+ aidlSources, aidlSinks, &aidlPatchId, &cleanups));
}
- // The IDs will be found by 'fillPortConfigs', however the original 'aidlSources' and
- // 'aidlSinks' will not be updated because 'setAudioPatch' only needs IDs. Here we log
- // the source arguments, where only the audio configuration and device specifications
- // are relevant.
- ALOGD("%s: [disregard IDs] sources: %s, sinks: %s",
- __func__, ::android::internal::ToString(aidlSources).c_str(),
- ::android::internal::ToString(aidlSinks).c_str());
- auto fillPortConfigs = [&](
- const std::vector<AudioPortConfig>& configs,
- const std::set<int32_t>& destinationPortIds,
- std::vector<int32_t>* ids, std::set<int32_t>* portIds) -> status_t {
- for (const auto& s : configs) {
- AudioPortConfig portConfig;
- bool created = false;
- RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
- s, destinationPortIds, &portConfig, &created));
- if (created) {
- cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, portConfig.id);
- }
- ids->push_back(portConfig.id);
- if (portIds != nullptr) {
- portIds->insert(portConfig.portId);
- }
- }
- return OK;
- };
- // When looking up port configs, the destinationPortId is only used for mix ports.
- // Thus, we process device port configs first, and look up the destination port ID from them.
- bool sourceIsDevice = std::any_of(aidlSources.begin(), aidlSources.end(),
- [](const auto& config) { return config.ext.getTag() == AudioPortExt::device; });
- const std::vector<AudioPortConfig>& devicePortConfigs =
- sourceIsDevice ? aidlSources : aidlSinks;
- std::vector<int32_t>* devicePortConfigIds =
- sourceIsDevice ? &aidlPatch.sourcePortConfigIds : &aidlPatch.sinkPortConfigIds;
- const std::vector<AudioPortConfig>& mixPortConfigs =
- sourceIsDevice ? aidlSinks : aidlSources;
- std::vector<int32_t>* mixPortConfigIds =
- sourceIsDevice ? &aidlPatch.sinkPortConfigIds : &aidlPatch.sourcePortConfigIds;
- std::set<int32_t> devicePortIds;
- RETURN_STATUS_IF_ERROR(fillPortConfigs(
- devicePortConfigs, std::set<int32_t>(), devicePortConfigIds, &devicePortIds));
- RETURN_STATUS_IF_ERROR(fillPortConfigs(
- mixPortConfigs, devicePortIds, mixPortConfigIds, nullptr));
- if (existingPatchIt != mPatches.end()) {
- RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
- mModule->setAudioPatch(aidlPatch, &aidlPatch)));
- existingPatchIt->second = aidlPatch;
- } else {
- bool created = false;
- RETURN_STATUS_IF_ERROR(findOrCreatePatch(aidlPatch, &aidlPatch, &created));
- // Since no cleanup of the patch is needed, 'created' is ignored.
- halPatchId = aidlPatch.id;
- *patch = static_cast<audio_patch_handle_t>(halPatchId);
- }
+ *patch = static_cast<audio_patch_handle_t>(aidlPatchId);
cleanups.disarmAll();
return OK;
}
@@ -830,26 +617,17 @@
status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
- if (!mModule) return NO_INIT;
+ if (mModule == nullptr) return NO_INIT;
static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
if (patch == AUDIO_PATCH_HANDLE_NONE) {
return BAD_VALUE;
}
- int32_t halPatchId = static_cast<int32_t>(patch);
- auto patchIt = mPatches.find(halPatchId);
- if (patchIt == mPatches.end()) {
- ALOGE("%s: patch with id %d not found", __func__, halPatchId);
- return BAD_VALUE;
- }
- RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->resetAudioPatch(halPatchId)));
- mPatches.erase(patchIt);
+ std::lock_guard l(mLock);
+ RETURN_STATUS_IF_ERROR(mMapper.releaseAudioPatch(static_cast<int32_t>(patch)));
return OK;
}
status_t DeviceHalAidl::getAudioPort(struct audio_port* port) {
- ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
- TIME_CHECK();
- if (!mModule) return NO_INIT;
if (port == nullptr) {
return BAD_VALUE;
}
@@ -862,7 +640,7 @@
status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port) {
ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
- if (!mModule) return NO_INIT;
+ if (mModule == nullptr) return NO_INIT;
if (port == nullptr) {
return BAD_VALUE;
}
@@ -878,14 +656,11 @@
const auto& matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
// It seems that we don't have to call HAL since all valid ports have been added either
// during initialization, or while handling connection of an external device.
- auto portsIt = findPort(matchDevice);
- if (portsIt == mPorts.end()) {
- ALOGE("%s: device port for device %s is not found in the module %s",
- __func__, matchDevice.toString().c_str(), mInstance.c_str());
- return BAD_VALUE;
- }
const int32_t fwkId = aidlPort.id;
- aidlPort = portsIt->second;
+ {
+ std::lock_guard l(mLock);
+ RETURN_STATUS_IF_ERROR(mMapper.getAudioPortCached(matchDevice, &aidlPort));
+ }
aidlPort.id = fwkId;
*port = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
aidlPort, isInput));
@@ -895,34 +670,30 @@
status_t DeviceHalAidl::getAudioMixPort(const struct audio_port_v7 *devicePort,
struct audio_port_v7 *mixPort) {
ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
- if (devicePort->type != AUDIO_PORT_TYPE_DEVICE) {
- return BAD_VALUE;
- }
- if (mixPort->type != AUDIO_PORT_TYPE_MIX) {
+ TIME_CHECK();
+ if (mModule == nullptr) return NO_INIT;
+ if (devicePort == nullptr || mixPort == nullptr ||
+ devicePort->type != AUDIO_PORT_TYPE_DEVICE || mixPort->type != AUDIO_PORT_TYPE_MIX) {
return BAD_VALUE;
}
const int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(mixPort->ext.mix.handle));
- auto it = findPortConfig(std::nullopt /*config*/, std::nullopt/*flags*/, aidlHandle);
- if (it == mPortConfigs.end()) {
- ALOGE("%s, cannot find mix port config for handle=%u", __func__, aidlHandle);
- return BAD_VALUE;
- }
AudioPort port;
- if (status_t status = getAudioPort(it->second.portId, &port); status != NO_ERROR) {
- return status;
+ {
+ std::lock_guard l(mLock);
+ RETURN_STATUS_IF_ERROR(mMapper.getAudioMixPort(aidlHandle, &port));
}
const bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
mixPort->role, mixPort->type)) == ::aidl::android::AudioPortDirection::INPUT;
*mixPort = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
port, isInput));
- return NO_ERROR;
+ return OK;
}
status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config) {
ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
- if (!mModule) return NO_INIT;
+ if (mModule == nullptr) return NO_INIT;
if (config == nullptr) {
return BAD_VALUE;
}
@@ -932,13 +703,16 @@
::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
*config, isInput, 0 /*portId*/));
AudioPortConfig portConfig;
- bool created = false;
- RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
- requestedPortConfig, std::set<int32_t>(), &portConfig, &created));
- return OK;
+ std::lock_guard l(mLock);
+ return mMapper.findOrCreatePortConfig(
+ requestedPortConfig, std::set<int32_t>(), &portConfig);
}
MicrophoneInfoProvider::Info const* DeviceHalAidl::getMicrophoneInfo() {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ TIME_CHECK();
+ if (!mModule) return {};
+ std::lock_guard l(mLock);
if (mMicrophones.status == Microphones::Status::UNKNOWN) {
TIME_CHECK();
std::vector<MicrophoneInfo> aidlInfo;
@@ -961,11 +735,12 @@
status_t DeviceHalAidl::getMicrophones(
std::vector<audio_microphone_characteristic_t>* microphones) {
- if (!microphones) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ TIME_CHECK();
+ if (mModule == nullptr) return NO_INIT;
+ if (microphones == nullptr) {
return BAD_VALUE;
}
- TIME_CHECK();
- if (!mModule) return NO_INIT;
auto staticInfo = getMicrophoneInfo();
if (!staticInfo) return INVALID_OPERATION;
std::vector<MicrophoneDynamicInfo> emptyDynamicInfo;
@@ -982,9 +757,10 @@
status_t DeviceHalAidl::addDeviceEffect(
const struct audio_port_config *device, sp<EffectHalInterface> effect) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
- if (!mModule) return NO_INIT;
- if (!effect) {
+ if (mModule == nullptr) return NO_INIT;
+ if (device == nullptr || effect == nullptr) {
return BAD_VALUE;
}
bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
@@ -998,12 +774,11 @@
return BAD_VALUE;
}
AudioPortConfig devicePortConfig;
- bool created;
- RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
- requestedPortConfig, {} /*destinationPortIds*/, &devicePortConfig, &created));
- Cleanups cleanups;
- if (created) {
- cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
+ Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
+ {
+ std::lock_guard l(mLock);
+ RETURN_STATUS_IF_ERROR(mMapper.findOrCreatePortConfig(
+ requestedPortConfig, {} /*destinationPortIds*/, &devicePortConfig, &cleanups));
}
auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->addDeviceEffect(
@@ -1013,9 +788,10 @@
}
status_t DeviceHalAidl::removeDeviceEffect(
const struct audio_port_config *device, sp<EffectHalInterface> effect) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
- if (!mModule) return NO_INIT;
- if (!effect) {
+ if (mModule == nullptr) return NO_INIT;
+ if (device == nullptr || effect == nullptr) {
return BAD_VALUE;
}
bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
@@ -1028,22 +804,24 @@
__func__, requestedPortConfig.toString().c_str());
return BAD_VALUE;
}
- auto existingPortConfigIt = findPortConfig(
- requestedPortConfig.ext.get<AudioPortExt::Tag::device>().device);
- if (existingPortConfigIt == mPortConfigs.end()) {
- ALOGE("%s: could not find a configured device port for the config %s",
- __func__, requestedPortConfig.toString().c_str());
- return BAD_VALUE;
+ AudioPortConfig devicePortConfig;
+ {
+ std::lock_guard l(mLock);
+ RETURN_STATUS_IF_ERROR(mMapper.findPortConfig(
+ requestedPortConfig.ext.get<AudioPortExt::Tag::device>().device,
+ &devicePortConfig));
}
auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
return statusTFromBinderStatus(mModule->removeDeviceEffect(
- existingPortConfigIt->first, aidlEffect->getIEffect()));
+ devicePortConfig.id, aidlEffect->getIEffect()));
}
status_t DeviceHalAidl::getMmapPolicyInfos(
media::audio::common::AudioMMapPolicyType policyType,
std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
+ if (mModule == nullptr) return NO_INIT;
AudioMMapPolicyType mmapPolicyType = VALUE_OR_RETURN_STATUS(
cpp2ndk_AudioMMapPolicyType(policyType));
@@ -1061,7 +839,9 @@
}
int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
+ if (mModule == nullptr) return NO_INIT;
int32_t mixerBurstCount = 0;
if (mModule->getAAudioMixerBurstCount(&mixerBurstCount).isOk()) {
return mixerBurstCount;
@@ -1070,7 +850,9 @@
}
int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
+ if (mModule == nullptr) return NO_INIT;
int32_t hardwareBurstMinUsec = 0;
if (mModule->getAAudioHardwareBurstMinUsec(&hardwareBurstMinUsec).isOk()) {
return hardwareBurstMinUsec;
@@ -1079,8 +861,9 @@
}
error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
- if (!mModule) return NO_INIT;
+ if (mModule == nullptr) return NO_INIT;
int32_t aidlHwAvSync;
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->generateHwAvSyncId(&aidlHwAvSync)));
return VALUE_OR_RETURN_STATUS(
@@ -1089,13 +872,14 @@
status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
TIME_CHECK();
- if (!mModule) return NO_INIT;
+ if (mModule == nullptr) return NO_INIT;
return mModule->dump(fd, Args(args).args(), args.size());
}
status_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
- if (!mModule) return NO_INIT;
+ if (mModule == nullptr) return NO_INIT;
if (supports == nullptr) {
return BAD_VALUE;
}
@@ -1104,21 +888,16 @@
status_t DeviceHalAidl::getSoundDoseInterface(const std::string& module,
::ndk::SpAIBinder* soundDoseBinder) {
- TIME_CHECK();
- if (!mModule) return NO_INIT;
+ if (soundDoseBinder == nullptr) {
+ return BAD_VALUE;
+ }
if (mSoundDose == nullptr) {
- ndk::ScopedAStatus status = mModule->getSoundDose(&mSoundDose);
- if (!status.isOk()) {
- ALOGE("%s failed to return the sound dose interface for module %s: %s",
- __func__,
- module.c_str(),
- status.getDescription().c_str());
- return BAD_VALUE;
- }
+ ALOGE("%s failed to retrieve the sound dose interface for module %s",
+ __func__, module.c_str());
+ return BAD_VALUE;
}
*soundDoseBinder = mSoundDose->asBinder();
ALOGI("%s using audio AIDL HAL sound dose interface", __func__);
-
return OK;
}
@@ -1126,29 +905,32 @@
// There is not AIDL API defined for `prepareToDisconnectExternalDevice`.
// Call `setConnectedState` instead.
// TODO(b/279824103): call prepareToDisconnectExternalDevice when it is added.
- if (const status_t status = setConnectedState(port, false /*connected*/); status == NO_ERROR) {
- mDeviceDisconnectionNotified.insert(port->id);
- }
+ RETURN_STATUS_IF_ERROR(setConnectedState(port, false /*connected*/));
+ std::lock_guard l(mLock);
+ mDeviceDisconnectionNotified.insert(port->id);
// Return that there was no error as otherwise the disconnection procedure will not be
- // considered complete for upper layers, and 'setConnectedState' will not be called again.
- return NO_ERROR;
+ // considered complete for upper layers, and 'setConnectedState' will not be called again
+ return OK;
}
status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
- if (!mModule) return NO_INIT;
+ if (mModule == nullptr) return NO_INIT;
if (port == nullptr) {
return BAD_VALUE;
}
- if (!connected && mDeviceDisconnectionNotified.erase(port->id) > 0) {
- // For device disconnection, APM will first call `prepareToDisconnectExternalDevice`
- // and then call `setConnectedState`. However, there is no API for
- // `prepareToDisconnectExternalDevice` yet. In that case, `setConnectedState` will be
- // called when calling `prepareToDisconnectExternalDevice`. Do not call to the HAL if
- // previous call is successful. Also remove the cache here to avoid a large cache after
- // a long run.
- return NO_ERROR;
+ if (!connected) {
+ std::lock_guard l(mLock);
+ if (mDeviceDisconnectionNotified.erase(port->id) > 0) {
+ // For device disconnection, APM will first call `prepareToDisconnectExternalDevice`
+ // and then call `setConnectedState`. However, there is no API for
+ // `prepareToDisconnectExternalDevice` yet. In that case, `setConnectedState` will be
+ // called when calling `prepareToDisconnectExternalDevice`. Do not call to the HAL if
+ // previous call is successful. Also remove the cache here to avoid a large cache after
+ // a long run.
+ return OK;
+ }
}
bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
::aidl::android::AudioPortDirection::INPUT;
@@ -1159,100 +941,17 @@
__func__, mInstance.c_str(), aidlPort.toString().c_str());
return BAD_VALUE;
}
- if (connected) {
- AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
- std::optional<AudioPort> templatePort;
- auto erasePortAfterConnectionIt = mPorts.end();
- // Connection of remote submix out with address "0" is a special case. Since there is
- // already an "augmented template" port with this address in mPorts, we need to replace
- // it with a connected port.
- // Connection of remote submix outs with any other address is done as usual except that
- // the template port is in `mRemoteSubmixOut`.
- if (mRemoteSubmixOut.has_value() &&
- matchDevice.type.type == AudioDeviceType::OUT_SUBMIX) {
- if (matchDevice.address == AudioDeviceAddress::make<AudioDeviceAddress::id>(
- AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS)) {
- erasePortAfterConnectionIt = findPort(matchDevice);
- }
- templatePort = mRemoteSubmixOut;
- } else if (mRemoteSubmixIn.has_value() &&
- matchDevice.type.type == AudioDeviceType::IN_SUBMIX) {
- templatePort = mRemoteSubmixIn;
- } else {
- // Reset the device address to find the "template" port.
- matchDevice.address = AudioDeviceAddress::make<AudioDeviceAddress::id>();
- }
- if (!templatePort.has_value()) {
- auto portsIt = findPort(matchDevice);
- if (portsIt == mPorts.end()) {
- // Since 'setConnectedState' is called for all modules, it is normal when the device
- // port not found in every one of them.
- return BAD_VALUE;
- } else {
- ALOGD("%s: device port for device %s found in the module %s",
- __func__, matchDevice.toString().c_str(), mInstance.c_str());
- }
- templatePort = portsIt->second;
- }
- resetUnusedPatchesAndPortConfigs();
-
- // Use the ID of the "template" port, use all the information from the provided port.
- aidlPort.id = templatePort->id;
- AudioPort connectedPort;
- RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
- aidlPort, &connectedPort)));
- const auto [it, inserted] = mPorts.insert(std::make_pair(connectedPort.id, connectedPort));
- LOG_ALWAYS_FATAL_IF(!inserted,
- "%s: module %s, duplicate port ID received from HAL: %s, existing port: %s",
- __func__, mInstance.c_str(), connectedPort.toString().c_str(),
- it->second.toString().c_str());
- mConnectedPorts[connectedPort.id] = false;
- if (erasePortAfterConnectionIt != mPorts.end()) {
- mPorts.erase(erasePortAfterConnectionIt);
- }
- } else { // !connected
- AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
- auto portsIt = findPort(matchDevice);
- if (portsIt == mPorts.end()) {
- // Since 'setConnectedState' is called for all modules, it is normal when the device
- // port not found in every one of them.
- return BAD_VALUE;
- } else {
- ALOGD("%s: device port for device %s found in the module %s",
- __func__, matchDevice.toString().c_str(), mInstance.c_str());
- }
- resetUnusedPatchesAndPortConfigs();
-
- // Disconnection of remote submix out with address "0" is a special case. We need to replace
- // the connected port entry with the "augmented template".
- const int32_t portId = portsIt->second.id;
- if (mRemoteSubmixOut.has_value() && matchDevice.type.type == AudioDeviceType::OUT_SUBMIX &&
- matchDevice.address == AudioDeviceAddress::make<AudioDeviceAddress::id>(
- AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS)) {
- mDisconnectedPortReplacement = std::make_pair(portId, *mRemoteSubmixOut);
- auto& port = mDisconnectedPortReplacement.second;
- port.ext.get<AudioPortExt::Tag::device>().device = matchDevice;
- port.profiles = portsIt->second.profiles;
- }
- // Streams are closed by AudioFlinger independently from device disconnections.
- // It is possible that the stream has not been closed yet.
- if (!isPortHeldByAStream(portId)) {
- RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
- mModule->disconnectExternalDevice(portId)));
- eraseConnectedPort(portId);
- } else {
- ALOGD("%s: since device port ID %d is used by a stream, "
- "external device disconnection postponed", __func__, portId);
- mConnectedPorts[portId] = true;
- }
- }
- return updateRoutes();
+ std::lock_guard l(mLock);
+ return mMapper.setDevicePortConnectedState(aidlPort, connected);
}
status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
TIME_CHECK();
- if (!mModule) return NO_INIT;
- resetUnusedPatchesAndPortConfigs();
+ if (mModule == nullptr) return NO_INIT;
+ {
+ std::lock_guard l(mLock);
+ mMapper.resetUnusedPatchesAndPortConfigs();
+ }
ModuleDebug debug{ .simulateDeviceConnections = enabled };
status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
// This is important to log as it affects HAL behavior.
@@ -1264,65 +963,8 @@
return status;
}
-bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
- if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
- return p.ext.get<AudioPortExt::Tag::device>().device == device;
-}
-
-bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPortConfig& p) {
- if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
- if (device.type.type == AudioDeviceType::IN_DEFAULT) {
- return p.portId == mDefaultInputPortId;
- } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
- return p.portId == mDefaultOutputPortId;
- }
- return p.ext.get<AudioPortExt::Tag::device>().device == device;
-}
-
-status_t DeviceHalAidl::createOrUpdatePortConfig(
- const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result, bool* created) {
- TIME_CHECK();
- AudioPortConfig appliedPortConfig;
- bool applied = false;
- RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
- requestedPortConfig, &appliedPortConfig, &applied)));
- if (!applied) {
- RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
- appliedPortConfig, &appliedPortConfig, &applied)));
- if (!applied) {
- ALOGE("%s: module %s did not apply suggested config %s",
- __func__, mInstance.c_str(), appliedPortConfig.toString().c_str());
- return NO_INIT;
- }
- }
-
- int32_t id = appliedPortConfig.id;
- if (requestedPortConfig.id != 0 && requestedPortConfig.id != id) {
- LOG_ALWAYS_FATAL("%s: requested port config id %d changed to %d", __func__,
- requestedPortConfig.id, id);
- }
-
- auto [it, inserted] = mPortConfigs.insert_or_assign(std::move(id),
- std::move(appliedPortConfig));
- *result = it;
- *created = inserted;
- return OK;
-}
-
-void DeviceHalAidl::eraseConnectedPort(int32_t portId) {
- mPorts.erase(portId);
- mConnectedPorts.erase(portId);
- if (mDisconnectedPortReplacement.first == portId) {
- const auto& port = mDisconnectedPortReplacement.second;
- mPorts.insert(std::make_pair(port.id, port));
- ALOGD("%s: disconnected port replacement: %s", __func__, port.toString().c_str());
- mDisconnectedPortReplacement = std::pair<int32_t, AudioPort>();
- }
-}
-
status_t DeviceHalAidl::filterAndRetrieveBtA2dpParameters(
AudioParameter &keys, AudioParameter *result) {
- TIME_CHECK();
if (String8 key = String8(AudioParameter::keyReconfigA2dpSupported); keys.containsKey(key)) {
keys.remove(key);
if (mBluetoothA2dp != nullptr) {
@@ -1339,7 +981,6 @@
}
status_t DeviceHalAidl::filterAndUpdateBtA2dpParameters(AudioParameter ¶meters) {
- TIME_CHECK();
std::optional<bool> a2dpEnabled;
std::optional<std::vector<VendorParameter>> reconfigureOffload;
(void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
@@ -1381,7 +1022,6 @@
}
status_t DeviceHalAidl::filterAndUpdateBtHfpParameters(AudioParameter ¶meters) {
- TIME_CHECK();
IBluetooth::HfpConfig hfpConfig;
(void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
parameters, String8(AudioParameter::keyBtHfpEnable),
@@ -1420,7 +1060,6 @@
}
status_t DeviceHalAidl::filterAndUpdateBtLeParameters(AudioParameter ¶meters) {
- TIME_CHECK();
std::optional<bool> leEnabled;
(void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
parameters, String8(AudioParameter::keyBtLeSuspended),
@@ -1443,7 +1082,6 @@
}
status_t DeviceHalAidl::filterAndUpdateBtScoParameters(AudioParameter ¶meters) {
- TIME_CHECK();
IBluetooth::ScoConfig scoConfig;
(void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
parameters, String8(AudioParameter::keyBtSco),
@@ -1501,7 +1139,6 @@
}
status_t DeviceHalAidl::filterAndUpdateScreenParameters(AudioParameter ¶meters) {
- TIME_CHECK();
(void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
parameters, String8(AudioParameter::keyScreenState),
[&](const String8& onOrOff) -> status_t {
@@ -1539,7 +1176,6 @@
}
status_t DeviceHalAidl::filterAndUpdateTelephonyParameters(AudioParameter ¶meters) {
- TIME_CHECK();
using TtyMode = ITelephony::TelecomConfig::TtyMode;
ITelephony::TelecomConfig telConfig;
(void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
@@ -1584,443 +1220,6 @@
return OK;
}
-status_t DeviceHalAidl::findOrCreatePatch(
- const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
- std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
- requestedPatch.sourcePortConfigIds.end());
- std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
- requestedPatch.sinkPortConfigIds.end());
- return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
-}
-
-status_t DeviceHalAidl::findOrCreatePatch(
- const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
- AudioPatch* patch, bool* created) {
- auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
- if (patchIt == mPatches.end()) {
- TIME_CHECK();
- AudioPatch requestedPatch, appliedPatch;
- requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
- sourcePortConfigIds.begin(), sourcePortConfigIds.end());
- requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
- sinkPortConfigIds.begin(), sinkPortConfigIds.end());
- RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
- requestedPatch, &appliedPatch)));
- patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
- *created = true;
- } else {
- *created = false;
- }
- *patch = patchIt->second;
- return OK;
-}
-
-status_t DeviceHalAidl::findOrCreatePortConfig(const AudioDevice& device, const AudioConfig* config,
- AudioPortConfig* portConfig, bool* created) {
- auto portConfigIt = findPortConfig(device);
- if (portConfigIt == mPortConfigs.end()) {
- auto portsIt = findPort(device);
- if (portsIt == mPorts.end()) {
- ALOGE("%s: device port for device %s is not found in the module %s",
- __func__, device.toString().c_str(), mInstance.c_str());
- return BAD_VALUE;
- }
- AudioPortConfig requestedPortConfig;
- requestedPortConfig.portId = portsIt->first;
- if (config != nullptr) {
- setPortConfigFromConfig(&requestedPortConfig, *config);
- }
- RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
- created));
- } else {
- *created = false;
- }
- *portConfig = portConfigIt->second;
- return OK;
-}
-
-status_t DeviceHalAidl::findOrCreatePortConfig(
- const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
- AudioSource source, const std::set<int32_t>& destinationPortIds,
- AudioPortConfig* portConfig, bool* created) {
- // These flags get removed one by one in this order when retrying port finding.
- static const std::vector<AudioInputFlags> kOptionalInputFlags{
- AudioInputFlags::FAST, AudioInputFlags::RAW };
- auto portConfigIt = findPortConfig(config, flags, ioHandle);
- if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
- auto optionalInputFlagsIt = kOptionalInputFlags.begin();
- AudioIoFlags matchFlags = flags.value();
- auto portsIt = findPort(config, matchFlags, destinationPortIds);
- while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
- && optionalInputFlagsIt != kOptionalInputFlags.end()) {
- if (!isBitPositionFlagSet(
- matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
- ++optionalInputFlagsIt;
- continue;
- }
- matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
- ~makeBitPositionFlagMask(*optionalInputFlagsIt++));
- portsIt = findPort(config, matchFlags, destinationPortIds);
- ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
- "retried with flags %s", __func__, config.toString().c_str(),
- flags.value().toString().c_str(), mInstance.c_str(),
- matchFlags.toString().c_str());
- }
- if (portsIt == mPorts.end()) {
- ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
- __func__, config.toString().c_str(), matchFlags.toString().c_str(),
- mInstance.c_str());
- return BAD_VALUE;
- }
- AudioPortConfig requestedPortConfig;
- requestedPortConfig.portId = portsIt->first;
- setPortConfigFromConfig(&requestedPortConfig, config);
- requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
- if (matchFlags.getTag() == AudioIoFlags::Tag::input
- && source != AudioSource::SYS_RESERVED_INVALID) {
- requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
- AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
- }
- RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
- created));
- } else if (portConfigIt == mPortConfigs.end() && !flags.has_value()) {
- ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
- "and was not created as flags are not specified",
- __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
- return BAD_VALUE;
- } else {
- AudioPortConfig requestedPortConfig = portConfigIt->second;
- if (requestedPortConfig.ext.getTag() == AudioPortExt::Tag::mix) {
- AudioPortMixExt& mixExt = requestedPortConfig.ext.get<AudioPortExt::Tag::mix>();
- if (mixExt.usecase.getTag() == AudioPortMixExtUseCase::Tag::source &&
- source != AudioSource::SYS_RESERVED_INVALID) {
- mixExt.usecase.get<AudioPortMixExtUseCase::Tag::source>() = source;
- }
- }
-
- if (requestedPortConfig != portConfigIt->second) {
- RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
- created));
- } else {
- *created = false;
- }
- }
- *portConfig = portConfigIt->second;
- return OK;
-}
-
-status_t DeviceHalAidl::findOrCreatePortConfig(
- const AudioPortConfig& requestedPortConfig, const std::set<int32_t>& destinationPortIds,
- AudioPortConfig* portConfig, bool* created) {
- using Tag = AudioPortExt::Tag;
- if (requestedPortConfig.ext.getTag() == Tag::mix) {
- if (const auto& p = requestedPortConfig;
- !p.sampleRate.has_value() || !p.channelMask.has_value() ||
- !p.format.has_value()) {
- ALOGW("%s: provided mix port config is not fully specified: %s",
- __func__, p.toString().c_str());
- return BAD_VALUE;
- }
- AudioConfig config;
- setConfigFromPortConfig(&config, requestedPortConfig);
- AudioSource source = requestedPortConfig.ext.get<Tag::mix>().usecase.getTag() ==
- AudioPortMixExtUseCase::Tag::source ?
- requestedPortConfig.ext.get<Tag::mix>().usecase.
- get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
- return findOrCreatePortConfig(config, requestedPortConfig.flags,
- requestedPortConfig.ext.get<Tag::mix>().handle, source, destinationPortIds,
- portConfig, created);
- } else if (requestedPortConfig.ext.getTag() == Tag::device) {
- return findOrCreatePortConfig(
- requestedPortConfig.ext.get<Tag::device>().device, nullptr /*config*/,
- portConfig, created);
- }
- ALOGW("%s: unsupported audio port config: %s",
- __func__, requestedPortConfig.toString().c_str());
- return BAD_VALUE;
-}
-
-DeviceHalAidl::Patches::iterator DeviceHalAidl::findPatch(
- const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
- return std::find_if(mPatches.begin(), mPatches.end(),
- [&](const auto& pair) {
- const auto& p = pair.second;
- std::set<int32_t> patchSrcs(
- p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
- std::set<int32_t> patchSinks(
- p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
- return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
-}
-
-DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(const AudioDevice& device) {
- if (device.type.type == AudioDeviceType::IN_DEFAULT) {
- return mPorts.find(mDefaultInputPortId);
- } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
- return mPorts.find(mDefaultOutputPortId);
- }
- if (device.address.getTag() != AudioDeviceAddress::id ||
- !device.address.get<AudioDeviceAddress::id>().empty()) {
- return std::find_if(mPorts.begin(), mPorts.end(),
- [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
- }
- // For connection w/o an address, two ports can be found: the template port,
- // and a connected port (if exists). Make sure we return the connected port.
- DeviceHalAidl::Ports::iterator portIt = mPorts.end();
- for (auto it = mPorts.begin(); it != mPorts.end(); ++it) {
- if (audioDeviceMatches(device, it->second)) {
- if (mConnectedPorts.find(it->first) != mConnectedPorts.end()) {
- return it;
- } else {
- // Will return 'it' if there is no connected port.
- portIt = it;
- }
- }
- }
- return portIt;
-}
-
-DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
- const AudioConfig& config, const AudioIoFlags& flags,
- const std::set<int32_t>& destinationPortIds) {
- auto belongsToProfile = [&config](const AudioProfile& prof) {
- return (isDefaultAudioFormat(config.base.format) || prof.format == config.base.format) &&
- (config.base.channelMask.getTag() == AudioChannelLayout::none ||
- std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
- config.base.channelMask) != prof.channelMasks.end()) &&
- (config.base.sampleRate == 0 ||
- std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
- config.base.sampleRate) != prof.sampleRates.end());
- };
- static const std::vector<AudioOutputFlags> kOptionalOutputFlags{AudioOutputFlags::BIT_PERFECT};
- int optionalFlags = 0;
- auto flagMatches = [&flags, &optionalFlags](const AudioIoFlags& portFlags) {
- // Ports should be able to match if the optional flags are not requested.
- return portFlags == flags ||
- (portFlags.getTag() == AudioIoFlags::Tag::output &&
- AudioIoFlags::make<AudioIoFlags::Tag::output>(
- portFlags.get<AudioIoFlags::Tag::output>() &
- ~optionalFlags) == flags);
- };
- auto matcher = [&](const auto& pair) {
- const auto& p = pair.second;
- return p.ext.getTag() == AudioPortExt::Tag::mix &&
- flagMatches(p.flags) &&
- (destinationPortIds.empty() ||
- std::any_of(destinationPortIds.begin(), destinationPortIds.end(),
- [&](const int32_t destId) { return mRoutingMatrix.count(
- std::make_pair(p.id, destId)) != 0; })) &&
- (p.profiles.empty() ||
- std::find_if(p.profiles.begin(), p.profiles.end(), belongsToProfile) !=
- p.profiles.end()); };
- auto result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
- if (result == mPorts.end() && flags.getTag() == AudioIoFlags::Tag::output) {
- auto optionalOutputFlagsIt = kOptionalOutputFlags.begin();
- while (result == mPorts.end() && optionalOutputFlagsIt != kOptionalOutputFlags.end()) {
- if (isBitPositionFlagSet(
- flags.get<AudioIoFlags::Tag::output>(), *optionalOutputFlagsIt)) {
- // If the flag is set by the request, it must be matched.
- ++optionalOutputFlagsIt;
- continue;
- }
- optionalFlags |= makeBitPositionFlagMask(*optionalOutputFlagsIt++);
- result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
- ALOGI("%s: port for config %s, flags %s was not found in the module %s, "
- "retried with excluding optional flags %#x", __func__, config.toString().c_str(),
- flags.toString().c_str(), mInstance.c_str(), optionalFlags);
- }
- }
- return result;
-}
-
-DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(const AudioDevice& device) {
- return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
- [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
-}
-
-DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
- const std::optional<AudioConfig>& config,
- const std::optional<AudioIoFlags>& flags,
- int32_t ioHandle) {
- using Tag = AudioPortExt::Tag;
- return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
- [&](const auto& pair) {
- const auto& p = pair.second;
- LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
- (!p.sampleRate.has_value() || !p.channelMask.has_value() ||
- !p.format.has_value() || !p.flags.has_value()),
- "%s: stored mix port config is not fully specified: %s",
- __func__, p.toString().c_str());
- return p.ext.getTag() == Tag::mix &&
- (!config.has_value() ||
- isConfigEqualToPortConfig(config.value(), p)) &&
- (!flags.has_value() || p.flags.value() == flags.value()) &&
- p.ext.template get<Tag::mix>().handle == ioHandle; });
-}
-
-bool DeviceHalAidl::isPortHeldByAStream(int32_t portId) {
- // It is assumed that mStreams has already been cleaned up.
- for (const auto& streamPair : mStreams) {
- int32_t patchId = streamPair.second;
- auto patchIt = mPatches.find(patchId);
- if (patchIt == mPatches.end()) continue;
- for (int32_t id : patchIt->second.sourcePortConfigIds) {
- auto portConfigIt = mPortConfigs.find(id);
- if (portConfigIt != mPortConfigs.end() && portConfigIt->second.portId == portId) {
- return true;
- }
- }
- for (int32_t id : patchIt->second.sinkPortConfigIds) {
- auto portConfigIt = mPortConfigs.find(id);
- if (portConfigIt != mPortConfigs.end() && portConfigIt->second.portId == portId) {
- return true;
- }
- }
- }
- return false;
-}
-
-void DeviceHalAidl::resetPatch(int32_t patchId) {
- if (auto it = mPatches.find(patchId); it != mPatches.end()) {
- mPatches.erase(it);
- TIME_CHECK();
- if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
- ALOGE("%s: error while resetting patch %d: %s",
- __func__, patchId, status.getDescription().c_str());
- }
- return;
- }
- ALOGE("%s: patch id %d not found", __func__, patchId);
-}
-
-void DeviceHalAidl::resetPortConfig(int32_t portConfigId) {
- if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
- mPortConfigs.erase(it);
- TIME_CHECK();
- if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
- !status.isOk()) {
- ALOGE("%s: error while resetting port config %d: %s",
- __func__, portConfigId, status.getDescription().c_str());
- }
- return;
- }
- ALOGE("%s: port config id %d not found", __func__, portConfigId);
-}
-
-void DeviceHalAidl::resetUnusedPatches() {
- // Since patches can be created independently of streams via 'createAudioPatch',
- // here we only clean up patches for released streams.
- for (auto it = mStreams.begin(); it != mStreams.end(); ) {
- if (auto streamSp = it->first.promote(); streamSp) {
- ++it;
- } else {
- resetPatch(it->second);
- it = mStreams.erase(it);
- }
- }
-}
-
-void DeviceHalAidl::resetUnusedPatchesAndPortConfigs() {
- resetUnusedPatches();
- resetUnusedPortConfigs();
-}
-
-void DeviceHalAidl::resetUnusedPortConfigs() {
- // The assumption is that port configs are used to create patches
- // (or to open streams, but that involves creation of patches, too). Thus,
- // orphaned port configs can and should be reset.
- std::map<int32_t, int32_t /*portID*/> portConfigIds;
- std::transform(mPortConfigs.begin(), mPortConfigs.end(),
- std::inserter(portConfigIds, portConfigIds.end()),
- [](const auto& pcPair) { return std::make_pair(pcPair.first, pcPair.second.portId); });
- for (const auto& p : mPatches) {
- for (int32_t id : p.second.sourcePortConfigIds) portConfigIds.erase(id);
- for (int32_t id : p.second.sinkPortConfigIds) portConfigIds.erase(id);
- }
- for (int32_t id : mInitialPortConfigIds) {
- portConfigIds.erase(id);
- }
- std::set<int32_t> retryDeviceDisconnection;
- for (const auto& portConfigAndIdPair : portConfigIds) {
- resetPortConfig(portConfigAndIdPair.first);
- if (const auto it = mConnectedPorts.find(portConfigAndIdPair.second);
- it != mConnectedPorts.end() && it->second) {
- retryDeviceDisconnection.insert(portConfigAndIdPair.second);
- }
- }
- for (int32_t portId : retryDeviceDisconnection) {
- if (!isPortHeldByAStream(portId)) {
- TIME_CHECK();
- if (auto status = mModule->disconnectExternalDevice(portId); status.isOk()) {
- eraseConnectedPort(portId);
- ALOGD("%s: executed postponed external device disconnection for port ID %d",
- __func__, portId);
- }
- }
- }
- if (!retryDeviceDisconnection.empty()) {
- updateRoutes();
- }
-}
-
-status_t DeviceHalAidl::updateRoutes() {
- TIME_CHECK();
- RETURN_STATUS_IF_ERROR(
- statusTFromBinderStatus(mModule->getAudioRoutes(&mRoutes)));
- ALOGW_IF(mRoutes.empty(), "%s: module %s returned an empty list of audio routes",
- __func__, mInstance.c_str());
- if (mRemoteSubmixIn.has_value()) {
- // Remove mentions of the template remote submix input from routes.
- int32_t rSubmixInId = mRemoteSubmixIn->id;
- // Remove mentions of the template remote submix out only if it is not in mPorts
- // (that means there is a connected port in mPorts).
- int32_t rSubmixOutId = mPorts.find(mRemoteSubmixOut->id) == mPorts.end() ?
- mRemoteSubmixOut->id : -1;
- for (auto it = mRoutes.begin(); it != mRoutes.end();) {
- auto& route = *it;
- if (route.sinkPortId == rSubmixOutId) {
- it = mRoutes.erase(it);
- continue;
- }
- if (auto sourceIt = std::find(route.sourcePortIds.begin(), route.sourcePortIds.end(),
- rSubmixInId); sourceIt != route.sourcePortIds.end()) {
- route.sourcePortIds.erase(sourceIt);
- if (route.sourcePortIds.empty()) {
- it = mRoutes.erase(it);
- continue;
- }
- }
- ++it;
- }
- }
- mRoutingMatrix.clear();
- for (const auto& r : mRoutes) {
- for (auto portId : r.sourcePortIds) {
- mRoutingMatrix.emplace(r.sinkPortId, portId);
- mRoutingMatrix.emplace(portId, r.sinkPortId);
- }
- }
- return OK;
-}
-
-status_t DeviceHalAidl::getAudioPort(int32_t portId, AudioPort* port) {
- ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
- TIME_CHECK();
- if (!mModule) {
- return NO_INIT;
- }
- const status_t status = statusTFromBinderStatus(mModule->getAudioPort(portId, port));
- if (status == OK) {
- auto portIt = mPorts.find(portId);
- if (portIt != mPorts.end()) {
- portIt->second = *port;
- } else {
- ALOGW("%s, port(%d) returned successfully from the HAL but not it is not cached",
- __func__, portId);
- }
- }
- return status;
-}
-
void DeviceHalAidl::clearCallbacks(void* cookie) {
std::lock_guard l(mLock);
mCallbacks.erase(cookie);
diff --git a/media/libaudiohal/impl/DeviceHalAidl.h b/media/libaudiohal/impl/DeviceHalAidl.h
index 99e8503..9493e47 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.h
+++ b/media/libaudiohal/impl/DeviceHalAidl.h
@@ -17,7 +17,9 @@
#pragma once
#include <map>
-#include <set>
+#include <memory>
+#include <mutex>
+#include <string>
#include <vector>
#include <aidl/android/media/audio/IHalAdapterVendorExtension.h>
@@ -26,9 +28,10 @@
#include <android-base/thread_annotations.h>
#include <media/audiohal/DeviceHalInterface.h>
#include <media/audiohal/EffectHalInterface.h>
-#include <media/audiohal/StreamHalInterface.h>
+#include "Cleanups.h"
#include "ConversionHelperAidl.h"
+#include "Hal2AidlMapper.h"
namespace android {
@@ -194,19 +197,6 @@
Status status = Status::UNKNOWN;
MicrophoneInfoProvider::Info info;
};
- // IDs of ports for connected external devices, and whether they are held by streams.
- using ConnectedPorts = std::map<int32_t /*port ID*/, bool>;
- using Patches = std::map<int32_t /*patch ID*/,
- ::aidl::android::hardware::audio::core::AudioPatch>;
- using PortConfigs = std::map<int32_t /*port config ID*/,
- ::aidl::android::media::audio::common::AudioPortConfig>;
- using Ports = std::map<int32_t /*port ID*/, ::aidl::android::media::audio::common::AudioPort>;
- using Routes = std::vector<::aidl::android::hardware::audio::core::AudioRoute>;
- // Answers the question "whether portID 'first' is reachable from portID 'second'?"
- // It's not a map because both portIDs are known. The matrix is symmetric.
- using RoutingMatrix = std::set<std::pair<int32_t, int32_t>>;
- using Streams = std::map<wp<StreamHalInterface>, int32_t /*patch ID*/>;
- class Cleanups;
// Must not be constructed directly by clients.
DeviceHalAidl(
@@ -216,14 +206,6 @@
~DeviceHalAidl() override = default;
- bool audioDeviceMatches(const ::aidl::android::media::audio::common::AudioDevice& device,
- const ::aidl::android::media::audio::common::AudioPort& p);
- bool audioDeviceMatches(const ::aidl::android::media::audio::common::AudioDevice& device,
- const ::aidl::android::media::audio::common::AudioPortConfig& p);
- status_t createOrUpdatePortConfig(
- const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig,
- PortConfigs::iterator* result, bool *created);
- void eraseConnectedPort(int32_t portId);
status_t filterAndRetrieveBtA2dpParameters(AudioParameter &keys, AudioParameter *result);
status_t filterAndUpdateBtA2dpParameters(AudioParameter ¶meters);
status_t filterAndUpdateBtHfpParameters(AudioParameter ¶meters);
@@ -231,60 +213,6 @@
status_t filterAndUpdateBtScoParameters(AudioParameter ¶meters);
status_t filterAndUpdateScreenParameters(AudioParameter ¶meters);
status_t filterAndUpdateTelephonyParameters(AudioParameter ¶meters);
- status_t findOrCreatePatch(
- const std::set<int32_t>& sourcePortConfigIds,
- const std::set<int32_t>& sinkPortConfigIds,
- ::aidl::android::hardware::audio::core::AudioPatch* patch, bool* created);
- status_t findOrCreatePatch(
- const ::aidl::android::hardware::audio::core::AudioPatch& requestedPatch,
- ::aidl::android::hardware::audio::core::AudioPatch* patch, bool* created);
- status_t findOrCreatePortConfig(
- const ::aidl::android::media::audio::common::AudioDevice& device,
- const ::aidl::android::media::audio::common::AudioConfig* config,
- ::aidl::android::media::audio::common::AudioPortConfig* portConfig,
- bool* created);
- status_t findOrCreatePortConfig(
- const ::aidl::android::media::audio::common::AudioConfig& config,
- const std::optional<::aidl::android::media::audio::common::AudioIoFlags>& flags,
- int32_t ioHandle,
- ::aidl::android::media::audio::common::AudioSource aidlSource,
- const std::set<int32_t>& destinationPortIds,
- ::aidl::android::media::audio::common::AudioPortConfig* portConfig, bool* created);
- status_t findOrCreatePortConfig(
- const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig,
- const std::set<int32_t>& destinationPortIds,
- ::aidl::android::media::audio::common::AudioPortConfig* portConfig, bool* created);
- Patches::iterator findPatch(const std::set<int32_t>& sourcePortConfigIds,
- const std::set<int32_t>& sinkPortConfigIds);
- Ports::iterator findPort(const ::aidl::android::media::audio::common::AudioDevice& device);
- Ports::iterator findPort(
- const ::aidl::android::media::audio::common::AudioConfig& config,
- const ::aidl::android::media::audio::common::AudioIoFlags& flags,
- const std::set<int32_t>& destinationPortIds);
- PortConfigs::iterator findPortConfig(
- const ::aidl::android::media::audio::common::AudioDevice& device);
- PortConfigs::iterator findPortConfig(
- const std::optional<::aidl::android::media::audio::common::AudioConfig>& config,
- const std::optional<::aidl::android::media::audio::common::AudioIoFlags>& flags,
- int32_t ioHandle);
- bool isPortHeldByAStream(int32_t portId);
- status_t prepareToOpenStream(
- int32_t aidlHandle,
- const ::aidl::android::media::audio::common::AudioDevice& aidlDevice,
- const ::aidl::android::media::audio::common::AudioIoFlags& aidlFlags,
- ::aidl::android::media::audio::common::AudioSource aidlSource,
- struct audio_config* config,
- Cleanups* cleanups,
- ::aidl::android::media::audio::common::AudioConfig* aidlConfig,
- ::aidl::android::media::audio::common::AudioPortConfig* mixPortConfig,
- ::aidl::android::hardware::audio::core::AudioPatch* aidlPatch);
- void resetPatch(int32_t patchId);
- void resetPortConfig(int32_t portConfigId);
- void resetUnusedPatches();
- void resetUnusedPatchesAndPortConfigs();
- void resetUnusedPortConfigs();
- status_t updateRoutes();
- status_t getAudioPort(int32_t portId, ::aidl::android::media::audio::common::AudioPort* port);
// CallbackBroker implementation
void clearCallbacks(void* cookie) override;
@@ -311,28 +239,14 @@
const std::shared_ptr<::aidl::android::hardware::audio::core::IBluetooth> mBluetooth;
const std::shared_ptr<::aidl::android::hardware::audio::core::IBluetoothA2dp> mBluetoothA2dp;
const std::shared_ptr<::aidl::android::hardware::audio::core::IBluetoothLe> mBluetoothLe;
- std::shared_ptr<::aidl::android::hardware::audio::core::sounddose::ISoundDose>
- mSoundDose = nullptr;
- Ports mPorts;
- // Remote submix "template" ports (no address specified, no profiles).
- // They are excluded from `mPorts` as their presence confuses the framework code.
- std::optional<::aidl::android::media::audio::common::AudioPort> mRemoteSubmixIn;
- std::optional<::aidl::android::media::audio::common::AudioPort> mRemoteSubmixOut;
- int32_t mDefaultInputPortId = -1;
- int32_t mDefaultOutputPortId = -1;
- PortConfigs mPortConfigs;
- std::set<int32_t> mInitialPortConfigIds;
- Patches mPatches;
- Routes mRoutes;
- RoutingMatrix mRoutingMatrix;
- Streams mStreams;
- Microphones mMicrophones;
+ const std::shared_ptr<::aidl::android::hardware::audio::core::sounddose::ISoundDose> mSoundDose;
+
std::mutex mLock;
std::map<void*, Callbacks> mCallbacks GUARDED_BY(mLock);
- std::set<audio_port_handle_t> mDeviceDisconnectionNotified;
- ConnectedPorts mConnectedPorts;
- std::pair<int32_t, ::aidl::android::media::audio::common::AudioPort>
- mDisconnectedPortReplacement;
+ std::set<audio_port_handle_t> mDeviceDisconnectionNotified GUARDED_BY(mLock);
+ Hal2AidlMapper mMapper GUARDED_BY(mLock);
+ LockedAccessor<Hal2AidlMapper> mMapperAccessor;
+ Microphones mMicrophones GUARDED_BY(mLock);
};
} // namespace android
diff --git a/media/libaudiohal/impl/Hal2AidlMapper.cpp b/media/libaudiohal/impl/Hal2AidlMapper.cpp
new file mode 100644
index 0000000..f187057
--- /dev/null
+++ b/media/libaudiohal/impl/Hal2AidlMapper.cpp
@@ -0,0 +1,927 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#define LOG_TAG "Hal2AidlMapper"
+// #define LOG_NDEBUG 0
+
+#include <algorithm>
+
+#include <media/audiohal/StreamHalInterface.h>
+#include <error/expected_utils.h>
+#include <system/audio.h> // For AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS
+#include <Utils.h>
+#include <utils/Log.h>
+
+#include "Hal2AidlMapper.h"
+
+using aidl::android::aidl_utils::statusTFromBinderStatus;
+using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioConfig;
+using aidl::android::media::audio::common::AudioDevice;
+using aidl::android::media::audio::common::AudioDeviceAddress;
+using aidl::android::media::audio::common::AudioDeviceDescription;
+using aidl::android::media::audio::common::AudioDeviceType;
+using aidl::android::media::audio::common::AudioFormatDescription;
+using aidl::android::media::audio::common::AudioInputFlags;
+using aidl::android::media::audio::common::AudioIoFlags;
+using aidl::android::media::audio::common::AudioOutputFlags;
+using aidl::android::media::audio::common::AudioPort;
+using aidl::android::media::audio::common::AudioPortConfig;
+using aidl::android::media::audio::common::AudioPortDeviceExt;
+using aidl::android::media::audio::common::AudioPortExt;
+using aidl::android::media::audio::common::AudioPortMixExt;
+using aidl::android::media::audio::common::AudioPortMixExtUseCase;
+using aidl::android::media::audio::common::AudioProfile;
+using aidl::android::media::audio::common::AudioSource;
+using aidl::android::media::audio::common::Int;
+using aidl::android::hardware::audio::common::isBitPositionFlagSet;
+using aidl::android::hardware::audio::common::isDefaultAudioFormat;
+using aidl::android::hardware::audio::common::makeBitPositionFlagMask;
+using aidl::android::hardware::audio::core::AudioPatch;
+using aidl::android::hardware::audio::core::AudioRoute;
+using aidl::android::hardware::audio::core::IModule;
+
+namespace android {
+
+namespace {
+
+bool isConfigEqualToPortConfig(const AudioConfig& config, const AudioPortConfig& portConfig) {
+ return portConfig.sampleRate.value().value == config.base.sampleRate &&
+ portConfig.channelMask.value() == config.base.channelMask &&
+ portConfig.format.value() == config.base.format;
+}
+
+void setConfigFromPortConfig(AudioConfig* config, const AudioPortConfig& portConfig) {
+ config->base.sampleRate = portConfig.sampleRate.value().value;
+ config->base.channelMask = portConfig.channelMask.value();
+ config->base.format = portConfig.format.value();
+}
+
+void setPortConfigFromConfig(AudioPortConfig* portConfig, const AudioConfig& config) {
+ if (config.base.sampleRate != 0) {
+ portConfig->sampleRate = Int{ .value = config.base.sampleRate };
+ }
+ if (config.base.channelMask != AudioChannelLayout{}) {
+ portConfig->channelMask = config.base.channelMask;
+ }
+ if (config.base.format != AudioFormatDescription{}) {
+ portConfig->format = config.base.format;
+ }
+}
+
+} // namespace
+
+Hal2AidlMapper::Hal2AidlMapper(const std::string& instance, const std::shared_ptr<IModule>& module)
+ : mInstance(instance), mModule(module) {
+}
+
+void Hal2AidlMapper::addStream(
+ const sp<StreamHalInterface>& stream, int32_t portConfigId, int32_t patchId) {
+ mStreams.insert(std::pair(stream, std::pair(portConfigId, patchId)));
+}
+
+bool Hal2AidlMapper::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
+ if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
+ return p.ext.get<AudioPortExt::Tag::device>().device == device;
+}
+
+bool Hal2AidlMapper::audioDeviceMatches(const AudioDevice& device, const AudioPortConfig& p) {
+ if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
+ if (device.type.type == AudioDeviceType::IN_DEFAULT) {
+ return p.portId == mDefaultInputPortId;
+ } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
+ return p.portId == mDefaultOutputPortId;
+ }
+ return p.ext.get<AudioPortExt::Tag::device>().device == device;
+}
+
+status_t Hal2AidlMapper::createOrUpdatePatch(
+ const std::vector<AudioPortConfig>& sources,
+ const std::vector<AudioPortConfig>& sinks,
+ int32_t* patchId, Cleanups* cleanups) {
+ auto existingPatchIt = *patchId != 0 ? mPatches.find(*patchId): mPatches.end();
+ AudioPatch patch;
+ if (existingPatchIt != mPatches.end()) {
+ patch = existingPatchIt->second;
+ patch.sourcePortConfigIds.clear();
+ patch.sinkPortConfigIds.clear();
+ }
+ // The IDs will be found by 'fillPortConfigs', however the original 'sources' and
+ // 'sinks' will not be updated because 'setAudioPatch' only needs IDs. Here we log
+ // the source arguments, where only the audio configuration and device specifications
+ // are relevant.
+ ALOGD("%s: [disregard IDs] sources: %s, sinks: %s",
+ __func__, ::android::internal::ToString(sources).c_str(),
+ ::android::internal::ToString(sinks).c_str());
+ auto fillPortConfigs = [&](
+ const std::vector<AudioPortConfig>& configs,
+ const std::set<int32_t>& destinationPortIds,
+ std::vector<int32_t>* ids, std::set<int32_t>* portIds) -> status_t {
+ for (const auto& s : configs) {
+ AudioPortConfig portConfig;
+ RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
+ s, destinationPortIds, &portConfig, cleanups));
+ ids->push_back(portConfig.id);
+ if (portIds != nullptr) {
+ portIds->insert(portConfig.portId);
+ }
+ }
+ return OK;
+ };
+ // When looking up port configs, the destinationPortId is only used for mix ports.
+ // Thus, we process device port configs first, and look up the destination port ID from them.
+ bool sourceIsDevice = std::any_of(sources.begin(), sources.end(),
+ [](const auto& config) { return config.ext.getTag() == AudioPortExt::device; });
+ const std::vector<AudioPortConfig>& devicePortConfigs =
+ sourceIsDevice ? sources : sinks;
+ std::vector<int32_t>* devicePortConfigIds =
+ sourceIsDevice ? &patch.sourcePortConfigIds : &patch.sinkPortConfigIds;
+ const std::vector<AudioPortConfig>& mixPortConfigs =
+ sourceIsDevice ? sinks : sources;
+ std::vector<int32_t>* mixPortConfigIds =
+ sourceIsDevice ? &patch.sinkPortConfigIds : &patch.sourcePortConfigIds;
+ std::set<int32_t> devicePortIds;
+ RETURN_STATUS_IF_ERROR(fillPortConfigs(
+ devicePortConfigs, std::set<int32_t>(), devicePortConfigIds, &devicePortIds));
+ RETURN_STATUS_IF_ERROR(fillPortConfigs(
+ mixPortConfigs, devicePortIds, mixPortConfigIds, nullptr));
+ if (existingPatchIt != mPatches.end()) {
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
+ mModule->setAudioPatch(patch, &patch)));
+ existingPatchIt->second = patch;
+ } else {
+ bool created = false;
+ RETURN_STATUS_IF_ERROR(findOrCreatePatch(patch, &patch, &created));
+ // No cleanup of the patch is needed, it is managed by the framework.
+ *patchId = patch.id;
+ if (!created) {
+ // The framework might have "created" a patch which already existed due to
+ // stream creation. Need to release the ownership from the stream.
+ for (auto& s : mStreams) {
+ if (s.second.second == patch.id) s.second.second = -1;
+ }
+ }
+ }
+ return OK;
+}
+
+status_t Hal2AidlMapper::createOrUpdatePortConfig(
+ const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result, bool* created) {
+ AudioPortConfig appliedPortConfig;
+ bool applied = false;
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
+ requestedPortConfig, &appliedPortConfig, &applied)));
+ if (!applied) {
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
+ appliedPortConfig, &appliedPortConfig, &applied)));
+ if (!applied) {
+ ALOGE("%s: module %s did not apply suggested config %s",
+ __func__, mInstance.c_str(), appliedPortConfig.toString().c_str());
+ return NO_INIT;
+ }
+ }
+
+ int32_t id = appliedPortConfig.id;
+ if (requestedPortConfig.id != 0 && requestedPortConfig.id != id) {
+ LOG_ALWAYS_FATAL("%s: requested port config id %d changed to %d", __func__,
+ requestedPortConfig.id, id);
+ }
+
+ auto [it, inserted] = mPortConfigs.insert_or_assign(std::move(id),
+ std::move(appliedPortConfig));
+ *result = it;
+ *created = inserted;
+ return OK;
+}
+
+void Hal2AidlMapper::eraseConnectedPort(int32_t portId) {
+ mPorts.erase(portId);
+ mConnectedPorts.erase(portId);
+ if (mDisconnectedPortReplacement.first == portId) {
+ const auto& port = mDisconnectedPortReplacement.second;
+ mPorts.insert(std::make_pair(port.id, port));
+ ALOGD("%s: disconnected port replacement: %s", __func__, port.toString().c_str());
+ mDisconnectedPortReplacement = std::pair<int32_t, AudioPort>();
+ }
+}
+
+status_t Hal2AidlMapper::findOrCreatePatch(
+ const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
+ std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
+ requestedPatch.sourcePortConfigIds.end());
+ std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
+ requestedPatch.sinkPortConfigIds.end());
+ return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
+}
+
+status_t Hal2AidlMapper::findOrCreatePatch(
+ const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
+ AudioPatch* patch, bool* created) {
+ auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
+ if (patchIt == mPatches.end()) {
+ AudioPatch requestedPatch, appliedPatch;
+ requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
+ sourcePortConfigIds.begin(), sourcePortConfigIds.end());
+ requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
+ sinkPortConfigIds.begin(), sinkPortConfigIds.end());
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
+ requestedPatch, &appliedPatch)));
+ patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
+ *created = true;
+ } else {
+ *created = false;
+ }
+ *patch = patchIt->second;
+ return OK;
+}
+
+status_t Hal2AidlMapper::findOrCreatePortConfig(
+ const AudioDevice& device, const AudioConfig* config, AudioPortConfig* portConfig,
+ bool* created) {
+ auto portConfigIt = findPortConfig(device);
+ if (portConfigIt == mPortConfigs.end()) {
+ auto portsIt = findPort(device);
+ if (portsIt == mPorts.end()) {
+ ALOGE("%s: device port for device %s is not found in the module %s",
+ __func__, device.toString().c_str(), mInstance.c_str());
+ return BAD_VALUE;
+ }
+ AudioPortConfig requestedPortConfig;
+ requestedPortConfig.portId = portsIt->first;
+ if (config != nullptr) {
+ setPortConfigFromConfig(&requestedPortConfig, *config);
+ }
+ RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
+ created));
+ } else {
+ *created = false;
+ }
+ *portConfig = portConfigIt->second;
+ return OK;
+}
+
+status_t Hal2AidlMapper::findOrCreatePortConfig(
+ const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
+ AudioSource source, const std::set<int32_t>& destinationPortIds,
+ AudioPortConfig* portConfig, bool* created) {
+ // These flags get removed one by one in this order when retrying port finding.
+ static const std::vector<AudioInputFlags> kOptionalInputFlags{
+ AudioInputFlags::FAST, AudioInputFlags::RAW, AudioInputFlags::VOIP_TX };
+ auto portConfigIt = findPortConfig(config, flags, ioHandle);
+ if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
+ auto optionalInputFlagsIt = kOptionalInputFlags.begin();
+ AudioIoFlags matchFlags = flags.value();
+ auto portsIt = findPort(config, matchFlags, destinationPortIds);
+ while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
+ && optionalInputFlagsIt != kOptionalInputFlags.end()) {
+ if (!isBitPositionFlagSet(
+ matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
+ ++optionalInputFlagsIt;
+ continue;
+ }
+ matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
+ ~makeBitPositionFlagMask(*optionalInputFlagsIt++));
+ portsIt = findPort(config, matchFlags, destinationPortIds);
+ ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
+ "retried with flags %s", __func__, config.toString().c_str(),
+ flags.value().toString().c_str(), mInstance.c_str(),
+ matchFlags.toString().c_str());
+ }
+ if (portsIt == mPorts.end()) {
+ ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
+ __func__, config.toString().c_str(), matchFlags.toString().c_str(),
+ mInstance.c_str());
+ return BAD_VALUE;
+ }
+ AudioPortConfig requestedPortConfig;
+ requestedPortConfig.portId = portsIt->first;
+ setPortConfigFromConfig(&requestedPortConfig, config);
+ requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
+ if (matchFlags.getTag() == AudioIoFlags::Tag::input
+ && source != AudioSource::SYS_RESERVED_INVALID) {
+ requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
+ AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
+ }
+ RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
+ created));
+ } else if (portConfigIt == mPortConfigs.end() && !flags.has_value()) {
+ ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
+ "and was not created as flags are not specified",
+ __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
+ return BAD_VALUE;
+ } else {
+ AudioPortConfig requestedPortConfig = portConfigIt->second;
+ if (requestedPortConfig.ext.getTag() == AudioPortExt::Tag::mix) {
+ AudioPortMixExt& mixExt = requestedPortConfig.ext.get<AudioPortExt::Tag::mix>();
+ if (mixExt.usecase.getTag() == AudioPortMixExtUseCase::Tag::source &&
+ source != AudioSource::SYS_RESERVED_INVALID) {
+ mixExt.usecase.get<AudioPortMixExtUseCase::Tag::source>() = source;
+ }
+ }
+
+ if (requestedPortConfig != portConfigIt->second) {
+ RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
+ created));
+ } else {
+ *created = false;
+ }
+ }
+ *portConfig = portConfigIt->second;
+ return OK;
+}
+
+status_t Hal2AidlMapper::findOrCreatePortConfig(
+ const AudioPortConfig& requestedPortConfig, const std::set<int32_t>& destinationPortIds,
+ AudioPortConfig* portConfig, bool* created) {
+ using Tag = AudioPortExt::Tag;
+ if (requestedPortConfig.ext.getTag() == Tag::mix) {
+ if (const auto& p = requestedPortConfig;
+ !p.sampleRate.has_value() || !p.channelMask.has_value() ||
+ !p.format.has_value()) {
+ ALOGW("%s: provided mix port config is not fully specified: %s",
+ __func__, p.toString().c_str());
+ return BAD_VALUE;
+ }
+ AudioConfig config;
+ setConfigFromPortConfig(&config, requestedPortConfig);
+ AudioSource source = requestedPortConfig.ext.get<Tag::mix>().usecase.getTag() ==
+ AudioPortMixExtUseCase::Tag::source ?
+ requestedPortConfig.ext.get<Tag::mix>().usecase.
+ get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
+ return findOrCreatePortConfig(config, requestedPortConfig.flags,
+ requestedPortConfig.ext.get<Tag::mix>().handle, source, destinationPortIds,
+ portConfig, created);
+ } else if (requestedPortConfig.ext.getTag() == Tag::device) {
+ return findOrCreatePortConfig(
+ requestedPortConfig.ext.get<Tag::device>().device, nullptr /*config*/,
+ portConfig, created);
+ }
+ ALOGW("%s: unsupported audio port config: %s",
+ __func__, requestedPortConfig.toString().c_str());
+ return BAD_VALUE;
+}
+
+status_t Hal2AidlMapper::findOrCreatePortConfig(
+ const AudioPortConfig& requestedPortConfig, const std::set<int32_t>& destinationPortIds,
+ AudioPortConfig* portConfig, Cleanups* cleanups) {
+ bool created = false;
+ RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
+ requestedPortConfig, destinationPortIds, portConfig, &created));
+ if (created && cleanups != nullptr) {
+ cleanups->add(&Hal2AidlMapper::resetPortConfig, portConfig->id);
+ }
+ return OK;
+}
+
+status_t Hal2AidlMapper::findPortConfig(const AudioDevice& device, AudioPortConfig* portConfig) {
+ if (auto it = findPortConfig(device); it != mPortConfigs.end()) {
+ *portConfig = it->second;
+ return OK;
+ }
+ ALOGE("%s: could not find a configured device port for device %s",
+ __func__, device.toString().c_str());
+ return BAD_VALUE;
+}
+
+Hal2AidlMapper::Patches::iterator Hal2AidlMapper::findPatch(
+ const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
+ return std::find_if(mPatches.begin(), mPatches.end(),
+ [&](const auto& pair) {
+ const auto& p = pair.second;
+ std::set<int32_t> patchSrcs(
+ p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
+ std::set<int32_t> patchSinks(
+ p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
+ return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
+}
+
+Hal2AidlMapper::Ports::iterator Hal2AidlMapper::findPort(const AudioDevice& device) {
+ if (device.type.type == AudioDeviceType::IN_DEFAULT) {
+ return mPorts.find(mDefaultInputPortId);
+ } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
+ return mPorts.find(mDefaultOutputPortId);
+ }
+ if (device.address.getTag() != AudioDeviceAddress::id ||
+ !device.address.get<AudioDeviceAddress::id>().empty()) {
+ return std::find_if(mPorts.begin(), mPorts.end(),
+ [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
+ }
+ // For connection w/o an address, two ports can be found: the template port,
+ // and a connected port (if exists). Make sure we return the connected port.
+ Hal2AidlMapper::Ports::iterator portIt = mPorts.end();
+ for (auto it = mPorts.begin(); it != mPorts.end(); ++it) {
+ if (audioDeviceMatches(device, it->second)) {
+ if (mConnectedPorts.find(it->first) != mConnectedPorts.end()) {
+ return it;
+ } else {
+ // Will return 'it' if there is no connected port.
+ portIt = it;
+ }
+ }
+ }
+ return portIt;
+}
+
+Hal2AidlMapper::Ports::iterator Hal2AidlMapper::findPort(
+ const AudioConfig& config, const AudioIoFlags& flags,
+ const std::set<int32_t>& destinationPortIds) {
+ auto belongsToProfile = [&config](const AudioProfile& prof) {
+ return (isDefaultAudioFormat(config.base.format) || prof.format == config.base.format) &&
+ (config.base.channelMask.getTag() == AudioChannelLayout::none ||
+ std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
+ config.base.channelMask) != prof.channelMasks.end()) &&
+ (config.base.sampleRate == 0 ||
+ std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
+ config.base.sampleRate) != prof.sampleRates.end());
+ };
+ static const std::vector<AudioOutputFlags> kOptionalOutputFlags{AudioOutputFlags::BIT_PERFECT};
+ int optionalFlags = 0;
+ auto flagMatches = [&flags, &optionalFlags](const AudioIoFlags& portFlags) {
+ // Ports should be able to match if the optional flags are not requested.
+ return portFlags == flags ||
+ (portFlags.getTag() == AudioIoFlags::Tag::output &&
+ AudioIoFlags::make<AudioIoFlags::Tag::output>(
+ portFlags.get<AudioIoFlags::Tag::output>() &
+ ~optionalFlags) == flags);
+ };
+ auto matcher = [&](const auto& pair) {
+ const auto& p = pair.second;
+ return p.ext.getTag() == AudioPortExt::Tag::mix &&
+ flagMatches(p.flags) &&
+ (destinationPortIds.empty() ||
+ std::any_of(destinationPortIds.begin(), destinationPortIds.end(),
+ [&](const int32_t destId) { return mRoutingMatrix.count(
+ std::make_pair(p.id, destId)) != 0; })) &&
+ (p.profiles.empty() ||
+ std::find_if(p.profiles.begin(), p.profiles.end(), belongsToProfile) !=
+ p.profiles.end()); };
+ auto result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
+ if (result == mPorts.end() && flags.getTag() == AudioIoFlags::Tag::output) {
+ auto optionalOutputFlagsIt = kOptionalOutputFlags.begin();
+ while (result == mPorts.end() && optionalOutputFlagsIt != kOptionalOutputFlags.end()) {
+ if (isBitPositionFlagSet(
+ flags.get<AudioIoFlags::Tag::output>(), *optionalOutputFlagsIt)) {
+ // If the flag is set by the request, it must be matched.
+ ++optionalOutputFlagsIt;
+ continue;
+ }
+ optionalFlags |= makeBitPositionFlagMask(*optionalOutputFlagsIt++);
+ result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
+ ALOGI("%s: port for config %s, flags %s was not found in the module %s, "
+ "retried with excluding optional flags %#x", __func__, config.toString().c_str(),
+ flags.toString().c_str(), mInstance.c_str(), optionalFlags);
+ }
+ }
+ return result;
+}
+
+Hal2AidlMapper::PortConfigs::iterator Hal2AidlMapper::findPortConfig(const AudioDevice& device) {
+ return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
+ [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
+}
+
+Hal2AidlMapper::PortConfigs::iterator Hal2AidlMapper::findPortConfig(
+ const std::optional<AudioConfig>& config,
+ const std::optional<AudioIoFlags>& flags,
+ int32_t ioHandle) {
+ using Tag = AudioPortExt::Tag;
+ return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
+ [&](const auto& pair) {
+ const auto& p = pair.second;
+ LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
+ (!p.sampleRate.has_value() || !p.channelMask.has_value() ||
+ !p.format.has_value() || !p.flags.has_value()),
+ "%s: stored mix port config is not fully specified: %s",
+ __func__, p.toString().c_str());
+ return p.ext.getTag() == Tag::mix &&
+ (!config.has_value() ||
+ isConfigEqualToPortConfig(config.value(), p)) &&
+ (!flags.has_value() || p.flags.value() == flags.value()) &&
+ p.ext.template get<Tag::mix>().handle == ioHandle; });
+}
+
+status_t Hal2AidlMapper::getAudioMixPort(int32_t ioHandle, AudioPort* port) {
+ auto it = findPortConfig(std::nullopt /*config*/, std::nullopt /*flags*/, ioHandle);
+ if (it == mPortConfigs.end()) {
+ ALOGE("%s, cannot find mix port config for handle %u", __func__, ioHandle);
+ return BAD_VALUE;
+ }
+ return updateAudioPort(it->second.portId, port);
+}
+
+status_t Hal2AidlMapper::getAudioPortCached(
+ const ::aidl::android::media::audio::common::AudioDevice& device,
+ ::aidl::android::media::audio::common::AudioPort* port) {
+
+ if (auto portsIt = findPort(device); portsIt != mPorts.end()) {
+ *port = portsIt->second;
+ return OK;
+ }
+ ALOGE("%s: device port for device %s is not found in the module %s",
+ __func__, device.toString().c_str(), mInstance.c_str());
+ return BAD_VALUE;
+}
+
+status_t Hal2AidlMapper::initialize() {
+ std::vector<AudioPort> ports;
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->getAudioPorts(&ports)));
+ ALOGW_IF(ports.empty(), "%s: module %s returned an empty list of audio ports",
+ __func__, mInstance.c_str());
+ mDefaultInputPortId = mDefaultOutputPortId = -1;
+ const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
+ for (auto it = ports.begin(); it != ports.end(); ) {
+ const auto& port = *it;
+ if (port.ext.getTag() != AudioPortExt::Tag::device) {
+ ++it;
+ continue;
+ }
+ const AudioPortDeviceExt& deviceExt = port.ext.get<AudioPortExt::Tag::device>();
+ if ((deviceExt.flags & defaultDeviceFlag) != 0) {
+ if (port.flags.getTag() == AudioIoFlags::Tag::input) {
+ mDefaultInputPortId = port.id;
+ } else if (port.flags.getTag() == AudioIoFlags::Tag::output) {
+ mDefaultOutputPortId = port.id;
+ }
+ }
+ // For compatibility with HIDL, hide "template" remote submix ports from ports list.
+ if (const auto& devDesc = deviceExt.device;
+ (devDesc.type.type == AudioDeviceType::IN_SUBMIX ||
+ devDesc.type.type == AudioDeviceType::OUT_SUBMIX) &&
+ devDesc.type.connection == AudioDeviceDescription::CONNECTION_VIRTUAL) {
+ if (devDesc.type.type == AudioDeviceType::IN_SUBMIX) {
+ mRemoteSubmixIn = port;
+ } else {
+ mRemoteSubmixOut = port;
+ }
+ it = ports.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ if (mRemoteSubmixIn.has_value() != mRemoteSubmixOut.has_value()) {
+ ALOGE("%s: The configuration only has input or output remote submix device, must have both",
+ __func__);
+ mRemoteSubmixIn.reset();
+ mRemoteSubmixOut.reset();
+ }
+ if (mRemoteSubmixIn.has_value()) {
+ AudioPort connectedRSubmixIn = *mRemoteSubmixIn;
+ connectedRSubmixIn.ext.get<AudioPortExt::Tag::device>().device.address =
+ AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS;
+ ALOGD("%s: connecting remote submix input", __func__);
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
+ connectedRSubmixIn, &connectedRSubmixIn)));
+ // The template port for the remote submix input couldn't be "default" because it is not
+ // attached. The connected port can now be made default because we never disconnect it.
+ if (mDefaultInputPortId == -1) {
+ mDefaultInputPortId = connectedRSubmixIn.id;
+ }
+ ports.push_back(std::move(connectedRSubmixIn));
+
+ // Remote submix output must not be connected until the framework actually starts
+ // using it, however for legacy compatibility we need to provide an "augmented template"
+ // port with an address and profiles. It is obtained by connecting the output and then
+ // immediately disconnecting it. This is a cheap operation as we don't open any streams.
+ AudioPort tempConnectedRSubmixOut = *mRemoteSubmixOut;
+ tempConnectedRSubmixOut.ext.get<AudioPortExt::Tag::device>().device.address =
+ AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS;
+ ALOGD("%s: temporarily connecting and disconnecting remote submix output", __func__);
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
+ tempConnectedRSubmixOut, &tempConnectedRSubmixOut)));
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->disconnectExternalDevice(
+ tempConnectedRSubmixOut.id)));
+ tempConnectedRSubmixOut.id = mRemoteSubmixOut->id;
+ ports.push_back(std::move(tempConnectedRSubmixOut));
+ }
+
+ ALOGI("%s: module %s default port ids: input %d, output %d",
+ __func__, mInstance.c_str(), mDefaultInputPortId, mDefaultOutputPortId);
+ std::transform(ports.begin(), ports.end(), std::inserter(mPorts, mPorts.end()),
+ [](const auto& p) { return std::make_pair(p.id, p); });
+ RETURN_STATUS_IF_ERROR(updateRoutes());
+ std::vector<AudioPortConfig> portConfigs;
+ RETURN_STATUS_IF_ERROR(
+ statusTFromBinderStatus(mModule->getAudioPortConfigs(&portConfigs))); // OK if empty
+ std::transform(portConfigs.begin(), portConfigs.end(),
+ std::inserter(mPortConfigs, mPortConfigs.end()),
+ [](const auto& p) { return std::make_pair(p.id, p); });
+ std::transform(mPortConfigs.begin(), mPortConfigs.end(),
+ std::inserter(mInitialPortConfigIds, mInitialPortConfigIds.end()),
+ [](const auto& pcPair) { return pcPair.first; });
+ std::vector<AudioPatch> patches;
+ RETURN_STATUS_IF_ERROR(
+ statusTFromBinderStatus(mModule->getAudioPatches(&patches))); // OK if empty
+ std::transform(patches.begin(), patches.end(),
+ std::inserter(mPatches, mPatches.end()),
+ [](const auto& p) { return std::make_pair(p.id, p); });
+ return OK;
+}
+
+bool Hal2AidlMapper::isPortBeingHeld(int32_t portId) {
+ // It is assumed that mStreams has already been cleaned up.
+ for (const auto& s : mStreams) {
+ if (portConfigBelongsToPort(s.second.first, portId)) return true;
+ }
+ for (const auto& [_, patch] : mPatches) {
+ for (int32_t id : patch.sourcePortConfigIds) {
+ if (portConfigBelongsToPort(id, portId)) return true;
+ }
+ for (int32_t id : patch.sinkPortConfigIds) {
+ if (portConfigBelongsToPort(id, portId)) return true;
+ }
+ }
+ return false;
+}
+
+status_t Hal2AidlMapper::prepareToOpenStream(
+ int32_t ioHandle, const AudioDevice& device, const AudioIoFlags& flags,
+ AudioSource source, Cleanups* cleanups, AudioConfig* config,
+ AudioPortConfig* mixPortConfig, AudioPatch* patch) {
+ ALOGD("%p %s: handle %d, device %s, flags %s, source %s, config %s, mix port config %s",
+ this, __func__, ioHandle, device.toString().c_str(),
+ flags.toString().c_str(), toString(source).c_str(),
+ config->toString().c_str(), mixPortConfig->toString().c_str());
+ resetUnusedPatchesAndPortConfigs();
+ const bool isInput = flags.getTag() == AudioIoFlags::Tag::input;
+ // Find / create AudioPortConfigs for the device port and the mix port,
+ // then find / create a patch between them, and open a stream on the mix port.
+ AudioPortConfig devicePortConfig;
+ bool created = false;
+ RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(device, config,
+ &devicePortConfig, &created));
+ if (created) {
+ cleanups->add(&Hal2AidlMapper::resetPortConfig, devicePortConfig.id);
+ }
+ RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(*config, flags, ioHandle, source,
+ std::set<int32_t>{devicePortConfig.portId}, mixPortConfig, &created));
+ if (created) {
+ cleanups->add(&Hal2AidlMapper::resetPortConfig, mixPortConfig->id);
+ }
+ setConfigFromPortConfig(config, *mixPortConfig);
+ if (isInput) {
+ RETURN_STATUS_IF_ERROR(findOrCreatePatch(
+ {devicePortConfig.id}, {mixPortConfig->id}, patch, &created));
+ } else {
+ RETURN_STATUS_IF_ERROR(findOrCreatePatch(
+ {mixPortConfig->id}, {devicePortConfig.id}, patch, &created));
+ }
+ if (created) {
+ cleanups->add(&Hal2AidlMapper::resetPatch, patch->id);
+ }
+ if (config->frameCount <= 0) {
+ config->frameCount = patch->minimumStreamBufferSizeFrames;
+ }
+ return OK;
+}
+
+status_t Hal2AidlMapper::releaseAudioPatch(int32_t patchId) {
+ return releaseAudioPatches({patchId});
+}
+
+status_t Hal2AidlMapper::releaseAudioPatches(const std::set<int32_t>& patchIds) {
+ status_t result = OK;
+ for (const auto patchId : patchIds) {
+ if (auto it = mPatches.find(patchId); it != mPatches.end()) {
+ mPatches.erase(it);
+ if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
+ ALOGE("%s: error while resetting patch %d: %s",
+ __func__, patchId, status.getDescription().c_str());
+ result = statusTFromBinderStatus(status);
+ }
+ } else {
+ ALOGE("%s: patch id %d not found", __func__, patchId);
+ result = BAD_VALUE;
+ }
+ }
+ resetUnusedPortConfigs();
+ return result;
+}
+
+void Hal2AidlMapper::resetPortConfig(int32_t portConfigId) {
+ if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
+ mPortConfigs.erase(it);
+ if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
+ !status.isOk()) {
+ ALOGE("%s: error while resetting port config %d: %s",
+ __func__, portConfigId, status.getDescription().c_str());
+ }
+ return;
+ }
+ ALOGE("%s: port config id %d not found", __func__, portConfigId);
+}
+
+void Hal2AidlMapper::resetUnusedPatchesAndPortConfigs() {
+ // Since patches can be created independently of streams via 'createOrUpdatePatch',
+ // here we only clean up patches for released streams.
+ std::set<int32_t> patchesToRelease;
+ for (auto it = mStreams.begin(); it != mStreams.end(); ) {
+ if (auto streamSp = it->first.promote(); streamSp) {
+ ++it;
+ } else {
+ if (const int32_t patchId = it->second.second; patchId != -1) {
+ patchesToRelease.insert(patchId);
+ }
+ it = mStreams.erase(it);
+ }
+ }
+ // 'releaseAudioPatches' also resets unused port configs.
+ releaseAudioPatches(patchesToRelease);
+}
+
+void Hal2AidlMapper::resetUnusedPortConfigs() {
+ // The assumption is that port configs are used to create patches
+ // (or to open streams, but that involves creation of patches, too). Thus,
+ // orphaned port configs can and should be reset.
+ std::map<int32_t, int32_t /*portID*/> portConfigIds;
+ std::transform(mPortConfigs.begin(), mPortConfigs.end(),
+ std::inserter(portConfigIds, portConfigIds.end()),
+ [](const auto& pcPair) { return std::make_pair(pcPair.first, pcPair.second.portId); });
+ for (const auto& p : mPatches) {
+ for (int32_t id : p.second.sourcePortConfigIds) portConfigIds.erase(id);
+ for (int32_t id : p.second.sinkPortConfigIds) portConfigIds.erase(id);
+ }
+ for (int32_t id : mInitialPortConfigIds) {
+ portConfigIds.erase(id);
+ }
+ for (const auto& s : mStreams) {
+ portConfigIds.erase(s.second.first);
+ }
+ std::set<int32_t> retryDeviceDisconnection;
+ for (const auto& portConfigAndIdPair : portConfigIds) {
+ resetPortConfig(portConfigAndIdPair.first);
+ if (const auto it = mConnectedPorts.find(portConfigAndIdPair.second);
+ it != mConnectedPorts.end() && it->second) {
+ retryDeviceDisconnection.insert(portConfigAndIdPair.second);
+ }
+ }
+ for (int32_t portId : retryDeviceDisconnection) {
+ if (!isPortBeingHeld(portId)) {
+ if (auto status = mModule->disconnectExternalDevice(portId); status.isOk()) {
+ eraseConnectedPort(portId);
+ ALOGD("%s: executed postponed external device disconnection for port ID %d",
+ __func__, portId);
+ }
+ }
+ }
+ if (!retryDeviceDisconnection.empty()) {
+ updateRoutes();
+ }
+}
+
+status_t Hal2AidlMapper::setDevicePortConnectedState(const AudioPort& devicePort, bool connected) {
+ if (connected) {
+ AudioDevice matchDevice = devicePort.ext.get<AudioPortExt::device>().device;
+ std::optional<AudioPort> templatePort;
+ auto erasePortAfterConnectionIt = mPorts.end();
+ // Connection of remote submix out with address "0" is a special case. Since there is
+ // already an "augmented template" port with this address in mPorts, we need to replace
+ // it with a connected port.
+ // Connection of remote submix outs with any other address is done as usual except that
+ // the template port is in `mRemoteSubmixOut`.
+ if (mRemoteSubmixOut.has_value() && matchDevice.type.type == AudioDeviceType::OUT_SUBMIX) {
+ if (matchDevice.address == AudioDeviceAddress::make<AudioDeviceAddress::id>(
+ AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS)) {
+ erasePortAfterConnectionIt = findPort(matchDevice);
+ }
+ templatePort = mRemoteSubmixOut;
+ } else if (mRemoteSubmixIn.has_value() &&
+ matchDevice.type.type == AudioDeviceType::IN_SUBMIX) {
+ templatePort = mRemoteSubmixIn;
+ } else {
+ // Reset the device address to find the "template" port.
+ matchDevice.address = AudioDeviceAddress::make<AudioDeviceAddress::id>();
+ }
+ if (!templatePort.has_value()) {
+ auto portsIt = findPort(matchDevice);
+ if (portsIt == mPorts.end()) {
+ // Since 'setConnectedState' is called for all modules, it is normal when the device
+ // port not found in every one of them.
+ return BAD_VALUE;
+ } else {
+ ALOGD("%s: device port for device %s found in the module %s",
+ __func__, matchDevice.toString().c_str(), mInstance.c_str());
+ }
+ templatePort = portsIt->second;
+ }
+ resetUnusedPatchesAndPortConfigs();
+
+ // Use the ID of the "template" port, use all the information from the provided port.
+ AudioPort connectedPort = devicePort;
+ connectedPort.id = templatePort->id;
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
+ connectedPort, &connectedPort)));
+ const auto [it, inserted] = mPorts.insert(std::make_pair(connectedPort.id, connectedPort));
+ LOG_ALWAYS_FATAL_IF(!inserted,
+ "%s: module %s, duplicate port ID received from HAL: %s, existing port: %s",
+ __func__, mInstance.c_str(), connectedPort.toString().c_str(),
+ it->second.toString().c_str());
+ mConnectedPorts[connectedPort.id] = false;
+ if (erasePortAfterConnectionIt != mPorts.end()) {
+ mPorts.erase(erasePortAfterConnectionIt);
+ }
+ } else { // !connected
+ AudioDevice matchDevice = devicePort.ext.get<AudioPortExt::device>().device;
+ auto portsIt = findPort(matchDevice);
+ if (portsIt == mPorts.end()) {
+ // Since 'setConnectedState' is called for all modules, it is normal when the device
+ // port not found in every one of them.
+ return BAD_VALUE;
+ } else {
+ ALOGD("%s: device port for device %s found in the module %s",
+ __func__, matchDevice.toString().c_str(), mInstance.c_str());
+ }
+ resetUnusedPatchesAndPortConfigs();
+
+ // Disconnection of remote submix out with address "0" is a special case. We need to replace
+ // the connected port entry with the "augmented template".
+ const int32_t portId = portsIt->second.id;
+ if (mRemoteSubmixOut.has_value() && matchDevice.type.type == AudioDeviceType::OUT_SUBMIX &&
+ matchDevice.address == AudioDeviceAddress::make<AudioDeviceAddress::id>(
+ AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS)) {
+ mDisconnectedPortReplacement = std::make_pair(portId, *mRemoteSubmixOut);
+ auto& port = mDisconnectedPortReplacement.second;
+ port.ext.get<AudioPortExt::Tag::device>().device = matchDevice;
+ port.profiles = portsIt->second.profiles;
+ }
+ // Streams are closed by AudioFlinger independently from device disconnections.
+ // It is possible that the stream has not been closed yet.
+ if (!isPortBeingHeld(portId)) {
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
+ mModule->disconnectExternalDevice(portId)));
+ eraseConnectedPort(portId);
+ } else {
+ ALOGD("%s: since device port ID %d is used by a stream, "
+ "external device disconnection postponed", __func__, portId);
+ mConnectedPorts[portId] = true;
+ }
+ }
+ return updateRoutes();
+}
+
+status_t Hal2AidlMapper::updateAudioPort(int32_t portId, AudioPort* port) {
+ const status_t status = statusTFromBinderStatus(mModule->getAudioPort(portId, port));
+ if (status == OK) {
+ auto portIt = mPorts.find(portId);
+ if (portIt != mPorts.end()) {
+ portIt->second = *port;
+ } else {
+ ALOGW("%s, port(%d) returned successfully from the HAL but not it is not cached",
+ __func__, portId);
+ }
+ }
+ return status;
+}
+
+status_t Hal2AidlMapper::updateRoutes() {
+ RETURN_STATUS_IF_ERROR(
+ statusTFromBinderStatus(mModule->getAudioRoutes(&mRoutes)));
+ ALOGW_IF(mRoutes.empty(), "%s: module %s returned an empty list of audio routes",
+ __func__, mInstance.c_str());
+ if (mRemoteSubmixIn.has_value()) {
+ // Remove mentions of the template remote submix input from routes.
+ int32_t rSubmixInId = mRemoteSubmixIn->id;
+ // Remove mentions of the template remote submix out only if it is not in mPorts
+ // (that means there is a connected port in mPorts).
+ int32_t rSubmixOutId = mPorts.find(mRemoteSubmixOut->id) == mPorts.end() ?
+ mRemoteSubmixOut->id : -1;
+ for (auto it = mRoutes.begin(); it != mRoutes.end();) {
+ auto& route = *it;
+ if (route.sinkPortId == rSubmixOutId) {
+ it = mRoutes.erase(it);
+ continue;
+ }
+ if (auto routeIt = std::find(route.sourcePortIds.begin(), route.sourcePortIds.end(),
+ rSubmixInId); routeIt != route.sourcePortIds.end()) {
+ route.sourcePortIds.erase(routeIt);
+ if (route.sourcePortIds.empty()) {
+ it = mRoutes.erase(it);
+ continue;
+ }
+ }
+ ++it;
+ }
+ }
+ mRoutingMatrix.clear();
+ for (const auto& r : mRoutes) {
+ for (auto portId : r.sourcePortIds) {
+ mRoutingMatrix.emplace(r.sinkPortId, portId);
+ mRoutingMatrix.emplace(portId, r.sinkPortId);
+ }
+ }
+ return OK;
+}
+
+} // namespace android
diff --git a/media/libaudiohal/impl/Hal2AidlMapper.h b/media/libaudiohal/impl/Hal2AidlMapper.h
new file mode 100644
index 0000000..70a2bd7
--- /dev/null
+++ b/media/libaudiohal/impl/Hal2AidlMapper.h
@@ -0,0 +1,186 @@
+/*
+ * 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 <memory>
+#include <map>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include <aidl/android/hardware/audio/core/IModule.h>
+#include <media/AidlConversionUtil.h>
+
+#include "Cleanups.h"
+
+namespace android {
+
+class Hal2AidlMapper;
+class StreamHalInterface;
+
+// The mapper class is needed because the framework was not yet updated to operate on AIDL-based
+// structures directly. Mapper does the job of translating the "legacy" way of identifying ports
+// and port configs (by device addresses and I/O handles) into AIDL IDs. Once the framework will
+// be updated to provide these IDs directly to libaudiohal, the need for the mapper will cease.
+class Hal2AidlMapper {
+ public:
+ using Cleanups = Cleanups<Hal2AidlMapper>;
+
+ Hal2AidlMapper(
+ const std::string& instance,
+ const std::shared_ptr<::aidl::android::hardware::audio::core::IModule>& module);
+
+ void addStream(const sp<StreamHalInterface>& stream, int32_t portConfigId, int32_t patchId);
+ status_t createOrUpdatePatch(
+ const std::vector<::aidl::android::media::audio::common::AudioPortConfig>& sources,
+ const std::vector<::aidl::android::media::audio::common::AudioPortConfig>& sinks,
+ int32_t* patchId, Cleanups* cleanups);
+ status_t findOrCreatePortConfig(
+ const ::aidl::android::media::audio::common::AudioDevice& device,
+ const ::aidl::android::media::audio::common::AudioConfig* config,
+ ::aidl::android::media::audio::common::AudioPortConfig* portConfig,
+ bool* created);
+ status_t findOrCreatePortConfig(
+ const ::aidl::android::media::audio::common::AudioConfig& config,
+ const std::optional<::aidl::android::media::audio::common::AudioIoFlags>& flags,
+ int32_t ioHandle,
+ ::aidl::android::media::audio::common::AudioSource source,
+ const std::set<int32_t>& destinationPortIds,
+ ::aidl::android::media::audio::common::AudioPortConfig* portConfig, bool* created);
+ status_t findOrCreatePortConfig(
+ const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig,
+ const std::set<int32_t>& destinationPortIds,
+ ::aidl::android::media::audio::common::AudioPortConfig* portConfig, bool* created);
+ status_t findOrCreatePortConfig(
+ const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig,
+ const std::set<int32_t>& destinationPortIds,
+ ::aidl::android::media::audio::common::AudioPortConfig* portConfig,
+ Cleanups* cleanups = nullptr);
+ status_t findPortConfig(
+ const ::aidl::android::media::audio::common::AudioDevice& device,
+ ::aidl::android::media::audio::common::AudioPortConfig* portConfig);
+ status_t getAudioMixPort(
+ int32_t ioHandle, ::aidl::android::media::audio::common::AudioPort* port);
+ status_t getAudioPortCached(
+ const ::aidl::android::media::audio::common::AudioDevice& device,
+ ::aidl::android::media::audio::common::AudioPort* port);
+ template<typename OutputContainer, typename Func>
+ status_t getAudioPorts(OutputContainer* ports, Func converter) {
+ return ::aidl::android::convertContainer(mPorts, ports,
+ [&converter](const auto& pair) { return converter(pair.second); });
+ }
+ template<typename OutputContainer, typename Func>
+ status_t getAudioRoutes(OutputContainer* routes, Func converter) {
+ return ::aidl::android::convertContainer(mRoutes, routes, converter);
+ }
+ status_t initialize();
+ status_t prepareToOpenStream(
+ int32_t ioHandle,
+ const ::aidl::android::media::audio::common::AudioDevice& device,
+ const ::aidl::android::media::audio::common::AudioIoFlags& flags,
+ ::aidl::android::media::audio::common::AudioSource source,
+ Cleanups* cleanups,
+ ::aidl::android::media::audio::common::AudioConfig* config,
+ ::aidl::android::media::audio::common::AudioPortConfig* mixPortConfig,
+ ::aidl::android::hardware::audio::core::AudioPatch* patch);
+ status_t releaseAudioPatch(int32_t patchId);
+ void resetUnusedPatchesAndPortConfigs();
+ status_t setDevicePortConnectedState(
+ const ::aidl::android::media::audio::common::AudioPort& devicePort, bool connected);
+
+ private:
+ // IDs of ports for connected external devices, and whether they are held by streams.
+ using ConnectedPorts = std::map<int32_t /*port ID*/, bool>;
+ using Patches = std::map<int32_t /*patch ID*/,
+ ::aidl::android::hardware::audio::core::AudioPatch>;
+ using PortConfigs = std::map<int32_t /*port config ID*/,
+ ::aidl::android::media::audio::common::AudioPortConfig>;
+ using Ports = std::map<int32_t /*port ID*/, ::aidl::android::media::audio::common::AudioPort>;
+ using Routes = std::vector<::aidl::android::hardware::audio::core::AudioRoute>;
+ // Answers the question "whether portID 'first' is reachable from portID 'second'?"
+ // It's not a map because both portIDs are known. The matrix is symmetric.
+ using RoutingMatrix = std::set<std::pair<int32_t, int32_t>>;
+ // There is always a port config ID set. The patch ID is set after stream
+ // creation, and can be set to '-1' later if the framework happens to create
+ // a patch between the same endpoints. In that case, the ownership of the patch
+ // is on the framework.
+ using Streams = std::map<wp<StreamHalInterface>,
+ std::pair<int32_t /*port config ID*/, int32_t /*patch ID*/>>;
+
+ const std::string mInstance;
+ const std::shared_ptr<::aidl::android::hardware::audio::core::IModule> mModule;
+
+ bool audioDeviceMatches(const ::aidl::android::media::audio::common::AudioDevice& device,
+ const ::aidl::android::media::audio::common::AudioPort& p);
+ bool audioDeviceMatches(const ::aidl::android::media::audio::common::AudioDevice& device,
+ const ::aidl::android::media::audio::common::AudioPortConfig& p);
+ status_t createOrUpdatePortConfig(
+ const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig,
+ PortConfigs::iterator* result, bool *created);
+ void eraseConnectedPort(int32_t portId);
+ status_t findOrCreatePatch(
+ const std::set<int32_t>& sourcePortConfigIds,
+ const std::set<int32_t>& sinkPortConfigIds,
+ ::aidl::android::hardware::audio::core::AudioPatch* patch, bool* created);
+ status_t findOrCreatePatch(
+ const ::aidl::android::hardware::audio::core::AudioPatch& requestedPatch,
+ ::aidl::android::hardware::audio::core::AudioPatch* patch, bool* created);
+ Patches::iterator findPatch(const std::set<int32_t>& sourcePortConfigIds,
+ const std::set<int32_t>& sinkPortConfigIds);
+ Ports::iterator findPort(const ::aidl::android::media::audio::common::AudioDevice& device);
+ Ports::iterator findPort(
+ const ::aidl::android::media::audio::common::AudioConfig& config,
+ const ::aidl::android::media::audio::common::AudioIoFlags& flags,
+ const std::set<int32_t>& destinationPortIds);
+ PortConfigs::iterator findPortConfig(
+ const ::aidl::android::media::audio::common::AudioDevice& device);
+ PortConfigs::iterator findPortConfig(
+ const std::optional<::aidl::android::media::audio::common::AudioConfig>& config,
+ const std::optional<::aidl::android::media::audio::common::AudioIoFlags>& flags,
+ int32_t ioHandle);
+ bool isPortBeingHeld(int32_t portId);
+ bool portConfigBelongsToPort(int32_t portConfigId, int32_t portId) {
+ auto it = mPortConfigs.find(portConfigId);
+ return it != mPortConfigs.end() && it->second.portId == portId;
+ }
+ status_t releaseAudioPatches(const std::set<int32_t>& patchIds);
+ void resetPatch(int32_t patchId) { (void)releaseAudioPatch(patchId); }
+ void resetPortConfig(int32_t portConfigId);
+ void resetUnusedPortConfigs();
+ status_t updateAudioPort(
+ int32_t portId, ::aidl::android::media::audio::common::AudioPort* port);
+ status_t updateRoutes();
+
+ Ports mPorts;
+ // Remote submix "template" ports (no address specified, no profiles).
+ // They are excluded from `mPorts` as their presence confuses the framework code.
+ std::optional<::aidl::android::media::audio::common::AudioPort> mRemoteSubmixIn;
+ std::optional<::aidl::android::media::audio::common::AudioPort> mRemoteSubmixOut;
+ int32_t mDefaultInputPortId = -1;
+ int32_t mDefaultOutputPortId = -1;
+ PortConfigs mPortConfigs;
+ std::set<int32_t> mInitialPortConfigIds;
+ Patches mPatches;
+ Routes mRoutes;
+ RoutingMatrix mRoutingMatrix;
+ Streams mStreams;
+ ConnectedPorts mConnectedPorts;
+ std::pair<int32_t, ::aidl::android::media::audio::common::AudioPort>
+ mDisconnectedPortReplacement;
+};
+
+} // namespace android
diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp
index e74fc16..378d919 100644
--- a/media/libaudiohal/impl/StreamHalAidl.cpp
+++ b/media/libaudiohal/impl/StreamHalAidl.cpp
@@ -83,6 +83,7 @@
mContext(std::move(context)),
mStream(stream),
mVendorExt(vext) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
{
std::lock_guard l(mLock);
mLastReply.latencyMs = nominalLatency;
@@ -97,6 +98,7 @@
}
StreamHalAidl::~StreamHalAidl() {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
if (mStream != nullptr) {
ndk::ScopedAStatus status = mStream->close();
ALOGE_IF(!status.isOk(), "%s: status %s", __func__, status.getDescription().c_str());
diff --git a/media/libmedia/MediaResource.cpp b/media/libmedia/MediaResource.cpp
index a6f0b60..1bcb4b9 100644
--- a/media/libmedia/MediaResource.cpp
+++ b/media/libmedia/MediaResource.cpp
@@ -61,8 +61,9 @@
}
//static
-MediaResource MediaResource::VideoBatteryResource() {
- return MediaResource(Type::kBattery, SubType::kVideoCodec, 1);
+MediaResource MediaResource::VideoBatteryResource(bool isHardware) {
+ SubType subType = isHardware ? SubType::kHwVideoCodec : SubType::kSwVideoCodec;
+ return MediaResource(Type::kBattery, subType, 1);
}
//static
diff --git a/media/libmedia/include/media/MediaResource.h b/media/libmedia/include/media/MediaResource.h
index 3b69d4f..c88fee2 100644
--- a/media/libmedia/include/media/MediaResource.h
+++ b/media/libmedia/include/media/MediaResource.h
@@ -41,7 +41,7 @@
int64_t instanceCount = 1);
static MediaResource GraphicMemoryResource(int64_t value);
static MediaResource CpuBoostResource();
- static MediaResource VideoBatteryResource();
+ static MediaResource VideoBatteryResource(bool isHardware = true);
static MediaResource DrmSessionResource(const std::vector<uint8_t> &id, int64_t value);
};
@@ -61,10 +61,13 @@
inline static const char *asString(MediaResource::SubType i, const char *def = "??") {
switch (i) {
case MediaResource::SubType::kUnspecifiedSubType: return "unspecified";
- case MediaResource::SubType::kAudioCodec: return "audio-codec";
- case MediaResource::SubType::kVideoCodec: return "video-codec";
- case MediaResource::SubType::kImageCodec: return "image-codec";
- default: return def;
+ case MediaResource::SubType::kHwAudioCodec: return "hw-audio-codec";
+ case MediaResource::SubType::kSwAudioCodec: return "sw-audio-codec";
+ case MediaResource::SubType::kHwVideoCodec: return "hw-video-codec";
+ case MediaResource::SubType::kSwVideoCodec: return "sw-video-codec";
+ case MediaResource::SubType::kHwImageCodec: return "hw-image-codec";
+ case MediaResource::SubType::kSwImageCodec: return "sw-image-codec";
+ default: return def;
}
}
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index c110f05..b37e3f8 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1017,12 +1017,19 @@
notify->post();
}
-static MediaResourceSubType toMediaResourceSubType(MediaCodec::Domain domain) {
+static MediaResourceSubType toMediaResourceSubType(bool isHardware, MediaCodec::Domain domain) {
switch (domain) {
- case MediaCodec::DOMAIN_VIDEO: return MediaResourceSubType::kVideoCodec;
- case MediaCodec::DOMAIN_AUDIO: return MediaResourceSubType::kAudioCodec;
- case MediaCodec::DOMAIN_IMAGE: return MediaResourceSubType::kImageCodec;
- default: return MediaResourceSubType::kUnspecifiedSubType;
+ case MediaCodec::DOMAIN_VIDEO:
+ return isHardware? MediaResourceSubType::kHwVideoCodec :
+ MediaResourceSubType::kSwVideoCodec;
+ case MediaCodec::DOMAIN_AUDIO:
+ return isHardware? MediaResourceSubType::kHwAudioCodec :
+ MediaResourceSubType::kSwAudioCodec;
+ case MediaCodec::DOMAIN_IMAGE:
+ return isHardware? MediaResourceSubType::kHwImageCodec :
+ MediaResourceSubType::kSwImageCodec;
+ default:
+ return MediaResourceSubType::kUnspecifiedSubType;
}
}
@@ -1791,7 +1798,7 @@
if (mBatteryChecker != nullptr) {
mBatteryChecker->onCodecActivity([this] () {
- mResourceManagerProxy->addResource(MediaResource::VideoBatteryResource());
+ mResourceManagerProxy->addResource(MediaResource::VideoBatteryResource(mIsHardware));
});
}
@@ -1863,7 +1870,7 @@
if (mBatteryChecker != nullptr) {
mBatteryChecker->onCodecActivity([this] () {
- mResourceManagerProxy->addResource(MediaResource::VideoBatteryResource());
+ mResourceManagerProxy->addResource(MediaResource::VideoBatteryResource(mIsHardware));
});
}
@@ -2118,13 +2125,16 @@
mBatteryChecker = new BatteryChecker(new AMessage(kWhatCheckBatteryStats, this));
}
- std::vector<MediaResourceParcel> resources;
- resources.push_back(MediaResource::CodecResource(secureCodec, toMediaResourceSubType(mDomain)));
-
// If the ComponentName is not set yet, use the name passed by the user.
if (mComponentName.empty()) {
+ mIsHardware = !MediaCodecList::isSoftwareCodec(name);
mResourceManagerProxy->setCodecName(name.c_str());
}
+
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(MediaResource::CodecResource(secureCodec,
+ toMediaResourceSubType(mIsHardware, mDomain)));
+
for (int i = 0; i <= kMaxRetry; ++i) {
if (i > 0) {
// Don't try to reclaim resource for the first time.
@@ -2368,7 +2378,7 @@
status_t err;
std::vector<MediaResourceParcel> resources;
resources.push_back(MediaResource::CodecResource(mFlags & kFlagIsSecure,
- toMediaResourceSubType(mDomain)));
+ toMediaResourceSubType(mIsHardware, mDomain)));
if (mDomain == DOMAIN_VIDEO || mDomain == DOMAIN_IMAGE) {
// Don't know the buffer size at this point, but it's fine to use 1 because
// the reclaimResource call doesn't consider the requester's buffer size for now.
@@ -2973,7 +2983,7 @@
status_t err;
std::vector<MediaResourceParcel> resources;
resources.push_back(MediaResource::CodecResource(mFlags & kFlagIsSecure,
- toMediaResourceSubType(mDomain)));
+ toMediaResourceSubType(mIsHardware, mDomain)));
if (mDomain == DOMAIN_VIDEO || mDomain == DOMAIN_IMAGE) {
// Don't know the buffer size at this point, but it's fine to use 1 because
// the reclaimResource call doesn't consider the requester's buffer size for now.
@@ -3729,9 +3739,8 @@
inline void MediaCodec::initClientConfigParcel(ClientConfigParcel& clientConfig) {
- clientConfig.codecType = toMediaResourceSubType(mDomain);
+ clientConfig.codecType = toMediaResourceSubType(mIsHardware, mDomain);
clientConfig.isEncoder = mFlags & kFlagIsEncoder;
- clientConfig.isHardware = !MediaCodecList::isSoftwareCodec(mComponentName);
clientConfig.width = mWidth;
clientConfig.height = mHeight;
clientConfig.timeStamp = systemTime(SYSTEM_TIME_MONOTONIC) / 1000LL;
@@ -3960,6 +3969,7 @@
CHECK(msg->findString("componentName", &mComponentName));
if (mComponentName.c_str()) {
+ mIsHardware = !MediaCodecList::isSoftwareCodec(mComponentName);
mediametrics_setCString(mMetricsHandle, kCodecCodec,
mComponentName.c_str());
// Update the codec name.
@@ -3987,7 +3997,7 @@
MediaCodecList::isSoftwareCodec(mComponentName) ? 0 : 1);
mResourceManagerProxy->addResource(MediaResource::CodecResource(
- mFlags & kFlagIsSecure, toMediaResourceSubType(mDomain)));
+ mFlags & kFlagIsSecure, toMediaResourceSubType(mIsHardware, mDomain)));
postPendingRepliesAndDeferredMessages("kWhatComponentAllocated");
break;
@@ -5506,7 +5516,7 @@
if (mBatteryChecker != nullptr) {
mBatteryChecker->onCheckBatteryTimer(msg, [this] () {
mResourceManagerProxy->removeResource(
- MediaResource::VideoBatteryResource());
+ MediaResource::VideoBatteryResource(mIsHardware));
});
}
break;
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index bc0f6c5..c1f9bbf 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -720,6 +720,7 @@
// An unique ID for the codec - Used by the metrics.
uint64_t mCodecId = 0;
+ bool mIsHardware = false;
std::function<sp<CodecBase>(const AString &, const char *)> mGetCodecBase;
std::function<status_t(const AString &, sp<MediaCodecInfo> *)> mGetCodecInfo;
diff --git a/media/module/service.mediatranscoding/tests/Android.bp b/media/module/service.mediatranscoding/tests/Android.bp
index 97fbd4c..9fb6d0d 100644
--- a/media/module/service.mediatranscoding/tests/Android.bp
+++ b/media/module/service.mediatranscoding/tests/Android.bp
@@ -14,6 +14,7 @@
cc_defaults {
name: "mediatranscodingservice_test_defaults",
+ cpp_std: "gnu++17",
cflags: [
"-Wall",
"-Werror",
diff --git a/media/utils/tests/Android.bp b/media/utils/tests/Android.bp
index 0689083..0d6a4c5 100644
--- a/media/utils/tests/Android.bp
+++ b/media/utils/tests/Android.bp
@@ -13,6 +13,7 @@
host_supported: true,
+ cpp_std: "gnu++17",
cflags: [
"-Wall",
"-Werror",
diff --git a/services/mediaresourcemanager/ResourceManagerMetrics.cpp b/services/mediaresourcemanager/ResourceManagerMetrics.cpp
index e26fd28..af85772 100644
--- a/services/mediaresourcemanager/ResourceManagerMetrics.cpp
+++ b/services/mediaresourcemanager/ResourceManagerMetrics.cpp
@@ -46,9 +46,12 @@
inline const char* getCodecType(MediaResourceSubType codecType) {
switch (codecType) {
- case MediaResourceSubType::kAudioCodec: return "Audio";
- case MediaResourceSubType::kVideoCodec: return "Video";
- case MediaResourceSubType::kImageCodec: return "Image";
+ case MediaResourceSubType::kHwAudioCodec: return "Hw Audio";
+ case MediaResourceSubType::kSwAudioCodec: return "Sw Audio";
+ case MediaResourceSubType::kHwVideoCodec: return "Hw Video";
+ case MediaResourceSubType::kSwVideoCodec: return "Sw Video";
+ case MediaResourceSubType::kHwImageCodec: return "Hw Image";
+ case MediaResourceSubType::kSwImageCodec: return "Sw Image";
case MediaResourceSubType::kUnspecifiedSubType:
default:
return "Unspecified";
@@ -56,39 +59,29 @@
return "Unspecified";
}
-static CodecBucket getCodecBucket(bool isHardware,
- bool isEncoder,
- MediaResourceSubType codecType) {
- if (isHardware) {
- switch (codecType) {
- case MediaResourceSubType::kAudioCodec:
- if (isEncoder) return HwAudioEncoder;
- return HwAudioDecoder;
- case MediaResourceSubType::kVideoCodec:
- if (isEncoder) return HwVideoEncoder;
- return HwVideoDecoder;
- case MediaResourceSubType::kImageCodec:
- if (isEncoder) return HwImageEncoder;
- return HwImageDecoder;
- case MediaResourceSubType::kUnspecifiedSubType:
- default:
- return CodecBucketUnspecified;
- }
- } else {
- switch (codecType) {
- case MediaResourceSubType::kAudioCodec:
- if (isEncoder) return SwAudioEncoder;
- return SwAudioDecoder;
- case MediaResourceSubType::kVideoCodec:
- if (isEncoder) return SwVideoEncoder;
- return SwVideoDecoder;
- case MediaResourceSubType::kImageCodec:
- if (isEncoder) return SwImageEncoder;
- return SwImageDecoder;
- case MediaResourceSubType::kUnspecifiedSubType:
- default:
- return CodecBucketUnspecified;
- }
+inline bool isHardwareCodec(MediaResourceSubType codecType) {
+ return (codecType == MediaResourceSubType::kHwAudioCodec ||
+ codecType == MediaResourceSubType::kHwVideoCodec ||
+ codecType == MediaResourceSubType::kHwImageCodec);
+}
+
+static CodecBucket getCodecBucket(bool isEncoder, MediaResourceSubType codecType) {
+ switch (codecType) {
+ case MediaResourceSubType::kHwAudioCodec:
+ return isEncoder? HwAudioEncoder : HwAudioDecoder;
+ case MediaResourceSubType::kSwAudioCodec:
+ return isEncoder? SwAudioEncoder : SwAudioDecoder;
+ case MediaResourceSubType::kHwVideoCodec:
+ return isEncoder? HwVideoEncoder : HwVideoDecoder;
+ case MediaResourceSubType::kSwVideoCodec:
+ return isEncoder? SwVideoEncoder : SwVideoDecoder;
+ case MediaResourceSubType::kHwImageCodec:
+ return isEncoder? HwImageEncoder : HwImageDecoder;
+ case MediaResourceSubType::kSwImageCodec:
+ return isEncoder? SwImageEncoder : SwImageDecoder;
+ case MediaResourceSubType::kUnspecifiedSubType:
+ default:
+ return CodecBucketUnspecified;
}
return CodecBucketUnspecified;
@@ -179,8 +172,10 @@
std::scoped_lock lock(mLock);
ClientConfigMap::iterator entry = mClientConfigMap.find(clientConfig.clientInfo.id);
if (entry != mClientConfigMap.end() &&
- (clientConfig.codecType == MediaResourceSubType::kVideoCodec ||
- clientConfig.codecType == MediaResourceSubType::kImageCodec)) {
+ (clientConfig.codecType == MediaResourceSubType::kHwVideoCodec ||
+ clientConfig.codecType == MediaResourceSubType::kSwVideoCodec ||
+ clientConfig.codecType == MediaResourceSubType::kHwImageCodec ||
+ clientConfig.codecType == MediaResourceSubType::kSwImageCodec)) {
int pid = clientConfig.clientInfo.pid;
// Update the pixel count for this process
updatePixelCount(pid, clientConfig.width * (long)clientConfig.height,
@@ -201,13 +196,13 @@
mClientConfigMap[clientConfig.clientInfo.id] = clientConfig;
// Update the concurrent codec count for this process.
- CodecBucket codecBucket = getCodecBucket(clientConfig.isHardware,
- clientConfig.isEncoder,
- clientConfig.codecType);
+ CodecBucket codecBucket = getCodecBucket(clientConfig.isEncoder, clientConfig.codecType);
increaseConcurrentCodecs(pid, codecBucket);
- if (clientConfig.codecType == MediaResourceSubType::kVideoCodec ||
- clientConfig.codecType == MediaResourceSubType::kImageCodec) {
+ if (clientConfig.codecType == MediaResourceSubType::kHwVideoCodec ||
+ clientConfig.codecType == MediaResourceSubType::kSwVideoCodec ||
+ clientConfig.codecType == MediaResourceSubType::kHwImageCodec ||
+ clientConfig.codecType == MediaResourceSubType::kSwImageCodec) {
// Update the pixel count for this process
increasePixelCount(pid, clientConfig.width * (long)clientConfig.height);
}
@@ -236,7 +231,7 @@
clientConfig.clientInfo.name.c_str(),
static_cast<int32_t>(clientConfig.codecType),
clientConfig.isEncoder,
- clientConfig.isHardware,
+ isHardwareCodec(clientConfig.codecType),
clientConfig.width, clientConfig.height,
systemConcurrentCodecs,
appConcurrentCodecs,
@@ -249,7 +244,7 @@
ALOGV("%s: Pushed MEDIA_CODEC_STARTED atom: "
"Process[pid(%d): uid(%d)] "
- "Codec: [%s: %ju] is %s %s %s "
+ "Codec: [%s: %ju] is %s %s "
"Timestamp: %jd "
"Resolution: %d x %d "
"ConcurrentCodec[%d]={System: %d App: %d} "
@@ -259,7 +254,6 @@
pid, clientConfig.clientInfo.uid,
clientConfig.clientInfo.name.c_str(),
clientConfig.id,
- clientConfig.isHardware? "hardware" : "software",
getCodecType(clientConfig.codecType),
clientConfig.isEncoder? "encoder" : "decoder",
clientConfig.timeStamp,
@@ -273,13 +267,13 @@
std::scoped_lock lock(mLock);
int pid = clientConfig.clientInfo.pid;
// Update the concurrent codec count for this process.
- CodecBucket codecBucket = getCodecBucket(clientConfig.isHardware,
- clientConfig.isEncoder,
- clientConfig.codecType);
+ CodecBucket codecBucket = getCodecBucket(clientConfig.isEncoder, clientConfig.codecType);
decreaseConcurrentCodecs(pid, codecBucket);
- if (clientConfig.codecType == MediaResourceSubType::kVideoCodec ||
- clientConfig.codecType == MediaResourceSubType::kImageCodec) {
+ if (clientConfig.codecType == MediaResourceSubType::kHwVideoCodec ||
+ clientConfig.codecType == MediaResourceSubType::kSwVideoCodec ||
+ clientConfig.codecType == MediaResourceSubType::kHwImageCodec ||
+ clientConfig.codecType == MediaResourceSubType::kSwImageCodec) {
// Update the pixel count for this process
decreasePixelCount(pid, clientConfig.width * (long)clientConfig.height);
}
@@ -319,7 +313,7 @@
clientConfig.clientInfo.name.c_str(),
static_cast<int32_t>(clientConfig.codecType),
clientConfig.isEncoder,
- clientConfig.isHardware,
+ isHardwareCodec(clientConfig.codecType),
clientConfig.width, clientConfig.height,
systemConcurrentCodecs,
appConcurrentCodecs,
@@ -327,7 +321,7 @@
usageTime);
ALOGV("%s: Pushed MEDIA_CODEC_STOPPED atom: "
"Process[pid(%d): uid(%d)] "
- "Codec: [%s: %ju] is %s %s %s "
+ "Codec: [%s: %ju] is %s %s "
"Timestamp: %jd Usage time: %jd "
"Resolution: %d x %d "
"ConcurrentCodec[%d]={System: %d App: %d} "
@@ -336,7 +330,6 @@
pid, clientConfig.clientInfo.uid,
clientConfig.clientInfo.name.c_str(),
clientConfig.id,
- clientConfig.isHardware? "hardware" : "software",
getCodecType(clientConfig.codecType),
clientConfig.isEncoder? "encoder" : "decoder",
clientConfig.timeStamp, usageTime,
@@ -433,9 +426,9 @@
}
void ResourceManagerMetrics::pushReclaimAtom(const ClientInfoParcel& clientInfo,
- const std::vector<int>& priorities,
- const std::vector<std::shared_ptr<IResourceManagerClient>>& clients,
- const PidUidVector& idList, bool reclaimed) {
+ const std::vector<int>& priorities,
+ const std::vector<ClientInfo>& targetClients,
+ bool reclaimed) {
// Construct the metrics for codec reclaim as a pushed atom.
// 1. Information about the requester.
// - UID and the priority (oom score)
@@ -460,7 +453,7 @@
// - UID and the Priority (oom score)
int32_t reclaimStatus = MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_SUCCESS;
if (!reclaimed) {
- if (clients.size() == 0) {
+ if (targetClients.size() == 0) {
// No clients to reclaim from
reclaimStatus =
MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_NO_CLIENTS;
@@ -470,10 +463,9 @@
MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_RECLAIM_RESOURCES;
}
}
- int32_t noOfCodecsReclaimed = clients.size();
+ int32_t noOfCodecsReclaimed = targetClients.size();
int32_t targetIndex = 1;
- for (PidUidVector::const_reference id : idList) {
- int32_t targetUid = id.second;
+ for (const ClientInfo& targetClient : targetClients) {
int targetPriority = priorities[targetIndex];
// Post the pushed atom
int result = stats_write(
@@ -485,7 +477,7 @@
reclaimStatus,
noOfCodecsReclaimed,
targetIndex,
- targetUid,
+ targetClient.mUid,
targetPriority);
ALOGI("%s: Pushed MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED atom: "
"Requester[pid(%d): uid(%d): priority(%d)] "
@@ -497,7 +489,7 @@
__func__, callingPid, requesterUid, requesterPriority,
clientName.c_str(), noOfConcurrentCodecs,
reclaimStatus, noOfCodecsReclaimed,
- targetIndex, id.first, targetUid, targetPriority, result);
+ targetIndex, targetClient.mPid, targetClient.mUid, targetPriority, result);
targetIndex++;
}
}
diff --git a/services/mediaresourcemanager/ResourceManagerMetrics.h b/services/mediaresourcemanager/ResourceManagerMetrics.h
index d99c5b1..a9bc34b 100644
--- a/services/mediaresourcemanager/ResourceManagerMetrics.h
+++ b/services/mediaresourcemanager/ResourceManagerMetrics.h
@@ -135,8 +135,8 @@
// To be called when after a reclaim event.
void pushReclaimAtom(const ClientInfoParcel& clientInfo,
const std::vector<int>& priorities,
- const std::vector<std::shared_ptr<IResourceManagerClient>>& clients,
- const PidUidVector& idList, bool reclaimed);
+ const std::vector<ClientInfo>& targetClients,
+ bool reclaimed);
// Add this pid/uid set to monitor for the process termination state.
void addPid(int pid, uid_t uid = 0);
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index 9552e25..c5eb537 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -168,13 +168,16 @@
sp<IMediaResourceMonitor> service = interface_cast<IMediaResourceMonitor>(binder);
for (size_t i = 0; i < resources.size(); ++i) {
switch (resources[i].subType) {
- case MediaResource::SubType::kAudioCodec:
+ case MediaResource::SubType::kHwAudioCodec:
+ case MediaResource::SubType::kSwAudioCodec:
service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_AUDIO_CODEC);
break;
- case MediaResource::SubType::kVideoCodec:
+ case MediaResource::SubType::kHwVideoCodec:
+ case MediaResource::SubType::kSwVideoCodec:
service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_VIDEO_CODEC);
break;
- case MediaResource::SubType::kImageCodec:
+ case MediaResource::SubType::kHwImageCodec:
+ case MediaResource::SubType::kSwImageCodec:
service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_IMAGE_CODEC);
break;
case MediaResource::SubType::kUnspecifiedSubType:
@@ -366,7 +369,8 @@
}
mCpuBoostCount++;
} else if (resource.type == MediaResource::Type::kBattery
- && resource.subType == MediaResource::SubType::kVideoCodec) {
+ && (resource.subType == MediaResource::SubType::kHwVideoCodec
+ || resource.subType == MediaResource::SubType::kSwVideoCodec)) {
mSystemCB->noteStartVideo(clientInfo.uid);
}
}
@@ -380,7 +384,8 @@
mSystemCB->requestCpusetBoost(false);
}
} else if (resource.type == MediaResource::Type::kBattery
- && resource.subType == MediaResource::SubType::kVideoCodec) {
+ && (resource.subType == MediaResource::SubType::kHwVideoCodec
+ || resource.subType == MediaResource::SubType::kSwVideoCodec)) {
mSystemCB->noteStopVideo(clientInfo.uid);
}
}
@@ -580,16 +585,28 @@
return Status::ok();
}
-void ResourceManagerService::getClientForResource_l(int callingPid,
- const MediaResourceParcel *res,
- PidUidVector* idVector,
- std::vector<std::shared_ptr<IResourceManagerClient>>* clients) {
+void ResourceManagerService::getClientForResource_l(
+ const ResourceRequestInfo& resourceRequestInfo,
+ std::vector<ClientInfo>& clientsInfo) {
+ int callingPid = resourceRequestInfo.mCallingPid;
+ const MediaResourceParcel* res = resourceRequestInfo.mResource;
if (res == NULL) {
return;
}
+
+ // Before looking into other processes, check if we have clients marked for
+ // pending removal in the same process.
+ uid_t uid = 0;
std::shared_ptr<IResourceManagerClient> client;
- if (getLowestPriorityBiggestClient_l(callingPid, res->type, res->subType, idVector, &client)) {
- clients->push_back(client);
+ if (getBiggestClientPendingRemoval_l(callingPid, res->type, res->subType, uid, &client)) {
+ clientsInfo.emplace_back(callingPid, uid, client);
+ return;
+ }
+
+ // Now find client(s) from a lowest priority process that has needed resources.
+ ClientInfo clientInfo;
+ if (getLowestPriorityBiggestClient_l(resourceRequestInfo, clientInfo)) {
+ clientsInfo.push_back(clientInfo);
}
}
@@ -602,8 +619,7 @@
mServiceLog->add(log);
*_aidl_return = false;
- std::vector<std::shared_ptr<IResourceManagerClient>> clients;
- PidUidVector idVector;
+ std::vector<ClientInfo> targetClients;
{
std::scoped_lock lock{mLock};
if (!mProcessInfo->isPidTrusted(callingPid)) {
@@ -637,98 +653,116 @@
// first pass to handle secure/non-secure codec conflict
if (secureCodec != NULL) {
+ MediaResourceParcel mediaResource{.type = MediaResource::Type::kSecureCodec,
+ .subType = secureCodec->subType};
+ ResourceRequestInfo resourceRequestInfo{callingPid, &mediaResource};
if (!mSupportsMultipleSecureCodecs) {
- if (!getAllClients_l(callingPid, MediaResource::Type::kSecureCodec,
- secureCodec->subType, &idVector, &clients)) {
+ if (!getAllClients_l(resourceRequestInfo, targetClients)) {
return Status::ok();
}
}
if (!mSupportsSecureWithNonSecureCodec) {
- if (!getAllClients_l(callingPid, MediaResource::Type::kNonSecureCodec,
- secureCodec->subType, &idVector, &clients)) {
+ mediaResource.type = MediaResource::Type::kNonSecureCodec;
+ if (!getAllClients_l(resourceRequestInfo, targetClients)) {
return Status::ok();
}
}
}
if (nonSecureCodec != NULL) {
if (!mSupportsSecureWithNonSecureCodec) {
- if (!getAllClients_l(callingPid, MediaResource::Type::kSecureCodec,
- nonSecureCodec->subType, &idVector, &clients)) {
+ MediaResourceParcel mediaResource{.type = MediaResource::Type::kSecureCodec,
+ .subType = nonSecureCodec->subType};
+ ResourceRequestInfo resourceRequestInfo{callingPid, &mediaResource};
+ if (!getAllClients_l(resourceRequestInfo, targetClients)) {
return Status::ok();
}
}
}
+
if (drmSession != NULL) {
- getClientForResource_l(callingPid, drmSession, &idVector, &clients);
- if (clients.size() == 0) {
+ ResourceRequestInfo resourceRequestInfo{callingPid, drmSession};
+ getClientForResource_l(resourceRequestInfo, targetClients);
+ if (targetClients.size() == 0) {
return Status::ok();
}
}
- if (clients.size() == 0) {
+ if (targetClients.size() == 0 && graphicMemory != nullptr) {
// if no secure/non-secure codec conflict, run second pass to handle other resources.
- getClientForResource_l(callingPid, graphicMemory, &idVector, &clients);
+ ResourceRequestInfo resourceRequestInfo{callingPid, graphicMemory};
+ getClientForResource_l(resourceRequestInfo, targetClients);
}
- if (clients.size() == 0) {
+ if (targetClients.size() == 0) {
// if we are here, run the third pass to free one codec with the same type.
- getClientForResource_l(callingPid, secureCodec, &idVector, &clients);
- getClientForResource_l(callingPid, nonSecureCodec, &idVector, &clients);
+ if (secureCodec != nullptr) {
+ ResourceRequestInfo resourceRequestInfo{callingPid, secureCodec};
+ getClientForResource_l(resourceRequestInfo, targetClients);
+ }
+ if (nonSecureCodec != nullptr) {
+ ResourceRequestInfo resourceRequestInfo{callingPid, nonSecureCodec};
+ getClientForResource_l(resourceRequestInfo, targetClients);
+ }
}
- if (clients.size() == 0) {
+ if (targetClients.size() == 0) {
// if we are here, run the fourth pass to free one codec with the different type.
- if (secureCodec != NULL) {
+ if (secureCodec != nullptr) {
MediaResource temp(MediaResource::Type::kNonSecureCodec, secureCodec->subType, 1);
- getClientForResource_l(callingPid, &temp, &idVector, &clients);
+ ResourceRequestInfo resourceRequestInfo{callingPid, &temp};
+ getClientForResource_l(resourceRequestInfo, targetClients);
}
- if (nonSecureCodec != NULL) {
+ if (nonSecureCodec != nullptr) {
MediaResource temp(MediaResource::Type::kSecureCodec, nonSecureCodec->subType, 1);
- getClientForResource_l(callingPid, &temp, &idVector, &clients);
+ ResourceRequestInfo resourceRequestInfo{callingPid, &temp};
+ getClientForResource_l(resourceRequestInfo, targetClients);
}
}
}
- *_aidl_return = reclaimUnconditionallyFrom(clients);
+ *_aidl_return = reclaimUnconditionallyFrom(targetClients);
// Log Reclaim Pushed Atom to statsd
- pushReclaimAtom(clientInfo, clients, idVector, *_aidl_return);
+ pushReclaimAtom(clientInfo, targetClients, *_aidl_return);
return Status::ok();
}
void ResourceManagerService::pushReclaimAtom(const ClientInfoParcel& clientInfo,
- const std::vector<std::shared_ptr<IResourceManagerClient>>& clients,
- const PidUidVector& idVector, bool reclaimed) {
+ const std::vector<ClientInfo>& targetClients,
+ bool reclaimed) {
int32_t callingPid = clientInfo.pid;
int requesterPriority = -1;
getPriority_l(callingPid, &requesterPriority);
std::vector<int> priorities;
priorities.push_back(requesterPriority);
- for (PidUidVector::const_reference id : idVector) {
+ for (const ClientInfo& targetClient : targetClients) {
int targetPriority = -1;
- getPriority_l(id.first, &targetPriority);
+ getPriority_l(targetClient.mPid, &targetPriority);
priorities.push_back(targetPriority);
}
- mResourceManagerMetrics->pushReclaimAtom(clientInfo, priorities, clients,
- idVector, reclaimed);
+ mResourceManagerMetrics->pushReclaimAtom(clientInfo, priorities, targetClients, reclaimed);
}
bool ResourceManagerService::reclaimUnconditionallyFrom(
- const std::vector<std::shared_ptr<IResourceManagerClient>>& clients) {
- if (clients.size() == 0) {
+ const std::vector<ClientInfo>& targetClients) {
+ if (targetClients.size() == 0) {
return false;
}
std::shared_ptr<IResourceManagerClient> failedClient;
- for (size_t i = 0; i < clients.size(); ++i) {
- String8 log = String8::format("reclaimResource from client %p", clients[i].get());
+ for (const ClientInfo& targetClient : targetClients) {
+ if (targetClient.mClient == nullptr) {
+ // skip already released clients.
+ continue;
+ }
+ String8 log = String8::format("reclaimResource from client %p", targetClient.mClient.get());
mServiceLog->add(log);
bool success;
- Status status = clients[i]->reclaimResource(&success);
+ Status status = targetClient.mClient->reclaimResource(&success);
if (!status.isOk() || !success) {
- failedClient = clients[i];
+ failedClient = targetClient.mClient;
break;
}
}
@@ -886,7 +920,7 @@
String8 log = String8::format("reclaimResourcesFromClientsPendingRemoval(pid %d)", pid);
mServiceLog->add(log);
- std::vector<std::shared_ptr<IResourceManagerClient>> clients;
+ std::vector<ClientInfo> targetClients;
{
std::scoped_lock lock{mLock};
if (!mProcessInfo->isPidTrusted(pid)) {
@@ -904,13 +938,16 @@
// Codec resources are segregated by audio, video and image domains.
case MediaResource::Type::kSecureCodec:
case MediaResource::Type::kNonSecureCodec:
- for (MediaResource::SubType subType : {MediaResource::SubType::kAudioCodec,
- MediaResource::SubType::kVideoCodec,
- MediaResource::SubType::kImageCodec}) {
+ for (MediaResource::SubType subType : {MediaResource::SubType::kHwAudioCodec,
+ MediaResource::SubType::kSwAudioCodec,
+ MediaResource::SubType::kHwVideoCodec,
+ MediaResource::SubType::kSwVideoCodec,
+ MediaResource::SubType::kHwImageCodec,
+ MediaResource::SubType::kSwImageCodec}) {
std::shared_ptr<IResourceManagerClient> client;
uid_t uid = 0;
if (getBiggestClientPendingRemoval_l(pid, type, subType, uid, &client)) {
- clients.push_back(client);
+ targetClients.emplace_back(pid, uid, client);
continue;
}
}
@@ -921,15 +958,15 @@
uid_t uid = 0;
if (getBiggestClientPendingRemoval_l(pid, type,
MediaResource::SubType::kUnspecifiedSubType, uid, &client)) {
- clients.push_back(client);
+ targetClients.emplace_back(pid, uid, client);
}
break;
}
}
}
- if (!clients.empty()) {
- reclaimUnconditionallyFrom(clients);
+ if (!targetClients.empty()) {
+ reclaimUnconditionallyFrom(targetClients);
}
return Status::ok();
}
@@ -946,73 +983,70 @@
return mProcessInfo->getPriority(newPid, priority);
}
-bool ResourceManagerService::getAllClients_l(int callingPid, MediaResource::Type type,
- MediaResource::SubType subType,
- PidUidVector* idVector,
- std::vector<std::shared_ptr<IResourceManagerClient>>* clients) {
- std::vector<std::shared_ptr<IResourceManagerClient>> temp;
- PidUidVector tempIdList;
+bool ResourceManagerService::getAllClients_l(
+ const ResourceRequestInfo& resourceRequestInfo,
+ std::vector<ClientInfo>& clientsInfo) {
+ MediaResource::Type type = resourceRequestInfo.mResource->type;
+ MediaResource::SubType subType = resourceRequestInfo.mResource->subType;
for (auto& [pid, infos] : mMap) {
for (const auto& [id, info] : infos) {
if (hasResourceType(type, subType, info.resources)) {
- if (!isCallingPriorityHigher_l(callingPid, pid)) {
+ if (!isCallingPriorityHigher_l(resourceRequestInfo.mCallingPid, pid)) {
// some higher/equal priority process owns the resource,
// this request can't be fulfilled.
- ALOGE("getAllClients_l: can't reclaim resource %s from pid %d",
- asString(type), pid);
+ ALOGE("%s: can't reclaim resource %s from pid %d",
+ __func__, asString(type), pid);
+ clientsInfo.clear();
return false;
}
- temp.push_back(info.client);
- tempIdList.emplace_back(pid, info.uid);
+ clientsInfo.emplace_back(pid, info.uid, info.client);
}
}
}
- if (temp.size() == 0) {
- ALOGV("getAllClients_l: didn't find any resource %s", asString(type));
- return true;
+ if (clientsInfo.size() == 0) {
+ ALOGV("%s: didn't find any resource %s", __func__, asString(type));
}
-
- clients->insert(std::end(*clients), std::begin(temp), std::end(temp));
- idVector->insert(std::end(*idVector), std::begin(tempIdList), std::end(tempIdList));
return true;
}
-bool ResourceManagerService::getLowestPriorityBiggestClient_l(int callingPid,
- MediaResource::Type type,
- MediaResource::SubType subType,
- PidUidVector* idVector,
- std::shared_ptr<IResourceManagerClient> *client) {
+// Process priority (oom score) based reclaim:
+// - Find a process with lowest priority (than that of calling process).
+// - Find the bigegst client (with required resources) from that process.
+bool ResourceManagerService::getLowestPriorityBiggestClient_l(
+ const ResourceRequestInfo& resourceRequestInfo,
+ ClientInfo& clientsInfo) {
+ int callingPid = resourceRequestInfo.mCallingPid;
+ MediaResource::Type type = resourceRequestInfo.mResource->type;
+ MediaResource::SubType subType = resourceRequestInfo.mResource->subType;
int lowestPriorityPid;
int lowestPriority;
int callingPriority;
uid_t uid = 0;
+ std::shared_ptr<IResourceManagerClient> client;
- // Before looking into other processes, check if we have clients marked for
- // pending removal in the same process.
- if (getBiggestClientPendingRemoval_l(callingPid, type, subType, uid, client)) {
- idVector->emplace_back(callingPid, uid);
- return true;
- }
if (!getPriority_l(callingPid, &callingPriority)) {
- ALOGE("getLowestPriorityBiggestClient_l: can't get process priority for pid %d",
- callingPid);
+ ALOGE("%s: can't get process priority for pid %d", __func__, callingPid);
return false;
}
if (!getLowestPriorityPid_l(type, subType, &lowestPriorityPid, &lowestPriority)) {
return false;
}
if (lowestPriority <= callingPriority) {
- ALOGE("getLowestPriorityBiggestClient_l: lowest priority %d vs caller priority %d",
- lowestPriority, callingPriority);
+ ALOGE("%s: lowest priority %d vs caller priority %d",
+ __func__, lowestPriority, callingPriority);
return false;
}
- if (!getBiggestClient_l(lowestPriorityPid, type, subType, uid, client)) {
+ if (!getBiggestClient_l(lowestPriorityPid, type, subType, uid, &client)) {
return false;
}
- idVector->emplace_back(lowestPriorityPid, uid);
+ clientsInfo.mPid = lowestPriorityPid;
+ clientsInfo.mUid = uid;
+ clientsInfo.mClient = client;
+ ALOGI("%s: CallingProcess(%d:%d) will reclaim from the lowestPriorityProcess(%d:%d)",
+ __func__, callingPid, callingPriority, lowestPriorityPid, lowestPriority);
return true;
}
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index aa88ac6..de7e4a3 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -33,7 +33,6 @@
namespace android {
class DeathNotifier;
-class ResourceManagerService;
class ResourceObserverService;
class ServiceLog;
struct ProcessInfoInterface;
@@ -61,8 +60,39 @@
bool pendingRemoval{false};
};
-// vector of <PID, UID>
-typedef std::vector<std::pair<int32_t, uid_t>> PidUidVector;
+/*
+ * Resource request info that encapsulates
+ * - the calling/requesting process pid.
+ * - the resource requesting (to be reclaimed from others)
+ */
+struct ResourceRequestInfo {
+ // uid of the calling/requesting process.
+ int mCallingPid = -1;
+ // resources requested.
+ const ::aidl::android::media::MediaResourceParcel* mResource;
+};
+
+/*
+ * Structure that defines the Client - a possible target to relcaim from.
+ * This encapsulates pid, uid of the process and the client.
+ * based on the reclaim policy.
+ */
+struct ClientInfo {
+ // pid of the process.
+ pid_t mPid;
+ // uid of the process.
+ uid_t mUid;
+ // Client to relcaim from.
+ std::shared_ptr<::aidl::android::media::IResourceManagerClient> mClient;
+ ClientInfo(
+ pid_t pid = -1,
+ uid_t uid = -1,
+ const std::shared_ptr<::aidl::android::media::IResourceManagerClient>& client = nullptr)
+ : mPid(pid),
+ mUid(uid),
+ mClient(client) {
+ }
+};
typedef std::map<int64_t, ResourceInfo> ResourceInfos;
typedef std::map<int, ResourceInfos> PidResourceInfosMap;
@@ -134,45 +164,40 @@
// Reclaims resources from |clients|. Returns true if reclaim succeeded
// for all clients.
bool reclaimUnconditionallyFrom(
- const std::vector<std::shared_ptr<IResourceManagerClient>>& clients);
+ const std::vector<ClientInfo>& targetClients);
// Gets the list of all the clients who own the specified resource type.
// Returns false if any client belongs to a process with higher priority than the
// calling process. The clients will remain unchanged if returns false.
- bool getAllClients_l(int callingPid, MediaResource::Type type, MediaResource::SubType subType,
- PidUidVector* idList,
- std::vector<std::shared_ptr<IResourceManagerClient>>* clients);
+ bool getAllClients_l(const ResourceRequestInfo& resourceRequestInfo,
+ std::vector<ClientInfo>& clientsInfo);
// Gets the client who owns specified resource type from lowest possible priority process.
// Returns false if the calling process priority is not higher than the lowest process
// priority. The client will remain unchanged if returns false.
- bool getLowestPriorityBiggestClient_l(int callingPid, MediaResource::Type type,
- MediaResource::SubType subType, PidUidVector* idList,
- std::shared_ptr<IResourceManagerClient> *client);
-
- // Gets lowest priority process that has the specified resource type.
- // Returns false if failed. The output parameters will remain unchanged if failed.
- bool getLowestPriorityPid_l(MediaResource::Type type, MediaResource::SubType subType, int *pid,
- int *priority);
+ bool getLowestPriorityBiggestClient_l(
+ const ResourceRequestInfo& resourceRequestInfo,
+ ClientInfo& clientInfo);
// Gets the client who owns biggest piece of specified resource type from pid.
- // Returns false with no change to client if there are no clients holdiing resources of thisi
+ // Returns false with no change to client if there are no clients holding resources of this
// type.
bool getBiggestClient_l(int pid, MediaResource::Type type, MediaResource::SubType subType,
- uid_t& uid, std::shared_ptr<IResourceManagerClient> *client,
- bool pendingRemovalOnly = false);
+ uid_t& uid, std::shared_ptr<IResourceManagerClient> *client,
+ bool pendingRemovalOnly = false);
// Same method as above, but with pendingRemovalOnly as true.
bool getBiggestClientPendingRemoval_l(int pid, MediaResource::Type type,
- MediaResource::SubType subType, uid_t& uid,
- std::shared_ptr<IResourceManagerClient> *client);
+ MediaResource::SubType subType, uid_t& uid,
+ std::shared_ptr<IResourceManagerClient>* client);
+ // A helper function that returns true if the callingPid has higher priority than pid.
+ // Returns false otherwise.
bool isCallingPriorityHigher_l(int callingPid, int pid);
- // A helper function basically calls getLowestPriorityBiggestClient_l and add
+ // A helper function basically calls getLowestPriorityBiggestClient_l and adds
// the result client to the given Vector.
- void getClientForResource_l(int callingPid, const MediaResourceParcel *res,
- PidUidVector* idList,
- std::vector<std::shared_ptr<IResourceManagerClient>>* clients);
+ void getClientForResource_l(const ResourceRequestInfo& resourceRequestInfo,
+ std::vector<ClientInfo>& clientsInfo);
void onFirstAdded(const MediaResourceParcel& res, const ResourceInfo& clientInfo);
void onLastRemoved(const MediaResourceParcel& res, const ResourceInfo& clientInfo);
@@ -188,9 +213,14 @@
void removeProcessInfoOverride_l(int pid);
void pushReclaimAtom(const ClientInfoParcel& clientInfo,
- const std::vector<std::shared_ptr<IResourceManagerClient>>& clients,
- const PidUidVector& idList, bool reclaimed);
+ const std::vector<ClientInfo>& targetClients,
+ bool reclaimed);
+ // The following utility functions are used only for testing by ResourceManagerServiceTest
+ // Gets lowest priority process that has the specified resource type.
+ // Returns false if failed. The output parameters will remain unchanged if failed.
+ bool getLowestPriorityPid_l(MediaResource::Type type, MediaResource::SubType subType,
+ int* lowestPriorityPid, int* lowestPriority);
// Get the peak concurrent pixel count (associated with the video codecs) for the process.
long getPeakConcurrentPixelCount(int pid) const;
// Get the current concurrent pixel count (associated with the video codecs) for the process.
diff --git a/services/mediaresourcemanager/ResourceObserverService.cpp b/services/mediaresourcemanager/ResourceObserverService.cpp
index 6c5cecf..72e249f 100644
--- a/services/mediaresourcemanager/ResourceObserverService.cpp
+++ b/services/mediaresourcemanager/ResourceObserverService.cpp
@@ -41,7 +41,8 @@
};
static MediaObservableType getObservableType(const MediaResourceParcel& res) {
- if (res.subType == MediaResourceSubType::kVideoCodec) {
+ if (res.subType == MediaResourceSubType::kHwVideoCodec ||
+ res.subType == MediaResourceSubType::kSwVideoCodec) {
if (res.type == MediaResourceType::kNonSecureCodec) {
return MediaObservableType::kVideoNonSecureCodec;
}
diff --git a/services/mediaresourcemanager/aidl/android/media/ClientConfigParcel.aidl b/services/mediaresourcemanager/aidl/android/media/ClientConfigParcel.aidl
index 3c9c8c7..85f1970 100644
--- a/services/mediaresourcemanager/aidl/android/media/ClientConfigParcel.aidl
+++ b/services/mediaresourcemanager/aidl/android/media/ClientConfigParcel.aidl
@@ -33,33 +33,29 @@
/**
* Type of codec (Audio/Video/Image).
*/
- MediaResourceSubType codecType;
+ MediaResourceSubType codecType = MediaResourceSubType.kUnspecifiedSubType;
/**
* true if this is an encoder, false if this is a decoder.
*/
- boolean isEncoder;
-
- /**
- * true if this is hardware codec, false otherwise.
- */
- boolean isHardware;
+ boolean isEncoder = false;
/*
* Video Resolution of the codec when it was configured, as width and height (in pixels).
*/
- int width;
- int height;
+ int width = 0;
+ int height = 0;
/*
* Timestamp (in microseconds) when this configuration is created.
*/
- long timeStamp;
+ long timeStamp = 0;
+
/*
* ID associated with the Codec.
* This will be used by the metrics:
* - Associate MediaCodecStarted with MediaCodecStopped Atom.
* - Correlate MediaCodecReported Atom for codec configuration parameters.
*/
- long id;
+ long id = 0;
}
diff --git a/services/mediaresourcemanager/aidl/android/media/MediaResourceParcel.aidl b/services/mediaresourcemanager/aidl/android/media/MediaResourceParcel.aidl
index b0f2b71..6f180e9 100644
--- a/services/mediaresourcemanager/aidl/android/media/MediaResourceParcel.aidl
+++ b/services/mediaresourcemanager/aidl/android/media/MediaResourceParcel.aidl
@@ -25,18 +25,15 @@
* {@hide}
*/
parcelable MediaResourceParcel {
- // TODO: default enum value is not supported yet.
- // Set default enum value when b/142739329 is fixed.
-
/**
* Type of the media resource.
*/
- MediaResourceType type;// = MediaResourceTypeEnum::kUnspecified;
+ MediaResourceType type = MediaResourceType.kUnspecified;
/**
* Sub-type of the media resource.
*/
- MediaResourceSubType subType;// = MediaResourceSubTypeEnum::kUnspecifiedSubType;
+ MediaResourceSubType subType = MediaResourceSubType.kUnspecifiedSubType;
/**
* Identifier of the media resource (eg. Drm session id).
diff --git a/services/mediaresourcemanager/aidl/android/media/MediaResourceSubType.aidl b/services/mediaresourcemanager/aidl/android/media/MediaResourceSubType.aidl
index 72a0551..311b6c3 100644
--- a/services/mediaresourcemanager/aidl/android/media/MediaResourceSubType.aidl
+++ b/services/mediaresourcemanager/aidl/android/media/MediaResourceSubType.aidl
@@ -24,7 +24,10 @@
@Backing(type="int")
enum MediaResourceSubType {
kUnspecifiedSubType = 0,
- kAudioCodec = 1,
- kVideoCodec = 2,
- kImageCodec = 3,
+ kHwAudioCodec = 1,
+ kSwAudioCodec = 2,
+ kHwVideoCodec = 3,
+ kSwVideoCodec = 4,
+ kHwImageCodec = 5,
+ kSwImageCodec = 6,
}
diff --git a/services/mediaresourcemanager/aidl/android/media/MediaResourceType.aidl b/services/mediaresourcemanager/aidl/android/media/MediaResourceType.aidl
index b2bb71b..353e59c 100644
--- a/services/mediaresourcemanager/aidl/android/media/MediaResourceType.aidl
+++ b/services/mediaresourcemanager/aidl/android/media/MediaResourceType.aidl
@@ -24,10 +24,13 @@
@Backing(type="int")
enum MediaResourceType {
kUnspecified = 0,
+ // Codec resource type as secure or unsecure
kSecureCodec = 1,
kNonSecureCodec = 2,
+ // Other Codec resource types understood by the frameworks
kGraphicMemory = 3,
kCpuBoost = 4,
kBattery = 5,
+ // DRM Session resource type
kDrmSession = 6,
}
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index ae3faea..7452275 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -28,32 +28,32 @@
private:
static MediaResource createSecureVideoCodecResource(int amount = 1) {
return MediaResource(MediaResource::Type::kSecureCodec,
- MediaResource::SubType::kVideoCodec, amount);
+ MediaResource::SubType::kHwVideoCodec, amount);
}
static MediaResource createNonSecureVideoCodecResource(int amount = 1) {
return MediaResource(MediaResource::Type::kNonSecureCodec,
- MediaResource::SubType::kVideoCodec, amount);
+ MediaResource::SubType::kHwVideoCodec, amount);
}
static MediaResource createSecureAudioCodecResource(int amount = 1) {
return MediaResource(MediaResource::Type::kSecureCodec,
- MediaResource::SubType::kAudioCodec, amount);
+ MediaResource::SubType::kHwAudioCodec, amount);
}
static MediaResource createNonSecureAudioCodecResource(int amount = 1) {
return MediaResource(MediaResource::Type::kNonSecureCodec,
- MediaResource::SubType::kAudioCodec, amount);
+ MediaResource::SubType::kHwAudioCodec, amount);
}
static MediaResource createSecureImageCodecResource(int amount = 1) {
return MediaResource(MediaResource::Type::kSecureCodec,
- MediaResource::SubType::kImageCodec, amount);
+ MediaResource::SubType::kHwImageCodec, amount);
}
static MediaResource createNonSecureImageCodecResource(int amount = 1) {
return MediaResource(MediaResource::Type::kNonSecureCodec,
- MediaResource::SubType::kImageCodec, amount);
+ MediaResource::SubType::kHwImageCodec, amount);
}
static MediaResource createGraphicMemoryResource(int amount = 1) {
@@ -272,13 +272,15 @@
// test adding new types (including types that differs only in subType)
resources11.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
- resources11.push_back(MediaResource(MediaResource::Type::kSecureCodec, MediaResource::SubType::kVideoCodec, 1));
+ resources11.push_back(MediaResource(MediaResource::Type::kSecureCodec,
+ MediaResource::SubType::kHwVideoCodec, 1));
mService->addResource(client1Info, mTestClient1, resources11);
expected.clear();
expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, 2));
expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
- expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, MediaResource::SubType::kVideoCodec, 1));
+ expected.push_back(MediaResource(MediaResource::Type::kSecureCodec,
+ MediaResource::SubType::kHwVideoCodec, 1));
expected.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 500));
expectEqResourceInfo(infos1.at(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
}
@@ -476,21 +478,25 @@
void testGetAllClients() {
addResource();
- MediaResource::Type type = MediaResource::Type::kSecureCodec;
- MediaResource::SubType subType = MediaResource::SubType::kUnspecifiedSubType;
- std::vector<std::shared_ptr<IResourceManagerClient> > clients;
- PidUidVector idList;
- EXPECT_FALSE(mService->getAllClients_l(kLowPriorityPid, type, subType, &idList, &clients));
+ std::vector<ClientInfo> targetClients;
+ MediaResource resource(MediaResource::Type::kSecureCodec,
+ MediaResource::SubType::kUnspecifiedSubType,
+ 1);
+ ResourceRequestInfo requestInfoHigh { kHighPriorityPid, &resource};
+ ResourceRequestInfo requestInfoMid { kMidPriorityPid, &resource};
+ ResourceRequestInfo requestInfoLow { kLowPriorityPid, &resource};
+
+ EXPECT_FALSE(mService->getAllClients_l(requestInfoLow, targetClients));
// some higher priority process (e.g. kTestPid2) owns the resource, so getAllClients_l
// will fail.
- EXPECT_FALSE(mService->getAllClients_l(kMidPriorityPid, type, subType, &idList, &clients));
- EXPECT_TRUE(mService->getAllClients_l(kHighPriorityPid, type, subType, &idList, &clients));
+ EXPECT_FALSE(mService->getAllClients_l(requestInfoMid, targetClients));
+ EXPECT_TRUE(mService->getAllClients_l(requestInfoHigh, targetClients));
- EXPECT_EQ(2u, clients.size());
+ EXPECT_EQ(2u, targetClients.size());
// (OK to require ordering in clients[], as the pid map is sorted)
- EXPECT_EQ(mTestClient3, clients[0]);
- EXPECT_EQ(mTestClient1, clients[1]);
+ EXPECT_EQ(mTestClient3, targetClients[0].mClient);
+ EXPECT_EQ(mTestClient1, targetClients[1].mClient);
}
void testReclaimResourceSecure() {
@@ -754,23 +760,22 @@
}
void testGetLowestPriorityBiggestClient() {
- MediaResource::Type type = MediaResource::Type::kGraphicMemory;
- MediaResource::SubType subType = MediaResource::SubType::kUnspecifiedSubType;
- std::shared_ptr<IResourceManagerClient> client;
- PidUidVector idList;
- EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(kHighPriorityPid, type, subType,
- &idList, &client));
+ ClientInfo clientInfo;
+ MediaResource resource(MediaResource::Type::kGraphicMemory,
+ MediaResource::SubType::kUnspecifiedSubType,
+ 1);
+ ResourceRequestInfo requestInfoHigh { kHighPriorityPid, &resource};
+ ResourceRequestInfo requestInfoLow { kLowPriorityPid, &resource};
+ EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(requestInfoHigh, clientInfo));
addResource();
- EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(kLowPriorityPid, type, subType,
- &idList, &client));
- EXPECT_TRUE(mService->getLowestPriorityBiggestClient_l(kHighPriorityPid, type, subType,
- &idList, &client));
+ EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(requestInfoLow, clientInfo));
+ EXPECT_TRUE(mService->getLowestPriorityBiggestClient_l(requestInfoHigh, clientInfo));
// kTestPid1 is the lowest priority process with MediaResource::Type::kGraphicMemory.
// mTestClient1 has the largest MediaResource::Type::kGraphicMemory within kTestPid1.
- EXPECT_EQ(mTestClient1, client);
+ EXPECT_EQ(mTestClient1, clientInfo.mClient);
}
void testGetLowestPriorityPid() {
@@ -811,7 +816,8 @@
// new client request should cause VIDEO_ON
std::vector<MediaResourceParcel> resources1;
- resources1.push_back(MediaResource(MediaResource::Type::kBattery, MediaResource::SubType::kVideoCodec, 1));
+ resources1.push_back(MediaResource(MediaResource::Type::kBattery,
+ MediaResource::SubType::kHwVideoCodec, 1));
ClientInfoParcel client1Info{.pid = static_cast<int32_t>(kTestPid1),
.uid = static_cast<int32_t>(kTestUid1),
.id = getId(mTestClient1),
@@ -826,7 +832,8 @@
// new client request should cause VIDEO_ON
std::vector<MediaResourceParcel> resources2;
- resources2.push_back(MediaResource(MediaResource::Type::kBattery, MediaResource::SubType::kVideoCodec, 2));
+ resources2.push_back(MediaResource(MediaResource::Type::kBattery,
+ MediaResource::SubType::kHwVideoCodec, 2));
ClientInfoParcel client2Info{.pid = static_cast<int32_t>(kTestPid2),
.uid = static_cast<int32_t>(kTestUid2),
.id = getId(mTestClient2),
@@ -1372,9 +1379,9 @@
int64_t id,
const ClientInfoParcel& clientInfo,
ClientConfigParcel& clientConfig) {
- clientConfig.codecType = MediaResource::SubType::kVideoCodec;
+ clientConfig.codecType = hw? MediaResource::SubType::kHwVideoCodec :
+ MediaResource::SubType::kSwVideoCodec;
clientConfig.isEncoder = encoder;
- clientConfig.isHardware = hw;
clientConfig.width = width;
clientConfig.height = height;
clientConfig.timeStamp = systemTime(SYSTEM_TIME_MONOTONIC) / 1000LL;
diff --git a/services/mediaresourcemanager/test/ResourceObserverService_test.cpp b/services/mediaresourcemanager/test/ResourceObserverService_test.cpp
index 85769d5..3f8ed2a 100644
--- a/services/mediaresourcemanager/test/ResourceObserverService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceObserverService_test.cpp
@@ -118,22 +118,22 @@
static MediaResource createSecureVideoCodecResource(int amount = 1) {
return MediaResource(MediaResource::Type::kSecureCodec,
- MediaResource::SubType::kVideoCodec, amount);
+ MediaResource::SubType::kHwVideoCodec, amount);
}
static MediaResource createNonSecureVideoCodecResource(int amount = 1) {
return MediaResource(MediaResource::Type::kNonSecureCodec,
- MediaResource::SubType::kVideoCodec, amount);
+ MediaResource::SubType::kHwVideoCodec, amount);
}
static MediaResource createSecureAudioCodecResource(int amount = 1) {
return MediaResource(MediaResource::Type::kSecureCodec,
- MediaResource::SubType::kAudioCodec, amount);
+ MediaResource::SubType::kHwAudioCodec, amount);
}
static MediaResource createNonSecureAudioCodecResource(int amount = 1) {
return MediaResource(MediaResource::Type::kNonSecureCodec,
- MediaResource::SubType::kAudioCodec, amount);
+ MediaResource::SubType::kHwAudioCodec, amount);
}
// Operators for GTest macros.