音频框架

  1. 音频框架的组成
    a) 应用层:应用厂商根据特定需求袭击写的各种音频处理apk
    b) 框架层:供开发音频相关产品时使用的java类
    c) JNI层:屏蔽了对Audio本地框架调用细节,相当于Java接口本地中转
    d) 库层:
    i. client部分:JNI层调用对应的本地实现,通过binder与server交互;
    ii. server部分:系统服务,是Android音频系统中最核心的部分;
    e) HAL层:音频的硬件抽象层,不同类型的音频设备对应不同的HAL层。
    f) tinyalsa:封装给用户态调用音频驱动ALSA架构接口的一个精简库。
  2. AudioFlinger:音频系统中的核心服务,是Android音频系统的中枢,是各功能的主要执行者。它同时也是一个系统服务,为上层提供访问接口,并直接与HAL(音频的硬件抽象层)进行交互。是音频策略的执行者,管理不同HAL层的打开和关闭,对不同的AudioTrack数据进行处理,包括混音、重采样、音效、音量控制。
  3. AudioPolicyService:音频系统中关于策略的重要服务,是Android音频策略的制定者。根据用户配置来指导AudioFlinger加载支持的设备HAL,对不同stream类型制定选择设备的优先级策略。
  4. MediaPlayerService:多媒体系统中的重要服务;
  5. CameraService:有关摄像/照相的重要服务;
  6. AudioTrack的两种数据加载模式
    a) MODE_STREAM:在这种模式下,通过write一次次把音频数据写到AudioTrack中,这和平时通过write系统调用往文件中写数据类似,但这种工作方式每次都需要把数据从用户提供的Buffer中拷贝到AudioTrack内部的Buffer中,这在一定程度上会使引起延时;
    b) MODE_STATIC:这种模式下,在play之前只需要把所有的数据通过一次write调用传递到AudioTrack的内部缓冲区中,后续就不必再传递数据了。这种迷失适用于像铃声这种占用量较小,延时要求较高的文件。但它也有一个缺点,就是一次write的数据不能太多,否则系统无法分配足够的内存来存储全部数据。
  7. 共享内存
    a) 每个进程的内存空间是4GB,这个4GB是由指针长度决定的,如果指针长度为32位,那么地址的最大编号就是0xFFFFFFFFF,为4GB;
    b) 上面说的内存空间是进程的虚拟地址空间,在应用程序中使用的指针其实是指向虚拟空间地址的。
  8. Linux平台创建和共享内存的步骤为
    a) 进程A创建并打开一个文件,得到一个文件描述符Id;
    b) 通过mmap调用fd映射成内存映射文件,在mmap调用中指定特定的参数表示要创建进程间共享内存;
    c) 进程B打开同一个文件,也得到一个文件描述符,这样A和B就打开了同一个文件;
    d) 进程B也要用mmap调用指定参数表示想使用共享内存,并传递打开的fd。这样A和B就通过打开同一个文件并构造内存映射,实现了进程间的内存共享。
  9. MemoryHeapBase构造后得到以下结果
    a) mBase变量指向共享内存的起始位置;
    b) mSize是所要求分配的内存大小;
    c) mFd是ashmem_create_region返回的文件描述符;
  10. AudioTrack在JNI层使用了Native的AudioTrack对象,总结一下调用Native对象的流程
    a) new一个AudioTrack,使用无参的构造函数;
    b) 调用set函数,把Java层的参数传进去,另外还设置一个audiocallback函数;
    c) 调用AudioTrack的start函数;
    d) 调用AudioTrack的write函数;
    e) 工作完毕后,调用stop;
    f) 最后就是Native对象的delete;
  11. flowControlFlag的总结
    a) 对于音频输出来说,flowControlFlag对应着underrun状态,underrun状态是指生产者提供数据的速度跟不上消费者使用数据的速度。这里的消费者指的是音频输出设备。由于音频输出设备采用环形缓冲方式管理,当生产者没有及时提供新数据时,输出设备就会循环使用缓冲中的数据,这样就会听到一段重复的声音。这种现象一般被称作“machinegun”。对于这种情况,一般的处理方法是暂停输出,等数据准备好后在恢复输出。
    b) 对应音频输入来说,flowControlFlag对应着overrun状态,它的意思和underrun一样,只是这里的生产者变成了音频输入设备,而消费者则变成了Audio系统的AudioRecord.
  12. AudioTrack的两种数据输入方式
    a) Push方式:用户主动调用write写数据,相当于数据被push到AudioTrack。
    b) Pull方式:AudioTrackThread将利用这个回调函数,以EVENT_MORE_DATA为参数,主动从用户那pull数据。ToneGenerator则用这种方式为AudioTrack提供数据。
  13. write的工作方式:通过共享内存传递数据,通过控制结构协调生产者和消费者的步调。
  14. AT和AF交互流程
    a) AT调用createTrack,得到第一个IAudioTrack对象;
    b) AT调用IAudioTrack对象的start,表示准备写数据了;
    c) AT通过write写数据,这个过程和audio_track_cblk_t有着密切关系;
    d) 最后AT调用IAudioTrack的stop或deleteIAudioTrack结束工作;
  15. Android在这里使用了Proxy模式,即TrackHandle是Track的代理,Track没有基于Binder通信,它不能接收来自远端进程的请求。TrackHandle能基于Binder通信,它可以接收来自远端进程的请求,并且能调用Track对应的函数。
  16. PlaybackThread:回放线程,用于音频输出;它有一个成员变量mOutput,为AudioStreamOutput*类型,这表明PlaybackThread直接和Audio音频输出设备建立了联系;
  17. RecordThread:录音线程,用于音频输入;
  18. MixerThread:混音线程,它将来自多个源的音频数据混音后在输出;
  19. DirectoutputThread:直接输出线程,它会选择一路音频流后将数据直接输出,由于没有混音操作,这样就可以减少很多延时;
  20. DuplicatingThread:多路输出现象,它从MixerThread派生,意味着它也能混音。它最终会把混音后的数据写到多个输出中,也就是一份数据会有多个接收者。
  21. MixerThread的线程函数大致的工作流程:
    a) 如果有通知信息或配置请求,则先完成这些工作。比如向监听者通知AF的一些信息,或者根据配置请求进行音量控制、声音设备切换等;
    b) 调用prepareTracks_l函数,检查活跃的Tracks是否有数据已备好;
    c) 调用混音器对象mAudioMixer的process,并且传入一个存储结果数据的缓冲,混音后的结果就存储在这个缓冲中;
    d) 调用代表音频设备的AudioOutputStream对象的write,把结果数据写入设备。
  22. AF的使用流程
    a) 调用framesReady看是否有可读数据;
    b) 获得可读数据的起始位置,这个和上面的buffer调用基本一样,都是根据offset和serverBase来获得可读数据块的首地址;
    c) 调用stepServer更新读位置;
  23. 系统有两个核心处理器,一个是应用处理的核心,叫AP,可把它当作是台式机上的CPU,在这上面可以运行操作系统。另一个和手机通信相关,一般叫做BP。
  24. AP和BP都能向音频DSP发送数据,它们在硬件的通道山峰互不干扰。于是就出现了一个问题,即如果两个P同时往DSP发送数据,而互相之间没有协调,那么就可能出现通话声和音乐声混杂的情况。
  25. AudioManager.java
    方法:setStreamVolume(intstreamType,intindex,intflags) 作用:直接设置音量大小。
    streamType,指定声音类型

STREAM_ALARM,手机闹铃,STREAM_MUSIC:手机音乐
Stream_RING:电话铃声,STREAM_SYSTEAM:手机系统
STREAM_DTMF:音调,STREAM_NOTIFICATION:系统提示 STREAM_VOICE_CALL:语音电话
index,调大或调小音量
flags,可选的标志位,比如AudioManager.FLAG_SHOW_UI,显示进度条,AudioManager.PLAY_SOUND:播放声音。

  1. AudioService:音频系统在java层中基本不参与数据流的,AudioService这个系统服务包含或者使用了几乎所有与音频有关的内容,所以说AUdioService是音频系统在Java层的大本营;AudioManager拥有AudioService的Bp端(应用芯片),是AudioService在客户端的一个代理,几乎所有客户对AudioManager进行的请求,最终都会交由AudioService实现;AudioService的功能依赖AudioSystem类,AudioSystem无法实例化,它是Java层到native层的代理,AudioService通过它与AudioPolicy以及AudioFlinger进行通信;
  2. RemoteException,通信异常;
  3. 方法:adjustSuggestedStreamVolume(intdirection,intsuggestedStreamType,intflags) 作用:调整“推荐的流”的音量
  4. 方法:setMasterMute(booleanmute,intflags) 作用:设置静音