在线 K 歌
实现独唱
更新时间: 2022/11/11 17:57:26
独唱是指麦位上的用户独自演唱,房间内的观众在线观看。
功能原理
独唱的原理图如下图所示。
NERTC SDK 将主唱的伴奏和干声传给 NERTC 服务器, NERTC 服务器将音频传给观众端。
前提条件
主唱实现方案
-
主唱调用
setAudioProfile
接口,设置音频profile
类型为HighQualityStereo
,设置scenario
为MUSIC
。 -
主唱申请上麦,成为连麦主播。具体实现方式请参见 IM 的聊天室队列。
-
麦位上的用户可以点歌,具体实现逻辑需要业务自行实现。
-
歌词展示与同步,具体实现逻辑需要业务自行实现。
-
主唱和合唱者在开始合唱前,调用如下代码开启 AEC 伴奏模式。
开启 AEC 伴奏模式时,本端的人声保留比较好,有助于演唱者的唱歌体验。
NERtcParameters mRtcParameters = new NERtcParameters(); NERtcParameters.Key audioMixKey = NERtcParameters.Key.createSpecializedKey("key_audio_external_audio_mix"); mRtcParameters.set(audioMixKey, true); NERtcEx.getInstance().setParameters(mRtcParameters); //先设置参数,后初始化
-
主唱以主流方式发送伴奏,将伴奏和人声混流后的音频流推送到远端。
收到歌曲开始消息后,开始 3 秒倒计时,3 秒后开始播放伴奏。
long position = System.currentTimeMillis() + 3 * 1000; NERtcCreateAudioEffectOption optPure = new NERtcCreateAudioEffectOption(); optPure.path = 纯伴奏音乐路径 optPure.loopCount = 1; optPure.sendEnabled = true; optPure.sendVolume = 发送音量; //如果当前放纯伴奏音乐,将带原唱的伴奏发送音量设成0 optPure.playbackVolume = 播放音量; //如果当前放纯伴奏音乐,将带原唱的播放音量设成0 optPure.sendWithAudioType = NERtcAudioStreamType.kNERtcAudioStreamTypeMain; //伴奏以主流方式发送 optPure.startTimestamp = position; NERtcEx.getInstance().playEffect(optPureEffectId, optPure); //optPureEffectId 自己定义的 effect id NERtcCreateAudioEffectOption optOriginalSong = new NERtcCreateAudioEffectOption(); optOriginalSong.path = 带原声音乐路径 optOriginalSong.loopCount = 1; optOriginalSong.sendEnabled = true; optOriginalSong.sendVolume = 0; //如果当前播放纯伴奏,将带原唱的伴奏发送音量设置成0 optOriginalSong.playbackVolume = 0; //如果当前播放纯伴奏音乐,将带原唱的播放音量设置成0 optOriginalSong.sendWithAudioType = NERtcAudioStreamType.kNERtcAudioStreamTypeMain; //伴奏以主流的方式发送 optOriginalSong.startTimestamp = position; NERtcEx.getInstance().playEffect(optOriginalEffectId, optOriginalSong); //自己定义的effect id
-
歌词同步。
主唱收到伴奏播放进度回调,并将自己的伴奏进度通过 SEI 发送出去。
@Override public void updateAudioEffectTimestamp(long effectId, long timestampMs) { //纯伴奏和带原唱的伴奏,两个进度是一样的,歌词进度只需要根据其中的一个伴奏进行同步 if(effectId != optOriginalEffectId) { return ; } JSONObject jsonObject = new JSONObject(); try { jsonObject.put("audio_effect_pos", timestampMs); } catch (JSONException e) { e.printStackTrace(); } NERtcEx.getInstance().sendSEIMsg(jsonObject.toString()); dataSource.pickService.musicPostion = timestampMs; //同步本地歌词进度 }
-
主唱申请下麦。具体实现方式请参见IM 的聊天室队列。
观众端实现方案
观众端通过以下方法同步本地歌词进度。
- 观众端监听
onNERtcEngineRecvSEIMsg
的 SEI 回调信息。 - 观众收到主唱发送的 SEI 消息,根据拿到的时间戳,解析歌词、展示时间戳对应时间段的歌词数据。
@Override
public void onRecvSEIMsg(long l, String s) {
long musicPosition = -1;
try {
JSONObject data = new JSONObject(s);
musicPosition = Integer.parseInt(data.getString("audio_effect_pos"));
} catch (Exception e) {
e.printStackTrace();
}
if(musicPosition == -1) {
Log.i(TAG, "Error decode SEI message");
return ;
}
dataSource.pickService.musicPosition = musicPosition;
}
进阶功能
静音和取消静音
建议通过以下方式静音和取消静音,以免损耗性能。该设置只影响麦克风采集音量,不影响发送的伴奏音量。
//mute
NERtcEx.getInstance().adjustRecordingSignalVolume(0);
//unmute
NERtcEx.getInstance().adjustPlaybackSignalVolume(100);
切换原唱和伴奏
实现切换播放原唱的示例代码如下:
//将带原唱的伴奏音量调整到正常,并将纯伴奏的伴奏音量调整成 0
NERtcEx.getInstance().setEffectSendVolume(optPureEffectId, 0);
NERtcEx.getInstance().setEffectPlaybackVolume(optPureEffectId, 0);
NERtcEx.getInstance().setEffectSendVolume(optOriginalEffectId, audioEffectVolume);
NERtcEx.getInstance().setEffectPlaybackVolume(optOriginalEffectId, audioEffectVolume);
实现切换为播放伴奏的示例代码如下:
//将带原唱的伴奏音量调整成 0,并将纯伴奏的伴奏音量调整成正常
NERtcEx.getInstance().setEffectSendVolume(optPureEffectId, audioEffectVolume);
NERtcEx.getInstance().setEffectPlaybackVolume(optPureEffectId, audioEffectVolume);
NERtcEx.getInstance().setEffectSendVolume(optOriginalEffectId, 0);
NERtcEx.getInstance().setEffectPlaybackVolume(optOriginalEffectId, 0);
此文档是否对你有帮助?
有帮助
我要吐槽