• 录音功能实现


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

     

     

     

     

     

     

     

     

     

     

     

     

     

  • 相关阅读:
    关于ligerui 中 grid 表格的扩展搜索功能在远程数据加载时无法使用的解决办法
    关于ligerUI中ligerTree代码中的一个bug,造成该控件无法通过url的POST方式加载数据
    通过注册表控制软件可否运行
    SQL 分组后获取其中一个字段最大值的整条记录
    sqlserver2005唯一性约束
    正则表达式
    关于AfterLogic WebMail 的.net版无法上传控件的解决办法
    使用openrowset跨库查询
    [转载]SQL字符串处理函数大全
    Tomcat 内存和线程配置优化
  • 原文地址:https://www.cnblogs.com/allanliu/p/4269304.html
Copyright © 2020-2023  润新知