在iOS中,音頻播放從形式上可以分為音效播放和音樂播放。
AudioToolbox.framework
框架實現。AVFoundation.framework
框架實現。AudioToolbox.framework
框架是一套基於C語言的框架
它的實現原理是將短音頻注冊到系統聲音服務(SystemSoundService)
導入AudioToolbox.framework
框架,添加頭文件:
#import <AudioToolbox/AudioToolbox.h>
添加進系統聲音服務,獲得系統聲音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 <AVFoundation/AVFoundation.h>
AVAudioPlayer
,並設置屬性和代理。perpareToPlay
方法加載音樂文件到緩沖區play
方法播放,調用pause
中斷播放實現AVAudioPlayerDelegate
方法,監聽播放完成。
#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>
@interface ViewController () <AVAudioPlayerDelegate>
@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~,我沒有找到好的圖片,就這樣吧。
事實上上面的播放器有一點問題,那就是一旦進入後台,我們的音樂器就自動暫停了,不可以/(ㄒoㄒ)/~~!那該怎麼辦呢?
設置info.plist文件,添加字段Required background modes
,
並設置App plays audio or streams audio/video using AirPlay
//獲取音頻會話單例對象
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;//設置標題
}
這樣,我們就可以後台播放了,(^o^)/~。