自 2025 年 3 月 27 日起,我们建议您使用 android-latest-release
而非 aosp-main
构建 AOSP 并为其做出贡献。如需了解详情,请参阅 AOSP 的变更。
音频延迟的影响因素
使用集合让一切井井有条
根据您的偏好保存内容并对其进行分类。
本页面将重点介绍输出延迟时间的影响因素,但是类似的内容也适用于输入延迟时间。
假设模拟电路的影响没有那么显著,那么音频延迟的主要 Surface 级影响因素如下:
- 应用
- 管道中的缓冲区总数
- 每个缓冲区的大小(以帧为单位)
- 应用处理器之后的额外延迟时间,例如来自 DSP 的延迟时间
上述影响因素列表在尽量做到准确的同时,可能也存在误导。原因在于缓冲区计数和缓冲区大小更像是结果而非原因。通常情况是,设计人员实现并测试一个指定的缓冲区方案,但是在测试期间,音频欠载或过载时会听到“咔哒声”或“砰砰声”。作为补偿措施,系统设计人员会增加缓冲区大小或缓冲区计数。这样一来,虽然达到了消除欠载或过载这一预期效果,但是也带来了延迟时间变长的负面影响。有关缓冲区大小的更多信息,请观看视频音频延迟:缓冲区大小。
更好的方法是了解欠载和过载的原因,然后纠正这些问题。这样可消除我们能听见的杂音,并且允许使用更小或更少的缓冲区,从而缩短延迟时间。
根据我们的经验,最常见的欠载和过载原因包括:
- Linux CFS(完全公平的调度程序)
- 具有 SCHED_FIFO 调度的高优先级线程
- 优先级倒置
- 长时间调度延迟
- 长时间运行的中断处理程序
- 长时间中断禁用
- 电源管理
- 安全内核
Linux CFS 和 SCHED_FIFO 调度
Linux CFS 旨在公平地对待共享通用 CPU 资源的竞争性工作负载。这种公平性按线程以 nice 参数表示。nice 值范围从 -19(最不友好,即分配最多的 CPU 时间)到 20(最友好,即分配最少的 CPU 时间)。一般来说,具有指定 nice 值的所有线程会获得差不多相同的 CPU 时间,而 nice 值较低的线程预计会获得更多的 CPU 时间。不过,只有在相对较长的观察期内,才能看出 CFS 是“公平”的。在较短的观察期内,CFS 可能会以不符合预期的方式分配 CPU 资源。例如,它可能会将具有较低 nice 值的线程上的 CPU 资源转移到具有较高 nice 值的线程。对于音频而言,这可能会导致欠载或过载。
显而易见的解决方案是避免将 CFS 用于高性能音频线程。从 Android 4.1 开始,此类线程现在使用 SCHED_FIFO
调度策略,而非通过 CFS 实现的 SCHED_NORMAL
(也称为 SCHED_OTHER
)调度策略。
SCHED_FIFO 优先级
虽然高性能音频线程现在使用 SCHED_FIFO
,但是它们仍然很容易受到其他优先级更高的 SCHED_FIFO
线程的影响。
这些线程通常是内核工作器线程,但也可能存在一些采用 SCHED_FIFO
政策的非音频用户线程。可用的 SCHED_FIFO
优先级范围是从 1 到 99。音频线程的运行优先级为 2 或 3。这使得优先级较低的线程可以使用优先级 1,而优先级较高的线程可以使用优先级 4 到 99。我们建议您尽可能使用优先级 1,并保留优先级 4 到 99 以用于以下线程:保证在有限时间内完成、执行时间短于音频线程时间,并且已知不会干扰音频线程调度。
速率单调调度
有关固定优先级分配理论的更多信息,请参阅维基百科文章速率单调调度 (RMS)。关键在于,固定优先级应严格按照周期分配,较高优先级分配给较短周期的线程,而不是基于观察到的“重要性”。可以使用最大执行频率和每次执行的最大计算能力将非周期性线程建模为周期性线程。如果非周期性线程无法建模为周期性线程(例如,它可以按无限频率执行,或每次执行使用无限计算能力),则不应为其分配固定优先级,否则会与真正的周期性线程的调度相矛盾。
优先级倒置
优先级倒置是实时系统的一种典型故障模式,是指优先级较高的任务因等待优先级较低的任务释放资源(如受互斥保护的共享状态)而无限长时间地受阻。请参阅“避免优先级倒置”一文,了解可减少这种情况的技术。
调度延迟
调度延迟时间是指从线程已准备好运行,到环境切换完成、可以在 CPU 上实际运行线程之间的间隔时间。延迟越短越好,一旦超过 2 毫秒,就会造成音频问题。在模式转换期间最有可能出现长时间的调度延迟,例如,启动或关闭 CPU、在安全内核和普通内核之间切换、从全功率模式切换为低功率模式,或者调整 CPU 时钟频率和电压。
中断
在许多设计中,CPU 0 负责处理所有外部中断。因此,长时间运行的中断处理程序可能会造成其他中断出现延迟,尤其是音频直接内存访问 (DMA) 完成中断。将中断处理程序设计为快速完成并将冗长的工作延迟到某个线程(最好是 CFS 线程或优先级为 1 的 SCHED_FIFO
线程)。
同样,如果将 CPU 0 上的中断停用很长一段时间,会带来与延迟音频中断服务一样的效果。长时间中断停用通常发生在等待内核自旋锁定时。检查这些自旋锁定,确保它们有时间限制。
电源、性能和散热管理
电源管理是一个广义的术语,涵盖为了监控并减少功耗、同时优化性能所采取的措施。散热管理和计算机冷却类似,不同之处在于,前者力求通过测定并控制热量来避免因过热而造成损坏。在 Linux 内核中,CPU 调节器负责低级别的政策,而用户模式则配置高级别的政策。用到的技术包括:
- 动态电压调节
- 动态频率调节
- 动态核心启用
- 集群切换
- 电源门控
- 热插拔(热交换)
- 各种睡眠模式(中断、停止、空闲、挂起等)
- 进程迁移
- 处理器关联
一些管理操作会导致“停工”或者在一段时间内应用处理器未执行任何有用的工作。这些停工会干扰音频,因此应该设计管理措施,确保音频处于活跃状态时,最糟糕的停工情况仍在可接受的范围内。当然,当出现散热失控的紧急情况时,避免永久损坏比音频更重要!
安全内核
数字版权管理 (DRM) 的安全内核可以在用于主要操作系统内核和应用代码的同一应用处理器核心上运行。只要安全内核操作在一个核心上处于活跃状态,就会导致在该核心上本应正常运行的普通工作停止。尤其是,这可能包括音频工作。本质上来看,从较高层级无法预测安全内核的内部行为,因而安全内核引起的任何性能异常会特别严重。例如,安全内核操作通常不会出现在环境切换的跟踪中。我们称之为“黑暗时期”,即在流逝却无法观察到的时间。安全内核应该经过设计,确保音频处于活跃状态时,最糟糕的停工情况仍在可接受的范围内。
本页面上的内容和代码示例受内容许可部分所述许可的限制。Java 和 OpenJDK 是 Oracle 和/或其关联公司的注册商标。
最后更新时间 (UTC):2025-03-26。
[[["易于理解","easyToUnderstand","thumb-up"],["解决了我的问题","solvedMyProblem","thumb-up"],["其他","otherUp","thumb-up"]],[["没有我需要的信息","missingTheInformationINeed","thumb-down"],["太复杂/步骤太多","tooComplicatedTooManySteps","thumb-down"],["内容需要更新","outOfDate","thumb-down"],["翻译问题","translationIssue","thumb-down"],["示例/代码问题","samplesCodeIssue","thumb-down"],["其他","otherDown","thumb-down"]],["最后更新时间 (UTC):2025-03-26。"],[],[],null,["# Contributors to audio latency\n\nThis page focuses on the contributors to output latency,\nbut a similar discussion applies to input latency.\n\n\nAssuming the analog circuitry does not contribute significantly, then the major\nsurface-level contributors to audio latency are the following:\n\n- Application\n- Total number of buffers in pipeline\n- Size of each buffer, in frames\n- Additional latency after the app processor, such as from a DSP\n\n\nAs accurate as the above list of contributors may be, it is also misleading.\nThe reason is that buffer count and buffer size are more of an\n*effect* than a *cause* . What usually happens is that\na given buffer scheme is implemented and tested, but during testing, an audio\nunderrun or overrun is heard as a \"click\" or \"pop.\" To compensate, the\nsystem designer then increases buffer sizes or buffer counts.\nThis has the desired result of eliminating the underruns or overruns, but it also\nhas the undesired side effect of increasing latency.\nFor more information about buffer sizes, see the video\n[Audio latency: buffer sizes](https://youtu.be/PnDK17zP9BI).\n\n\nA better approach is to understand the causes of the\nunderruns and overruns, and then correct those. This eliminates the\naudible artifacts and may permit even smaller or fewer buffers\nand thus reduce latency.\n\n\nIn our experience, the most common causes of underruns and overruns include:\n\n- Linux CFS (Completely Fair Scheduler)\n- high-priority threads with SCHED_FIFO scheduling\n- priority inversion\n- long scheduling latency\n- long-running interrupt handlers\n- long interrupt disable time\n- power management\n- security kernels\n\n### Linux CFS and SCHED_FIFO scheduling\n\n\nThe Linux CFS is designed to be fair to competing workloads sharing a common CPU\nresource. This fairness is represented by a per-thread *nice* parameter.\nThe nice value ranges from -19 (least nice, or most CPU time allocated)\nto 20 (nicest, or least CPU time allocated). In general, all threads with a given\nnice value receive approximately equal CPU time and threads with a\nnumerically lower nice value should expect to\nreceive more CPU time. However, CFS is \"fair\" only over relatively long\nperiods of observation. Over short-term observation windows,\nCFS may allocate the CPU resource in unexpected ways. For example, it\nmay take the CPU away from a thread with numerically low niceness\nonto a thread with a numerically high niceness. In the case of audio,\nthis can result in an underrun or overrun.\n\n\nThe obvious solution is to avoid CFS for high-performance audio\nthreads. Beginning with Android 4.1, such threads now use the\n`SCHED_FIFO` scheduling policy rather than the `SCHED_NORMAL` (also called\n`SCHED_OTHER`) scheduling policy implemented by CFS.\n\n### SCHED_FIFO priorities\n\n\nThough the high-performance audio threads now use `SCHED_FIFO`, they\nare still susceptible to other higher priority `SCHED_FIFO` threads.\nThese are typically kernel worker threads, but there may also be a few\nnon-audio user threads with policy `SCHED_FIFO`. The available `SCHED_FIFO`\npriorities range from 1 to 99. The audio threads run at priority\n2 or 3. This leaves priority 1 available for lower priority threads,\nand priorities 4 to 99 for higher priority threads. We recommend\nyou use priority 1 whenever possible, and reserve priorities 4 to 99 for\nthose threads that are guaranteed to complete within a bounded amount\nof time, execute with a period shorter than the period of audio threads,\nand are known to not interfere with scheduling of audio threads.\n\n### Rate-monotonic scheduling\n\n\nFor more information on the theory of assignment of fixed priorities,\nsee the Wikipedia article\n[Rate-monotonic scheduling](http://en.wikipedia.org/wiki/Rate-monotonic_scheduling) (RMS).\nA key point is that fixed priorities should be allocated strictly based on period,\nwith higher priorities assigned to threads of shorter periods, not based on perceived \"importance.\"\nNon-periodic threads may be modeled as periodic threads, using the maximum frequency of execution\nand maximum computation per execution. If a non-periodic thread cannot be modeled as\na periodic thread (for example it could execute with unbounded frequency or unbounded computation\nper execution), then it should not be assigned a fixed priority as that would be incompatible\nwith the scheduling of true periodic threads.\n\n### Priority inversion\n\n\n[Priority inversion](http://en.wikipedia.org/wiki/Priority_inversion)\nis a classic failure mode of real-time systems,\nwhere a higher-priority task is blocked for an unbounded time waiting\nfor a lower-priority task to release a resource such as (shared\nstate protected by) a\n[mutex](http://en.wikipedia.org/wiki/Mutual_exclusion).\nSee the article \"[Avoiding priority inversion](/docs/core/audio/avoiding_pi)\" for techniques to\nmitigate it.\n\n### Scheduling latency\n\n\nScheduling latency is the time between when a thread becomes\nready to run and when the resulting context switch completes so that the\nthread actually runs on a CPU. The shorter the latency the better, and\nanything over two milliseconds causes problems for audio. Long scheduling\nlatency is most likely to occur during mode transitions, such as\nbringing up or shutting down a CPU, switching between a security kernel\nand the normal kernel, switching from full power to low-power mode,\nor adjusting the CPU clock frequency and voltage.\n\n### Interrupts\n\n\nIn many designs, CPU 0 services all external interrupts. So a\nlong-running interrupt handler may delay other interrupts, in particular\naudio direct memory access (DMA) completion interrupts. Design interrupt handlers\nto finish quickly and defer lengthy work to a thread (preferably\na CFS thread or `SCHED_FIFO` thread of priority 1).\n\n\nEquivalently, disabling interrupts on CPU 0 for a long period\nhas the same result of delaying the servicing of audio interrupts.\nLong interrupt disable times typically happen while waiting for a kernel\n*spin lock*. Review these spin locks to ensure they are bounded.\n\n### Power, performance, and thermal management\n\n\n[Power management](http://en.wikipedia.org/wiki/Power_management)\nis a broad term that encompasses efforts to monitor\nand reduce power consumption while optimizing performance.\n[Thermal management](http://en.wikipedia.org/wiki/Thermal_management_of_electronic_devices_and_systems)\nand [computer cooling](http://en.wikipedia.org/wiki/Computer_cooling)\nare similar but seek to measure and control heat to avoid damage due to excess heat.\nIn the Linux kernel, the CPU\n[governor](http://en.wikipedia.org/wiki/Governor_%28device%29)\nis responsible for low-level policy, while user mode configures high-level policy.\nTechniques used include:\n\n- dynamic voltage scaling\n- dynamic frequency scaling\n- dynamic core enabling\n- cluster switching\n- power gating\n- hotplug (hotswap)\n- various sleep modes (halt, stop, idle, suspend, etc.)\n- process migration\n- [processor affinity](http://en.wikipedia.org/wiki/Processor_affinity)\n\n\nSome management operations can result in \"work stoppages\" or\ntimes during which there is no useful work performed by the application processor.\nThese work stoppages can interfere with audio, so such management should be designed\nfor an acceptable worst-case work stoppage while audio is active.\nOf course, when thermal runaway is imminent, avoiding permanent damage\nis more important than audio!\n\n### Security kernels\n\n\nA [security kernel](http://en.wikipedia.org/wiki/Security_kernel) for\n[Digital rights management](http://en.wikipedia.org/wiki/Digital_rights_management)\n(DRM) may run on the same application processor core(s) as those used\nfor the main operating system kernel and application code. Any time\nduring which a security kernel operation is active on a core is effectively a\nstoppage of ordinary work that would normally run on that core.\nIn particular, this may include audio work. By its nature, the internal\nbehavior of a security kernel is inscrutable from higher-level layers, and thus\nany performance anomalies caused by a security kernel are especially\npernicious. For example, security kernel operations do not typically appear in\ncontext switch traces. We call this \"dark time\" --- time that elapses\nyet cannot be observed. Security kernels should be designed for an\nacceptable worst-case work stoppage while audio is active."]]