最近实现了一个简单功能,类似微信发送语音,按下录音,松开结束录音;并且可播放;
效果图:
Demo下载地址:
http://download.csdn.net/download/rhljiayou/6535125
需要导入
#import <AVFoundation/AVFoundation.h>
利用此框架中的
AVAudioRecorder和AVAudioPlayer来录音和播放
以下是AVAudioRecorder录音的使用方法:
- - (IBAction)downAction:(id)sender {
- //按下录音
- if ([self canRecord]) {
- NSError *error = nil;
- //必须真机上测试,模拟器上可能会崩溃
- recorder = [[AVAudioRecorder alloc] initWithURL:[NSURL URLWithString:playName] settings:recorderSettingsDict error:&error];
- if (recorder) {
- //是否允许刷新电平表,默认是off
- recorder.meteringEnabled = YES;
- //创建文件,并准备录音
- [recorder prepareToRecord];
- //开始录音
- [recorder record];
- //启动定时器,为了更新电平
- timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(levelTimer:) userInfo:nil repeats:YES];
- } else
- {
- int errorCode = CFSwapInt32HostToBig ([error code]);
- NSLog(@"Error: %@ [%4.4s])" , [error localizedDescription], (char*)&errorCode);
- }
- }
- }
- - (IBAction)upAction:(id)sender {
- //松开 结束录音
- //录音停止
- [recorder stop];
- recorder = nil;
- //结束定时器
- [timer invalidate];
- timer = nil;
- //图片重置
- soundLodingImageView.image = [UIImage imageNamed:[volumImages objectAtIndex:0]];
- }
以下是AVAudioPlayer播放器的使用方法:
- - (IBAction)playAction:(id)sender {
- NSError *playerError;
- //播放
- player = nil;
- player = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:playName] error:&playerError];
- if (player == nil)
- {
- NSLog(@"ERror creating player: %@", [playerError description]);
- }else{
- [player play];
- }
- }
如果是7.0,第一次运行会提示,是否允许使用麦克风:
7.0需要设置:
- if ([[[UIDevice currentDevice] systemVersion] compare:@"7.0"] != NSOrderedAscending)
- {
- //7.0第一次运行会提示,是否允许使用麦克风
- AVAudioSession *session = [AVAudioSession sharedInstance];
- NSError *sessionError;
- //AVAudioSessionCategoryPlayAndRecord用于录音和播放
- [session setCategory:AVAudioSessionCategoryPlayAndRecord error:&sessionError];
- if(session == nil)
- NSLog(@"Error creating session: %@", [sessionError description]);
- else
- [session setActive:YES error:nil];
- }
ok!完美,perfect!
补充:新建项目工程,首先导入AV Foundation框架,此处使用ARC=YES,导入相关图片文件,创建ViewController,带上xib文件,把AppDelegate的rootViewController交给ViewController,通过ib文件加载视图。在ViewController中导入<AVFoundation/AVFoundation.h>库,定义如下变量和实例方法:
{
IBOutlet UIImageView *soundLodingImageView;//从IB链接的一个UIImageView
IBOutlet UIButton *playBtn;//从IB链接的button
AVAudioRecorder *recorder; //录音器
AVAudioPlayer *player; //播放器
NSDictionary *recorderSettingsDict;//播放器的配置添加到一个字典里
NSTimer *timer; //定时器
NSMutableArray *volumImages; //图片组
double lowPassResults;//创建一个double类型的lowPassResults获取最低分贝值
NSString *playName; //录音名字
}
- (IBAction)downAction:(id)sender;//点击开始录音执行的方法
- (IBAction)upAction:(id)sender;//松手录音结束的方法
- (IBAction)playAction:(id)sender;//播放音频
实现Demo中AV Foundation的方法:【此处使用的时AVAudioSession类】
1、AVAudioSession 直接继承与NSObjectà AVAudioSession : NSObject;
2、创建会话session,调用AVAudioSession的类方法+ (id)sharedInstance;返回一个单例实例
3、- (BOOL)setCategory:(NSString *)category error:(NSError **)outError;
AVAudioSession中设置音频类型的实例方法,返回一个BOOL类型;
setCategory需要返回一个NSString类型的分类属性的值,调用失败返回error:
AVF_EXPORT NSString *const AVAudioSessionCategoryPlayAndRecord,表示用于录音和播放;(一般选这个,录制和播放都可以使用)
AVF_EXPORT NSString *constAVAudioSessionCategoryRecord,表示录制音频;
还有几个不常用的类别:添加背景声音如雨、汽车发动机噪声等混合与其他音乐,使用背景音乐类型并停止其他音乐播放(这个类别在录制和播放语音时会使用,前提条件是存在音乐播放软件的情况下),使用硬件编解码器或信号处理器。
4、//调用AVFoundation框架的setActive方法这是会话活动:
- (BOOL)setActive:(BOOL)activeerror:(NSError **)outError;返回一个BOOL类型
5、设置录音器和播放器
recorderSettingsDict =[[NSDictionary alloc]initWithObjectsAndKeys:
[NSNumbernumberWithInt:kAudioFormatMPEG4AAC],AVFormatIDKey,
[NSNumbernumberWithInt:1000.0],AVSampleRateKey,
[NSNumbernumberWithInt:2],AVNumberOfChannelsKey,
[NSNumbernumberWithInt:8],AVLinearPCMBitDepthKey,
[NSNumbernumberWithBool:NO],AVLinearPCMIsBigEndianKey,
[NSNumbernumberWithBool:NO],AVLinearPCMIsFloatKey,nil];
/*录音设置,初始化播放器,
AVFormatIDKey->格式的ID,格式使用了CoreAudio库中的CoreAudioTypes类的一组枚举方法,例子中使用的AAC的格式这里需要注意iOS常用的几种音频格式,详见下文【iOS系统支持音频格式及编码要求】和【CoreAudioTypes类中音频格式枚举值】
AVSampleRateKey->音频采样率,
AVNumberOfChannelsKey->关键渠道,通道,
AVLinearPCMBitDepthKey->采样位数,默认为16,
AVLinearPCMIsBigEndianKey->大端还是小端,是内存的组织方式
AVLinearPCMIsFloatKey,nil]->采样信号是否是浮点数NO*/
具体关于音频格式和ACC等格式编码转解码的内容可进入:http://www.360doc.com/content/14/0313/15/9075092_360274297.shtml查看具体分析
-----一切就绪,开始设置点击录音,松开停止并保存音频,点击播放功能啦----
6、点击按钮触发录音功能,开启记录方法,则初始化录音器,定义捕获音频的存储路径并设置播放器,初始化AV Foundation下的AVAudioRecorder类,直接继承自NSObject;
初始化调用-(id)initWithURL:(NSURL *)url settings:(NSDictionary *)settings error:(NSError**)outError;实例方法,传一个url进去,设置记录文件的扩展名,如果存在则覆盖;
7、录音器初始化成功,开启计量器,调用AVFoundation框架的prepareToRecord方法创建文件,准备记录,该方法会自动记录[recorder prepareToRecord];启动AVFoundation的记录或回复文件方法[recorderrecord],开启定时器,定时器启动后调用levelTimer方法。
8、松开后结束录音,直接使用[recorder stop],此时注意要把recorder设置为nil,由于使用了ARC,是系统自动管理内存,所以如果recorder停止调用后将不再指向内存区域,为了防止偶然调用到野指针,安全起见还是需要把值设为nil,指向一片不存在的内存。录音结束的同时调用定时器也停止,同样定时器也要把指针设为nil。
9、点击播放已经录制好的音频,在初始化player播放器时使用AV Foundation框架下的AVAudioPlayer类,读取存储在本地的录音格式文件,点击执行[player play];
----基本的按钮功能也都写好了,接下来是定时器调用的levelTimer方法设置分贝和不同分贝显示的图片----
10、peakPowerForChannel 峰值功率通道,返回峰值功率分贝对于一个给定的通道,AVFoundation的方法。
//call to refresh meter values刷新平均和峰值功率,此计数是以对数刻度计量的,lowPassResults是最低值,初始值为0 ,
[recorder updateMeters];//录音器调用刷新记值的方法
const double ALPHA = 0.05;//alpha值在物理分贝表示中+0.05为最小分贝数,-0.05为最大分贝数,+80为最小分贝数,-80为最大分贝数
doublepeakPowerForChannel = pow(10, (0.05 * [recorder peakPowerForChannel:0]));
lowPassResults= ALPHA * peakPowerForChannel + (1.0 - ALPHA) * lowPassResults;
以上两套算法公式尚不明白其运算过程和使用方法,暂时只要记住怎么用吧,lowPassResults是最小分贝值,通过计算得到一个最小分贝值来判断图片的显示;
11、7.0新增方法,判断是否允许使用麦克风requestRecordPermission
-(BOOL)canRecord
{
__block BOOL bCanRecord = YES;
if ([[[UIDevice currentDevice] systemVersion] compare:@"7.0"]!= NSOrderedAscending)
{
//- (BOOL)respondsToSelector:(SEL)Selector;在NSObject和NSProxy中都存在,在NSProxy中是一个类方法,此处使用的是它的类方法
AVAudioSession*audioSession = [AVAudioSession sharedInstance]; if([audioSessionrespondsToSelector:@selector(requestRecordPermission:)]){
//performSelector选择执行器,requestRecordPermission:会话类别等。例子:AV音频会话类别记录,AV音频会话类别和记录,AVFoundation的一个实例方法。
[audioSession performSelector:@selector(requestRecordPermission:)withObject:^(BOOL granted) {
if (granted) {
bCanRecord = YES;
}
else {
bCanRecord = NO;
//返回主线程执行UI操作,此处可以不使用回调,安全起见回调主函数运行
dispatch_async(dispatch_get_main_queue(),^{
[[[UIAlertViewalloc] initWithTitle:nil
message:@"app需要访问您的麦克风。\n请启用麦克风-设置/隐私/麦克风"
delegate:nil
cancelButtonTitle:@"关闭"
otherButtonTitles:nil] show];
});
}
}];
}
}
return bCanRecord;
}
【注】Demo的url设置可以决定是在真机运行还是模拟器运行。
[[AVAudioRecorder alloc] initWithURL:[NSURLfileURLWithPath:playName] settings:recorderSettingsDict error:&error];
如果要在模拟器运行,需要将NSURL的获取方式改为fileURLWithPath,若在真机运行则改为URLWithPath。
【iOS系统支持音频格式及编码要求:】
AAC (16 至 320 Kbps)、Protected AAC (来自 iTunes Store)、MP3 (16 至 320 Kbps)、MP3 VBR、Audible (formats 2、3、4)、Apple Lossless、AIFF 及 WAV
The audio technologies in iOS support thefollowing audio formats:
• AAC
• Apple Lossless (ALAC)
• A-law
• IMA/ADPCM (IMA4)
• Linear PCM
• µ-law
• DVI/Intel IMA ADPCM
• Microsoft GSM 6.10
• AES3-2003
【CoreAudioTypes类中音频格式枚举值:】
kAudioFormatLinearPCM = 'lpcm',
kAudioFormatAC3 = 'ac-3',
kAudioFormat60958AC3 = 'cac3',
kAudioFormatAppleIMA4 = 'ima4',
kAudioFormatMPEG4AAC = 'aac ',
kAudioFormatMPEG4CELP = 'celp',
kAudioFormatMPEG4HVXC = 'hvxc',
kAudioFormatMPEG4TwinVQ = 'twvq',
kAudioFormatMACE3 = 'MAC3',
kAudioFormatMACE6 = 'MAC6',
kAudioFormatULaw = 'ulaw',
kAudioFormatALaw = 'alaw',
kAudioFormatQDesign = 'QDMC',
kAudioFormatQDesign2 = 'QDM2',
kAudioFormatQUALCOMM = 'Qclp',
kAudioFormatMPEGLayer1 = '.mp1',
kAudioFormatMPEGLayer2 = '.mp2',
kAudioFormatMPEGLayer3 = '.mp3',
kAudioFormatTimeCode = 'time',
kAudioFormatMIDIStream = 'midi',
kAudioFormatParameterValueStream = 'apvs',
kAudioFormatAppleLossless = 'alac',
kAudioFormatMPEG4AAC_HE = 'aach',
kAudioFormatMPEG4AAC_LD = 'aacl',
kAudioFormatMPEG4AAC_ELD = 'aace',
kAudioFormatMPEG4AAC_ELD_SBR = 'aacf',
kAudioFormatMPEG4AAC_ELD_V2 = 'aacg',
kAudioFormatMPEG4AAC_HE_V2 = 'aacp',
kAudioFormatMPEG4AAC_Spatial = 'aacs',
kAudioFormatAMR = 'samr',
kAudioFormatAudible = 'AUDB',
kAudioFormatiLBC = 'ilbc',
kAudioFormatDVIIntelIMA = 0x6D730011,
kAudioFormatMicrosoftGSM = 0x6D730031,
kAudioFormatAES3 = 'aes3'
viewController.m
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
/*UIDevice->UI设备 ,currentDevice->当前的设备,systemVersion->系统版本,compare->比较*/
//判断当前设备的系统版本是否在7.0及以上版本
if ([[[UIDevice currentDevice] systemVersion] compare:@"7.0"] != NSOrderedAscending)
{
//7.0第一次运行会提示,是否允许使用麦克风
AVAudioSession *session = [AVAudioSession sharedInstance];
//创建会话这个共享类session
NSError *sessionError;
//AVAudioSessionCategoryPlayAndRecord用于录音和播放
//setCategory//设置音频类型
[session setCategory:AVAudioSessionCategoryPlayAndRecord error:&sessionError];
//如果会话为空
if(session == nil)
NSLog(@"Error creating session: %@", [sessionError description]);
//打印error说明
else
//调用AVFoundation框架的setActive方法
[session setActive:YES error:nil];
}
//NSSearchPathForDirectoriesInDomains搜索路径中的目录域,NSDocumentDirectory文档目录,
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
//录音存储格式为aac格式
playName = [NSString stringWithFormat:@"%@/play.aac",docDir];
/*录音设置,初始化播放器,
AVFormatIDKey->格式的ID,
AVSampleRateKey->音频采样率,
AVNumberOfChannelsKey->关键渠道,通道,
AVLinearPCMBitDepthKey->采样位数,默认为16,
AVLinearPCMIsBigEndianKey->大端还是小端,是内存的组织方式
AVLinearPCMIsFloatKey,nil]->采样信号是否是浮点数NO
*/
recorderSettingsDict =[[NSDictionary alloc] initWithObjectsAndKeys:
[NSNumber numberWithInt:kAudioFormatMPEG4AAC],AVFormatIDKey,
[NSNumber numberWithInt:1000.0],AVSampleRateKey,
[NSNumber numberWithInt:2],AVNumberOfChannelsKey,
[NSNumber numberWithInt:8],AVLinearPCMBitDepthKey,
[NSNumber numberWithBool:NO],AVLinearPCMIsBigEndianKey,
[NSNumber numberWithBool:NO],AVLinearPCMIsFloatKey,
nil];
//音量图片数组
volumImages = [[NSMutableArray alloc]initWithObjects:@"RecordingSignal001",@"RecordingSignal002",@"RecordingSignal003",
@"RecordingSignal004", @"RecordingSignal005",@"RecordingSignal006",
@"RecordingSignal007",@"RecordingSignal008", nil];
}
//Button的点击实现方法
- (IBAction)downAction:(id)sender {
//按下录音
if ([self canRecord]) {
NSError *error = nil;
//必须真机上测试,模拟器上可能会崩溃,如果要在模拟器运行,需要将NSURL的获取方式改为fileURLWithPath,若在真机运行则改为URLWithPath;
//如果按钮触发时可以开启记录方法,则初始化录音器,定义捕获音频的存储路径并设置播放器
recorder = [[AVAudioRecorder alloc] initWithURL:[NSURL fileURLWithPath:playName] settings:recorderSettingsDict error:&error];
if (recorder) {
recorder.meteringEnabled = YES;//启用计量
//调用AVFoundation框架的prepareToRecord方法创建文件,准备记录,该方法会自动记录
[recorder prepareToRecord];
//启动AVFoundation的记录或回复文件方法
[recorder record];
//启动定时器
timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(levelTimer:) userInfo:nil repeats:YES];
} else
{
int errorCode = CFSwapInt32HostToBig ([error code]);
NSLog(@"Error: %@ [%4.4s])" , [error localizedDescription], (char*)&errorCode);
// localizedDescription 本地化的描述
}
}
}
- (IBAction)upAction:(id)sender {
//松开 结束录音
//录音停止
[recorder stop];
recorder = nil;
//结束定时器
[timer invalidate];
timer = nil;
//图片重置
soundLodingImageView.image = [UIImage imageNamed:[volumImages objectAtIndex:0]];
}
//
- (IBAction)playAction:(id)sender {
NSError *playerError;
//播放
player = nil;
//初始化player播放器
player = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:playName] error:&playerError];
if (player == nil)
{
NSLog(@"ERror creating player: %@", [playerError description]);
}else{
[player play];
}
}
//peakPowerForChannel 峰值功率通道,返回峰值功率分贝对于一个给定的通道,AVFoundation的方法,字面理解为峰值的幂,从其网络上搜索后得到上面的答案,但其结果并不是分贝,而是一个从0-1的波动值
-(void)levelTimer:(NSTimer*)timer_
{
//call to refresh meter values刷新平均和峰值功率,此计数是以对数刻度计量的,-160表示完全安静,0表示最大输入值,lowPassResults是最低值,初始值为0 ,
//alpha=0.05
[recorder updateMeters];//录音器调用刷新记值的方法
const double ALPHA = 0.05;//alpha值在物理分贝表示中+0.05为最小分贝数,-0.05为最大分贝数,+80为最小分贝数,-80为最大分贝数
double peakPowerForChannel = pow(10, (0.05 * [recorder peakPowerForChannel:0]));
lowPassResults = ALPHA * peakPowerForChannel + (1.0 - ALPHA) * lowPassResults;
//x=a*b+(c-a)*x;
NSLog(@"Average input: %f Peak input: %f Low pass results: %f", [recorder averagePowerForChannel:0], [recorder peakPowerForChannel:0], lowPassResults);
if (lowPassResults>=0.8) {
soundLodingImageView.image = [UIImage imageNamed:[volumImages objectAtIndex:7]];
}else if(lowPassResults>=0.7){
soundLodingImageView.image = [UIImage imageNamed:[volumImages objectAtIndex:6]];
}else if(lowPassResults>=0.6){
soundLodingImageView.image = [UIImage imageNamed:[volumImages objectAtIndex:5]];
}else if(lowPassResults>=0.5){
soundLodingImageView.image = [UIImage imageNamed:[volumImages objectAtIndex:4]];
}else if(lowPassResults>=0.4){
soundLodingImageView.image = [UIImage imageNamed:[volumImages objectAtIndex:3]];
}else if(lowPassResults>=0.3){
soundLodingImageView.image = [UIImage imageNamed:[volumImages objectAtIndex:2]];
}else if(lowPassResults>=0.2){
soundLodingImageView.image = [UIImage imageNamed:[volumImages objectAtIndex:1]];
}else if(lowPassResults>=0.1){
soundLodingImageView.image = [UIImage imageNamed:[volumImages objectAtIndex:0]];
}else{
soundLodingImageView.image = [UIImage imageNamed:[volumImages objectAtIndex:0]];
}
}
//判断是否允许使用麦克风7.0新增的方法requestRecordPermission
-(BOOL)canRecord
{
__block BOOL bCanRecord = YES;
if ([[[UIDevice currentDevice] systemVersion] compare:@"7.0"] != NSOrderedAscending)
{
//- (BOOL)respondsToSelector:(SEL)Selector;在NSObject和NSProxy中都存在,在NSProxy中是一个类方法,此处使用的是它的类方法
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
if ([audioSession respondsToSelector:@selector(requestRecordPermission:)]) {
//performSelector选择执行器,requestRecordPermission:会话类别等。例子:AV音频会话类别记录,AV音频会话类别和记录,AVFoundation的一个实例方法。
[audioSession performSelector:@selector(requestRecordPermission:) withObject:^(BOOL granted) {
if (granted) {
bCanRecord = YES;
}
else {
bCanRecord = NO;
//返回主线程执行UI操作,安全起见回调主函数运行
dispatch_async(dispatch_get_main_queue(), ^{
[[[UIAlertView alloc] initWithTitle:nil
message:@"app需要访问您的麦克风。\n请启用麦克风-设置/隐私/麦克风"
delegate:nil
cancelButtonTitle:@"关闭"
otherButtonTitles:nil] show];
});
}
}];
}
}
return bCanRecord;
}
@end