Preface
Recently I am working on a sound effect function to modify some parameters of the audio device through an app. At this time, you need to use adev_set_parameters() in audio_hw.cpp to control. In order to better realize the function, the calling and implementation process of this interface are tracked in detail.
1.AudioManager.setParameters()
This interface is exposed to the upper-layer app and is used as follows:
mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mAudioManager.setParameters("key=value");
The prototype of this function is in android/frameworks/base/media/java/android/media/AudioManager.java
/**
* Sets a variable number of parameter values to audio hardware.
*
* @param keyValuePairs list of parameters key value pairs in the form:
* key1=value1;key2=value2;...
*
*/
public void setParameters(String keys) {
AudioSystem.setParameters(keyValuePairs);
}
2. AudioSystem.setParameters()
The native interface of android/frameworks/base/media/java/android/media/AudioSystem.java is called here
/*
* Sets a group generic audio configuration parameters. The use of these parameters
* are platform dependent, see libaudio
*
* param keyValuePairs list of parameters key value pairs in the form:
* key1=value1;key2=value2;...
*/
public static native int setParameters(String keyValuePairs);
Search android_media_AudioSystem*, you can find it in android/frameworks/base/core/jni/android_media_AudioSystem.cpp
static jint
android_media_AudioSystem_setParameters(JNIEnv *env, jobject thiz, jstring keyValuePairs)
{
const jchar* c_keyValuePairs = env->GetStringCritical(keyValuePairs, 0);
String8 c_keyValuePairs8;
if (keyValuePairs) {
c_keyValuePairs8 = String8(
reinterpret_cast<const char16_t*>(c_keyValuePairs),
env->GetStringLength(keyValuePairs));
env->ReleaseStringCritical(keyValuePairs, c_keyValuePairs);
}
int status = check_AudioSystem_Command(AudioSystem::setParameters(c_keyValuePairs8));
return (jint) status;
}
3. AudioSystem::setParameters()
Continue to track, in android/frameworks/av/media/libaudioclient/AudioSystem.cpp
status_t AudioSystem::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs)
{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
return af->setParameters(ioHandle, keyValuePairs);
}
4. AudioFlinger->setParameters()
Here, through get_audio_flinger(), the call is here android/frameworks/av/services/audioflinger/AudioFlinger.cpp
1220 status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs)
1221 {
1222 ALOGV("setParameters(): io %d, keyvalue %s, calling pid %d calling uid %d",
1223 ioHandle, keyValuePairs.string(),
1224 IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid());
1225
1226 // check calling permissions
1227 if (!settingsAllowed()) {
1228 return PERMISSION_DENIED;
1229 }
1230
1231 String8 filteredKeyValuePairs = keyValuePairs;
1232 filterReservedParameters(filteredKeyValuePairs, IPCThreadState::self()->getCallingUid());
1233
1234 ALOGV("%s: filtered keyvalue %s", __func__, filteredKeyValuePairs.string());
1235
1236 // AUDIO_IO_HANDLE_NONE means the parameters are global to the audio hardware interface
1237 if (ioHandle == AUDIO_IO_HANDLE_NONE) {
1238 Mutex::Autolock _l(mLock);
1239 // result will remain NO_INIT if no audio device is present
1240 status_t final_result = NO_INIT;
1241 {
1242 AutoMutex lock(mHardwareLock);
1243 mHardwareStatus = AUDIO_HW_SET_PARAMETER;
1244 for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
1245 sp<DeviceHalInterface> dev = mAudioHwDevs.valueAt(i)->hwDevice();
1246 status_t result = dev->setParameters(filteredKeyValuePairs);
1247 // return success if at least one audio device accepts the parameters as not all
1248 // HALs are requested to support all parameters. If no audio device supports the
1249 // requested parameters, the last error is reported.
1250 if (final_result != NO_ERROR) {
1251 final_result = result;
1252 }
1253 }
1254 mHardwareStatus = AUDIO_HW_IDLE;
1255 }
1256 // disable AEC and NS if the device is a BT SCO headset supporting those pre processings
1257 AudioParameter param = AudioParameter(filteredKeyValuePairs);
1258 String8 value;
1259 if (param.get(String8(AudioParameter::keyBtNrec), value) == NO_ERROR) {
1260 bool btNrecIsOff = (value == AudioParameter::valueOff);
1261 if (mBtNrecIsOff.exchange(btNrecIsOff) != btNrecIsOff) {
1262 for (size_t i = 0; i < mRecordThreads.size(); i++) {
1263 mRecordThreads.valueAt(i)->checkBtNrec();
1264 }
1265 }
1266 }
1267 String8 screenState;
1268 if (param.get(String8(AudioParameter::keyScreenState), screenState) == NO_ERROR) {
1269 bool isOff = (screenState == AudioParameter::valueOff);
1270 if (isOff != (AudioFlinger::mScreenState & 1)) {
1271 AudioFlinger::mScreenState = ((AudioFlinger::mScreenState & ~1) + 2) | isOff;
1272 }
1273 }
1274 return final_result;
1275 }
1276
1277 // hold a strong ref on thread in case closeOutput() or closeInput() is called
1278 // and the thread is exited once the lock is released
1279 sp<ThreadBase> thread;
1280 {
1281 Mutex::Autolock _l(mLock);
1282 thread = checkPlaybackThread_l(ioHandle);
1283 if (thread == 0) {
1284 thread = checkRecordThread_l(ioHandle);
1285 if (thread == 0) {
1286 thread = checkMmapThread_l(ioHandle);
1287 }
1288 } else if (thread == primaryPlaybackThread_l()) {
1289 // indicate output device change to all input threads for pre processing
1290 AudioParameter param = AudioParameter(filteredKeyValuePairs);
1291 int value;
1292 if ((param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) &&
1293 (value != 0)) {
1294 broacastParametersToRecordThreads_l(filteredKeyValuePairs);
1295 }
1296 }
1297 }
1298 if (thread != 0) {
1299 return thread->setParameters(filteredKeyValuePairs);
1300 }
1301 return BAD_VALUE;
1302 }
Here, we will find that the smart pointer sp<DeviceHalInterface> dev is used and calls dev->setParameters .
Keep it now, you will use it later.
5. AudioFlinger
Continue to analyze AudioFlinger, first look at its constructor, which contains
mDevicesFactoryHal = DevicesFactoryHalInterface::create();
Search mDevicesFactoryHal and find that openDevice is performed in loadHwModule_l()
1795 // loadHwModule_l() must be called with AudioFlinger::mLock held
1796 audio_module_handle_t AudioFlinger::loadHwModule_l(const char *name)
1797 {
1798 for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
1799 if (strncmp(mAudioHwDevs.valueAt(i)->moduleName(), name, strlen(name)) == 0) {
1800 ALOGW("loadHwModule() module %s already loaded", name);
1801 return mAudioHwDevs.keyAt(i);
1802 }
1803 }
1804
1805 sp<DeviceHalInterface> dev;
1806
1807 int rc = mDevicesFactoryHal->openDevice(name, &dev);
1808 if (rc) {
1809 ALOGE("loadHwModule() error %d loading module %s", rc, name);
1810 return AUDIO_MODULE_HANDLE_NONE;
1811 }
1812
1813 mHardwareStatus = AUDIO_HW_INIT;
1814 rc = dev->initCheck();
1815 mHardwareStatus = AUDIO_HW_IDLE;
1816 if (rc) {
1817 ALOGE("loadHwModule() init check error %d for module %s", rc, name);
1818 return AUDIO_MODULE_HANDLE_NONE;
1819 }
1820
1821 // Check and cache this HAL's level of support for master mute and master
1822 // volume. If this is the first HAL opened, and it supports the get
1823 // methods, use the initial values provided by the HAL as the current
1824 // master mute and volume settings.
1825
1826 AudioHwDevice::Flags flags = static_cast<AudioHwDevice::Flags>(0);
1827 { // scope for auto-lock pattern
1828 AutoMutex lock(mHardwareLock);
1829
1830 if (0 == mAudioHwDevs.size()) {
1831 mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME;
1832 float mv;
1833 if (OK == dev->getMasterVolume(&mv)) {
1834 mMasterVolume = mv;
1835 }
1836
1837 mHardwareStatus = AUDIO_HW_GET_MASTER_MUTE;
1838 bool mm;
1839 if (OK == dev->getMasterMute(&mm)) {
1840 mMasterMute = mm;
1841 }
1842 }
1843
1844 mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
1845 if (OK == dev->setMasterVolume(mMasterVolume)) {
1846 flags = static_cast<AudioHwDevice::Flags>(flags |
1847 AudioHwDevice::AHWD_CAN_SET_MASTER_VOLUME);
1848 }
1849
1850 mHardwareStatus = AUDIO_HW_SET_MASTER_MUTE;
1851 if (OK == dev->setMasterMute(mMasterMute)) {
1852 flags = static_cast<AudioHwDevice::Flags>(flags |
1853 AudioHwDevice::AHWD_CAN_SET_MASTER_MUTE);
1854 }
1855
1856 mHardwareStatus = AUDIO_HW_IDLE;
1857 }
1858
1859 audio_module_handle_t handle = (audio_module_handle_t) nextUniqueId(AUDIO_UNIQUE_ID_USE_MODULE);
1860 mAudioHwDevs.add(handle, new AudioHwDevice(handle, name, dev, flags));
1861
1862 ALOGI("loadHwModule() Loaded %s audio interface, handle %d", name, handle);
1863
1864 return handle;
1865
1866 }
As you can imagine, the audio device is associated through it
6. DevicesFactoryHalInterface
Continue to track, android/frameworks/av/media/libaudiohal/DevicesFactoryHalInterface.cpp
sp<DevicesFactoryHalInterface> DevicesFactoryHalInterface::create() {
if (hardware::audio::V4_0::IDevicesFactory::getService() != nullptr) {
return new V4_0::DevicesFactoryHalHybrid();
}
if (hardware::audio::V2_0::IDevicesFactory::getService() != nullptr) {
return new DevicesFactoryHalHybrid();
}
return nullptr;
}
Different instances will be returned according to different HW versions. Android 9.0 uses version 4.0.
7. DevicesFactoryHalHybrid
Look down, android/frameworks/av/media/libaudiohal/4.0/DevicesFactoryHalHybrid.cpp
DevicesFactoryHalHybrid::DevicesFactoryHalHybrid()
: mLocalFactory(new DevicesFactoryHalLocal()),
mHidlFactory(new DevicesFactoryHalHidl()) {
}
DevicesFactoryHalHybrid::~DevicesFactoryHalHybrid() {
}
status_t DevicesFactoryHalHybrid::openDevice(const char *name, sp<DeviceHalInterface> *device) {
if (mHidlFactory != 0 && strcmp(AUDIO_HARDWARE_MODULE_ID_A2DP, name) != 0 &&
strcmp(AUDIO_HARDWARE_MODULE_ID_HEARING_AID, name) != 0) {
return mHidlFactory->openDevice(name, device);
}
return mLocalFactory->openDevice(name, device);
}
There are two objects in the constructor here. When openDevice(), one of the two objects will be selected based on the name. AUDIO_HARDWARE_MODULE_ID_A2DP query found that it is in AudioFlinger
static const char * const audio_interfaces[] = {
AUDIO_HARDWARE_MODULE_ID_PRIMARY,
AUDIO_HARDWARE_MODULE_ID_A2DP,
AUDIO_HARDWARE_MODULE_ID_USB,
};
Judging from the name, A2DP is related to Bluetooth, USB is a USB flash drive, and PRIMARY is used in other common situations.
In other words, under normal circumstances, the mHidlFactory process is followed.
8. DevicesFactoryHalHidl
Continue reading, android/frameworks/av/media/libaudiohal/4.0/DevicesFactoryHalHidl.cpp
55 status_t DevicesFactoryHalHidl::openDevice(const char *name, sp<DeviceHalInterface> *device) {
56 if (mDevicesFactory == 0) return NO_INIT;
57 Result retval = Result::NOT_INITIALIZED;
58 Return<void> ret = mDevicesFactory->openDevice(
59 name,
60 [&](Result r, const sp<IDevice>& result) {
61 retval = r;
62 if (retval == Result::OK) {
63 *device = new DeviceHalHidl(result);
64 }
65 });
66 if (ret.isOk()) {
67 if (retval == Result::OK) return OK;
68 else if (retval == Result::INVALID_ARGUMENTS) return BAD_VALUE;
69 else return NO_INIT;
70 }
71 return FAILED_TRANSACTION;
72 }
mDevicesFactory is used here. Search up in this file and find that it is in the constructor.
mDevicesFactory = IDevicesFactory::getService();
This is a binder interface
9. DevicesFactory.impl.h
Continue to pursue, and found in android/hardware/interfaces/audio/core/all-versions/default/include/core/all-versions/default/DevicesFactory.impl.h, this is a public interface
Return<void> DevicesFactory::openDevice(const hidl_string& moduleName, openDevice_cb _hidl_cb) {
if (moduleName == AUDIO_HARDWARE_MODULE_ID_PRIMARY) {
return openDevice<PrimaryDevice>(moduleName.c_str(), _hidl_cb);
}
return openDevice(moduleName.c_str(), _hidl_cb);
}
In point 7 of this article, we speculate that under normal circumstances, PRIMARY is used, so the template class follows the process. The following is its private implementation.
Return<void> DevicesFactory::openDevice(const char* moduleName, openDevice_cb _hidl_cb) {
return openDevice<implementation::Device>(moduleName, _hidl_cb);
}
template <class DeviceShim, class Callback>
Return<void> DevicesFactory::openDevice(const char* moduleName, Callback _hidl_cb) {
audio_hw_device_t* halDevice;
Result retval(Result::INVALID_ARGUMENTS);
sp<DeviceShim> result;
int halStatus = loadAudioInterface(moduleName, &halDevice);
if (halStatus == OK) {
result = new DeviceShim(halDevice);
retval = Result::OK;
} else if (halStatus == -EINVAL) {
retval = Result::NOT_INITIALIZED;
}
_hidl_cb(retval, result);
return Void();
}
The main thing is to call loadAudioInterface and then return the PrimaryDevice object
80 int DevicesFactory::loadAudioInterface(const char* if_name, audio_hw_device_t** dev) {
81 const hw_module_t* mod;
82 int rc;
83
84 rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod);
85 if (rc) {
86 ALOGE("%s couldn't load audio hw module %s.%s (%s)", __func__, AUDIO_HARDWARE_MODULE_ID,
87 if_name, strerror(-rc));
88 goto out;
89 }
90 rc = audio_hw_device_open(mod, dev);
91 if (rc) {
92 ALOGE("%s couldn't open audio hw device in %s.%s (%s)", __func__, AUDIO_HARDWARE_MODULE_ID,
93 if_name, strerror(-rc));
94 goto out;
95 }
96 if ((*dev)->common.version < AUDIO_DEVICE_API_VERSION_MIN) {
97 ALOGE("%s wrong audio hw device version %04x", __func__, (*dev)->common.version);
98 rc = -EINVAL;
99 audio_hw_device_close(*dev);
100 goto out;
101 }
102 return OK;
103
104 out:
105 *dev = NULL;
106 return rc;
107 }
Here we get dev from the Hal layer, which is a PrimaryDevice object.
10. PrimaryDevice.impl.h
Continue to analyze, android/hardware/interfaces/audio/core/all-versions/default/include/core/all-versions/default/PrimaryDevice.impl.h
dev is obtained, then we return to point 4 dev->setParameters, then it should be
Return<Result> PrimaryDevice::setParameters(const hidl_vec<ParameterValue>& context,
const hidl_vec<ParameterValue>& parameters) {
return mDevice->setParameters(context, parameters);
}
What is mDevice here? Let’s look up at the constructor.
PrimaryDevice::PrimaryDevice(audio_hw_device_t* device) : mDevice(new Device(device)) {}
We can't stop here yet
11. Device.impl.h
Continue to check, android/hardware/interfaces/audio/core/all-versions/default/include/core/all-versions/default/Device.impl.h, there is nothing special about the constructor here
Device::Device(audio_hw_device_t* device) : mDevice(device) {}
Let’s look at its setParameters
Return<Result> Device::setParameters(const hidl_vec<ParameterValue>& context,
const hidl_vec<ParameterValue>& parameters) {
return setParametersImpl(context, parameters);
}
12. ParametersUtil.impl.h
继续追踪,android/hardware/interfaces/audio/core/all-versions/default/include/core/all-versions/default/ParametersUtil.impl.h
139 Result ParametersUtil::setParametersImpl(const hidl_vec<ParameterValue>& context,
140 const hidl_vec<ParameterValue>& parameters) {
141 AudioParameter params;
142 for (auto& pair : context) {
143 params.add(String8(pair.key.c_str()), String8(pair.value.c_str()));
144 }
145 for (size_t i = 0; i < parameters.size(); ++i) {
146 params.add(String8(parameters[i].key.c_str()), String8(parameters[i].value.c_str()));
147 }
148 return setParams(params);
149 }
156 Result ParametersUtil::setParams(const AudioParameter& param) {
157 int halStatus = halSetParameters(param.toString().string());
158 return util::analyzeStatus(halStatus);
159 }
13. Device.impl.h
Back here again
59 int Device::halSetParameters(const char* keysAndValues) {
60 return mDevice->set_parameters(mDevice, keysAndValues);
61 }
It can be seen that the final call is set_parameters in audio_hw_device_t
14. audio_hw_device
Found this structure in android/hardware/libhardware/include/hardware/audio.h
typedef struct audio_hw_device audio_hw_device_t;
So where are the members in this structure assigned?
15. audio_hw
Found here in android/vendor/mediatek/proprietary_tv/open/hardware/audio/audio_hw_7_0/audio_hw.cpp when adev_open()
adev->device.set_parameters = adev_set_parameters;
adev->device.get_parameters = adev_get_parameters;
Then, the place where HAL is finally implemented is found