Flex Flash Player回声消除的最佳方法
Adobe Flash Player 已经成为音频和视频播放的非常流行的工具。实际上,目前大多数因特网视频均使用 Flash Player观看。 Flash Player 通过将许多技术进行组合可以提供具有丰富视觉体验和效率的高质量的播放功能,这些技术包括高级音频和视频压缩方法 (H.264、MP3和 AAC codecs)、通用媒体功能 (多速率流媒体、播放列表、搜寻和其它功能) 和高效的播放机制 (硬件解码和直接渲染)等。
由于Flash Player 在桌面计算机上的广泛应用已经在移动设备上的日趋流行,使用Flash Player 进行实时音频和视频通信变得非常重要。 然而,当与视频播放相比,实时通信具有完全不同的要求。 其中最重要的要求包括:
- 最大程度地减小通信端点之间的时延
- 具有错误恢复功能的、高质量语音编解码器
- 免提的回声抑制消除功能
尽管Flash Player 从 2002年开始已经支持音频/视频功能并且已经可以利用Adobe Connect 和Big Blue Button等的解决方案进行web会议,但真正游戏的变更事件发生在2008年 Flash Player 10发布的时候,Flash Player 10引入了低时延传输协议和新的音频编解码器,这使得Flash Player 非常适合实时通信。
在本文中,我将简单地描述实时通信的要求以及Flash Player 如何满足这些要求。 我还将介绍新的用于增强音频功能的ActionScript API,为你提供相应的最佳方法并且给出相应的缺点,以及为你展示一个范例应用程序。
在2002年,Flash Player 6引入了实时消息协议(Real-Time Messaging Protocol (RTMP))和Nellymoser音频编解码器。 利用 Flash Communications Server MX,开发人员能够开发用于两个或更多Flash Player端点之间的实时通信应用程序。
RTMP基于传输控制协议(Transmission Control Protocol (TCP)),它能够提供可靠的数据传输功能,但代价是时延无法控制—这意味着时延可以无限长。 因此,接收一个无误码的传输数据包的方法是重复发送丢失的数据包。 如果数据包发生不断丢失的现象,则产生的时延将会很大,因为丢失的数据包必须重传。
Nellymoser 是一种私有协议的编解码器,它的压缩效率低并且业界支持受限。 如果使用 RTMP,则音频消息绝不会产生丢失现象,但由于组网或服务器问题可能出现排队现象。 为了防止时延累积,Flash Player 使用一种所谓的 catch-up机制,利用这一机制,音频能够以快于其自然取样速率的方式进行播放。 这种渐进式的时延降低方式仅仅带来最低程度的音频失真但不会改变音频的声调。
尽管RTMP适用于广播和webcast应用程序(在这里对时延没有严格要求),但对实时通信来说,它的适用性有限,因为几百微秒的时延可能导致通话不能正常进行。 在实时通信过程中,最大程度地减少时延比维持无误码传输更为重要。 大多数音频和视频编码技术 (例如H.264 视频编解码和 Speex 语音编解码) 在设计时均考虑网络传输误码问题,因此均能够处理这些问题。
Flash Player 10引入了实时媒体流协议(Real-Time Media Flow Protocol (RTMFP))。 与RTMP不同,RTMFP 基于用户数据报协议(User Datagram Protocol (UDP))。 RTMFP支持进行可靠的数据发送 (使用重传机制) 或不可靠的数据发送。 通过使用不可靠的传输机制能够最大限度地降低传输时延。 此外,RTMFP 支持端到端的直接连接,它不仅能够降低服务器的要求,还能够进一步降低通信端点之间的时延。
Flash Player 10 还引入了Speex 编解码技术。 Speex 是一种开源、免版税的编解码技术,因此它获得业界的广泛支持。 Flash支持16 kHz的 Speex 编码。 此外,当Speex用于实时通信时,使用 RTMFP的传输时延能够降到最低程度。 RTMFP 在收到所有的 Speex消息时能够立即将它们传递到较高层。 Flash Player在播放消息时,使用一种自适应Speex 抖动缓存器。 另外,Adobe 已经实现了Speex 噪音抑制功能和语音激活检测功能,因此在语音静默期间能够最大程度地降低传输带宽。
这些功能使得利用RTMFP和 Speex技术开发实时通信应用程序成为可能。 一种可接受的用户体验是用户应该戴耳机以防止回声。 通常当声音从计算机的喇叭反馈到麦克风时将产生回声。 使用耳机在公司环境中是可以接受的,但在消费者环境中是明显不受欢迎的,因为通常用户使用网络相机或内置的笔记本电脑麦克风。 因此,为了获得广泛的适应性,回声抑制(acoustic echo cancellation (AEC))是 voice-over-IP (VoIP) 应用程序的绝对必需的功能。 messenger应用程序(例如 Skype和Google Talk) 和softphone (例如 Xlite) 均支持AEC功能。
Adobe Flash Player 10.3和 Adobe AIR 2.7 已经引入了增强音频功能,其中包括回声抑制和噪音抑制功能。 Flash Player和 AIR支持的所有桌面平台均支持增强语音功能。
我们已经在 Flash平台中添加一个新的API 以便支持增强语音功能。 Flash Player和 AIR支持的所有桌面平台均支持该功能。 只有ActionScript 3支持该新的API。你必须将你的制作环境升级到Flash Player 10.3或 AIR 2.7 (或更高版本) 和SWF v12,并且你必须更新你的playerglobal.swc。 下面的类将受到影响:
Microphone
:将一个新的静态方法添加到该类以便创建增强的麦克风功能以及用于配置增强的麦克风功能选项的read/write 属性。MicrophoneEnhancedOptions
:该新类允许你配置增强的麦克风设置。MicrophoneEnhancedMode
:该新类可以枚举增强的麦克风操作模式。
利用下列几行代码可以实现将音频发送到另一个Flash 端点或 Flash Media Server :
var netConnection:NetConnection = new NetConnection(); netConnection.connect("rtmfp://example.com/rtc"); var netStream:NetStream = new NetStream(netConnection); var microphone:Microphone = Microphone.getMicrophone(); netStream.attachAudio(microphone);
使用增强的音频功能非常简单:你可以利用Microphone.getEnhancedMicrophone()
静态方法获得一个增强麦克风:
var microphone:Microphone = Microphone.getEnhancedMicrophone();
netStream.attachAudio(microphone);
除了回声消除功能,增强音频还能够提供噪音抑制功能。 以前,Flash Player 只能为 Speex 音频提供噪音抑制功能。 新的噪音抑制方案可以适用于所有捕捉的音频范例。 Microphone类的现有的noiseSuppressionLevel
属性可以控制噪音抑制功能并且在默认情形下提供该功能。 将noiseSuppressionLevel
设置为 0 可以禁用噪音抑制功能。
增强音频功能具有下列一些限制:
- 你不能同时使用增强和非增强音频功能。
- 在任意给定的时刻,你只能使用一个单一增强音频捕获功能。
当麦克风由于上述原因停止提供音频数据时,Flash Player 下发 Microphone 状态事件Microphone.UNAVAILABLE
。 与非增强音频功能相比,这是一个不太严重的缺点,但对于实际的实时通信应用程序来说,提供一个激活的麦克风应该是足够的。
增强音频的操作是由你的Microphone 对象的enhancedOptions
属性和 MicrophoneEnhancedOptions
类控制的。 该类具有下列属性:
MicrophoneEnhancedOptions.mode
可以为增强音频功能选择相应的操作模式。 关于可能的取值,请参见MicrophoneEnhancedMode
类。 USB捕捉设备的默认值是MicrophoneEnhancedMode.HALF_DUPLEX
其它设备的默认值是MicrophoneEnhancedMode.FULL_DUPLEX
。MicrophoneEnhancedOptions.echoPath
指定了回声路径长度(单位是微秒)。 较长的回声路径意味着较好的回声消除效果,但也引入了较长的时延并且需要较多处理能力。 相应的默认值是128;唯一的其它可能值是256。MicrophoneEnhancedOptions.nonLinearProcessing
指定了是否使用非线性处理模式抑制残余回声。 使用时域技术,并且使用默认值。
在MicrophoneEnhancedMode
类中,枚举了可用的增强麦克风操作模式。 系统支持下列值:
MicrophneEnhancedMode.FULL_DUPLEX
: 全双工处理提供最佳质量的回声消除功能。 通话双方能够同时说话。 这一模式要求高质量的输入和输出设备和最强的计算能力。 这对于内置喇叭和麦克风设备的笔记本计算机来说是最理想的方法。MicrophoneEnhancedMode.HALF_DUPLEX
:与全双工相比,半双工使用更为简单的处理方式,因此需要较少的计算能力。 它假定同时只有通话的一方说话。 半双工是USB麦克风设备的默认模式。MicrophoneEnhancedMode.HEADSET
:回声消除使用低回声操作模式并且假定通话双方均使用耳机。 这一模式消除了可能从喇叭泄露到麦克风的最低限度的回声。 这一模式要求最少的处理能力。MicrophoneEnhancedMode.SPEAKER_MUTE
: 回声消除功能关闭,但其它语音处理功能 (例如噪音降低功能) 仍然处于打开状态。MicrophoneEnhancedMode.OFF
: 所有增强音频功能均关闭。
MicrophoneEnhancedOptions
的构造器将设置下列默认属性:
var options:MicrophoneEnhancedOptions = new MicrophoneEnhancedOptions();
options.mode = MicrophoneEnhancedMode.FULL_DUPLEX;
options.echoPath = 128;
options.nonLinearProcessing = true;
请使用下列代码查询实际使用的增强麦克风选项:
var microphone:Microphone = Microphone.getEnhancedMicrophone();
var options:MicrophoneEnhancedOptions = microphone.enhancedOptions;
当你只希望修改增强音频功能的参数时,确保你没有使用构造器创建一个MicrophoneEnhancedOptions
对象,因为你可能会不注意地覆盖了其它参数。
当你使用具有增强音频功能的麦克风数据生成API (范例数据事件) ,你将收到回声消除和噪音抑制的范例。
当为VoIP应用程序提供相应的最佳用户体验时,你应该使用具有Speex编解码及增强音频功能的RTMFP功能。 在接收器侧,确保使用未缓存的实时流模式,通过适当地设置你的NetStream对象的 bufferTime
属性可以属性这一目的。 这将能够确保音频消息能够以非可靠方式传送,因此相应的传输时延最小。 我强烈建议你尽可能地使用端到端连接,以便获得最小的传输时延。 这在多方通信的情形下或在不支持RTMFP 的情形下可能是不可行的(请参见我的文章:Flash Media Server的实时协作的最佳方法)。
使用全双工模式能够获得最佳的回声消除效果。 如果你的笔记本电脑附带一个USB网络相机,则你应该使用内置的麦克风。 你也可以实现一个允许用户根据自己的要求选择麦克风的用户界面。 正如前面所述,你能够通过使用下列声明获得一个功能增强的麦克风:
var microphone:Microphone = Microphone.getEnhancedMicrophone();
推荐使用默认的增强麦克风选项。 (USB设备的增强麦克风模式的默认值是半双工,而其它设备的增强麦克风模式的默认值是全双工。回声路径是 128 ms 并且非线性处理功能启用)。
此外,Adobe 还强烈推荐你使用 Speex编解码技术。 Speex 捕捉和压缩功能只支持 16 kHz (播放功能还支持 8 kHz),因此无需指定取样速率:
microphone.codec = SoundCodec.SPEEX;
Speex 基于取样帧运行,并且每帧长度为 20 ms (320 取样/16 kHz)。 你能够定义你希望在一个消息中发送的帧数。 默认的帧数是2,而最大的帧数是8。为了最大限度地减少时延,你能够在每个消息中发送一个单一帧。
microphone.framesPerPacket = 1;
显然,在一个消息中发送更多的帧能够降低传输的开销;对每个消息来说,开销字节的数量可以多达50 (RTMFP/UDP/IP headers)。 这一开销是显著的并且不可忽略。 你可以在时延和开销之间寻求平衡(特别是在无线或3G情形下),但在大多数情形下,最大限度地减少时延更为重要。
通常应该将静默级别设置为0。当静默级别是非0时,将发生不连续传输现象。 这对 Speex 抖动缓存和回声消除算法将产生负面影响。 此外,Speex 能够实现语音激活检测功能并且在没有检测到语音时只使用 4 Kbps 带宽。
microphone.setSilenceLevel(0, 2000);
将静默级别设置为0的后果之一是你将不再收到语音激活事件。 如果你的应用程序必须依赖麦克风的激活事件来检测一个用户是否正在说话,则你必须选择其它的方法。
当设置麦克风增益时请小心地考虑这一问题。 Flash Player不能修改系统捕捉或播放量电平:它只能执行音频取样的乘法。 对于Speex和回声消除功能,过载级别能够导致性能变差。 将增益设置为50不能修改取样值,这可能是最佳的方法:
microphone.gain = 50;
不正确的麦克风和播放电平能够导致音频质量的降低。 你可能希望通知用户调整其硬件音频电平。
Microphone 类支持利用 setUseEchoSuppression()
方法的回声抑制。 相应的算法非常简单:当有输出音频产生时,将麦克风输入取样的大小除以2。这将会导致麦克风音频电平的变化,而在某些应用程序中,这是不希望发生的情形。 当使用增强音频功能时,可以忽略该回声抑制功能。
从计算能力方面来看,AEC 是浪费的。 目前,只有桌面平台支持Flash Player 和AIR。 尽管AEC已经针对 SIMD 架构进行优化,但它在低性能的笔记本计算机中占用大量 CPU计算能力。 当系统不支持AEC时,Microphone.getEnhancedMicrophone()
将返回 null
。
多方回声消除操作存在很多棘手问题。 尽管从API的角度来看,没有什么问题能够阻止你创建多方通信应用程序,但增强音频功能的性能针对两方进行优化。
为了回声消除功能可以正常工作,你必须使用未缓存的音频。也就是说,必须将预定的NetStream对象的bufferTime 属性设置为0。由NetStream产生的、缓存时间大于0的音频将不包含在回声消除功能的范围内。
全双工模式能够提供最佳质量的回声消除效果并且还支持"双向通话(double-talk)" (双方同时说话)。 然而,它要求最强的处理能力和良好的硬件性能。 它不能用于USB捕捉设备,因为目前系统不支持USB捕捉设备和喇叭声卡之间的同步功能。
当你使用非增强音频功能时,并且你具有多音频捕捉设备,下面的代码将如预期的那样运行:
ns1.attachAudio(Microphone.getMicrophone(0));
ns2.attachAudio(Microphone.getMicrophone(1));
其中ns1和 ns2 是两个不同的发布 NetStream对象。 每个NetStream对象可以发布从各自的非增强麦克风的捕捉的音频。 目前,当使用增强音频功能时,系统不支持该功能:你只能在任一时刻支持一个单一增强的麦克风实例。 此外,你也不能同时支持非增强和增强麦克风捕捉音频功能。 当你使用增强语音功能并且希望打开一个不同的麦克风实例时,现有的麦克风将停止产生数据并且下发 Microphone.UNAVAILABLE
事件。 下面的使用案例将对此进行说明:
使用案例 1
- 创建麦克风 mic1。
- 创建增强麦克风 mic2;mic1 将下发 Microphone.UNAVAILABLE 状态事件。
使用案例 2
- 创建增强麦克风 mic1。
- 创建麦克风 mic2;mic1 将下发 Microphone.UNAVAILABLE 状态事件。
使用案例 3
- 创建增强麦克风 mic1。
- 利用一个不同设备,创建增强麦克风mic2;mic1将下发 Microphone.UNAVAILABLE 状态事件。
使用案例 4
- 创建麦克风mic1。
- 利用一个不同设备,创建麦克风mic2;mic1 和 mic2 均能够提供音频数据。
在以前的一篇文章中,我使用Adobe Cirrus开发了一款范例实时协作应用程序。 我已经升级了该应用程序以便使用新引入的增强音频API。 我创建了一个能够获取一个麦克风的中央函数:
private function getMicrophone():Microphone
{
if (enhancedCheckbox.selected)
{
return Microphone.getEnhancedMicrophone(micIndex);
}
else
{
return Microphone.getMicrophone(micIndex);
}
}
在该函数中,micIndex
是一个存储用户选中的麦克风索引的变量,enhancedCheckbox
是一个 Flex Spark 复选框组件,用于控制增强麦克风选择。
在本文中,我讨论了实时通信的三个关键组件 (最大程度地降低时延,高质量和开源语音编解码以及回声消除) 并且介绍了Flash Player 如何满足这些要求。 我的讨论重点放在增强音频,它是在 Adobe Flash Player 10.3和 Adobe AIR 2.7中引入的功能。 利用这些功能,你可以开发高质量和用户友好的各种实时通信和协作应用程序。
请查阅用于在Flash Player 10中使用RTMFP开发端到端应用程序的Cirrus服务和使用Flash Media Server进行实时协作的最佳方法,以便了解实时通信应用程序的其它方面信息。