录音功能实现

 
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];
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted on 2015-02-03 10:13  奋进的闹钟  阅读(1211)  评论(0编辑  收藏  举报

导航