标签:循环 object users last nis lock 名称 后台播放 mtime
下载地址:AVPlayer播放网络音乐
1、(核心)播放器通过一个网络链接播放音乐
2、(基本)播放器的常用操作:暂停、播放、上一首、下一首等等
3、(基本)监听该音乐的播放进度、获取音乐的总时间、当前播放时间
4、(基本)监听改播放器状态:
?????(1)媒体加载状态
?????(2)数据缓冲状态
?????(3)播放完毕状态
5、(可选)Remote Control控制音乐的播放
6、(可选)Now Playing Center展示正在播放的音乐
我自己写了一个管理类 (里面封装了大部分播放逻辑)
已完成功能:播放、暂停、上下一首、单曲循环、随机播放、后台播放、锁屏信息。
第一次写这种管理类,可能会有点复杂,不太容易看懂 。 我把歌曲的信息也存在里面了。
.h 文件
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
#import "SongsMessageModel.h"
typedef NS_ENUM(NSInteger, playerType) {
AVPlayerTypeNormal = 0, //正常循环播放状态
AVPlayerTypeRandom, //随机播放
AVPlayerTypeSingle, //单曲循环
};
/**返回缓冲进度*/
typedef void(^loadTime)(NSString *str);
/**返回 当前进度、总时长、slider 最大值和当前值*/
typedef void(^returnTime)(NSString *current,NSString *total,float max,float value);
/**返回 AVPlayerItem的序号(换背景图、歌手、歌曲)*/
typedef void(^returnImage)(NSInteger index);
@interface AVPlayerManager : NSObject
/**存放AVplayerItem的数组*/
@property(nonatomic,strong)NSMutableArray *musicArray;
//**歌曲地址数组*/
@property(nonatomic,strong)NSMutableArray *songArray;// 是否进入的已存在的歌单!
/**海报数组*/
@property(nonatomic,strong)NSMutableArray *imageArray;
/**歌手数组*/
@property(nonatomic,strong)NSMutableArray *singerArray;
/**歌曲名数组*/
@property(nonatomic,strong)NSMutableArray *songNameArray;
/**AVPlayer播放器*/
@property (nonatomic, strong) AVPlayer *player;
/**播放模式*/
@property (nonatomic,assign) NSInteger playerType;
/**当前播放时间*/
@property(nonatomic,assign) float currentPlayTime;
/**当前缓冲时间*/
@property(nonatomic,assign)NSTimeInterval currentLoadTime;
/**slider最大值*/
@property(nonatomic,assign) float silderMaxValue;
/**slider当前值*/
@property(nonatomic,assign) float silderValue;
/***/
@property(nonatomic,strong) NSString *playTime;
/**总时长*/
@property(nonatomic,strong) NSString *totalTime;
/**缓冲提示*/
@property(nonatomic,strong) NSString *loadTime;
@property(nonatomic,strong)loadTime block;
@property(nonatomic,strong)returnTime block1;
@property(nonatomic,strong) returnImage block2;
/**通知 获取当前播放状态 控制按钮状态*/
@property(nonatomic,strong) NSNotificationCenter * center;
/**判断是否是从歌单列表进入播放器 还是 直接在进入播放器*/
@property(nonatomic,assign) BOOL listInto;
+ (instancetype)shareManager;
//**播放*/
- (void)musicPlayerWithArray:(NSArray *)musicArray andIndex:(NSInteger )index;
//**正在播放时 播放指定歌曲, */
- (void)musicPlayerWithIndex:(NSInteger )index;
//*播放
-(void)playMusic;
//*暂停
-(void)pasueMusic;
//**下一首*/
- (void)nextSong;
//**上一首*/
- (void)lastSong;
//**进度条 调节 */
- (void)playerProgressWithProgressFloat:(CGFloat)progressFloat;
//**移除观察者*/
-(void)removeObserver;
/**获取当前播放序号*/
-(NSInteger )getcurrentItem;
.m 文件
#import "AVPlayerManager.h"
#import <MediaPlayer/MediaPlayer.h>
@implementation AVPlayerManager
{
id timeObserve;// 为 当前AVPlayerItem 添加观察者获取各种播放状态
}
+(instancetype)shareManager{
static AVPlayerManager *manager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [AVPlayerManager new];
});
return manager;
}
-(instancetype)init{
if (self =[super init]) {
_playerType = AVPlayerTypeNormal;
}
return self;
}
//播放器懒加载
-(AVPlayer *)player{
if (!_player) {
_player = [AVPlayer new];
}
return _player;
}
-(NSMutableArray *)musicArray{
if (!_musicArray) {
_musicArray = [NSMutableArray array];
_center = [NSNotificationCenter defaultCenter];
}
return _musicArray;
}
//播放指定url
- (void)musicPlayerWithURL:(NSURL *)playerItemURL{
//创建要播放的资源
AVPlayerItem *playerItem = [[AVPlayerItem alloc]initWithURL:playerItemURL];
//添加观察者
//播放当前资源
[self.player replaceCurrentItemWithPlayerItem:playerItem];
}
-(void)musicPlayerWithIndex:(NSInteger)index{
// 播放AVPlayerItem数组中指定序号歌曲 (此操作之前需要将上一个item 的 观察者移除 并将 seekTime 设置为0 确保下次播放从头开始)
[self.player replaceCurrentItemWithPlayerItem:self.musicArray[index]];
self.block2([self.musicArray indexOfObject:self.player.currentItem]);
[self addObserver];
}
//重新添加新的歌单列表进来
- (void)musicPlayerWithArray:(NSArray *)musicArray andIndex:(NSInteger )index{
//首先移除之前的歌单列表 再 重新添加
[self.songArray removeAllObjects];
[self.songArray addObjectsFromArray:musicArray];
for (NSString * obj in musicArray) {
AVPlayerItem *songItem = [[AVPlayerItem alloc] initWithURL:[NSURL URLWithString:obj]];
[self.musicArray addObject:songItem];
}
//播放歌单列表序号对应的歌曲
[self.player replaceCurrentItemWithPlayerItem:self.musicArray[index]];
//对当前item 添加观察者
[self addObserver];
}
//播放
-(void)playMusic{
[self.player play];
}
//暂停
-(void)pasueMusic{
[self.player pause];
}
//上一首
-(void)lastSong{
[self removeObserver];//先移除当前 观察者
[self.player.currentItem seekToTime:(kCMTimeZero) completionHandler:^(BOOL finished) {
if (self.playerType == AVPlayerTypeNormal) {//顺序循环播放
//判断当前歌曲是否是第一首歌曲,如果是跳转到最后一首歌
if ([self.musicArray indexOfObject:self.player.currentItem] ==0) {
[self.player replaceCurrentItemWithPlayerItem:self.musicArray.lastObject];
}else{
[self.player replaceCurrentItemWithPlayerItem:self.musicArray[[self.musicArray indexOfObject:self.player.currentItem]-1]];
}
}else if (self.playerType == AVPlayerTypeRandom){//随机播放
NSInteger random = arc4random_uniform((int)self.musicArray.count);
NSLog(@"%ld",random);
[self.player replaceCurrentItemWithPlayerItem:self.musicArray[arc4random_uniform((int)self.musicArray.count)]];
}else if (self.playerType ==AVPlayerTypeSingle){ //单曲循环在自动切换歌曲时进行判断
//判断当前歌曲是否是第一首歌曲,如果是跳转到最后一首歌
if ([self.musicArray indexOfObject:self.player.currentItem] ==0) {
[self.player replaceCurrentItemWithPlayerItem:self.musicArray.lastObject];
}else{
[self.player replaceCurrentItemWithPlayerItem:self.musicArray[[self.musicArray indexOfObject:self.player.currentItem]-1]];
}
}
[self playMusic];
//放回对应歌曲的信息
self.block2([self.musicArray indexOfObject:self.player.currentItem]);
[self addObserver];//添加观察者
}];
}
//下一首
-(void)nextSong{
[self removeObserver];
[self.player.currentItem seekToTime:(kCMTimeZero) completionHandler:^(BOOL finished) {
if (self.playerType == AVPlayerTypeNormal) {
//判断当前歌曲是否是最后一首歌曲,如果是跳转到第一首歌
if ([self.musicArray indexOfObject:self.player.currentItem]+1 == self.musicArray.count) {
[self.player replaceCurrentItemWithPlayerItem:self.musicArray.firstObject];
}else{
[self.player replaceCurrentItemWithPlayerItem:self.musicArray[[self.musicArray indexOfObject:self.player.currentItem]+1]];
}
}else if (self.playerType == AVPlayerTypeRandom){
[self.player replaceCurrentItemWithPlayerItem:self.musicArray[arc4random_uniform((int)self.musicArray.count)]];
}else if (self.playerType == AVPlayerTypeSingle){
//判断当前歌曲是否是最后一首歌曲,如果是跳转到第一首歌
if ([self.musicArray indexOfObject:self.player.currentItem]+1 == self.musicArray.count) {
[self.player replaceCurrentItemWithPlayerItem:self.musicArray.firstObject];
}else{
[self.player replaceCurrentItemWithPlayerItem:self.musicArray[[self.musicArray indexOfObject:self.player.currentItem]+1]];
}
}
[self playMusic];
self.block2([self.musicArray indexOfObject:self.player.currentItem]);
[self addObserver];
}];
}
//获取 当前播放歌曲在AVPlayerItem中的 序号
-(NSInteger )getcurrentItem{
return [self.musicArray indexOfObject:self.player.currentItem];
}
//将slider的值传入使 歌曲进度 前进或后退
-(void)playerProgressWithProgressFloat:(CGFloat)progressFloat{
if (progressFloat > self.currentLoadTime) {
NSDictionary *dict = @{@"播放状态":@0};
[self.center postNotificationName:@"playOrPasue" object:self userInfo:dict];
}
[self.player seekToTime:CMTimeMake(progressFloat, 1.0)];
}
//接受播放完成的通知 开始下一首
- (void)playbackFinished:(NSNotification *)notice {
//判断是否是单曲循环 是的话 移除观察者 将当前进度调为0 重新播放
if (self.playerType == AVPlayerTypeSingle) {
[self removeObserver];
[self.player.currentItem seekToTime:kCMTimeZero];
[self musicPlayerWithIndex:[self getcurrentItem]];
[self playMusic];
}else{
[self nextSong];
}
}
//为当前播放的item 添加观察者
-(void)addObserver{
__weak typeof(self) weekSelf = self;
__weak AVPlayer *weekPlayer = self.player;
//观察该item 是否能播放
[self.player.currentItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
//观察该item 加载进度
[self.player.currentItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];