Android Essay: The Connection between AudioManger and HAL

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

Guess you like

Origin blog.csdn.net/hmz0303hf/article/details/124338270