android Audio(4)框架

ASLA -Advanced Sound Linux Architecture
OSS -以前的Linux音频体系结构,被ASLA取代并兼容
I2S/PCM/AC97 - Codec与CPU间音频的通信协议/接口/总线
DAI - Digital Audio Interface 数字音频接口 其实就是I2S/PCM/AC97
DAPM - Dynamic Audio Power Management 动态音频电源管理
Mixer-混合器
DSP-Digital Signal Processor 数字信号处理器
1) 播放音乐

这里写图片描述

2) 录音

这里写图片描述

3)打电话

这里写图片描述
这里写图片描述

4) 通过蓝牙打电话

这里写图片描述
这里写图片描述

Android系统上的音频框架

这里写图片描述

Framework

MediaPlayer和MediaRecorder
AudioTrack和AudioRecorder

Android系统还为我们控制音频系统提供了AudioManager、AudioService及AudioSystem类。这些都是framework为便利上层应用开发所设计的。

libraries (AudioFlinger )

除了上面的类库实现外,音频系统还需要一个“核心中控”,或者用Android中通用的实现来讲,需要一个系统服务(比如 ServiceManager、LocationManagerService、ActivityManagerService等等),这就是 AudioFlinger和AudioPolicyService。它们的代码放置在frameworks/av/services /audioflinger,生成的最主要的库叫做libaudioflinger。

音频体系中另一个重要的系统服务是MediaPlayerService,它的位置在frameworks/av/media/libmediaplayerservice。

其一,以库为线索。比如AudioPolicyService和AudioFlinger都是在libaudioflinger库中;而AudioTrack、AudioRecorder等一系列实现则在libmedia库中。

其二,以进程为线索。库并不代表一个进程,进程则依赖于库来运行。虽然有的类是在同一个库中实现的,但并不代表它们会在同一个进程中被调用。比如 AudioFlinger和AudioPolicyService都驻留于名为mediaserver的系统进程中;而 AudioTrack/AudioRecorder和MediaPlayer/MediaRecorder一样实际上只是应用进程的一部分,它们通过 binder服务来与其它系统进程通信。

HAL( audio_hw.cpp ,audio.primary.so)

从设计上来看,硬件抽象层是AudioFlinger直接访问的对象。这说明了两个问题,一方面AudioFlinger并不直接调用底层的驱动程 序;另一方面,AudioFlinger上层(包括和它同一层的MediaPlayerService)的模块只需要与它进行交互就可以实现音频相关的功 能了。因而我们可以认为AudioFlinger是Android音频系统中真正的“隔离板”,无论下面如何变化,上层的实现都可以保持兼容。

Audio HAL提供了统一的接口来定义它与AudioFlinger/AudioPolicyService之间的通信方式,这就是* audio_hw_device、audio_stream_in及audio_stream_out*等等存在的目的,这些Struct数据类型内部大多 只是函数指针的定义,是一些“壳”。当AudioFlinger/AudioPolicyService初始化时,它们会去寻找系统中最匹配的实现(这些 实现驻留在以audio.primary.,audio.a2dp.为名的各种库中)来填充这些“壳”。

这里写图片描述

AudioFlinger

Android中的系统服务分为两类,分别是Java层和Native层的System Services。其中AudioFlinger和SurfaceFlinger一样,都属于后者。Java层服务通常在 SystemServer.java中启动,比如后面会看到的AudioService就是这种情况.

1.mediaserver

mediaserver的目录下只有一个文件,它的任务很简单,就是把所有媒体相关的native层服务(包括AudioFlinger,MediaPlayerService,CameraService和AudioPolicyService)启动起来.

int main(int argc, char** argv)
{
    sp<ProcessState>proc(ProcessState::self());
    sp<IServiceManager>sm = defaultServiceManager();
   ALOGI("ServiceManager: %p", sm.get());
   AudioFlinger::instantiate();
   MediaPlayerService::instantiate();
   CameraService::instantiate();
   AudioPolicyService::instantiate();
   ProcessState::self()->startThreadPool();
   IPCThreadState::self()->joinThreadPool();
}
 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

AudioFlinger 继承BinderService

class AudioFlinger :
    public BinderService<AudioFlinger>,
    public BnAudioFlinger…
实际的初始化工作不在构造函数中,而在void AudioFlinger::onFirstRef()
 
 
 
 
  • 1
  • 2
  • 3
  • 4
2.音频设备的管理

AudioPolicyService是策略的制定者,比如什么时候打开音频接口设备、某种Stream类型的音频对应什么设备等等。

AudioFlinger则是策略的执行者,例如具体如何与音频设备通信,如何维护现有系统中的音频设备,以及多个音频流的混音如何处理等等都得由它来完 成。

Audio系统中支持的音频设备接口(Audio Interface)分为三大类,即:

/*frameworks/av/services/audioflinger/AudioFlinger.cpp*/
static const char * const audio_interfaces[] = {
   AUDIO_HARDWARE_MODULE_ID_PRIMARY, //主音频设备,必须存在
   AUDIO_HARDWARE_MODULE_ID_A2DP, //蓝牙A2DP音频
   AUDIO_HARDWARE_MODULE_ID_USB, //USB音频,早期的版本不支持
};
 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

每种音频设备接口由一个对应的so库提供支持。

AudioFlinger::loadHwModule(const char *name)/*name就是前面audio_interfaces 数组
                                                            成员中的字符串*/
Step1@ loadHwModule_l. 首先查找mAudioHwDevs是否已经添加了变量name所指示的audio interface,如果是的话直接返回。第一次进入时mAudioHwDevs的size为0,所以还会继续往下执行。
Step2@ loadHwModule_l. 加载指定的audiointerface,比如“primary”、“a2dp”或者“usb”。函数load_audio_interface用来加载 设备所需的库文件,然后打开设备并创建一个audio_hw_device_t实例。音频接口设备所对应的库文件名称是有一定格式的,比如a2dp的模块 名可能是audio.a2dp.so或者audio.a2dp.default.so等等。查找路径主要有两个,即:
/** Base path of the hal modules */
#define HAL_LIBRARY_PATH1 "/system/lib/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib/hw"
Step3@ loadHwModule_l,进行初始化操作。其中init_check是为了确定这个audio interface是否已经成功初始化,0是成功,其它值表示失败。接下来如果这个device支持主音量,我们还需要通过 set_master_volume进行设置。在每次操作device前,都要先改变mHardwareStatus的状态值,操作结束后将其复原为 AUDIO_HW_IDLE(根据源码中的注释,这样做是为了方便dump时正确输出内部状态,这里我们就不去深究了)。
Step4@ loadHwModule_l. 把加载后的设备添加入mAudioHwDevs键值对中,其中key的值是由nextUniqueId生成的,这样做保证了这个audiointerface拥有全局唯一的id号。
 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

AudioFlinger是如何打开一个Output通道

audio_io_handle_t  AudioFlinger::openOutput(audio_module_handle_tmodule, audio_devices_t *pDevices,
                                          uint32_t *pSamplingRate,audio_format_t *pFormat,
                                          audio_channel_mask_t *pChannelMask,
                                          uint32_t *pLatencyMs, audio_output_flags_t flags)
/*入参中的module是由前面的loadHwModule 获得的,它是一个audiointerface的id号,可以通过此id在mAudioHwDevs中查找到对应的AudioHwDevice对象*/

outHwDev用于记录一个打开的音频接口设备,它的数据类型是audio_hw_device_t,是由HAL规定的一个音频接口设备所应具有的属性集合
struct audio_hw_device {
    struct hw_device_t common;
     …
    int (*set_master_volume)(struct audio_hw_device *dev, float volume);
    int (*set_mode)(struct audio_hw_device *dev, audio_mode_t mode);
    int (*open_output_stream)(struct audio_hw_device *dev,
                             audio_io_handle_t handle,
                             audio_devices_t devices,
                             audio_output_flags_t flags,
                             struct audio_config *config,
}
 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

Step1. 在openOutput中,设备outHwDev是通过查找当前系统来得到的

audio_hw_device_t*  AudioFlinger::findSuitableHwDev_l(audio_module_handle_t module, uint32_t devices)
 
 
 
 
  • 1

一种情况就是前面看到的modules为0时,会load所有潜在设备,另一种情况就是AudioPolicyManagerBase在构造时会预加载所有audio_policy.conf中所描述的output。

Step2,调用open_output_stream打开一个audio_stream_out_t。

Step3,生成AudioStreamOut对象。这个变量没什么特别的,它把audio_hw_device_t和audio_stream_out_t做为一个整体来封装。

Step4. 既然通道已经打开,那么由谁来往通道里放东西呢?这就是PlaybackThread。

DirectOutput 如果不需要混音
Mixer 需要混音
这两种情况分别对应DirectOutputThread和MixerThread两种线程

Step5,到目前为止,我们已经成功的建立起一个音频通道,就等着AudioTrack往里丢数据了。

Audio Codec

1.内置

2.WM8978 欧胜微电子(Wolfson英国的爱丁堡)
3.ALC5623 (realtek)

tinymix

tinymix: 查看配置混音器

tinyplay: 播放音频

tinycap: 录音

查看当前系统的声卡

cat /proc/asound/cards

pcm设备

在Android中一个pcm设备最多可有

一个mixer设备”/dev/snd/controlC%u”(一般是controlC0)和

32个/dev/snd/pcmC%uD%uc(一般是pcmC0D0c)、/dev/snd/pcmC%uD%u%p(一般是pcmC0D0p),pcm设备中的C代表card,D代表device,c代表capture,p代表playback。

tinyalsa的对外提供的头文件一个”asoundlib.h”,提供最基础的pcm和mixer操作。
实现文件为pcm.c(实现pcm api)和mixer.c(实现mixer api)

  •                     <li class="tool-item tool-active is-like "><a href="javascript:;"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#csdnc-thumbsup"></use>
                        </svg><span class="name">点赞</span>
                        <span class="count"></span>
                        </a></li>
                        <li class="tool-item tool-active is-collection "><a href="javascript:;" data-report-click="{&quot;mod&quot;:&quot;popu_824&quot;}"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#icon-csdnc-Collection-G"></use>
                        </svg><span class="name">收藏</span></a></li>
                        <li class="tool-item tool-active is-share"><a href="javascript:;" data-report-click="{&quot;mod&quot;:&quot;1582594662_002&quot;}"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#icon-csdnc-fenxiang"></use>
                        </svg>分享</a></li>
                        <!--打赏开始-->
                                                <!--打赏结束-->
                                                <li class="tool-item tool-more">
                            <a>
                            <svg t="1575545411852" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5717" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M179.176 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5718"></path><path d="M509.684 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5719"></path><path d="M846.175 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5720"></path></svg>
                            </a>
                            <ul class="more-box">
                                <li class="item"><a class="article-report">文章举报</a></li>
                            </ul>
                        </li>
                                            </ul>
                </div>
                            </div>
            <div class="person-messagebox">
                <div class="left-message"><a href="https://blog.csdn.net/gbmaotai">
                    <img src="https://profile.csdnimg.cn/1/8/4/3_gbmaotai" class="avatar_pic" username="gbmaotai">
                                            <img src="https://g.csdnimg.cn/static/user-reg-year/1x/12.png" class="user-years">
                                    </a></div>
                <div class="middle-message">
                                        <div class="title"><span class="tit"><a href="https://blog.csdn.net/gbmaotai" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}" target="_blank">gbmaotai</a></span>
                                            </div>
                    <div class="text"><span>发布了117 篇原创文章</span> · <span>获赞 9</span> · <span>访问量 3万+</span></div>
                </div>
                                <div class="right-message">
                                            <a href="https://im.csdn.net/im/main.html?userName=gbmaotai" target="_blank" class="btn btn-sm btn-red-hollow bt-button personal-letter">私信
                        </a>
                                                            <a class="btn btn-sm  bt-button personal-watch" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}">关注</a>
                                    </div>
                            </div>
                    </div>
    
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值