开发音频插件
本文展示如何开发一个与声网 Web SDK 4.x 搭配使用的音频插件。
技术原理
声网为开发音频插件提供以下抽象类:
- 必需的基础类:
AudioExtension
:实现插件的初始化,包括创建插件、设置日志上报、设置事件上报等。AudioProcessor
:实现音频数据的处理能力,包括接收、处理和返回处理完的音频数据。
- 可选的辅助类:
Ticker
:帮助管理周期性任务。Logger
:向声网 SDK 上传日志。Reporter
:向声网 SDK 报告事件。
前提条件
开发前,请确保你的开发环境满足以下要求:
- Windows 或 macOS 计算机,需满足以下要求:
- 下载声网 Web SDK 支持的浏览器。声网强烈推荐使用最新稳定版 Google Chrome 浏览器。
- 具备物理音视频采集设备。
- 可连接到互联网。如果你的网络环境部署了防火墙,请参考应对防火墙限制以正常使用声网服务。
- 搭载 2.2 GHz Intel 第二代 i3/i5/i7 处理器或同等性能的其他处理器。
- 安装 Node.js 及 npm。
准备开发环境
通过 npm 将插件开发模块(agora-rte-extension)集成到你的项目中:
-
运行以下命令安装:
Shellnpm install --save agora-rte-extension
-
在你的
.js
文件中加入以下代码导入插件开发模块:JavaScriptimport {AudioExtension, AudioProcessor} from 'agora-rte-extension'
开发音频插件
本节详细介绍开发音频插件必须实现的 API。你还可以根据实际需要实现一些辅助类 API,优化插件的设计和性能,详见 API 参考。
实现插件初始化
插件初始化通过 AudioExtension
类实现。你需要实现 AudioExtension
类的 createProcessor
方法:
createProcessor
abstract class AudioExtension<T extends AudioProcessor> {
createProcessor(): T;
}
创建 AudioProcessor
实例。
插件使用者调用 extension.createProcessor
时,SDK 会调用该方法。你需要在该方法中返回创建好的 AudioProcessor
实例。
实现音频数据处理
实现音频数据处理包括以下步骤:
- 接收待处理的音频:通过
AudioProcessor
类的onNode
和AudioProcessorContext
类的getAudioContext
方法实现。 - 处理音频:需要你自行实现。
- 输出处理后的音频:通过
AudioProcessor
类的output
方法实现。
onNode
abstract onNode?(node: AudioNode, context: IAudioProcessorContext): void;
从前一个节点接收到待处理的音频数据回调。
参数
-
node
:前一个AudioNode
。AudioNode
是 Web Audio API 提供的接口类,详见 Web Audio API interfaces。 -
context
:当前音频处理管道的 context。
output
output(track: MediaStreamTrack | AudioNode, context: IProcessorContext): void;
输出处理后的音频数据。
参数
-
track
:处理后的音频数据。推荐使用AudioNode
。 -
context
:当前音频处理管道的 context。
getAudioContext
getAudioContext(): Promise<AudioContext>;
获取当前音频处理管道的 AudioContext
。AudioContext
是 Web Audio API 提供的接口类,详见 Web Audio API interfaces。
示例项目
声网提供一个 Web 插件开发的示例项目供你参考,你可以前往下载或查看其中的源代码。
- Gitee:ExtensionDemo
- GitHub:ExtensionDemo
以下示例代码展示了如何开发一个音频插件:
class YourExtension extends AudioExtension<YourProcessor> {
// 创建 Processor
protected _createProcessor(): YourProcessor {
return new YourProcessor();
}
}
class CustomAudioProcessor extends AudioProcessor {
// 从前一个 AudioNode 接收到音频数据
onNode(node: AudioNode, context: IAudioProcessorContext) {
// 创建 AudioNode
const audioContext = context.getAudioContext();
const gainNode = audioContext.createGain();
// 连接前一个 AudioNode
node.connect(gainNode);
}
process() {
// TODO:添加你的插件的音频处理逻辑
// 输出处理后的音频数据
this.output(gainNode, context);
}
}
API 参考
本节介绍开发音频插件的辅助类 API。
AudioProcessor
name
name: string;
Processor
的名称。
enabled
enabled :boolean;
Processor
的开启状态。
ID
public readonly ID:string;
Processor
的标识符。
kind
public get Kind():'video' | 'audio';
Processor
的类型,分为视频和音频两种。
context
protected context?: IProcessorContext;
用于 Processor
请求原始媒体流并重新进行采集。
onPiped
abstract onPiped?(context: IProcessorContext): void;
LocalVideoTrack
连接到当前媒体处理管道回调。
如果只是连接多个 Processor
,不会触发该回调。例如:插件使用者调用 processorA.pipe(processorB)
。
onUnpiped
abstract onUnPiped?(): void;
Processor
断开与媒体处理管道的连接回调。
onEnableChange
abstract onEnableChange?(enabled: boolean): void | Promise<void>;
Processor
的开启状态变化回调。
inputNode
protected inputNode?:AudioNode;
Processor
接收到的音频。
outputNode
protected outputNode?:AudioNode;
Processor
处理后的音频。
AudioProcessorContext
interface IAudioProcessorContext extends IProcessorContext {
getAudioContext(): Promise<AudioContext>;
}
用于 AudioProcessor
请求原始音频流并重新进行采集。
Ticker
constructor
public constructor(type:"Timer" | "RAF" | "Oscillator", interval: number):Ticker;
Ticker
的构建函数。
参数
-
type
:类型,支持以下三种:-
Timer
: 使用setTimeout
作为插件内部的计时器。 -
(推荐)
RAF
: 使用requestAnimationFrame
作为插件内部的计时器。大多数情况下,该类型的Ticker
渲染性能最好。 -
Oscillator
: 使用WebAudio
的OscillatorNode
作为插件内部的计时器。该类型的Ticker
在浏览器页面不被浏览时也能运行。
-
-
interval
:两次回调之间的间隔。Ticker
会按照这个间隔执行,但无法保证 100% 精准。
Ticker.add
public add(fn: Function): void;
添加计时任务。
Ticker.remove
public remove():void;
取消添加的计时任务。
Ticker.start
public start():void;
开始计时。
Ticker.stop
public stop():void;
停止计时。
Logger
interface IExtensionLogger {
debug(...args: any): void;
error(...args: any): void;
info(...args: any): void;
warning(...args: any): void;
}
提供四种级别的日志。
插件使用者如果在调用 AgoraRTC.registerExtension
注册插件时选择了上传日志,通过 Logger
类上报日志的插件状态会更新。
Reporter
Reporter.reportApiInvoke
public reportApiInvoke<T>(params: ReportApiInvokeParams): AgoraApiExecutor<T>;
向 SDK 报告 API 调用的相关事件。
其中 ReportApiInvokeParams
和 AgoraApiExecutor
的定义如下:
interface ReportApiInvokeParams {
// 被调用的 API 的名称
name: string;
// 与该 API 有关的参数或选项
options: any;
// 是否报告该 API 的调用结果
reportResult?: boolean;
// 定义多久为调用超时
timeout?: number;
}
interface AgoraApiExecutor<T> {
// API 调用成功
onSuccess: (result: T) => void;
// API 调用失败
onError: (err: Error) => void;
}