Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :
文章目录
-
- 1、概述
-
- 1)应用怎么播放音频?
- 2)Android Framework层音频框架
- 2、AudioService (AS) -java
- 3、Audioserver(as)-native
- 4、AudioPolicyService(aps)-native
-
- 1、术语概念
- 2、AudioPolicyService的作用及形式
- 3、audio policy策略配置文件
-
- 1)配置文件类型
- 2)audio_policy.conf
- 3)audio_policy_configuration.xml
- 4、APS启动代码时序图
- 5、关键点代码分析
- 5、AudioFlinger(af) - native启动过程分析
-
- 1、术语概念
- 2、AudioFlingerService的作用
- 3、数据结构及代码时序图
-
- 1)数据结构 - HAL层的类图
- 2)数据结构 - AudioFlinger层 与 hal层的对接关系类图
- 4)AudioFlinger初始化代码流程图
- 6、AudioTrack创建过程
-
- 1、AudioTrack创建过程
- 2、选择一个output
- 3、创建Track代码流程图
- 4、共享内存机制
- 5、PlaybackThread
-
- 1)概述
- 2)数据结构 - playbackThread与Track类图
- 3)关键代码分析
- 6、AudioMix处理流程
-
- 1)概述
- 2)关键代码分析
- 3)如何实现混音?
- 7、Playback音频数据的传递
- 7、音量调节 - 综合应用
-
- 1)基本概念
- 2)讨论两种线程对音量的设置
- 3)数据结构与重点方法
- 4)代码时序图
1、概述
1)应用怎么播放音频?
先来看看一个APP播放多媒体音频示例程序import android.media.AudioFormat;import android.media.AudioTrack;import android.media.AudioAttributes;import android.media.AudioManager;public class AudioPlayer { private AudioTrack audioTrack; public void initAndPlay() { int sampleRateInHz = 44100; // 音频采样率 int channelConfig = AudioFormat.CHANNEL_OUT_STEREO; // 音频通道配置 int audioFormat = AudioFormat.ENCODING_PCM_16BIT; // 音频格式 int minBufferSize = AudioTrack.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat); // 创建 AudioTrack 对象 AudioAttributes attributes = new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_MEDIA) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) .build(); audioTrack = new AudioTrack( attributes, sampleRateInHz, channelConfig, audioFormat, minBufferSize, AudioTrack.MODE_STREAM ); // 生成示例音频数据(1秒 440Hz 的正弦波) int duration = 1; // 秒 int numSamples = sampleRateInHz * duration; short[] audioData = new short[numSamples]; double frequency = 440.0; // Hz double amplitude = 32767.0; // 最大振幅(16位PCM) for (int i = 0; i < numSamples; i++) { double angle = 2.0 * Math.PI * i * frequency / sampleRateInHz; audioData[i] = (short) (Math.sin(angle) * amplitude); } // 开始播放 audioTrack.play(); // 将音频数据写入 AudioTrack audioTrack.write(audioData, 0, audioData.length); // 停止播放并释放资源 audioTrack.stop(); audioTrack.release(); }}
APP播放音频流只需要简单的几个步骤
new AudioTrack()
AudioTrack.play()
AudioTrack.write()
2)Android Framework层音频框架
1、组件和术语
1、AudioTrack : 音轨2、AudioRecord: 录音3、AudioFlinger : native层server4、stream type : 声音类型5、policy :罗列各类条件 - 优先级、选择设备6、headset/headphone(不带麦克风)7、APM:audio policy management 音频策略管理
2、重点分析
1)AudioTrack / AuioRecord是Framework层给APP调用的最上层接口,接下来以AudioTrack作为线索往下研究分析2)绝大部分核心实现都在native层,java层的Service只是对native层的进一步封装,接下来重点分析native层的AudioPolicyService/AudioFlinger3)注意音频子系统中的数据结构庞大,更不好的是 各个层级的命名不统一(估计是Google不同工程师编写),令人混乱!
2、AudioService (AS) -java
1、AudioServiceandroid\\frameworks\\base\\services\\core\\java\\com\\android\\server\\audio\\AudioService.javaAudioService用于管理音频设备路由策略,即java层对AudioPolicyService封装
3、Audioserver(as)-native
android\\frameworks\\av\\media\\audioserver\\main_audioserver.cpp //注意audio/media是分开的cc_binary { name: \"audioserver\", shared_libs: [ \"packagemanager_aidl-cpp\", \"libaaudioservice\", \"libaudioclient\", \"libaudioflinger\", \"libaudiopolicyservice\", \"libaudioprocessing\",}
4、AudioPolicyService(aps)-native
1、术语概念
深度分析:https://blog.csdn.net/yangwen123/article/details/39497375术语1、spatializer:空间音响2、关键点:1、android\\frameworks\\av\\services\\audiopolicy\\service\\AudioPolicyService.cppvoid AudioPolicyService::onFirstRef() //指南指针的强引用机制{}AudioPolicyService继承RefBase(Android引用计数基类),当new sp时,引用计数从0变1,触发onFirstRef();C++中,构造函数和onFirstRef,有什么不同,执行优先级?1)构造函数在创建对象时触发;2)OnFirstRef在引用对象时触发(传参也算引用),用于延迟初始化,这样可以节省资源;相当于将构造函数分开两个地方放,看代码时都要看!2、CPP11以后引入的显示底层类型枚举enum enum_name1 : underlying_type {}enum_name23、Vector / Collection机制class HwAudioOutputCollection : public DefaultKeyedVector< audio_io_handle_t, sp >{}DefaultKeyedVector是一个容器类,结合Vector和HashMap的特性typedef Vector<sp > OutputProfileCollection;
2、AudioPolicyService的作用及形式
1、路由作用
1)基本作用就是将上层抛下来的数据传给哪种设备播放,及路由作用;
2)为什么单独拎出来,用Switch不就完事了?原因是Android音频播放设计得比较复杂,有较多拓扑关系,单看Stream Type的类型就够多够复杂,这样可以实现多种表现满足用户要求
举个例子:
stream type为VOICE CALL时,没有接耳机时,从喇叭输出;接耳机时,从耳机和喇叭同时输出;
用户使用过程中有更复杂的组合场景,当然不同设备(手机/TV…)的复杂度也是不同;
2、AudioTrack、AudioPolicyService和AudioFlinger的层级关系
1)AudioPolicyService充当“switch”角色,将各种STREAM_TYPE 的Track数据分发给AudioFlinger层的PlaybackThread处理;
2)一种类型STREAM_TYPE对应一个PlaybackThread线程;
3、audio policy策略配置文件
1)配置文件类型
一般放置在device目录下,比如/android/device/mediatek/mt5862/common/audio_policy/Android下的文件策略配置文件1)低版本(Android 7.0)audio_policy_configuration.xml对应的加载函数:AudioPolicyConfig::loadFromXmlAndroid 7.0后推出,能描述复杂的音频拓扑,例如电视和汽车等行业audio_policy.conf还有必要了解? 代码中还有保留这部分逻辑,需要了解识别!
2)audio_policy.conf
audio_policy.conf一个简单的例子如下a2dp { //称为Module 或 HwModule 或interface outputs { a2dp { sampling_rates 44100|48000 channel_masks AUDIO_CHANNEL_OUT_STEREO formats AUDIO_FORMAT_PCM_16_BIT devices AUDIO_DEVICE_OUT_ALL_A2DP } } # a2dp sink inputs { a2dp { sampling_rates 44100 channel_masks AUDIO_CHANNEL_IN_STEREO formats AUDIO_FORMAT_PCM_16_BIT devices AUDIO_DEVICE_IN_BLUETOOTH_A2DP } }}1、module 一般指一个厂商提供的一个HAL库(可以理解为一个音频系统下的子系统!),AudiopolicyService会根据这个字段找到对应的库(格式audio.\"module\".default.so,比如audio.a2dp.default.so,那还不如直接写库的名称更为直接!),module一般包含一个output和input,也就是这个库所驱动的外设,output/input设备就比较多种多样了。2、一个简单的例子1)output:包含一个speaker(device)和earphone(device),他们具备同样的profile,所以放在一起,从上层来看,他们没有区别,音频数据往这个output塞,因为上层知道他们都可以处理,至于最终走哪个device,由其它条件决定;2)input:包含一个headset和bluetooth,同理3、文件路径1)在线路径(板卡):/vendor/etc/audio_policy.conf2)离线路径(跟厂商):android/device/mediatek/audio_policy
为何这样分类设计?根据产品的设计和管理来进行理解
3)audio_policy_configuration.xml
1、拓扑关系
(1)理解并区分两个概念:policy (策略/路由) 、profile(配置/属性)
2、xml对应的类图
相当复杂,了解即可,工程应用上只需配置xml
1)基础类型
2)HwModule/AudioPolicyConfig
3)AudioOutputDescripter/AudioInputDescripter
4、APS启动代码时序图
1)重点数据结构和方法
Policy相关的类图
1、AudioPolicyService统一向上提供服务接口(binder接口)
2、AudioPolicyManger负责厂家策略服务,AudioPolicyClient则负责调用AudioFlinger接口
3、MAudioPolicyManager 来自厂家提供的libaudiopolicymanagercustom.so,主要作用是调用
4、AudioSystem封装AudioFlinger接口 提供给AudioPolicyClient
7、Engine - 负责路由的选择,比如决出最适合的output
1)Engine.cpp(在高Android版本才有此模块,抽离出来 让厂商来制定路由)
2)低版本函数getDeviceForStrategy() 对应Engine模块的getOutputDevicesForAttributes()
3)几个重要函数
mEngine->getOutputDevicesForAttributes()
mEngine->getAllAttributesForProductStrategy()
mEngine->getOrderedProductStrategies()
8、小结几个重点类的关系:AudioPolicyServiceAudioPolicyManagerEngine
2)初始化逻辑
5、关键点代码分析
1、AudioPolicyClient 是 AudioFliger 的客户端2、AudioPolicyService访问AudioFlinger需要跨进程? >> 需要,属于两个服务(但属于Binder同进程通讯,注意区分),在main_audioserver.cpp中启动sp sm = defaultServiceManager();sm->addService(String16(IAudioFlinger::DEFAULT_SERVICE_NAME), afAdapter,false /* allowIsolated */, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT);sm->addService(String16(AudioPolicyService::getServiceName()), aps,false /* allowIsolated */, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT);3、audio_policy_configuration.xml 对应的数据结构在哪里解析?android\\frameworks\\av\\services\\audiopolicy\\common\\managerdefinitions\\src //每一项都有对应的类xml是什么?audio_policy_configuration.xml/vendor/etc/audio_policy_configuration.xml4、AudioSystem.cpp均是静态方法,不需要new 即可调用status_t AudioPolicyService::AudioPolicyClient::getAudioPolicyConfig( media::AudioPolicyConfig *config){ sp af = AudioSystem::get_audio_flinger(); return af->getAudioPolicyConfig(config);}5、AudioPolicyService中的CommandStatus AudioPolicyService::onNewAudioModulesAvailable(){ mOutputCommandThread->audioModulesUpdateCommand(); return Status::ok();}6、MAudioPolicyManager 厂商部分代码的嵌入设计1)厂家部分 封装成一个库 1、一部分是class内容(继承AudioPolicyManager);2、另一部分是: extern \"c\" function (dlopen,主要负责初始化);>> 这样设计的好处?
5、AudioFlinger(af) - native启动过程分析
1、delegate : 授权2、如何打开devices?AUDIO_DEVICE_OUT_SPEAKER //枚举变量为什么用线程来接收track?1、CPP中的命名空间和前向声明namespace android {class StreamInHalInterface;class StreamOutHalInterface;class DeviceHalInterface : public virtual RefBase{}//前向声明(Forward Declaration),仅使用此类的指针或引用,无需知道类的具体结构,前向声明即可满足;解决头文件依赖(会触发对应源文件的编译)和循环依赖;2、android\\frameworks\\av\\services\\audioflinger\\AudioFlinger.cppmDevicesFactoryHal = DevicesFactoryHalInterface::create(); //打开hal库,获取hal接口mEffectsFactoryHal = audioflinger::EffectConfiguration::getEffectsFactoryHal(); //音频效果3、AudioFlingerService 优先于 AudioPolicyService启动;后者需要调用前者4、AudioFlingerClientAdapter?//用于封装处理Binder IPC(aidl) 通信异常情况- AudioFlingerstatic inline ::android::status_t statusTFromBinderStatus(const ::android::binder::Status &status) { return status.isOk() ? ::android::OK // check ::android::OK, : status.serviceSpecificErrorCode() // service-side error, not standard Java exception// (fromServiceSpecificError) ?: status.transactionError() // a native binder transaction error (fromStatusT) ?: statusTFromExceptionCode(status.exceptionCode()); // a service-side error with a // standard Java exception (fromExceptionCode)}5、Delagate代理模式-与继承功能相反1)适合基类会变化,而子类不会变化的情况class AudioFlingerServerAdapter : public media::BnAudioFLingerService {public: using Status = binder::Status; class Delegate : public IAudioFling { friend class AudioFlingerServerAdapter; } explicit AudioFlingerServerAdapter(const sp& delegate)private: sp mDelegate;}6、通过aidl访问hal层android\\frameworks\\av\\media\\libaudiohal\\impl\\DevicesFactoryHalAidl.cppif (std::find(deviceNames.begin(), deviceNames.end(), name) != deviceNames.end()) { if (strcmp(name, \"primary\") == 0) name = \"default\"; auto serviceName = std::string(IModule::descriptor) + \"/\" + name; service = IModule::fromBinder( ndk::SpAIBinder(AServiceManager_waitForService(serviceName.c_str()))); //获取aidl服务 ALOGE_IF(service == nullptr, \"%s fromBinder %s failed\", __func__, serviceName.c_str());}7、hal1)android\\frameworks\\av\\media\\libaudiohal\\impl2)android\\frameworks\\av\\media\\libaudiohal\\include\\media\\audiohal充斥着大量的跨进程封装(parcel/错误处理/返回值处理等等),使用factory模式 兼容hidl和aidl
1、术语概念
2、AudioFlingerService的作用
3、数据结构及代码时序图
1)数据结构 - HAL层的类图
1、为什么如此复杂?为了适应不同系统版本共存的HAL/HIDL/AIDL方式
2、以AIDL为例:DevicesFactoryHalAidl包含DeviceHalAidl (hal接口)
2)数据结构 - AudioFlinger层 与 hal层的对接关系类图
1)AudioHwDevice对应的是audio policy策略文件中的module,在AudioPolicyService中又被称为HwModule!
4)AudioFlinger初始化代码流程图
1、PlaybackTread是AudioFlinger模块中的组成,在初始化时创建,循环地将音频从共享内存中稍加处理后送到硬件中;
2、创建MixerThread(由audio_policy_configuration.xml决定创建哪种类型的Thread)后,上层即可从mPlaybackTrreads选择对应的Thread丢数据;
3、应用给底层丢数据的过程如下:
一种类型STREAM_TYPE对应一个PlaybackThread线程;
4、audio_io_handle_t
audio_io_handle_t是一个全局唯一的整形值,作为键值对的索引值key,在output中对应PlaybackThread/* AudioFlinger and AudioPolicy services use I/O handles to identify audio sources and sinks */typedef int audio_io_handle_t;audio_io_handle_t AudioFlinger::openDuplicateOutput(audio_io_handle_t output1, audio_io_handle_t output2){... mPlaybackThreads.add(id, thread); // notify client processes of the new output creation thread->ioConfigChanged(AUDIO_OUTPUT_OPENED); return id;}
6、AudioTrack创建过程
1、playback: 重放2、offload : 音频数据不解码,即软件不解码,硬件负责解码3、time-stretch : 时间拉伸,对应音频的加速4、fallback : 回放5、MSD :multi-Stream Decoder6、underrun : 生产速度 赶不上 消费速度10、一个音轨Track对应一个共享内存,一个APP只能对应一个Track;AudioFlinger会轮训多个Track,送进mixer,混合后给到output->device;1、android\\frameworks\\av\\media\\libaudioclient\\AudioSystem.cpp2、android\\frameworks\\av\\media\\libaudioclient\\AudioTrack.cppconst sp& aps = AudioSystem::get_audio_policy_service(); //获取AudioFliger接口
1、AudioTrack创建过程
先来看从java层如何使用AudioTrack
1、播放音频流几个步骤new AudioTrackAudioTrack.set()AudioTrack.start()2、调用native方法创建Trackandroid\\frameworks\\base\\media\\java\\android\\media\\AudioTrack.javaint initResult = native_setup();3、写共享内存public int write(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes) { return write(audioData, offsetInBytes, sizeInBytes, WRITE_BLOCKING);}final int ret = native_write_byte(audioData, offsetInBytes, sizeInBytes, mAudioFormat, writeMode == WRITE_BLOCKING);
2、选择一个output
1、基础数据结构
1、audio_flags_mask_ttypedef enum { AUDIO_FLAG_NONE = 0x0, AUDIO_FLAG_AUDIBILITY_ENFORCED = 0x1, //不能被静音,比如防止偷拍 AUDIO_FLAG_SECURE = 0x2, //音频加密类型,受数字版权管理(DRM) AUDIO_FLAG_SCO = 0x4, //SCO Synchronous Connection-Oriented 蓝牙 AUDIO_FLAG_BEACON = 0x8,}2、enum legacy_strategy { STRATEGY_NONE = -1, STRATEGY_MEDIA, //媒体播放的音频策略 STRATEGY_PHONE, //通话的音频策略 STRATEGY_SONIFICATION, //系统提示音 STRATEGY_SONIFICATION_RESPECTFUL, //尊重用户环境的系统提示音 STRATEGY_DTMF, //双音多频(DTML), 蓝牙设备 STRATEGY_ENFORCED_AUDIBLE, //强制可听 STRATEGY_TRANSMITTED_THROUGH_SPEAKER, //通过speaker STRATEGY_ACCESSIBILITY, //辅助功能 STRATEGY_REROUTING, //音频重路由 STRATEGY_CALL_ASSISTANT, //通话辅助};stream_type(music-细分) -> strategy(media-粗分)
audio_stream_type_t、audio_attributes_t、Strategy、Device的关联关系
2、决出一个output,选择大致过程简述:
1)stream type->attribute(属性)->stratege(根据属性分组/类别)->device(此类别所对应的设备)->output(支持此设备的output,有一定的优先级)2)AudioPolicyManager根据stream type获取合适的output(由Engine模块来负责决策)audio_io_handle_t AudioPolicyManager::getOutput(audio_stream_type_t stream){ DeviceVector devices = mEngine->getOutputDevicesForStream(stream, false /*fromCache*/); SortedVector
3、创建Track代码流程图
4、共享内存机制
1)基本数据结构(无非就是将实体往上封装 加点管理接口)
2)共享内存(cbk : control block)示意图
3)重点部分
1、基本数据结构定义的头文件android\\frameworks\\av\\include\\private\\media\\AudioTrackShared.h2、通过共享内存提供音频数据的两种方式1)一次性提供方式(MODE_STATIC,也称为静态模式),适合音频数据很小的场合,比如系统铃声,警告声;流式提供(MODE_STREAM,也称流模式),比如音乐;2)MODE_STATIC、MODE_STREAM对应的共享内存创建者不同android\\frameworks\\base\\core\\jni\\android_media_AudioTrack.cppstatic jint android_media_AudioTrack_setup(...,jint memoryMode, ...)switch (memoryMode) { case MODE_STREAM: //APP层不创建内容,由AudioFlingerService负责创建,需要复杂的管理机制支持(环形buffer),底层控制实现 status = lpTrack->set(); break; case MODE_STATIC: //APP层创建共享内存,因为是一次性任务,不需要管理,直接APP层创建好传给底层即可 { // AudioTrack is using shared memory const auto iMem = allocSharedMem(buffSizeInBytes); if (iMem == nullptr) { ALOGE(\"Error creating AudioTrack in static mode: error creating mem heap base\"); goto native_init_failure; } status = lpTrack->set(..,iMem,..); break; }}3)AudioFlingerService创建共享内存1、共享内存相关的变量android\\frameworks\\av\\services\\audioflinger\\TrackBase.hclass TrackBase : public ExtendedAudioBufferProvider, public RefBase { sp mCblkMemory; audio_track_cblk_t* mCblk; sp mBufferMemory; // currently non-0 for fast RecordTrack only void* mBuffer; // start of track buffer, typically in shared memory // except for OutputTrack when it is in local memory size_t mBufferSize; // size of mBuffer in bytes}2、分配内存android\\frameworks\\av\\services\\audioflinger\\Tracks.cppAudioFlinger::ThreadBase::TrackBase::TrackBase(){ if (client != 0) { mCblkMemory = client->allocator().allocate(mediautils::NamedAllocRequest{{size}, std::string(\"Track ID: \").append(std::to_string(mId))}); } else { mCblk = (audio_track_cblk_t *) malloc(size); }}3、Tracks.cpp : AudioTrackServerProxy和StaticAudioTrackServerProxy都是负责管理共享内存的类AudioFlinger::PlaybackThread::Track::Track(){ if (sharedBuffer == 0) { mAudioTrackServerProxy = new AudioTrackServerProxy(mCblk, mBuffer, frameCount, mFrameSize, !isExternalTrack(), sampleRate); //对应MODE_STATIC } else { mAudioTrackServerProxy = new StaticAudioTrackServerProxy(mCblk, mBuffer, frameCount, mFrameSize, sampleRate); //对应MODE_STATIC }}4、AudioFlinger::PlaybackThread::OutputTrack::OutputTrack( mClientProxy = new AudioTrackClientProxy(mCblk, mBuffer, mFrameCount, mFrameSize,}
4、共享内存采用的是Ashmem匿名共享机制
5、PlaybackThread
1)概述
疑问:1、音频数据格式 谁来解析处理?编解码模块(Codec)负责处理2、Mix 原理是什么?1、PlaybackThread的作用及整体的处理音频数据流程1)PlaybackTread是AudioFlinger模块中的组成,在初始化时创建,循环地将音频从共享内存中稍加处理后送到硬件中;2)整理流程:轮询共享内存 -> 取出处理 -> 送到HAL层去 -> 硬件播放
2)数据结构 - playbackThread与Track类图
1、audio_track_cblk_t 是共享内存 控制块,用于音频流的传送
2、PlaybackThread中对Track的管理
3)关键代码分析
1、Threads.cppAudioFlinger::PlaybackThread::PlaybackThread(const sp& audioFlinger, AudioStreamOut* output, audio_io_handle_t id, type_t type, bool systemReady, audio_config_base_t *mixerConfig) : ThreadBase(audioFlinger, id, type, systemReady, true /* isOut */), mNormalFrameCount(0), mSinkBuffer(NULL),{ }2、整体流程1)onFirstRef执行runvoid AudioFlinger::PlaybackThread::onFirstRef(){ if (!isStreamInitialized()) { ALOGE(\"The stream is not open yet\"); // This should not happen. } run(mThreadName, ANDROID_PRIORITY_URGENT_AUDIO); mThreadSnapshot.setTid(getTid());}2)进入子线程循环体bool AudioFlinger::PlaybackThread::threadLoop(){ .... for (int64_t loopCount=0; !exitPending(); ++loopCount) { // mMixerStatusIgnoringFastTracks is also updated internally mMixerStatus = prepareTracks_l(&tracksToRemove); //取出Track音频数据 .... if (mBytesRemaining == 0) { mCurrentWriteLength = 0; if (mMixerStatus == MIXER_TRACKS_READY) { // threadLoop_mix() sets mCurrentWriteLength threadLoop_mix(); //对音频数据进行mix } } .... if (!waitAsynCallback()) { ret = threadLoop_write(); //调用hal接口写入硬件 } } .... threadLoop_exit();}3)threadLoop_write()ssize_t AudioFlinger::MixerThread::threadLoop_write() { return PlaybackThread::threadLoop_write();}ssize_t AudioFlinger::PlaybackThread::threadLoop_write(){ if(mNormalSink != 0) { //采用NBAIO(Non-blocking Audio I/O),即先将数据送进缓冲区,让软件进一步处理(比如mix混音),再通过非阻塞方式将数据传输到音频硬件 ssize_t frameWritten = mNormalSink->write((char *)mSinkBuffer + offset, count); }else{ //Direct output and offload, 即不进行音频处理,直接调用hal接口写入,比如HDMI设备 bytesWritten = mOutput->write((char *)mSinkBuffer + offset, mBytesRemaining); }}
6、AudioMix处理流程
1)概述
每一个MixerThread都有一个唯一对应的AudioMixer,接口如下
2)关键代码分析
1、调用处android\\frameworks\\av\\services\\audioflinger\\Threads.cppvoid AudioFlinger::MixerThread::threadLoop_mix(){ //mix buffers.. mAudioMixer->process();}2、Mixer的内部实现android\\frameworks\\av\\media\\libaudioprocessing\\include\\media\\AudioMixerBase.hclass AudioMixer : public AudioMixerBase{ //process的实现如下,调用mHook,mHooK会根据不同场景赋值,指向不同的函数 void process() { preProcess(); (this->*mHook)(); postProcess(); } // process hook functionality - 函数指针,指向AudioMixerBase的函数 using process_hook_t = void(AudioMixerBase::*)(); process_hook_t mHook = &AudioMixerBase::process__nop; // one of process__*, never nullptr //函数指针,指向TrackBase的函数 using hook_t = void(TrackBase::*)(int32_t* output, size_t numOutFrames, int32_t* temp, int32_t* aux); hook_t hook; void process__validate(); void process__nop(); void process__genericNoResampling(); //两路以上Track,不重采样 void process__genericResampling(); //两路以上Track,重采样 void process__oneTrack16BitsStereoNoResampling();//只有一路Track,16bit 立体声,不重采样}注意AudioMixer和TrackBase是共用音频数据缓冲区的
mHook的变化图
3)如何实现混音?
1、以process__genericResampling为例void AudioMixerBase::process__genericResampling(){ ALOGVV(\"process__genericResampling\\n\"); int32_t * const outTemp = mOutputTemp.get(); // 临时buffer存放Track size_t numFrames = mFrameCount; for (const auto &pair : mGroups) { const auto &group = pair.second; const std::shared_ptr &t1 = mTracks[group[0]]; //应用程序提供的Track数据 // clear temp buffer memset(outTemp, 0, sizeof(*outTemp) * t1->mMixerChannelCount * mFrameCount); for (const int name : group) { const std::shared_ptr &t = mTracks[name]; int32_t *aux = NULL; if (CC_UNLIKELY(t->needs & NEEDS_AUX)) { aux = t->auxBuffer; } // this is a little goofy, on the resampling case we don\'t // acquire/release the buffers because it\'s done by // the resampler. if (t->needs & NEEDS_RESAMPLE) { (t.get()->*t->hook)(outTemp, numFrames, mResampleTemp.get() /* naked ptr */, aux); } else { size_t outFrames = 0; while (outFrames buffer.frameCount = numFrames - outFrames; t->bufferProvider->getNextBuffer(&t->buffer); t->mIn = t->buffer.raw; // t->mIn == nullptr can happen if the track was flushed just after having // been enabled for mixing. if (t->mIn == nullptr) break; (t.get()->*t->hook)( outTemp + outFrames * t->mMixerChannelCount, t->buffer.frameCount, mResampleTemp.get() /* naked ptr */, aux != nullptr ? aux + outFrames : nullptr); outFrames += t->buffer.frameCount; t->bufferProvider->releaseBuffer(&t->buffer); } } } convertMixerFormat(t1->mainBuffer, t1->mMixerFormat, outTemp, t1->mMixerInFormat, numFrames * t1->mMixerChannelCount); //转换格式,最终数据存放在t1->mainBuffer中 }}总的来说就是将各个Track音频数据叠加起来,实现混音
7、Playback音频数据的传递
AudioTrack或AudioFlingerService创建好共享内存,APP只需要将数据写进共享内存,并通知AudioFlingerService(主要是PLaybackThread和AudioMix)进行处理即可,我们从宏观上了解交互控制部分,其它细节比较晦涩(极端buffer大小等)不好记忆,这里不展开,需要了解时再去琢磨
1)Audio Playback数据流传递如下
2)AudioTrack(生产者-user) 与AudioFlinger(消费者-Server)的数据交互大致如下
3)环形缓冲区
4)AudioTrack与AudioFlinger都通过obtainBuffer和releaseBuffer来获取/释放同一块缓冲区,
如何实现互斥?这两个方法使用Mutex实现互斥功能
7、音量调节 - 综合应用
1)基本概念
master volume //Android框架中的主音量,决定全局的音量
stream volume //Android框架中的流类型音量,决定局部(比如铃声/电话/音乐)的音量
stream volume alias //Android框架中的流类型音量,即对stream volume二次分类
track volume //音频流中的音量( 附属在音频数据中 )
无论是AudioTrack volume、stream volume, 都是单独设置.
能否通过某个变量影响到所有stream、所有AudioTrack的音量?
有!这就是 master volume, 这个值是可以直接用来控制声卡的
音量处理公式:final volume = master volume * stream volume * stream volume alias * track volume
2)讨论两种线程对音量的设置
1)哪里决定使用哪种线程驱动声卡?
audio_policy_configuration.xmlflags=\"AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ\" maxOpenCount=\"2\" maxActiveCount=\"1\">
2)数据流简图
1、对于MixerThread
APP对音量的设置不会影响到声卡的硬件音量,而只会影响APP的音频数据的幅值(变小或放大),这些音频数据最终被混合后传给声卡,多个APP本身的音量设置互不影响对于混音的音量处理公式app1: data1_mix = data1_in * master_volume * stream1_volume * AudioTrack1_volumeapp2: data2_mix = data2_in * master_volume * stream2_volume * AudioTrack2_volume混合在一起:data_mix = data1_mix + data2_mix
2、对于DirectOutputThread
同一时间里只有一个APP、只有一个AudioTrack使用它,
所以该AudioTrack的音量可以被DirectOutputThread直接用来设置硬件音量
3)数据结构与重点方法
1、基本数据结构
1、android\\frameworks\\av\\services\\audioflinger\\AudioFlinger.hstruct stream_type_t { stream_type_t() : volume(1.0f), mute(false) { } float volume; bool mute; };2、android\\frameworks\\av\\services\\audioflinger\\AudioFlinger.hclass AudioFlinger : public AudioFlingerServerAdapter::Delegate{ // member variables below are protected by mLock float mMasterVolume; bool mMasterMute; float mMasterBalance = 0.f; // end of variables protected by mLock}3、void AudioFlinger::PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value){ Mutex::Autolock _l(mLock); mStreamTypes[stream].volume = value; broadcast_l();}4、status_t AudioFlinger::setMasterVolume(float value){ Mutex::Autolock _l(mLock); mMasterVolume = value; //设置设备的主音量 AudioHwDevice *dev = mAudioHwDevs.valueAt(i); dev->hwDevice()->setMasterVolume(value); //如果声卡不支持主音量设置,在每个PlaybackThreads中设置软件\"主音量\" mPlaybackThreads.valueAt(i)->setMasterVolume(value); return NO_ERROR;}
2、Mixer中对音量的控制
android\\frameworks\\av\\media\\libaudioprocessing\\include\\media\\AudioMixerBase.hclass AudioMixerBase{ struct TrackBase { // TODO: Eventually remove legacy integer volume settings union { int16_t volume[MAX_NUM_VOLUMES]; // U4.12 fixed point (top bit should be zero) int32_t volumeRL; }; int32_t prevVolume[MAX_NUM_VOLUMES]; int32_t volumeInc[MAX_NUM_VOLUMES]; int32_t auxInc; int32_t prevAuxLevel; int16_t auxLevel; // 0 <= auxLevel <= MAX_GAIN_INT, but signed for mul performance float mVolume[MAX_NUM_VOLUMES]; // floating point set volume float mPrevVolume[MAX_NUM_VOLUMES]; // floating point previous volume float mVolumeInc[MAX_NUM_VOLUMES]; // floating point volume increment float mAuxLevel; // floating point set aux level float mPrevAuxLevel; // floating point prev aux level float mAuxInc; // floating point aux increment }}aux:指的是单声道设备
prevolume/inc/volume的关系,目的是为了平缓音量的变化,避免对用户产生不适
3、音量最终在哪里生效?
android\\frameworks\\av\\services\\audioflinger\\Threads.cppAudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTracks_l( Vector< sp
4)代码时序图
1、
2、用户按下音量键先进入输入子系统,再转到音频子系统处理
1、输入子系统入口android\\frameworks\\base\\services\\core\\java\\com\\android\\server\\policy\\PhoneWindowManager.javapublic long interceptKeyBeforeDispatching(IBinder focusedToken, KeyEvent event, int policyFlags) {}2、音频子系统入口android\\frameworks\\base\\services\\core\\java\\com\\android\\server\\audio\\AudioService.javapublic void handleVolumeKey(@NonNull KeyEvent event, boolean isOnTv, @NonNull String callingPackage, @NonNull String caller) {}3、音量相关的keyeventcase KeyEvent.KEYCODE_VOLUME_UP:case KeyEvent.KEYCODE_VOLUME_DOWN:case KeyEvent.KEYCODE_VOLUME_MUTE: