声音管理系统用来实现声音的输入和输出、声音的控制和路由等功能,包括主和各种音源的音量调节、声音焦点控制,声音外设的检测和状态管理,声音源输入和输出的策略管理、音效的播放、音轨设置和播放、录音设置和启动等功能。

整个声音管理系统相关类图如下:主要由JAVA端的系统服务AudioService及两个本地服务声音输入输出策略管理服务AudioPolicyService及声音输出投射服务AudioFlinger来实现相关功能。

应用主要通过AudioManage接口来使用AudioService提供的服务。系统服务AudioService与两个本地服务之间通过AudioSystem类提供的接口借助JNI进行交互。

系统服务AudioService使用蓝牙监听对象BluetoothProfile.ServiceListener来监听蓝牙框架服务HeadsetProfile及HeadsetProfile的连接,并获得两个蓝牙框架服务的客户端对象BluetoothHeadset和BluetoothA2dp来与对应的蓝牙框架服务实现交互。使用一个AudioServiceBroadcastReceiver广播接收对象来监听基座状态事件、蓝牙连接状态改变事件、外设插拔事件、声音状态改变事件、屏幕打开关闭事件、配置改变事件、用户切换事件等事件并进行相应处理。

当检测到需要切换声音路由时,由相关应用通过AudioManage接口调用AudioService系统服务提供的setWiredDeviceConnectionState、setBluetoothA2dpDeviceConnectionState()接口来发起或AudioService系统服务本身检测到相关的事件来触发媒体路由切换,并通过IAudioRoutesObserver接口调用dispatchAudioRoutesChanged()函数来通知媒体路由切换相关进程和服务进行相应处理。

声音焦点控制主要有AudioService系统服务提供的MediaFocusControl对象进行控制。声音焦点控制实现同时只有一个应用能够获得焦点播放同种类型的声音,ANDROID提供和支持STREAM_VOICE_CALL(电话呼叫)、STREAM_SYSTEM(系统)、STREAM_RING(振铃和消息提示)、STREAM_MUSIC(音乐媒体播放)、STREAM_ALARM(警报声)、STREAM_NOTIFICATION(通知音)、STREAM_BLUETOOTH_SCO(蓝牙电话)、STREAM_SYSTEM_ENFORCED(强制系统声音)、STREAM_DTMF(DTMF拨号音)及STREAM_TTS(文本识别音)九种声音流类型,每种类型可以独立的调节声音大小,其中除了STREAM_MUSIC类型是应用播放媒体使用的类型外其它都是系统要处理的声音类型。MediaFocusControl对象的相关类图如下:

本地服务AudioPolicyService提供不同声音流类型对应的输入输出设备的策略获取及策略的选择和控制(输入输出选择、输入输出设备的打开和停止、关闭等)、设置和获取声音设备的连接状态以及不同流类型对应的设备的音量的设置和获取、音频参数的设置、音效设置等功能。类图如下:

AudioPolicyService有一个内部线程类AudioCommandThread,顾名思义,所有的命令(音量控制,输入、输出的切换等)最终都会在该线程中排队执行;

在AudioPolicyService实例化时调用audio_policy_dev_open函数打开一个声音策略设备,并通过声音策略设备的create_audio_policy接口返回一个audio_policy策略函数结构体指针,AudioPolicyService对应的函数通过这个audio_policy函数结构体指针调用声音策略设备的对应函数实现设备的策略控制,在AudioPolicyService调用create_audio_policy函数时也把AudioPolicyService内部的一个audio_policy_service_ops函数结构体传给声音策略设备对象,供声音策略设备对象内部调用。声音策略设备使用create_audio_policy函数除了为audio_policy策略函数结构体函数指针赋值以外,还实例了两个对象,一个AudioPolicyClientInterface对象,作为AudioPolicyService客户端使用,声音策略设备使用AudioPolicyClientInterface对象通过AudioPolicyService的内部接口audio_policy_service_op调用AudioPolicyService的相关函数;另外一个对象为具体的实现相关声音策略接口的AudioPolicyInterface对象,这里采用的是设计模式的策略模式,这也是AudioPolicyService称为声音策略服务的原因吧,
AudioPolicyInterface接口的具体实例的创建采用了工厂方法。

下面以AudioPolicyService的getInput函数为例子具体说明整个调用流程。AudioPolicyService的getInput函数实现根据函数传进来的声音输入类型、采样率、声音格式、通道掩码参数打开一个输入设备,整个流程为:

  1. AudioPolicyService的getInput首先通过create_audio_policy获得的audio_policy函数结构体指针调用其get_input函数;

  2. get_input函数然后调用create_audio_policy内部采用工厂方法createAudioPolicyManager创建的具体AudioPolicyInterface对象的getInput函数。

  3. AudioPolicyInterface对象的getInput函数内部首先调用getDeviceForInputSource函数根据函数传进来的输入源类型获得对应的audio_devices_t设备类型,然后调用getInputProfile函数根据传进来的声音采样率、声音格式、通道掩码等参数与获得的设备支持的Input
    Profile比较返回一个与设备Profile匹配的IOProfile,然后根据返回的IOProfile对象构造一个AudioInputDescriptor对象添加到输入描述数组中,并调用create_audio_policy内部创建的一个具体AudioPolicyClientInterface对象的openInput函数;

  4. AudioPolicyClientInterface对象的openInput函数调用AudioPolicyService内部audio_policy_service_op函数结构体的open_input_on_module函数;

  5. audio_policy_service_op函数结构体的open_input_on_module函数指针指向AudioPolicyService的aps_open_input_on_module函数,因此调用aps_open_input_on_module,aps_open_input_on_module内部首先AudioSystem类的get_audio_flinger函数获得IAudioFlinger接口,然后通过IAudioFlinger接口调用AudioFlinger服务的openInput函数,打开选择的输入设备,返回AudioPolicyService的getInput函数一个audio_io_handle_t句柄;

AudioPolicyService的getInput函数接着根据传进来的audioSession参数构造一个InputDesc对象,把getInput函数返回的audio_io_handle_t句柄添加到向量数组中,根据输入源类型从支持的输入源向量列表获得该输入源支持的EffectDesc数组,并对每一个EffectDesc根据EffectDesc的Uuid、返回的audio_io_handle_t句柄及audioSession参数实例化一个AudioEffect对象,并调用AudioEffect对象的setParameter函数为每一个EffectDesc设置声音参数。每个AudioEffect对象也添加到InputDesc对象AudioEffect的数组中。完成整个流程。

版权所有,转载时请尊重原创显要处注明链接,谢谢!

第十七篇 --ANDROID DisplayManager 服务解析一 







第十八篇 ANDROID的声音管理系统及服务的更多相关文章

  1. Python之路【第十八篇】:Web框架们

    Python之路[第十八篇]:Web框架们   Python的WEB框架 Bottle Bottle是一个快速.简洁.轻量级的基于WSIG的微型Web框架,此框架只由一个 .py 文件,除了Pytho ...

  2. Egret入门学习日记 --- 第十八篇(书中 8.5~8.7 节 内容)

    第十八篇(书中 8.5~8.7 节 内容) 其实语法篇,我感觉没必要写录入到日记里. 我也犹豫了好久,到底要不要录入. 这样,我先读一遍语法篇的所有内容,我觉得值得留下的,我就录入日记里. 不然像昨天 ...

  3. Android UI开发第二十八篇——Fragment中使用左右滑动菜单

    Fragment实现了Android UI的分片管理,尤其在平板开发中,好处多多.这一篇将借助Android UI开发第二十六篇——Fragment间的通信. Android UI开发第二十七篇——实 ...

  4. Android高手进阶教程(二十八)之---Android ViewPager控件的使用(基于ViewPager的横向相册)!!!

      分类: Android高手进阶 Android基础教程 2012-09-14 18:10 29759人阅读 评论(35) 收藏 举报 android相册layoutobjectclassloade ...

  5. Android笔记(五十八)Android总结:四大组件——Activity篇

    什么是Activity Activity是一种包含用户界面的组件,主要用于和用户进行交互,一个APP通常由多个Activity组成. 每个Activity都对应一个布局文件,通过setContentV ...

  6. Python开发【第十八篇】Web框架之Django【基础篇】

    一.简介 Python下有许多款不同的 Web 框架,Django 是重量级选手中最有代表性的一位,许多成功的网站和APP都基于 Django. Django 是一个开放源代码的Web应用框架,由 P ...

  7. 十八、Android引导界面

    一.所需素材 很有必要整理一下,里面附带友盟的社会化分享组件,我就不去掉了. 二.代码 import com.umeng.update.UmengUpdateAgent; import android ...

  8. 第五十八篇、iOS 微信聊天发送小视频的秘密

    对于播放视频,大家应该一开始就想到比较方便快捷使用简单的MPMoviePlayerController类,确实用这个苹果官方为我们包装好了的 API 确实有很多事情都不用我们烦心,我们可以很快的做出一 ...

  9. python【第十八篇】Django基础

    1.什么是Django? Django是一个Python写成的开源Web应用框架.python流行的web框架还有很多,如tornado.flask.web.py等.django采用了MVC的框架模式 ...

随机推荐

  1. 物料分类新增&更新

    --新增 INV_ITEM_CATEGORY_PUB.Create_Category ( p_api_version IN NUMBER, p_init_msg_list IN VARCHAR2 DE ...

  2. AR模块常用函数

    --AR模块常用函数 FUNCTION get_fnd_user_name ( p_user_id IN NUMBER ) return VARCHAR2 IS CURSOR c_user_name ...

  3. SpriteKit中的共享动作(Sharing Actions)

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 在SpriteKit中某些动作需要一些额外的延时,如果每次都重 ...

  4. [tornado]使用webscoket的使用总是403错误

    使用的tornado版本为4.0+ 后台: PS D:\CodeHouse\tornado\websocket> python .\ws_app.py WARNING:tornado.acces ...

  5. 剑指offer面试题5 从头到尾打印链表(c)

  6. const引用

    在C++中可以声明const引用 const Type& name = var: const引用让变量拥有只读属性 const int &a = b const int &a ...

  7. Uva - 1593 - Alignment of Code

    直接用<iomanip>的格式输出,setw设置输出宽度,setiosflags(ios::left)进行左对齐. AC代码: #include <iostream> #inc ...

  8. android官方技术文档翻译——Android Lint

    本文译自androd官方技术文档<Android Lint>,原文地址:http://tools.android.com/tips/lint. 本文地址:http://blog.csdn. ...

  9. HEVC,VP9,x264性能对比

    Dan Grois等人在论文<Performance Comparison of H.265/MPEG-HEVC, VP9, andH.264/MPEG-AVC Encoders>中,比较 ...

  10. 学习pthreads,使用条件变量进行多线程之间的同步

    条件变量提供另一种多线程同步的方法.互斥量通过控制对共享数据的访问来同步任务.条件变量可以根据数据的值来同步任务.条件变量是当一个事件发生时发送信号的信号量.一旦事件发生,可能会有多个线程在等待信号, ...