iOS學習筆記23-音效與音樂
一、音頻
在iOS中,音頻播放從形式上可以分為音效播放和音樂播放。
* 音效:
* 主要指一些短音訊播放,這類音頻一般不需要進行進度、迴圈等控制。
* 在iOS中,音效我們是使用AudioToolbox.framework
架構實現。
* 音樂:
* 主要指一些較長的音頻,通常需要對播放進行精確控制。
* 在iOS中,音樂我們是使用AVFoundation.framework
架構實現。
二、音效
AudioToolbox.framework
架構是一套基於C語言的架構
它的實現原理是將短音頻註冊到系統聲音服務(SystemSoundService)
系統聲音服務的一些限制:音頻播放時間不能超過30s 資料必須是PCM或者IMA4格式,現在的基本都符合音頻檔案必須是CAF、AIF、WAV的一種,實際上有些MP3格式也可以播放。使用步驟:匯入
AudioToolbox.framework
架構,添加標頭檔:
#import
擷取音效檔案的路徑URL 添加進系統聲音服務,獲得系統聲音ID,ID是區分不同音效的唯一標示
void AudioServicesCreateSystemSoundID( CFURLRef inFileURL, /* 音效檔案URL,需要把NSURL橋接成CGURLRef */ SystemSoundID *outSystemSoundID /* 返迴音效唯一標示ID */);
如果需要監聽音效播放完成,需要綁定回呼函數
void AudioServicesAddSystemSoundCompletion( SystemSoundID inSystemSoundID, /* 音效ID */ CFRunLoopRef inRunLoop, /* 所在迴圈,一般為NULL */ CFStringRef inRunLoopMode,/* 迴圈模式,一般為NULL */ void (*)(SystemSoundID,void*) inCompletionRoutine,/* 回調C語言函數指標 */ void *inClientData /* 回呼函數的參數 */);
開始播放,有兩種播放模式:
/* 開始播放音效 */void AudioServicesPlaySystemSound(SystemSoundID inSystemSoundID);/* 開始播放音效並帶震動 */void AudioServicesPlayAlertSound(SystemSoundID inSystemSoundID);
下面是使用執行個體:
- (void)viewDidLoad{ [super viewDidLoad]; [self playSoundEffect:@"bellTone.wav"];}#pragma mark -音效/* 音效播放完成的回呼函數,這個是C語言函數,第一個參數是音效ID,第二個是萬能參數 */void soundCompleteCallBack(SystemSoundID soundID, void *clientData){ NSLog(@"播放完成");}- (void)playSoundEffect:(NSString *)name { //擷取音效檔案路徑 NSString *filePath = [[NSBundle mainBundle] pathForResource:name ofType:nil]; //建立音效檔案URL NSURL *fileUrl = [NSURL URLWithString:filePath]; //音效聲音的唯一標示ID SystemSoundID soundID = 0; //將音效加入到系統音效服務中,NSURL需要橋接成CFURLRef,會返回一個長整形ID,用來做音效的唯一標示 AudioServicesCreateSystemSoundID((__bridge CFURLRef)(fileUrl), &soundID); //設定音效播放完成後的回調C語言函數 AudioServicesAddSystemSoundCompletion(soundID,NULL,NULL,soundCompleteCallBack,NULL); //開始播放音效 AudioServicesPlaySystemSound(soundID);}
三、音樂
如果播放較大的音頻,需要對其進行精確控制,我們需要使用到另外一個架構,即:
AVFoundation.framework
架構,它支援多種音頻格式,可以進行精確控制。
音樂播放功能我們使用到的是AVFoundation.framework
的AVAudioPlayer
音樂播放器來實現。
下面有一些
AVAudioPlayer
類的常用屬性:
@property (readonly, getter=isPlaying) BOOL playing;//是否現正播放@property NSTimeInterval currentTime;//當前已經播放的時間@property (readonly) NSTimeInterval duration;//播放的總時間@property float volume;//音量大小@property float rate;//播放速率,預設為1.0@property (readonly) NSURL *url;//音樂檔案的URL
下面是常用的對象方法:
/* 初始化方法 */- (instancetype)initWithContentsOfURL:(NSURL *)url error:(NSError **)outError;- (BOOL)prepareToPlay;/* 把音樂檔案載入到緩衝區 */- (BOOL)play;/* 開始播放音樂 */- (BOOL)playAtTime:(NSTimeInterval)time;/* 在指定時間開始播放音樂 */- (void)pause;/* 中斷音樂,可以通過調用play方法繼續播放 */- (void)stop;/* 終止音樂,無法繼續播放 */
常用的代理方法:
/* 播放完成時調用 */- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag;/* 音頻解碼發生錯誤時調用 */- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error;
使用步驟:匯入
AVFoundation.framework
架構,添加標頭檔:
#import
擷取音樂檔案的本地檔案路徑URL,不能使用網路URL 建立音樂播放器對象
AVAudioPlayer
,並設定屬性和代理。調用
perpareToPlay
方法載入音樂檔案到緩衝區調用
play
方法播放,調用
pause
中斷播放實現
AVAudioPlayerDelegate
方法,監聽播放完成。我們來做個簡易的音樂播放器吧:可以迴圈播放音樂可以中斷音樂可以切換不同的音樂可以知道播放進度下面是具體的簡易音樂播放器項目代碼:
#import "ViewController.h"#import @interface ViewController () @property (nonatomic, strong) NSArray *musicArray;/*< 音樂列表 */@property (nonatomic, strong) IBOutlet UIProgressView *progress;/*< 進度條 */@property (nonatomic, strong) AVAudioPlayer *audioPlayer;/*< 音樂播放器對象 */@property (nonatomic, strong) NSTimer *timer;/* 定時器 */@property (nonatomic, strong) IBOutlet UILabel *titleLabel;/* 顯示標題 */@property (nonatomic, assign) NSInteger selectMusic;/* 當前播放音樂的索引 */@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; //音樂檔案清單 self.musicArray = @[@"大夢想家",@"江南",@"酒幹倘賣無", @"泡沫",@"夏洛特煩惱",@"演員"]; //建立定時器,用於不斷更新進度條 self.timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(updataProgress) userInfo:nil repeats:YES]; //建立播放器 [self initAudioPlayerWithNumber:0]; //播放器開始播放音樂 [self.audioPlayer play];}/* 初始化播放器 */- (void)initAudioPlayerWithNumber:(NSInteger)num{ if (num >= self.musicArray.count) { return; } //擷取音樂檔案路徑 NSString *name = self.musicArray[num]; NSString *filePath = [[NSBundle mainBundle] pathForResource:name ofType:@"mp3"]; //建立音樂檔案URL,必須是fileURLWithPath,AVAudioPlayer不支援HTTP的URL NSURL *fileUrl = [NSURL fileURLWithPath:filePath]; //建立播放器 NSError *error = nil; AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileUrl error:&error]; if (error) { NSLog(@"初始化播放器錯誤,錯誤:%@",error.localizedDescription); return; } audioPlayer.numberOfLoops = 0;//設定迴圈次數,0表示不迴圈 audioPlayer.delegate = self;//設定代理 [audioPlayer prepareToPlay];//載入音樂檔案到緩衝,還不會播放 self.selectMusic = num;//儲存當前的音樂索引 self.audioPlayer = audioPlayer;//儲存當前播放器 self.titleLabel.text = name;//設定標題}/* 進度條更新方法,每0.5秒更新一次 */- (void)updataProgress{ //currentTime是當前播放時間,duration是播放總時間長度 CGFloat progress = self.audioPlayer.currentTime / self.audioPlayer.duration; [self.progress setProgress:progress animated:YES];}/* 點擊播放按鈕 */- (IBAction)musicPlay:(id)sender { //如果播放器沒有在播放,才需要調用播放方法 if (![self.audioPlayer isPlaying]) { [self.audioPlayer play]; //恢複定時器 self.timer.fireDate = [NSDate distantPast]; }}/* 點擊暫停按鈕 */- (IBAction)musicPause:(id)sender { //如果播放器在播放,才需要調用暫停方法 if ([self.audioPlayer isPlaying]) { [self.audioPlayer pause]; //停止定時器 self.timer.fireDate = [NSDate distantFuture]; }}/* 點擊下一首歌按鈕 */- (IBAction)next:(id)sender { //音樂索引迴圈遞增 self.selectMusic = (self.selectMusic + 1)%self.musicArray.count; //重新設定播放器 [self initAudioPlayerWithNumber:self.selectMusic]; //播放器播放 [self.audioPlayer play];}#pragma mark - AVAudioPlayerDelegate代理方法-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{ //自動跳轉播放下一首歌 [self next:nil];}
(⊙﹏⊙)b,也是夠簡陋的,你可以做精美一點,比如如果每首歌對應一個圖片,到時候切歌的時候,圖片顯示在背景,一定賞心悅目多了,O(∩_∩)O~,我沒有找到好的圖片,就這樣吧。<喎?http://www.bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxoMyBpZD0="四後台播放音樂">四、後台播放音樂
事實上上面的播放器有一點問題,那就是一旦進入後台,我們的音樂器就自動暫停了,不可以/(ㄒoㄒ)/~~!那該怎麼辦呢?
1. 設定後台運行模式
設定info.plist檔案,添加欄位Required background modes
,
並設定App plays audio or streams audio/video using AirPlay
2. 使用音頻會話,設定後台運行類型
//擷取音頻會話單例對象AVAudioSession *audioSession = [AVAudioSession sharedInstance];//設定會話為後台播放[audioSession setCategory:AVAudioSessionCategoryPlayback error:NULL];//啟用修改,啟動會話[audioSession setActive:YES error:NULL];
音頻會話除了後台播放外,還可以有以下的播放模式:
上面的代碼只需修改初始化播放器方法即可實現後台播放:
/* 初始化播放器 */- (void)initAudioPlayerWithNumber:(NSInteger)num{ if (num >= self.musicArray.count) { return; } //擷取音樂檔案路徑 NSString *name = self.musicArray[num]; NSString *filePath = [[NSBundle mainBundle] pathForResource:name ofType:@"mp3"]; //建立音樂檔案URL,必須是fileURLWithPath,AVAudioPlayer不支援HTTP的URL NSURL *fileUrl = [NSURL fileURLWithPath:filePath]; //建立播放器 NSError *error = nil; AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileUrl error:&error]; if (error) { NSLog(@"初始化播放器錯誤,錯誤:%@",error.localizedDescription); return; } audioPlayer.numberOfLoops = 0;//設定迴圈次數,0表示不迴圈 audioPlayer.delegate = self;//設定代理 [audioPlayer prepareToPlay];//載入音樂檔案到緩衝,還不會播放 //擷取音頻會話單例對象 AVAudioSession *audioSession = [AVAudioSession sharedInstance]; //設定會話為後台播放 [audioSession setCategory:AVAudioSessionCategoryPlayback error:NULL]; //啟用修改,啟動會話 [audioSession setActive:YES error:NULL]; self.selectMusic = num;//儲存當前的音樂索引 self.audioPlayer = audioPlayer;//儲存當前播放器 self.titleLabel.text = name;//設定標題}