实现独唱
更新时间: 2024/11/26 15:44:05
独唱是指麦位上的用户独自演唱,房间内的观众在线观看。
功能原理
独唱的原理图如下图所示。
NERTC SDK 将主唱的伴奏和干声传给 NERTC 服务器, NERTC 服务器将音频传给观众端。
主唱实现方案
-
主唱调用
applyOnSeat
申请上麦,成为连麦主播。fun requestSeat(callback: NECallback<AnyObject>) { roomContext?.seatController.submitSeatRequest { code, msg, _ in if code == 0 { NEKaraokeLog.successLog(kitTag, desc: "Successfully apply on seat.") } else { NEKaraokeLog.errorLog(kitTag, desc: "Failed to apply on seat. Code: \(code). Msg: \(msg ?? "")") } callback?(code, msg, nil) } }
-
麦位上的用户可以点歌,具体实现逻辑需要业务自行实现。
-
歌词展示与同步,具体实现逻辑需要业务自行实现。
-
主唱以主流方式发送伴奏,将伴奏和人声混流后的音频流推送到远端。
roomContext?.rtcController.setParameters(["key_audio_external_audio_mix": true]) roomContext?.rtcController.setParameters(["engine.audio.ktv.chrous": true])
-
主唱播放音乐
func playOrginalAndAccompany(_ roomContext: NERoomContext, _ orginalPath: String, _ accompanyPath: String, _ volume: Int, timestamp: Int64 = 0, type: NERoomAudioStreamType = .main, sendEnable:Bool = true) -> Int { roomContext.rtcController.stopAllEffects() // 原唱 let oOption = NERoomCreateAudioEffectOption() oOption.startTimeStamp = timestamp oOption.path = orginalPath oOption.playbackVolume = 0 oOption.sendVolume = 0 oOption.sendEnabled = sendEnable oOption.sendWithAudioType = type var code = roomContext.rtcController.playEffect(effectId: originalId, option: oOption) if code == 0 { // 伴奏 let aOption = NERoomCreateAudioEffectOption() aOption.startTimeStamp = timestamp aOption.path = accompanyPath aOption.playbackVolume = volume aOption.sendVolume = volume aOption.sendEnabled = sendEnable aOption.sendWithAudioType = type code = roomContext.rtcController.playEffect(effectId: accompanyId, option: aOption) } return code }
-
歌词同步。
主唱收到伴奏播放进度回调,并将自己的伴奏进度通过 SEI 发送出去。
self.playTimer = Timer.init(timeInterval: 0.1, repeats: true, block: { timer in let position = self.roomContext?.rtcController.getEffectCurrentPosition(effectId: self.isOriginal ? self.originalId : self.accompanyId) // 上报当前播放进度 if self.callback != nil && position != nil { self.callback!.onSongPlayPosition(position!) } // 发送SEI if let data = SEI(position ?? 0).toData() { self.roomContext?.rtcController.sendSEIMsg(data) } }) if self.playTimer != nil { RunLoop.current.add(self.playTimer!, forMode: .common) self.playTimer?.fire() }
-
主唱
leaveSeat
接口申请下麦。self.roomContext!.seatController.leaveSeat { code, msg, _ in if code == 0 { NEKaraokeLog.successLog(kitTag, desc: "Successfully leaveseat.") } else { NEKaraokeLog.errorLog(kitTag, desc: "Failed to leave seat. Code: \(code). Msg: \(msg ?? "")") } callback?(code, msg, nil) }
观众端实现方案
- 观众端调用
setAudioProfile
接口,设置音频profile
类型为HighQualityStereo
,设置scenario
为MUSIC
。 - 观众端同步本地歌词进度。
- 观众端监听
onRtcReciveSEIMessage
的 SEI 回调信息。 - 观众收到主唱发送的 SEI 消息,根据拿到的时间戳,解析歌词、展示时间戳对应时间段的歌词数据。
/// 接收到SEI消息 func onRtcReciveSEIMessage(_ userUuid: String, message: Data) { // String转字典 guard let jsonObjc = NEKaraokeDecoder.decode(message) else { return } guard let musicPosition = jsonObjc[SEI_KEY] as? UInt64 else { return } // 上报当前主唱的演唱进度 self.callback?.onSongPlayPosition(musicPosition) }
- 观众端监听
此文档是否对你有帮助?