跳到主要内容

混音

音视频 SDK 支持两种方式的混音,分别是从指定音频文件混音和用户传入音频数据混音。

  • 早于 5.1.11 版本的 SDK,因为底层逻辑用的是一个通道,所以不支持同时使用两种混音方式。
  • 5.1.11 及之后版本,支持两种方式同时混音。

前提条件

从网络音源混音的能力依赖 player 插件。SDK 需要使用以下插件将网络文件下载后播放。如有需要,请集成以下插件:

dependencies {
// x.y.z,请填写具体的 SDK 版本号,新集成用户建议使用 SDK 和插件的最新版。
...
implementation 'cn.rongcloud.sdk:player:x.y.z' // CDN 扩展库(可选)
...
}

从音频文件或网络音源混音

混音功能支持将用户自定义的音频数据、音频文件或网络音源与本地麦克风采集的音频数据进行混合。支持的用户自定义音频文件或网络音源格式有:MP3、AAC、M4A、WAV。

加入房间并发布默认资源成功后,调用 RCRTCAudioMixer.startMix 方法使用指定的音频文件混音,退出房间前需要调用 RCRTCAudioMixer.stop 结束混音。

String audioFile = "/sdcard/emulated/0/music.mp3";
RCRTCAudioMixer.getInstance().startMix(audioFile, RCRTCAudioMixer.Mode.MIX, true, -1);

// 调节混音音量(修改的是对端听到的声音音量)
RCRTCAudioMixer.getInstance().setMixingVolume(80);
// 调节本地播放音量(修改的是本端听到的声音音量)
RCRTCAudioMixer.getInstance().setPlaybackVolume(80);
// 获取混音文件播放总时长(ms),方法一
RCRTCAudioMixer.getInstance().getDurationMillis();
// 获取混音文件播放总时长(ms),方法二
RCRTCAudioMixer.getInstance().getDurationMillis(String path);
// 获取混音进度,例如 0.2 表示播放了 20%
RCRTCAudioMixer.getInstance().getCurrentPosition();
// 调节混音进度,例如 0.2 表示调节至 20% 处开始播放
RCRTCAudioMixer.getInstance().seekTo(float position);
// 暂停混音
RCRTCAudioMixer.getInstance().pause();
// 继续混音
RCRTCAudioMixer.getInstance().resume();
// 停止混音
RCRTCAudioMixer.getInstance().stop();
提示
  • 调用之前应用必须已经授予 <uses-permission android: name="android.permission.READ_EXTERNAL_STORAGE" /> 权限。
  • 如果 Android 10 手机上授予了权限后也出现了混音失败,请参考知识库 为什么 Android 10 无法使用 startMix 进行混音?
  • 从 5.2.5.4 开始,SDK 支持先设置播放位置(seekTo),再调用开始混音(startMix)。

在混音开始前后均可以设置播放位置。如果希望从混音文件指定位置开始混音,建议先设置播放位置,再调用开始混音。

参数类型说明
pathString文件的绝对路径,如 /sdcard/emulated/0/music.mp3,或者是 assets 文件,格式如 file:///android_asset/music.mp3;如果是网络音源,则填音源地址。
modeRCRTCAudioMixer.Mode混音模式,Mode.MIX: 将音频文件的音频数据与麦克风采集的数据混音发送至对端,Mode.REPLACE: 将麦克风采集的数据替换为音频文件的音频数据发送至对端,Mode.NONE: 不做任何操作,对端仅听到本地麦克风发送的声音
playBackboolean是否在本地播放混音音频文件
loopCountintloopCount > 0 : 循环混音 loopCount 次;loopCount = -1 : 无限循环;其他取值:混音一次

从音频数据混音

加入房间并发布默认资源成功后首先调用 RCRTCAudioMixer.getInstance().startWrite(),再调用 RCRTCAudioMixer.write 方法混音原始音频数据,取消发布音频资源或离开房间后需要调用 RCRTCAudioMixer.getInstance().stopWrite() 方法停止混音。

  • 示例代码:

    // 循环写入音频数据
    while (keepAlive) {
    RCRTCAudioMixer.getInstance().write(pcmData, 48000, 2, AudioFormat.ENCODING_PCM_16BIT, RCRTCAudioMixer.Mode.MIX);
    }
    // 结束时需要调用 stop 停止混音
    RCRTCAudioMixer.getInstance().stop();

混音设置声道

采用上述方式混音时,还可以调用 setAudioDualMonoMode 单独选择混音的左右声道。例如,您可以通过左右声道切换实现原唱、伴唱切换,以满足卡拉 OK 场景下的需求(通过声道切换原唱、伴唱要求音源支持,即原唱、伴唱音轨分别位于两个独立声道)。

此接口默认左右声道同时混,设置即时生效。

  • 示例代码:

    // 当左声道为伴奏音轨,按如下方式调用即可开启卡拉 OK 模式
    RCRTCAudioMixer.getInstance().setAudioDualMonoMode(AudioDualMonoMode.AUDIO_DUAL_MONO_L);

设置混音状态监听

开始混音、暂停/继续混音、结束混音、混音文件已自动混流完成、实时混音进度等状态监听。

RCRTCAudioMixer.getInstance().setAudioMixingStateChangeListener(new RCRTCAudioMixingStateChangeListener() {
@Override
public void onMixEnd() {
// 此方法从 5.1.4 版本开始废弃
}

@Override
public void onStateChanged(MixingState state) {
// 此方法从 5.1.4 版本开始废弃
}
/**
* Added from 5.1.4
* 混音状态变化
*
* @param state 变更后的状态
* @param reason 状态变更的原因
*/
@Override
public void onStateChanged(MixingState state, MixingStateReason reason) {
if (state == MixingState.STOPPED){
// 混音完成,可能的原因有:
if (reason == MixingStateReason.ALL_LOOPS_COMPLETED){
// 调用startMix方法时,传入的loopCount > 0,并且loopCount次数的混音已经完成
}else if (reason == MixingStateReason.ONE_LOOP_COMPLETED){
// 调用startMix方法时,传入的loopCount < 0(无限循环)或 > 1,混音完成一次。接下来会继续自动开始下一次混音。
}else if (reason == MixingStateReason.STOPPED_BY_USER){
// 调用stopMix方法停止混音
}
} else if (state == MixingState.PLAY){
// 开始混音,可能的原因有:
if (reason == MixingStateReason.STARTED_BY_USER){
// 调用了 startMix 方法开始混音
}else if (reason == MixingStateReason.START_NEW_LOOP){
// 调用了 startMix 且传入的 loopCount < 0(无限循环)或 > 1 时,自动开始下一次混音。
}else if (reason == MixingStateReason.RESUMED_BY_USER){
// 调用了 resume方法继续开始混音
}else if (reason == MixingStateReason.FILE_LOAD_FINISHED){
// 本地或网络混音文件已加载完成(SDK 必须等待资源加载完成后才能播放混音文件),该回调要求 SDK 版本 ≧ 5.2.5.4。
}
} else if (state == MixingState.PAUSED){
// 暂停混音,reason 为 MixingStateReason.PAUSED_BY_USER
}
}

/**
* Added from 5.1.4
* 混音播放进度,默认 200 毫秒回调一次
* @param progress 播放进度 [0,1]
*/
@Override
public void onReportPlayingProgress(final float progress) {
// 非UI线程,更新UI需要切换线程
}
});

获取混音后的音频数据

通过注册监听 RCRTCEngine.getInstance().getDefaultAudioStream().setMixedAudioDataListener 获取本地混音后的 PCM 音频流数据。

  • 参数说明:

    参数类型说明
    ListenerIRCRTCAudioDataListener本地混音后的 PCM 数据采集回调
  • 回调参数:

    回调参数回调类型说明
    rtcAudioFrameRCRTCAudioFrame混音后的音频 PCM 数据对象
  • 示例代码:

    RCRTCEngine.getInstance().getDefaultAudioStream().setMixedAudioDataListener(new IRCRTCAudioDataListener() {
    @Override
    public byte[] onAudioFrame(RCRTCAudioFrame rcrtcAudioFrame) {
    return rcrtcAudioFrame.getBytes();
    }
    });