iOS多媒體音頻(下)-錄音及其播放的實(shí)例
上一篇中總結(jié)了iOS中音效和音頻播放的最基本使用方法,其中音頻的播放控制是使用AVFoundation.framework框架中的AVAudioPlayer播放器對(duì)象來(lái)實(shí)現(xiàn)的,而這里音頻的錄制則是使用了同樣框架下的一個(gè)叫AVAudioRecorder的錄音機(jī)對(duì)象來(lái)實(shí)現(xiàn),這兩個(gè)類的用法流程非常類似,類的屬性和方法也類似,例如:播放器中需要獲取音頻文件的url,而錄音機(jī)要在沙盒中Docuemnt目錄下創(chuàng)建一個(gè)音頻文件路徑url;
播放器有isPlaying變量判斷是否正在播放,錄音機(jī)中有isRecording變量表示是否正在錄制;currentTime在播放器中表示播放時(shí)間,在錄音機(jī)中則表示錄音時(shí)間;播放器通過(guò)prepareToPlay方法加載文件到緩沖區(qū),錄音機(jī)通過(guò)prepareToRecord創(chuàng)建緩沖區(qū);播放音頻有play方法,音頻錄制有record方法,另外都有pause暫停方法和stop停止方法等等,具體可直接打開(kāi)兩個(gè)類的頭文件詳細(xì)了解。
這里實(shí)現(xiàn)最基本的錄音流程以及錄音過(guò)程的控制,并通過(guò)之前使用的AVAudioPlayer來(lái)播放錄制好的音頻。注意iOS錄制的音頻為caf格式,如果需要通用化可以通過(guò)lame等插件將caf格式音頻轉(zhuǎn)成mp3格式。
錄音
這里實(shí)現(xiàn)開(kāi)始錄音,暫停,繼續(xù)以及停止錄音。
創(chuàng)建文件目錄
iOS沙盒內(nèi)胡要有三個(gè)目錄:Documents目錄,tmp目錄以及Library目錄,其中Documents目錄用來(lái)存放用戶的應(yīng)用程序數(shù)據(jù),需要定期備份的數(shù)據(jù)要放在這里,和plist文件存儲(chǔ)一樣,我們要找到存放文件的路徑,然后在該路徑下放一個(gè)我們的文件,因此要自定義一個(gè)帶后綴的文件名,將獲得的路徑和文件名拼在一起記得到我們的文件的絕對(duì)路徑:
// 文件名 #define fileName_caf @"demoRecord.caf" // 錄音文件絕對(duì)路徑 @property (nonatomic, copy) NSString *filepathCaf; // 獲取沙盒Document文件路徑 NSString *sandBoxPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; // 拼接錄音文件絕對(duì)路徑 _filepathCaf = [sandBoxPath stringByAppendingPathComponent:fileName_caf];
創(chuàng)建音頻會(huì)話
錄音前要?jiǎng)?chuàng)建一個(gè)音頻會(huì)話,同時(shí)要設(shè)置錄音類型,提供的類型有以下幾種:
- AVF_EXPORT NSString *const AVAudioSessionCategoryAmbient; // 用于錄制背景聲音,像雨聲、汽車引擎發(fā)動(dòng)噪音等,可和其他音樂(lè)混合
- AVF_EXPORT NSString *const AVAudioSessionCategorySoloAmbient; // 也是背景聲音,但其他音樂(lè)會(huì)被強(qiáng)制停止
- AVF_EXPORT NSString *const AVAudioSessionCategoryPlayback; // 音軌
- AVF_EXPORT NSString *const AVAudioSessionCategoryRecord; // 錄音
- AVF_EXPORT NSString *const AVAudioSessionCategoryPlayAndRecord; // 錄音和回放
- AVF_EXPORT NSString *const AVAudioSessionCategoryAudioProcessing; // 用于底層硬件編碼信號(hào)處理等
- AVF_EXPORT NSString *const AVAudioSessionCategoryMultiRoute; // 內(nèi)置硬件相關(guān),iOS 6.0以上可用
常用的是AVAudioSessionCategoryPlayAndRecord類型,便于錄音后播放。
// 創(chuàng)建音頻會(huì)話 AVAudioSession *audioSession=[AVAudioSession sharedInstance]; // 設(shè)置錄音類別(這里選用錄音后可回放錄音類型) [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil]; [audioSession setActive:YES error:nil];
錄音設(shè)置
錄音前要根據(jù)需要對(duì)錄音進(jìn)行一些相應(yīng)的基本設(shè)置,例如錄音格式(LinearPCM)、采樣率、通道數(shù)等等,設(shè)置保存在一個(gè)字典內(nèi)并作為初始化錄音機(jī)的一個(gè)參數(shù)。
// 錄音設(shè)置 -(NSDictionary *)getAudioSetting{ // LinearPCM 是iOS的一種無(wú)損編碼格式,但是體積較為龐大 // 錄音設(shè)置信息字典 NSMutableDictionary *recordSettings = [[NSMutableDictionary alloc] init]; // 錄音格式 [recordSettings setValue :@(kAudioFormatLinearPCM) forKey: AVFormatIDKey]; // 采樣率 [recordSettings setValue :@11025.0 forKey: AVSampleRateKey]; // 通道數(shù)(雙通道) [recordSettings setValue :@2 forKey: AVNumberOfChannelsKey]; // 每個(gè)采樣點(diǎn)位數(shù)(有8、16、24、32) [recordSettings setValue :@16 forKey: AVLinearPCMBitDepthKey]; // 采用浮點(diǎn)采樣 [recordSettings setValue:@YES forKey:AVLinearPCMIsFloatKey]; // 音頻質(zhì)量 [recordSettings setValue:@(AVAudioQualityMedium) forKey:AVEncoderAudioQualityKey]; // 其他可選的設(shè)置 // ... ... return recordSettings; }
創(chuàng)建錄音機(jī)對(duì)象
錄音機(jī)對(duì)象的創(chuàng)建主要是利用上面的保存路徑和錄音設(shè)置進(jìn)行初始化得到:
// 懶加載錄音機(jī)對(duì)象get方法 - (AVAudioRecorder *)audioRecorder { if (!_audioRecorder) { // 保存錄音文件的路徑url NSURL *url = [NSURL URLWithString:_filepathCaf]; // 創(chuàng)建錄音格式設(shè)置setting NSDictionary *setting = [self getAudioSetting]; // error NSError *error=nil; _audioRecorder = [[AVAudioRecorder alloc]initWithURL:url settings:setting error:&error]; _audioRecorder.delegate = self; _audioRecorder.meteringEnabled = YES;// 監(jiān)控聲波 if (error) { NSLog(@"創(chuàng)建錄音機(jī)對(duì)象時(shí)發(fā)生錯(cuò)誤,錯(cuò)誤信息:%@",error.localizedDescription); return nil; } } return _audioRecorder; }
錄音控制方法
錄音過(guò)程控制主要是開(kāi)始錄音、暫停、繼續(xù)和停止錄音,其中開(kāi)始錄音和繼續(xù)錄音都是record方法。
// 開(kāi)始錄音或者繼續(xù)錄音 - (IBAction)startOrResumeRecord { // 注意調(diào)用audiorecorder的get方法 if (![self.audioRecorder isRecording]) { // 如果該路徑下的音頻文件錄制過(guò)則刪除 [self deleteRecord]; // 開(kāi)始錄音,會(huì)取得用戶使用麥克風(fēng)的同意 [_audioRecorder record]; } } // 錄音暫停 - (IBAction)pauseRecord { if (_audioRecorder) { [_audioRecorder pause]; } } // 結(jié)束錄音 - (IBAction)stopRecord { [_audioRecorder stop]; }
錄音播放
錄音的播放很簡(jiǎn)單,就是之前AVAudioPlayer音頻播放的簡(jiǎn)單應(yīng)用,播放的路徑即我們錄音時(shí)創(chuàng)建好的音頻路徑。但這里注意為了保證每次都播放最新錄制的音頻,播放器的get方法要每次重新創(chuàng)建初始化。
// audioPlayer懶加載getter方法 - (AVAudioPlayer *)audioPlayer { _audioRecorder = NULL; // 每次都創(chuàng)建新的播放器,刪除舊的 // 資源路徑 NSURL *url = [NSURL fileURLWithPath:_filepathCaf]; // 初始化播放器,注意這里的Url參數(shù)只能為本地文件路徑,不支持HTTP Url NSError *error = nil; _audioPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:url error:&error]; //設(shè)置播放器屬性 _audioPlayer.numberOfLoops = 0;// 不循環(huán) _audioPlayer.delegate = self; _audioPlayer.volume = 0.5; // 音量 [_audioPlayer prepareToPlay];// 加載音頻文件到緩存【這個(gè)函數(shù)在調(diào)用play函數(shù)時(shí)會(huì)自動(dòng)調(diào)用】 if(error){ NSLog(@"初始化播放器過(guò)程發(fā)生錯(cuò)誤,錯(cuò)誤信息:%@",error.localizedDescription); return nil; } return _audioPlayer; } // 播放錄制好的音頻 - (IBAction)playRecordedAudio { // 沒(méi)有文件不播放 if (![[NSFileManager defaultManager] fileExistsAtPath:self.filepathCaf]) return; // 播放最新的錄音 [self.audioPlayer play]; }
完整源碼和Demo下載
// // ViewController.m // IOSRecorderDemo // // Created by Xinhou Jiang on 29/12/16. // Copyright © 2016年 Xinhou Jiang. All rights reserved. // #import "ViewController.h" #import <AVFoundation/AVFoundation.h> // 文件名 #define fileName_caf @"demoRecord.caf" @interface ViewController () // 錄音文件絕對(duì)路徑 @property (nonatomic, copy) NSString *filepathCaf; // 錄音機(jī)對(duì)象 @property (nonatomic, strong) AVAudioRecorder *audioRecorder; // 播放器對(duì)象,和上一章音頻播放的方法相同,只不過(guò)這里簡(jiǎn)單播放即可 @property (nonatomic, strong) AVAudioPlayer *audioPlayer; // 用一個(gè)processview顯示聲波波動(dòng)情況 @property (nonatomic, weak) IBOutlet UIProgressView *processView; // 用一個(gè)label顯示錄制時(shí)間 @property (nonatomic, weak) IBOutlet UILabel *recordTime; // UI刷新監(jiān)聽(tīng)器 @property (nonatomic, strong) NSTimer *timer; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // 初始化工作 [self initData]; } // 初始化 - (void)initData { // 獲取沙盒Document文件路徑 NSString *sandBoxPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; // 拼接錄音文件絕對(duì)路徑 _filepathCaf = [sandBoxPath stringByAppendingPathComponent:fileName_caf]; // 1.創(chuàng)建音頻會(huì)話 AVAudioSession *audioSession=[AVAudioSession sharedInstance]; // 設(shè)置錄音類別(這里選用錄音后可回放錄音類型) [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil]; [audioSession setActive:YES error:nil]; // 2.開(kāi)啟定時(shí)器 [self timer]; } #pragma mark -錄音設(shè)置工具函數(shù) // 懶加載錄音機(jī)對(duì)象get方法 - (AVAudioRecorder *)audioRecorder { if (!_audioRecorder) { // 保存錄音文件的路徑url NSURL *url = [NSURL URLWithString:_filepathCaf]; // 創(chuàng)建錄音格式設(shè)置setting NSDictionary *setting = [self getAudioSetting]; // error NSError *error=nil; _audioRecorder = [[AVAudioRecorder alloc]initWithURL:url settings:setting error:&error]; _audioRecorder.delegate = self; _audioRecorder.meteringEnabled = YES;// 監(jiān)控聲波 if (error) { NSLog(@"創(chuàng)建錄音機(jī)對(duì)象時(shí)發(fā)生錯(cuò)誤,錯(cuò)誤信息:%@",error.localizedDescription); return nil; } } return _audioRecorder; } // audioPlayer懶加載getter方法 - (AVAudioPlayer *)audioPlayer { _audioRecorder = NULL; // 每次都創(chuàng)建新的播放器,刪除舊的 // 資源路徑 NSURL *url = [NSURL fileURLWithPath:_filepathCaf]; // 初始化播放器,注意這里的Url參數(shù)只能為本地文件路徑,不支持HTTP Url NSError *error = nil; _audioPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:url error:&error]; //設(shè)置播放器屬性 _audioPlayer.numberOfLoops = 0;// 不循環(huán) _audioPlayer.delegate = self; _audioPlayer.volume = 0.5; // 音量 [_audioPlayer prepareToPlay];// 加載音頻文件到緩存【這個(gè)函數(shù)在調(diào)用play函數(shù)時(shí)會(huì)自動(dòng)調(diào)用】 if(error){ NSLog(@"初始化播放器過(guò)程發(fā)生錯(cuò)誤,錯(cuò)誤信息:%@",error.localizedDescription); return nil; } return _audioPlayer; } // 計(jì)時(shí)器get方法 - (NSTimer *)timer { if (!_timer) { _timer = [NSTimer scheduledTimerWithTimeInterval:0.1f repeats:YES block:^(NSTimer * _Nonnull timer) { if(_audioRecorder) { // 1.更新錄音時(shí)間,單位秒 int curInterval = [_audioRecorder currentTime]; _recordTime.text = [NSString stringWithFormat:@"%02d:%02d",curInterval/60,curInterval%60]; // 2.聲波顯示 //更新聲波值 [self.audioRecorder updateMeters]; //第一個(gè)通道的音頻,音頻強(qiáng)度范圍:[-160~0],這里調(diào)整到0~160 float power = [self.audioRecorder averagePowerForChannel:0] + 160; [_processView setProgress:power/160.0]; } }]; } return _timer; } // 錄音設(shè)置 -(NSDictionary *)getAudioSetting{ // LinearPCM 是iOS的一種無(wú)損編碼格式,但是體積較為龐大 // 錄音設(shè)置信息字典 NSMutableDictionary *recordSettings = [[NSMutableDictionary alloc] init]; // 錄音格式 [recordSettings setValue :@(kAudioFormatLinearPCM) forKey: AVFormatIDKey]; // 采樣率 [recordSettings setValue :@11025.0 forKey: AVSampleRateKey]; // 通道數(shù)(雙通道) [recordSettings setValue :@2 forKey: AVNumberOfChannelsKey]; // 每個(gè)采樣點(diǎn)位數(shù)(有8、16、24、32) [recordSettings setValue :@16 forKey: AVLinearPCMBitDepthKey]; // 采用浮點(diǎn)采樣 [recordSettings setValue:@YES forKey:AVLinearPCMIsFloatKey]; // 音頻質(zhì)量 [recordSettings setValue:@(AVAudioQualityMedium) forKey:AVEncoderAudioQualityKey]; // 其他可選的設(shè)置 // ... ... return recordSettings; } // 刪除filepathCaf路徑下的音頻文件 -(void)deleteRecord{ NSFileManager* fileManager=[NSFileManager defaultManager]; if ([[NSFileManager defaultManager] fileExistsAtPath:self.filepathCaf]) { // 文件已經(jīng)存在 if ([fileManager removeItemAtPath:self.filepathCaf error:nil]) { NSLog(@"刪除成功"); }else { NSLog(@"刪除失敗"); } }else { return; // 文件不存在無(wú)需刪除 } } #pragma mark -錄音流程控制函數(shù) // 開(kāi)始錄音或者繼續(xù)錄音 - (IBAction)startOrResumeRecord { // 注意調(diào)用audiorecorder的get方法 if (![self.audioRecorder isRecording]) { // 如果該路徑下的音頻文件錄制過(guò)則刪除 [self deleteRecord]; // 開(kāi)始錄音,會(huì)取得用戶使用麥克風(fēng)的同意 [_audioRecorder record]; } } // 錄音暫停 - (IBAction)pauseRecord { if (_audioRecorder) { [_audioRecorder pause]; } } // 結(jié)束錄音 - (IBAction)stopRecord { [_audioRecorder stop]; } #pragma mark -錄音播放 // 播放錄制好的音頻 - (IBAction)playRecordedAudio { // 沒(méi)有文件不播放 if (![[NSFileManager defaultManager] fileExistsAtPath:self.filepathCaf]) return; // 播放最新的錄音 [self.audioPlayer play]; } @end
Demo下載:demo
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 解決ios微信下vue項(xiàng)目組件切換并自動(dòng)播放音頻問(wèn)題
- IOS中微信小程序播放緩存的音頻文件的方法
- iOS開(kāi)發(fā)中音頻視頻播放的簡(jiǎn)單實(shí)現(xiàn)方法
- iOS中的音頻服務(wù)和音頻AVAudioPlayer音頻播放器使用指南
- 詳解iOS應(yīng)用中播放本地視頻以及選取本地音頻的組件用法
- iOS開(kāi)發(fā)實(shí)現(xiàn)音頻播放功能
- 詳解iOS App中調(diào)用AVAudioPlayer播放音頻文件的用法
- 實(shí)例解析iOS app開(kāi)發(fā)中音頻文件播放工具類的封裝
- iOS開(kāi)發(fā)中音頻工具類的封裝以及音樂(lè)播放器的細(xì)節(jié)控制
- iOS獲取本地音頻文件(屬性/信息)
相關(guān)文章
iOS如何固定UITableView中cell.imageView.image的圖片大小
這篇文章主要給大家介紹了關(guān)于iOS如何固定UITableView中cell.imageView.image圖片大小的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)各位iOS開(kāi)發(fā)者們的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-11-11Objective-C中編程中一些推薦的書寫規(guī)范小結(jié)
這篇文章主要介紹了Objective-C的一些編程書寫規(guī)范小結(jié),包括類與方法等面向?qū)ο缶幊滔嚓P(guān)的代碼編寫風(fēng)格,需要的朋友可以參考下2016-04-04iOS開(kāi)發(fā)實(shí)現(xiàn)計(jì)算器功能
這篇文章主要為大家詳細(xì)介紹了iOS開(kāi)發(fā)實(shí)現(xiàn)計(jì)算器功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10iOS使用 CABasicAnimation 實(shí)現(xiàn)簡(jiǎn)單的跑馬燈(無(wú)cpu暴漲)
本篇文章主要介紹了iOS使用 CABasicAnimation 實(shí)現(xiàn)簡(jiǎn)單的跑馬燈(無(wú)cpu暴漲),具有一定的參考價(jià)值,有興趣的可以了解一下。2017-01-01iOS中幾種定時(shí)器的實(shí)現(xiàn)小結(jié)
這篇文章主要介紹了iOS中幾種定時(shí)器的實(shí)現(xiàn)小結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01