全民K歌IOT开放平台
  1. KtvSDK3.0接入说明
全民K歌IOT开放平台
  • 厂商合作流程
  • 快速接入K歌开放平台流程
  • SDK bug提单规范
  • 如何在线调试接口
  • 常见问题FAQ
  • 开放平台API错误码说明
  • 开放平台接入指南
    • 登录鉴权方式介绍V2(推荐)
    • 如何申请接入
    • CDK权限申请流程
    • 暗账号绑定明账号对接文档
    • 获取应用级token
    • 获取登录二维码
    • 查询二维码的状态
    • 获取用户级token
    • 刷新用户级token
    • 暗账号解绑K歌uid
    • 获取暗账号绑定信息
  • KtvSDK3.0接入说明
    • 厂商合作流程
    • bug提单规范
    • KtvSDK-接入指南
    • KtvSDK-打分
    • KtvSDK-登录
    • KtvSDK-歌词
    • KtvSDK-播放
    • 多屏一起唱---歌词与打分适配
    • 3.0新打分样式及五维打分
    • KtvSDK-多屏渲染
    • KtvSDK-2.0升级到3.0版本迁移指南
    • KtvSDK-3.0版本新功能
    • KtvSDK-Android4.4设备G2证书兼容处理
    • KtvSDK-播放页实现示例
    • KtvSDK-常见问题FAQ
    • KtvSDK-低性能设备处理
    • KtvSDK-反馈
    • KtvSDK-缓存管理
    • KtvSDK-切换音频视频清晰度
    • KtvSDK-跳过前奏
    • Ktv支付-米大师支付
    • 播放失败错误码说明
    • 作品录音、合成与播放2.0版
  • 基础类
    • tagId对照表
    • 歌曲详情
    • 查询mv的播放地址
    • 搜索
    • 搜索联想
    • 查询歌手歌曲
    • 获取歌曲歌词文件
    • Q音歌曲mid映射K歌
    • 短剧播放链接
    • 查询应用限免配置
    • 转换Q音或酷狗歌曲ID
  • 运营类
    • 排行榜id说明
    • 获取城市id列表
    • 获取专题分类列表
    • 获取云端配置
    • 热门ugc
    • 热搜词
    • 排行榜
    • 获取专题下歌曲信息
    • 获取车联渠道映射
    • 热门推荐
    • (新)排行榜
    • 综合歌单列表查询
    • 设置缓存设备
    • TV版分类歌单列表
    • 获取用户协议
    • 综合歌单列表查询(海外)
    • 榜单列表查询(海外)
    • 自建歌单列表查询(海外)
    • 获取广告配置
    • 拉取短剧合集的列表
  • 用户类
    • 用户信息查询
    • 删除用户UGC作品
    • 获取推荐/翻唱作品
    • 获取同城作品
    • 用户作品列表
    • 获取好友作品
    • UGC作品详情
    • 更改作品访问权限
    • 用户个推歌单
  • 支付类
    • 支付接入流程
    • 订单发货使用简述
    • 开通设备会员限免简述
    • 订单发货中通用sign计算规则
    • 通用返回结构
    • 【CDK】CDK兑换
    • 【CDK】生成CDK
    • 【CDK】CDK召回
    • 【CDK】CDK状态查询
    • 【三方支付】订单发货
    • 【三方支付】手机号发货
    • 【三方支付】订单状态查询
    • 【米大师支付】获取会员商品列表
    • 【米大师支付】未登录-查询会员商品列表
    • 【米大师支付】支付下单
    • 【米大师支付】支付成功通知
    • 【米大师支付】查询用户支付成功订单记录
    • 查询设备以及用户是否有赠送资格
    • 查询设备限免剩余时长
    • 设备会员迁移
    • 查询会员赠送时长
    • 同步支付订单接口
    • 【三方支付】存量会员迁移领取查询
    • 【三方支付】存量会员迁移接口
    • 授权设备体验会员
    • 查询用户会员信息
    • 【三方支付】超会发货
    • 取消授权设备体验会员
  • 用户作品-文件类
    • callback_url说明
    • 上传音频源文件
    • (服务端)上传音频作品的链接
  • 通用类
    • 【厂商定制】匹配搜索
    • 获取kg的短链接
  1. KtvSDK3.0接入说明

3.0新打分样式及五维打分

sdk3.0 增加新打分UI:SingIntonationViewer
老打分UI为MidiScoreView,新打分UI支持更炫的效果。
为了支持一端播放录唱,多端共同显示的功能,新增轮询模式,使用外部传入的接口轮询歌曲的打分信息。具体使用请看下面的示例。

1 播放页布局中添加打分view#

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/intonation_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/transparent"
        android:clipToPadding="false"
        android:clipChildren="false"
        tools:ignore="MissingDefaultResource">

    <com.tme.ktv.intonation.view.PerfectAnimView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/karaoke_perfect_view"
            />

    <com.tme.ktv.intonation.view.SimpleScoreBar
            android:focusable="false"
            android:id="@+id/pk_score_bar"
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:layout_marginStart="@dimen/pk_score_layout_margin_left"
            android:layout_marginTop="160dp" />

    <com.tme.ktv.intonation.SingIntonationViewer
            android:id="@+id/player_float_intonation_viewer"
            android:layout_width="match_parent"
            android:layout_height="80dp"
            android:layout_gravity="bottom"
            android:layout_marginStart="30dp"
            android:layout_marginEnd="30dp"
            android:layout_marginBottom="130dp" />
</FrameLayout>

2 初始化打分辅助类#

    private var mIntonationDelegate: SingIntonationDelegate? = null
    private var containerView: ViewGroup? = null
    private var intonationViewer: SingIntonationViewer? = null
    private var pkScoreBar: SimpleScoreBar? = null
    private var perfectAnimView: PerfectAnimView? = null
    private val isPollMode: Boolean = KtvPlayerConfig.getInstance().isEnableScorePolling
    

    containerView = it.findViewById(R.id.intonation_container)
    intonationViewer = it.findViewById(R.id.player_float_intonation_viewer)
    pkScoreBar = it.findViewById(R.id.pk_score_bar)
    perfectAnimView = it.findViewById(R.id.karaoke_perfect_view)
    mIntonationDelegate =
    SingIntonationDelegate(
        containerView,
        intonationViewer,
        pkScoreBar,
        perfectAnimView,
        userService?.getUserInfo()?.value?.headUrl,
        isPollMode
      )
其中 userService?.getUserInfo()?.value?.headUrl是用户的头像url,可以通过用户信息接口中获取,如果不传则显示默认头像
其中 isPollMode 表示是否开启轮询模式,可以从 KtvPlayerConfig 中配置,默认关闭。

五维打分#

五维打分相较于普通打分,回调的信息更加丰富。除了提供歌曲总分外,还提供音准、节奏、技巧、气息、情感这五个维度的分数。
使用时与普通打分的集成方式类似,唯一区分是在KaraokePlayer.OnScoreListener回调中,提供额外获取五个维度分数的方法:
private class ScoreListenerImpl extends KaraokePlayer.OnScoreListener{

    @Override
    protected void onPrepareScore(SingCompetitor competitor, int nums) {
        //获取到节拍数据,设置给midiView
        mMidiScoreView.initData(competitor);
    }
       /** 
         *五维打分回调
         * 每唱完一句出一次分数,上一句就是刚唱完的那一句
         * @param lastScore 上一句的分数
         * @param timeStamp 时间戳
         * @param lastLongToneScore 上一句的气息分数
         * @param lastRhythmScore 上一句的节奏分数
         * @param lastStableScore 上一句的音准分数
         * @param dynamicScore 上一句的情感分数
         * @param skillScore 上一句的技巧分数
         * @param lastSkillTrillCount 上一句命中的颤音个数
         * @param lastSkillGlintCount 上一句命中的滑音个数
         * @param lastSkillTransliterationCount 上一句命中的转音个数
         */
        public void onDoingMultiScore(int lastScore, long timeStamp, int lastLongToneScore, int lastRhythmScore,
                                      int lastStableScore, int dynamicScore, int skillScore,
                                      int lastSkillTrillCount, int lastSkillGlintCount,
                                      int lastSkillTransliterationCount) {
        }


       /** 
         * 五维打分回调
         * @param finalLongToneScore 气息分数
         * @param finalRhythmScore 节奏分数
         * @param finalStableScore 音准分数
         * @param finalDynamicScore 情感分数
         * @param finalSkillScore 技巧分数
         * @param lastSentenceIndex 最后一句歌词的索引
         * @param totalSentences 这首歌的句子数
         */
        public void onMultiScoreFinish(int finalLongToneScore, int finalRhythmScore, int finalStableScore,
                                       int finalDynamicScore, int finalSkillScore, int lastSentenceIndex,
                                       int totalSentences) {
        }
}

3 设置打分回调#

(代码中isPollMode 是用于多屏一起唱的场景,如果不涉及 直接把isPollMode认为false 不需要这个分支的逻辑)
注意:即使设置了开启五维打分也要同时设置普通打分的回调,因为部分歌曲支持打分但是不支持五维打分,此时会自动回落到普通打分。
inner class ScoreListenerImpl : KaraokePlayer.OnScoreListener() {

        private val multiScoreResultInfo=MultiScoreResultInfo()
        override fun onPrepareScore(competitor: SingCompetitor?, nums: Int) {
            // 打分数据就绪回调
            if (isPollMode) {
                val dataRequester = object : ScoreResultRequester {
                    override fun getMidiTime(): Long {
                        return viewModel.currPlayer()?.timeLineTime ?: 0
                    }
                    override fun getScoreResult(timestamp: Long): ScoreResult? {
                        return viewModel.currPlayer()?.getScoreResult(timestamp)
                    }
                }
                mIntonationDelegate?.initData(viewModel.currPlayer()?.noteItems,
                    nums, dataRequester)
            } else {
                mIntonationDelegate?.initData(competitor)
            }
        }
        在轮询模式下,需要设置数据获取接口,播放器都提供了获取对应数据的接口,可以从播放器获取再按需使用。

        override fun onDoingScore(score: Int, level: String?, timeStamp: Int) {
            //普通打分实时回调
            if(!isPollMode) mIntonationDelegate?.postUpdateScore(score,timeStamp.toFloat(),null)
        }

        override fun onDoingMultiScore(
            lastScore: Int,
            timeStamp: Long,
            lastLongToneScore: Int,
            lastRhythmScore: Int,
            lastStableScore: Int,
            dynamicScore: Int,
            skillScore: Int,
            lastSkillTrillCount: Int,
            lastSkillGlintCount: Int,
            lastSkillTransliterationCount: Int
        ) {
            //五维打分实时回调
            multiScoreResultInfo.resetLastScore()
            multiScoreResultInfo.lastLongToneScore = lastLongToneScore
            multiScoreResultInfo.lastRhythmScore = lastRhythmScore
            multiScoreResultInfo.lastStableScore = lastStableScore
            multiScoreResultInfo.lastDynamicScore = dynamicScore
            multiScoreResultInfo.lastSkillScore = skillScore
            multiScoreResultInfo.lastSkillTrillCount = lastSkillTrillCount
            multiScoreResultInfo.lastSkillTransliterationCount = lastSkillGlintCount
            mIntonationDelegate?.postUpdateScore(lastScore, timeStamp.toFloat(), multiScoreResultInfo)
        }

        override fun onMultiScoreFinish(
            finalLongToneScore: Int,
            finalRhythmScore: Int,
            finalStableScore: Int,
            finalDynamicScore: Int,
            finalSkillScore: Int,
            lastSentenceIndex: Int,
            totalSentences: Int
        ) {
            //五维打分回调结束
            //总分需要主动获取一下
            val totalScore = mIntonationDelegate?.getTotalScore()
            //等级目前需要主动转换一下
            //平均分= totalScore/totalSentences
            //分数等级是按照单句平均分来定级的(<60 -->C;>=60&<70 -->B;>=70&<80 -->A;>=80&<90-->S;>=90&<95-->SS;>=95-->SSS)
        }

        override fun onFinishScore(totalScore: Int, level: String?) {
            //普通打分结束
        }
    }
    
    //添加播放回调的监听 在相应的事件中处理打分和节拍器
 inner class KtvScoreCallbackImpl : KaraokePlayerListener() {

        override fun onPlayStart(request: KaraokePlayRequest) {
        }

        override fun onLyricResourceChanged(request: KaraokePlayRequest) {
            super.onLyricResourceChanged(request)
            if (request.songInfoObject.mNoteBytes == null && request.songInfoObject.songType == SongType.SONG_TYPE_K_SONG) {
                //没有节拍数据 无法打分 demo是做了提示不支持打分
                if (KtvPlayerConfig.getInstance().isEnableScore && PlayConsole.get().openScore.value == true) {
                    mIntonationDelegate?.stopMidi()
                }
            }
            mIntonationDelegate?.startMidi(viewModel.currPlayer()?.timeLineTime ?: 0)
        }

        override fun onPlayPositionChange(
            mKtvPlayRequest: KaraokePlayRequest,
            currentTime: Long,
            duration: Long
        ) {
            getActivity()?.let {
                if (!KGDialog.isActivityDestroyed(it)) {
                    mIntonationDelegate?.seekMidi(currentTime.toLong())
                }
            }
        }
        
        override fun onResume(mKtvPlayRequest: KaraokePlayRequest) {
            mIntonationDelegate?.startMidi(viewModel.currPlayer()?.timeLineTime ?: 0)
        }

        override fun onPause(mKtvPlayRequest: KaraokePlayRequest) {
            mIntonationDelegate?.stopMidi()
        }

        override fun onBufferingStart(mKtvPlayRequest: KaraokePlayRequest) {
            mIntonationDelegate?.onBuffingStart()
        }

        override fun onBufferingEnd(mKtvPlayRequest: KaraokePlayRequest) {
            mIntonationDelegate?.onBufferingEnd()
        }

        override fun onPlayEnd(request: KaraokePlayRequest, endInfo: PlayEndInfo) {
            mHandler.post {
                mIntonationDelegate?.onSongPlayComplete()
                mIntonationDelegate?.stopMidi()
                mIntonationDelegate?.releaseMidi()
            }
        }

        override fun onSeekComplete(request: KaraokePlayRequest, position: Long) {
            Logger.d(TAG, "onSeekComplete currentTime $position")
            mIntonationDelegate?.seekMidi(position)
        }
    }

    初始化时把两个实现添加到播放器中
            if (ktvScoreCallBackImpl==null){
                ktvScoreCallBackImpl = KtvScoreCallbackImpl()
            }

            if (scoreListenerImpl==null){
                scoreListenerImpl = ScoreListenerImpl()
            }

            karaokePlayer?.apply {
                removeOnScoreListener(scoreListenerImpl)
                removeCallback(ktvScoreCallBackImpl)
                addOnScoreListener(scoreListenerImpl)
                addCallback(ktvScoreCallBackImpl)
            }
修改于 2025-09-01 07:13:29
上一页
多屏一起唱---歌词与打分适配
下一页
KtvSDK-多屏渲染
Built with