【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) {// 保存录音文件的路径urlNSURL *url = [NSURL URLWithString:_filepathCaf];// 创建录音格式设置settingNSDictionary *setting = [self getAudioSetting];// errorNSError *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 UrlNSError *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) {// 保存录音文件的路径urlNSURL *url = [NSURL URLWithString:_filepathCaf];// 创建录音格式设置settingNSDictionary *setting = [self getAudioSetting];// errorNSError *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 UrlNSError *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~160float 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下载:https://github.com/jiangxh1992/iOSAudioRecorderDemo
【iOS沉思录】:iOS多媒体音频(下)-录音及其播放相关推荐
- 【iOS沉思录】Objective-C语言的动态性总结(编译时与运行时)
编译时与运行时 编译时: 即编译器对语言的编译阶段,编译时只是对语言进行最基本的检查报错,包括词法分析.语法分析等等,将程序代码翻译成计算机能够识别的语言(例如汇编等),编译通过并不意味着程序就可以成 ...
- 【iOS沉思录】如何招聘一个靠谱的 iOS程序员+面试题详解
说明:面试题来源是微博@我就叫Sunny怎么了的这篇博文:<招聘一个靠谱的 iOS>,其中共55题,除第一题为纠错题外,其他54道均为简答题. 出题者简介: 孙源(sunnyxx),目前就 ...
- 【iOS沉思录】iOS内存管理试题总结与详解
"iOS中的GC垃圾回收机制与内存管理机制以及block" 问题:僵尸对象.野指针.空指针分别指什么,有什么区别? 僵尸对象:一个OC对象引用计数为0被释放后就变成僵尸对象了,僵尸 ...
- 【iOS沉思录】iOS沙盒内存使用深入剖析
背景 沙盒存储是iOS数据持久化的一种方案,操作简单,可以将数据以NSData以及常用的NSDictionary和NSArray的组织方式(通过plist文件创建文件对象)在沙盒的Documents目 ...
- 【iOS沉思录】iOS添加自定义字体详解
字体是软件开发中个性化的一个重要元素,系统自带了很多丰富的字体,但有时候并不能满足个性化的需求,这时候可以向工程中添加自定义的系统字体,然后就可以像使用系统字体一样使用.字体文件最常用的为ttf等格式 ...
- 【iOS沉思录】BAD_ACCESS内存错误调试
BAD_ACCESS 在什么情况下出现 BAD_ACCESS 报错属于内存访问错误,会导致程序崩溃,错误的原因是访问了野指针(悬挂指针).野指针指的是本来指针指向的对象已经释放了,但指向该对象的指针没 ...
- 【iOS沉思录】Objective-C语言消息传递机制三道防线:消息转发机制详解
消息传递机制: 在OC中,方法的调用不再理解为对象调用其方法,而是要理解成对象接收消息,消息的发送采用'动态绑定'机制,具体会调用哪个方法直到运行时才能确定,确定后才会去执行绑定的代码.方法的调用实际 ...
- Swift实现iOS录音与播放音频功能
Swift实现iOS录音与播放音频功能 作用 AVPLayer:可以用来播放在线及本地音视频 AVAudioSession:音频会话,主要用来管理音频设置与硬件交互 使用时需要导入 #import & ...
- iOS短视频源码音频采集过程中的音效实现
在移动短视频直播中, 声音是主播和观众互动的重要途径之一, 为了丰富直播的内容,大家都会想要在声音上做一些文章, 在短视频源码采集录音的基础上玩一些花样. 比如演唱类的直播间中, 主播伴随着背景音乐演 ...
- iOS短视频源码音频采集过程中的音效实现 1
在移动短视频直播中, 声音是主播和观众互动的重要途径之一, 为了丰富直播的内容,大家都会想要在声音上做一些文章, 在短视频源码采集录音的基础上玩一些花样. 比如演唱类的直播间中, 主播伴随着背景音乐演 ...
最新文章
- Spring学习笔记_IOC
- 极光推送收不到推送消息
- MySQL 引擎特性 · InnoDB Buffer Pool
- Java文档阅读笔记-JDBC Driver
- Python生态概览(三):图形用户界面开发库、游戏开发库、虚拟现实库、图形艺术库
- 解决Android Studio不停的Indexing的问题
- Redis中的lua脚本
- stm32之神州三号开发板 USB DFU 实现过程
- 教育技术资源大全(05-11-28)
- 姓周取名:周姓漂亮有涵养的女孩名字
- 红米Note5官方刷机日记 - 小米助手Recovery刷机
- 腾讯开源 GFP-GAN 代码
- 安装ubuntu系统16.04版本
- 前端全栈工程师进阶学习笔记
- 场效应晶体管在电路中的五大作用,你了解哪一种?
- Python的优点与缺点
- Android 输入法键盘和自定义表情面板
- 无法从命令行或调试器启动服务,必须首先安装Windows服务....。在“安装”阶段发生异常。 System.Security.SecurityException:未找到源
- MAC下linux双系统的安装
- ps中用钢笔进行抠图