AudioRecord一个设备只创建一个线程

Posted 迅哥儿00001

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AudioRecord一个设备只创建一个线程相关的知识,希望对你有一定的参考价值。

不要太相信方法名,尤其是那种看起来很简单的方法名。

在很多博客下面都已经讲过AudioRecord的创建流程,从android_media_AudioRecord.cpp--->AudioRecord--->AudidPolicyService--->AudioPolicyManager--->AudioFlinger

其中过程就不细讲,其中最关键的方法就是getInputForAttr()

前面的调用不提,最终会调用到AudioPolicyManager.cpp的getInputForAttr,这个方法先根据attr的source得到对应的device,然后再用这个device去获取Input,也就是AudioPolicyManager.cpp的getInputForDevice方法:


 audio_io_handle_t AudioPolicyManager::getInputForDevice(const sp<DeviceDescriptor> &device,
                                                         audio_session_t session,
                                                         const audio_attributes_t &attributes,
                                                         const audio_config_base_t *config,
                                                         audio_input_flags_t flags,
                                                         const sp<AudioPolicyMix> &policyMix)
 
     audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
     audio_source_t halInputSource = attributes.source;
     bool isSoundTrigger = false;
     // 特殊源处理(语音识别和电话等)
     if (attributes.source == AUDIO_SOURCE_HOTWORD) 
         ssize_t index = mSoundTriggerSessions.indexOfKey(session);
         if (index >= 0) 
             input = mSoundTriggerSessions.valueFor(session);
             isSoundTrigger = true;
             flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_HW_HOTWORD);
             ALOGV("SoundTrigger capture on session %d input %d", session, input);
          else 
             halInputSource = AUDIO_SOURCE_VOICE_RECOGNITION;
         
      else if (attributes.source == AUDIO_SOURCE_VOICE_COMMUNICATION &&
                audio_is_linear_pcm(config->format)) 
         flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_VOIP_TX);
     
 
     // find a compatible input profile (not necessarily identical in parameters)
     sp<IOProfile> profile;
     // sampling rate and flags may be updated by getInputProfile
     uint32_t profileSamplingRate = (config->sample_rate == 0) ?
             SAMPLE_RATE_HZ_DEFAULT : config->sample_rate;
     audio_format_t profileFormat;
     audio_channel_mask_t profileChannelMask = config->channel_mask;
     audio_input_flags_t profileFlags = flags;
     for (;;) 
         profileFormat = config->format; // reset each time through loop, in case it is updated
        // 通过采样率,采样格式等参数去和配置文件夹在的那个匹配来获取Profile
         profile = getInputProfile(device, profileSamplingRate, profileFormat, profileChannelMask,
                                   profileFlags);
         if (profile != 0) 
             break; // success
          else if (profileFlags & AUDIO_INPUT_FLAG_RAW) 
             profileFlags = (audio_input_flags_t) (profileFlags & ~AUDIO_INPUT_FLAG_RAW); // retry
          else if (profileFlags != AUDIO_INPUT_FLAG_NONE) 
             profileFlags = AUDIO_INPUT_FLAG_NONE; // retry
          else  // fail
             ALOGW("%s could not find profile for device %s, sampling rate %u, format %#x, "
                   "channel mask 0x%X, flags %#x", __func__, device->toString().c_str(),
                   config->sample_rate, config->format, config->channel_mask, flags);
             return input;
         
     
     // Pick input sampling rate if not specified by client
     uint32_t samplingRate = config->sample_rate;
     if (samplingRate == 0) 
         samplingRate = profileSamplingRate;
     
 
     if (profile->getModuleHandle() == 0) 
         ALOGE("getInputForAttr(): HW module %s not opened", profile->getModuleName());
         return input;
     
     // canOpenNewIo:能打开新的IO,加个!,就是不能打开新的IO
     if (!profile->canOpenNewIo()) 
         for (size_t i = 0; i < mInputs.size(); ) 
             sp <AudioInputDescriptor> desc = mInputs.valueAt(i);
             if (desc->mProfile != profile) 
                 i++;
                 continue;
             
             // if sound trigger, reuse input if used by other sound trigger on same session
             // else
             //    reuse input if active client app is not in IDLE state
             //
             RecordClientVector clients = desc->clientsList();
             bool doClose = false;
             for (const auto& client : clients) 
                 if (isSoundTrigger != client->isSoundTrigger()) 
                     continue;
                 
                // 语音识别直接复用
                 if (client->isSoundTrigger()) 
                     if (session == client->session()) 
                         return desc->mIoHandle;
                     
                     continue;
                 
                // 如果客户端未处于空闲状态,直接重用这个输入
                 if (client->active() && client->appState() != APP_STATE_IDLE) 
                     return desc->mIoHandle;
                 
                 doClose = true;
             
             if (doClose) 
                 closeInput(desc->mIoHandle);
              else 
                 i++;
             
         
     
     // 创建新的输入对象
     sp<AudioInputDescriptor> inputDesc = new AudioInputDescriptor(profile, mpClientInterface);
 
     audio_config_t lConfig = AUDIO_CONFIG_INITIALIZER;
     lConfig.sample_rate = profileSamplingRate;
     lConfig.channel_mask = profileChannelMask;
     lConfig.format = profileFormat;
     // 内部会调用audioFlinger来创建新的RecordThread
     status_t status = inputDesc->open(&lConfig, device, halInputSource, profileFlags, &input);
 
     // only accept input with the exact requested set of parameters
     if (status != NO_ERROR || input == AUDIO_IO_HANDLE_NONE ||
         (profileSamplingRate != lConfig.sample_rate) ||
         !audio_formats_match(profileFormat, lConfig.format) ||
         (profileChannelMask != lConfig.channel_mask)) 
         ALOGW("getInputForAttr() failed opening input: sampling rate %d"
               ", format %#x, channel mask %#x",
               profileSamplingRate, profileFormat, profileChannelMask);
         if (input != AUDIO_IO_HANDLE_NONE) 
             inputDesc->close();
         
         return AUDIO_IO_HANDLE_NONE;
     
 
     inputDesc->mPolicyMix = policyMix;
 
     addInput(input, inputDesc);
     mpClientInterface->onAudioPortListUpdate();
 
     return input;
 


===============IOProfile.h======================
 bool canOpenNewIo() 
          if (maxOpenCount == 0 || curOpenCount < maxOpenCount) 
              return true;
          
          return false;
      

IOProfile(const String8 &name, audio_port_role_t role)
          : AudioPort(name, AUDIO_PORT_TYPE_MIX, role),
            maxOpenCount(1),
            curOpenCount(0),
            maxActiveCount(1),
            curActiveCount(0) 
之前我看到canOpenNewIo以为是能否打开新的输入流,我一个设备可以打开多个输入流,所以到这一步肯定返回true,加上!就是false,我就直接略过了,琢磨了好几天还是没想通他怎么实现一个设备只有一个RecordThread的,就再次去看了下,emmmm,就是这个判断:

构造方法那写死了,最大可打开数是1,着只要打开过设备,那肯定会返回false,那第二个用这个设备的录音就肯定会进入这个判断,然后返回AudioInputDescriptor的IOhandle,然后创建一个 RecordClientDescriptor加入到AudioInputDescriptor进行管理。

再讲一下这个返回的IOhandle,它是getInputForAttr 的第二个参数,回到调用的最开始(就是AudioFlinger里面createRecord调用的那个output.inputId

用checkRecordThread_l(output.inputId)的时候就可以拿到AudioInputDescriptor里面创建的那个RecordThread

继续讲讲没啥用的后续过程:,通过checkRecordThread_l拿到RecordThread,然后创建一个RecordTrack,然后把这个track放到recordHandle里保存着,后面start的时候就可以直接对track操作,然后thread会处理这个改变后的track

以上是关于AudioRecord一个设备只创建一个线程的主要内容,如果未能解决你的问题,请参考以下文章

AudioRecord一个设备只创建一个线程

Audio子系统之AudioRecord.startRecording

Android 音视频开发:使用AudioRecord采集音频PCM并保存

非 HTC 设备的 AudioRecord 问题

Android 调用未初始化的 AudioRecord 错误

使用 AudioRecord 录制音频