DSP

Android N Audio: Mute Microphone流程

2019-07-13 20:25发布

  下图是通过AudioManager进行setMicrophoneMute的过程,       应用可通过AudioManager获取系统服务,再调用服务提供的接口进行mute操作,     public void setMicrophoneMute(boolean on) {         IAudioService service = getService();         try {             service.setMicrophoneMute(on, getContext().getOpPackageName(),                     UserHandle.getCallingUserId());         } catch (RemoteException e) {             throw e.rethrowFromSystemServer();         }     }     AudioManager通过AudioService,间接调用到AudioSystem.muteMicrophone,这个是native方法,  最终调用到native的AudioSystem.cpp   static jint android_media_AudioSystem_muteMicrophone(JNIEnv *env, jobject thiz, jboolean on) {     return (jint) check_AudioSystem_Command(AudioSystem::muteMicrophone(on)); }       AudioSystem.cpp通过binder,调用到AF,   status_t AudioSystem::muteMicrophone(bool state) {     const sp& af = AudioSystem::get_audio_flinger();     if (af == 0) return PERMISSION_DENIED;     return af->setMicMute(state); }       AF则轮询所有的设备,依次将其mute。   status_t AudioFlinger::setMicMute(bool state) {       for (size_t i = 0; i < mAudioHwDevs.size(); i++) {         audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();         status_t result = dev->set_mic_mute(dev, state);         if (result != NO_ERROR) {             ret = result;         }     }     mHardwareStatus = AUDIO_HW_IDLE;     return ret; }       例如,对于设备模块,下面有加载模块后给函数指针的赋值代码,也有相应的调用过程, Audio_hw.c (hardwareqcomaudiohal) static int adev_open(const hw_module_t *module, const char *name,                      hw_device_t **device) {… adev->device.set_mic_mute = adev_set_mic_mute; }   static int adev_set_mic_mute(struct audio_hw_device *dev, bool state) {     int ret;       pthread_mutex_lock(&adev->lock);     ALOGD("%s state %d ", __func__, state);     ret = voice_set_mic_mute((struct audio_device *)dev, state);     pthread_mutex_unlock(&adev->lock);       return ret; }       Voice.c(hardwareqcomaudiohal): 分在通话中和voip状态下进行mute操作。 int voice_set_mic_mute(struct audio_device *adev, bool state) {     int err = 0;       adev->voice.mic_mute = state;     if (adev->mode == AUDIO_MODE_IN_CALL)         err = platform_set_mic_mute(adev->platform, state);     if (adev->mode == AUDIO_MODE_IN_COMMUNICATION)         err = voice_extn_compress_voip_set_mic_mute(adev, state);       return err; }     Platform.c里,调用了my_data->csd->mic_mute, int platform_set_mic_mute(void *platform, bool state) {     struct platform_data *my_data = (struct platform_data *)platform;     struct audio_device *adev = my_data->adev;       if (my_data->csd != NULL) {         ret = my_data->csd->mic_mute(ALL_SESSION_VSID, state,                                      DEFAULT_MUTE_RAMP_DURATION_MS);         if (ret < 0) {             ALOGE("%s: csd_mic_mute error %d", __func__, ret);         }     } }   ALL_SESSION_VSID 表示将所有session都进行mute, #define VOICE_SESSION_VSID  0x10C01000 #define VOICE2_SESSION_VSID 0x10DC1000 #define VOLTE_SESSION_VSID  0x10C02000 #define VOWLAN_SESSION_VSID 0x10002000 #define ALL_SESSION_VSID    0xFFFFFFFF       其中, my_data是在Audio_hw.c (hardwareqcomaudiohal): adev_open()里,通过platform_init()初始的,platform即my_data,     adev->platform = platform_init(adev);   而csd的赋值,则是在platform_init()里初始,          my_data->csd = open_csd_client(my_data->is_i2s_ext_modem);   open_csd_client则是打开一个libcsd-client.so库文件,给csd的函数指针赋值,我们需要的mute就在里面, 同时open_csd_client会进行初始化csd_client_init。 static struct csd_data *open_csd_client(bool i2s_ext_modem) {     struct csd_data *csd = calloc(1, sizeof(struct csd_data));       if (!csd) {         ALOGE("failed to allocate csd_data mem");         return NULL;     }   csd->csd_client = dlopen(LIB_CSD_CLIENT, RTLD_NOW);           csd->deinit = (deinit_t)dlsym(csd->csd_client,                                              "csd_client_deinit");           csd->disable_device = (disable_device_t)dlsym(csd->csd_client,                                              "csd_client_disable_device"); …         csd->mic_mute = (mic_mute_t)dlsym(csd->csd_client,                                              "csd_client_mic_mute"); …         csd->init = (init_t)dlsym(csd->csd_client, "csd_client_init");          csd->init(i2s_ext_modem); }     csd_client_init实现在csd_client.c,它主要是初始数据,创建一个Thread,并打开一个audio_slimslave。 int csd_client_init(bool i2s_ext_modem) {       rc = initialize_client_data();       rc = csd_create_thread();   csd_client.slim_fd = open("/dev/audio_slimslave", O_RDWR); }   qmi_idl_lib_internal.h         再回到csd_client_mic_mute,它就是通过set_stream_mute给qmi发送一个QMI_CSD_IOCTL_VS_CMD_SET_MUTE_REQ_V01请求消息,具体mute通话的过程则由modem来完成。 int csd_client_mic_mute(uint32_t vsid, int mute, uint16_t ramp_duration) {       iterator_init(&it, sessionid);     while (iterator_has_next(&it)) {         iterator_next(&it, &service, &session);               if ((session->state == SESSION_STARTED ||                  session->state == SESSION_STANDBY) &&                 (session->lch_mode == VOICE_LCH_STOP)) {                 rc = set_stream_mute(service, session, mute,                                      ramp_duration);                 if (rc < 0) {                     LOGE("%s: Error %d setting mic mute on session %s ",                          __func__, rc, session->name);                 }           }     }   可以看出,android在处理audio的时候,仅仅是通话音频通道的mute,并没有由telephony简单的调用qmi来完成,而是绕了很大一个弯。这样设计的目的,是为了保持模块的一致性,采用通用框架,更好维护和管理,但在效率上则大打折扣。