AI 音效
更新时间: 2024/10/30 09:37:31
在社交娱乐行业的互动场景中,美声、变声、降噪功能起着重要作用。本文介绍了如何使用网易云信音视频通话的 AI 音效插件,实现 AI 降噪和美声变声结合的功能。
应用场景
网易云信音视频通话 SDK(简称 NERTC SDK)支持设置多种预设的美声与变声音效,您也可以通过设置本地语音音效均衡或混响来达到自定义的人声效果,增加场景气氛。在多人语聊或 K 歌房场景中,AI 音效能够对主播或参与者的声音进行美化,营造更加娱乐化的氛围,提高互动体验。
在音视频通话或互动直播场景中,背景噪声可能会干扰通话质量,例如户外的车流声或室内的背景人声。AI 音效插件使用网易云信自主研发的 AI 算法,具备降噪功能。它能智能识别环境中的各种声音,过滤掉环境噪声对通话造成的干扰。开启 AI 降噪功能后,可将背景中的人声、键盘声等不稳定噪音进行降噪处理,同时提高对稳定噪声的抑制,使人声更加清晰纯净。
变更记录
以下为 NERTC SDK AI 音效插件的变更记录,您可以前往 网易云信 SDK 下载中心 获取最新版本 SDK。
- 从 5.6.41 版本起,如果使用
await rtc.localStream.registerPlugin()
方式注册 AI 音效插件,您需要在调用registerPlugin()
之前绑定插件事件。 - 从 5.6.10 版本起,NERTC SDK 支持远端流的美声变声能力。使用方法请参考下文 远端流示例代码。
- 从 5.5.11 版本起,NERTC SDK 支持美声变声混响。注册插件时 AI 降噪使用的
key
需要从AIDenoise
替换为AIAudioEffects
,其他接口使用方式不变。 - 从 4.6.25 版本起,NERTC SDK 支持 AI 降噪。
浏览器版本
AI 音效需要的浏览器最低版本兼容情况如下:
- Google Chrome 浏览器 72 及以上版本
- Apple Safari 浏览器 15.4 及以上版本
- Mozilla Firefox 浏览器最新(120)版本
- Microsoft Edge 浏览器最新(119)版本
注意事项
setAudioEffect
不支持预设,需要在触发audio-effect-enabled
后调用。- 调用
disableAudioEffect
后再次调用enableAudioEffect
,需要重新设置美声变声效果。 - 开启伴音替换麦克风采集的音频流后,不支持开启 AI 音效。
本端流 AI 音效
AI 降噪
-
调用
createStream
方法创建并返回一个本地音视频流对象。调用
createStream
创建媒体流之前,需要通过getDevices
方法获取麦克风和摄像头设备的 deviceId。详细说明请参考 音视频设备检测。 -
调用
registerPlugin
方法并配置pluginOptions
参数注册 AI 音效插件,其中pluginOptions = {key: 'AIAudioEffects', pluginUrl?: string, pluginObj?: Object, wasmUrl: string}
,相关字段的具体说明如下:参数是否必选 描述 key
是 AIAudioEffects
,必填,表示 AI 音效插件。pluginUrl
否 插件的 CDN 地址,同 pluginObj 互斥。支持自定义 URL pluginObj
否 插件对象,同 pluginUrl 互斥。请通过 NPM 方式安装,具体安装方式请参考下方 说明。 wasmUrl
是 插件依赖的 wasm 文件地址。官网的 SDK 包以及 NPM 包均提供原文件,可以部署到您自己本地的服务器中。 -
AI 音效插件提供 simd 版本和非 simd 版本,建议使用 simd 版本以体验更佳的性能。在不支持 smid 版本的浏览器中请使用非 smid 版本的插件,关于您的浏览器是否支持 simd 版本的插件,请参考
wasm-feature-detect
。 -
必须传入
pluginUrl
和pluginObj
的其中一项。 -
安装
pluginObj
的代码如下:Bash
//第一步,安装 nertc-web-sdk npm install nertc-web-sdk //第二步,导入 AI 音效插件 import AIAudioEffects from 'nertc-web-sdk/NERTC_Web_SDK_AIAudioEffects'
-
若您选择通过 NPM 安装插件,您在安装后可在
nertc-web-sdk/wasm
路径下的文件夹中找到NERTC_Web_SDK_AIAudioEffects_simd.wasm
和NERTC_Web_SDK_AIAudioEffects_nosimd.wasm
文件,该文件可部署到您自己本地的服务器中,并将部署后的文件地址通过wasmUrl
参数传递给 SDK。
-
-
在本端监听
on('plugin-load')
和on('plugin-load-error')
事件,以判断 AI 音效插件是否加载成功。若因插件注册失败触发了
on('plugin-load-error')
回调,请关注返回的event
结构里的msg
详细字段:Load {wasmUrl} error
:wasm 加载失败,需要检查 URL 地址。unsupport plugin {key}
:不支持该插件,需要检查key
参数和pluginUrl/pluginObj
是否匹配。Load plugin ${pluginUrl} error
:pluginUrl 加载失败。
-
在触发
plugin-load
回调后,调用enableAIDenoise
方法启用 AI 降噪功能。 -
若您需要取消 AI 降噪效果,请调用
disableAIDenoise
方法关闭 AI 降噪进程。 -
若您需要销毁 AI 音效插件,请调用
unregisterPlugin(pluginKey)
方法销毁插件。
美声和变声
NERTC SDK 为您提供多种类型的预设人声效果,以满足您在不同场景下的美声与变声需求。如果预设的美声与变声效果无法满足您的需求,也可以通过音调、音效均衡和混响,实现自定义的人声效果。
调用 setAudioEffect(type, value)
方法可以设置各类音效,支持以下美声,变声和自定义音效:
type | value | 说明 |
---|---|---|
0(变声) | 0 | 关闭变声 |
1 | 机器人 | |
2 | 巨人 | |
3 | 恐怖 | |
4 | 成熟 | |
5 | 男变女 | |
6 | 女变男 | |
7 | 男变萝莉 | |
8 | 女变萝莉 | |
1(美声) | 0 | 关闭美声 |
1 | 低沉 | |
2 | 圆润 | |
3 | 清澈 | |
4 | 磁性 | |
5 | 录音棚 | |
6 | 天籁 | |
7 | KTV | |
8 | 悠远 | |
9 | 教堂 | |
10 | 卧室 | |
11 | Live | |
Pitch(音调) | [0.5, 2],步长 0.1 | 默认值 = 1 |
EQ | Array(10),[-15,15],步长 1 | 默认值 = 0,分别代表 10 个频带,对应的中心频率分别为 31、62、125、250、500、1k、2k、4k、8k 和 16k |
- Reverb(混响) | Object | 步长均为 0.1 |
wetGain | Number | 湿信号增益。该参数的单位为分贝(dB),取值范围为 0 ~ 1,默认值为 0.0 |
dryGain | Number | 干信号增益。该参数的单位为分贝(dB),取值范围为 0 ~ 1,默认值为 1.0 |
damping | Number | 混响阻尼,用于设置混响的衰减程度,阻尼越大表示衰减越大。取值范围为 0 ~ 1,默认值为 1.0 |
decayTime | Number | 持续强度,用于设置混响的拖尾长度。该参数的单位为秒,取值范围为 0.1 ~ 20,默认值为 0.1 |
roomSize | Number | 房间大小,用于设置模拟的 房间 大小,房间越大表示混响越强。取值范围为 0.1 ~ 2,默认值为 0.1 |
preDelay | Number | 延迟长度。该参数的单位为秒,取值范围为 0 ~ 1,默认值为 0.0 |
- 注册
audio-effect-enabled
事件。 - 调用
enableAudioEffect
方法开启美声和变声功能,功能开启后无预设效果。 - 调用
setAudioEffect
设置美声和变声音效。
示例代码
使用 CDN 插件
JavaScript// 创建本端 stream 实例
rtc.localStream = NERTC.createStream({
uid: uid, // 本端的 uid
audio: true, // 是否从麦克风采集音频
microphoneId: microphoneId, // 麦克风设备 deviceId,通过 getMicrophones() 获取
video: true, // 是否从摄像头采集视频
cameraId: cameraId // 摄像头设备 deviceId,通过 getCameras() 获取
});
//localStream 初始化之后再进行注册
await rtc.localStream.init()
await rtc.localStream.publish()
const pluginOptions = {
key: 'AIAudioEffects', // 插件名
pluginUrl: '', // 插件 js 地址
wasmUrl: '', // 插件依赖的 wasm 文件地址
}
// 注册 plugin-load 事件,当插件初始化完成后回调 onPluginLoaded
rtc.localStream.on('plugin-load', onPluginLoaded);
// 插件注册失败时触发,event 结构:{key: 插件名,msg: 详细信息}
rtc.localStream.on('plugin-load-error', event); // 具体参考信息见上文配置步骤
// 注册 AI 音效插件
// 注意,自 v5.6.41 版本开始,如果使用 await rtc.localStream.registerPlugin() 方式注册,插件的事件绑定需要在调用 registerPlugin() 之前进行
rtc.localStream.registerPlugin(pluginOptions)
//'plugin-load'事件回调方法
function onPluginLoaded(name: string) {
if (name === 'AIAudioEffects') {
// 在此处可立即调用 enableAIDenoise() 或者美声变声
// 打开美声变声
rtc.localStream.enableAudioEffect()
}
}
//AI 降噪和美声变声同时开启,需要在'audio-effect-enabled'回调中调用 enableAIDenoise()
rtc.localStream.on('audio-effect-enabled', () => {
console.warn('AI 音效已开启');
// 设置音效
const reverb = {
wetGain: 0,
dryGain: 1,
damping: 1,
roomSize: 0.1,
decayTime: 0.1,
preDelay: 0,
};
//setAudioEffect() 必须在触发 'audio-effect-enabled' 事件后调用,否则不生效
rtc.localStream.setAudioEffect('Reverb', reverb);
//打开 AI 降噪
rtc.localStream.enableAIDenoise()
});
// 关闭 AI 降噪
rtc.localStream.disableAIDenoise();
// 关闭美声变声
rtc.localStream.disableAudioEffect();
// 销毁插件,销毁之后如果需要使用插件则需再次注册
rtc.localStream.unregisterPlugin(pluginKey);
使用 NPM 插件
JavaScriptimport NERTC from 'nertc-web-sdk';
import AIAudioEffects from 'nertc-web-sdk/NERTC_Web_SDK_AIAudioEffects'
// 创建本端 stream 实例
rtc.localStream = NERTC.createStream({
uid: uid, // 本端的 uid
audio: true, // 是否从麦克风采集音频
microphoneId: microphoneId, // 麦克风设备 deviceId,通过 getMicrophones() 获取
video: true, // 是否从摄像头采集视频
cameraId: cameraId // 摄像头设备 deviceId,通过 getCameras() 获取
});
//localStream 初始化之后再进行注册
await rtc.localStream.init()
await rtc.localStream.publish()
const pluginOptions = {
key: 'AIAudioEffects', // 插件名
pluginObj: AIAudioEffects, // AI 音效对象
wasmUrl: '', // 插件依赖的 wasm 文件地址
}
// 注册 plugin-load 事件,当插件初始化完成后回调 onPluginLoaded
rtc.localStream.on('plugin-load', onPluginLoaded);
// 插件注册失败时触发,event 结构:{key: 插件名,msg: 详细信息}
rtc.localStream.on('plugin-load-error', event); // 具体参考信息见上文配置步骤
// 注册 AI 音效插件
// 注意,自 v5.6.41 版本开始,如果使用 await rtc.localStream.registerPlugin() 方式注册,插件的事件绑定需要在调用 registerPlugin() 之前进行
rtc.localStream.registerPlugin(pluginOptions)
//'plugin-load'事件回调方法
function onPluginLoaded(name: string) {
if (name === 'AIAudioEffects') {
// 在此处可立即调用 enableAIDenoise() 或者美声变声
// 打开美声变声
rtc.localStream.enableAudioEffect()
}
}
//AI 降噪和美声变声同时开启,需要在'audio-effect-enabled'回调中调用 enableAIDenoise()
rtc.localStream.on('audio-effect-enabled', () => {
console.warn('AI 音效已开启');
// 设置音效
const reverb = {
wetGain: 0,
dryGain: 1,
damping: 1,
roomSize: 0.1,
decayTime: 0.1,
preDelay: 0,
};
//setAudioEffect() 必须在触发 'audio-effect-enabled' 事件后调用,否则不生效
rtc.localStream.setAudioEffect('Reverb', reverb);
//打开 AI 降噪
rtc.localStream.enableAIDenoise()
});
// 关闭 AI 降噪
rtc.localStream.disableAIDenoise();
// 关闭美声变声
rtc.localStream.disableAudioEffect();
// 销毁插件,销毁之后如果需要使用插件则需再次注册
rtc.localStream.unregisterPlugin(pluginKey);
远端流美声变声
注意事项
- 使用远端流美声变声之前,请确保您已经注册了 AI 音效插件。
- 远端流涉及到对
stream
订阅/取消订阅,播放/停止播放等的操作。这些操作会影响美声变声能力,您需要在业务层处理美声变声的开启。具体操作请参考下方示例代码。 - 本端流和远端流,建议开启的美声变声不超过 6 路。
示例代码
JavaScript//AI 音效插件配置,需要在 remoteStream.play() 完成后才能注册插件
const pluginOptions = {
key: 'AIAudioEffects', // 插件名
pluginUrl: '', // 插件 js 地址
wasmUrl: '', // 插件依赖的 wasm 文件地址
}
//在主动开启美声变声时,增加一个 flag 记录美声变声是否开启,此处用 audioEffectEnabled
$('#enableAudioEffect').on('click', () => {
remoteStream.enableAudioEffect()
remoteStream.audioEffectEnabled = true
})
//主动关闭美声变声时,将 audioEffectEnabled 置为 false
$('#disableAudioEffect').on('click', () => {
remoteStream.disableAudioEffect()
remoteStream.audioEffectEnabled = false
})
//触发 'stream-removed' 时,如果开启了美声变声,需要关闭美声变声
rtc.client.on('stream-removed', (evt) => {
var remoteStream = evt.stream
console.warn('收到别人停止发布的消息: ', remoteStream.streamID, 'mediaType: ', evt.mediaType)
//关闭 美声变声
if (remoteStream.audioEffectEnabled && evt.mediaType == 'audio') {
remoteStream.disableAudioEffect()
}
remoteStream.stop(evt.mediaType)
})
//触发 'stream-subscribed' 时,如果之前开启了美声变声,需要开启美声变声
rtc.client.on('stream-subscribed', (evt) => {
var remoteStream = evt.stream
console.warn('订阅别人的流成功的通知: ', remoteStream.streamID, 'mediaType: ', evt.mediaType)
await remoteStream.play(remoteDiv, playOptions);
console.log('播放对端的流成功', playOptions)
//这里注册 AI 音效插件
if (evt.mediaType == 'audio') {
const stream = remoteStream
stream.on('audio-effect-enabled', () => {
//这里可以设置一个默认变声
stream.setAudioEffect(0, 2)
})
stream.on('plugin-load', function () {
//插件注册成功后开启美声变声
stream.enableAudioEffect()
})
stream.on('plugin-load-error', (e) => {
console.error('plugin-load-error', e)
})
// 注册 AI 音效插件
// 注意,自 v5.6.41 版本开始,如果使用 await stream.registerPlugin() 方式注册,插件的事件绑定需要在调用 registerPlugin() 之前进行
stream.registerPlugin(pluginOptions)
}
//同一路流,在 'stream-removed' 后重新订阅,要重新开启 美声变声
if (remoteStream.audioEffectEnabled && evt.mediaType == 'audio') {
remoteStream.enableAudioEffect()
}
})
//取消订阅音频流(unsubConf.audio == false)时,如果开启了美声变声,需要关闭美声变声
const unsubConf = {}
const mediaType = 'audio'
unsubConf[mediaType] = true
rtc.client
.unsubscribe(remoteStream, unsubConf)
.then(() => {
console.log('取消订阅:' + mediaType)
//关闭变声
if (remoteStream.audioEffectEnabled && mediaType == 'audio') {
remoteStream.disableAudioEffect()
}
})
.catch((err) => {
console.error('取消订阅失败: ', mediaType, err)
})
//取消订阅远端流(即 unsubscribe 第二个参数为空)时,如果开启了美声变声,需要关闭美声变声
rtc.client.unsubscribe(remoteStream).then(() => {
//关闭美声变声
if (remoteStream.audioEffectEnabled && remoteStream.audio) {
remoteStream.disableAudioEffect()
}
})
//主动开始播放远端音频流时,如果之前开启了美声变声,需要再次开启美声变声
let mediaType = 'audio'
let stream = remoteStream
if (mediaType) { //有 playOptions 参数
const playOptions = {
audio: true,
}
await stream.play(remoteDiv, playOptions)
if (stream.audio && stream.audioEffectEnabled) {
stream.enableAudioEffect()
}
} else { //无 playOptions 参数
stream.play(remoteDiv)
if (stream.audioEffectEnabled) {
stream.enableAudioEffect()
}
}
//主动停止播放远端音频流时,如果之前开启了美声变声,需要关闭美声变声
let mediaType = 'audio'
let stream = remoteStream
if (mediaType) { //有 mediaType
stream.stop(mediaType)
if (mediaType == 'audio' && stream.audioEffectEnabled) {
stream.disableAudioEffect()
}
} else { //无 mediaType
stream.stop()
if (stream.audioEffectEnabled) {
stream.disableAudioEffect()
}
}