合唱

  • Android

更新时间不可用

了解场景化 API 方案在不同平台上的合唱方式,包括接入流程、关键配置和平台差异。

本文介绍如何实现合唱。在此之前,请确保你已参考实现文档集成 KTV API。

方案介绍

合唱场景下存在三种角色:

  • 主唱:在没有伴唱加入、伴唱中途退出后,演唱的人的用户角色为独唱者。独唱者开始唱歌后,如有人加入合唱,独唱则成为合唱中主唱。主唱需要加入主频道,加载并播放歌曲,发布麦克风采集的音频流。此外,主唱还需要加入合唱子频道将人声同步给伴唱。KTV API 模块内部控制音乐播放器播放音乐,同步主唱的音乐播放进度,让歌词组件进入歌词滚动状态等逻辑。
  • 伴唱:独唱者开始唱歌后,如有人加入合唱,则其成为合唱中的伴唱。伴唱需要加入合唱子频道,加载并播放歌曲,发布麦克风采集的音频流。KTV API 模块内部控制音乐播放器播放音乐,同步主唱的音乐播放进度,让歌词组件进入歌词滚动状态等逻辑。
  • 听众:加入主频道,加载歌词。KTV API 模块内部控制听众订阅主唱的人声和音乐的音频合流,订阅伴唱的人声,同步主唱的音乐播放进度,让歌词组件进入歌词滚动状态等逻辑。如果普通听众需要上麦聊天,可以更新媒体选项。

下图为合唱方案的技术原理图:

主唱实现

1. 加入频道

调用 joinChannel 加入频道。为保证高音质,声网推荐你在加入频道前调用 setAudioProfile 将音频编码属性设为 MUSIC_HIGH_QUALITY,将音频场景设为 AUDIO_SCENARIO_GAME_STREAMING。

Kotlin
// 加入频道
mRtcEngine.joinChannel(
    <Your_Rtc_Token>,
    <Your_Channel_Name>,
    <Your_Uid>,
    // 媒体选项详见第 4 步操作
    channelMediaOption
)

信息

为同步频道内的歌词进度等状态信息,你需要在成功加入频道后调用 renewInnerDataStreamId 来创建数据流通道。如果退出频道后再次加入频道,你需要在加入频道成功后重新调用该方法来创建数据流通道。一个频道中最多只能创建 5 个数据流通道。

2. 加载及播放歌曲

调用 loadMusic 加载歌曲。在调用该方法后需调用 switchSingerRole 将用户角色设为独唱(SoloSinger),然后调用 startSing 才可以播放歌曲。

注意

如需加载声网提供的版权音乐,请参考获取版权音乐。

Kotlin

// 加载歌曲
ktvApiProtocol.loadMusic(
    songCode,
    KTVLoadMusicConfiguration("<SongId>", "<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?) {}
    }
)

3. 切换角色

有人加入合唱成为伴唱时,独唱者需将其用户角色切换为主唱;最后一个伴唱者退出合唱时,主唱需将其用户角色切回独唱者;歌曲结束后,需将用户角色切为听众。

Kotlin

// 听众加入合唱成为伴唱,独唱者切换角色为主唱
ktvApiProtocol.switchSingerRole(KTVSingRole.LeadSinger, null);
// 最后一个伴唱退出合唱,主唱切换角色为独唱
ktvApiProtocol.switchSingerRole(KTVSingRole.SoloSinger, null);
// 歌曲结束后,将角色切换为听众
ktvApiProtocol.switchSingerRole(KTVSingRole.Audience, null);

4. 根据角色更新媒体选项

通过 updateChannelMediaOptions 方法在加入频道后更新频道媒体选项,例如是否开启本地音频采集,是否发布本地音频流等。

Kotlin
val channelMediaOption = ChannelMediaOptions()
// 发布本地麦克风流
channelMediaOption.publishMicrophoneTrack = true
// 启用音频采集和播放
channelMediaOption.enableAudioRecordingOrPlayout = true
// 设置角色为主播
channelMediaOption.clientRoleType = CLIENT_ROLE_BROADCASTER
// 更新媒体选项
mRtcEngine.updateChannelMediaOptions(channelMediaOption)

伴唱实现

1. 加入频道

调用 joinChannel 让伴唱加入频道。为保证高音质,声网推荐你在加入频道前调用 setAudioProfile 将音频编码属性设为 MUSIC_HIGH_QUALITY,将音频场景设为 AUDIO_SCENARIO_GAME_STREAMING。

Kotlin
// 加入频道
mRtcEngine.joinChannel(
    <Your_Rtc_Token>,
    <Your_Channel_Name>,
    <Your_Uid>,
    // 媒体选项详见第 4 步操作
    channelMediaOption
)

2. 加载歌曲

听众加入合唱成为伴唱前,需调用 loadMusic 加载歌曲。歌曲加载完成后,调用 switchSingerRole 将用户角色设为伴唱(CoSinger)。

Kotlin

// 加载歌曲
ktvApiProtocol.loadMusic(songCode, KTVLoadMusicConfiguration("<SongId>", "<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?)
})

3. 切换角色

当歌曲结束或伴唱想要中途退出合唱时,调用 switchSingerRole 将用户角色切换为听众。

Kotlin
ktvApiProtocol.switchSingerRole(KTVSingRole.Audience, null);

4. 根据角色更新媒体选项

通过 updateChannelMediaOptions 方法在伴唱加入频道后更新频道媒体选项,例如是否开启本地音频采集,是否发布本地音频流等。

Kotlin
val channelMediaOption = ChannelMediaOptions()
// 发布本地麦克风流
channelMediaOption.publishMicrophoneTrack = true
// 启用音频采集和播放
channelMediaOption.enableAudioRecordingOrPlayout = true
// 设置角色为主播
channelMediaOption.clientRoleType = CLIENT_ROLE_BROADCASTER
// 更新媒体选项
mRtcEngine.updateChannelMediaOptions(channelMediaOption)

听众实现

1. 加入频道

调用 joinChannel 让听众加入频道,订阅音频流。为保证高音质,声网推荐你在加入频道前调用 setAudioProfile 将音频编码属性设为 MUSIC_HIGH_QUALITY,将音频场景设为 AUDIO_SCENARIO_GAME_STREAMING。

Kotlin
// 加入频道
mRtcEngine.joinChannel(
    <Your_Rtc_Token>,
    <Your_Channel_Name>,
    <Your_Uid>,
    // 媒体选项详见第 3 步操作
    channelMediaOption
)

2. 加载歌词

调用 loadMusic 加载歌词。听众加入频道后,默认订阅主唱人声和音乐混合的音频流,默认订阅伴唱人声。

Kotlin
// 听众角色仅需加载歌词
ktvApiProtocol.loadMusic(songCode, KTVLoadMusicConfiguration("<SongId>", "<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?)
})

3. 根据角色更新媒体选项

通过 updateChannelMediaOptions 方法在听众加入频道后更新频道媒体选项,例如是否开启本地音频采集,是否发布本地音频流等。

听众的用户角色为 CLIENT_ROLE_AUDIENCE,因此无法在频道内发布音频流。如果听众想上麦与演唱者语聊,需要将用户角色修改为 CLIENT_ROLE_BROADCASTER。修改角色后,SDK 默认发布该连麦听众的音频流,主唱、伴唱、其他听众都能听到连麦听众的声音。

Kotlin
// 对需要上麦聊天的听众更新媒体选项
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)

下图展示合唱的 API 调用时序图:

API 参考

本文集成步骤中使用如下 API:

相关文档