当前位置: 首页 > news >正文

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句柄,值就是我们创建的线程

http://www.dtcms.com/a/350188.html

相关文章:

  • 如何用DeepSeek让Excel数据处理自动化:告别重复劳动的智能助手
  • 面试手写 Promise:链式 + 静态方法全实现
  • 扣子智能体商业化卡在哪?井云系统自动化交易+私域管理,闭环成交全流程拆解
  • 3491定期复盘代码实现设计模式的忌假应用
  • 使用Docker配置Redis Stack集群的步骤
  • React 19 与 Next.js:利用最新 React 功能
  • SQL性能调优
  • HTTP、HTTPS 与 WebSocket 详解
  • UDS诊断案例-新能源汽车电池管理系统(BMS)诊断
  • Git提交流程与最佳实践
  • debug kernel 的一些trace的方法
  • 嵌入式Linux内核编译与配置
  • GraphRAG
  • 掌握C++ std::invoke_result_t:类型安全的函数返回值提取利器
  • VSCode远程连接阿里云ECS服务器
  • ABB机器人焊接混合气节气阀
  • Chrome GPU 加速优化配置(前端 3D 可视化 / 数字孪生专用)
  • LangChain4J-(2)-高阶API与低阶API
  • 从人工巡检到AI预警:智慧工地如何用技术重构施工安全体系
  • Dubbo3.3 Idea Maven编译命令
  • 指纹手机技术支持体系:从核心技术到场景化落地保障
  • (四十六)深度解析领域特定语言(DSL)第八章——语法分析器组合子:案例实现(Part2)
  • Spring Boot 集成 Eclipse Mosquitto
  • 2025生成式引擎优化(GEO)技术研究报告:技术演进、行业应用与服务商能力选择指南
  • 【小增长电商技术分享】电商支付宝批量转账工具技术测评:架构特性、合规风险与选型方法论,支付宝官方|小增长|云方付|易推客省心返
  • 深度学习——神经网络简单实践(在乳腺癌数据集上的小型二分类示例)
  • 深度学习入门:从概念到实战,用 PyTorch 轻松上手
  • 【科研绘图系列】R语言浮游植物生态数据的统计与可视化
  • Java 图像处理传 JNI 到 C++(OpenCV):两种高效实现方式对比
  • Element-ui icon鼠标移入显示提示(已解决)