本文展示如何开发一个与声网 Web SDK 4.x 搭配使用的音频插件。
声网为开发音频插件提供以下抽象类:
AudioExtension
:实现插件的初始化,包括创建插件、设置日志上报、设置事件上报等。AudioProcessor
:实现音频数据的处理能力,包括接收、处理和返回处理完的音频数据。Ticker
:帮助管理周期性任务。Logger
:向声网 SDK 上传日志。Reporter
:向声网 SDK 报告事件。开发前,请确保你的开发环境满足以下要求:
通过 npm 将插件开发模块(agora-rte-extension)集成到你的项目中:
运行以下命令安装:
npm install --save agora-rte-extension
在你的 .js
文件中加入以下代码导入插件开发模块:
import {AudioExtension, AudioProcessor} from 'agora-rte-extension'
本节详细介绍开发音频插件必须实现的 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 插件开发的示例项目 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。
name: string;
Processor
的名称。
enabled :boolean;
Processor
的开启状态。
public readonly ID:string;
Processor
的标识符。
public get Kind():'video' | 'audio';
Processor
的类型,分为视频和音频两种。
protected context?: IProcessorContext;
用于 Processor
请求原始媒体流并重新进行采集。
abstract onPiped?(context: IProcessorContext): void;
LocalVideoTrack
连接到当前媒体处理管道回调。
注意:如果只是连接多个 Processor
,不会触发该回调。例如:插件使用者调用 processorA.pipe(processorB)
。
abstract onUnPiped?(): void;
Processor
断开与媒体处理管道的连接回调。
abstract onEnableChange?(enabled: boolean): void | Promise<void>;
Processor
的开启状态变化回调。
protected inputNode?:AudioNode;
Processor
接收到的音频。
protected outputNode?:AudioNode;
Processor
处理后的音频。
interface IAudioProcessorContext extends IProcessorContext {
getAudioContext(): Promise<AudioContext>;
}
用于 AudioProcessor
请求原始音频流并重新进行采集。
public constructor(type:"Timer" | "RAF" | "Oscillator", interval: number):Ticker;
Ticker
的构建函数。
参数
type
:类型,支持以下三种:
Timer
: 使用 setTimeout
作为插件内部的计时器。
(推荐)RAF
: 使用 requestAnimationFrame
作为插件内部的计时器。大多数情况下,该类型的 Ticker
渲染性能最好。
Oscillator
: 使用 WebAudio
的 OscillatorNode
作为插件内部的计时器。该类型的 Ticker
在浏览器页面不被浏览时也能运行。
interval
:两次回调之间的间隔。 Ticker
会尽量按照这个间隔执行,但不保证 100% 精准。
public add(fn: Function): void;
添加计时任务。
public remove():void;
取消添加的计时任务。
public start():void;
开始计时。
public stop():void;
停止计时。
interface IExtensionLogger {
debug(...args: any): void;
error(...args: any): void;
info(...args: any): void;
warning(...args: any): void;
}
提供四种级别的日志。
插件使用者如果在调用 AgoraRTC.registerExtension
注册插件时选择了上传日志,通过 Logger
类上报日志的插件状态会更新。
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;
}