簡單粗暴的錄音、播放功能

參考:http://blog.csdn.net/u013346305/article/details/47280731#t8

代碼看下面,需要看效果的話直接復制到控制器即可,注意的是本案例采用storyboard布置界面,需要自己往ViewController里面拖拽幾個UIBarButtonItem,并對UIBarButtonItem對應的方法連線。

注意以下是AVAudioRecorder文件里面主要的屬性、對象方法、代理方法,并不是全部的,如有需要還得AVAudioRecorder.h中查看完整的屬性、對象方法、代理方法。

屬性 說明
@property(readonly, getter=isRecording) BOOL recording; 是否正在錄音,只讀
@property(readonly) NSURL *url; 錄音文件存儲地址,只讀
@property(readonly) NSDictionary *settings; 錄音文件設置, 只讀
@property(readonly) NSTimeInterval currentTime; 錄音時長,注意僅僅在錄音狀態可用
@property(readonly) NSTimeInterval deviceCurrentTime; 輸入設置的時間長度,只讀 注意此屬性一直可訪問
@property(getter=isMeteringEnabled) BOOL meteringEnabled; 是否啟用錄音測量 ,如果啟用錄音測量可以獲得錄音分貝等數據信息
@property(nonatomic, copy) NSArray *channelAssignments; 當前錄音的通道
對象方法 說明
- (instancetype)initWithURL:(NSURL *)url settings:(NSDictionary *)settings error:(NSError **)outError; 錄音機對象初始化方法,注意其中的url必須是本地文件url,settings是錄音格式、編碼等設置
- (BOOL)prepareToRecord 準備錄音,主要用于創建緩沖區,如果不手動調用,在調用record錄音時也會自動調用
- (BOOL)record 開始錄音
- (BOOL)recordAtTime:(NSTimeInterval)time; 在指定的時間開始錄音,一般用于錄音暫停再恢復錄音
- (BOOL)recordForDuration:(NSTimeInterval) duration; 按指定的時長開始錄音
- (BOOL)recordAtTime:(NSTimeInterval)time forDuration:(NSTimeInterval) duration; 在指定的時間開始錄音,并指定錄音時長
- (void)pause; 暫停錄音
- (void)stop; 停止錄音
- (BOOL)deleteRecording; 刪除錄音,注意要刪除錄音此時錄音機必須處于停止狀態
- (void)updateMeters; 更新測量數據,注意只有meteringEnabled為YES此方法才可用
- (float)peakPowerForChannel:(NSUInteger)channelNumber; 指定通道的測量峰值,注意只有調用完updateMeters才有值
- (float)averagePowerForChannel:(NSUInteger)channelNumber; 指定通道的測量平均值,注意只有調用完updateMeters才有值
代理方法 說明
- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag; 完成錄音
- (void)audioRecorderEncodeErrorDidOccur:(AVAudioRecorder *)recorder error:(NSError *)error; 錄音編碼發生錯誤
//
//  ViewController.m
//  錄音
//
//  Created by wwh on 17/2/21.
//  Copyright ? 2017年 wwh. All rights reserved.
//

#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>
#import "MBProgressHUD.h"

#define kRecordAudioFile @"Record.caf"

@interface ViewController ()<AVAudioRecorderDelegate, AVAudioPlayerDelegate, MBProgressHUDDelegate>

@property (nonatomic,strong) AVAudioRecorder *audioRecorder;//音頻錄音機
@property (nonatomic,strong) AVAudioPlayer *audioPlayer;//音頻播放器,用于播放錄音文件
@property (nonatomic,strong) NSTimer *timer;//錄音聲波監控
@property (nonatomic,strong) NSTimer *timer1;//播放聲波監控
@property (weak, nonatomic) IBOutlet UIProgressView  *audioPower;//音頻波動
@end

@implementation ViewController

#pragma mark - 控制器視圖方法

- (void)dealloc {
    [self.timer invalidate];
    self.timer = nil;
    
    [self.timer1 invalidate];
    self.timer1 = nil;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // 設置控制器View背景
    self.view.backgroundColor = [UIColor darkGrayColor];
    
    // 設置音頻會話
    [self setAudioSession];
}

#pragma mark - 私有方法
/**
 *  設置音頻會話
 */
- (void)setAudioSession {
    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    //設置為播放和錄音狀態,以便可以在錄制完之后播放錄音
    [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
    [audioSession setActive:YES error:nil];
}

/**
 *  取得錄音文件保存路徑
 *
 *  @return 錄音文件路徑
 */
- (NSURL *)getSavePath {
    NSString *urlStr = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    urlStr = [urlStr stringByAppendingPathComponent:kRecordAudioFile];
    NSURL *url = [NSURL fileURLWithPath:urlStr];
    return url;
}

/**
 *  取得錄音文件設置
 *  Note:在創建錄音機時除了指定路徑外還必須指定錄音設置信息,因為錄音機必須知道錄音文件的格式、采樣率、通道數、每個采樣點的位數等信息,但是也并不是所有的信息都必須設置,通常只需要幾個常用設置
 *
 *  @return 錄音設置
 */
- (NSDictionary *)getAudioSetting{
    NSMutableDictionary *dicSettings = [NSMutableDictionary dictionary];
    //設置錄音格式
    [dicSettings setObject:@(kAudioFormatLinearPCM) forKey:AVFormatIDKey];
    //設置錄音采樣率,8000是電話采樣率,對于一般錄音已經夠了
    [dicSettings setObject:@(8000) forKey:AVSampleRateKey];
    //設置通道,這里采用單聲道
    [dicSettings setObject:@(1) forKey:AVNumberOfChannelsKey];
    //每個采樣點位數,分為8、16、24、32
    [dicSettings setObject:@(8) forKey:AVLinearPCMBitDepthKey];
    //是否使用浮點數采樣
    [dicSettings setObject:@(YES) forKey:AVLinearPCMIsFloatKey];
    //....其他設置等
    return dicSettings;
}

/**
 *  獲得AVAudioRecorder對象
 *
 *  @return AVAudioRecorder對象
 */
- (AVAudioRecorder *)audioRecorder{
    if (!_audioRecorder) {
        //創建錄音文件保存路徑
        NSURL *url = [self getSavePath];
        //創建錄音格式設置
        NSDictionary *setting = [self getAudioSetting];
        //創建錄音機
        NSError *error = nil;
        _audioRecorder = [[AVAudioRecorder alloc] initWithURL:url settings:setting error:&error];
        _audioRecorder.delegate = self;
        _audioRecorder.meteringEnabled = YES;//如果要監控聲波則必須設置為YES
        if (error) {
            NSLog(@"創建錄音機對象時發生錯誤,錯誤信息:%@",error.localizedDescription);
            return nil;
        }
    }
    return _audioRecorder;
}

/**
 *  創建播放器
 *
 *  @return 播放器
 */
- (AVAudioPlayer *)audioPlayer{
    if (!_audioPlayer) {
        NSURL *url = [self getSavePath];
        NSError *error = nil;
        _audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
        _audioPlayer.numberOfLoops = 0;
        _audioPlayer.delegate = self;
        _audioPlayer.meteringEnabled = YES;
        [_audioPlayer prepareToPlay];
        if (error) {
            NSLog(@"創建播放器過程中發生錯誤,錯誤信息:%@",error.localizedDescription);
            return nil;
        }
    }
    return _audioPlayer;
}

/**
 *  錄音聲波監控定制器
 *
 *  @return 定時器
 */
- (NSTimer *)timer{
    if (!_timer) {
        _timer = [NSTimer scheduledTimerWithTimeInterval:0.1f target:self selector:@selector(audioPowerChange) userInfo:nil repeats:YES];
    }
    return _timer;
}

/**
 *  播放聲波監控定制器
 *
 *  @return 定時器
 */
- (NSTimer *)timer1{
    if (!_timer1) {
        _timer1 = [NSTimer scheduledTimerWithTimeInterval:0.1f target:self selector:@selector(playAudioPowerChange) userInfo:nil repeats:YES];
    }
    return _timer1;
}

/**
 *  錄音聲波狀態設置
 */
- (void)audioPowerChange {
    [self.audioRecorder updateMeters];//更新測量值
    float power = [self.audioRecorder averagePowerForChannel:0];//取得第一個通道的音頻,注意音頻強度范圍時-160到0
    CGFloat progress = (1.0/160.0)*(power+160.0);
    [self.audioPower setProgress:progress];
}

#pragma mark - UI事件
/**
 *  點擊錄音按鈕
 *
 *  @param sender 錄音按鈕
 */
- (IBAction)recordClick:(UIBarButtonItem *)sender {
    if (![self.audioRecorder isRecording]) {
        // 滿足一些特定時長錄音需求
        //- (BOOL)recordForDuration:(NSTimeInterval) duration;
        
        [self.audioRecorder record];//首次使用應用時如果調用record方法會詢問用戶是否允許使用麥克風
        self.timer.fireDate = [NSDate distantPast];
    }
}

/**
 *  點擊暫定按鈕
 *
 *  @param sender 暫停按鈕
 */
- (IBAction)pauseClick:(UIBarButtonItem *)sender {
    if ([self.audioRecorder isRecording]) {
        [self.audioRecorder pause];
        self.timer.fireDate = [NSDate distantFuture];
    }
}

/**
 *  點擊恢復按鈕
 *  恢復錄音只需要再次調用record,AVAudioSession會幫助你記錄上次錄音位置并追加錄音
 *
 *  @param sender 恢復按鈕
 */
- (IBAction)resumeClick:(UIBarButtonItem *)sender {

    [self recordClick:sender];
}

/**
 *  點擊停止按鈕
 *
 *  @param sender 停止按鈕
 */
- (IBAction)stopClick:(UIBarButtonItem *)sender {
    [self.audioRecorder stop];
    self.timer.fireDate = [NSDate distantFuture];
    self.audioPower.progress = 0.0;
}

/**
 *  點擊播放按鈕
 *
 *  @param sender 播放按鈕
 */
- (IBAction)playClick:(UIBarButtonItem *)sender {
    if (![self.audioPlayer isPlaying]) {
        [self.audioPlayer play];
        self.timer1.fireDate = [NSDate distantPast];
    }
}

/**
 *  播放聲波狀態設置
 */
- (void)playAudioPowerChange {
    [self.audioPlayer updateMeters];//更新測量值
    
    //取得第一個通道的音頻,注意音頻強度范圍時-160到0
    float power = [self.audioPlayer averagePowerForChannel:0];
    CGFloat progress = (1.0/160.0)*(power+160.0);
    [self.audioPower setProgress:progress];
}

#pragma mark - AVAudioRecorderDelegate Methods
/**
 *  錄音完成
 *
 *  @param recorder AVAudioRecorder對象
 *  @param flag     是否成功
 */
- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag{
    if (flag) {
        [MBProgressHUD showHUDAddedTo:self.view animated:YES];
        MBProgressHUD *hud = [MBProgressHUD HUDForView:self.view];
        hud.mode = MBProgressHUDModeCustomView;
        hud.label.text = @"錄音完畢";
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [hud hideAnimated:YES];
        });
    }
}

#pragma mark - AVAudioPlayerDelegate Methods
/**
 *  播放完成
 *
 *  @param player AVAudioPlayer對象
 *  @param flag   是否成功
 */
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
    if (flag) {
        [MBProgressHUD showHUDAddedTo:self.view animated:YES];
        MBProgressHUD *hud = [MBProgressHUD HUDForView:self.view];
        hud.mode = MBProgressHUDModeCustomView;
        hud.label.text = @"播放完畢";
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [hud hideAnimated:YES];
        });
    }
}

@end


最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,908評論 6 541
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,324評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,018評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,675評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,417評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,783評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,779評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,960評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,522評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,267評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,471評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,009評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,698評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,099評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,386評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,204評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,436評論 2 378

推薦閱讀更多精彩內容