最近工作中遇到一个需求。我需要做一个在线音乐APP,通过一段时间的努力已经实现了。所以本文主要介绍一个如何在iOS中使用AVPlayer播放在线音乐的教程。文章中的介绍很详细,有需要的朋友可以参考一下。让我们一起来看看吧。
前言
如果你要做一个像百度音乐、豆瓣电台这样的在线音乐APP,你会怎么做?
首先了解一下音频播放的实现级别:
(1)离线播放:这里不是指应用程序不联网,而是播放本地的音频文件,包括先下载音频文件再播放。这可以通过在AVFoundation中使用AVAudioPlayer来满足。
(2)在线播放:使用AVFoundation的AVPlayer即可满足要求
(3)同时播放在线商店文件:可以使用音频文件流媒体工具+音频队列。
(4)带声音处理的在线播放:使用音频文件流器+音频队列+声音模块(系统自带或自研)满足要求。
本文主要针对第二个层面,介绍如何使用AVPlayer播放在线音乐。
什么是AVPlayer
AVFoundation中存在AVPlayer。其实是个视频播放器,不过用它放音乐还是可以的。当然,播放音乐不需要接口,所以我们不需要实现它的接口。
跟AVPlayer联系密切的名词:
Asset:AVAsset是一个抽象类,不能直接使用。它的子类AVURLAsset可以根据URL生成包含媒体信息的资产对象。
AVPlayerItem:与媒体资源有对应关系,管理媒体资源的信息和状态。
功能需求
通常,在界面上播放和显示音乐时,我们需要实现的功能如下:
1.(核心)播放器通过网络链接播放音乐。
2.(基础)播放器常见操作:暂停、播放、上一首、下一首等。
3.(基本)监控音乐的播放进度、获取音乐的总时间和当前播放时间。
4.(基本)监控和更改播放器状态:
(1)媒体加载状态
(2)数据缓冲状态
(3)播放完毕的状态。
5.(可选)遥控器控制音乐的播放。
6.(可选)现在播放中心显示正在播放的音乐。
功能实现
1、通过一个网络链接播放音乐
NSURL * URL=[NSURL URL with string:self . current song . URL];
AVPlayerItem * song item=[[AVPlayerItem alloc]init with URL:URL];
av player * player=[[av player alloc]initWithPlayerItem:song item];
这里,一个资产被用来初始化播放器,当然,你也可以用URL直接初始化它:
av player * player=[[av player alloc]init with URL:URL];
要获取当前播放的项目,您可以像这样获取:
AVPlayerItem * song item=player . current item;
2、播放器的常用操作
播放:
【玩家玩法】;
需要注意的是,初始化播放器后,可能不会立即开始播放。您需要等待播放器的状态变为ReadyToPlay才能播放。
暂停:
【玩家暂停】;
上一页,下一页:
有两种方法可以实现这一点。一种是自己控制下一首歌的项,用当前播放的项替换。
[player replacecurrentitetemwithplayeritem:song item];
另一种是使用AVPlayer的子类AVQueuePlayer播放多项,调用advanceToNextItem播放下一首音乐。
NSArray * items=@[item1,item2,item3.];
AVQueuePlayer * queue player=[[AVQueuePlayer alloc]initwitheitems:items];
3、监听播放进度
使用addperiodtimeobserver服务:queue: using block:来监控播放器的进度。
(1)方法传入一个CMTime结构,每隔一定时间会回调一次,包括播放的开始和结束。
(2)如果块内操作时间过长,下次可能得不到回调,尽量减少块的操作时间。
(3)该方法将返回一个observer对象,回放结束时需要移除该对象。
添加观察员:
id time observe=[self . player addperiodictimeobserverforinterval:cmtimemake(1.0,1.0)queue:dispatch _ get _ main _ queue()usingblock:^(cmtime时间){
浮充电流=CMTimeGetSeconds(时间);
float total=CMTimeGetSeconds(song item . duration);
如果(当前){
weakSelf.progress=当前/总计;
软弱的自己。playtime=[ns string字符串格式:@ % .f ,当前];
软弱的自己。播放时长=[ns字符串字符串格式:@ %。2f ,合计];}
}];
移除观察者:
如果(时间观察){
[玩家移除时间观察者:_时间观察者];
时间观察=零
}
4、监听改播放器状态
(1) 媒体加载状态
[song item add observer:self forkey path:@ status options:nskeyvalueobservingoptions新上下文:nil];
然后可以在KVO方法中获取其状态的改变
-(void)observeValueForKeyPath:(ns string *)对象的关键路径:(id)对象更改:(NSDictionaryNSString *,id *)更改上下文:(void *)上下文{
if([key path is equal tostring:@ status ]){
switch (self.player.status) {
案例AVPlayerStatusUnknown:
BASE_INFO_FUN(@KVO:未知状态,此时不能播放);
打破;
案例AVPlayerStatusReadyToPlay:
自我。status=SUPlayStatusReadyToPlay;
BASE_INFO_FUN(@KVO:准备完毕,可以播放);
打破;
案例AVPlayerStatusFailed失败:
BASE_INFO_FUN(@KVO:加载失败,网络或者服务器出现问题);
打破;
默认值:
打破;
}
}
}
一般初始化运动员到播放都会经历未知的到随时可以玩这个过程,网络情况良好时可能不会出现未知的状态的提示,网络情况差的时候未知的的状态可能会持续比较久甚至可能不进入随时可以玩状态,针对这种情况我们要做特殊的处理。
播放完成之后需要移除观察者:
[歌曲项移除观察者:自身forkey路径:@ status ];
(2) 数据缓冲状态
[song item addObserver:self for key path:@ loaded time ranges options:nskeyvalueobservingoption new context:nil];
然后可以在KVO方法中获取其状态的改变
-(void)observeValueForKeyPath:(ns string *)对象的关键路径:(id)对象更改:(NSDictionaryNSString *,id *)更改上下文:(void *)上下文{
AVPlayerItem * songItem=object
if([key path is equal tostring:@ loadedTimeRanges ]){
NSArray * array=song item。loadedtimeranges
CMTimeRange时间范围=[array。第一个对象CMTimeRangeValue];//本次缓冲的时间范围
NSTimeInterval总缓冲区=CMTimeGetSeconds(时间范围。start)CMTimeGetSeconds(时间范围。持续时间);//缓冲总长度
苏洛格(@ 共缓冲%.2f ,总缓冲);
}
}
如果你需要在进度条展示缓冲的进度,可以增加这个观察者。
播放完成之后需要移除观察者:
[song item remove observer:self forkey path:@ loadedTimeRanges ];
(3) 播放完毕状态
监听AVPlayer播放完成通知
[[NSNotificationCenter默认中心]添加观察者:自身选择器:@ selector(播放完毕:)名称:AVPlayerItemDidPlayToEndTimeNotification对象:歌曲项];
-(无效)回放完成:(NSNotification *)通知{
BASE_INFO_FUN(@ 播放完成);
【自玩下一个】;
}
播放完毕后,一般都会进行播放下一首的操作。
播放下一首前,别忘了移除这个项目的观察者:
[[NSNotificationCenter默认中心]删除观察者:自己];
5、Remote Control控制音乐的播放
远程控制可以让你在不打开应用的情况下控制其播放,最常见的出现于锁屏界面、从屏幕底部上拉和耳机线控三种,可以达到增强用户体验的作用。
我们在应用委托里去设置远程控制:
(1)声明接收远程控制事件
[[ui应用程序共享应用程序]beginReceivingRemoteControlEvents];
(2)重写方法,成为第一响应者
-(BOOL)canBecomeFirstResponder {
返回是
}
(3)对事件进行处理
-(void)remoteControlReceivedWithEvent:(ui事件*)事件{
开关(event.subtype) {
案例UIEventSubtypeRemoteControlPlay:
【自我。【玩家开始玩】;
BASE_INFO_FUN(@"remote_播放);
打破;
案例UIEventSubtypeRemoteControlPause:
【自我。【玩家暂停播放】;
BASE_INFO_FUN(@remote_暂停);
打破;
案例uieventsubtyperemotecontcontrolnexttrack:
【自我。【播放器播放下一首歌】;
BASE_INFO_FUN(@remote_下一首);
打破;
案例UIEventSubtypeRemoteControlTogglePlayPause:
self.player.isPlaying?【self . player pause play】:【self . player start play】;
base _ info _ fun(@“Remote _ Headset的播放/暂停”);
打破;
默认值:
打破;}
}
6、Now Playing Center
现在Playing Center可以在锁屏界面显示音乐信息,也提升了用户体验。
-(void)ConfigNowPlayingCenter { base _ info _ fun(@ Configure NowPlayingCenter );
NSMutableDictionary * info=[NSMutableDictionary字典];
//音乐的标题
[info set object:_ player . current song . title forKey:mpmediaitempropertyttitle];
//音乐的艺术家
[info set object:_ player . current song . artist forKey:mpmediaitempropertymartist];
//音乐的播放时间
[info set object:@(self . player . play time . int value)forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime];
//音乐的播放速度
[info set object:@(1)forKey:MPNowPlayingInfoPropertyPlaybackRate];
//音乐的总时间
[info set object:@(self . player . play duration . int value)forKey:MPMediaItemPropertyPlaybackDuration];
//音乐的封面
mpmediaitem artwork * artwork=[[mpmediaitem artwork alloc]init with image:_ player . cover img];
[info set object:artwork forKey:mpmediaitemproperty artwork];
//完成安装
[[mpnowplayingfocenter default center]setNowPlayingInfo:info];
}
现在打中锋不需要每秒刷新(设置)。它根据您设置的播放速率计算进度条显示的进度。例如,如果您发送播放速率1,它将每秒刷新进度显示。当然,播放暂停时会自动暂停。
什么时候设立Now Playing Center比较合适?播放在线音乐,有几个时间点需要刷新:当前播放的歌曲发生变化的时候(比如切换到下一首歌曲),当前歌曲的信息发生变化的时候(比如从未知到ReadyToPlay),当前歌曲拖动的时候。
如果有读者用百度音乐听歌,会发现它已经锁屏歌词了。其实就是通过“把歌词和封面设置成新的画面作为现在播放中心的封面+歌词跃进时刷新现在播放中心”来实现的。感兴趣的包可以研究一下。
论整体游戏逻辑
总结音乐播放器的播放逻辑:
(1)初始化播放界面
(2)从界面获取播放列表,选择第一首歌曲作为当前播放歌曲
(3)根据当前歌曲初始化播放器,将歌曲信息同步到播放界面(此时播放界面应显示歌曲信息,但播放按钮应不可用并有加载等提示表示正在加载歌曲),将歌曲信息同步到正在播放中心。
(4)当播放器状态变为ReadyToPlay时,播放歌曲,同步播放信息到播放界面(播放时间、总时间、进度条等。),并将信息同步播放到Now Playing Center。
(5)当用户暂停时,刷新播放界面。
(6)当用户执行下一个或上一个操作或播放完某首歌曲时,将对应的歌曲设置为当前播放的歌曲,重复步骤3-5。
(7)当播放器因网络条件不好而自动停止播放时,应刷新播放界面。
(8)如因网络情况不好导致播放器无法进入播放状态,应进行处理(如提示耐心等待或播放本地离线歌曲)
后记
本文仅从实现基本功能的角度介绍AVPlayer播放在线音乐的实现。其实AVPlayer的功能不止于此,有兴趣的同学可以深入研究一下AVFoundation。
好了,这就是本文的全部内容。希望这篇文章的内容能给你的学习或者工作带来一些帮助。有问题可以留言交流。谢谢你的支持。