一、功能概览
·多端人声和音乐同步对齐: 基于 NTP 时间戳对齐技术,确保跨设备间人声与伴奏的精准同步,有效解决网络抖动带来的音画不同步问题。
·实时打分与音准曲线:曲库歌曲可实时展示标准音高与用户个人音准曲线,唱歌得分同步广播给全房观众;本地导入歌曲暂不支持打分和音准显示。
·毫秒级歌词滚动:支持 VTT、LRC 格式歌词,随音乐进度精准滚动。
·多样化音乐源支持: 全面支持在线曲库点播与本地音乐(MP3/M4A)上传和播放。
三、步骤1:开通服务
参考 开通服务 文档开通「体验版」或「大规模直播版」套餐。
四、步骤2:代码集成
参考 准备工作 接入 TUILiveKit。
六、布局选择与接入
我们提供了两种不同交互的布局模式,你可以根据直播间的业务侧重点(例如:专业 K 歌房、社交娱乐房)选择最合适的集成方案。
标准 KTV 模式悬浮球模式 KTV 接入该模式主要通过 KaraokeControlView 实现,视图通常固定置于房间顶部。它提供了完整的歌词滚动、音高曲线评分以及播放控制功能。你可以根据业务需求,通过 XML 声明或代码动态构建的方式将该组件集成到应用中。方式1:通过 XML 布局文件集成(推荐)适用于 UI 布局相对固定的场景。通过在布局 XML 中直接定义,可以精确控制其在房间顶部的层次关系。<io.trtc.tuikit.atomicx.karaoke.view.KaraokeControlView android:id="@+id/karaoke_control_view" android:layout_width="match_parent" android:layout_height="170dp" android:layout_marginTop="10dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" />方式2:通过代码动态构建对于使用 Kotlin 语言开发的工程,集成逻辑如下。import android.view.ViewGroupimport io.trtc.tuikit.atomicx.karaoke.view.KaraokeControlViewfun initKaraokeView(container: ViewGroup, roomId: String, isOwner: Boolean) { // 1. 实例化组件 val karaokeView = KaraokeControlView(context) // 3. 设置布局参数并添加到容器 // 标准模式通常占据屏幕顶部固定高度 val layoutParams = ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, 500 // 对应高度约 170dp ) container.addView(karaokeView, layoutParams)}该模式主要通过 KaraokeFloatingView 实现,支持手动拖拽。提供了歌词滚动、音准打分曲线及播放控制功能。你可以根据业务需求,通过 XML 声明或代码动态构建的方式将该组件集成到应用中。方式1:通过 XML 布局文件集成这是最推荐的集成方式,适用于布局相对固定的场景。通过在布局 XML 中直接定义,可以方便地配合 ConstraintLayout 等容器进行 UI 适配。<io.trtc.tuikit.atomicx.karaoke.view.KaraokeFloatingView android:id="@+id/karaoke_floating_view" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" />方式2:通过代码动态构建对于使用 Kotlin 语言开发的工程,集成逻辑如下。我们建议将 KaraokeFloatingView 添加到页面的根布局中,以确保其悬浮层级。import android.view.ViewGroupimport android.widget.FrameLayoutimport io.trtc.tuikit.atomicx.karaoke.view.KaraokeFloatingViewfun setupKaraokeFloatingView(container: ViewGroup, roomId: String, isOwner: Boolean) { // 1. 实例化组件 val floatingView = KaraokeFloatingView(context) // 2. 将组件挂载到父容器并设置悬浮模式 // FloatingMode.RIGHT_HALF_MOVE 表示允许在屏幕右侧半屏区域内上下拖动 floatingView.attachAsFloating(container, KaraokeFloatingView.FloatingMode.RIGHT_HALF_MOVE)}
七、添加音乐
Karaoke 组件提供了灵活的数据源适配机制,支持集成本地音乐资源或商业版权曲库。你可以通过继承 MusicSourceService 类来实现不同场景下的音乐加载逻辑。
场景一:添加本地音乐
若你希望播放应用内置或本地沙盒中的音乐文件,请在你的工程中新建 KaraokeLocalSource.kt 文件。该类继承自 MusicSourceService 基类。在本地音乐模式下,KaraokeLocalSource 核心承担以下两项职责:
1. 管理音乐列表:负责检索本地资源(例如 Assets 或沙盒路径),并将其映射为组件可识别的 MusicInfo 标准列表。
2. 实现播放鉴权:KTV 场景下需要合唱机器人进入房间协同播放音乐,因此该类需负责获取 UserSig 签名,以确保播放流程的鉴权通过。
注意:说明:
注意:实时评分与音准检测功能需配合版权曲库的标准音轨数据实现。因此,本地音乐目前仅支持歌词展示与同步播放,不支持打分和计算用户的实时音准。
package io.trtc.tuikit.atomicx.karaoke.storeimport android.content.Contextimport androidx.core.content.ContextCompatimport com.tencent.qcloud.tuikit.debug.GenerateTestUserSigimport io.trtc.tuikit.atomicx.karaoke.store.utils.MusicInfoimport java.io.File/** * 本地音乐数据源实现类 * 负责加载本地存储的演示歌曲,并处理基础鉴权逻辑 */class KaraokeLocalSource(private val context: Context) : MusicSourceService() { /** * 步骤 1:获取本地歌曲列表 * 将本地文件路径封装为 MusicInfo 对象并返回 */ override fun getSongList(callback: GetSongListCallBack) { // 1. 获取本地存储的绝对路径。 // 确保在调用此方法前,相关 mp3/vtt 文件已通过 copyAssetToFile 拷贝至该路径。 val localPath = ContextCompat.getExternalFilesDirs(context, null)[0].absolutePath + File.separator // 2. 配置 MusicInfo 核心字段。 // musicId: 歌曲唯一标识;musicName: 歌曲名称;artist: 歌手名列表。 val demoMusic = MusicInfo().apply { musicId = " local_demo_01" // LiveKit中,本地音乐的musicId前缀是local_demo. musicName = "后来" artist = "刘若英" lyricUrl = "lyricUrl.vtt" // 对应歌词文件的 URL originalUrl = "originalUrl.mp3" // 对应原唱文件的 URL accompanyUrl = "accompanyUrl.mp3" // 对应伴奏文件的 URL } // 4. 构建列表并通过回调返回。 val musicList = arrayListOf(demoMusic) callback.onSuccess(musicList) } /** * 步骤 2:生成用户签名 * 为当前用户生成合法的业务签名,用于初始化组件和鉴权 */ override fun generateUserSig(userId: String, callback: ActionCallback) { // 调用测试环境工具生成 UserSig val userSig = GenerateTestUserSig.genTestUserSig(userId) if (userSig.isNotEmpty()) { callback.onSuccess(userSig) } else { callback.onError(-1, "Generate UserSig failed") } }}
场景二:添加曲库音乐
如果你已购买版权曲库服务(例如 音速达曲库),可以通过继承 MusicSourceService 实现云端资源的集成。请在工程中新建 KaraokeOnlineSource.kt 文件。在曲库模式下,该类核心承担以下三项职责:
1. 管理云端列表:对接业务后台或腾讯云接口,获取在线歌曲元数据并映射为组件可识别的 MusicInfo 标准列表。
2. 实现播放鉴权:KTV 场景下需要合唱机器人进入房间协同播放。该职责负责获取合法的 UserSig 签名,确保机器人具备进房播放权限。
3. 获取播放凭证:针对受版权保护的数字音乐,需根据 musicId 向服务器换取 playToken 及 License 授权,这是在线流媒体正常解密播放的核心凭证。
package io.trtc.tuikit.atomicx.karaoke.storeimport io.trtc.tuikit.atomicx.karaoke.store.utils.MusicInfo/** * 在线曲库数据源实现类 * 职责:1. 检索云端歌曲;2. 提供机器人进房鉴权;3. 获取版权播放凭证 */class KaraokeOnlineSource : MusicSourceService() { /** * 职责一:获取云端歌曲列表 * 此处通常调用你的业务后端接口,将返回的 JSON 解析为 MusicInfo 列表 */ override fun getSongList(callback: GetSongListCallBack) { // 示例:此处模拟网络请求成功后构建的在线歌曲对象 val onlineMusic = MusicInfo().apply { musicId = "online_id_1001" // 云端歌曲唯一 ID musicName = "在线歌曲示例" artist = mutableListOf("歌手名") coverUrl = "https://example.com/cover.jpg" // 在线封面 URL } callback.onSuccess(arrayListOf(onlineMusic)) } /** * 职责二:鉴权播放 * 建议由你的业务后端生成 UserSig,确保合唱机器人安全入会 */ override fun generateUserSig(userId: String, callback: ActionCallback) { // 示例:此处应发起网络请求从你的服务器获取 UserSig val userSig = "YOUR_SERVER_GENERATED_USERSIG" callback.onSuccess(userSig) } /** * 职责三:获取播放凭证 (在线模式核心) * 根据 musicId 获取播放 Token、License 等版权信息 */ override fun queryPlayToken(musicId: String, userId: String, callback: QueryPlayTokenCallBack) { // 示例:此处应向服务器请求该音乐的播放许可 val playToken = "YOUR_PLAY_TOKEN" val licenseKey = "YOUR_LICENSE_KEY" val licenseUrl = "YOUR_LICENSE_URL" // 验证成功后返回凭证 callback.onSuccess(musicId, playToken, licenseKey, licenseUrl) }}
九、歌词组件(LyricView)
LyricView 是 Karaoke 组件中负责文本表现的核心视图。它能够根据音乐播放进度,实现毫秒级的歌词平滑滚动与逐字颜色填充,为演唱者提供精准的节奏指引。
组件能力:
1. 高精度对齐:支持 VTT、LRC 等标准歌词格式,确保歌词的逐字染色进度与伴奏精准同步。
2. 自适应排版:内置长句拆行与缩减逻辑,当歌词过长时会自动进行排版优化,防止 UI 溢出。
3. 双行渲染模式:默认采用“当前行+下一行”的双行显示策略,帮助演唱者提前预判歌词内容。
十、自定义歌词 UI 样式
为了适配不同风格的直播间布局,LyricView 提供了丰富的自定义接口。你无需修改组件源码,通过简单的 API 调用即可调整歌词的颜色、大小及对齐方式。
1. 设置歌词颜色。你可以分别设置第一行(当前行)的两种状态颜色,以及第二行(等待行)的颜色。
// 设置歌词颜色lyricView.setLyricColors( currentLineNormalColor = Color.WHITE, // 第一行:尚未唱到的底色 currentLineHighlightedColor = Color.BLUE, // 第一行:已经唱到的高亮色 nextLineColor = Color.GRAY // 第二行:等待演唱行的颜色)
2. 调整字体与间距你可以为“当前正在演唱行”和“后续等待行”分别设置不同的字体大小,以增强视觉层级感。
// 设置歌词字体:参数1为高亮行大小,参数2为次行大小 (单位:sp)lyricView.setLyricTextSize(18f, 12f)
3. 变换对齐方式根据 UI 设计需求,你可以灵活切换歌词的水平对齐模式。
// 支持居中对齐 (LyricAlign.CENTER) 或 居右对齐 (LyricAlign.RIGHT)lyricView.setLyricAlign(LyricAlign.CENTER)
4. 实时驱动进度LyricView 的状态由进度数据驱动。你只需将音乐播放器返回的毫秒级进度注入组件,即可实现丝滑的滚动效果。
// 在进度监听器中调用,驱动歌词染色与滚动lyricView.setPlayProgress(currentProgressMs)
十一、音准组件 (PitchView)
PitchView 是 Karaoke 组件中实现专业级打分功能的核心视图。它通过波形化的视觉反馈,将演唱者的实时音高(Pitch)与歌曲标准音轨进行对比,为用户提供极具趣味性与挑战性的“音准校对”体验。
组件能力:
1. 实时音准反馈:毫秒级呈现演唱者的音高动态,通过移动的“音准粒子”实时反馈音准偏移情况。
2. 标准基准线对比:自动加载歌曲的标准音高数据,形成可视化的音高参考矩形块,方便演唱者找准音调。
3. 视觉命中反馈:当演唱音高进入标准范围内时,组件会自动触发高亮染色与“蝴蝶点缀”等动效,强化演唱成就感。
4. 多端状态同步:支持将房主的演唱得分与音高曲线实时广播给全房观众,实现跨端的视觉同步。
十二、自定义音准 UI 样式
PitchView 提供了深度的自定义配置接口,允许开发者根据直播间的视觉调性,调整曲线的外观、命中判定规则以及动画效果。
1. 开启/关闭打分模式:你可以动态控制打分功能的开关。关闭后,组件将不再显示评分标签。
// 开启打分显示逻辑pitchView.setScoringEnabled(true)
2. 设置标准音轨数据:在歌曲开始播放前,需要将标准音高序列注入组件,用于生成参考背景。pitchList 数据来自合唱回调 onChorusMusicLoadSucceed 中的 pitchList 字段。
// 注入来自 TXChorusMusicPlayer 的标准音高列表pitchView.setPitchList(pitchList)
3. 实时驱动播放进度:PitchView 需要实时进度来驱动音轨的横向滚动。
// 在进度监听器中调用,驱动音轨随音乐进度平滑滚动pitchView.setPlayProgress(currentProgressMs)
4. 注入演唱者当前音高:将人声检测到的实时音高注入组件,用于绘制当前演唱的粒子位置。
// 注入演唱者当前的实时音高值(通常为 0-100)pitchView.setUserPitch(userPitch)
5. 实时更新分数:显示当打分逻辑计算出最新得分时,可以调用此接口更新界面顶部的分数标签。
// 设置当前实时得分,视图会自动更新分数的冒泡显示pitchView.setScore(85)
6. 配置核心颜色:通过代码接口,你可以自定义标准音轨、命中高亮以及背景分割线的颜色。
// 注:PitchView 内部默认集成了以下视觉属性的配置逻辑// 你可以通过 XML 或自定义属性扩展来调整:// 标准音轨色:lineColor (默认灰色)// 命中填充色:highlightColor (默认红色)// 引导粒子色:dotColor (默认白色)
十四、合唱相关
TXChorusMusicPlayer 是合唱功能的核心控制单元,封装在 TRTC SDK 中。该组件基于 NTP 时间戳对齐技术,确保跨设备间人声与伴奏的精准同步,并提供了完整的音乐播放控制能力 。
注意:TXChorusMusicPlayer 主要负责音频流的加载、同步与播放控制 。音准检测与实时评分功能是由版权曲库实现的。
十五、核心控制方法
| 方法名 | 说明 | 调用权限 |
| start() | 开始播放合唱音乐。 | 仅限主唱 |
| stop() | 停止合唱播放。 | 仅限主唱 |
| pause() | 暂停合唱播放。 | 仅限主唱 |
| resume() | 恢复合唱播放。 | 仅限主唱 |
| seek(long progressMs) | 跳转到指定播放进度。 | 仅限主唱 |
| setChorusRole(ChorusRole role, TRTCParams params) | 设置合唱角色(例如主唱、副唱、观众等)。 | 所有角色 |
| switchMusicTrack(MusicTrack track) | 切换原唱与伴奏。主唱设置会同步影响观众。 | 主唱/副唱 |
十六、音乐加载与配置
| 方法名 | 说明 |
| loadMusic(ChorusMusicParams params) | 加载版权曲库(例如音速达)音乐。 |
| loadExternalMusic(ExternalParams params) | 加载本地或自定义 URL 音乐文件。 |
| setPublishVolume(int volume) | 设置主唱推流到远端的 BGM 音量 (0-100)。 |
| setPlayoutVolume(int volume) | 设置本地播放的 BGM 音量 (0-100)。 |
十七、事件回调 (ITXChorusPlayerListener)
| 回调方法 | 触发时机 |
| onChorusStarted() | 合唱正式开始播放时触发。 |
| onMusicProgressUpdated(long progress, long duration) | 毫秒级播放进度更新。 |
| onVoicePitchUpdated(int pitch, boolean hasVoice, long progressMs) | 演唱音高实时更新(-1 表示间奏/无人声)。 |
| onVoiceScoreUpdated(int current, int average) | 每一句歌词唱完后的实时得分反馈。 |
| onChorusRequireLoadMusic(String musicId) | 主唱发起点播后,通知其他角色同步加载歌曲。 |
十八、点歌台相关
TUISongListManager 负责管理直播间的点唱队列,包括添加歌曲、删除歌曲、歌曲置顶及自动切歌逻辑。
| 方法名 | 说明 |
| addSong(List<SongInfo> list, callback) | 将歌曲添加至待播列表。 |
| removeSong(List<String> ids, callback) | 从队列中移除指定歌曲。 |
| setNextSong(String songId, callback) | 置顶某首歌曲,使其成为下一首播放的曲目。 |
| playNextSong(callback) | 立即切换至下一首歌曲。 |
| getWaitingList(cursor, count, callback) | 分页获取当前待播列表。 |
| getPlayedList(cursor, count, callback) | 分页获取已播放的历史列表。 |
20、是否有推荐的曲库供应商?
国内建议优先选择音速达曲库。它具备丰富的正版曲目授权,且与组件的音准打分系统深度适配。你可以访问 音速达帮助中心 获取更多接入支持。
21、为什么演唱时没有音高曲线或实时评分?
音准检测与打分功能高度依赖版权曲库(例如音速达)提供的标准音高基准文件。如果你使用的是本地音乐(External Source),由于缺少标准的参考数据,系统将无法触发 onVoicePitchUpdated(音高更新)和 onVoiceScoreUpdated(分数更新)回调。
22、本地音乐加载失败,报错“Music load failed (-5)”如何处理?
请确认传入 loadExternalMusic 的文件路径是否合法且具备读取权限。如果音乐资源存放在工程的 Assets 目录中,必须先将其拷贝至应用的沙盒路径(例如 getExternalFilesDir)下,方可被底层播放引擎成功识别并加载。
23、如何解决合唱时人声被伴奏掩盖的问题?
你可以使用 setPublishVolume 接口动态调整推流中伴奏的音量(建议范围 30-60),同时通过 TRTC SDK 的 setAudioCaptureVolume 调大人声采集音量 。此外,建议主唱使用 Music 音质模式(TRTCAudioQualityMusic)以获得更好的音频效果 。