audio unity 加速_浅谈Unity中Android、iOS音频延迟

在Unity上面做音游,当在移动端实机运行起来,会发现,音频的发出会有一定的延迟,无论是长音效还是短音效,Unity内置的Audio内部使用的是FMOD,有以下手段改善

通过设置稍微改善其延迟的问题

Edit → Project Settings → Audio → 设置DSP Buffer size为Best latency(设置 dsp 缓冲区大小以优化延迟或性能,设置一个不合适的值会导致安卓设备的电流音)

音频文件的Load Type为Decompress On Load(让音频提前读取到缓存中)

让音频文件越小越好

代码来获取准确的音轨采样时间

糟糕的方式

AudioSource audioSource;

//100ms延迟

float GetTrackTime()

{

return audioSource.time;

}

好的方式

//20ms延迟

float GetTrackTime()

{

return 1f * audioSource.timeSamples / audioSource.clip.frequency;

}

更好的方式

double trackStartTime;

void StartMusic()

{

trackStartTime = AudioSettings.dspTime + 1;

audioSource.PlayScheduled(trackStartTime);

}

double GetTrackTime()

{

return AudioSettings.dspTime - trackStartTime;

}

最好的方式

Stopwatch stopwatch = new Stopwatch();

void StartMusic()

{

audioSource.Play();

stopwatch.Start();

}

double GetTrackTime()

{

return stopwatch.ElapsedMilliseconds/1000f;

}

//timeSample的Get方法受限与音频异步的问题是有20ms的延迟的,但是Set方法几乎没有延迟

void SetTrackTime(float time)

{

audioSource.timeSample = (int)(time * audioSource.clip.frequency);

}

但是结果往往还是无法让人满意,经过测试,iOS大多数设备的延迟降到10ms以内,误差范围外,相当于没有了,但是安卓设备的延迟根据机型的不同有不同的延迟,大约在100ms~500ms:

image.png

硬件和软件的原因造成了Android设备的延迟偏高以及不统一

音频播放的不同阶段

模拟音频输入

可能有几种不同的模拟组件,例如内置麦克风的前置放大器。在这种情况下,这些模拟组件可被视为“零延迟”,因为它们的真实延迟通常低于1 ms。

延迟:0

模数转换(ADC)

音频芯片以预定义的间隔测量输入的音频流,并将每个测量值转换为数字。此预定义间隔称为采样率,以Hz为单位。我们的移动音频普查和延迟测试应用程序显示,48000 Hz是Android和iOS设备上大多数音频芯片的原生采样率,这意味着音频流每秒采样48000次。

由于ADC实现通常在内部包含过采样滤波器,因此经验法则是将ADC步长归因于1 ms延迟。

现在音频流已经数字化,从这一点开始,音频流现在是数字音频。数字音频几乎不会一个接一个地传播,而是以块状称,称为“缓冲区”或“周期”。

延迟:1毫秒

总线从音频芯片传输到音频驱动器

音频芯片有几个任务。它处理ADC和DAC,在多个输入和输出之间切换或混合,应用音量等。它还将离散数字音频样本“分组”到缓冲区中,并处理这些缓冲区到操作系统的传输。

音频芯片通过总线连接到CPU,例如USB,PCI,Firewire等。每个总线都有自己的传输延迟,具体取决于其内部缓冲区大小和缓冲区计数。此处的延迟通常为1 ms(内部系统总线上的音频芯片)至6 ms(具有保守USB总线设置的USB声卡)。

延迟:1-6毫秒

音频驱动程序(ALSA,OSS等)

音频驱动器使用音频芯片的本机采样率(大多数情况下为48000 Hz)以“总线缓冲区大小”步骤将输入音频接收到环形缓冲器中。

此环形缓冲区在平滑总线传输抖动(“粗糙度”)中起着重要作用,并将总线传输缓冲区大小“连接”到操作系统音频堆栈的缓冲区大小。从环形缓冲区消耗数据发生在操作系统音频堆栈的缓冲区大小中,因此它自然会增加一些延迟。

Android运行在Linux的“顶部”,大多数Android设备使用最流行的Linux音频驱动程序系统ALSA(高级Linux声音架构)。ALSA像这样处理环形缓冲区:

音频以“周期大小”步骤从环形缓冲器中消耗。

环形缓冲区的大小是“周期大小”的倍数。

例如:

周期大小= 480个样本。

期间数= 2。

环形缓冲区的大小为480x2 = 960个样本。

音频输入接收到一个周期(480个样本),而音频堆栈读取/处理另一个周期(480个样本)。

延迟= 1个周期,480个样本。它等于48000 Hz时的10 ms。

环形缓冲液(960个样品)

期间(480个样本) 期间(480个样本)

常见的周期数为2,但有些系统可能会更高。

延迟:一个或多个时期

Android音频硬件抽象层(HAL)

HAL充当Android媒体服务器和Linux音频驱动程序之间的中间人。在将Android“移植”到设备上时,移动设备的制造商提供HAL实现。

实现是开放的,供应商可以自由创建任何类型的HAL代码。使用预定义的结构进行与媒体服务器的通信。媒体服务器加载HAL并要求创建具有可选首选参数的输入或输出流,例如采样率,缓冲区大小或音频效果。

注意:HAL可能会也可能不会根据参数执行,并且媒体服务器必须“适应”HAL。

典型的HAL实现是tinyALSA,用于与ALSA音频驱动程序通信。一些供应商在这里提供了封闭的源代码来实现他们认为重要的音频功

在分析Android源存储库中的许多开源HAL实现的代码之后,我们发现了一些怪癖,由于奇怪的配置和糟糕的编码而不必要地增加了音频路径的大量延迟和CPU负载。

一个好的HAL实现不应该添加任何延迟。

延迟:0个或更多样本

Audio Flinger

Android媒体服务器包含两项服务:

AudioPolicy服务处理音频会话和权限处理,例如启用麦克风访问或呼叫中断。它与iOS的音频会话处理非常相似。

Audio Flinger服务处理数字音频流。

Audio Flinger创建了一个RecordThread,它充当应用程序和音频驱动程序之间的中间人。它的基本工作是:

使用Android HAL从驱动程序的环形缓冲区中获取下一个输入音频缓冲区。

如果应用程序请求的采样率与本机采样率不同,则重新采样缓冲区。

如果应用程序请求的缓冲区大小不同于本机周期大小,则执行其他缓冲。

如果按照这种方式配置Android,音频Flinger有一个“快速混音器”路径。如果用户应用程序使用本机(Android NDK)代码并设置具有本机硬件采样率和周期大小的音频缓冲区队列,则不会在此步骤中进行重新采样,额外缓冲或混合(“MixerThread”)。

RecordThread使用“推”方法,没有与音频驱动程序的任何严格同步。它试图在醒来和跑步时进行“有根据的猜测”,但“推”方法对辍学者更敏感。低延迟系统始终使用“拉”方法,其中音频驱动程序通过整个音频链“指示”音频i / o。很明显,当最初构思,设计和开发Android OS时,低延迟音频不是优先考虑的事情。

延迟:1个周期(最佳情况)

Binder

Android主进程间通信系统中的共享内存用于在Audio Flinger和用户应用程序之间传输音频缓冲区。它是Android的核心,在Android内部随处使用。

延迟:0

AudioRecord

我们现在处于用户应用程序的过程中。AudioRecord实现音频输入的应用程序端。这是一个可通过OpenSL ES访问的客户端库功能。

AudioRecord运行一个线程,定期从Audio Flinger获取一个新缓冲区,其音频Flinger描述了“推送”理念。如果开发人员将其设置为仅使用一个缓冲区,则不会为音频路径添加延迟。

延迟:0+样本

用户应用程序

最后,音频输入到达其目的地,即用户应用程序。

由于输入和输出线程不相同,因此用户应用程序必须在线程之间实现环形缓冲区。它的大小最小为2个周期(1个用于音频输入,1个用于音频输出),但写得不好的应用程序通常使用暴力并使用更多周期来解决CPU瓶颈。

从这一点开始,我们开始带着一些音频输出返回。

延迟:超过1个周期,通常接近2个(最佳情况)

AudioTrack

AudioTrack实现音频输出的用户应用程序。这是一个可通过OpenSL ES访问的客户端库功能。它运行一个线程,定期将下一个音频缓冲区发送到Audio Flinger。在Android 4.4.4之后,AudioTrack不会为音频路径添加延迟,因为它可以设置为仅使用一个缓冲区。

延迟:0+样本

Audio Flinger

创建一个PlaybackThread,它作为音频输入中描述的RecordThread的反转。

延迟:1期(最佳情况)

Android音频HAL

与音频输入相同。

延迟:0个或更多样本

音频驱动程序(ALSA,OSS等)

音频驱动器中的音频输出与音频输入的工作方式相同,也使用环形缓冲器。

延迟:一个或多个时期

总线从音频驱动器传输到音频芯片

与音频输入的总线传输类似,此处的延迟通常为1 ms至6 ms。

延迟:1-6毫秒

数模转换(DAC)

在这一点上,ADC的反转,数字音频被“转换”回模拟。出于与ADC相同的原因,经验法则是假设DAC有1 ms的延迟。

延迟:1毫秒

模拟音频输出

DAC的输出信号是模拟音频,但它需要额外的组件来驱动连接的设备,如耳机。与模拟音频输入类似,模拟组件可被视为“零延迟”。

延迟:0

解决方案

在所有阶段中,除非重写安卓底层音频系统,否则我们开发者能够操作的部分只有音频的播放方式,目前安卓原生的播放方式有三种:

MediaPlayer

SoundPool

AudioTrack(OpenSL)

AAudio

第一种用于长音频播放,实际测试结果为音频延迟依然十分大100ms~500ms之间

第二种和第三种用于短音频播放,短音频的播放延迟得到了很大的改善,基本徘徊在50ms之间

但是由于无法应用于长音频的播放,问题依旧还是没得到解决

image.png

现有的解决方案推荐

superpowered

致力于安卓低延迟做底层开发的C++ API

NativeAudio

Unity插件,泰国音频大佬

Unity2019

听说2019优化了底层音频的播放机制

关于长音频的延迟在各个机型上的不同而无法自动修正的解决方案

收集各种机型预设一个延迟的值

设计一个体验良好的界面可以帮助用户设置这个延迟的值

Unity2017默认音频、NativeAudio(OpenSL)、Criware(OpenSL)、Unity2019(OpenSL)默认音频延迟比较

短音效

单位是10ms

短音效延迟上NativeAudio和Criware是最低的,也是差不多的。

长音效

误差范围内的差距

效率待实验。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/453773.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深度学习之 hard negative mining (难例挖掘)

Hard Negative Mining Method 思想 hard是困难样本,negative是负样本,hard negative就是说在对负样本分类时候,loss比较大(label与prediction相差较大)的那些样本,也可以说是容易将负样本看成正样本的那些…

单列表_使用Excel中的quot;记录单quot;功能快速录入数据

在Excel中进行数据录入的时候,平常都是一行一行地录入数据,但是有时候在单元格之间,行与行,列与列之间频繁地切换去录入数据,费事费力还容易出错。今天给你推荐一个既好用又有效率的Excel中的隐藏功能——“记录单”。…

CentOS 6.9下的Setup工具(用于管理服务/防火墙/网络配置/验证服务)

说明:Setup工具套件好像是CentOS下特有的用于管理服务/防火墙/网络配置等,其实就是基于命令行模式界面的GUI工具。唯一特点就是方便。 安装: #安装Setup命令工具 yum -y install setuptool #安装Setup工具配套的系统服务组件 yum -y insta…

wireshark解析rtp协议,流媒体中的AMR/H263/H264包的方法

原文教程:http://hi.baidu.com/zjxiaoyu3/blog/item/22f9f18f32b45de5f11f3670.html 抓到完整的流媒体包之后,用wireshark打开,其中的包可能不会自动映射成RTP+AMR/H263/H264的包,做如下修改操作…

深度学习之非极大值抑制(Non-maximum suppression,NMS)

非极大值抑制(Non-maximum suppression,NMS)是一种去除非极大值的算法,常用于计算机视觉中的边缘检测、物体识别等。 算法流程 给出一张图片和上面许多物体检测的候选框(即每个框可能都代表某种物体)&…

148. 颜色分类

给定一个包含红,白,蓝且长度为 n 的数组,将数组元素进行分类使相同颜色的元素相邻,并按照红、白、蓝的顺序进行排序。 我们可以使用整数 0,1 和 2 分别代表红,白,蓝。 注意事项 不能使用代码库中…

vue项目token放在哪里_关于vue动态菜单的那点事

vue-element-admin4.0国内节点访问地址:https://panjiachen.gitee.io/vue-element-admin-site/zh/本此使用的是https://github.com/PanJiaChen/vue-element-admin/tree/i18n 国际化分支的版本。说是除了国际化其他都一样。本文主要介绍前台动态的使用资源权限。后台…

H264学习方法历程资料

我的H.264学习历程 半年前,我知道了H.264这个名词。那个时候决定学习H.264,可是我连资料都不知道如何收集。而且整个学校就只有我一个人在学习H.264, 找不到人交流,所以那个时候学得真的是举步维艰,很痛苦&#xff0c…

深度学习之 ROI Pooling

什么是ROI? ROI是 Region of interest 的简写,指的是 Faster R-CNN 结构中,经过 RPN 层后,产生的 proposal 对应的 box 框。 ROI Pooling 顾名思义,是 pooling 层的一种,而且是针对 ROIs 的 pooling。整个…

KD树小结

很久之前我就想过怎么快速在二维平面上查找一个区域的信息,思考许久无果,只能想到几种优秀一点的暴力。 KD树就是干上面那件事的。 别的不多说,赶紧把自己的理解写下来,免得凉了。 KD树的组成 以维护k维空间(x,y,……)内的KD树为例…

多元函数求极值中的a_多元函数的条件极值和拉格朗日乘数法

、条件极值、拉格朗日乘数法1. 转化为无条件极值在讨论多元函数极值问题时,如果遇到除了在定义域中寻求驻点(可能的极值点)外,对自变量再无别的限制条件,我们称这类问题为函数的无条件极值。如求的极值,就是无条件极值问题。然而在…

深度学习之 RPN(RegionProposal Network)- 区域候选网络

anchor boxes基本概念与作用: feature map 上的一个点可以映射回输入图片上的一个点,以特征图上这个点为中心,预先人为设定 k 个 boxes,这些 boxes 就称为在这个点上生成的 k 个 anchor boxes(所有anchor boxes的中心点坐标是一样…

h264的码率控制 JVT-G012

开始看h264的码率控制,很多地方都提到 G012,拿来做为参考比较,看来很有必要研究清楚。 偶这人,E文文档不翻译的话,看过就忘了,于是草草翻译了下,因为不打算做B帧,也不准备在同一帧中…

Android RecyclerView嵌套EditView实时更新Item数据

一、场景(例如:购物车) 1、当我们需要以列表样式管理某些数据时,可能需要列表项的某个字段可编辑 2、编辑Item上的某个字段后可能还要更新相关字段的值 二、可能遇到的问题 1、列表滑动导致输入框中的数据错位(或者焦点…

workbench拓扑优化教程_优化技术在水泵水力设计的应用(上篇)

文章来源:安世亚太官方订阅号(搜索:Peraglobal)CFD技术在泵的内流数值模拟、研究泵内部流动规律和结构方面已广泛应用,取得了很多成果。但是初步设计的产品如果通过CFD仿真得到的性能曲线不能满足使用要求,…

深度学习之 TensorRT

1 简介 TensorRT是一个高性能的深度学习推理(Inference)优化器,可以为深度学习应用提供低延迟、高吞吐率的部署推理。TensorRT可用于对超大规模数据中心、嵌入式平台或自动驾驶平台进行推理加速。TensorRT现已能支持TensorFlow、Caffe、Mxne…

H.264笔记

H.264标准写得比较繁复,所以考虑在浏览完Whitepaper之后就开始研读X264代码。X264代码风格还是比较清晰简洁的。根据对标准得理解,Picture Order Count在Slice解码的一开始就被提及:I0 B1 B2 P3 B4 B5 P6I0 P3 B1 B2 P6 B4 B5于是I0的POC是0&…

进制转换中dbho是什么意思_什么是网段?二进制十进制如何互相转换?看完这篇,你就全明白了...

之前的文章讲了ip,子网掩码,网关的关系,今天着重讲一下网段。我们用傻瓜交换机通讯时,一个网段的设备才能互相通讯,怎么能判断两个ip是同一个网段呢?今天就简单的说一下。(这篇文章用语音听可以起到催眠作用…

【网络流24题】星际转移问题(最大流)

【网络流24题】星际转移问题(最大流) 题面 Cogs 题解 因为天数是未知的,所以我们要想办法处理天数 可以选择二分或者依次累加天数 因为数据范围较小,使用二分可能反而复杂度会增高 所以使用不断累加天数 那么,把所有的…

使用 gunicorn 部署flask项目

1、WSGI协议 Web框架致力于如何生成HTML代码,而Web服务器用于处理和响应HTTP请求。Web框架和Web服务器之间的通信,需要一套双方都遵守的接口协议。WSGI协议就是用来统一这两者的接口的。 2、WSGI容器 常用的WSGI容器有Gunicorn和uWSGI,但G…