iOS 音頻播放
- 本地音頻文件 AVPlayer / AVAudioPlayer
- 在線音頻流 AVPlayer
- iPod 歌曲 AVPlayer / AVAudioPlayer / MPMusicPlayerController
- 音效 AudioServices
iPod 音樂(lè)
- iPod 歌曲的讀取
-
MPMediaPickerController系統(tǒng)封裝的, 包括 UI -
MPMediaLibrary + MPMediaQuery系統(tǒng)封裝的讀取類(lèi), 不包含 UI
-
- iPod 歌曲的讀取權(quán)限
- 權(quán)限相關(guān)接口: iOS 9.3+
- iPod 讀取權(quán)限彈窗: iOS 9.3+ 暫時(shí)不會(huì)直接提醒彈窗權(quán)限, 在 iOS10 加入了彈窗
- 權(quán)限用途的說(shuō)明文案: iOS 10+; Xcode 8+ 必須要在 info.plist 寫(xiě)明
NSAppleMusicUsageDescription
- 使用 MPMediaPickerController 讀取
@interface MPMediaPickerController : UIViewController
@property (nonatomic, readonly) MPMediaType mediaTypes;
@property (nonatomic, weak, nullable) id<MPMediaPickerControllerDelegate> delegate;
@property (nonatomic) BOOL allowsPickingMultipleItems;
@property (nonatomic) BOOL showsCloudItems;
@property (nonatomic) BOOL showsItemsWithProtectedAssets;
@property (nonatomic, copy, mullable) NSString *prompt;
@protocol MPMediaPickerControllerDelegate <NSObject>
- (void)mediaPicker:(MPMediaPickerController *)mediaPicker didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection;
- (void)mediaPickerDidCancel:(MPMediaPickerController *)mediaPicker;
@interface MPMediaItemCollection : MPMediaEntity
@interface MPMediaItem : MPMediaEntity
-
[musicPlayer prepareToPlay]將選中的音樂(lè)放進(jìn)播放列表中- 直接調(diào)用
play方法也可以達(dá)到將歌曲放入播放列表中的效果
- 直接調(diào)用
-
播放狀態(tài)
/*** MPMusicPlaybackState ***/ MPMusicPlaybackStateStopped MPMusicPlaybackStatePlaying // 播放 MPMusicPlaybackStatePaused // 暫停 MPMusicPlaybackStateInterrupted // 中斷狀態(tài) MPMusicPlaybackStateSeekingForward // 線控時(shí)播放狀態(tài) MPMusicPlaybackStateSeekingBackword // 線控時(shí)播放狀態(tài) -
播放狀態(tài)的通知
MPMusicPlayerControllerPlaybackStateDidChangeNotification 播放進(jìn)度
-
切歌
@interface MPMusicPlayerController (MPPlaybackControl) - (void)skipToNextItem; // 下一曲 - (void)skipToPreviousItem; // 上一曲 -
播放模式
repeatMode MPMusicRepeatModeDefault MPMusicRepeatModeNone MPMusicRepeatModeOne MPMusicRepeatModeAll shuffleMode MPMusicShuffleModeDefault MPMusicShuffleModeOff MPMusicShuffleModeSongs MPMusicShuffleModeAlbums -
定義自己的播放模式
typedef NS_ENUM (NSUInteger, AudioPlayerMode) { AudioPlayerModeRepeat, AudioPlayerModeSingle, AudioPlayerModeRandom, } - (void)setMode:(AudioPlayerMode)mode { _mode = mode; if (mode == AudioPlayerModeRepeat) { _musicPlayer.repeatMode = MPMusicRepeatModeAll; _musicPlayer.shuffleMode = MPMusicShuffleModeOff; } else if (mode == AudioPlayerModeSingle) { _musicPlayer.repeatMode = MPMusicRepeatModeOne; _musicPlayer.shuffleMode = MPMusicShuffleModeOff; } else if (mode == AudioPlayerModeRandom) { _musicPlayer.repeatMode = MPMusicRepeatModeAll; _musicPlayer.shuffleMode = MPMusicShuffleModeSongs; } } -
applicationMusicPlayer & systemMusicPlayer
- 都是調(diào)用系統(tǒng)的音樂(lè) app 進(jìn)行播放
- 不同
- applicationMusicPlayer 不會(huì)改變系統(tǒng)正在播放的歌曲
- systemMusicPlayer 會(huì)改變系統(tǒng)自動(dòng)播放的歌曲, 相當(dāng)于直接在系統(tǒng)音樂(lè)中進(jìn)行播放
優(yōu)勢(shì)
- 接口完全封裝, 使用簡(jiǎn)單
- 不關(guān)心播放模式, 播放列表的維護(hù)
- 不關(guān)心其他的問(wèn)題, 例如打斷
問(wèn)題
- 只能播放 iPod 歌曲
- 不是自己的 app 在后臺(tái)播放, 而是調(diào)用系統(tǒng)的音樂(lè) app 在播放
- 進(jìn)入系統(tǒng)選歌界面或者使用 MPMediaLibrary 歌曲會(huì)停止, 播放列表會(huì)清空
自行實(shí)現(xiàn) iPod 歌曲選擇
- MPMediaLibrary
| 類(lèi)型 | 資源 | 類(lèi) |
|---|---|---|
| 在線音頻流 | 音頻 URL | AVURLAsset |
| 本地音頻文件 | 音頻文件 | AVURLAsset |
| iPod 歌曲 | Music.app 中的歌曲 | MPMediaItem |
-
Metadata
- 音頻信息
- 歌名
- 專(zhuān)輯
- 歌手
- 封面圖
- 音頻數(shù)據(jù) - 聽(tīng)到的音樂(lè)
- 音頻信息
-
commonMetadata & metadata
- commonMetadata 共有格式的數(shù)據(jù)內(nèi)容
- metadata 不一定通用的格式
AVPlayer
- 在線
- 本地
- iPod
AVPlayerItem
- 代表一個(gè)播放對(duì)象
- 加載狀態(tài)
- 播放總時(shí)長(zhǎng)
- 進(jìn)行 seek 操作
AVQueuePlayer
初始化
- 在線歌曲不能獲取 metadata, 所以對(duì)于在線歌曲就不獲取 metadata
- 使用 rate 控制播放狀態(tài)
- 使用在線音頻的時(shí)候不能直接做立即播放
AudioSession
后臺(tái)播放
- Set AudioSession Category & Active
- Set App Background Mode
- [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]
管理輸入輸出設(shè)備
NowPlayingCenter
錄音
AudioSession
- 獲取錄音權(quán)限 + 填寫(xiě)使用理由
AVAudioSessionRecordPermission permission = [[AVAudioSession sharedInstance] recordPermission];
- set Category
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryRecord error:nil];[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
- set Active
[[AVAudioSession sharedInstance] setActive:YES error:nil];
- 處理打斷或設(shè)備更換
AVAudioRecorder
#import <AVFoundation/AVFoundation.h>
NSString *const AVNumberOfChannelsKey; // 聲道數(shù)
NSString *const AVSampleRateKey; // 采樣率
NSString *const AVLinearPCMBitDepthKey; // 位聲
NSString *const AVFormatIDKey;
/* ------ AVFormatIDKey ------
kAudioFormatLinearPCM = 'lpcm'
kAudioFormatApplelMA4 = 'ima4'
kAudioFormatMPEG4AAc = 'aac'
kAudioFormatULaw = 'ulaw'
kAudioFormatALaw = 'alaw'
kAudioFormatAppleLossless = 'alac'
*/
- PCM 文件: 最原始的未經(jīng)過(guò)處理的錄音文件
- 等同于: WAV
- 壓縮成: AAC, MP3(有損壓縮), FLAC(無(wú)損壓縮), ...
- iOS 不能直接錄制成 MP3 格式
NSString *filePath = [NSTemporaryDirectory() stringByAppendingFileComponent:@"tempRecord.aac"];
NSDictionary *settings = @{
AVNumberOfChannelsKey : @1,
AVSampleRateKey : @8000,
AVLinearPCMBitDepthKey : @16,
AVFormatIDKey : @(kAudioFormatMPEG4AAC)
};
NSError *error = nil;
// 生成 recorder
_recorder = [[AVAudioRecorder alloc] initWithURL:[NSURL fileURLWithPath:filePath] settings:settings error:&error];
創(chuàng)建文件
開(kāi)始錄音
- (BOOL)preparedToRecord;
- (BOOL)record;
- (BOOL)recordAtTime:(NSTimeInterval)time; // 開(kāi)始時(shí)間
- (BOOL)recordForDuration:(NSTimeInterval)duration; // 錄音時(shí)長(zhǎng)
- (BOOL)recordAtTime:(NSTimeInterval)time forDuration:(NSTimeInterval)duration;
錄音停止和文件操作
- (void)pause;
- (void)stop;
- (BOOL)deleteRecording;
@property BOOL recording;
@property NSURL *url;
@property NSTimeInterval currentTime; // 當(dāng)前錄音進(jìn)行的時(shí)間
AVAudioPlayer
- 不支持播放模式
- 調(diào)整左右聲道
- 調(diào)整播放器內(nèi)部的音量
- 調(diào)整播放速率
- 讀取播放歌曲的數(shù)據(jù)參數(shù), 例如采樣率
- 讀取某個(gè)時(shí)間點(diǎn)的歌曲聲音大小
資源類(lèi)型
| 類(lèi)型 | 資源 | 類(lèi) |
|---|---|---|
| 在線音頻流 | 音頻 URL | AVURLAsset |
| 本地音頻文件 | 音頻文件 | AVURLAsset |
| iPod歌曲 | Music.app中的歌曲 | MPMediaItem |
AVURLAsset ?: AVAsset
/* AVAsset */
@interface AVAsset : NSObject
+ assetWithURL:(NSURL *)URL;
@property (notatomic, readonly) CMTime duration;
@property NSArray *commomMetadata;
@property NSArray *metadata;
/* AVURLAsset */
@interface AVURLAsset : AVAsset
+ URLAssetWithURL: options: ;
- initWithURL: options: ;
@property NSURL *URL;
// 繼承子 AVAsset 后提供了兩個(gè)初始化方法
// 提供 URL 屬性的訪問(wèn)
// 提供 metadata 的讀取
Metadata
- 音頻數(shù)據(jù) : 聽(tīng)到的音樂(lè)
- 音頻信息 : 歌名, 專(zhuān)輯, 歌手, 封面 等
創(chuàng)建 AVURLAsset
- 三種資源轉(zhuǎn)換成 AVURLAsset
// 在線音頻
NSURL *audioURL = [NSURL URLWithString:@"http://xxx.com/music.mp3"];
AVURLAsset *audioAsset = [AVURLAsset assetWithURL:audioURL];
// 本地音頻
NSString *filePath = [[NSBundle mainBundle] pathForResources:@"music" ofType:@"mp3"];
NSURL *fileURL = [NSURL fireURLWithPath:filePath];
AVURLAsset *fileAsset = [AVURLAsset assetWithURL:fileURL];
// iPod 音頻
MPMediaQuery *query = [MPMediaQuery songsQuery];
if (query.items.count > 0) {
MPMediaItem *item = query.item[0];
AVURLAsset *iPodAsset = [AVURLAsset assetWithURL:item.assetURL];
}
AVAudioPlayer
- 初始化方法
- 盡量使用帶有 fileTypeHint 的初始化方法, 并填入 hint
- 如果使用 URL 作為參數(shù), 盡量讓其帶有后綴名, 例如: xxx.mp3
- 使用 URL 作為參數(shù)時(shí)只能是本地文件的 URL, 不能是網(wǎng)絡(luò) URL 地址
@interface AVAudioPlayer : NSObject
- initWithContentOfURL: error: ;
- initWithData: error: ;
- initWithContentOfURL: fileTypeHint: error: ; // 表示單個(gè)歌曲
- initWithData: fileTypeHint: error: ;
- fileTypeHint : 文件類(lèi)型的判斷, 幫助解碼器判斷, 使得解碼不容易出錯(cuò)