你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS多媒體音頻(下)-錄音及其播放的實例

iOS多媒體音頻(下)-錄音及其播放的實例

編輯:IOS開發綜合

上一篇中總結了iOS中音效和音頻播放的最基本使用方法,其中音頻的播放控制是使用AVFoundation.framework框架中的AVAudioPlayer播放器對象來實現的,而這裡音頻的錄制則是使用了同樣框架下的一個叫AVAudioRecorder的錄音機對象來實現,這兩個類的用法流程非常類似,類的屬性和方法也類似,例如:播放器中需要獲取音頻文件的url,而錄音機要在沙盒中Docuemnt目錄下創建一個音頻文件路徑url;

播放器有isPlaying變量判斷是否正在播放,錄音機中有isRecording變量表示是否正在錄制;currentTime在播放器中表示播放時間,在錄音機中則表示錄音時間;播放器通過prepareToPlay方法加載文件到緩沖區,錄音機通過prepareToRecord創建緩沖區;播放音頻有play方法,音頻錄制有record方法,另外都有pause暫停方法和stop停止方法等等,具體可直接打開兩個類的頭文件詳細了解。

這裡實現最基本的錄音流程以及錄音過程的控制,並通過之前使用的AVAudioPlayer來播放錄制好的音頻。注意iOS錄制的音頻為caf格式,如果需要通用化可以通過lame等插件將caf格式音頻轉成mp3格式。

錄音

這裡實現開始錄音,暫停,繼續以及停止錄音。

創建文件目錄

iOS沙盒內胡要有三個目錄:Documents目錄,tmp目錄以及Library目錄,其中Documents目錄用來存放用戶的應用程序數據,需要定期備份的數據要放在這裡,和plist文件存儲一樣,我們要找到存放文件的路徑,然後在該路徑下放一個我們的文件,因此要自定義一個帶後綴的文件名,將獲得的路徑和文件名拼在一起記得到我們的文件的絕對路徑:

// 文件名
#define fileName_caf @"demoRecord.caf"
// 錄音文件絕對路徑
@property (nonatomic, copy) NSString *filepathCaf;

// 獲取沙盒Document文件路徑
NSString *sandBoxPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
// 拼接錄音文件絕對路徑
_filepathCaf = [sandBoxPath stringByAppendingPathComponent:fileName_caf];

創建音頻會話

錄音前要創建一個音頻會話,同時要設置錄音類型,提供的類型有以下幾種:

  • AVF_EXPORT NSString *const AVAudioSessionCategoryAmbient; // 用於錄制背景聲音,像雨聲、汽車引擎發動噪音等,可和其他音樂混合
  • AVF_EXPORT NSString *const AVAudioSessionCategorySoloAmbient; // 也是背景聲音,但其他音樂會被強制停止
  • AVF_EXPORT NSString *const AVAudioSessionCategoryPlayback; // 音軌
  • AVF_EXPORT NSString *const AVAudioSessionCategoryRecord; // 錄音
  • AVF_EXPORT NSString *const AVAudioSessionCategoryPlayAndRecord; // 錄音和回放
  • AVF_EXPORT NSString *const AVAudioSessionCategoryAudioProcessing; // 用於底層硬件編碼信號處理等
  • AVF_EXPORT NSString *const AVAudioSessionCategoryMultiRoute; // 內置硬件相關,iOS 6.0以上可用

常用的是AVAudioSessionCategoryPlayAndRecord類型,便於錄音後播放。

// 創建音頻會話
AVAudioSession *audioSession=[AVAudioSession sharedInstance];
// 設置錄音類別(這裡選用錄音後可回放錄音類型)
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
[audioSession setActive:YES error:nil];

錄音設置

錄音前要根據需要對錄音進行一些相應的基本設置,例如錄音格式(LinearPCM)、采樣率、通道數等等,設置保存在一個字典內並作為初始化錄音機的一個參數。

// 錄音設置
-(NSDictionary *)getAudioSetting{
  // LinearPCM 是iOS的一種無損編碼格式,但是體積較為龐大
  // 錄音設置信息字典
  NSMutableDictionary *recordSettings = [[NSMutableDictionary alloc] init];
  // 錄音格式
  [recordSettings setValue :@(kAudioFormatLinearPCM) forKey: AVFormatIDKey];
  // 采樣率
  [recordSettings setValue :@11025.0 forKey: AVSampleRateKey];
  // 通道數(雙通道)
  [recordSettings setValue :@2 forKey: AVNumberOfChannelsKey];
  // 每個采樣點位數(有8、16、24、32)
  [recordSettings setValue :@16 forKey: AVLinearPCMBitDepthKey];
  // 采用浮點采樣
  [recordSettings setValue:@YES forKey:AVLinearPCMIsFloatKey];
  // 音頻質量
  [recordSettings setValue:@(AVAudioQualityMedium) forKey:AVEncoderAudioQualityKey];
  // 其他可選的設置
  // ... ...

  return recordSettings;
}

創建錄音機對象

錄音機對象的創建主要是利用上面的保存路徑和錄音設置進行初始化得到:

// 懶加載錄音機對象get方法
- (AVAudioRecorder *)audioRecorder {
  if (!_audioRecorder) {
    // 保存錄音文件的路徑url
    NSURL *url = [NSURL URLWithString:_filepathCaf];
    // 創建錄音格式設置setting
    NSDictionary *setting = [self getAudioSetting];
    // error
    NSError *error=nil;

    _audioRecorder = [[AVAudioRecorder alloc]initWithURL:url settings:setting error:&error];
    _audioRecorder.delegate = self;
    _audioRecorder.meteringEnabled = YES;// 監控聲波
    if (error) {
      NSLog(@"創建錄音機對象時發生錯誤,錯誤信息:%@",error.localizedDescription);
      return nil;
    }
  }
  return _audioRecorder;
}

錄音控制方法

錄音過程控制主要是開始錄音、暫停、繼續和停止錄音,其中開始錄音和繼續錄音都是record方法。

// 開始錄音或者繼續錄音
- (IBAction)startOrResumeRecord {
  // 注意調用audiorecorder的get方法
  if (![self.audioRecorder isRecording]) {
    // 如果該路徑下的音頻文件錄制過則刪除
    [self deleteRecord];
    // 開始錄音,會取得用戶使用麥克風的同意
    [_audioRecorder record];
  }
}

// 錄音暫停
- (IBAction)pauseRecord {
  if (_audioRecorder) {
    [_audioRecorder pause];
  }
}

// 結束錄音
- (IBAction)stopRecord {
  [_audioRecorder stop];
}

錄音播放

錄音的播放很簡單,就是之前AVAudioPlayer音頻播放的簡單應用,播放的路徑即我們錄音時創建好的音頻路徑。但這裡注意為了保證每次都播放最新錄制的音頻,播放器的get方法要每次重新創建初始化。

// audioPlayer懶加載getter方法
- (AVAudioPlayer *)audioPlayer {
  _audioRecorder = NULL; // 每次都創建新的播放器,刪除舊的

  // 資源路徑
  NSURL *url = [NSURL fileURLWithPath:_filepathCaf];

  // 初始化播放器,注意這裡的Url參數只能為本地文件路徑,不支持HTTP Url
  NSError *error = nil;
  _audioPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:url error:&error];

  //設置播放器屬性
  _audioPlayer.numberOfLoops = 0;// 不循環
  _audioPlayer.delegate = self;
  _audioPlayer.volume = 0.5; // 音量
  [_audioPlayer prepareToPlay];// 加載音頻文件到緩存【這個函數在調用play函數時會自動調用】

  if(error){
    NSLog(@"初始化播放器過程發生錯誤,錯誤信息:%@",error.localizedDescription);
    return nil;
  }

  return _audioPlayer;
}

// 播放錄制好的音頻
- (IBAction)playRecordedAudio {
  // 沒有文件不播放
  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 ()

// 錄音文件絕對路徑
@property (nonatomic, copy) NSString *filepathCaf;
// 錄音機對象
@property (nonatomic, strong) AVAudioRecorder *audioRecorder;
// 播放器對象,和上一章音頻播放的方法相同,只不過這裡簡單播放即可
@property (nonatomic, strong) AVAudioPlayer *audioPlayer;
// 用一個processview顯示聲波波動情況
@property (nonatomic, weak) IBOutlet UIProgressView *processView;
// 用一個label顯示錄制時間
@property (nonatomic, weak) IBOutlet UILabel *recordTime;
// UI刷新監聽器
@property (nonatomic, strong) NSTimer *timer;

@end

@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];
  // 初始化工作
  [self initData];
}

// 初始化
- (void)initData {
  // 獲取沙盒Document文件路徑
  NSString *sandBoxPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
  // 拼接錄音文件絕對路徑
  _filepathCaf = [sandBoxPath stringByAppendingPathComponent:fileName_caf];

  // 1.創建音頻會話
  AVAudioSession *audioSession=[AVAudioSession sharedInstance];
  // 設置錄音類別(這裡選用錄音後可回放錄音類型)
  [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
  [audioSession setActive:YES error:nil];

  // 2.開啟定時器
  [self timer];
}

#pragma mark -錄音設置工具函數
// 懶加載錄音機對象get方法
- (AVAudioRecorder *)audioRecorder {
  if (!_audioRecorder) {
    // 保存錄音文件的路徑url
    NSURL *url = [NSURL URLWithString:_filepathCaf];
    // 創建錄音格式設置setting
    NSDictionary *setting = [self getAudioSetting];
    // error
    NSError *error=nil;

    _audioRecorder = [[AVAudioRecorder alloc]initWithURL:url settings:setting error:&error];
    _audioRecorder.delegate = self;
    _audioRecorder.meteringEnabled = YES;// 監控聲波
    if (error) {
      NSLog(@"創建錄音機對象時發生錯誤,錯誤信息:%@",error.localizedDescription);
      return nil;
    }
  }
  return _audioRecorder;
}

// audioPlayer懶加載getter方法
- (AVAudioPlayer *)audioPlayer {
  _audioRecorder = NULL; // 每次都創建新的播放器,刪除舊的

  // 資源路徑
  NSURL *url = [NSURL fileURLWithPath:_filepathCaf];

  // 初始化播放器,注意這裡的Url參數只能為本地文件路徑,不支持HTTP Url
  NSError *error = nil;
  _audioPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:url error:&error];

  //設置播放器屬性
  _audioPlayer.numberOfLoops = 0;// 不循環
  _audioPlayer.delegate = self;
  _audioPlayer.volume = 0.5; // 音量
  [_audioPlayer prepareToPlay];// 加載音頻文件到緩存【這個函數在調用play函數時會自動調用】

  if(error){
    NSLog(@"初始化播放器過程發生錯誤,錯誤信息:%@",error.localizedDescription);
    return nil;
  }

  return _audioPlayer;
}

// 計時器get方法
- (NSTimer *)timer {
  if (!_timer) {
    _timer = [NSTimer scheduledTimerWithTimeInterval:0.1f repeats:YES block:^(NSTimer * _Nonnull timer) {
      if(_audioRecorder) {
        // 1.更新錄音時間,單位秒
        int curInterval = [_audioRecorder currentTime];
        _recordTime.text = [NSString stringWithFormat:@"%02d:%02d",curInterval/60,curInterval%60];
        // 2.聲波顯示
        //更新聲波值
        [self.audioRecorder updateMeters];
        //第一個通道的音頻,音頻強度范圍:[-160~0],這裡調整到0~160
        float power = [self.audioRecorder averagePowerForChannel:0] + 160;
        [_processView setProgress:power/160.0];
      }
    }];
  }
  return _timer;
}

// 錄音設置
-(NSDictionary *)getAudioSetting{
  // LinearPCM 是iOS的一種無損編碼格式,但是體積較為龐大
  // 錄音設置信息字典
  NSMutableDictionary *recordSettings = [[NSMutableDictionary alloc] init];
  // 錄音格式
  [recordSettings setValue :@(kAudioFormatLinearPCM) forKey: AVFormatIDKey];
  // 采樣率
  [recordSettings setValue :@11025.0 forKey: AVSampleRateKey];
  // 通道數(雙通道)
  [recordSettings setValue :@2 forKey: AVNumberOfChannelsKey];
  // 每個采樣點位數(有8、16、24、32)
  [recordSettings setValue :@16 forKey: AVLinearPCMBitDepthKey];
  // 采用浮點采樣
  [recordSettings setValue:@YES forKey:AVLinearPCMIsFloatKey];
  // 音頻質量
  [recordSettings setValue:@(AVAudioQualityMedium) forKey:AVEncoderAudioQualityKey];
  // 其他可選的設置
  // ... ...

  return recordSettings;
}

// 刪除filepathCaf路徑下的音頻文件
-(void)deleteRecord{
  NSFileManager* fileManager=[NSFileManager defaultManager];
  if ([[NSFileManager defaultManager] fileExistsAtPath:self.filepathCaf]) {
    // 文件已經存在
    if ([fileManager removeItemAtPath:self.filepathCaf error:nil]) {
      NSLog(@"刪除成功");
    }else {
      NSLog(@"刪除失敗");
    }
  }else {
    return; // 文件不存在無需刪除
  }
}

#pragma mark -錄音流程控制函數
// 開始錄音或者繼續錄音
- (IBAction)startOrResumeRecord {
  // 注意調用audiorecorder的get方法
  if (![self.audioRecorder isRecording]) {
    // 如果該路徑下的音頻文件錄制過則刪除
    [self deleteRecord];
    // 開始錄音,會取得用戶使用麥克風的同意
    [_audioRecorder record];
  }
}

// 錄音暫停
- (IBAction)pauseRecord {
  if (_audioRecorder) {
    [_audioRecorder pause];
  }
}

// 結束錄音
- (IBAction)stopRecord {
  [_audioRecorder stop];
}

#pragma mark -錄音播放
// 播放錄制好的音頻
- (IBAction)playRecordedAudio {
  // 沒有文件不播放
  if (![[NSFileManager defaultManager] fileExistsAtPath:self.filepathCaf]) return;
  // 播放最新的錄音
  [self.audioPlayer play];
}

@end

Demo下載:demo

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持本站。

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved