Android音频学习(十五)——打开输出流
从上节总的流程中可以看到,创建AudioPolicyManager的最后一步,是创建SwAudioOutputDescriptor对象,它关联了输出句柄,设备,流类型等重要信息。然后调用其open函数,open函数的流程分析如下:
在调用到AudioFlinger的openOutput_l()时,首先调用findSuitableHwDev_l查找上一步中调用loadHwModule_l
加载的AudioHwDevice
。如果没有module为0,则再调用loadHwModule_l重新加载
AudioHwDevice* AudioFlinger::findSuitableHwDev_l(audio_module_handle_t module,audio_devices_t deviceType)
{// if module is 0, the request comes from an old policy manager and we should load// well known modulesAutoMutex lock(mHardwareLock);if (module == 0) {ALOGW("findSuitableHwDev_l() loading well know audio hw modules");for (size_t i = 0; i < arraysize(audio_interfaces); i++) {loadHwModule_l(audio_interfaces[i]);}// then try to find a module supporting the requested device.for (size_t i = 0; i < mAudioHwDevs.size(); i++) {AudioHwDevice *audioHwDevice = mAudioHwDevs.valueAt(i);sp<DeviceHalInterface> dev = audioHwDevice->hwDevice();uint32_t supportedDevices;if (dev->getSupportedDevices(&supportedDevices) == OK &&(supportedDevices & deviceType) == deviceType) {return audioHwDevice;}}} else {// check a match for the requested module handleAudioHwDevice *audioHwDevice = mAudioHwDevs.valueFor(module);if (audioHwDevice != NULL) {return audioHwDevice;}}return NULL;
}
找到对应的AudioHwDevice后则调用其openOutputStream方法打开对应的输出流,这一步会调用到HAL层,AudioHwDevice 有一个成员变量audio_hw_device_t* const mHwDevice;数据类型audio_hw_device_t包含了一个音频接口设备所具有的属性集合。
status_t status = outHwDev->openOutputStream(&outputStream,*output,deviceType,flags,config,address.string());
AudioHwDevice.cpp
status_t status = outputStream->open(handle, deviceType, config, address);
AudioStreamOut.cpp
sp<DeviceHalInterface> AudioStreamOut::hwDev() const
{return audioHwDev->hwDevice();
}status_t AudioStreamOut::open(audio_io_handle_t handle,audio_devices_t deviceType,struct audio_config *config,const char *address)
{sp<StreamOutHalInterface> outStream;audio_output_flags_t customFlags = (config->format == AUDIO_FORMAT_IEC61937)? (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO): flags;int status = hwDev()->openOutputStream(handle,deviceType,customFlags,config,address,&outStream);
最终调用在加载设备时调用adev_open时会设定open_Output_Stream的回调函数,open_output_stream
是 HAL 实现中承上启下的关键函数,它直接与内核驱动交互,完成硬件初始化。
我们再回到AudioFlinger,在AudioFlinger的openOutput_l方法中,openOutputStream打开成功后,会为根据FLAG为其创建一个播放线程。
status_t status = outHwDev->openOutputStream(&outputStream,*output,deviceType,flags,config,address.string());mHardwareStatus = AUDIO_HW_IDLE;if (status == NO_ERROR) {if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {sp<MmapPlaybackThread> thread =new MmapPlaybackThread(this, *output, outHwDev, outputStream, mSystemReady);mMmapThreads.add(*output, thread);ALOGV("openOutput_l() created mmap playback thread: ID %d thread %p",*output, thread.get());return thread;} else {sp<PlaybackThread> thread;if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {thread = new OffloadThread(this, outputStream, *output, mSystemReady);ALOGV("openOutput_l() created offload output: ID %d thread %p",*output, thread.get());} else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT)|| !isValidPcmSinkFormat(config->format)|| !isValidPcmSinkChannelMask(config->channel_mask)) {thread = new DirectOutputThread(this, outputStream, *output, mSystemReady);ALOGV("openOutput_l() created direct output: ID %d thread %p",*output, thread.get());} else {thread = new MixerThread(this, outputStream, *output, mSystemReady);ALOGV("openOutput_l() created mixer output: ID %d thread %p",*output, thread.get());}mPlaybackThreads.add(*output, thread);mPatchPanel.notifyStreamOpened(outHwDev, *output);return thread;}}
每打开一个outputs,成功后都会为它创建一个线程,会根据其flag创建不同的线程,MmapPlaybackThread、 OffloadThread、DirectOutputThread、MixerThread等线程,最后保存到mMmapThreads和mPlaybackThreads。线程在第八章有详细讲解,请参考Android音频学习(八)——AudioFlinger线程_audioflinger thread-CSDN博客
关键就是output句柄,值就是我们创建的线程