版权音乐
更新时间: 2024/11/26 15:44:05
网易云信支持独立集成版权音乐,实现在线 KTV 场景中搜索、下载和播放版权音乐的能力。
注意事项
前提条件
请确认您已完成以下操作:
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];
-
调用
initialize
接口初始化组件。
/// 初始化 NECopyrightedMedia
/// @param appkey appkey
/// @param token token
/// @param userUuid userUuid
/// @param extras 填入Nil
/// @param callback 异步回调 NSError 为Nil 则成功
- (void)initialize:(NSString *_Nonnull)appkey
token:(NSString *_Nonnull)token
userUuid:(NSString *_Nullable)userUuid
extras:(NSDictionary *_Nullable)extras
callback:(void (^)(NSError *_Nullable error))callback;
-
调用
NECopyrightedMedia.setSongScene
接口,指定音乐场景为 K 歌的场景。版权曲库支持听歌场景(TYPE_LISTENING_TO_MUSIC)和 K 歌场景(TYPE_KTV),您需要在初始化曲库 SDK 后指定对应的场景。如果您的应用既需要 K 歌场景,又需要听歌场景,请在获取歌曲列表前重新调用本接口设置对应的场景即可。
// 设置K歌场景 NECopyrightedMedia.getInstance().setSongScene(TYPE_KTV)
-
调用
setEventHandler
接口注册事件通知回调。当您的曲库 Token 过期时,会触发
onTokenExpired
回调。此时,您需要参见曲库动态 Token 鉴权生成新的 Token,并调用renewToken
更新 Token 后才能继续调用 NECopyrightedMedia SDK 的API。//设置动态Token过期代理 [[NECopyrightedMedia getInstance] setEventHandler:self]; //回调如下 - (void)onTokenExpired { // Token过期 //此处需要申请新的realTimeToken }
-
调用
renewToken
接口更新 Token。[[NECopyrightedMedia getInstance] renewToken:copyrightedToken];
初始化操作完毕,如果能正常调用以下接口,表示初始化成功。
步骤2 获取歌曲列表
用户可以通过搜索、请求歌曲列表两种方式获取歌曲列表。
通过搜索获取歌曲
调用 NECopyrightedMedia.searchSong
接口获取搜索的歌曲列表和歌曲的song ID。
参数 | 类型 | 描述 |
---|---|---|
keyword | String | 搜索的关键字。 |
channel | Integer | 版权渠道,默认不传则包含所有签约渠道。
|
pageNum | Integer | 页码。 默认值为 0。 |
pageSize | Integer | 每页显示的行数,默认值为 20。 |
callback | Callback | 回调 |
示例代码如下:
[[NECopyrightedMedia getInstance]
searchSong:keyword
channel:nil
pageNum:pageNum
pageSize:pageSize
callback:^(NSArray<NECopyrightedSong *> *_Nonnull songList, NSError *_Nonnull error) {
if (error) {
NSLog(@"搜索歌曲列表失败 --- %@", error.description);
} else {
NSLog(@"搜索歌曲列表成功");
}
}]
通过推荐获取歌曲
调用getSongList
接口获取推荐歌单的歌曲 song ID。
/**
* 歌曲列表
* @param tags 设置nil 预留字段
* @param channel 版权渠道,默认不传则包含所有签约渠道。1:网易云音乐; 2: 咪咕;3:HIFIVE
* @param pageNum 页码
* @param pageSize 页面size 默认 20
* @param callback 回调
*/
- (void)getSongList:(NSArray<NSString *> *_Nullable)tags
channel:(NSNumber *_Nullable)channel
pageNum:(NSNumber *_Nullable)pageNum
pageSize:(NSNumber *_Nullable)pageSize
callback:(void (^)(NSArray<NECopyrightedSong *> *songList, NSError *error))callback;
示例代码如下:
[[NECopyrightedMedia getInstance] getSongList:nil channel:nil pageNum:@(0) pageSize:@(NEPageNumber) callback:^(NSArray<NECopyrightedSong *> * _Nonnull songList, NSError * _Nonnull error) {
if (error) {
NSLog(@"获取歌曲列表失败");
}else{
NSLog(@"获取歌曲列表成功");
for (NECopyrightedSong *songItem in songList) {
//遍历数据
NSLog(@"songDta --- %@",songItem);
}
}
}];
通过榜单获取歌曲
调用getHotSongList
接口获取推荐歌单的歌曲 song ID。
/**
* 榜单歌曲查询
* @param hotType 热门类型
* @param hotDimension 场景类型
* @param channel 渠道 SongChannel: 可为空
* @param pageNum 页码
* @param pageSize 页面size 默认 20
* @param callback 回调
*/
- (void)getHotSongList:(NECopyrightedHotType)hotType
hotDimension:(NECopyrightedHotDimension)hotDimension
channel:(NSNumber *_Nullable)channel
pageNum:(NSNumber *_Nullable)pageNum
pageSize:(NSNumber *_Nullable)pageSize
callback:
(void (^)(NSArray<NECopyrightedHotSong *> *songList, NSError *error))callback;
示例代码如下:
[[NECopyrightedMedia getInstance] getHotSongList:HOTTYPE_DEFAULT channel:@1 hotDimension:HOTDIMENSION_PLATFORM pageNum:@0 pageSize:@20 callback:^(NSArray<NECopyrightedHotSong *> * _Nonnull songList, NSError * _Nonnull error) {
if (error) {
NSLog(@"获取歌曲列表失败");
}else{
NSLog(@"获取歌曲列表成功");
for (NECopyrightedSong *songItem in songList) {
//遍历数据
NSLog(@"songDta --- %@",songItem);
}
}
}];
步骤3 下载歌曲资源
调用 preloadSong
接口下载歌曲资源,包括原唱、伴奏、歌词和MIDI。
/**
* 预加载 Song 数据
*
* @param songId 歌曲id
* @param channel 渠道
* @param observe 观察者
*/
- (void)preloadSong:(NSString *)songId
channel:(SongChannel)channel
observe:(id<NESongPreloadProtocol> _Nullable)observe;
示例代码如下:
//遵循协议:
<NESongPreloadProtocol>
//请求示例:
[[NECopyrightedMedia getInstance] preloadSong:songModel.songId channel:CLOUD_MUSIC observe:self];
//请求回调:
//开始下载回调
-(void)onPreloadStart:(NSString *)songId channel:(SongChannel)channel{
NSLog(@"onPreloadStart -- songId = %@",songId);
}
//下载进度回调
-(void)onPreloadProgress:(NSString *)songId channel:(SongChannel)channel progress:(float)progress{
NSLog(@"onPreloadProgress -- songId = %@ ; progress = %.2f",songId,progress);
}
//下载失败/完成回调
-(void)onPreloadComplete:(NSString *)songId channel:(SongChannel)channel error:(NSError * _Nullable)error{
if(error){
NSLog(@"onPreloadComplete error reason:%@",error.description);
}else{
NSLog(@"onPreloadComplete")
}
}
步骤4 取消预加载歌曲数据
调用cancelPreloadSong
接口取消预加载歌曲数据。
/// 取消预加载 Song 数据
/// @param songId 歌曲id
/// @param channel 渠道 需要是songId对应的渠道
- (void)cancelPreloadSong:(NSString *)songId channel:(SongChannel)channel;
示例代码如下:
[[NECopyrightedMedia getInstance]cancelPreloadSong:songItem.songId channel:songItem.channel];
步骤5 检测是否已预加载歌曲数据
调用isSongPreloaded
接口检测是否已预加载歌曲数据。
/**
* 检测是否已预加载 Song 数据
*
* @param songId 歌曲id
* @param channel 版权渠道,1:网易云音乐; 2: 咪咕;3:HIFIVE
* @return 是否已预加载
*/
- (bool)isSongPreloaded:(NSString *)songId channel:(SongChannel)channel;
示例代码如下:
[[NECopyrightedMedia getInstance] isSongPreloaded:songItem.songId channel:songItem.channel];
步骤6 生成歌曲 URI
调用 getSongURI
获取 伴奏/原唱 的本地路径
/**
* 原唱&伴奏:传给 NERtc 播放的 URI
*
* @param songId 音乐 ID
* @param channel 版权渠道,1:网易云音乐; 2: 咪咕;3:HIFIVE
* @param songResType 1:原唱,2:伴奏
* @return 返回资源的本地路径
*/
- (NSString *_Nullable)getSongURI:(NSString *_Nonnull)songId
channel:(SongChannel)channel
songResType:(SongResType)songResType;
示例代码如下:
return [[NECopyrightedMedia getInstance] getSongURI:songItem.songId channel:songItem.channel songResType:SongResType];
步骤7 获得歌词内容
调用getLyric
获取加载完成后的歌词内容
/**
* 歌词
* @param songId 音乐 ID
* @param channel 版权渠道,1:网易云音乐; 2: 咪咕;3:HIFIVE
* @return 歌词内容
*/
- (NSString *_Nullable)getLyric:(NSString *_Nonnull)songId channel:(SongChannel)channel;
示例代码如下:
[[NECopyrightedMedia getInstance] getLyric:songItem.songId channel:songItem.channel];
步骤8 获得打分内容
调用getMidi
获取加载完成后的打分内容
/**
* 打分
* @param songId 音乐 ID
* @param channel 版权渠道,1:网易云音乐; 2: 咪咕;3:HIFIVE
* @return 打分内容
*/
- (NSString *_Nullable)getPitch:(NSString *_Nonnull)songId channel:(SongChannel)channel;
示例代码如下:
[[NECopyrightedMedia getInstance] getPitch:songItem.songId channel:songItem.channel];
步骤9 预加载歌词内容
调用preloadSongLyric
接口单独加载歌词
/// 预加载歌词
/// @param songId 音乐ID
/// @param callback 回调
- (void)preloadSongLyric:(NSString *)songId
channel:(SongChannel)channel
callback:(void (^)(NSString *_Nullable content, NSString *_Nullable lyricType,
NSError *_Nullable error))callback;
示例代码如下:
[[NECopyrightedMedia getInstance] preloadSongLyric:songModel.songId channel:songItem.channel callback:^(NSString * _Nullable content, NSString * _Nullable lyricType, NSError * _Nullable error) {
if (error) {
NSLog(@"下载歌词失败");
}else{
NSLog(@"下载歌词成功");
}
}];
步骤10 使用 NERTC 播放并发送音乐
- 调用
preloadSong
接口预加载歌词。 - 加载成功后,加入音视频房间,调用 NERTC 的
playEffectWitdId
接口播放音乐。
示例代码如下:
更详细的示例代码请参考曲库示例项目源码。
// 调用以下代码会播放并上行伴奏:
NERtcCreateAudioEffectOption *aOption = [[NERtcCreateAudioEffectOption alloc] init];
aOption.path = accompanyPath;
aOption.playbackVolume = 播放音量;
aOption.sendVolume = 发送音量;
aOption.sendEnabled = true;
aOption.loopCount = 1;
aOption.sendWithAudioType = kNERtcAudioStreamTypeMain;
int aCode = [[NERtcEngine sharedEngine] playEffectWitdId:optPureEffectId effectOption:aOption];//optPureEffectId 自己定义的伴奏effect id
// 调用以下代码会播放并上行原唱:
NERtcCreateAudioEffectOption *oOption = [[NERtcCreateAudioEffectOption alloc] init];
oOption.path = originalPath;
oOption.playbackVolume = aCode == 0 ? 0 : 播放音量; // 如果伴奏播放失败则播放原唱
oOption.sendVolume = aCode == 0 ? 0 : 发送音量;
oOption.sendEnabled = true;
oOption.loopCount = 1;
oOption.sendWithAudioType = kNERtcAudioStreamTypeMain;
[[NERtcEngine sharedEngine] playEffectWitdId:optPureEffectId effectOption:aOption]; //optOriginalEffectId 自己定义的原唱effect id