录音功能实现

 
http://hhuai.github.com/blog/2012/02/05/ios-and-andorid-voice/
 

介绍

学习ios第一个练手功能就是给已有产品加上语音通信功能,能够互通ios与android。这里给出自己的一些心得,希望能给他人一些参考。

资料搜集与参考

  1. 类似产品使用的技术

    • talkbox Android版用的是ilbc的第三方编解码库,在iPhone上用的是caf
    • 微信   Android版估计是amr估计转码的是交给腾讯强大的服务器了。
    • 米聊   Android版和Iphone版用的都是speex

    目前支持的开源第三方库也就只有 ilbc和speex了

  2. 考虑采用的方案

    speex 需要Android和ios都进入转码,工作量太大,不采用。 剩下的方案就是在amr和ilbc上选择了,android支持amr,低版本不支持ilbc, ios高版本(4.3)只支持ilbc,不能支持amr。 刚开始的测试方案使用的是android将语音转ilbc, 由于我对于android开发不是太熟悉,在同事的帮助下一直没有转换成功,现在想想可能是处理问题,如果能转换成或,这种方案应该是最方便的。

ios实现amr编解码

录制

  1. 将语音录成原始pcm码

    注意这里,虽然录制是pcm码,但出来的文件ios依然会封装一层,将其包装成pcf格式。所以就有了第二步。

  2. 将pcf中的pcm码取出来

  3. 使用libopencore库将其编成amr格式,这时可以发送给android端播放了。

播放

  1. 将android版本发送过来的amr解码出来

  2. 播放原始pcm即可

代码文件都放在github上了,有需要的可以参考一下。 https://github.com/hhuai/ios_util

--------------------------------------------------------------

真正用到的例子

https://github.com/guange2015/ios-amr

 

--------------------------------------------------------------

国外专门的博客

http://www.raywenderlich.com/69365/audio-tutorial-ios-file-data-formats-2014-edition

--------------------------------------------------------------

我是采用的AVAudioRecorder这个框架来进行录音

这个录音跟官方网站上的speakHere有些区别,最大的区别是,这个必须要录制完成才能处理文件,而speakhere示例是可以实现边录制边上传的效果。

 

#import <AVFoundation/AVFoundation.h>

#import <CoreAudio/CoreAudioTypes.h>

引入框架,这是使用录音功能的基本配备


先说明一点,默认AVAudioRecorder录制后的格式是.caf,而大部分的播放器都是不支持这个格式的,下面一段设置是可以让录制格式是wav的格式


 

NSDictionary *recordSetting = [[NSDictionary alloc] initWithObjectsAndKeys:

                                  [NSNumber numberWithFloat: 44100.0],AVSampleRateKey, //采样率

                                  [NSNumber numberWithInt: kAudioFormatLinearPCM],AVFormatIDKey,

                                  [NSNumber numberWithInt:16],AVLinearPCMBitDepthKey,//采样位数 默认 16

                                  [NSNumber numberWithInt: 2], AVNumberOfChannelsKey,//通道的数目

                                  [NSNumber numberWithBool:NO],AVLinearPCMIsBigEndianKey,//大端还是小端 是内存的组织方式

                                  [NSNumber numberWithBool:NO],AVLinearPCMIsFloatKey,nil];//采样信号是整数还是浮点数


 

NSURL *recordedTmpFile = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent: [NSString stringWithFormat: @"%.0f.%@", [NSDate timeIntervalSinceReferenceDate] * 1000.0, @"wav"]]];  //文件名的设置

//Setup the recorder to use this file and record to it.

AVAudioRecorder *recorder = [[ AVAudioRecorder alloc] initWithURL:recordedTmpFile settings:recordSetting error:&error];

 

[recorder prepareToRecord];

[recorder record];


下面代码应该是当前.m文件加载时候就设置

AVAudioSession * audioSession = [AVAudioSession sharedInstance];

[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error: &error]; //设置音频类别,这里表示当应用启动,停掉后台其他音频

[audioSession setActive:YES error: &error];//设置当前应用音频活跃性

---------------------------------------------------------------------------------

//参数指定录音文件名和路径

-(void)startRecordWithPath:(NSString *)path

{

    NSError * err = nil;

    

    AVAudioSession *audioSession = [AVAudioSession sharedInstance];

    [audioSession setCategory :AVAudioSessionCategoryPlayAndRecord error:&err];

    

    if(err){

        NSLog(@"audioSession: %@ %d %@", [err domain], [err code], [[err userInfo] description]);

        return;

    }

    

    [audioSession setActive:YES error:&err];

    

    err = nil;

    if(err){

        NSLog(@"audioSession: %@ %d %@", [err domain], [err code], [[err userInfo] description]);

        return;

    }

    

    

    

    /*

     

     ios  几种格式录音大小

     Here are the results for few encoding supported by iPhone. Size of audio file in KB of duration 10 sec.

     

     kAudioFormatMPEG4AAC : 164,

     

     kAudioFormatAppleLossless : 430,

     

     kAudioFormatAppleIMA4 : 475,

     

     kAudioFormatULaw : 889,

     

     kAudioFormatALaw : 889,

     

     Among these kAudioFormatMPEG4AAC is having smallest size

     

     */

    //默认AVAudioRecorder录制后的格式是.caf

//    NSMutableDictionary * recordSetting = [NSMutableDictionary dictionary];

//    [recordSetting setValue :[NSNumber numberWithInt:kAudioFormatAppleIMA4] forKey:AVFormatIDKey]; //caf

//    [recordSetting setValue:[NSNumber numberWithFloat:16000.0] forKey:AVSampleRateKey];  //采样率

//    [recordSetting setValue:[NSNumber numberWithInt: 1] forKey:AVNumberOfChannelsKey];

    

    //大部分的播放器都是不支持这个格式的,下面一段设置是可以让录制格式是wav的格式

//    NSDictionary *recordSetting = [[NSDictionary alloc] initWithObjectsAndKeys:

//                                   [NSNumber numberWithFloat: 44100.0],AVSampleRateKey, //采样率

//                                   [NSNumber numberWithInt: kAudioFormatLinearPCM],AVFormatIDKey,

//                                   [NSNumber numberWithInt:16],AVLinearPCMBitDepthKey,//采样位数 默认 16

//                                   [NSNumber numberWithInt: 2], AVNumberOfChannelsKey,//通道的数目

//                                   [NSNumber numberWithBool:NO],AVLinearPCMIsBigEndianKey,//大端还是小端 是内存的组织方式

//                                   [NSNumber numberWithBool:NO],AVLinearPCMIsFloatKey,nil];//采样信号是整数还是浮点数

    

//    NSDictionary *recordSetting = @{AVFormatIDKey : @(kAudioFormatLinearPCM), AVEncoderBitRateKey:@(16),AVEncoderAudioQualityKey : @(AVAudioQualityMax), AVSampleRateKey : @(8000.0), AVNumberOfChannelsKey : @(1)};

    

    

    self.recordPath = path;

    NSURL * url = [NSURL fileURLWithPath:self.recordPath];

    

    err = nil;

    

    NSData * audioData = [NSData dataWithContentsOfFile:[url path] options: 0 error:&err];

    

    if(audioData)

    {

        NSFileManager *fm = [NSFileManager defaultManager];

        [fm removeItemAtPath:[url path] error:&err];

    }

    

    err = nil;

    

    if(self.recorder){[self.recorder stop];self.recorder = nil;}

    

    self.recorder = [[AVAudioRecorder alloc] initWithURL:url settings:recordSetting error:&err];

    

    if(!_recorder){

        NSLog(@"recorder: %@ %d %@", [err domain], [err code], [[err userInfo] description]);

        UIAlertView *alert =

        [[UIAlertView alloc] initWithTitle: @"Warning"

                                   message: [err localizedDescription]

                                  delegate: nil

                         cancelButtonTitle:@"OK"

                         otherButtonTitles:nil];

        [alert show];

        return;

    }

    

    [_recorder setDelegate:self];

    [_recorder prepareToRecord];

    _recorder.meteringEnabled = YES;

    

    BOOL audioHWAvailable = audioSession.inputIsAvailable;

    if (! audioHWAvailable) {

        UIAlertView *cantRecordAlert =

        [[UIAlertView alloc] initWithTitle: @"提醒"

                                   message: @"设备无录音功能"

                                  delegate: nil

                         cancelButtonTitle:@"OK"

                         otherButtonTitles:nil];

        [cantRecordAlert show];

        return;

    }

    

    //[_recorder recordForDuration:(NSTimeInterval) 60];

    

    self.recordTime = 0;

    [self resetTimer];

    

    timer_ = [NSTimer scheduledTimerWithTimeInterval:WAVE_UPDATE_FREQUENCY target:self selector:@selector(updateMeters) userInfo:nil repeats:YES];

    NSLog(@"------- timer_ : %@",timer_);

    

    [self showVoiceHudOrHide:YES];

    

}



-(void) stopRecordWithCompletionBlock:(void (^)())completion

{

    dispatch_async(dispatch_get_main_queue(),completion);

    

   // [self.recorder stopRecording]; //停止录音

    

    [self resetTimer];

    [self showVoiceHudOrHide:NO];

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(实现)