Karaoke 组件是 TUILiveKit 的标准化 K 歌功能模块,可快速集成至视频直播及语音房场景。组件支持本地与在线音乐接入,内置歌词滚动、音准检测、实时打分及多种音效设置。为用户提供低延迟、高保真的实时 K 歌体验。
功能概览
多端人声和音乐同步对齐: 基于
NTP 时间戳对齐技术,确保跨设备间人声与伴奏的精准同步,有效解决网络抖动带来的音画不同步问题。实时打分与音准曲线:曲库歌曲可实时展示标准音高与用户个人音准曲线,唱歌得分同步广播给全房观众。本地导入歌曲暂不支持打分和音准显示。
毫秒级歌词滚动:支持 VTT、LRC 格式歌词,随音乐进度精准滚动。
多样化音乐源支持: 全面支持在线曲库点播与本地音乐(MP3/M4A)上传播放。

快速接入
步骤 1. 开通服务
步骤 2. 代码集成
步骤 3. 集成 KTV 功能
布局选择与接入
我们提供了两种不同交互的布局模式,您可以根据直播间的业务侧重点(例如:专业 K 歌房、社交娱乐房)选择最合适的集成方案。
该模式主要通过
KTVView 实现,视图通常固定置于房间顶部。它提供了完整的歌词滚动、音高曲线评分以及播放控制功能。您可以根据业务需求,通过代码动态构建的方式将该组件集成到应用中。
方式1:通过代码动态构建
对于使用 Swift 语言开发的工程,集成逻辑如下。
import AtomicXimport AtomicXCoreimport UIKitimport SnapKitclass ViewController: UIViewController { //替换为您真实的类名private let liveID: Stringprivate let isOwner: Bool// 1. 初始化 KaraokeManagerprivate lazy var karaokeManager: KaraokeManager = {let manager = KaraokeManager(roomId: liveID) //roomId:房间唯一标识return manager}()// 2. 创建 KtvViewprivate lazy var ktvView: KtvView = {let ktvView = KtvView(karaokeManager: karaokeManager,isOwner: isOwner, //isOwner: 是否是房主isKTV: true)return ktvView}()init(liveID: String) {self.liveID = liveIDself.isOwner = LiveListStore.shared.state.value.currentLive.liveOwner.userID == LoginStore.shared.state.value.loginUserInfo?.userIDsuper.init(nibName: nil, bundle: nil)}required init?(coder: NSCoder) {fatalError("init(coder:) has not been implemented")}override func viewDidLoad() {super.viewDidLoad()setupKaraokeView()setupKaraoke()}// 3. 添加 KtvView 到视图private func setupKaraokeView() {view.addSubview(ktvView)// 替换为您真实的布局ktvView.snp.makeConstraints { make inmake.left.right.equalToSuperview()make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom).offset(-20)make.height.equalTo(150)}}// 4. 初始化 Karaoke 功能private func setupKaraoke() {karaokeManager.show()}}
该模式主要通过
KTVView 实现,支持手动拖拽。提供了歌词滚动、音准打分曲线及播放控制功能。您可以根据业务需求,通过代码动态构建的方式将该组件集成到应用中。
方式1:通过代码动态构建
对于使用 Swift 语言开发的工程,集成逻辑如下。
import AtomicXimport AtomicXCoreimport UIKitimport SnapKitclass ViewController: UIViewController { //替换为您真实的类名private let liveID: Stringprivate let isOwner: Bool// 1. 初始化 KaraokeManagerprivate lazy var karaokeManager: KaraokeManager = {let manager = KaraokeManager(roomId: liveID) //roomId:房间唯一标识return manager}()// 2. 创建 KtvViewprivate lazy var ktvView: KtvView = {let ktvView = KtvView(karaokeManager: karaokeManager,isOwner: isOwner, //isOwner: 是否是房主isKTV: false)return ktvView}()init(liveID: String) {self.liveID = liveIDself.isOwner = LiveListStore.shared.state.value.currentLive.liveOwner.userID == LoginStore.shared.state.value.loginUserInfo?.userIDsuper.init(nibName: nil, bundle: nil)}required init?(coder: NSCoder) {fatalError("init(coder:) has not been implemented")}override func viewDidLoad() {super.viewDidLoad()setupKaraokeView()setupKaraoke()}// 3. 添加 KtvView 到视图private func setupKaraokeView() {view.addSubview(ktvView)//替换为您真实的布局ktvView.snp.makeConstraints { make inmake.trailing.equalToSuperview().inset(20.scale375())make.top.equalTo(view.safeAreaLayoutGuide.snp.top).offset(100)make.height.equalTo(150)}}// 4. 初始化 Karaoke 功能private func setupKaraoke() {karaokeManager.show()}}
添加音乐
Karaoke 组件提供了灵活的数据源适配机制,支持集成本地音乐资源或商业版权曲库。您可以通过继承
MusicSourceService 类来实现不同场景下的音乐加载逻辑。
场景一:添加本地音乐
若您希望播放应用内置或本地音乐文件,请在您的工程中修改或重写
LocalMusicCatalogServiceImpl类。该类继承自 MusicCatalogService基类。在本地音乐模式下,LocalMusicCatalogServiceImpl 核心承担以下职责:管理音乐列表:负责检索本地资源,并将其映射为组件可识别的
MusicInfo 标准列表。说明:
实时评分与音准检测功能需配合版权曲库的标准音轨数据实现。因此,本地音乐目前仅支持歌词展示与同步播放,不支持打分和计算用户的实时音准。
步骤一:导入音乐资源文件到
AtomicX.bundle1. 在 Xcode 中,找到
AtomicX 工程目录。2. 将您的音乐资源文件添加到
AtomicX/Resources/KTVResource/目录下。3. 确保文件包含以下类型:
原唱文件:例如
houlai_original.mp3伴奏文件:例如
houlai_accompany.mp3歌词文件:例如
houlai.vtt4. 在
AtomicX.podspec中,确保资源文件被正确打包:s.resource_bundles = {'AtomicXBundle' => ['Resources/**/*.{xcassets,json,png,xcstrings,vtt,mp3,json,flac,gif}']}
5. 修改完成后,回到您的
.xcworkspace文件路径下重新执行以下命令使配置生效:pod install
步骤二:在
AppDelegate 中初始化KaraokeConfig。在使用 Karaoke 组件前,您需要在
AppDelegate.swift 中配置您的SDKAppID 和SecretKey:import UIKitimport AtomicX@mainclass AppDelegate: UIResponder, UIApplicationDelegate {func initKaraokeConfig() {// 配置您的腾讯云 SDKAppID 和 SecretKeyKaraokeConfig.shared.updateConfig(SDKAPPID: Int32(SDKAPPID), SECRETKEY: SECRETKEY)}func application(_ application: UIApplication,didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {// 初始化 KaraokeConfig(必须在使用 Karaoke 组件前调用)initKaraokeConfig()return true}}
步骤三:实现
LocalMusicCatalogServiceImpl类。import Foundationclass LocalMusicCatalogServiceImpl: MusicCatalogService {/*** 步骤 1:获取本地歌曲列表* 将本地文件路径封装为 MusicInfo 对象并返回,确保在调用此方法前,相关 mp3/vtt 等文件已导入到 AtomicX.bundle 中。* 在 Xcode 中,找到 `AtomicX` 工程目录,并将您的音乐资源文件添加到 `AtomicX/Resources/KTVResource/` 目录下* 执行pod install*/func getSongList(completion: @escaping ([MusicInfo]) -> Void) {// 1. 配置 MusicInfo 核心字段。// musicId: 歌曲唯一标识;musicName: 歌曲名称;artist: 歌手名列表。let demoMusic = MusicInfo(musicId: "local_demo_01", // LiveKit中,本地音乐的musicId前缀是local_demo.musicName: "", // 真实的音乐名artist: "", // 真实的歌手列表duration: 0, // 真实的音乐持续时间coverUrl: "", // 真实的歌曲封面accompanyUrl: atomicXBundle.path(forResource: "houlai_accompany", ofType: "mp3") ?? "", // 对应伴奏文件的 URLoriginalUrl: atomicXBundle.path(forResource: "houlai_original", ofType: "mp3") ?? "", // 对应原唱文件的 URLlyricUrl: atomicXBundle.path(forResource: "houlai", ofType: "vtt") ?? "",isOriginal: true,hasRating: false)// 2. 构建列表并通过回调返回。let musicList = [demoMusic]completion(musicList)}/*** 步骤 2:生成音乐鉴权token* 本地集成音乐暂不需要实现*/public func queryPlayToken(musicId: String, liveID: String, callback: QueryPlayTokenCallBack) {}}
场景二:添加曲库音乐
如果您已购买版权曲库服务(例如 音速达曲库),可以通过继承
MusicCatalogService 实现云端资源的集成。请在工程中实现MusicCatalogServiceImpl类。在曲库模式下,该类核心承担以下两项职责:管理云端列表:对接业务后台或腾讯云接口,获取在线歌曲元数据并映射为组件可识别的
MusicInfo 标准列表。获取播放凭证:针对受版权保护的数字音乐,需根据
musicId 向服务器换取 playToken 及 License 授权,这是在线流媒体正常解密播放的核心凭证。步骤一:在
AppDelegate 中初始化 KaraokeConfig。在使用 Karaoke 组件前,您需要在
AppDelegate.swift 中配置您的SDKAppID 和 SecretKey并注册网络音乐服务:import UIKitimport AtomicX@mainclass AppDelegate: UIResponder, UIApplicationDelegate {func initKaraokeConfig() {// 1. 初始化 KaraokeConfig(必需)KaraokeConfig.shared.updateConfig(SDKAPPID: Int32(SDKAPPID), SECRETKEY: SECRETKEY)// 2. 注册网络音乐服务let networkMusicSource = MusicCatalogServiceImpl()MusicCatalogServiceManager.shared.setService(networkMusicSource)}func application(_ application: UIApplication,didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {initKaraokeConfig()return true}}
步骤二:实现
MusicCatalogServiceImpl 类。import Foundationimport AtomicX/*** 网络音乐数据源实现类* 负责从版权曲库获取在线音乐列表,并处理播放鉴权逻辑*/public class MusicCatalogServiceImpl: MusicCatalogService {// 版权曲库 License 配置private let copyrightedLicenseKey = "your_license_key" //替换为您真实的曲库(音速达)LicenseKeyprivate let copyrightedLicenseUrl = "your_license_url" //替换为您真实的曲库(音速达)LicenseURLpublic init() {}/*** 步骤 1:获取版权曲库歌曲列表* 通过网络请求从版权曲库中检索指定标签的音乐列表*/public func getSongList(completion: @escaping ([MusicInfo]) -> Void) {// 示例:此处模拟网络请求成功后构建的在线歌曲对象// 实际使用时,您需要替换为真实的网络请求逻辑,从后端服务获取歌曲列表let onlineMusic = MusicInfo(musicId: "online_music_001", // 在线音乐IDmusicName: "示例歌曲", // 歌曲名称artist: "示例歌手", // 歌手名称duration: 240, // 歌曲时长(秒)coverUrl: "https://example.com/cover.jpg", // 封面图片URLaccompanyUrl: "https://example.com/accompany.m3u8", // 伴奏URLoriginalUrl: "https://example.com/original.m3u8", // 原唱URLlyricUrl: "https://example.com/lyric.vtt", // 歌词URLisOriginal: true,hasRating: true)let musicList = [onlineMusic]completion(musicList)}/*** 步骤 2:获取播放凭证* 向后端服务请求 playToken,用于授权音乐播放*/public func queryPlayToken(musicId: String, liveID: String, callback: QueryPlayTokenCallBack) {// 示例:此处模拟网络请求成功后返回的播放凭证// 实际使用时,您需要替换为真实的网络请求逻辑,从后端服务获取 playTokenlet playToken = "your_play_token_from_server"callback.onSuccess(musicId: musicId,playToken: playToken,copyrightedLicenseKey: self.copyrightedLicenseKey,copyrightedLicenseUrl: self.copyrightedLicenseUrl)}}
核心 UI 组件
歌词组件(LyricView)
LyricView 是 Karaoke 组件中负责文本表现的核心视图。它能够根据音乐播放进度,实现毫秒级的歌词平滑滚动与逐字颜色填充,为演唱者提供精准的节奏指引。
组件能力:
1. 高精度对齐:支持 VTT、LRC 等标准歌词格式,确保歌词的逐字染色进度与伴奏精准同步。
2. 自适应排版:内置长句拆行与缩减逻辑,当歌词过长时会自动进行排版优化,防止 UI 溢出。
3. 双行渲染模式:默认采用“当前行+下一行”的双行显示策略,帮助演唱者提前预判歌词内容。
自定义歌词 UI 样式
为了适配不同风格的直播间布局,您可以通过以下方式来修改组件样式。
1. 设置歌词颜色。您可以分别设置第一行(当前行)的两种状态颜色,以及第二行(等待行)的颜色。
// 修改 LyricCell 的 configure 方法,项目使用了自定义 UIColor 扩展 UIColor(_hex: String)func configure(with line: LyricLine, isCurrentLine: Bool, progress: Int, alignment: NSTextAlignment) {karaokeLyricLabel.text = line.textif isCurrentLine {// 当前行:白色底色karaokeLyricLabel.textColor = .whiteupdateProgress(progress)} else {// 等待行:浅灰色karaokeLyricLabel.textColor = .lightGraykaraokeLyricLabel.progress = 0karaokeLyricLabel.setNeedsDisplay()}}// 修改 KaraokeLyricLabel 的 draw 方法中的高亮色override func draw(_ rect: CGRect) {// ... 绘制底色文字 ...if progress > 0 {// 修改这里的颜色,设置高亮色let attributes: [NSAttributedString.Key: Any] = [.font: font,.foregroundColor: UIColor("00ABD6"), // 修改为您需要的高亮色.paragraphStyle: style]// ... 绘制高亮文字 ...}}
2. 调整字体与间距您可以为“当前正在演唱行”和“后续等待行”分别设置不同的字体大小,以增强视觉层级感。
// 在 LyricCell 的 configure 方法中修改字体func configure(with line: LyricLine, isCurrentLine: Bool, progress: Int, alignment: NSTextAlignment) {if alignment == .center { // KTV 模式karaokeLyricLabel.font = isCurrentLine ?UIFont(name: "PingFangSC-Semibold", size: 18) ?? .systemFont(ofSize: 18, weight: .semibold) :UIFont(name: "PingFangSC-Regular", size: 12) ?? .systemFont(ofSize: 12, weight: .regular)} else { // 直播模式karaokeLyricLabel.font = isCurrentLine ?UIFont(name: "PingFangSC-Medium", size: 14) ?? .systemFont(ofSize: 14, weight: .medium) :UIFont(name: "PingFangSC-Regular", size: 10) ?? .systemFont(ofSize: 10, weight: .regular)}// ... 其他配置 ...}private func lyricRowStyle(for isKTV: Bool, row: Int) -> LyricRowStyle {if isKTV {if row == 0 { //当前行return LyricRowStyle(labelHeight: 21, top: 3, bottom: 3)} else {return LyricRowStyle(labelHeight: 17, top: 5, bottom: 5)}} else {if row == 0 { //当前行return LyricRowStyle(labelHeight: 18, top: 4, bottom: 0)} else {return LyricRowStyle(labelHeight: 14, top: 4, bottom: 4)}}}
3. 变换对齐方式。根据 UI 设计需求,您可以在
LyricView中灵活切换歌词的水平对齐模式。// 对齐方式由初始化时的 isKTV 参数决定,在 cellForRowAt 方法中应用。func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {// ... 其他配置 ...let lineIndex = currentLineIndex + indexPath.rowguard lineIndex < lyricsData.count else { return cell }let line = lyricsData[lineIndex == -1 ? 0 : lineIndex]let isCurrentLine = indexPath.row == 0// isKTV 为 true 时居中对齐,false 时右对齐cell.configure(with: line,isCurrentLine: isCurrentLine,progress: currentPlaybackProgress,alignment: isKTV ? .center : .right)return cell}
4. 实时驱动进度LyricView 的状态由进度数据驱动。您只需将音乐播放器返回的毫秒级进度注入组件,即可实现丝滑的滚动效果。
// 在进度监听器中调用,驱动歌词染色与滚动lyricsView.updateLyrics(progress: currentProgressMs)
音准组件 (PitchView)
PitchView 是 Karaoke 组件中实现专业级打分功能的核心视图。它通过波形化的视觉反馈,将演唱者的实时音高(Pitch)与歌曲标准音轨进行对比,为用户提供极具趣味性与挑战性的“音准校对”体验。
组件能力:
1. 实时音准反馈:毫秒级呈现演唱者的音高动态,通过移动的“音准粒子”实时反馈音准偏移情况。
2. 标准基准线对比:自动加载歌曲的官方标准音高数据,形成可视化的音高参考矩形块,方便演唱者找准音调。
3. 视觉命中反馈:当演唱音高进入标准范围内时,组件会自动触发高亮染色与“蝴蝶点缀”等动效,强化演唱成就感。
4. 多端状态同步:支持将房主的演唱得分与音高曲线实时广播给全房观众,实现跨端的视觉同步。
自定义音准 UI 样式
PitchView 提供了深度的自定义配置接口,允许开发者根据直播间的视觉调性,调整曲线的外观、命中判定规则以及动画效果。1. 开启/关闭打分模式:您可以动态控制打分功能的开关。关闭后,组件将不再显示评分标签。
// 开启打分显示逻辑pitchView.setScoreComponentVisible(true)
2. 设置标准音轨数据:在歌曲开始播放前,需要将标准音高序列注入组件,用于生成参考背景。
pitchList 数据来自合唱回调 onChorusMusicLoadSucceed 中的 pitchList 字段。// 注入来自 TXChorusMusicPlayer 的标准音高列表pitchView.setStandardPitchModels(standardPitchModels: pitchModels)
3. 实时驱动播放进度:PitchView 需要实时进度来驱动音轨的横向滚动。
// 在进度监听器中调用,驱动音轨随音乐进度平滑滚动pitchView.setCurrentSongProgress(progress: currentProgressMs)
4. 注入演唱者当前音高:将人声检测到的实时音高注入组件,用于绘制当前演唱的粒子位置。
// 注入演唱者当前的实时音高值(通常为 0-100)pitchView.setCurrentPitch(pitch: userPitch)
5. 实时更新分数:当打分逻辑计算出最新得分时,可调用此接口更新界面顶部的分数标签。
// 设置当前实时得分,视图会自动更新分数的冒泡显示pitchView.setScore("85")
6. 核心配置项:通过
PitchViewConfig 配置接口,您可以自定义标准音轨、命中高亮以及背景分割线的颜色等设置。// 创建配置对象let config = PitchViewConfig()// 配置颜色config.standardRectColor = UIColor.white.withAlphaComponent(0.7) // 标准音轨颜色config.hitRectColor = UIColor("FF6A4C") // 命中填充颜色config.pitchIndicatorColor = .white // 引导粒子颜色config.verticalLineColor = UIColor.white.withAlphaComponent(0.45) // 竖线颜色config.scoreTextColor = UIColor("FF6A4C") // 分数文本颜色// 配置时间相关config.timeElapsedOnScreen = 1175 // 竖线左侧表示的时间(ms)config.timeToPlayOnScreen = 2750 // 竖线右侧表示的时间(ms)config.estimatedCallInterval = 20 // 进度更新间隔(ms)// 配置音高范围config.pitchNum = 20 // 音高等级数(影响垂直分辨率)config.maxPitch = 90 // 最大音高值config.minPitch = 5 // 最小音高值// 应用配置pitchView.setConfig(config: config)
API 参考
合唱相关
TXChorusMusicPlayer 是合唱功能的核心控制单元,封装在 TRTC SDK 中。该组件基于 NTP 时间戳对齐技术,确保跨设备间人声与伴奏的精准同步,并提供了完整的音乐播放控制能力 。注意:
TXChorusMusicPlayer 主要负责音频流的加载、同步与播放控制 。音准检测与实时评分功能是由版权曲库实现的。
核心控制方法
方法名 | 说明 | 调用权限 |
start() | 开始播放合唱音乐。 | 仅限主唱 |
stop() | 停止合唱播放。 | 仅限主唱 |
pause() | 暂停合唱播放。 | 仅限主唱 |
resume() | 恢复合唱播放。 | 仅限主唱 |
seek(_ timestampMs: Int64) | 跳转到指定播放进度。 | 仅限主唱 |
setChorusRole(_ role: TXChorusRole,trtcParamsForPlayer: TRTCParams) | 设置合唱角色(例如主唱、副唱、观众等)。 | 所有角色 |
switch(_ track: TXChorusMusicTrack) | 切换原唱与伴奏。主唱设置会同步影响观众。 | 主唱/副唱 |
音乐加载与配置
方法名 | 说明 |
loadMusic(_ params: TXChorusCopyrightedMusicParams) | 加载版权曲库音乐。 |
loadExternalMusic(_ params: TXChorusExternalMusicParams) | 加载本地或自定义 URL 音乐文件。 |
setPublishVolume(_ volume: Int32) | 设置主唱推流到远端的 BGM 音量 (0-100)。 |
setPlayoutVolume(_ volume: Int32) | 设置本地播放的 BGM 音量 (0-100)。 |
事件回调 (ITXChorusPlayerListener)
回调方法 | 触发时机 |
onChorusStarted() | 合唱正式开始播放时触发。 |
onMusicProgressUpdated(_ progressMs: Int64, durationMs: Int64) | 毫秒级播放进度更新。 |
onVoicePitchUpdated(_ pitch: Int32, hasVoice: Bool, progressMs: Int64) | 演唱音高实时更新(-1 表示间奏/无人声)。 |
onVoiceScoreUpdated(_ currentScore: Int32, averageScore: Int32, currentLine: Int32) | 每一句歌词唱完后的实时得分反馈。 |
onChorusRequireLoadMusic(_ musicId: String) | 主唱发起点播后,通知其他角色同步加载歌曲。 |
点歌台相关
TUISongListManager 负责管理直播间的点唱队列,包括添加歌曲、删除歌曲、歌曲置顶及自动切歌逻辑。方法名 | 说明 |
addSong(songList , onSuccess, onError) | 将歌曲添加至待播列表。 |
removeSong(songIdList , onSuccess, onError) | 从队列中移除指定歌曲。 |
setNextSong(targetSongId, onSuccess, onError) | 置顶某首歌曲,使其成为下一首播放的曲目。 |
playNextSong(onSuccess , onError) | 立即切换至下一首歌曲。 |
getWaitingList(cursor, count, onSuccess, onError) | 分页获取当前待播列表。 |
getPlayedList(cursor, count, onSuccess, onError) | 分页获取已播放的历史列表。 |
常见问题
是否有推荐的曲库供应商?
为什么演唱时没有音高曲线或实时评分?
音准检测与打分功能高度依赖版权曲库(例如音速达)提供的标准音高基准文件。如果您使用的是本地音乐(External Source),由于缺少标准的参考数据,系统将无法触发
onVoicePitchUpdated(音高更新)和 onVoiceScoreUpdated(分数更新)回调。如何解决合唱时人声被伴奏掩盖的问题?
您可以使用 setPublishVolume 接口动态调整推流中伴奏的音量(建议范围 30-60),同时通过 TRTC SDK 的 setAudioCaptureVolume 调高人声采集音量 。此外,建议主唱使用 Music 音质模式(TRTCAudioQualityMusic)以获得更好的音频效果 。