> 技术文档 > Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

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层音频框架

Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

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、路由作用
Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

1)基本作用就是将上层抛下来的数据传给哪种设备播放,及路由作用;

2)为什么单独拎出来,用Switch不就完事了?原因是Android音频播放设计得比较复杂,有较多拓扑关系,单看Stream Type的类型就够多够复杂,这样可以实现多种表现满足用户要求

Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

举个例子:

stream type为VOICE CALL时,没有接耳机时,从喇叭输出;接耳机时,从耳机和喇叭同时输出;

用户使用过程中有更复杂的组合场景,当然不同设备(手机/TV…)的复杂度也是不同;

2、AudioTrack、AudioPolicyService和AudioFlinger的层级关系
Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

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

为何这样分类设计?根据产品的设计和管理来进行理解
Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

3)audio_policy_configuration.xml

1、拓扑关系
Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

(1)理解并区分两个概念:policy (策略/路由) 、profile(配置/属性)

2、xml对应的类图

相当复杂,了解即可,工程应用上只需配置xml

1)基础类型
Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

2)HwModule/AudioPolicyConfig
Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

3)AudioOutputDescripter/AudioInputDescripter
Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

4、APS启动代码时序图

1)重点数据结构和方法

Policy相关的类图
Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

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)初始化逻辑Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

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层的类图

Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

1、为什么如此复杂?为了适应不同系统版本共存的HAL/HIDL/AIDL方式

2、以AIDL为例:DevicesFactoryHalAidl包含DeviceHalAidl (hal接口)

2)数据结构 - AudioFlinger层 与 hal层的对接关系类图

Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

1)AudioHwDevice对应的是audio policy策略文件中的module,在AudioPolicyService中又被称为HwModule!

4)AudioFlinger初始化代码流程图

Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

1、PlaybackTread是AudioFlinger模块中的组成,在初始化时创建,循环地将音频从共享内存中稍加处理后送到硬件中;

2、创建MixerThread(由audio_policy_configuration.xml决定创建哪种类型的Thread)后,上层即可从mPlaybackTrreads选择对应的Thread丢数据;

3、应用给底层丢数据的过程如下:
Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

一种类型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、基础数据结构
Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

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的关联关系
Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

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代码流程图

Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

4、共享内存机制

1)基本数据结构(无非就是将实体往上封装 加点管理接口)
Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

2)共享内存(cbk : control block)示意图
Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

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匿名共享机制
Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

5、PlaybackThread

1)概述
疑问:1、音频数据格式 谁来解析处理?编解码模块(Codec)负责处理2、Mix 原理是什么?1、PlaybackThread的作用及整体的处理音频数据流程1)PlaybackTread是AudioFlinger模块中的组成,在初始化时创建,循环地将音频从共享内存中稍加处理后送到硬件中;2)整理流程:轮询共享内存 -> 取出处理 -> 送到HAL层去 -> 硬件播放
2)数据结构 - playbackThread与Track类图

Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

1、audio_track_cblk_t 是共享内存 控制块,用于音频流的传送

2、PlaybackThread中对Track的管理
Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

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,接口如下
Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

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的变化图
Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

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数据流传递如下
Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

2)AudioTrack(生产者-user) 与AudioFlinger(消费者-Server)的数据交互大致如下
Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

3)环形缓冲区
Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

4)AudioTrack与AudioFlinger都通过obtainBuffer和releaseBuffer来获取/释放同一块缓冲区,

如何实现互斥?这两个方法使用Mutex实现互斥功能

7、音量调节 - 综合应用

1)基本概念

master volume //Android框架中的主音量,决定全局的音量
stream volume //Android框架中的流类型音量,决定局部(比如铃声/电话/音乐)的音量
stream volume alias //Android框架中的流类型音量,即对stream volume二次分类
track volume //音频流中的音量( 附属在音频数据中 )
Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

无论是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)数据流简图
Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

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的关系,目的是为了平缓音量的变化,避免对用户产生不适
Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

3、音量最终在哪里生效?

android\\frameworks\\av\\services\\audioflinger\\Threads.cppAudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTracks_l( Vector< sp > *tracksToRemove){// cache the combined master volume and stream type volume for fast mixer; this // lacks any synchronization or barrier so VolumeProvider may read a stale value const float vh = track->getVolumeHandler()->getVolume(  proxy->framesReleased()).first; volume *= vh; track->mCachedVolume = volume; gain_minifloat_packed_t vlr = proxy->getVolumeLR(); float vlf = float_from_gain(gain_minifloat_unpack_left(vlr)); float vrf = float_from_gain(gain_minifloat_unpack_right(vlr)); vlf *= volume; //volume left final vrf *= volume; //volume right final track->setFinalVolume(vlf, vrf); ++fastTracks;}void AudioFlinger::PlaybackThread::Track::setFinalVolume(float volumeLeft, float volumeRight){ mFinalVolumeLeft = volumeLeft; mFinalVolumeRight = volumeRight;}

4)代码时序图

1、

Android14音频子系统-Framework分析_const sp<media::iaudioflingerservice> delegate) :

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: