为降低开发者的集成难度,声网为 K 歌房场景提供了场景化 API。场景化 API 封装了声网音视频 SDK 的 API,并提供了 K 歌业务常见的功能,例如,对领唱和伴唱进行 NTP 时间同步。你只需要调用一个场景化 API 即可实现通过多个音视频 SDK 的 API 完成的复杂代码逻辑,从而更轻松实现 K 歌场景。声网在 GitHub 上提供 KTV 场景化 API 的源码文件 KTVApi.kt 和 KTVApiImpl.kt。
本文介绍如何使用 KTV 场景化 API 实现点歌、独唱、合唱等基础业务功能。
开始前,请确保你的开发环境满足以下条件:
Android Studio 4.0.0 或以上版本。
Android 4.1 或以上版本的设备。
有效的声网开发者账号。
有效的声网项目,获取项目的 App ID、RTC Token、RTM Token。
如果你的网络环境部署了防火墙,请参考应用企业防火墙限制以正常使用声网服务。
参考以下步骤来配置项目:
本节介绍如何实现点歌功能。点歌指用户通过浏览榜单或搜索关键词选定想唱的正版音乐,然后下载播放音乐。用户需要在唱歌前进行点歌。
下图展示点歌的 API 调用时序图:
调用 create
初始化 RtcEngine
。
请确保 RtcEngine
的生命周期大于 KTV API 模块的生命周期。
// 初始化 RtcEngine
val config = RtcEngineConfig()
config.mContext = context.getApplicationContext()
// 填入你项目的 App ID,可在声网控制台获取。
config.mAppId = "<Your_Agora_Appid>"
config.mEventHandler = object : IRtcEngineEventHandler() {}
config.mChannelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING
config.mAudioScenario = AUDIO_SCENARIO_CHORUS
val mRtcEngine = RtcEngine.create(config) as RtcEngineEx
调用 createKTVApi
创建 KTV API 实例,调用 initialize
初始化 KTV API 实例,然后调用 addEventHandler
注册 KTV API 事件。
// 创建 KTV API 实例
val ktvApiProtocol = createKTVApi()
// 初始化 KTV API 模块
ktvApiProtocol.initialize(KTVApiConfig(
// 你的 App ID。
"<Your Agora Appid>",
// RTM Token。
"<Your Agora Rtm Token>",
mRtcEngine,
// 需加入的频道 1 的名称。
"<Your Channel Name>",
// 用户 ID。
"<Your Uid>",
// 需加入的频道 2 的名称,详见合唱方案介绍。
"<Your Chorus Channel Name>",
// 根据频道 2 的名称和用户 ID 生成的 Token,用于加入频道 2 时进行鉴权。
"<Your Agora Chorus Token>")
// 设置可缓存的音乐资源数量,最多不能超过 50。
10,
// 设置 K 歌的场景。
KTVType.Normal,
// 音乐资源类型,默认为声网音乐内容中心提供的版权音乐。
KTVMusicType.SONG_CODE
)
// 更新数据流 ID。一个频道中最多只能创建 5 个数据流。
ktvApiProtocol.renewInnerDataStreamId();
// 注册 KTVAPI 事件。
ktvApiProtocol.addEventHandler(object: IKTVApiEventHandler() {
override fun onMusicPlayerStateChanged(state: MediaPlayerState, error: MediaPlayerError, isLocal: boolean) {
}
}
);
KTVApi
下的 getMusicContentCenter 获取音乐内容中心实例,再调用 KTVApi
下的 renewToken 来更新 Token。KTVApi
下的 renewToken 来更新 Token。IRtcEngineEventHandler
类下的 onTokenPrivilegeWillExpire 回调,你需要调用 IRtcEngine
下的 renewToken 来更新 Token。通过关键词搜索或音乐榜单获取歌曲列表。
// 用关键词搜索歌曲。
fun searchSong(condition: String, page: Int) {
val jsonOption = "{\"pitchType\":1,\"needLyric\":true}" // 搜索过滤条件。
ktvApiProtocol.searchMusicByKeyword(condition, page, 50, jsonOption) { requestId, status, page, pageSize, total, list ->
// 回调内直接处理异步调用结果。
}
}
// 获取音乐榜单。
fun fetchMusicCharts() {
ktvApiProtocol.fetchMusicCharts() { requestId, status, list ->
// 回调内直接处理异步调用结果。
}
}
// 通过榜单号获取歌曲列表。
fun searchSongWithRankingChartId(type: Int, page: Int) {
val jsonOption = "{\"pitchType\":1,\"needLyric\":true}" // 过滤条件
ktvApiProtocol.searchMusicByMusicChartId(type, page, 50, jsonOption) { requestId, status, page, pageSize, total, list ->
// 回调内直接处理异步调用结果
}
}
jsonOption
字段来筛选有副歌片段、支持打分的音乐资源。jsonOption
字段的具体说明见 searchMusicByKeyword 及 searchMusicByMusicChartId 的 API 文档。调用 loadMusic
加载歌曲。该方法中你需要传入歌曲编号并进行歌曲加载配置。歌曲加载结果会通过 IMusicLoadStateListener
接口类下的回调通知你。在调用 loadMusic
时,你需要传入下列参数:
songCode
:歌曲编号,可参考步骤 2获取。如果你需要播放歌曲的副歌片段,需要先调用 getInternalSongCode
方法为该片段创建一个编号,作为该片段的唯一标识。当你获取到该片段的编号后,调用 loadMusic
并将获取到的副歌片段编号传入 songCode
参数来加载该副歌片段。config
:歌曲加载配置,包含下列参数:autoPlay
:歌曲加载完成后是否自动播放true
:自动播放歌曲,此时用户角色会自动切换为独唱者。false
:不自动播放歌曲。歌曲加载成功后如果听众需要开始独唱或加入合唱,则需要在 onMusicLoadSuccess
回调内调用 switchSingerRole
切换为对应的角色然后调用 startSing
播放歌曲。mode
:歌曲加载的模式,默认为加载歌曲及歌词。mainSingerUid
:独唱者的用户 ID。IMusicLoadStateListener
:监听歌曲加载状态的接口类。// 示例代码为用户点歌后需要开始独唱的场景,你可以选择下列任意一个方案开始独唱。
// 方案1:autoPlay 设置为 true, 歌曲加载成功后会自动将用户角色切换为独唱者并开始播放歌曲。
// KTVLoadMusicMode.LOAD_MUSIC_AND_LRC 同时加载歌曲和歌词。
ktvApiProtocol.loadMusic(songCode, KTVLoadMusicConfiguration(true, mainSingerUid, KTVLoadMusicMode.LOAD_MUSIC_AND_LRC), object: IMusicLoadStateListener {
override fun onMusicLoadSuccess(songCode: Long, lyricUrl: String) {
// 加载成功。
}
override fun onMusicLoadFail(songCode: Long, reason: KTVLoadSongFailReason) {
// 加载失败。
}
override fun onMusicLoadProgress(songCode: Long, percent: Int, status: MusicLoadStatus, msg: String?, lyricUrl: String?) {
// 报告加载进度。
}
}
// 方案2:autoPlay 设置为 false 时, 歌曲加载成功后不会自动播放。
// KTVLoadMusicMode.LOAD_MUSIC_AND_LRC 同时加载音乐和歌词。
ktvApiProtocol.loadMusic(songCode, KTVLoadMusicConfiguration(true, mainSingerUid, KTVLoadMusicMode.LOAD_MUSIC_AND_LRC), object: IMusicLoadStateListener {
override fun onMusicLoadSuccess(songCode: Long, lyricUrl: String) {
// 歌曲加载成功后,调用 switchSingerRole 将用户角色设为独唱者。
ktvApiProtocol.switchSingerRole(SoloSinger)
// 开始唱歌。
ktvApiProtocol.startSing(songCode, 0)
}
override fun onMusicLoadFail(songCode: Long, reason: KTVLoadSongFailReason) {
// 加载失败。
}
override fun onMusicLoadProgress(songCode: Long, percent: Int, status: MusicLoadStatus, msg: String?, lyricUrl: String?) {
// 显示加载进度。
}
}
KTV API 初始化时默认用户角色为听众,如果需要开始独唱或加入合唱,需要调用 switchSingerRole
来切换至相应的角色。 KTV API 内部会根据角色的切换来控制演唱过程中音乐播放器的播放、同步,以及订阅和发布音频流的行为。你还可以通过 ISwitchRoleStateListener
接口类下的回调来获取切换的状态。
请参考下图来进行角色切换:
// 根据你的业务场景,将用户角色设为独唱、领唱、合唱、伴唱。
ktvApiProtocol.switchSingerRole(KTVSingRole.CoSinger, object: ISwitchRoleStateListener {
override fun onSwitchRoleSuccess() {}
override fun onSwitchRoleFail(reason: SwitchRoleFailReason) {}
}
歌曲播放时,音乐播放器会通过 onMusicPlayerStateChanged
回调向业务层通知歌曲播放状态改变。收到 onPlayerStateChanged(PLAYER_STATE_OPEN_COMPLETED)
回调后,你可以通过 seekSing
、pauseSing
、resumeSing
等方法控制播放器。
onMusicPlayerStateChanged
回调获取远端播放器的状态。// 跳转到指定时间播放歌曲。
ktvApiProtocol.seekSing(time)
退出 K 歌场景时,你需要调用 release
释放 KTV API 模块内的资源和取消注册事件回调。请确保 RtcEngine
的生命周期大于 KTV API 模块。释放资源时,请在释放 KTV API 模块之后再释放 RtcEngine
。
ktvApiProtocol.release()
本节介绍如何实现独唱功能。用户点歌后,可以开始独唱,K 歌房内的听众都可以听到其演唱。房间内想与独唱者连麦语聊的听众可以上麦。
独唱场景下存在两种角色:
下图展示独唱的 API 调用时序图:
调用 joinChannel
让独唱者加入频道。为保证高音质,声网推荐你在加入频道前调用 SetAudioProfile
将音频编码属性设为 MUSIC_HIGH_QUALITY
,将音频场景设为 AUDIO_SCENARIO_GAME_STREAMING
。
// 加入频道
mRtcEngine.joinChannel(
<Your_Rtc_Token>,
<Your_Channel_Name>,
<Your_Uid>,
// 媒体选项详见第 5 步操作
channelMediaOption
)
调用 loadMusic
加载歌曲。在调用该方法时,如果你将 autoPlay
设为 true
,歌曲加载完成后会自动播放,用户角色会自动设为独唱者。如果设置为 false
,则需调用 switchSingerRole
将用户角色设为独唱者(SoloSinger
),然后调用 startSing
才可以播放歌曲。
// 加载歌曲并设置自动播放
ktvApiProtocol.loadMusic(songCode, KTVLoadMusicConfiguration(true, "<MainSingerUid>", KTVLoadMusicMode.LOAD_MUSIC_AND_LRC), object: IMusicLoadStateListener {
// 加载成功。
override fun onMusicLoadSuccess(songCode: Long, lyricUrl: String) {}
// 加载失败。
override fun onMusicLoadFail(songCode: Long, reason: KTVLoadSongFailReason) {}
// 显示加载进度。
override fun onMusicLoadProgress(songCode: Long, percent: Int, status: MusicLoadStatus, msg: String?, lyricUrl: String?)
}
// 加载歌曲。
ktvApiProtocol.loadMusic(songCode, KTVLoadMusicConfiguration(false, "<MainSingerUid>", KTVLoadMusicMode.LOAD_MUSIC_AND_LRC), object: IMusicLoadStateListener {
override fun onMusicLoadSuccess(songCode: Long, lyricUrl: String) {
// 加载成功后,将用户角色设为独唱者。
ktvApiProtocol.switchSingerRole(SoloSinger)
// 开始播放。
ktvApiProtocol.startSing(songCode, 0)
}
override fun onMusicLoadFail(songCode: Long, reason: KTVLoadSongFailReason) {
// 加载失败。
}
override fun onMusicLoadProgress(songCode: Long, percent: Int, status: MusicLoadStatus, msg: String?, lyricUrl: String?) {
// 显示加载进度。
}
}
当歌曲播放完成或切歌后,你需要调用 switchSingerRole
将用户的角色切回听众。
ktvApiProtocol.switchSingerRole(KTVSingRole.Audience, null);
独唱者停止唱歌或希望暂时关闭麦克风时,可以调用 adjustRecordingSignalVolume
,将音频采集信号音量设置为 0。
mRtcEngine.adjustRecordingSignalVolume(0)
通过 updateChannelMediaOptions
方法在主播加入频道后更新频道媒体选项,例如是否开启本地音频采集,是否发布本地音频流等。
val channelMediaOption = ChannelMediaOptions()
// 发布本地麦克风流。
channelMediaOption.publishMicrophoneTrack = true
// 启用音频采集和播放。
channelMediaOption.enableAudioRecordingOrPlayout = true
// 设置角色为主播。
channelMediaOption.clientRoleType = CLIENT_ROLE_BROADCASTER
// 更新媒体选项。
mRtcEngine.updateChannelMediaOptions(channelMediaOption)
调用 joinChannel
让听众加入频道。为保证高音质,声网推荐你在加入频道前调用 SetAudioProfile
将音频编码属性设为 MUSIC_HIGH_QUALITY
,将音频场景设为 AUDIO_SCENARIO_GAME_STREAMING
。
// 加入频道。
mRtcEngine.joinChannel(
<Your_Rtc_Token>,
<Your_Channel_Name>,
<Your_Uid>,
// 媒体选项详见第 3 步操作。
channelMediaOption
)
调用 loadMusic
加载歌词。听众加入频道后,默认订阅独唱者发布的音频合流,即独唱者人声和音乐混合的音频流,因此观众仅需加载歌词。
// 将 autoPlay 设为 false。
// mainSingerUid 为独唱者的 UID。
// KTVLoadMusicMode.LOAD_LRC_ONLY 听众只需要加载歌词。
ktvApiProtocol.loadMusic(songCode, KTVLoadMusicConfiguration(false, mainSingerUid, KTVLoadMusicMode.LOAD_LRC_ONLY), object: IMusicLoadStateListener {
override fun onMusicLoadSuccess(songCode: Long, lyricUrl: String) {}
override fun onMusicLoadFail(songCode: Long, reason: KTVLoadSongFailReason) {}
override fun onMusicLoadProgress(songCode: Long, percent: Int, status: MusicLoadStatus, msg: String?, lyricUrl: String?) {}
}
通过 updateChannelMediaOptions
方法在听众加入频道后更新频道媒体选项,例如是否开启本地音频采集,是否发布本地音频流等。
听众的用户角色为 CLIENT_ROLE_AUDIENCE
,因此无法在频道内发布音频流。如果听众想上麦与演唱者语聊,需要将用户角色修改为 CLIENT_ROLE_BROADCASTER
。修改角色后,SDK 默认发布该连麦听众的音频流,独唱者和其他听众都能听到连麦听众的声音。
// 对需要上麦聊天的听众更新媒体选项。
val channelMediaOption = ChannelMediaOptions()
// 发布本地麦克风流。
channelMediaOption.publishMicrophoneTrack = true
// 启用音频采集和播放。
channelMediaOption.enableAudioRecordingOrPlayout = true
// 设置角色为主播。
channelMediaOption.clientRoleType = CLIENT_ROLE_BROADCASTER
// 更新媒体选项。
mRtcEngine.updateChannelMediaOptions(channelMediaOption)
// 对未上麦的听众更新媒体选项。
val channelMediaOption = ChannelMediaOptions()
// 不发布本地麦克风流。
channelMediaOption.publishMicrophoneTrack = false
// 启用音频采集和播放。
channelMediaOption.enableAudioRecordingOrPlayout = true
// 设置角色为观众。
channelMediaOption.clientRoleType = CLIENT_ROLE_AUDIENCE
// 更新媒体选项。
mRtcEngine.updateChannelMediaOptions(channelMediaOption)
本节介绍如何实现合唱功能。独唱者点歌开唱,伴唱加入后独唱者成为领唱,K 歌房内的听众都可以听到合唱。房间内想与领唱或伴唱连麦语聊的听众可以上麦。
合唱场景下存在四种角色:
下图展示合唱的 API 调用时序图:
调用 joinChannel
加入频道。为保证高音质,声网推荐你在加入频道前调用 SetAudioProfile
将音频编码属性设为 MUSIC_HIGH_QUALITY
,将音频场景设为 AUDIO_SCENARIO_GAME_STREAMING
。
// 加入频道。
mRtcEngine.joinChannel(
<Your_Rtc_Token>,
<Your_Channel_Name>,
<Your_Uid>,
// 媒体选项详见第 4 步操作。
channelMediaOption
)
调用 loadMusic
加载歌曲。在调用该方法时,如果你将 autoPlay
设为 true
,歌曲加载完成后会自动播放,用户角色会自动设为独唱者。如果设置为 false
,则需调用 switchSingerRole
将用户角色设为独唱(SoloSinger
),然后调用 startSing
才可以播放歌曲。
// 加载歌曲并设置自动播放后,用户角色自动设为独唱者。
ktvApiProtocol.loadMusic(songCode, KTVLoadMusicConfiguration(true, "<MainSingerUid>", KTVLoadMusicMode.LOAD_MUSIC_AND_LRC), object: IMusicLoadStateListener {
// 加载成功。
override fun onMusicLoadSuccess(songCode: Long, lyricUrl: String) {}
// 加载失败。
override fun onMusicLoadFail(songCode: Long, reason: KTVLoadSongFailReason) {}
// 报告加载进度。
override fun onMusicLoadProgress(songCode: Long, percent: Int, status: MusicLoadStatus, msg: String?, lyricUrl: String?)
}
// 加载歌曲。
ktvApiProtocol.loadMusic(songCode, KTVLoadMusicConfiguration(false, "<MainSingerUid>", KTVLoadMusicMode.LOAD_MUSIC_AND_LRC), object: IMusicLoadStateListener {
override fun onMusicLoadSuccess(songCode: Long, lyricUrl: String) {
// 加载成功后,将用户角色设为独唱者。
ktvApiProtocol.switchSingerRole(SoloSinger)
// 开始播放。
ktvApiProtocol.startSing(songCode, 0)
}
override fun onMusicLoadFail(songCode: Long, reason: KTVLoadSongFailReason) {
// 加载失败。
}
override fun onMusicLoadProgress(songCode: Long, percent: Int, status: MusicLoadStatus, msg: String?, lyricUrl: String?) {
// 报告加载进度。
}
}
有人加入合唱成为伴唱时,独唱者需将其用户角色切换为领唱;最后一个伴唱者退出合唱时,领唱需将其用户角色切回独唱者;歌曲结束后,需将用户角色切为听众。
// 听众加入合唱成为伴唱,独唱者切换角色为领唱。
ktvApiProtocol.switchSingerRole(KTVSingRole.LeadSinger, null);
// 最后一个伴唱退出合唱,领唱切换角色为独唱。
ktvApiProtocol.switchSingerRole(KTVSingRole.SoloSinger, null);
// 歌曲结束后,将角色切换为听众。
ktvApiProtocol.switchSingerRole(KTVSingRole.Audience, null);
通过 updateChannelMediaOptions
方法在加入频道后更新频道媒体选项,例如是否开启本地音频采集,是否发布本地音频流等。
val channelMediaOption = ChannelMediaOptions()
// 发布本地麦克风流。
channelMediaOption.publishMicrophoneTrack = true
// 启用音频采集和播放。
channelMediaOption.enableAudioRecordingOrPlayout = true
// 设置角色为主播。
channelMediaOption.clientRoleType = CLIENT_ROLE_BROADCASTER
// 更新媒体选项。
mRtcEngine.updateChannelMediaOptions(channelMediaOption)
调用 joinChannel
让伴唱加入频道。为保证高音质,声网推荐你在加入频道前调用 SetAudioProfile
将音频编码属性设为 MUSIC_HIGH_QUALITY
,将音频场景设为 AUDIO_SCENARIO_GAME_STREAMING
。
// 加入频道
mRtcEngine.joinChannel(
<Your_Rtc_Token>,
<Your_Channel_Name>,
<Your_Uid>,
// 媒体选项详见第 4 步操作
channelMediaOption
)
听众加入合唱成为伴唱前,需调用 loadMusic
加载歌曲。歌曲加载完成后,调用 switchSingerRole
将用户角色设为伴唱(CoSinger
)。
// 加载歌曲。
ktvApiProtocol.loadMusic(songCode, KTVLoadMusicConfiguration(false, "<MainSingerUid>", KTVLoadMusicMode.LOAD_MUSIC_ONLY), object: IMusicLoadStateListener {
// 歌曲加载成功。
override fun onMusicLoadSuccess(songCode: Long, lyricUrl: String) {
// 将用户角色切换为伴唱。
ktvApiProtocol.switchSingerRole(KTVSingRole.CoSinger, null)
}
// 歌曲加载失败。
override fun onMusicLoadFail(songCode: Long, reason: KTVLoadSongFailReason) {}
// 报告加载进度。
override fun onMusicLoadProgress(songCode: Long, percent: Int, status: MusicLoadStatus, msg: String?, lyricUrl: String?)
}
当歌曲结束或伴唱想要中途退出合唱时,调用 switchSingerRole
将用户角色切换为听众。
ktvApiProtocol.switchSingerRole(KTVSingRole.Audience, null);
通过 updateChannelMediaOptions
方法在伴唱加入频道后更新频道媒体选项,例如是否开启本地音频采集,是否发布本地音频流等。
val channelMediaOption = ChannelMediaOptions()
// 发布本地麦克风流。
channelMediaOption.publishMicrophoneTrack = true
// 启用音频采集和播放。
channelMediaOption.enableAudioRecordingOrPlayout = true
// 设置角色为主播。
channelMediaOption.clientRoleType = CLIENT_ROLE_BROADCASTER
// 更新媒体选项。
mRtcEngine.updateChannelMediaOptions(channelMediaOption)
调用 joinChannel
让听众加入频道,订阅音频流。为保证高音质,声网推荐你在加入频道前调用 SetAudioProfile
将音频编码属性设为 MUSIC_HIGH_QUALITY
,将音频场景设为 AUDIO_SCENARIO_GAME_STREAMING
。
// 加入频道。
mRtcEngine.joinChannel(
<Your_Rtc_Token>,
<Your_Channel_Name>,
<Your_Uid>,
// 媒体选项详见第 3 步操作
channelMediaOption
)
调用 loadMusic
加载歌词。听众加入频道后,默认订阅领唱人声和音乐混合的音频流,默认订阅伴唱人声。
// 听众角色需将 autoplay 设为 false。
// 听众角色仅需加载歌词。
ktvApiProtocol.loadMusic(songCode, KTVLoadMusicConfiguration(false, "<MainSingerUid>", KTVLoadMusicMode.LOAD_LRC_ONLY), object: IMusicLoadStateListener {
// 加载成功。
override fun onMusicLoadSuccess(songCode: Long, lyricUrl: String) {}
// 加载失败。
override fun onMusicLoadFail(songCode: Long, reason: KTVLoadSongFailReason) {}
// 报告加载进度。
override fun onMusicLoadProgress(songCode: Long, percent: Int, status: MusicLoadStatus, msg: String?, lyricUrl: String?)
}
通过 updateChannelMediaOptions
方法在听众加入频道后更新频道媒体选项,例如是否开启本地音频采集,是否发布本地音频流等。
听众的用户角色为 CLIENT_ROLE_AUDIENCE
,因此无法在频道内发布音频流。如果听众想上麦与演唱者语聊,需要将用户角色修改为 CLIENT_ROLE_BROADCASTER
。修改角色后,SDK 默认发布该连麦听众的音频流,领唱、伴唱、其他听众都能听到连麦听众的声音。
// 对需要上麦聊天的听众更新媒体选项。
val channelMediaOption = ChannelMediaOptions()
// 发布本地麦克风流。
channelMediaOption.publishMicrophoneTrack = true
// 启用音频采集和播放。
channelMediaOption.enableAudioRecordingOrPlayout = true
// 设置角色为主播。
channelMediaOption.clientRoleType = CLIENT_ROLE_BROADCASTER
// 更新媒体选项。
mRtcEngine.updateChannelMediaOptions(channelMediaOption)
// 对未上麦的听众更新媒体选项。
val channelMediaOption = ChannelMediaOptions()
// 不发布本地麦克风流。
channelMediaOption.publishMicrophoneTrack = false
// 启用音频采集和播放。
channelMediaOption.enableAudioRecordingOrPlayout = true
// 设置角色为观众。
channelMediaOption.clientRoleType = CLIENT_ROLE_AUDIENCE
// 更新媒体选项。
mRtcEngine.updateChannelMediaOptions(channelMediaOption)
声网基于独唱推出抢唱功能,本节介绍如何实现副歌片段抢唱功能。
默认由房主播放副歌片段(播放的实现逻辑同独唱),听众可以上麦进行抢唱,抢到麦后房主停止播放,抢到麦的人播放副歌片段并进行独唱,K 歌房内的听众都可以听到其演唱。
抢唱场景下存在两种角色:
下图展示抢唱的 API 调用时序图:
与独唱方案相比,抢唱方案中仅需在 KTVApiConfig
中将 KTVType
设为 SingBattle
(抢唱场景),独唱者实现和听众实现也仅在加载及播放这一步骤有差异。因此,你可以参考独唱方案来实现独唱者和听众逻辑。
在播放副歌片段之前,你需要先调用 getInternalSongCode
方法为该片段创建一个编号,作为该片段的唯一标识。当你获取到该片段的编号后,调用 loadMusic
并将获取到的副歌片段编号传入 songCode
参数来加载该副歌片段。
抢唱场景下的播放和演唱的音乐资源为副歌片段,你可以参考下列步骤来获取副歌片段的总分:
通过 onHighPartTime
回调获取副歌片段开始和结束时间。
调用歌词组件中的 parseLyricsData 方法解析歌词文件数据,获取歌词数据模型。
通过歌词的行数来计算副歌片段的总分,示例代码如下:
// 变量,用于保存副歌片段的总分
int totalScore = 0;
// 计数器,用于统计处于副歌片段开始和结束时间之间的歌词行数
AtomicInteger lineCount = new AtomicInteger();
// 遍历歌词数据模型中的每一行歌词,检查每行歌词是否处于副歌片段开始和结束时间的范围内
lyricsModel.lines.forEach(line -> {
if (line.getStartTime() >= highStartTime && line.getEndTime() <= highEndTime) {
// 计算出处于开始和结束时间之间的歌词行数
lineCount.getAndIncrement();
}
});
// 总分=行数*100
totalScore = lineCount.get() * 100;
本文集成步骤中使用如下 API: