尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

第 15 章:音频系统

第 15 章:音频系统 Android 音频栈是 AOSP 中对性能要求最高的子系统之一。它必须将音频采样数据从 Java 应用程序一直输送到硬件 DAC,同时具备确定的延迟;还要同时支持音效处理、策略驱动的路由、带头部追踪的空间音频,以及面向专业级录音的低延迟 MMAP 通路。本章沿着 AOSP 树中的实际源码文件,逐层梳理整个音频栈,从 Java 层AudioTrackAPI 一直向下追踪到 Audio HAL 硬件接口。音频核心服务位于frameworks/av/目录下,仅AudioFlinger就包含约 5 万行 C++ 代码;音频策略引擎、AAudio/Oboe 服务、音效库、头部追踪流水线还另有 3 万行代码。我们将阅读关键数据结构,逐行解析混音线程循环,并讲解每一处优化 —— 从运行在SCHED_FIFO优先级 3 级的 FastMixer,到完全绕过 AudioFlinger 的 MMAP 零拷贝通路。15.1 音频架构概述15.1.1 整体视图Android 音频系统是一套分层流水线。音频数据经过多次进程边界传递,从应用代码流转至硬件:应用层(Java / NDK) | v AudioTrack / AAudio (客户端库,运行在应用进程) | Binder IPC v AudioFlinger (audioserver进程 —— 混音、音效处理) | HAL接口 v Audio HAL (厂商进程,或通过HIDL/AIDL运行于同进程) | v 硬件(编解码器 / DSP / DAC)AudioPolicyService与AudioFlinger共同运行在audioserver进程内。它不处理音频数据,只负责路由决策:选择输出设备、确定要施加的音效、音量处理逻辑。15.1.2 进程与服务audioserver进程托管三大核心服务:服务Binder 接口源码位置AudioFlingerIAudioFlingerframeworks/av/services/audioflinger/AudioFlinger.cpp(5288 行)AudioPolicyServiceIAudioPolicyServiceframeworks/av/services/audiopolicy/service/AudioPolicyService.cpp(2759 行)AAudioServiceIAAudioServiceframeworks/av/services/oboeservice/AAudioService.cpp(527 行)AudioFlinger 优先完成注册:// AudioFlinger.cpp,第303‑308行 void AudioFlinger::instantiate() { spIServiceManager sm(defaultServiceManager()); sm-addService(String16(IAudioFlinger::DEFAULT_SERVICE_NAME), new AudioFlingerServerAdapter(new AudioFlinger()), false, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT); }15.1.3 信号流向图15.1.4 数据通路与控制通路音频系统存在两条完全独立的通路:数据通路—— 实际 PCM 采样数据。普通混音通路的数据流向:应用向共享内存环形缓冲区(“cblk” 控制块)写入数据。AudioFlinger 的MixerThread读取所有处于激活状态的 Track,执行混音。将混音结果写入 HAL 输出流。控制通路—— 路由决策、音量变更、设备连接事件:应用调用 Java 层AudioManager。AudioPolicyService通过 Binder 接收请求。AudioPolicyManager完成路由决策。指令下发至 AudioFlinger,创建 / 修改线程与音频通路。15.1.5 共享内存架构客户端与服务端之间所有音频数据传输均使用共享内存,不使用 Binder 事务。核心结构体audio_track_cblk_t定义位置:frameworks/av/include/private/media/AudioTrackShared.h该控制块包含:读位置(服务端)、写位置(客户端)欠载 / 过载检测标志位音量与静音状态基于 futex 的低延迟唤醒信号机制实际音频缓冲区存放在另一块独立共享内存区域,同时映射至客户端、服务端地址空间。进程间音频数据传输完全消除数据拷贝。15.1.6 audioserver 进程audioserver二进制程序是托管全部音频服务的原生守护进程,由 init 在开机早期启动:# audioserver.rc(简化版) service audioserver /system/bin/audioserver class core user audioserver group audio camera drmrpc media mediadrm net_bt net_bt_admin capabilities BLOCK_SUSPEND SYS_NICE ioprio rt 4 task_profiles ProcessCapacityHigh HighPerformance onrestart restart vendor.audio‑halaudioserver 进程关键特性:以audioserver用户运行,具备 audio 用户组权限。拥有BLOCK_SUSPEND能力,播放期间可阻止设备休眠。拥有SYS_NICE能力,用于设置实时线程优先级。I/O 优先级设置为实时 rt 4。应用ProcessCapacityHigh与HighPerformance任务配置,做 CPU 调度优化。重启 audioserver 的同时会重启厂商音频 HAL。进程内部结构15.1.7 线程类型总览AudioFlinger 会根据输出设备创建不同类型线程:线程类型类名用途源码位置MixerMixerThread多路 PCM 音轨混音Threads.cpp 约 3700 行起DirectDirectOutputThread单路 PCM 或压缩音轨Threads.cppOffloadOffloadThread硬件压缩播放Threads.cppDuplicatingDuplicatingThread输出镜像至多个输出设备Threads.cppRecordRecordThread音频输入采集Threads.cppMmapMmapPlaybackThread / MmapCaptureThreadMMAP 零拷贝通路Threads.cppSpatializerSpatializerThread空间音频混音Threads.cpp每一类线程绑定一个 HAL 输入 / 输出流,运行在高优先级实时线程。15.1.8 音频格式支持Android 支持丰富的音频格式:分类格式PCM16‑bit、24‑bit packed、32‑bit、8.24 定点、float 浮点有损压缩MP3、AAC、AAC‑LC、HE‑AAC、Vorbis、Opus无损压缩FLAC、ALAC空间音频Dolby Atmos、DTS:X(透传 passthrough)语音AMR‑NB、AMR‑WB、EVSPCM 格式流经混音器与音效链路。压缩格式可通过MediaCodec软件解码后送入 AudioTrack,也可直接下发至 HAL 做硬件解码(offload 通路)。15.2 AudioFlingerAudioFlinger 是 Android 音频的核心混音引擎,是音频栈中复杂度最高的组件。核心实现分布在 6 个源码文件,总代码量超 27000 行:文件行数用途AudioFlinger.cpp5288服务入口、Binder 接口实现Threads.cpp12053全部线程循环逻辑实现Tracks.cpp4057Track 对象(播放、录音、mmap)Effects.cpp3898音效链路管理PatchPanel.cpp1085音频路由通路管理fastpath/FastMixer.cpp517低延迟 fast mixer 通路前 5 个文件位于frameworks/av/services/audioflinger/。fastpath 相关代码独立存放于fastpath/子目录(包含 FastMixer.cpp、FastCapture.cpp、FastThread.cpp、StateQueue.cpp 以及 dump/state 辅助文件);audioflinger 目录下还包含afutils/、datapath/、sounddose/、timing/子目录,分别存放工具函数、HAL 流、声音剂量、帧计数相关辅助代码。线程类声明在Threads.h(2573 行),实现在Threads.cpp。15.2.1 AudioFlinger 初始化AudioFlinger 构造函数逻辑十分简洁,繁重初始化工作在onFirstRef()中执行:// AudioFlinger.cpp,第310‑341行 AudioFlinger::AudioFlinger() { // 随时间推移,移动音频会话唯一ID生成器起始基准值 // 降低audioserver重启后ID重复生成的风险 timespec ts{}; clock_gettime(CLOCK_MONOTONIC, ts); uint32_t movingBase = (uint32_t)std::max((long)1, ts.tv_sec); for (unsigned use = AUDIO_UNIQUE_ID_USE_UNSPECIFIED; use AUDIO_UNIQUE_ID_USE_MAX; use++) { mNextUniqueIds[use] = ((use == AUDIO_UNIQUE_ID_USE_SESSION || use == AUDIO_UNIQUE_ID_USE_CLIENT) ? movingBase : 1) * AUDIO_UNIQUE_ID_USE_MAX; } BatteryNotifier::getInstance().noteResetAudio(); }会话 ID 生成器基于单调时间偏移,避免 audioserver 重启后 ID 冲突。这一点至关重要:客户端重连时会复用之前分配的会话 ID。onFirstRef()内部,基于工厂模式完成设备发现:// AudioFlinger.cpp,第342‑363行 void AudioFlinger::onFirstRef() { audio_utils::lock_guard _l(mutex()); mMode = AUDIO_MODE_NORMAL; mDeviceEffectManager = spDeviceEffectManager::make( spIAfDeviceEffectManagerCallback::fromExisting(this)), mDevicesFactoryHalCallback = new DevicesFactoryHalCallbackImpl; mDevicesFactoryHal-setCallbackOnce(mDevicesFactoryHalCallback); // ... mPatchPanel = IAfPatchPanel::create( spIAfPatchPanelCallback::fromExisting(this)); mMelReporter = spMelReporter::make( spIAfMelReporterCallback::fromExisting(this), mPatchPanel); }15.2.2 类继承关系AudioFlinger 通过菱形继承模式实现多个回调接口:// AudioFlinger.h,第60‑67行 class AudioFlinger : public AudioFlingerServerAdapter::Delegate // IAudioFlinger客户端接口 , public IAfClientCallback , public IAfDeviceEffectManagerCallback , public IAfMelReporterCallback , public IAfPatchPanelCallback , public IAfThreadCallback {15.2.3 Binder 接口AudioFlinger 对外暴露超过 50 个方法的 Binder 接口。完整方法列表以宏的形式定义在 AudioFlinger.cpp:// AudioFlinger.cpp,第173‑244行 #define IAUDIOFLINGER_BINDER_METHOD_MACRO_LIST \ BINDER_METHOD_ENTRY(createTrack) \ BINDER_METHOD_ENTRY(createRecord) \ BINDER_METHOD_ENTRY(sampleRate) \ BINDER_METHOD_ENTRY(format) \ BINDER_METHOD_ENTRY(frameCount) \ BINDER_METHOD_ENTRY(latency) \ BINDER_METHOD_ENTRY(setMasterVolume) \ BINDER_METHOD_ENTRY(setMasterMute) \ // … 40+个其余条目 BINDER_METHOD_ENTRY(getSoundDoseInterface) \ BINDER_METHOD_ENTRY(getAudioPolicyConfig) \ BINDER_METHOD_ENTRY(getAudioMixPort) \ BINDER_METHOD_ENTRY(resetReferencesForTest) \每一个 Binder 方法都会通过MethodStatistics基础设施做统计与性能采集。15.2.4 Track 创建流程应用执行new AudioTrack()时,会调用 Binder 的createTrack方法。关键参数(AudioFlinger.h 第 82‑83 行):status_t createTrack(const media::CreateTrackRequest input, media::CreateTrackResponse output) final EXCLUDES_AudioFlinger_Mutex;请求参数包含音频属性(usage、content type)、格式、采样率、通道掩码、帧计数、标志位。AudioFlinger 执行逻辑:校验调用来源(AudioFlinger.cpp 第 126‑157 行)。向 AudioPolicyService 查询正确输出句柄。查找或创建对应的播放线程。为 Track 音频缓冲区分配共享内存。创建 Track 对象并挂载到线程。15.2.5 硬件模块加载AudioFlinger 使用工厂模式加载 HAL 模块。已知模块 ID:// AudioFlinger.cpp,第684‑688行 static const char * const audio_interfaces[] = { AUDIO_HARDWARE_MODULE_ID_PRIMARY, AUDIO_HARDWARE_MODULE_ID_A2DP, AUDIO_HARDWARE_MODULE_ID_USB, };findSuitableHwDev_l()(第 690 行)遍历已加载 HAL 模块,筛选支持目标设备类型的硬件模块。15.2.6 MixerThread 循环混音工作发生在MixerThread。Threads.cpp中的threadLoop()是 Android 音频的核心心脏。循环逻辑结构:Threads.cpp 中关键时间常量:// Threads.cpp,第132‑134行 static const int8_t kMaxTrackRetries = 50; static const int8_t kMaxTrackStartupRetries = 50; // Threads.cpp,第154行 static const int32_t kMaxTrackRetriesDirectMs = 200; // Threads.cpp,第169行 static const uint32_t kMinThreadSleepTimeUs = 5000; // Threads.cpp,第175‑177行 static const uint32_t kMinNormalSinkBufferSizeMs = 20; static const uint32_t kMaxNormalSinkBufferSizeMs = 24;混音循环周期约 20ms。每个周期执行:prepareTracks_l():评估全部 Track,筛选激活 Track,为每个激活 Track 配置 AudioMixer(采样率、音量、格式)。threadLoop_mix():调用AudioMixer::process()读取所有激活 Track 缓冲区,混音写入mMixerBuffer。processEffects_l():对混音完成的音频执行音效链路处理。threadLoop_write():将最终缓冲区写入 HAL。15.2.7 threadLoop_write () 方法写通路存在两个分支(Threads.cpp 第 3557‑3616 行):// Threads.cpp,第3557‑3626行 ssize_t PlaybackThread::threadLoop_write() { LOG_HIST_TS(); mInWrite = true; ssize_t bytesWritten; const size_t offset = mCurrentWriteLength - mBytesRemaining; // 如果存在NBAIO sink,使用它写入普通混音器的子混音数据 if (mNormalSink != 0) { const size_t count = mBytesRemaining / mFrameSize; ATRACE_BEGIN("write"); // AudioFlinger::mScreenState变化时更新setpoint const uint32_t screenState = mAfThreadCallback-getScreenState(); if (screenState != mScreenState) { mScreenState = screenState; MonoPipe *pipe = (MonoPipe *)mPipeSink.get(); if (pipe != NULL) { pipe-setAvgFrames((mScreenState 1) ? (pipe-maxFrames() * 7) / 8 : mNormalFrameCount * 2); } } ssize_t framesWritten = mNormalSink-write( (char *)mSinkBuffer + offset, count); ATRACE_END(); // … } else { // direct输出与offload线程 ATRACE_BEGIN("write"); bytesWritten = mOutput-write( (char *)mSinkBuffer + offset, mBytesRemaining); ATRACE_END(); } // … }对于 MixerThread,写操作经过 NBAIO(非阻塞音频 I/O)MonoPipe转发至 FastMixer。Direct 与 Offload 线程直接写入 HAL 流。屏幕状态优化逻辑值得关注:屏幕点亮时,管道平均帧阈值提升至最大值的 7/8,降低 UI 活跃时音频欠载概率;屏幕熄灭时,阈值降为普通帧数量的 2 倍,节省功耗。15.2.8 待机管理线程等待可配置时长(默认 3 秒)后进入待机状态:// Threads.cpp,第252‑262行 static const nsecs_t kDefaultStandbyTimeInNsecs = seconds(3); static nsecs_t getStandbyTimeInNanos() { static nsecs_t standbyTimeInNanos = []() { const int ms = property_get_int32( "ro.audio.flinger_standbytime_ms", kDefaultStandbyTimeInNsecs / NANOS_PER_MILLISECOND); ALOGI("%s: Using %d ms as standby time", __func__, ms); return milliseconds(ms); }(); return standbyTimeInNanos; }待机状态下,线程释放 HAL 流,释放唤醒锁,显著降低功耗。offload 输出的待机延迟更短:// Threads.cpp,第184行 static const nsecs_t kOffloadStandbyDelayNs = seconds(1);15.2.9 TracksTrack 对象代表线程内部独立音频流。基类TrackBase定义在 Tracks.cpp:// Tracks.cpp,第89‑138行 TrackBase::TrackBase( IAfThreadBase *thread, const spClient client, const audio_attributes_t attr, uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, size_t frameCount, void *buffer, size_t bufferSize, audio_session_t sessionId, pid_t creatorPid, uid_t clientUid, bool isOut, const alloc_type alloc, track_type type, audio_port_handle_t portId, std::string metricsId) : mThread(thread), mAllocType(alloc), mClient(client), mCblk(NULL), mState(IDLE), mAttr(attr), mSampleRate(sampleRate), mFormat(format), mChannelMask(channelMask), mChannelCount(isOut ? audio_channel_count_from_out_mask(channelMask) : audio_channel_count_from_in_mask(channelMask)), mFrameSize(audio_bytes_per_frame(mChannelCount, format)), mFrameCount(frameCount), mSessionId(sessionId), // …每个 Track 拥有原子生成的唯一 ID:// Tracks.cpp,第86行 static volatile int32_t nextTrackId = 55;Track 继承层级:15.2.10 FastMixer —— 低延迟通路FastMixer 是独立高优先级线程,对延迟敏感的音轨可以绕过普通混音循环。定义位置:frameworks/av/services/audioflinger/fastpath/FastMixer.cpp(517 行)FastMixer 严格的设计约束(源码头部注释):// FastMixer.cpp,第17‑21行 // IMPORTANT_WARNING // threadLoop()的设计约束见StateQueue.h中“Fast mixer thread”章节注释。 // 特别注意:仅可在明确允许的位置调用库与系统调用。 // /IMPORTANT_WARNINGFastMixer 支持 4 种工作策略:// Threads.cpp,第202‑216行 static const enum { FastMixer_Never, // 绝不初始化、绝不使用,仅用于调试 FastMixer_Always, // 始终初始化并启用,即使没有需求 FastMixer_Static, // 需要时初始化,之后持续运行 FastMixer_Dynamic, // 需要时初始化,动态启停 } kUseFastMixer = FastMixer_Static;默认策略FastMixer_Static:一旦初始化完成,FastMixer 持续运行。优先级配置:// Threads.cpp,第226‑228行 static const int kPriorityAudioApp = 2; static const int kPriorityFastMixer = 3; static const int kPriorityFastCapture = 3;Fast track 乘数控制共享缓冲区大小:// Threads.cpp,第237‑244行 static const int kFastTrackMultiplier = 2; static const int kFastTrackMultiplierMin = 1; static const int kFastTrackMultiplierMax = 2; static int sFastTrackMultiplier = kFastTrackMultiplier;FastMixer 线程循环FastMixer 的onWork()(328 行)是紧凑内层循环:// FastMixer.cpp,第328‑333行 void FastMixer::onWork() { const FastMixerState * const current = (const FastMixerState *) mCurrent; FastMixerDumpState * const dumpState = (FastMixerDumpState *) mDumpState;处理三类命令:MIX —— 将音轨混音写入混音缓冲区WRITE —— 将缓冲区写入输出 sinkMIX_WRITE —— 同时执行混音与写操作输出配置变更时,FastMixer 重新配置:// FastMixer.cpp,第245‑270行 if (frameCount 0 mSampleRate 0) { mMixer = new AudioMixer(frameCount, mSampleRate); // … mPeriodNs = (frameCount * 1000000000LL) / mSampleRate; // 1.00 mUnderrunNs = (frameCount * 1750000000LL) / mSampleRate; // 1.75 mOverrunNs = (frameCount * 500000000LL) / mSampleRate; // 0.50 mForceNs = (frameCount * 950000000LL) / mSampleRate; // 0.95 mWarmupNsMin = (frameCount * 750000000LL) / mSampleRate; // 0.75 mWarmupNsMax = (frameCount * 1250000000LL) / mSampleRate; // 1.25 }以上时间阈值定义判定标准:周期 1.75 倍判定欠载,0.5 倍判定过载。FastMixer 内 Track 更新单条音轨更新在updateMixerTrack()完成:// FastMixer.cpp,第123‑191行 void FastMixer::updateMixerTrack(int index, Reason reason) { // … switch (reason) { case REASON_REMOVE: mMixer-destroy(index); break; case REASON_ADD: { const status_t status = mMixer-create( index, fastTrack-mChannelMask, fastTrack-mFormat, AUDIO_SESSION_OUTPUT_MIX); // … } [[fallthrough]]; case REASON_MODIFY: mMixer-setBufferProvider(index, fastTrack-mBufferProvider); // 设置音量、重采样、格式、通道掩码、触觉反馈参数 mMixer-enable(index); break; } }音量从 Track 的VolumeProvider获取:// FastMixer.cpp,第155‑161行 float vlf, vrf; if (fastTrack-mVolumeProvider != nullptr) { const gain_minifloat_packed_t vlr = fastTrack-mVolumeProvider-getVolumeLR(); vlf = float_from_gain(gain_minifloat_unpack_left(vlr)); vrf = float_from_gain(gain_minifloat_unpack_right(vlr)); } else { vlf = vrf = AudioMixer::UNITY_GAIN_FLOAT; }15.2.11 PatchPanel —— 音频路由PatchPanel 管理源端与接收端之间的音频路由通路:frameworks/av/services/audioflinger/PatchPanel.cpp(1085 行)一条 patch 连接多个音频端口;可以是硬件直通(设备‑设备)、设备‑混音器、混音器‑设备。创建逻辑处理多种场景:// PatchPanel.cpp,第112‑135行 status_t PatchPanel::createAudioPatch_l( const struct audio_patch* patch, audio_patch_handle_t *handle, bool endpointPatch) { // … if (!audio_patch_is_valid(patch) || (patch-num_sinks == 0 patch-num_sources != 2)) { return BAD_VALUE; } // 当前限制源端数量最大为1;跨硬件模块特殊场景允许2个源端 if (patch-num_sources 2) { return INVALID_OPERATION; }源端数量等于 2 的特殊场景用于跨 HAL 模块路由,音频需要在两套不同 HAL 模块之间转发(例如主音频设备转发至 USB 音频)。15.2.12 扩展声道与精度MixerThread 支持立体声之外的扩展声道配置:// Threads.cpp,第267行 constexpr bool kEnableExtendedChannels = true;同时支持扩展精度格式:// Threads.cpp,第301行 constexpr bool kEnableExtendedPrecision = true;合法 PCM 输出 sink 格式(305‑317 行):bool IAfThreadBase::isValidPcmSinkFormat(audio_format_t format) { switch (format) { case AUDIO_FORMAT_PCM_16_BIT: return true; case AUDIO_FORMAT_PCM_FLOAT: case AUDIO_FORMAT_PCM_24_BIT_PACKED: case AUDIO_FORMAT_PCM_32_BIT: case AUDIO_FORMAT_PCM_8_24_BIT: return kEnableExtendedPrecision; default: return false; } }15.2.13 createTrack () 深度解析完整createTrack()实现(AudioFlinger.cpp 第 1038 行)展示完整 Track 创建流水线:// AudioFlinger.cpp,第1038‑1075行 status_t AudioFlinger::createTrack( const media::CreateTrackRequest _input, media::CreateTrackResponse _output) { ATRACE_CALL(); CreateTrackInput input = VALUE_OR_RETURN_STATUS(CreateTrackInput::fromAidl(_input)); CreateTrackOutput output; spIAfTrack track; spClient client; status_t lStatus; audio_stream_type_t streamType; audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE; std::vectoraudio_io_handle_t secondaryOutputs; bool isSpatialized = false; bool isBitPerfect = false; audio_io_handle_t effectThreadId = AUDIO_IO_HANDLE_NONE; std::vectorint effectIds; audio_attributes_t localAttr = input.attr;该方法校验调用来源;需要时分配会话 ID;向 AudioPolicyService 查询正确输出:// AudioFlinger.cpp,第1069‑1091行 sessionId = input.sessionId; if (sessionId == AUDIO_SESSION_ALLOCATE) { sessionId = (audio_session_t) newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION); } lStatus = AudioSystem::getOutputForAttr( localAttr, output.outputId, sessionId, streamType, adjAttributionSource, input.config, input.flags, selectedDeviceIds, portId, secondaryOutputs, isSpatialized, isBitPerfect);获取输出之后,校验格式、通道掩码,定位播放线程,注册客户端,处理音效链路迁移:// AudioFlinger.cpp,第1114‑1157行 { audio_utils::lock_guard _l(mutex()); IAfPlaybackThread* thread = checkPlaybackThread_l(output.outputId); client = registerClient( adjAttributionSource.pid, adjAttributionSource.uid); // 检查是否存在同session ID的音效链路运行在其他输出线程,需要迁移至此 for (const auto [outputId, t] : mPlaybackThreads) { if (outputId != output.outputId) { uint32_t sessions = t-hasAudioSession(sessionId); if (sessions IAfThreadBase::EFFECT_SESSION) { effectThread = t.get(); break; } } } track = thread-createTrack_l(client, streamType, localAttr, output.sampleRate, input.config.format, input.config.channel_mask, output.frameCount, output.notificationFrameCount, input.notificationsPerBuffer, input.speed, input.sharedBuffer, sessionId, output.flags, callingPid, adjAttributionSource, input.clientInfo.clientTid, lStatus, portId, input.audioTrackCallback, isSpatialized, isBitPerfect, output.afTrackFlags);输出结构体记录线程实际配置关键信息:// AudioFlinger.cpp,第1161‑1167行 output.afFrameCount = thread-frameCount(); output.afSampleRate = thread-sampleRate(); output.afChannelMask = static_castaudio_channel_mask_t( thread-channelMask() | thread-hapticChannelMask()); output.afFormat = thread-format(); output.afLatencyMs = thread-latency(); output.portId = portId;15.2.14 dump () 调试输出系统AudioFlinger 的 dump 系统功能完备,支持选择性调试:// AudioFlinger.cpp,第838‑849行 static void dump_printHelp(int fd) { constexpr static auto helpStr = "AudioFlinger dumpsys help options\n" " -h/--help: Print this help text\n" " --hal: Include dump of audio hal\n" " --stats: Include call/lock/watchdog stats\n" " --effects: Include effect definitions\n" " --memory: Include memory dump\n" " -a/--all: Print all except --memory\n"sv; write(fd, helpStr.data(), helpStr.length()); }dump 方法遍历全部线程类型:// AudioFlinger.cpp,第930‑952行 // dump播放线程 for (const auto [_, thread] : mPlaybackThreads) { thread-dump(fd, args); } // dump录音线程 for (const auto [_, thread] : mRecordThreads) { thread-dump(fd, args); } // dump mmap线程 for (const auto [_, thread] : mMmapThreads) { thread-dump(fd, args); } // dump孤立音效链路 if (mOrphanEffectChains.size() != 0) { writeStr(fd, " Orphan Effect Chains\n"); for (const auto [_, effectChain] : mOrphanEffectChains) { effectChain-dump(fd, args); } }同时输出电源管理、互斥锁统计、内存状态:// AudioFlinger.cpp,第974‑979行 dprintf(fd, "\n ## BEGIN power dump\n"); writeStr(fd, media::psh_utils::AudioPowerManager:: getAudioPowerManager().toString()); // AudioFlinger.cpp,第819‑822行 writeStr(fd, audio_utils::mutex::all_stats_to_string()); writeStr(fd, audio_utils::mutex::all_threads_to_string());15.2.15 线程循环中的音效处理混音线程循环内的音效处理阶段值得重点关注。混音完成后执行音效链路处理:// Threads.cpp,第4322‑4348行 if (mSleepTimeUs == 0 mType != OFFLOAD) { for (size_t i = 0; i effectChains.size(); i++) { effectChains[i]-process_l(); // 处理音效链路输出的触觉反馈数据 if (activeHapticSessionId != AUDIO_SESSION_NONE activeHapticSessionId == effectChains[i]-sessionId()) { uint32_t hapticSessionChannelCount = mEffectBufferValid ? audio_channel_count_from_out_mask( mMixerChannelMask) : mChannelCount; const size_t audioBufferSize = mNormalFrameCount * audio_bytes_per_frame( hapticSessionChannelCount, AUDIO_FORMAT_PCM_FLOAT); memcpy_by_audio_format( (uint8_t*)effectChains[i]-outBuffer() + audioBufferSize, AUDIO_FORMAT_PCM_FLOAT, (const uint8_t*)effectChains[i]-inBuffer() + audioBufferSize, AUDIO_FORMAT_PCM_FLOAT, mNormalFrameCount * mHapticChannelCount); } } }触觉反馈数据做特殊处理:直接从音效输入缓冲区拷贝至输出缓冲区,跳过后续音效处理。因为触觉通道由HapticGenerator生成,不应该被链路中后续音效修改。offload 类型 Track 即使没有音频数据,依然执行音效处理:// Threads.cpp,第4350‑4358行 if (mType == OFFLOAD) { for (size_t i = 0; i effectChains.size(); i++) { effectChains[i]-process_l(); } }音效处理完成后,将音效缓冲区拷贝至 sink 缓冲区,对 float PCM 做限幅保护,保障 HAL 安全:// Threads.cpp,第4398‑4405行 static constexpr float HAL_FLOAT_SAMPLE_LIMIT = 2.0f; memcpy_to_float_from_float_with_clamping( static_castfloat*(mSinkBuffer), static_castconst float*(effectBuffer), framesToCopy, HAL_FLOAT_SAMPLE_LIMIT /* absMax */);限幅到 ±2.0f,用于保护无法处理 NaN、超大浮点数值的 HAL 实现。15.2.16 写操作时间与抖动统计写入 HAL 之后,线程循环统计时间抖动:// Threads.cpp,第4436‑4476行 const int64_t lastIoBeginNs = systemTime(); ret = threadLo
返回列表