音乐混音
对于互动娱乐等类型的场景来说,除了正常的对话交流,有时候还需要在房间中播放一些背景音乐和音效以实现类似 KTV 的效果。对于这个需求,SDK 提供了 音乐混音
这个方案。通过 SDK 提供的混音模块,开发者可以很方便地将采集到的人声与背景音乐或者音效混合。
注意!使用和调试混音模块时,请佩戴耳机,防止外放的音乐被麦克风重复录入而导致被回声消除。
创建一个混音模块
在 SDK 的设计中,一个混音模块,主要由 3 个部分构成:
- 输入:通常是包含人声的媒体对象
- 各种外部音源,包括背景音乐和音效
- 输出:将输入和外部音源混音后输出的媒体对象
这里我们只需要提供用于输入的媒体对象就可以创建一个混音模块了:
import * as QNRTC from "pili-rtc-web";
// 获取用于输入的人声媒体对象
const stream = await QNRTC.deviceManager.getLocalStream({
auidio: { enabled: true },
video: { enabled: true },
});
// 创建混音模块的函数被封装在 AudioUtils 下
const AudioUtils = QNRTC.AudioUtils;
// 传入刚刚采集到的人声媒体对象,创建一个混音模块
const mixingManager = AudioUtils.createAudioMixingManagerFromStream(stream);
代码最后的 mixingManager
就是我们创建好的混音模块,关于 AudioUtils 的细节可以点击蓝字查看其 API 文档。Stream 模式下混音模块的类型是 StreamMixingManager,详细也可以参考其 API 文档。
使用混音模块
就像上文说的,每一个混音模块对象有其对应的输入
与输出
,输入就是刚刚传入的人声媒体对象,输出就是混音输出后的媒体对象。分别可以通过以下方式访问:
// 混音的输入
const inputTrack = mixingManager.input;
// 混音的输出
const outputTrack = mixingManager.outputStream;
如果目前同时播放这 2 个 Stream 的话,其实它们是完全一致的,因为我们还没有添加任何外部音源到这个混音模块中,下面我们将演示如何添加背景音乐和音效。
使用背景音乐
通过如下代码使用背景音乐混音:
// 配置背景音乐混音
mixingManager.musicManager.setMusicOption({
loop: true, // 设置循环播放
playbackVolume: 1, // 设置本地播放音量,1 代表原始音量
remoteVolume: 0.4, // 设置远端播放音量
});
// 开始背景音乐混音
await mixingManager.musicManager.startMusicMixing("http://pkeamo5ex.bkt.clouddn.com/alice.mp3");
// 暂停背景音乐混音
mixingManager.musicManager.pauseMusicMixing();
// 恢复背景音乐混音
mixingManager.musicManager.resumeMusicMixing();
// 停止背景音乐混音
mixingManager.musicManager.stopMusicMixing();
其中开始背景音乐混音的参数除了像示例中支持 在线音频地址 以外,还支持传入 本地文件 或者 音频 Buffer。关于如何获取本地文件对象,可以参考 外部音频导入 中的代码。
除了基本的播放/暂停/循环以外,SDK 还提供了背景音乐时长控制相关的接口:
// 获取当前的播放时间
const currentTime = mixingManager.musicManager.getMusicCurrentTime();
// 获取当前背景音乐的时长
const duration = mixingManager.musicManager.getMusicDuration();
// 设置当前背景音乐的播放时间
mixingManager.musicManager.setMusicCurrentTime(60);
其中需要注意的是 getMusicDuration 这个接口,如果是在线的背景音乐,获取时长可能会有些延迟(网络原因)。具体可以点进蓝字里看 API 文档里的详细说明。
最后,很多场景下需要能跟踪当前背景音乐的播放状态以在 UI 层做一些展示(比如在线音频正在加载)。SDK 也提供了相应的事件来帮助您实现这个需求,详细可以参见 API 文档中的 music-state-change:
mixingManager.musicManager.on("music-state-change", (curr, last) => {
if (curr === "loading") {
console.log("now loading!");
}
})
关于背景音乐详细的 API 说明可以参考 AudioMusicManager
使用音效
相对于背景音乐,音效不会有暂停恢复跳转这些播放流程控制的 API,而是增加了多音源管理方面的方法。在大部分场景中,背景音乐一般只有一个而音效却有很多个,所以在音效的管理上我们引入了 key
这个概念,具体可以参考下面的代码:
// 添加一个音效
// 第一个参数和背景音乐一样,支持 在线音频地址、本地音乐文件、音频 Buffer
// 第二个参数指这个音频的 key ,每个音效在添加时需要指定一个 key
await mixingManager.effectManager.addEffectSource(
"http://pkeamo5ex.bkt.clouddn.com/drum.mp3",
"drum",
);
// 传入之前指定的 key ,播放指定音效
// 第二个参数是指播放的音量,1 代表原始音量
mixingManager.effectManager.playEffect("drum", 1.3);
// 删除指定的音效
mixingManager.removeEffectSource("drum");
// 已经添加的音效列表
const myEffectList = mixingManager.effectList;
关于音效详细的 API 说明可以参考 AudioEffectManager
配置返音(本地播放)
为了上层控制的灵活性,输入音源(一般是人声)、背景音乐以及音效的返听都有独立接口来控制。默认情况下,背景音乐和音效的返听默认开启,输入音源的返听默认关闭。也就是开启混音后本地默认能听到背景音乐但是听不见原始的输入音源(人声)。
下面的代码展示了如何开启输入音源(人声)的返听
// 打开输入音源的返听
mixingManager.setSourcePlaybackState(true);
详细的配置 API 可以参考 StreamMixingManager