利用AVFoundation框架实现录音和播放(AVAudioSession、AVAudioRecorder、AVAudioPlayer)

最近实现了一个简单功能,类似微信发送语音,按下录音,松开结束录音;并且可播放;

效果图:


Demo下载地址:

http://download.csdn.net/download/rhljiayou/6535125

需要导入

#import <AVFoundation/AVFoundation.h>

利用此框架中的

AVAudioRecorder和AVAudioPlayer来录音和播放

以下是AVAudioRecorder录音的使用方法:

[cpp]  view plain copy
  1. - (IBAction)downAction:(id)sender {  
  2.     //按下录音  
  3.     if ([self canRecord]) {  
  4.   
  5.         NSError *error = nil;  
  6.         //必须真机上测试,模拟器上可能会崩溃  
  7.         recorder = [[AVAudioRecorder alloc] initWithURL:[NSURL URLWithString:playName] settings:recorderSettingsDict error:&error];  
  8.           
  9.         if (recorder) {  
  10.             //是否允许刷新电平表,默认是off  
  11.             recorder.meteringEnabled = YES;  
  12.             //创建文件,并准备录音  
  13.             [recorder prepareToRecord];  
  14.             //开始录音  
  15.             [recorder record];  
  16.               
  17.             //启动定时器,为了更新电平  
  18.             timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(levelTimer:) userInfo:nil repeats:YES];  
  19.               
  20.         } else  
  21.         {  
  22.             int errorCode = CFSwapInt32HostToBig ([error code]);  
  23.             NSLog(@"Error: %@ [%4.4s])" , [error localizedDescription], (char*)&errorCode);  
  24.               
  25.         }  
  26.     }  
  27.      
  28. }  
  29.   
  30. - (IBAction)upAction:(id)sender {  
  31.     //松开 结束录音  
  32.       
  33.     //录音停止  
  34.     [recorder stop];  
  35.     recorder = nil;  
  36.     //结束定时器  
  37.     [timer invalidate];  
  38.     timer = nil;  
  39.     //图片重置  
  40.     soundLodingImageView.image = [UIImage imageNamed:[volumImages objectAtIndex:0]];  
  41.       
  42. }  

以下是AVAudioPlayer播放器的使用方法:

[cpp]  view plain copy
  1. - (IBAction)playAction:(id)sender {  
  2.       
  3.     NSError *playerError;  
  4.       
  5.     //播放  
  6.     player = nil;  
  7.     player = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:playName] error:&playerError];  
  8.       
  9.     if (player == nil)  
  10.     {  
  11.         NSLog(@"ERror creating player: %@", [playerError description]);  
  12.     }else{  
  13.         [player play];  
  14.     }  
  15.       
  16. }  

如果是7.0,第一次运行会提示,是否允许使用麦克风:

7.0需要设置:

[cpp]  view plain copy
  1. if ([[[UIDevice currentDevice] systemVersion] compare:@"7.0"] != NSOrderedAscending)  
  2.     {  
  3.         //7.0第一次运行会提示,是否允许使用麦克风  
  4.         AVAudioSession *session = [AVAudioSession sharedInstance];  
  5.         NSError *sessionError;  
  6.         //AVAudioSessionCategoryPlayAndRecord用于录音和播放  
  7.         [session setCategory:AVAudioSessionCategoryPlayAndRecord error:&sessionError];  
  8.         if(session == nil)  
  9.             NSLog(@"Error creating session: %@", [sessionError description]);  
  10.         else  
  11.             [session setActive:YES error:nil];  
  12.     }  

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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值