iOS音频播放 // JWDev 

JerryXia 发表于 , 阅读 (0)

音频播放

音频播放一般有两种途径,第一种是通过AVFoundation框架的 AVPlayer,第二种是通过AVFoundation框架的AVAudioSession.

关键类/结构体

  1. AVPlayer
  2. AVPlayerItem
  3. CMTime

其中AVPlayer就是一个播放器,而AVPlayerItem就是一个要播放的资源,我们平时是不是用一个MP3播放器播放音乐,其中这个AVPlayer就是一个MP3播放器,而AVPlayerItem就是一首要播放的资源.当然我们的播放器中是不是存放了很多首歌曲?所以我们也要想办法怎么去存放很多AVPlayerItem去让AVPlayer去播放,而CMTime只是一个结构体,用来记录AVPlayerItem资源的播放进度已经这个AVPlayerItem资源的一些其他信息

关键方法

1
2
3
4
5
6
7
8
9
10
11
//初始化一个AVPlayer,参数是一个AVPlayerItem
- (instancetype)initWithPlayerItem:(AVPlayerItem *)item;

//让AVPlayer开始播放AVPlayerItem资源
- (void)play;

//暂停播放
- (void)pause;

//替换AVPlayer实例的AVPlayerItem对象,可以用来做上一首和下一首功能.
- (void)replaceCurrentItemWithPlayerItem:(AVPlayerItem *)item;

代码实例

播放

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@interface ViewController ()
//播放器对象
@property (nonatomic,strong) AVPlayer * player;

@end

@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];

//初始化播放的资源
AVPlayerItem *item = [[AVPlayerItem alloc] initWithURL:[NSURL URLWithString:@"http://m1.music.126.net/gpi8Adr_-pfCuP7ZXk_F2w==/2926899953898363.mp3"]];

//初始化播放器
self.player = [[AVPlayer alloc] initWithPlayerItem:item];

//条用播放器的播放事件,这是我们的音乐就可以播放了.
[self.player play];
}
@end

当然要有暂停功能喽

1
2
//让AVPlayer暂停播放
[self.player pause];

而且还要有切歌的功能哦

1
2
//替换一个新的资源
[self.player replaceCurrentItemWithPlayerItem:newItem];

当然,我们现在这些都是零碎的代码,如何才能具体来实现一个音乐播放器呢?这时我们需要思考一下,AVPlayer这个对象应该怎么存储,我们想一想网易云音乐,当播放音乐时,是不是可以切换到音乐列表页面,但是音乐还在播放的?也就是不管页面怎么切换,我们的AVPlayer都一直存在的,而且还在播放的!!!

猜猜该怎么做?

有没有想到一个设计模式?

单例?

bingo!!!就是单例,我们只需要将单例存放到单例中这样,程序运行期间,这个AVPlayer就会一直存在.

但是如何去换一首歌呢,还记得我们上面说到了一个方法是替换当前播放器的正在播放的资源的接口么?ok,我们可以通过替换当前播放歌曲来实现上一首下一首的功能.

ok,思路有了!你可不可以来实现这个音乐播放器的单例呢?试试吧!不试怎么知道不可能呢?

写个单例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
@interface AVAudioManager ()
{
BOOL isPlaying;//是否真正播放
BOOL isPrePare; // 是否准备好资源
}
//音乐播放器
@property (nonatomic,strong) AVPlayer * player;



@end

@implementation AVAudioManager

//利用dispatch_once 创建一个单例
+ (instancetype)sharedManager{
static AVAudioManager *manager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [AVAudioManager new];
});
return manager;
}

//根据一个音乐链接播放音乐
- (void)playWithURL:(NSString *)playerItemURL{
//创建一个要播放的资源
AVPlayerItem *item = [[AVPlayerItem alloc] initWithURL:[NSURL URLWithString:playerItemURL]];

//用self 观察一下item 的 status
//当item 的 status 属性发生变化是就会触发观察者事件
[item addObserver:self forKeyPath:@"status" options:(NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew) context:nil];

//替换当前播放器在播放的资源,开始加载资源
[self.player replaceCurrentItemWithPlayerItem:item];
}

//播放
- (void)play{
//如果没有准备好的话,就直接返回了,就不播放了
if (!isPrePare) {
return;
}
//开始播放
[self.player play];
//标记为正在播放
isPlaying = YES;
}
//暂停
- (void)pause{
//如果没有正在播放就直接返回了
if (!isPlaying) {
return;
}
//暂停播放
[self.player pause];
//标记没有播放
isPlaying = NO;
}

#pragma mark - 观察者
//当item
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{
NSLog(@"%@,%@",keyPath,change);
AVPlayerItemStatus status = [change[@"new"] integerValue];
switch (status) {
case AVPlayerItemStatusReadyToPlay:
isPrePare = YES;
[self play];
break;
case AVPlayerItemStatusFailed:
NSLog(@"音乐加载失败");
break;
case AVPlayerItemStatusUnknown:
NSLog(@"音乐未知");
break;
default:
break;
}
}

#pragma mark - lazy load
- (AVPlayer *)player{
if (!_player) {
_player = [AVPlayer new];
}
return _player;
}
@end

播放

写完了这个单例后,我们想播放音乐时,只需要执行下面的代码就行了.

1
2
AVAudioManager *manager = [AVAudioManager sharedManager];
[manager playWithURL:@"http://m1.music.126.net/gpi8Adr_-pfCuP7ZXk_F2w==/2926899953898363.mp3"];

暂停

这样当这个单例中的AVPlayer对象加载完AVPlayerItem后就会自动播放.然后当我们想暂停时,只需要执行单例的 -(void)pause方法就可以暂停了.

1
2
//暂停
[[AVAudioManager sharedManager] pause];

继续播放

同样的道理,当我们暂停后可以调用play方法播放

1
2
//播放
[[AVAudioManager sharedManager] play];

延展知识点