音頻播放(iOS開發)


音頻處理

一.錄音

  1. 錄音應用場景
    • 語音聊天
      • 即時通訊軟件中,都包含語音發送功能
    • 語音備忘錄
      • 錄一段音頻,來記錄某件事情
  2. 錄音功能實現
    • 導入AVFoundation框架
      • 作用:一些多媒體的處理,基本上都是用這個框架
      • #import <AVFoundation/AVFoundation.h>
    • 使用AVAudioRecorder進行錄音
      1. 創建錄音文件存放路徑
      2. 設置錄音附加設置項
        • #import <AVFoundation/AVAudioSettings.h>
        • 錄音參數設置,保存到字典中,不需要掌握,固定的設置
        • 設置編碼格式:AVFormatIDKey
        • 采樣率:AVSampleRateKey
        • 通道數:AVNumberOfChannelsKey
        • 音頻質量,采樣質量:AVEncoderAudioQualityKey
      3. 根據路徑以及設置項,創建錄音對象
        • _audioRecorder = [[AVAudioRecorder alloc] initWithURL:url settings:recordSettings error:nil];
      4. 准備錄音
        • [self.audioRecorder prepareToRecord];
      5. 開始錄音
        • [self.audioRecorder record];
      6. 停止錄音
        • [self.audioRecorder stop];
  3. 概念補充
    • 編碼
      • 概念:編碼是信息從一種形式轉換為另一種形式的過程
      • 編碼格式:
        • PCM:脈沖編碼調制,是一種非壓縮音頻數字化技術,是一種未壓縮的原音重現,數字模式下,音頻的廚師信號是PCM
        • MP3
        • AAC:AAC其實是"高級音頻編碼(advanced audio coding)"的縮寫,它是被設計用來取代MP3格式的
        • HE-AAC:HE-AAC是AAC的一個超集,這個"HE"代表的是"high efficiency",HE-AAC是專門為低比特率所優化的一種音頻編碼格式
        • AMR:AMR全稱是"adaptive multi-rate"的縮寫,它也是專門為低比特率所優化的一種音頻編碼格式
        • ALAC:它全稱是"Apple Lossless",這是一種沒有任何質量損失的音頻編碼方式,也就是我們說的無損壓縮
        • IMA4:這是一個在16bit音頻文件下按照4:1的壓縮比來進行壓縮的格式
    • 文件格式(不同的文件格式,可保存不同的編碼格式編碼的文件)
      • wav
        • 特點:音質最好的格式,對應PCM編碼
        • 適用:多媒體開發/保存音樂/音效素材
      • mp3
        • 特點:音質好,壓縮比比較高,被大量軟件和硬件支持
        • 適用:適合用於比較高要求的音樂欣賞
      • caf
        • 特點:適用於幾乎iOS中所有的編碼格式
  4. 開發經驗
    • caf文件格式,因為某些編碼設置,文件可能會很大,而且caf格式並不是很通用,所以在開發過程中,一般會進行壓縮轉碼為MP3格式
  5. lame靜態庫

二.音效播放

1.音效概念簡介

  • 音效和音樂的區別
    • 其實並沒有嚴格意義上的限定,一般在開發中,將時間比較短,播放頻率比較高的,當做音效處理
    • 將播放時間比較長,需要監聽播放進度,控制播放速率等操作的音頻當做音樂處理

2.導入AVFoundation框架

  • 其實音效處理對應的框架是AudioToolbox,只不過AVFoundation框架包含了此框架

3.使用對應的API,開始播放音效

  1. 根據音效文件,生成SystemSoundID
    • 獲取URL
      • CFURLRef urlRef = (__bridge CFURLRef)([[NSBundle mainBundle] URLForResource:@"m_16.wav" withExtension:nil]);
    • 創建保存soundID的變量
      • SystemSoundID soundID;
    • 通過URL和SoundID的地址,接收對應的音效SoundID
      • AudioServicesCreateSystemSoundID(urlRef, &soundID);
  2. 播放音效
    • AudioServicesPlaySystemSound(soundID);
      • 效果:直接播放,沒有震動效果
    • AudioServicesPlayAlertSound(soundID);
      • 效果:直接播放,有震動效果
    • AudioServicesPlaySystemSoundWithCompletion(soundID,block);
      • 效果:帶有播放完成回調代碼塊
  3. 根據SoundID釋放內存
    • AudioServicesDisposeSystemSoundID(soundID);
  4. 代碼優化,播放工具類的封裝
    • 優化SoundID的生成,不需要每次都創建一遍
    • 封裝播放邏輯,供多處調用

三.音樂播放

1.音樂播放

  1. 導入AVFoundation框架
  2. 使用AVAudioPlayer類,進行播放音樂
    • 根據音頻文件URL,創建AVAudioPlayer對象
      • 獲取資源URL
        • NSURL *url = [[NSBundle mainBundle] URLForResource:@"test.mp3" withExtension:nil];
      • 根據資源URL,創建AVAudioPlayer對象
        • AVAuioPlayer audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
    • 准備播放
      • [self.audioPlayer prepareToPlay];
    • 開始播放
      • [self.audioPlayer play];
  3. 附加設置
    • 暫停
      • [self.audioPlayer pause];
    • 停止
      • [self.audioPlayer stop];
        • 停止某個音樂,下次再播放,會從當前位置開始播放
      • self.audioPlayer.currentTime = 0;
        • 重置當前播放時間
    • 快進
      • 系統已經對currentTime做了容錯處理,不用擔心事件為負數或者大於音樂總時長
      • self.audioPlayer.currentTime += 5;
    • 倍速播放
      • 1.0為正常
      • 設置允許調整播放速率,注意,此方法必須設置在准備播放之前(經測試,在播放前也可以)
      • self.audioPlayer = nil;
      • self.audioPlayer.enableRate = YES;
      • self.audioPlayer.rate = 2.0;
    • 音量調節
      • 音量調節范圍:0.0~1.0
      • self.audioPlayer.volume = slider.value;
    • 監聽播放事件
      • 設置代理
      • 實現代理方法
  4. 后台播放
    • 注意:模擬器測試不准確,以真機為准
    • 勾選后台模式
    • 激活音頻播放會話
      • 在iOS中每個應用都有一個音頻會話,這個會話就可以通過AVAudioSessiion來表示
      • AVAudioSession同樣存在於AVFoundation框架中,它是單例模式設計,通過sharedInstance進行訪問
      • 音頻會話類型簡介
        • AVAudioSessionCategoryAmbient
          • 混音播放,可以與其他音頻應用同時播放
        • AVAudioSessionCategorySoloAmbient
          • 獨占播放
        • AVAudioSessionCategoryPlayback
          • 后台播放,也是獨占的
        • AVAudioSessionCategoryRecord
          • 錄音模式,用於錄音時使用
        • AVAudioSessionCategoryPlayAndRecord
          • 播放和錄音,此時可以錄音也可以播放
        • AVAudioSessionCategoryProcessing
          • 硬件解碼音頻,此時不能播放和錄制
        • AVAudioSessionCategoryMultiRoute
          • 多種輸入輸出,例如可以耳機/USB設備同時播放
    • 代碼實現
      • 獲取音頻會話
        • AVAudioSession *session = [AVAudioSession sharedInstace];
      • 設置會話分類
        • [session setCategory: AVAudioSessionCategoryPlayback error:nil];
      • 激活會話
        • [session setActive:YES error:nil];
  5. 代碼封裝重構(注意容錯處理)
    • 結合QQ音樂案例進行封裝
  6. 使用須知
    • 每一個AVPlayer對象對應一個音頻播放,如果想播放多個音頻,就需要創建多個AVPlayer
    • 使用AVAudioPlayer類,只能播放本地資源,不能播放遠程音樂
  7. 測試環境
    • 后台播放,需要使用真機進行測試,模擬器測試不准確

2.模仿QQ音樂

  1. 搭建項目結構
    • 划分項目功能模塊,創建文件夾結構
      • 音樂列表
        • 主要負責展示音樂列表,當點擊某一個音樂時,就播放對應音樂,停止其他音樂播放
      • 音樂詳情
        • 主要負責展示音樂詳情,包含音樂名稱/歌手/專輯圖片/歌詞/進度以及控制邏輯
    • 拖入必要的資源和工具類,以及第三方框架(可以使用時再拖入)
    • 根據界面跳轉邏輯,搭建Storyboard,並創建好對應的控制器
      • 導航控制器為初始控制器,其根控制器為UITableViewController(QQ音樂列表控制器)
      • 當點擊QQ音樂列表控制器某一行時,跳轉到詳情控制愛UIViewController
  2. 實現音樂列表功能
    • 界面基本設置
      • 背景圖片
      • 隱藏導航欄
      • 狀態欄設置為白色
    • 加載QQ列表數據
      • 經驗:千萬不要把獲取數據的實現邏輯寫在控制器中,不利於維護和重用,也不利於后期擴展
      • 創建數據模型
        • 根據音樂列表plist文件內容,創建對應的音樂數據模型xxxMusicModel
      • 創建數據操作工具類
        • 主要負責數據的獲取,和以后數據的操作
        • 此處提供,供外界調用的獲取數據的接口
        • 請使用block將數據傳遞出去,不要直接返回一個數組(因為后期如果改為從網絡獲取列表,因為網絡獲取數據是異步的,所以返回的結果可能為nil)
        • 獲取所有音樂列表的接口如下:
          • getMusicModelsWithResultBlock:block
      • 在表格控制器內,調用數據操作類提供的接口,加載數據並顯示
    • 音樂列表界面展示
      • 使用自定義cell,以便后期擴充
    • 預留好對接接口
      • 經驗:知道到時候在哪里調用真正的外接播放接口/停止接口,為了統一管理
      • 播放接口
      • 停止播放接口
    • 實現音樂播放功能
      • 經驗:千萬不要把播放的業務實現邏輯直接寫在控制器里面,應當抽取一個工具類
      • 高級經驗:針對於音樂播放功能,建議分為兩層
        • 最底層負責單個音樂的播放/暫停/停止等操作
        • 上層則負責播放的業務邏輯,比如上一首/下一首/隨機播放/順序播放等
        • 這樣易於維護,重用和擴展
      • 封裝單個音樂文件操作的工具類(xxxAudioTool)
        • 接口1:根據音頻名稱播放音頻
          • playAudioWithName:
        • 接口2:暫停音頻
          • pauseCurrentAudio
        • 接口3:停止音頻
          • stopCurrentAudio
      • 封裝多個音樂文件操作的工具類(xxxMusicOperationTool)
        • 接口1:根據音樂數據模型,播放一首音樂
          • playMusicWithMusicModel:
        • 接口2:暫停當前音樂
          • pauseCurrentMusic
        • 接口3:停止當前音樂
          • stopCurrentMusic
      • 重要建議:
        • 將此工具類設計成為一個單例
        • 因為會有很多界面使用,而且多個界面操作的數據一致
    • 功能測試
      • 在預留接口中,調用工具類的對應接口,然后測試
      • 音樂列表功能開發結束
  3. 詳情界面實現
    • 音樂詳情界面搭建
      1. 分析界面結構,選擇合適控件搭建界面
      2. 注意將同一組子控件使用一個父控件進行包裝,方便添加約束布局
      3. 稍微不好構思的地方在於歌詞界面和專輯界面的切換,需要借助UIScrollView
      4. 關聯屬性和方法到對應的詳情控制器,方便后續的動畫和賦值操作
    • 擴展音樂播放工具類接口,實現播放業務邏輯,並展示音樂詳情
      1. 擴展多個音樂操作的工具類(xxxMusicOperationTool)的上一首/下一首等接口
        • 接口1:播放上一首音樂
          • preMusic
        • 接口2:播放下一首音樂
          • nextMusic
      2. 在控制器對應的關聯方法中,調用不同的播放接口,進行測試
      3. 將需要展示的數據按"刷新頻率"進行分類,分別提供"單次刷新"和"實時刷新"方法
        • 需要根據不同的數據刷新頻率,采用不同的刷新策略
        • 如果實時刷新,就可以使用NSTimer,使用定時任務不斷刷新,展示最新數據,比如播放進度,就需要不斷刷新
        • 而歌曲圖片和作者,只需要刷新一次
      4. 匯總所有需要刷新的字段,根據字段,創建歌曲播放信息數據模型(此數據模型由多個音樂操作的工具類同一提供)
        • 不要非常零散的單獨獲取,到處拼湊
        • 之所以由工具類統一提供歌曲播放信息數據模型,主要原因
          • 因為此功能,應該划分到此類的業務邏輯中
          • 只有這個類,最了解當前音樂的播放信息
      5. 直接從控制器預留的"單次刷新"和"實時刷新"刷新方法中,從多個音樂操作的工具類中獲取最新的音樂播放數據
    • 實時更新歌詞,並實現進度展示
      • 創建歌詞數據模型(xxxLrcModel)
        • 屬性列表
        • 每一句歌詞開始時間
          • @property (nonatomic, assign) double beginTime;
        • 每一句歌詞結束時間
          • @property (nonatomic, assign) double endTime;
        • 每一句歌詞的內容
          • @property (nonatomic, copy) NSString *lrcText;
      • 創建歌詞解析工具類(xxxLrcTool),負責解析不同歌曲對應的歌詞文件
        • 根據歌詞文件名稱,解析歌詞
          • getLrcModelsWithLrcName:
        • 根據某個時間點,獲取歌詞模型數組中對應的歌詞模型
          • getLrcModelInModels:withTime:
      • 使用UITableView展示歌詞
        • 單獨抽離一個控制器,負責管理歌詞
      • 根據當前播放進度,實時滾動切換歌詞
      • 根據每句歌詞的播放進度,通過顏色展示單句歌詞進度
        • 自定義集成自UILabel的子類
        • 重寫drawRect:方法
          • CGRect fillRect = CGRectMake(0,0,rect.size.width*self.progress,rect.size.height);
          • [[UIColor greenColor] set];
          • UIRectFillUsingBlendMode(fillRect,kCGBlendModeSourceIn);
  4. 后台播放實現
    • 勾選后台模式->音頻播放
    • 激活音頻播放會話
      • 獲取音頻會話
      • 設置會話分類
      • 激活會話
  5. 顯示鎖屏界面,並接收遠程事件
    • 顯示鎖屏信息
      • 獲取鎖屏信息中心
        • MPNowPlayingInfoCenter *playInfoCenter = [MPNowPlayingInfoCenter defaultCenter];
      • 創建鎖屏信息(信息從多音樂操作工具類中獲取,並保存到可變字典dic中)
      • 設置鎖屏信息
        • playInfoCenter.nowPlayingInfo = dic;
      • 接收遠程控制事件
        • [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
    • 接收遠程事件
      • 可以監聽遠程事件的前提
        • 必須啟動遠程事件接收
        • 必須可以成為第一響應者
        • 應用程序必須是該事件的控制者
      • 在控制器中需要實現的方法
        • remoteControlReceivedWithEvent:
      • 補充:事件類型對應的含義
        • UIEventSubtypeNone
          • 不包含任何字事件類型
        • UIEventSubtypeMotionShake
          • 搖晃事件(從iOS3.0開始支持此事件)
        • 遠程控制自事件類型(從iOS4.0開始支持遠程控制事件)
        • UIEventSubtypeRemoteControlPlay
          • 播放事件(操作:停滯狀態下,按二級線控中間按鈕一下)
        • UIEventSubtypeRemoteControlPause
          • 暫停事件
        • UIEventSubtypeRemoteControlStop
          • 停止事件
        • UIEventSubtypeRemoteControlTogglePlayPause
          • 播放或暫停切換(操作:播放或暫停狀態下,按耳機線控中間按鈕一下)
        • UIEventSubtypeRemoteControlNextTrack
          • 下一曲(操作:按耳機線控中間按鈕兩下)
        • UIEventSubtypeRemoteControlPreviousTrack
          • 上一曲(操作:按耳機線控中間按鈕三下)
        • UIEventSubtypeRemoteControlBeginSeekingBackward
          • 快退開始(操作:按耳機線控中間按鈕三下不要松開)
        • UIEventSubtypeRemoteControlEndSeekingBackward
          • 快退停止(操作:按耳機線控中間按鈕三下到了快退的位置松開)
        • UIEventSubtypeRemoteControlBeginSeekingForward
          • 快進開始(操作:按耳機線控中間按鈕兩下不要松開)
        • UIEventSubtypeRemoteControlEndSeekingForward
          • 快進停止(操作:按耳機線控中間按鈕兩下到了快進的位置松開)
  6. 鎖屏界面顯示歌詞
    • 實現方案:利用鎖屏顯示圖片設置項,實時的將歌詞繪制到圖片上,組成一個新的圖片,設置為鎖屏的圖片
    • 繪制步驟
      1. 開啟圖形上下文
      2. 繪制背景圖片
      3. 獲取歌詞信息,並繪制
      4. 從圖形上下文中獲取混合圖片
      5. 關閉圖形上下文
    • 注意:效率優化
  7. 功能完善,細節處理
    1. 通過進度條拖拽,控制播放進度
    2. 通過點擊進度條某個位置,控制播放進度
    3. 自動播放下一首
    4. 列表歌詞頁的歌詞進度展示
    5. iOS9.0新推出的Storyboard Reference

3.播放遠程音樂

  • 使用AVPlayer來播放遠程音樂
  • 方案1:
    • 根據URL,創建AVPlayer
      • self.player = [[AVPlayer alloc] initWithURL:remoteURL];
    • 播放
      • [self.player play];
  • 方案2:
    • 根據AVPlayerItem,創建AVPlayer
      • NSURL *remoteURL = [NSURL URLWithString:remoteURL];
      • AVPlayerItem *playerItem = [AVPlayerItem playerItemWihtURL:remoteURL];
      • self.player = [[AVPlayer alloc] initWithPlayerItem:playerItem];
    • 播放
      • [self.player play];
  • 方案對比
    • 如果通過方案1播放某個遠程音頻,那么后面如果想要更改音樂,則需要重新創建AVPlayer對象
    • 方案2就可以直接通過更改播放項來間接更換播放遠程音樂


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM