版权音乐

更新时间: 2023/10/12 01:41:18

网易云信支持独立集成版权音乐,实现在线 KTV 场景中搜索、下载和播放版权音乐的能力。

注意事项

  • 使用版权音乐时,请务必在播放界面明显位置用图标说明该音乐内容对应的版权方,界面效果类似如下图所示。版权Logo的图标请参考曲库示例项目源码
  • 您可以通过 getChannel 接口查询音乐的版权方。

点歌.png

前提条件

请确认您已完成以下操作:

API 时序图

版权音乐的实现流程如下图所示。

sequenceDiagram
    autonumber

  participant 应用App
  participant 曲库SDK
  participant 版权音乐服务端

  Note over 应用App, 版权音乐服务端: 歌曲列表 
  应用App->>曲库SDK: 获取歌曲列表 getSongList
  曲库SDK->>版权音乐服务端: 获取歌曲列表
  版权音乐服务端-->>曲库SDK: 返回歌曲列表
  曲库SDK-->>应用App: 返回歌曲列表 Callback<List<NECopyrightedSong>>

  Note over 应用App, 版权音乐服务端: 歌曲/伴奏下载
  应用App->>曲库SDK: 预加载歌曲 preloadSong
  曲库SDK->>版权音乐服务端: 获取歌曲详情
  版权音乐服务端-->>曲库SDK: 返回歌曲资源信息(包括歌词、MIDI、歌曲下载地址地址等)
  曲库SDK->>曲库SDK: 从远端加载歌曲/伴奏
  曲库SDK-->>应用App: 返回歌曲预加载完成回调
  应用App->>曲库SDK: 请求原唱/伴奏歌曲URI getSongURI
  曲库SDK-->>应用App: 返回原唱/伴奏URI
  应用App->>应用App: 根据歌曲URI获得歌曲音频

  Note over 应用App, 版权音乐服务端: 获得歌词
  应用App->>曲库SDK: 请求歌词 getLyric
  曲库SDK-->>应用App: 返回歌词

  Note over 应用App, 版权音乐服务端: 获得MIDI
  应用App->>曲库SDK: 请求MIDI getMidi
  曲库SDK-->>应用App: 返回MIDI

示例项目源码

曲库的示例项目源码请参见 曲库示例项目源码

步骤1 初始化曲库组件

  1. 调用 NECopyrightedMedia.getInstance() 接口创建版权音乐对象。 示例代码如下:

    NECopyrightedMedia copyRight = NECopyrightedMedia.getInstance();
    
  2. 调用 NECopyrightedMedia.initialize 接口初始化组件。在调用 SDK 初始化接口之前,需要先为应用下的每一位用户生成user账号(account),同时获取对应的 Token。Token 鉴权相关步骤,请参考 曲库动态 Token 鉴权 即可,下文不再赘述。

    示例代码如下:

    NECopyrightedMedia copyRight = NECopyrightedMedia.getInstance();
    HashMap<String, Object> extras = new HashMap<>();
    copyRight.initialize(
        context,
        appkey,
        token,
        user,     //请传入您的应用账号体系中的账号ID,用于数据统计
        extras,
        new NECopyrightedMedia.Callback<Unit>() {
            @Override
            public void success(@Nullable Unit info) {
            Toast.makeText(
                    context,
                    "init CopyrightedMedia success",
                    Toast.LENGTH_LONG)
                .show();
            }
    
            @Override
            public void error(int code, @Nullable String msg) {
            Toast.makeText(
                    context, "init CopyrightedMedia fail", Toast.LENGTH_LONG)
                .show();
            }
        }
    );
    
  3. 调用 NECopyrightedMedia.setSongScene 接口,指定音乐场景为 K 歌的场景。

    版权曲库支持听歌场景(TYPE_LISTENING_TO_MUSIC)和 K 歌场景(TYPE_KTV),您需要在初始化曲库 SDK 后指定对应的场景。如果您的应用既需要 K 歌场景,又需要听歌场景,请在获取歌曲列表前重新调用本接口设置对应的场景即可。

    // 设置K歌场景
    NECopyrightedMedia.getInstance().setSongScene(SongScene.TYPE_KTV);
    
  4. 调用 NECopyrightedMedia.setEventHandler 接口注册事件通知回调。

    当您的曲库 Token 过期时,会触发 onTokenExpired 回调。此时,您需要参见曲库动态 Token 鉴权生成新的 Token,并调用 renewToken 更新 Token 后才能继续调用 NECopyrightedMedia SDK 的API。

    示例代码如下:

    NECopyrightedMedia.getInstance().setEventHandler(new NECopyrightedEventHandler() {
        @Override
        public void onTokenExpired() {
            // token过期监听回调
        }
    });
    
  5. 调用 NECopyrightedMedia.renewToken 接口更新Token。

    示例代码如下:

    NECopyrightedMedia.getInstance().renewToken(token);
    

    初始化操作完毕,如果能正常调用以下接口,表示初始化成功。

步骤2 获取歌曲列表

用户可以通过搜索、请求歌曲列表、榜单三种方式获取歌曲列表。

通过搜索获取歌曲

调用 NECopyrightedMedia.searchSong 接口获取搜索的歌曲列表和歌曲的song ID。

参数 类型 描述
keyword String 搜索的关键字。
channel Integer 版权渠道,默认不传则包含所有签约渠道。
  • 1:网易云音乐
  • 2: 咪咕
  • 3:HIFIVE
pageNum Integer 页码。 默认值为 0。
pageSize Integer 每页显示的行数,默认值为 20。
callback Callback 回调

示例代码如下:

NECopyrightedMedia.getInstance().searchSong(
        keyword,
        channel,
        pageNum,
        pageSize,
        new NECopyrightedMedia.Callback<List<NECopyrightedSong>>() {
            @Override
            public void error(int code, @Nullable String msg) {
                ALog.e("searchSong fail:" + msg);
            }

            @Override
            public void success(@Nullable List<NECopyrightedSong> info) {
                ALog.i("searchSong success:" + info);
            }
        });

通过请求歌曲列表获得歌曲

调用 NECopyrightedMedia.getSongList 接口获取歌曲列表和歌曲的song ID。

/**
    * 歌曲列表
    *
    * @param tags           标签
    * @param channel        版权渠道,默认不传则包含所有签约渠道。 1:云音乐, 2:咪咕,3:HIFIVE
    * @param pageNum        页码  默认值为0
    * @param pageSize       页大小 默认值为20
    * @param callback       回调[Callback]
    */
fun getSongList(
    tags: List<String>? = listOf(),
    channel: Int?,
    pageNum: Int?,
    pageSize: Int?,
    callback: Callback<List<NECopyrightedSong>>
)

示例代码如下:

NECopyrightedMedia.getInstance().getSongList(
        null,
        null,
        pageNum,
        pageSize,
        new NECopyrightedMedia.Callback<List<NECopyrightedSong>>() {
            @Override
            public void error(int code, @Nullable String msg) {
                ALog.e("getSongList fail:" + msg);
            }

            @Override
            public void success(@Nullable List<NECopyrightedSong> info) {
                ALog.i("getSongList success:" + info);
            }
        });

通过榜单获取歌曲

调用 getHotSongList 接口获取推荐歌单的歌曲 song ID。

/**
    * 热门榜单
    *
    * @param hotType           点歌榜单类型
    * @param hotDimension      榜单维度
    * @param pageNum        页码  默认值为0
    * @param pageSize       页大小 默认值为20
    * @param callback       回调[Callback]
    */
fun getHotSongList(
    hotType: NECopyrightedHotType,
    hotDimension: NECopyrightedHotDimension,
    pageNum: Int?,
    pageSize: Int?,
    callback: Callback<List<NECopyrightedHotSong>>
)

示例代码如下:

NECopyrightedMedia.getInstance().getHotSongList(NECopyrightedHotType.HOTTYPE_DEFAULT,
    NECopyrightedHotDimension.HOTDIMENSION_PLATFORM,
    pageNum,
    pageSize,
    object : NECopyrightedMedia.Callback<List<NECopyrightedHotSong>> {
        override fun success(info: List<NECopyrightedHotSong>?) {
            ALog.i("getHotSongList success:$info")
        }

        override fun error(code: Int, msg: String?) {
            ALog.e("getHotSongList fail:$msg")
        }
    })

步骤3 预加载歌曲数据

调用 NECopyrightedMedia.preloadSong 接口预加载,包括原唱、伴奏、歌词和MIDI。

/**
    * 预加载 歌曲数据
    *
    * @param songId            音乐 ID
    * @param channel           版权渠道。  1:云音乐, 2:咪咕,3:HIFIVE
    * @param callback          下载回调 [NESongPreloadCallback]
    */
fun preloadSong(songId: String, channel: Int, callback: NESongPreloadCallback)

示例代码如下:

copyRight.preloadSong(songId, channel, new NESongPreloadCallback() {

    @Override
    public void onPreloadStart(String songId, int channel) {
        ALog.i("onPreloadStart songId = " + songId);
    }

    @Override
    public void onPreloadProgress(String songId, int channel, float progress) {
        ALog.i("onPreloadProgress songId = " + songId + " progress = " + progress);
    }

    @Override
    public void onPreloadComplete(String songId, int channel, int errorCode, String msg) {
        ALog.i("onPreloadComplete songId = " + songId + ", errorCode = " + errorCode + ", msg = " +
                        msg);
    }
});

public interface NESongPreloadCallback {
    /**
     * 开始下载
     * @param songId            音乐 ID
     * @param channel           版权渠道。  1:云音乐, 2:咪咕,3:HIFIVE
     */
    void onPreloadStart(String songId, int channel);

    /**
     * 下载进度更新
     * @param songId            音乐 ID
     * @param channel           版权渠道。  1:云音乐, 2:咪咕,3:HIFIVE
     * @param progress          进度
     */
    void onPreloadProgress(String songId, int channel, float progress);

    /**
     * 下载完成
     * @param songId            音乐 ID
     * @param channel           版权渠道。  1:云音乐, 2:咪咕,3:HIFIVE
     * @param errorCode         错误码
     * @param msg               错误提示
     */
    void onPreloadComplete(String songId, int channel, int errorCode, String msg);
}

步骤4 (可选)取消预加载歌曲数据

调用 NECopyrightedMedia.cancelPreloadSong 接口取消预加载歌曲数据。

/**
    * 取消预加载 Song 数据
    *
    * @param songId            音乐 ID
    * @param channel           版权渠道。  1:云音乐, 2:咪咕,3:HIFIVE
    */
fun cancelPreloadSong(songId: String, channel: Int)

示例代码如下:

copyRight.cancelPreloadSong(songId, channel);

步骤5 检测是否已预加载歌曲数据

调用 NECopyrightedMedia.isSongPreloaded 接口检测是否已预加载歌曲数据。

/**
    * 检测是否已预加载 Song 数据
    *
    * @param songID            音乐 ID
    * @param channel           版权渠道。  1:云音乐, 2:咪咕,3:HIFIVE
    * @return
    */
fun isSongPreloaded(songID: String): Boolean

示例代码如下:

copyRight.isSongPreloaded(songId, channel);

步骤6 生成歌曲 URI

App 客户端在 preloadSong 成功之后,调用 NECopyrightedMedia.getSongURI 将原唱&伴奏传给 NERtc 进行播放。

/**
    * 原唱&伴奏:用于播放的本地文件路径
    *
    * @param songId           音乐 ID
    * @param channel          版权渠道。  1:云音乐, 2:咪咕,3:HIFIVE
    * @param songResType      资源类型 1:原唱,2:伴奏
    * @return
    */
fun getSongURI(songId: String, channel: Int, songResType: SongResType): String?

示例代码如下:

String typeOriginPath = NECopyrightedMedia.getInstance().getSongURI(model.getSongId(), model.getChannel(), SongResType.TYPE_ORIGIN);
String typeAccPath = NECopyrightedMedia.getInstance().getSongURI(model.getSongId(), model.getChannel(), SongResType.TYPE_ACCOMP);

步骤7 获得歌词

App 客户端在 preloadSong 成功之后,调用 NECopyrightedMedia.getLyric 获取歌词。

/**
    * 本地歌词
    * @param songId           音乐 ID
    * @param channel          版权渠道。  1:云音乐, 2:咪咕,3:HIFIVE
    * @return
    */
fun getLyric(songId: String, channel: Int): String?

示例代码如下:

String lyric = NECopyrightedMedia.getInstance().getLyric(songId, channel);

步骤8 获得打分 MIDI

App 客户端在 preloadSong 成功之后,调用 NECopyrightedMedia.getPitch 获取MIDI。

/**
    * 本地MIDI
    * @param songId           音乐 ID
    * @param channel          版权渠道。  1:云音乐, 2:咪咕,3:HIFIVE
    * @return
    */
fun getPitch(songId: String, channel: Int): String?

示例代码如下:

String midiContent = NECopyrightedMedia.getInstance().getMidi(songId, channel);

步骤9 预加载歌词内容

调用 NECopyrightedMedia.preloadSongLyric 接口单独加载歌词。

/**
    * 加载歌词
    *
    * @param songId           音乐 ID
    * @param channel          版权渠道。  1:云音乐, 2:咪咕,3:HIFIVE
    * @param callback         加载歌词回调 [LyricCallback]
    */
fun preloadSongLyric(songId: String, channel: Int, callback: LyricCallback)

示例代码如下:

NECopyrightedMedia.getInstance().preloadSongLyric(songId, channel, new LyricCallback() {

    @Override
    public void success(@NonNull String content, @Nullable String type, channel: Int) {
        KaraokeLog.i(TAG, "loadLyric success 歌词的具体内容 = " + content + " 歌词类型 = " + type);
    }

    @Override
    public void error(int code, @Nullable String msg) {
        KaraokeLog.i(TAG, "loadLyric error code = " + code + " " + msg);
    }
});

步骤10 使用 NERTC 播放并发送音乐

  1. 调用 NECopyrightedMedia.preloadSong 接口预加载歌词。
  2. 加载成功后,加入音视频房间,调用 NERTC 的 playEffect 接口播放音乐。

更详细的示例代码请参考曲库示例项目源码

示例代码如下:

long position = System.currentTimeMillis() + 3 * 1000;
NERtcCreateAudioEffectOption optPure = new NERtcCreateAudioEffectOption();
NERtcCreateAudioEffectOption optOriginalSong = new NERtcCreateAudioEffectOption();

optPure.path = NECopyrightedMedia.getInstance().getSongURI(songId, channel, SongResType.TYPE_ACCOMP);  //纯伴奏音乐路径
optPure.loopCount = 1;
optPure.sendEnabled = true;
optPure.sendWithAudioType = NERtcAudioStreamType.kNERtcAudioStreamTypeMain; //伴奏以主流方式发送
optPure.startTimestamp = position;

optOriginalSong.path = NECopyrightedMedia.getInstance().getSongURI(songId, channel, SongResType.TYPE_ORIGIN);  //带原声音乐路径
optOriginalSong.loopCount = 1;
optOriginalSong.sendEnabled = true;
optOriginalSong.sendWithAudioType = NERtcAudioStreamType.kNERtcAudioStreamTypeMain; //原唱以主流的方式发送
optOriginalSong.startTimestamp = position;

// 调用以下代码会播放并上行伴奏:
optPure.sendVolume = 发送音量;  
optPure.playbackVolume = 播放音量;  
optOriginalSong.sendVolume = 0; 
optOriginalSong.playbackVolume = 0; 

// 调用以下代码会播放并上行原唱:
optPure.sendVolume = 0;  
optPure.playbackVolume = 0;  
optOriginalSong.sendVolume = 发送音量; 
optOriginalSong.playbackVolume = 播放音量; 

NERtcEx.getInstance().playEffect(optPureEffectId, optPure);  //optPureEffectId 自己定义的伴奏effect id
NERtcEx.getInstance().playEffect(optOriginalEffectId, optOriginalSong); //optOriginalEffectId 自己定义的原唱effect id

NERtcEx.getInstance().stopEffect(optPureEffectId);  // 关闭播放伴奏(切换下一首需要先关闭播放)
NERtcEx.getInstance().stopEffect(optOriginalEffectId); // 关闭播放原唱(切换下一首需要先关闭播放)
此文档是否对你有帮助?
有帮助
去反馈
  • 注意事项
  • 前提条件
  • API 时序图
  • 示例项目源码
  • 步骤1 初始化曲库组件
  • 步骤2 获取歌曲列表
  • 通过搜索获取歌曲
  • 通过请求歌曲列表获得歌曲
  • 通过榜单获取歌曲
  • 步骤3 预加载歌曲数据
  • 步骤4 (可选)取消预加载歌曲数据
  • 步骤5 检测是否已预加载歌曲数据
  • 步骤6 生成歌曲 URI
  • 步骤7 获得歌词
  • 步骤8 获得打分 MIDI
  • 步骤9 预加载歌词内容
  • 步骤10 使用 NERTC 播放并发送音乐