AVAudioPlayer 簡述
AVAudioPlayer是屬于
AVFundation.framework
的一個類,它的功能類似于一個功能強大的播放器丢习,AVAudioPlayer每次播放都需要將上一個player對象釋放掉,然后重新創(chuàng)建一個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創(chuàng)建成功之后調用羹令,調用[player play]則可以節(jié)省播放之前的間隔時間鲤屡。
- (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 //輸出設備播放音頻的時間显拜,注意如果播放中被暫停此時間也會繼續(xù)累加
numberOfLoops //循環(huán)次數,如果要單曲循環(huán)爹袁,設置為負數
volume //播放器的音頻增益远荠,值:0.0~1.0
channelAssignments //獲得或設置播放聲道
AVAudioPlayer 代理方法
//音頻播放完成
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag;
//音頻解碼發(fā)生錯誤
- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError * __nullable)error
//如果音頻被中斷,比如有電話呼入失息,該方法就會被回調譬淳,該方法可以保存當前播放信息,以便恢復繼續(xù)播放的進度
- (void)audioPlayerBeginInterruption:(AVAudioPlayer *)player
AVPlayer 簡述
AVPlayer支持播放本地盹兢、分步下載邻梆、或在線流媒體音視頻,不僅可以播放音頻绎秒,配合AVPlayerLayer類可實現視頻播放浦妄。另外支持播放進度監(jiān)聽。
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添加監(jiān)聽
1.播放狀態(tài)改變監(jiān)聽
//KVO監(jiān)聽播放狀態(tài)
[self.player.currentItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
處理KVO回調事件
//處理KVO回調事件
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
if ([keyPath isEqualToString:@"status"]) {
switch (self.player.status) {
case AVPlayerStatusUnknown:
NSLog(@"未知轉態(tài)");
break;
case AVPlayerStatusReadyToPlay:
NSLog(@"準備播放");
break;
case AVPlayerStatusFailed:
NSLog(@"加載失敗");
break;
default:
break;
}
}
}
2.KVO監(jiān)聽音樂緩沖狀態(tài)
//KVO監(jiān)聽音樂緩沖狀態(tài)
[self.player.currentItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
處理KVO回調事件
//處理KVO回調事件
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)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;
}
}
- 播放結束事件的監(jiān)聽
//播放結束事件的監(jiān)聽
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(playFinied:) name:AVPlayerItemDidPlayToEndTimeNotification
object:self.player.currentItem];
處理KVO回調事件
//播放結束回調
- (void)playFinied:(AVPlayerItem *)item {
NSLog(@"播放結束");
self.slider.value = 0;
}
- 開始播放時,通過AVPlayer的方法監(jiān)聽播放進度耳胎,并更新進度條(定期監(jiān)聽的方法)
//開始播放時惯吕,通過AVPlayer的方法監(jiān)聽播放進度,并更新進度條(定期監(jiān)聽的方法)
__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數組創(chuàng)建一個AVQueuePlayer實例
+ (instancetype)queuePlayerWithItems:(NSArray<AVPlayerItem *> *)items;
//通過給定的AVPlayerItem數組初始化一個AVQueuePlayer實例
- (AVQueuePlayer *)initWithItems:(NSArray<AVPlayerItem *> *)items;
//獲取當前播放隊列數組
- (NSArray<AVPlayerItem *> *)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做列表播放也是可以的,自己維護一個播放列表數組扳炬,監(jiān)聽用戶點擊上一首和下一首按鈕吏颖,并監(jiān)聽播放結束事件,調用 AVPlayer 實例的replaceCurrentItemWithPlayerItem:方法傳入播放列表中的上一首或下一首就行恨樟。
后臺播放
首先在AppDelegate.m的- (BOOL)application:didFinishLaunchingWithOptions:方法中添加代碼:
//設置后臺播放功能
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayback error:nil];
[session setActive:YES error:nil];
然后在info.plist里面配置:
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
</array>
鎖屏信息
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];
// 啟用播放命令 (鎖屏界面和上拉快捷功能菜單處的播放按鈕觸發(fā)的命令)
commandCenter.playCommand.enabled = YES;
// 為播放命令添加響應事件, 在點擊后觸發(fā)
[commandCenter.playCommand addTarget:self action:@selector(playAction:)];
// 播放, 暫停, 上下曲的命令默認都是啟用狀態(tài), 即enabled默認為YES
// 為暫停, 上一曲, 下一曲分別添加對應的響應事件
[commandCenter.pauseCommand addTarget:self action:@selector(pauseAction:)];
[commandCenter.previousTrackCommand addTarget:self action:@selector(previousTrackAction:)];
[commandCenter.nextTrackCommand addTarget:self action:@selector(nextTrackAction:)];
// 啟用耳機的播放/暫停命令 (耳機上的播放按鈕觸發(fā)的命令)
commandCenter.togglePlayPauseCommand.enabled = YES;
// 為耳機的按鈕操作添加相關的響應事件
[commandCenter.togglePlayPauseCommand addTarget:self action:@selector(playOrPauseAction:)];