版权音乐
更新时间: 2024/11/26 15:44:05
网易云信支持独立集成版权音乐,实现在线 KTV 场景中搜索、下载和播放版权音乐的能力。
注意事项
- 使用版权音乐时,请务必在播放界面明显位置用图标说明该音乐内容对应的版权方,界面效果类似如下图所示。版权Logo的图标请参考曲库示例项目源码。
- 您可以通过 getChannel 接口查询音乐的版权方。
前提条件
请确认您已完成以下操作:
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 初始化曲库组件
-
调用
NECopyrightedMedia.getInstance()
接口创建版权音乐对象。 示例代码如下:NECopyrightedMedia copyRight = NECopyrightedMedia.getInstance();
-
调用
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(); } } );
-
调用
NECopyrightedMedia.setSongScene
接口,指定音乐场景为 K 歌的场景。版权曲库支持听歌场景(TYPE_LISTENING_TO_MUSIC)和 K 歌场景(TYPE_KTV),您需要在初始化曲库 SDK 后指定对应的场景。如果您的应用既需要 K 歌场景,又需要听歌场景,请在获取歌曲列表前重新调用本接口设置对应的场景即可。
// 设置K歌场景 NECopyrightedMedia.getInstance().setSongScene(SongScene.TYPE_KTV);
-
调用
NECopyrightedMedia.setEventHandler
接口注册事件通知回调。当您的曲库 Token 过期时,会触发
onTokenExpired
回调。此时,您需要参见曲库动态 Token 鉴权生成新的 Token,并调用renewToken
更新 Token 后才能继续调用 NECopyrightedMedia SDK 的API。示例代码如下:
NECopyrightedMedia.getInstance().setEventHandler(new NECopyrightedEventHandler() { @Override public void onTokenExpired() { // token过期监听回调 } });
-
调用
NECopyrightedMedia.renewToken
接口更新Token。示例代码如下:
NECopyrightedMedia.getInstance().renewToken(token);
初始化操作完毕,如果能正常调用以下接口,表示初始化成功。
步骤2 获取歌曲列表
用户可以通过搜索、请求歌曲列表、榜单三种方式获取歌曲列表。
通过搜索获取歌曲
调用 NECopyrightedMedia.searchSong
接口获取搜索的歌曲列表和歌曲的song ID。
参数 | 类型 | 描述 |
---|---|---|
keyword | String | 搜索的关键字。 |
channel | Integer | 版权渠道,默认不传则包含所有签约渠道。
|
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 播放并发送音乐
- 调用
NECopyrightedMedia.preloadSong
接口预加载歌词。 - 加载成功后,加入音视频房间,调用 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); // 关闭播放原唱(切换下一首需要先关闭播放)