AudioFlinger分析
【Android系统原理与开发要点详解】07_Android的Audio系统
Android 的 Audio 系统
2.2 media 库中的 Audio 框架部分
AudioSystem +setXXX() +getXXX() IAudioFlinger +createTrack () +openRecord() +registerClient()
AudioTrack -mAudioTrack +start() +stop() +flush() +pause () +write() BnAudioFlinger IAudioTrack
Audio 系统的头文件 (路径为: frameworks/base/include/media/ ) : AudioSystem.h IAudioFlinger.h AudioTrack.h IAudioTrack.h AudioRecorder.h IAudioRecorder.h Ixxx 的接口通过 AudioFlinger 来实现,其他接口 通过 JNI 向上层提供接口。
2.2 media 库中的 Audio 框架部分
enum audio_mode { // Audio 模式 // …… 省略部分内容 }; enum audio_routes { // Audio 路径类型 ROUTE_EARPIECE = (1 << 0), ROUTE_SPEAKER = (1 << 1), ROUTE_BLUETOOTH_SCO = (1 << 2), ROUTE_HEADSET = (1 << 3), ROUTE_BLUETOOTH_A2DP = (1 << 4), ROUTE_ALL = -1UL, }; static status_t setMasterVolume(float value); static status_t setMasterMute(bool mute); static status_t getMasterVolume(float* volume); static status_t getMasterMute(bool* mute); static status_t setStreamVolume(int stream, float value); static status_t setStreamMute(int stream, bool mute); static status_t getStreamVolume(int stream, float* volume); static status_t getStreamMute(int stream, bool* mute); static status_t setMode(int mode); static status_t getMode(int* mode); static status_t setRouting(int mode, uint32_t routes, uint32_t mask); static status_t getRouting(int mode, uint32_t* routes); // …… 省略部分内容 };
AudioEffect分析(转)
AudioEffect分析(转)音效AudioEffect如下图,应用程序开发者使用android.media.audiofx.AudioEffect来控制音效,它的子类包括:BassBoost, EnvironmentalReverb, Equalizer, PresetReverb, Virtua lizer。
AudioEffect的接口如激活/去激活等,它将调用到JNI层,而JNI 层将调用C++类AudioEffect,后者再通过接口IEffect指针指向的BpEffect代理对象跨进程调用到Server侧AudioFlinger的EffectHandle。
AudioEffectAudioRecord.cpp调用APIandroid.media.audiofx.AudioEffectAppsJNIandroid_media_AudioEffectcppIEffectIEffect.cppBinder IPCAudioFlinger::EffectHandleBnEffectBnInterface<IEffect>JavaC/C++音效的处理在Server侧的AudioFlinger的单独线程中,它与播放线程(PlaybackThread)相关联。
一个音效由EffectModule表示,它实际上是一个定义了统一接口的包裹(wrapper)类。
具体的音效处理算法肯能封装在别的库里,EffectModule负责调用它们。
音效处理引擎实际处理音效的是音效引擎(engine),往往封装在单独的库中。
在Android的frameworks/base/media/libeffects目录下面,就有几个音效处理引擎。
这些引擎要实现一定的API(见frameworks/base/include/media/EffectApi.h),供外部调用。
在Android的音效框架中,作为音效引擎的wrapper类,EffectModule 调用音效引擎API。
android audio系统介绍
Android 音频系统整理在framework中c/c++层的音频系统服务主要有三个。
在base/media/mediaserver/Main_mediaserver.cpp的代码中可以找到。
一个是AudioFlinger, MediaPlayerService, 和AudioPolicyService。
AudioFlinger和AudioPolicyService是android audio系统的服务,负责音频方面的数据流传输和控制功能,也负责音频设备的管理。
这个部分作为Android的Audio系统的输入/输出层次,一般负责播放PCM声音输出和从外部获取PCM声音,以及管理声音设备和设置。
Mediaplayerservice 是Android中很重要也最为复杂的媒体播放器(MediaPlayer)部分的服务。
MediaPlayer在底层是基于OpenCore(PacketVideo)和stagefright的库实现的。
音频服务端和客户端之间的交互包含了进程间通讯等内容,这种进程间通讯的基础是Android基本库中的Binder机制。
代码框架:1:Java部分代码(frameworks/base/media/java/android/media)2:Audio的JNI层JNI的cpp分布在两个部分,base/core/jni中有AudioRecord,AudioSystem,AudioTrack,JetPlayer,ToneGenarator,其他的在base/media/jni中。
3:Audio的c/c++层1)Audio框架见下图:Audio本地框架是media库的一部分,本部分内容被编译成库libmedia.so,主要实现AudioSystem、AudioTrack和AudioRecorder三个类,对上面提供接口,由下层的本地代码去实现。
AudioFlinger内容被编译成库libaudioflinger.so,它是Audio系统的本地服务部分,它是audio系统中真正做事的类,它通过硬件抽象层提供到硬件的接口。
蓝牙耳机简单的流程
最近在关注蓝牙耳机方面的问题,做下简单的流程分析。
解码后,在AudioFlinger里把音频数据写到设备里。
这里主要看看AudioFlinger,AudioPolicyManager 和external/bluetooth/bluez/audio里面的android_audio_hw.c和liba2dp.c。
在AudioPolicyManager里有设备连接判断。
status_t AudioPolicyManagerBase::setDeviceConnectionState(AudioSystem::audio_devices device, AudioSystem::device_connection_state state, const char *device_address){#ifdef WITH_A2DP// handle A2DP device connectionif (AudioSystem::isA2dpDevice(device)) {status_t status = handleA2dpConnection(device, device_address);//这里是执行蓝牙连接if (status != NO_ERROR) {mAvailableOutputDevices &= ~device;return status;}} else#endif}。
status_t AudioPolicyManagerBase::handleA2dpConnection(AudioSystem::audio_devices device,const char *device_address){...............mA2dpOutput = mpClientInterface->openOutput(&outputDesc->mDevice,&outputDesc->mSamplingRate,&outputDesc->mFormat,&outputDesc->mChannels,&outputDesc->mLatency,outputDesc->mFlags);if (mA2dpOutput) {// add A2DP output descriptoraddOutput(mA2dpOutput, outputDesc);//TODO: configure audio effect output stage here// set initial stream volume for A2DP deviceapplyStreamVolumes(mA2dpOutput, device);if (a2dpUsedForSonification()) {mDuplicatedOutput = mpClientInterface->openDuplicateOutput(mA2dpOutput, mHardwareOutput);}if (mDuplicatedOutput != 0 ||!a2dpUsedForSonification()) {// If both A2DP and duplicated outputs are open, send device address to A2DP hardware // interfaceAudioParameter param;param.add(String8("a2dp_sink_address"), String8(device_address));mpClientInterface->setParameters(mA2dpOutput, param.toString());mA2dpDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);if (a2dpUsedForSonification()) {// add duplicated output descriptorAudioOutputDescriptor *dupOutputDesc = new AudioOutputDescriptor();dupOutputDesc->mOutput1 = mOutputs.valueFor(mHardwareOutput);dupOutputDesc->mOutput2 = mOutputs.valueFor(mA2dpOutput);dupOutputDesc->mSamplingRate = outputDesc->mSamplingRate;dupOutputDesc->mFormat = outputDesc->mFormat;dupOutputDesc->mChannels = outputDesc->mChannels;dupOutputDesc->mLatency = outputDesc->mLatency;addOutput(mDuplicatedOutput, dupOutputDesc);applyStreamVolumes(mDuplicatedOutput, device);}} else {.........}如果只是蓝牙播放,那么mDuplicatedOutput和a2dpUsedForSonification都为0,仅执行addOutput(mA2dpOutput, outputDesc);,走类似speaker和麦克风的流程。
Android深入浅出之Audio
uint32_t minFrameCount = (afFrameCount*sampleRateInHertz*minBufCount)/afSamplingRate; //下面根据最小的 framecount 计算最小的 buffersize int minBuffSize = minFrameCount * (audioFormat == javaAudioTrackFields.PCM16 ? 2 : 1) * nbChannels; return minBuffSize; }
if (AudioSystem::getOutputLatency(&afLatency) != NO_ERROR) { return -1; } //音频中最常见的是 frame 这个单位,什么意思?经过多方查找,最后还是在 ALSA 的 wiki 中 //找到解释了。一个 frame 就是 1 个采样点的字节数*声道。为啥搞个 frame 出来?因为对于多//声道的话,用 1 个采样点的字节 数表示不全,因为播放的时候肯定是多个声道的数据都要播出来//才行。所以为了方便,就说 1 秒钟有多少个 frame,这样就能抛开 声道数,把意思表示全了。 // Ensure that buffer depth covers at least audio hardware latency uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSamplingRate); if (minBufCount < 2) minBufCount = 2;
AudioTrack.getMinBufferSize(8000,// 每秒 8K 个点 AudioFormat.CHANNEL_CONFIGURATION_STEREO,// 双声道 AudioFormat.ENCODING_PCM_16BIT); ----->AudioTrack.JAVA //注意,这是个 static 函数 static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) { int channelCount = 0; switch(channelConfig) { case AudioFormat.CHANNEL_OUT_MONO: case AudioFormat.CHANNEL_CONFIGURATION_MONO: channelCount = 1; break; case AudioFormat.CHANNEL_OUT_STEREO: case AudioFormat.CHANNEL_CONFIGURATION_STEREO: channelCount = 2;--->看到了吧,外面名字搞得这么酷,其实就是指声道数 break; default: loge("getMinBufferSize(): Invalid channel configuration."); return AudioTrack.ERROR_BAD_VALUE; } //目前只支持 PCM8 和 PCM16 精度的音频
Audio(2)-audio数据控制块audio_track_cblk_t
Audio(2)-audio数据控制块audio_track_cblk_t 背景介绍AudioTrack与AudioFlinger之间的数据传输分为两种⽅式,MODE_STATIC与MODE_STREAM。
1. MODE_STATIC:static⽅式适⽤于数据较⼩,实时性⽐较⾼的情形,⽐如ring,系统铃声等。
这种模式下,是在AT端创建共享内存,⼀次性将数据copy到buffer中,然后传递到AF端。
2. MODE_STREAM:stream⽅式适⽤于数据较⼤,media播放等更多其他的情况,也⽐较复杂。
在这种模式下,共享内存是由AF创建的,然后通过⽣产者-消费者的模式,进⾏数据的传输。
即AT是数据的⽣产者,AF是数据的消费者。
这个数据读写的控制,是由struct audio_track_cblk_t来实现的,这篇⽂章主要来分析这个控制块的实现。
audio_track_cblk_t的创建1. AT与AF之间,是通过IAudioTrack接⼝进⾏交互的,⽽这个audio_track_cblk_t的创建,就是在AT调⽤AF创建IAudioTrack接⼝的同时创建的。
2. AT->AF.createTrack()//在AT.play之前,必须要与AF建⽴联系3. PlaybackThread.createTrack_l() //创建AT与AF之间实际功能调⽤的实现者4. new Track() //创建Track,并把它包装在实现了IAudioTrack接⼝的TrackHandle中5. TrackBase::TrackBase()//Track的⽗类,创建audio_track_cblk_t的⼯作是在TrackBase的构造函数中进⾏的size_t size = sizeof(audio_track_cblk_t); //计算audio_track_cblk_t的⼤⼩uint8_t channelCount = popcount(channelMask);size_t bufferSize = frameCount*channelCount*sizeof(int16_t); //计算实际数据buffer⼤⼩if (sharedBuffer == 0) {size += bufferSize; //共享内存实际分配⼤⼩为:cblk + data buffer}if (client != NULL) {mCblkMemory = client->heap()->allocate(size); //分配共享内存,实际的实现会在其他⽂章中分析,这⾥之分析对共享内存的使⽤if (mCblkMemory != 0) {mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer()); // audio_track_cblk_t* mCblk,指向共享内存的地址if (mCblk != NULL) { // construct the shared structure in-place.new(mCblk) audio_track_cblk_t(); //这⾥是C++的语法: //(1)struct可以像class⼀样,使⽤new来创建。
关于AudioEffect使用过程中的构造以及处理流程遇到的几个问题
关于AudioEffect使用过程中的构造以及处理流程遇到的几个问题最近遇到几个与AudioEffect相关的问题,在此记录下作为一个记忆总结android系统中如果想使用自己开发或者第三方的音效算法,有一种比较简单的办法就是放到hal层的out_write接口中,这样做优点是简单,方便快速集成。
还有标准的做法就是做成android标准的音效接口,上层应用就可以像使用android自带的音效一样来调用自己所添加的自定义音效。
如何实现自定义的音效库以及AudioEffect的构造流程分析,已经有不少写的很好的文章,可以参考以下博客AudioEffect构造流程跟踪 & 音效库实现(native侧)https:///wkw1125/article/details/65632960Android Effect 解析https:///kuang_tian_you/article/details/835107 13这里主要记录我遇到的几个问题,我看很少有文章讲到,在此做个记录之前讲到音效集成自己放在hal层或是在送往alsa输出之前做处理这种方法简单同时也能保证系统输出的音频数据都能经过音效算法处理。
做成android音效标准接口就有需要注意的地方了,先来看下android audioeffect 处理的地方,在audioflinger的playbackthread中PlaybackThread::threadLoop()这就意味中必须是meplayer或是audiotrack播放的音频流才能获得音效作用,但是对于一些android TV来说,很多方案商的TV In 的音频数据比如HDMI IN、AV IN并不通过audiotrack去播放,例如google专门为android TV设计的TIF架构,走的是audiopatch机制,audio in到audio out的处理基本上在hal层就干完了,不经过audiotrack 那么如何使用auudioeffect音效呢,这样就能想到如果音效不在audioflinger那一层处理,而是也在hal层去处理,这个功能就完成了。
Android音频系统之AudioFlinger(一)
Android音频系统之AudioFlinger(一)1.1 AudioFlinger在上面的框架图中,我们可以看到AudioFlinger(下面简称AF)是整个音频系统的核心与难点。
作为Android系统中的音频中枢,它同时也是一个系统服务,启到承上(为上层提供访问接口)启下(通过HAL 来管理音频设备)的作用。
只有理解了AudioFlinger,才能以此为基础更好地深入到其它模块,因而我们把它放在前面进行分析。
1.1.1 AudioFlinger服务的启动和运行我们知道,Android中的系统服务分为两类,分别是Java层和Native层的System Services。
其中AudioFlinger和SurfaceFlinger 一样,都属于后者。
Java层服务通常在SystemServer.java中启动,比如后面会看到的AudioService就是这种情况。
而Native层服务则通常是各服务方按照自己的特定部署来决定何时启动、如何启动。
例如AudioFlinger就是利用一个Linux程序来间接创建的,如下所示:/*frameworks/av/media/mediaserver/Main_mediaserver.cp p*/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();}这个mediaserver的目录下只有一个文件,它的任务很简单,就是把所有媒体相关的native层服务(包括AudioFlinger,MediaPlayerService,CameraService和AudioPolicyService)启动起来,可以参考其Android.mk: LOCAL_SRC_FILES:= \main_mediaserver.cppLOCAL_SHARED_LIBRARIES := \libaudioflinger\libcameraservice\libmediaplayerservice\libutils \libbinder…LOCAL_MODULE:= mediaserver根据前面的分析,AudioFlinger的源码实现是放在libaudioflinger库中的,因而在编译mediaserver时要引用这个库,其它服务也是一样的做法。
AudioEffect 分析(转)
AudioEffect 分析(转)音效AudioEffect如下图,应用程序开发者使用android.media.audiofx.AudioEffect来控制音效,它的子类包括:BassBoost, EnvironmentalReverb, Equalizer, PresetReverb, Virtualizer。
AudioEffect的接口如激活/去激活等,它将调用到JNI层,而JNI层将调用C++类AudioEffect,后者再通过接口IEffect指针指向的BpEffect代理对象跨进程调用到Server侧AudioFlinger的EffectHandle。
AudioEffectAudioRecord.cpp 调用APIandroid.media.audiofx.AudioEffectAppsJNIandroid_me dia_AudioEffectcpp IEffectIEffect.cppBinder IPCAudioFlinger::EffectHandleBnEffectBnInterface<IEff ect>JavaC/C++ 音效的处理在Server侧的AudioFlinger 的单独线程中,它与播放线程(PlaybackThread)相关联。
一个音效由EffectModule表示,它实际上是一个定义了统一接口的包裹(wrapper)类。
具体的音效处理算法肯能封装在别的库里,EffectModule负责调用它们。
音效处理引擎实际处理音效的是音效引擎(engine),往往封装在单独的库中。
在Android的frameworks/base/media/libeffects目录下面,就有几个音效处理引擎。
这些引擎要实现一定的API (见frameworks/base/include/media/EffectApi.h),供外部调用。
在Android的音效框架中,作为音效引擎的wrapper 类,EffectModule调用音效引擎API。
AudioTrack与AudioFlinger交换音频数据
AudioTrack和AudioFlinger的通信机制通常,AudioTrack和AudioFlinger并不在同一个进程中,它们通过android中的binder机制建立联系。
AudioFlinger是android中的一个service,在android启动时就已经被加载。
如何使用AudioTrackAudioTrack的主要代码位于frameworks/base/media/libmedia/audiotrack.cpp中。现在先通过一个例子来了解一下如何使用AudioTrack,ToneGenerator是android中产生电话拨号音和其他音调波形的一个实现,我们就以它为例子:
frameCount-- FIFO的大小,以音频数据的帧为单位,16bit的音频每帧的大小是2字节
buffers -- 指向FIFO的起始地址
out -- 音频流的方向,对于AudioTrack,out=1,对于AudioRecord,out=0
audio_track_cblk_t的主要成员函数:
framesAvailable_l()和framesAvailable()用于获取FIFO中可写的空闲空间的大小,只是加锁和不加锁的区别。
ToneGenerator的初始化函数:
boolToneGenerator::initAudioTrack(){//Openaudiotrackinmono,PCM16bit,defaultsamplingrate,defaultbuffersizempAudioTrack=newAudioTrack();mpAudioTrack->set(mStreamType,0,AudioSystem::PCM_16_BIT,AudioSystem::CHANNEL_OUT_MONO,0,0,audioCallback,this,0,0,mThreadCanCallJava);if(mpAudioTrack->initCheck()!=NO_ERROR){LOGE("AudioTrack->initCheckfailed");gotoinitAudioTrack_exit;}mpAudioTrack->setVolume(mVolume,mVolume);mState=TONE_INIT;......} 可见,创建步骤很简单,先new一个AudioTrack的实例,然后调用set成员函数完成参数的设置并注册到AudioFlinger中,然后可以调用其他诸如设置音量等函数进一步设置音频参数。其中,一个重要的参数是audioCallback,audioCallback是一个回调函数,负责响应AudioTrack的通知,例如填充数据、循环播放、播放位置触发等等。回调函数的写法通常像这样:voidToneGenerator::audioCallback(intevent,void*user,void*info){if(event!=AudioTrack::EVENT_MORE_DATA)return;AudioTrack::Buffer*buffer=static_cast<AudioTrack::Buffer*>(info);ToneGenerator*lpToneGen=static_cast<ToneGenerator*>(user);short*lpOut=buffer->i16;unsignedintlNumSmp=buffer->size/sizeof(short);constToneDescriptor*lpToneDesc=lpToneGen->mpToneDesc;if(buffer->size==0)return;//Clearoutputbuffer:WaveGeneratoraccumulatesintolpOutbuffermemset(lpOut,0,buffer->size);......//以下是产生音调数据的代码,略....}该函数首先判断事件的类型是否是EVENT_MORE_DATA,如果是,则后续的代码会填充相应的音频数据后返回,当然你可以处理其他事件,以下是可用的事件类型enumevent_type{EVENT_MORE_DATA=0,//RequesttowritemoredatatoPCMbuffer.EVENT_UNDERRUN=1,//PCMbufferunderrunoccured.EVENT_LOOP_END=2,//Sampleloopendwasreached;playbackrestartedfromloopstartifloopcountwasnot0.EVENT_MARKER=3,//Playbackheadisatthespecifiedmarkerposition(SeesetMarkerPosition()).EVENT_NEW_POS=4,//Playbackheadisatanewposition(SeesetPositionUpdatePeriod()).EVENT_BUFFER_END=5//Playbackheadisattheendofthebuffer.}; 关于开始播放和停止播放 ,只要简单的调用start() ,stop()即可
Android音频系统之AudioFlinger(四)
Android音频系统之AudioFlinger(四)1.1.1 AudioMixer每一个MixerThread都有一个唯一对应的AudioMixer(在MixerThread中用mAudioMixer表示),它的作用如其名所表示的,就是为了完成音频的混音操作。
如上图,MixerThread对外开放的接口主要涉及到Parameter(比如setParameter)、Resampler(比如setResampler)、Volume(比如adjustVolumeRamp)、Buffer(比如setBufferProvider)及Track(比如getTrackName)五个部分。
在内部的实现中,MixerThread的核心是一个mState变量(state_t类型),所有的混音工作都会在这个变量中体现出来——特别是其中的tracks数组,如下所示:struct state_t {uint32_t enabledTracks;uint32_t needsChanged;size_t frameCount;void (*hook)(state_t* state, int64_tpts); // one of process__*, never NULLint32_t *outputTemp;int32_t *resampleTemp;int32_t reserved[2];track_t tracks[MAX_NUM_TRACKS];__attribute__((aligne d(32)));};MAX_NUM_TRACKS=32,也就是说最多支持32路同时混音,这对于大部分情况肯定是足够了。
数据类型track_t是对每个Track的描述,可想而知类似Parameter这种设置,最终影响的就是Track的属性。
struct track_t {…union {int16_t volume[MAX_NUM_CHANNELS];int32_t volumeRL;};//音量相关的属性int32_t prevVolume[MAX_NUM_CHANNELS];int32_t volumeInc[MAX_NUM_CHANNELS];…uint8_t channelCount; //只能是1或2uint8_t format; // 总是16uint16_t enabled; // 实际是布尔类型audio_channel_mask_t channelMask;AudioBufferProvider* bufferProvider;mutableAudioBufferProvider::Buffer buffer; // 8 byteshook_t hook;const void* in; //buffer中的当前位置AudioResampler* resampler;uint32_t sampleRate;int32_t* mainBuffer;int32_t* auxBuffer;…bool setResampler(uint32_t sampleRate,uint32_t devSampleRate);bool doesResample() const { return resampler!= NULL; } void resetResampler() { if (resampler !=NULL)resampler->reset(); }void adjustVolumeRamp(bool aux);size_t getUnreleasedFrames() const { return resampler != NULL ?resampler->getUnreleasedFrames() : 0; };};AudioFlinger的threadLoop中,通过不断调用prepareTracks_l 来准备数据,而每次prepare实际上都是对所有Track的一次调整。
Android_Audio_深入分析
[键入文字]Android音频通路架构分析[键入文字]目录1. Abstract (3)2. Introduction (3)3. ARM11侧audio通路设置 (4)3.1 代码位置 (5)3.2 录音通路控制 (6)3.2.1 AudioRecord创建 (6)3.2.2 AudioRecord start (11)4. ARM9侧audio通路设置 (15)4.1 代码位置 (16)4.2 通路控制 (17)4.2.1 RPC&Snd Task (17)4.2.2 DEVMGR (18)4.2.3 AFE(audio codec config) (19)4.2.4 ADIE(ADIE codec config) (21)5. ARM9侧audio通路添加 (22)6. 内部PA和外部PA的使用 (26)7. Audio数据流 (27)1.Abstract主要是分析一下android平台音频通路的设置架构。
2.Introduction音频架构在android系统中非常复杂,本节主要分析audio通路的设置,以Radio通路的设置为例,详细介绍一下ARM9和ARM11侧的audio通路如何设置。
从整体架构上分析,与audio通路设置相关的模块包括ARM11,ARM9,ADSP,MDSP,Codec,音频设备。
其中控制信息主要集中在ARM11,ARM9,Internal Codec部分。
以图中的audio control data的流向为主线,对audio通路的设置进行分析。
主要包含以下几部分:●ARM11侧audio通路设置●ARM9侧audio通路设置●ARM9侧audio通路添加3.ARM11侧audio通路设置FM采取了先录再放的机制来设置声音通路。
如上图所示,总共包含以下几部分:JAVA应用层:包含FM的用户操作界面等,主要是FMRadio.java和FMRadioService.java.JNI层:主要用于连接java和c代码的中间层,主要是android_media_AudioRecord.cpp 和android_media_AudioTrack.cpp。
[Audio]从AudioTrack到AudioFlinger(上)
[Audio]从AudioTrack到AudioFlinger(上)展开全文本文转载自zyuanyun的博客,原文地址为:https:///zyuanyun/article/details/60890534 转载请注明作者及原文链接。
1. Android 音频框架概述Audio 是整个 Android 平台非常重要的一个组成部分,负责音频数据的采集和输出、音频流的控制、音频设备的管理、音量调节等,主要包括如下部分:•Audio Application Framework:音频应用框架o AudioTrack:负责回放数据的输出,属Android 应用框架 API 类o AudioRecord:负责录音数据的采集,属Android 应用框架 API 类o AudioSystem:负责音频事务的综合管理,属Android 应用框架 API 类•Audio Native Framework:音频本地框架o AudioTrack:负责回放数据的输出,属Android 本地框架 API 类o AudioRecord:负责录音数据的采集,属Android 本地框架 API 类o AudioSystem:负责音频事务的综合管理,属Android 本地框架 API 类•Audio Services:音频服务o AudioPolicyService:音频策略的制定者,负责音频设备切换的策略抉择、音量调节策略等o AudioFlinger:音频策略的执行者,负责输入输出流设备的管理及音频流数据的处理传输•Audio HAL:音频硬件抽象层,负责与音频硬件设备的交互,由AudioFlinger 直接调用与Audio 强相关的有MultiMedia,MultiMedia 负责音视频的编解码,MultiMedia 将解码后的数据通过AudioTrack 输出,而AudioRecord 采集的录音数据交由 MultiMedia 进行编码。
ADP协议详析
A2DP 协议分析 1、 A2DP 整体协议结构2、 A2DP 音频 audio codec3、 GAVDP 分配设备角色4、 常见问题日志分析1、A2DP 整体协议结构A2DP 全程 Advaneed Audio Distribution Profile 建议在 AVDTP 协议之上的配置文件。
A2DP 定义了两种角色 audio source 和audio sink ,如下图所示。
左侧的source 端作为音频的输入端对音频数据进行编码后,通过两个设备之间建立的 链路发送给对方设备(sink 端),在sink 端收到音频数据后,进行解码操作还原出音频完成audio 数据传输。
Application Audio Source A A /DTP SDPLMPL2CAPApplication Audio Sink4 LVDTPSDPLMPL2CAPAudio Source SideACL Aixtio SourceAudio SinkEncodingDecodingEncryption (optional) Decryption (oplSal)L2CAPL2CAPtPacket FormatBasebandAudio Sink SideAVDTPAVDTPReceive AudioStre&mSend Audio Stream R.畑為 F^ykMdOP Con 临nt prcM&cbori haader MP M&dia packet hasder L2GARL2CAP reader2、A2DP 音频 codec蓝牙联盟规定sbccodec 强制支持,其他三种为可选。
SBC header Audio source 端的SBC 数据HCI 日志如下所示。
和上图的SBC 帧格式——对应。
0- 2DP:k Link! 15 -h 'Addr&ss: 2k- Role: Master (Audio Source] k-Codec : SBC□■- Media Pkl Headeri — Numter of &BC frames; 7]—L: Nd Iasi packet of fragmented SBC Frame!■■- G: Not stalling packet of Fiagmenled SBC Frame ■— SBC Frame: Nc^ hagmented © SBC Frame I Frame HeaderSyncWord: 0>i9c [-Sub_bands S|-”闯1口詢心11』础口d; LOUDNESSj j k Channel Mods: JailNT_STEREOk- Blocks: 16h - Sam plin g_fiec|: 44.1Sitpcd; 0H 35I ] h Bit Rate (kb/si : 327|j k' CFIC: 0x44Join with FIFA Oi»dcScale Factors :: Ox 77 75 55 30 36 75 45 40Audo Samples with Padding : Ox f6 a8 25d£ c4 ad 03 c6 be 6d 99 39 57 65 b5 e3 6baaad bb ZE ;其中channel mode 项表示音频的类型支持的参数如下所示, 单声道(MONO )、双声道(DUALOctetO Ocletl Octets Octet3Figure 4.1: Codec Spocific Information Elements for SBCMedia 数据包如下所示(a) When the media pay load contains an integral number of SBC frames(b) When the SBC frame is fragmentedFigure7& 5432 1 0| F ] _S _ L|[Number of frames| QctetOFigure 4.3: Header format of psyio&d for SBCF=1表示SBC 帧是分段的,后面只跟单个 SBC 帧S=1表示SBC 帧的start 包。
Audio Precision音频分析仪测试介绍
THD + N
Headphone output
THD + N
THD + N vs Level
THD + N
THD + N vs Level
THD + N
Headphone output
THD + N
Headphone output
THD + N
Headphone output
AP introduction
AP1 Panel
AP introduction
THD + N vs Level Curve
AP introduction
Analyzer Panel
AP introduction
Sweep Definitions Panel
AP introduction
2 – Signal, 3 – Ground.
e.g., Channel A: 2 – Left output, 3 – Ground
Ground
Channel B: 2 – Right output, 3 –
- Differential output (loudspeaker)
2 – Non-inverting signal, 3 – Inverting signal
Frequency Response - Frequency Response measurements are made by stepping or sweeping a sine wave oscillator, at a fixed amplitude, across the spectrum of interest. - Usually stated in terms of dB variation from some reference midband frequency(e.g., 1KHz). - The test may be easily modified. The frequency range and direction of sweep can be changed from the 20 KHz ~ 20 Hz stored by entering new values for START and STOP under SWEEP (F9) DEFINITIONS panel.
AudioEffect音频数据流笔记--buffer相关
AudioEffect⾳频数据流笔记--buffer相关AudioEffect笔记--buffer相关这⾥排版⽐较⿇烦,这⾥的排版会好看些:AudioEffect笔记--buffer相关android audio effect1 ⾳频数据流这⾥仅仅讨论mixerThread的流。
⾳频数据流如下图:2 mInBuffer、mOutBuffer设置mInBuffer、mOutBuffer的设置在创建effectChain时,调⽤addEffectChain_l()函数完成:1. status_tAudioFlinger::PlaybackThread::addEffectChain_l(const sp<EffectChain>& chain)2. {3. audio_session_t session = chain->sessionId();4. int16_t* buffer =reinterpret_cast<int16_t*>(mEffectBufferEnabled5. ? mEffectBuffer : mSinkBuffer);6. bool ownsBuffer =false;7.8. if(session > AUDIO_SESSION_OUTPUT_MIX){9. if(mType != DIRECT){10. /* 如果不是DIRECT流,则为该EffectChain创建输⼊buffer */11. size_t numSamples = mNormalFrameCount * mChannelCount;12. buffer =newint16_t[numSamples];13. memset(buffer,0, numSamples *sizeof(int16_t));14. ownsBuffer =true;15. }16.17. }18. chain->setThread(this);19. /* 如果不是DIRECT流,则把输⼊buffer设置为刚刚设置的buffer20. 如果是DIRECT流,则输⼊buffer为mEffectBuffer或mSinkBuffer */21. chain->setInBuffer(buffer, ownsBuffer);22. /* 设置输出buffer为mEffectBuffer或mSinkBuffer */23. chain->setOutBuffer(reinterpret_cast<int16_t*>(mEffectBufferEnabled24. mEffectBuffer : mSinkBuffer));25. }3 AudioTrack mMainBuffer设置mMainBuffer在创建EffectChain和AudioTrack时都会设置⼀次,在创建EffectChain时的设置如下:1. status_tAudioFlinger::PlaybackThread::addEffectChain_l(const sp<EffectChain>& chain)2. {3. audio_session_t session = chain->sessionId();4. int16_t* buffer =reinterpret_cast<int16_t*>(mEffectBufferEnabled5. ? mEffectBuffer : mSinkBuffer);6. bool ownsBuffer =false;7.8. if(session > AUDIO_SESSION_OUTPUT_MIX){9. /* 遍历该Thread下已经创建的所有Track */10. for(size_t i =0; i < mTracks.size();++i){11. sp<Track> track = mTracks[i];12. /* 找到sessionId与要创建的EffectChain相同的Track */13. if(session == track->sessionId()){14. /* 设置该Track的mMainBuffer为EffectChain的mInBuffer15. 这⾥的buffer实际上就是即将被设置为mInBuffer的内存16. 详细说明见上节 */17. track->setMainBuffer(buffer);18. /* 增加该chain的Track计数,如果track计数为0,那么表⽰19. 该effectChain没有使⽤者,在process时不会被启⽤ */20. chain->incTrackCnt();21. }22. }23. }24. }在创建AudioTrack时的设置如下:1. AudioFlinger::PlaybackThread::createTrack_l(){2. /* 获取跟创建的AudioTrack相同sessionId的effectChain */3. sp<EffectChain> chain = getEffectChain_l(sessionId);4. if(chain !=0){5. /* 如果找到了对应的chain,则把effectChain的mInBuffer设置为6. track的mMainBuffer*/7. track->setMainBuffer(chain->inBuffer());8. /* 设置effectChain的流策略 */9. chain->setStrategy(AudioSystem::getStrategyForStream(track->streamType()));10. /* 增加该effectChain的Track计数,如果track计数为0,那么表⽰11. 该effectChain没有使⽤者,在process时不会被启⽤ */12. chain->incTrackCnt();13. }14. }。
最新关于android电话录音问题的详细分析
关于a n d r o i d电话录音问题的详细分析关于android电话录音问题的详细分析作者:老猫一直以来都是在网络上看别人的文章,老老实实的做潜水员,今天一时兴起,写点东西,希望对大家有所帮助,不要再走同样的弯路。
本文是关于Android下录音问题的分析,网络上都说Android录音时记录下的语音信号都是混音器的信号。
但是都没有给出详细说明为什么是这样。
我们知道Android下进行电话录音的代码很简单:大致流程如下:recorder = new MediaRecorder();//这里mode可以设置为 VOICE_UPLINK|VOICE_DOWNLINK|VOICE_CALLrecorder.setAudioSource(mode);recorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT); recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); recorder.setOutputFile(recFile.getAbsolutePath());//准备录音recorder.prepare();//启动录音recorder.start();//停止录音recorder.stop();MediaRecorder.AudioSource中定义了以下常量可以用于recorder.setAudioSource这里和电话录音相关的有3个常量Voice_call 录制上行线路和下行线路Voice_uplink 录制上行线路,应该是对方的语音Voice_downlink 录制下行线路,应该是我方的语音网络上关于java层如何调用native代码的介绍很多,这里只做简单介绍。
JAVA中MediaRecorder的方法会掉用本地C++代码,这些代码编译后为libmedia.so,再通过进程间通信机制Binder和MediaServer通信,MediaServer收到请求后,把这些请求转发给opencore。
AudioFlinger分析
AudioFlinger分析一目的本文承接Audio第一部分的AudioTrack,通过AudioTrack作为AF(AudioFlinger)的客户端,来看看AF是如何完成工作的。
在AT(AudioTrack)中,我们涉及到的都是流程方面的事务,而不是系统Audio策略上的内容。
WHY?因为AT是AF的客户端,而AF是Android系统中Audio管理的中枢。
AT 我们分析的是按流程方法,那么以AT为切入点的话,AF的分析也应该是流程分析了。
对于分析AT来说,只要能把它的调用顺序(也就是流程说清楚就可以了),但是对于AF的话,简单的分析调用流程我自己感觉是不够的。
因为我发现手机上的声音交互和管理是一件比较复杂的事情。
举个简单例子,当听music的时候来电话了,声音处理会怎样?虽然在Android中,还有一个叫AudioPolicyService的(APS)东西,但是它最终都会调用到AF中去,因为AF实际创建并管理了硬件设备。
所以,针对Android声音策略上的分析,我会单独在以后来分析。
二从AT切入到AF直接从头看代码是没法掌握AF的主干的,必须要有一个切入点,也就是用一个正常的调用流程来分析AF的处理流程。
先看看AF的产生吧,这个C/S架构的服务者是如何产生的呢?2.1 AudioFlinger的诞生AF是一个服务,这个就不用我多说了吧?代码在framework/base/media/mediaserver/Main_mediaServer.cpp中。
int main(int argc, char** argv) {sp proc(ProcessState::self()); sp sm = defaultServiceManager(); ....AudioFlinger::instantiate();--->AF的实例化AudioPolicyService::instantiate();--->APS的实例化 ....ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); }哇塞,看来这个程序的负担很重啊。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第二部分 AudioFlinger分析一目的本文承接Audio第一部分的AudioTrack,通过AudioTrack作为AF(AudioFlinger)的客户端,来看看AF是如何完成工作的。
在AT(AudioTrack)中,我们涉及到的都是流程方面的事务,而不是系统Audio策略上的内容。
WHY?因为AT是AF的客户端,而AF是Android系统中Audio管理的中枢。
AT我们分析的是按流程方法,那么以AT为切入点的话,AF的分析也应该是流程分析了。
对于分析AT来说,只要能把它的调用顺序(也就是流程说清楚就可以了),但是对于AF的话,简单的分析调用流程我自己感觉是不够的。
因为我发现手机上的声音交互和管理是一件比较复杂的事情。
举个简单例子,当听music的时候来电话了,声音处理会怎样?虽然在Android中,还有一个叫AudioPolicyService的(APS)东西,但是它最终都会调用到AF 中去,因为AF实际创建并管理了硬件设备。
所以,针对Android声音策略上的分析,我会单独在以后来分析。
二从AT切入到AF直接从头看代码是没法掌握AF的主干的,必须要有一个切入点,也就是用一个正常的调用流程来分析AF的处理流程。
先看看AF的产生吧,这个C/S架构的服务者是如何产生的呢?2.1 AudioFlinger的诞生AF是一个服务,这个就不用我多说了吧?代码在framework/base/media/mediaserver/Main_mediaServer.cpp中。
int main(int argc, char** argv){sp<ProcessState> proc(ProcessState::self());sp<IServiceManager> sm = defaultServiceManager();....AudioFlinger::instantiate();--->AF的实例化AudioPolicyService::instantiate();--->APS的实例化....ProcessState::self()->startThreadPool();IPCThreadState::self()->joinThreadPool();}哇塞,看来这个程序的负担很重啊。
没想到。
为何AF,APS要和MediaService和CameraService都放到一个篮子里?看看AF的实例化静态函数,在framework/base/libs/audioFlinger/audioFlinger.cpp 中void AudioFlinger::instantiate() {defaultServiceManager()->addService( //把AF实例加入系统服务String16("media.audio_flinger"), new AudioFlinger());}再来看看它的构造函数是什么做的。
AudioFlinger::AudioFlinger(): BnAudioFlinger(),//初始化基类mAudioHardware(0), //audio硬件的HAL对象mMasterVolume(1.0f), mMasterMute(false), mNextThreadId(0){mHardwareStatus = AUDIO_HW_IDLE;//创建代表Audio硬件的HAL对象mAudioHardware = AudioHardwareInterface::create();mHardwareStatus = AUDIO_HW_INIT;if (mAudioHardware->initCheck() == NO_ERROR) {setMode(AudioSystem::MODE_NORMAL);//设置系统的声音模式等,其实就是设置硬件的模式setMasterVolume(1.0f);setMasterMute(false);}}AF中经常有setXXX的函数,到底是干什么的呢?我们看看setMode函数。
status_t AudioFlinger::setMode(int mode){mHardwareStatus = AUDIO_HW_SET_MODE;status_t ret = mAudioHardware->setMode(mode);//设置硬件的模式mHardwareStatus = AUDIO_HW_IDLE;return ret;}当然,setXXX还有些别的东西,但基本上都会涉及到硬件对象。
我们暂且不管它。
等分析到Audio策略再说。
好了,Android系统启动的时候,看来AF也准备好硬件了。
不过,创建硬件对象就代表我们可以播放了吗?2.2 AT调用AF的流程我这里简单的把AT调用AF的流程列一下,待会按这个顺序分析AF的工作方式。
--参加AudioTrack分析的4.1节1. 创建AudioTrack* lpTrack = new AudioTrack();lpTrack->set(...);这个就进入到C++的AT了。
下面是AT的set函数audio_io_handle_t output =AudioSystem::getOutput((AudioSystem::stream_type)streamType,sampleRate, format, channels, (AudioSystem::output_flags)flags);status_t status = createTrack(streamType, sampleRate, format, channelCount,frameCount, flags, sharedBuffer, output);----->creatTrack会和AF打交道。
我们看看createTrack重要语句const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();//下面很重要,调用AF的createTrack获得一个IAudioTrack对象sp<IAudioTrack> track = audioFlinger->createTrack();sp<IMemory> cblk = track->getCblk();//获取共享内存的管理结构总结一下创建的流程,AT调用AF的createTrack获得一个IAudioTrack对象,然后从这个对象中获得共享内存的对象。
2. start和write看看AT的start,估计就是调用IAudioTrack的start吧?void AudioTrack::start(){//果然啊...status_t status = mAudioTrack->start();}那write呢?我们之前讲了,AT就是从共享buffer中:●Lock缓存●写缓存●Unlock缓存注意,这里的Lock和Unlock是有问题的,什么问题呢?待会我们再说按这种方式的话,那么AF一定是有一个线程在那也是:●Lock,●读缓存,写硬件●Unlock总之,我们知道了AT的调用AF的流程了。
下面一个一个看。
2.3 AF流程1 createTracksp<IAudioTrack> AudioFlinger::createTrack(pid_t pid,//AT的pid号int streamType,//MUSIC,流类型uint32_t sampleRate,//8000 采样率int format,//PCM_16类型int channelCount,//2,双声道int frameCount,//需要创建的buffer可包含的帧数uint32_t flags,const sp<IMemory>& sharedBuffer,//AT传入的共享buffer,这里为空int output,//这个是从AuidoSystem获得的对应MUSIC流类型的索引status_t *status){sp<PlaybackThread::Track> track;sp<TrackHandle> trackHandle;sp<Client> client;wp<Client> wclient;status_t lStatus;{Mutex::Autolock _l(mLock);//根据output句柄,获得线程?PlaybackThread *thread = checkPlaybackThread_l(output);//看看这个进程是不是已经是AF的客户了//这里说明一下,由于是C/S架构,那么作为服务端的AF肯定有地方保存作为C的AT的信息//那么,AF是根据pid作为客户端的唯一标示的//mClients是一个类似map的数据组织结构wclient = mClients.valueFor(pid);if (wclient != NULL) {} else {//如果还没有这个客户信息,就创建一个,并加入到map中去client = new Client(this, pid);mClients.add(pid, client);}//从刚才找到的那个线程对象中创建一个tracktrack = thread->createTrack_l(client, streamType, sampleRate, format,channelCount, frameCount, sharedBuffer, &lStatus);}//喔,还有一个trackHandle,而且返回到AF端的是这个trackHandle对象trackHandle = new TrackHandle(track);return trackHandle;}这个AF函数中,突然冒出来了很多新类型的数据结构。
说实话,我刚开始接触的时候,大脑因为常接触到这些眼生的东西而死机!大家先不要拘泥于这些东西,我会一一分析到的。
先进入到checkPlaybackThread_l看看。
AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l(int output) const{PlaybackThread *thread = NULL;//看到这种indexOfKey的东西,应该立即能想到://喔,这可能是一个map之类的东西,根据key能找到实际的valueif (mPlaybackThreads.indexOfKey(output) >= 0) {thread = (PlaybackThread *)mPlaybackThreads.valueFor(output).get();}//这个函数的意思是根据output值,从一堆线程中找到对应的那个线程return thread;}看到这里很疑惑啊:●AF的构造函数中没有创建线程,只创建了一个audio的HAL对象●如果AT是AF的第一个客户的话,我们刚才的调用流程里边,也没看到哪有创建线程的地方呀。