AVAudioPlayer 简述

AVAudioPlayer是属于 AVFundation.framework 的一个类,它的功能类似于一个功能强大的播放器,AVAudioPlayer每次播放都需要将上一个player对象释放掉,然后重新创建一个player来进行播放,AVAudioPlayer 支持广泛的音频格式,主要是以下这些格式。

ACC

AMR(Adaptive multi-Rate,一种语音格式)

ALAC (Apple lossless Audio Codec)

iLBC (internet Low Bitrate Codec,另一种语音格式)

IMA4 (IMA/ADPCM)

linearPCM (uncompressed)

u-law 和 a-law

MP3 (MPEG-Laudio Layer 3)

AVAudioPlayer 使用

AVAudioPlayer 初始化

1. initWithContentsOfURL: error: 从URL加载音频,返回 AVAudioPlayer 对象

2. initWithData: error: 加载NSdata对象的音频文件,返回 AVAudioPlayer 对象

AVAudioPlayer 方法调用

//准备播放 可以判断player创建成功之后调用,调用[player play]则可以节省播放之前的间隔时间。

- (BOOL)prepareToPlay;

//异步播放

- (BOOL)play;

//在某个时间点播放

- (BOOL)playAtTime:(NSTimeInterval)time NS_AVAILABLE(10_7, 4_0);

//暂停播放,但仍然可以播放

- (void)pause;

//停止播放,不再准备播放了

- (void)stop;

//更新音频测量值,注意如果要更新音频测量值必须设置meteringEnabled为YES,通过音频测量值可以即时获得音频分贝等信息

- (void)updateMeters;

//返回给定通道的分贝峰值功率

- (float)peakPowerForChannel:(NSUInteger)channelNumber;

//获得指定声道的分贝峰值,注意如果要获得分贝峰值必须在此之前调用updateMeters方法

- (float)averagePowerForChannel:(NSUInteger)channelNumber;

AVAudioPlayer 属性设置

playing //播放器是否正在播放 获取通过isPlaying

numberOfChannels //该音频的声道次数,只读

duration //该音频播放时长

url //音频文件路径, 只读

data //音频数据,只读

pan NS_AVAILABLE(10_7, 4_0) //立体声设置 设为 -1.0 则左边播放 设为 0.0 则中央播放 设为 1.0 则右边播放

enableRate NS_AVAILABLE(10_8, 5_0); //是否允许改变播放速率

rate NS_AVAILABLE(10_8, 5_0); //播放速率 0.5 (半速播放) ~ 2.0(倍速播放) 注1.0 是正常速度

currentTime //该音频的播放点

deviceCurrentTime //输出设备播放音频的时间,注意如果播放中被暂停此时间也会继续累加

numberOfLoops //循环次数,如果要单曲循环,设置为负数

volume //播放器的音频增益,值:0.0~1.0

channelAssignments //获得或设置播放声道

AVAudioPlayer 代理方法

//音频播放完成

- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag;

//音频解码发生错误

- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError * __nullable)error

//如果音频被中断,比如有电话呼入,该方法就会被回调,该方法可以保存当前播放信息,以便恢复继续播放的进度

- (void)audioPlayerBeginInterruption:(AVAudioPlayer *)player

AVPlayer 简述

AVPlayer支持播放本地、分步下载、或在线流媒体音视频,不仅可以播放音频,配合AVPlayerLayer类可实现视频播放。另外支持播放进度监听。

AVPlayer只支持单个媒体资源播放。

AVPlayer需要配合AVPlayerItem关联来进行媒体播放。

AVPlayer 使用

AVPlayer 初始化

//类方法,从url加载音频

+ (instancetype)playerWithURL:(NSURL *)URL

//类方法,配合AVPlayerItem使用

+ (instancetype)playerWithPlayerItem:(nullable AVPlayerItem *)item

//实例方法,从url加载音频

- (instancetype)initWithURL:(NSURL *)URL

//实例方法,配合AVPlayerItem使用

- (instancetype)initWithPlayerItem:(nullable AVPlayerItem *)item

AVPlayer KVO添加监听

1.播放状态改变监听

//KVO监听播放状态

[self.player.currentItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];

处理KVO回调事件

//处理KVO回调事件

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {

if ([keyPath isEqualToString:@"status"]) {

switch (self.player.status) {

case AVPlayerStatusUnknown:

NSLog(@"未知转态");

break;

case AVPlayerStatusReadyToPlay:

NSLog(@"准备播放");

break;

case AVPlayerStatusFailed:

NSLog(@"加载失败");

break;

default:

break;

}

}

}

2.KVO监听音乐缓冲状态

//KVO监听音乐缓冲状态

[self.player.currentItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];

处理KVO回调事件

//处理KVO回调事件

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {

if ([keyPath isEqualToString:@"loadedTimeRanges"]) {

NSArray *timeRanges = self.player.currentItem.loadedTimeRanges;

//本次缓冲的时间范围

CMTimeRange timeRange = [timeRanges.firstObject CMTimeRangeValue];

//缓冲总长度

NSTimeInterval totalLoadTime = CMTimeGetSeconds(timeRange.start) + CMTimeGetSeconds(timeRange.duration);

//音乐的总时间

NSTimeInterval duration = CMTimeGetSeconds(self.player.currentItem.duration);

//计算缓冲百分比例

NSTimeInterval scale = totalLoadTime/duration;

NSLog(@"---%f,---%f,---%f",totalLoadTime,duration,scale);

//更新缓冲进度条

// self.loadProgress.progress = scale;

}

}

播放结束事件的监听

//播放结束事件的监听

[[NSNotificationCenter defaultCenter] addObserver:self

selector:@selector(playFinied:) name:AVPlayerItemDidPlayToEndTimeNotification

object:self.player.currentItem];

处理KVO回调事件

//播放结束回调

- (void)playFinied:(AVPlayerItem *)item {

NSLog(@"播放结束");

self.slider.value = 0;

}

开始播放时,通过AVPlayer的方法监听播放进度,并更新进度条(定期监听的方法)

//开始播放时,通过AVPlayer的方法监听播放进度,并更新进度条(定期监听的方法)

__weak typeof(self) weakSelf = self;

[self.player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 1.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {

//当前播放的时间

float current = CMTimeGetSeconds(time);

//总时间

float total = CMTimeGetSeconds(item.duration);

if (current) {

float progress = current / total;

//更新播放进度条

weakSelf.slider.value = progress;

}

}];

拖动进度条改变播放进度

//拖动进度条改变播放进度

- (void)playValueChange:(UISlider *)sender {

//计算时间

float time = sender.value * CMTimeGetSeconds(self.player.currentItem.duration);

//跳到当前指定时间

[self.player seekToTime:CMTimeMake(time, 1)];

}

AVQueuePlayer 简述

AVPlayer只支持单个媒体资源的播放,我们可以使用AVPlayer的子类AVQueuePlayer实现列表播放。在AVPlayer的基础上,增加以下方法:

//通过给定的AVPlayerItem数组创建一个AVQueuePlayer实例

+ (instancetype)queuePlayerWithItems:(NSArray *)items;

//通过给定的AVPlayerItem数组初始化一个AVQueuePlayer实例

- (AVQueuePlayer *)initWithItems:(NSArray *)items;

//获取当前播放队列数组

- (NSArray *)items;

//停止当前播放的,播放队列中的下一首

- (void)advanceToNextItem;

//判断是否可以插入AVPlayerItem

- (BOOL)canInsertItem:(AVPlayerItem *)item afterItem:(nullable AVPlayerItem *)afterItem;

//往播放队列中插入新的AVPlayerItem

- (void)insertItem:(AVPlayerItem *)item afterItem:(nullable AVPlayerItem *)afterItem;

//移除指定的AVPlayerItem

- (void)removeItem:(AVPlayerItem *)item;

//移除所有播放队列中的AVPlayerItem

- (void)removeAllItems;

*官方API中没找到播放上一首的方法,所以其实直接用AVPlayer做列表播放也是可以的,自己维护一个播放列表数组,监听用户点击上一首和下一首按钮,并监听播放结束事件,调用 AVPlayer 实例的replaceCurrentItemWithPlayerItem:方法传入播放列表中的上一首或下一首就行。

后台播放

首先在AppDelegate.m的- (BOOL)application:didFinishLaunchingWithOptions:方法中添加代码:

//设置后台播放功能

AVAudioSession *session = [AVAudioSession sharedInstance];

[session setCategory:AVAudioSessionCategoryPlayback error:nil];

[session setActive:YES error:nil];

然后在info.plist里面配置:

UIBackgroundModes

audio

锁屏信息

1、在播放控制界面接受远程控制

- (void)viewWillAppear:(BOOL)animated

{

[super viewWillAppear:YES];

// 开始接受远程控制

[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];

[self resignFirstResponder];

}

- (void)viewWillDisappear:(BOOL)animated

{

// 接触远程控制

[[UIApplication sharedApplication] endReceivingRemoteControlEvents];

[self becomeFirstResponder];

}

// 重写父类成为响应者方法

- (BOOL)canBecomeFirstResponder

{

return YES;

}

2、对远程控制事件做出相应的操作

//重写父类方法,接受外部事件的处理

- (void) remoteControlReceivedWithEvent: (UIEvent *) receivedEvent {

NSLog(@"remote");

if (receivedEvent.type == UIEventTypeRemoteControl) {

switch (receivedEvent.subtype) { // 得到事件类型

case UIEventSubtypeRemoteControlTogglePlayPause: // 暂停 ios6

[self.player pause]; // 调用你所在项目的暂停按钮的响应方法 下面的也是如此

break;

case UIEventSubtypeRemoteControlPreviousTrack: // 上一首

[self lastMusic:nil];

break;

case UIEventSubtypeRemoteControlNextTrack: // 下一首

[self nextMusic:nil];

break;

case UIEventSubtypeRemoteControlPlay: //播放

[self playMusic:nil];

break;

case UIEventSubtypeRemoteControlPause: // 暂停 ios7

[self playMusic:nil];

break;

default:

break;

}

}

}

3、设置锁屏主题

//锁屏信息

NSMutableDictionary *songInfo = [ [NSMutableDictionary alloc] init];

//锁屏图片

UIImage *img = [UIImage imageNamed:@"iPhoneX"];

if (img) {

MPMediaItemArtwork *albumArt = [[MPMediaItemArtwork alloc]initWithImage:img];

[songInfo setObject: albumArt forKey:MPMediaItemPropertyArtwork ];

}

//锁屏标题

NSString *title = @"music";

[songInfo setObject:[NSNumber numberWithFloat:100] forKey:MPMediaItemPropertyPlaybackDuration];

[songInfo setObject:title forKey:MPMediaItemPropertyTitle];

[songInfo setObject:title forKey:MPMediaItemPropertyAlbumTitle];

[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:songInfo ];

通过耳机、锁屏界面控制

// 直接使用sharedCommandCenter来获取MPRemoteCommandCenter的shared实例

MPRemoteCommandCenter *commandCenter = [MPRemoteCommandCenter sharedCommandCenter];

// 启用播放命令 (锁屏界面和上拉快捷功能菜单处的播放按钮触发的命令)

commandCenter.playCommand.enabled = YES;

// 为播放命令添加响应事件, 在点击后触发

[commandCenter.playCommand addTarget:self action:@selector(playAction:)];

// 播放, 暂停, 上下曲的命令默认都是启用状态, 即enabled默认为YES

// 为暂停, 上一曲, 下一曲分别添加对应的响应事件

[commandCenter.pauseCommand addTarget:self action:@selector(pauseAction:)];

[commandCenter.previousTrackCommand addTarget:self action:@selector(previousTrackAction:)];

[commandCenter.nextTrackCommand addTarget:self action:@selector(nextTrackAction:)];

// 启用耳机的播放/暂停命令 (耳机上的播放按钮触发的命令)

commandCenter.togglePlayPauseCommand.enabled = YES;

// 为耳机的按钮操作添加相关的响应事件

[commandCenter.togglePlayPauseCommand addTarget:self action:@selector(playOrPauseAction:)];