美文网首页ios 音视频播放相关Ios开发学习iOS Developer
iOS 使用AVFoundation实现语音的录制和播放

iOS 使用AVFoundation实现语音的录制和播放

作者: zziazm | 来源:发表于2016-08-30 20:17 被阅读4855次

    iOS的AVFoundation框架中的AVAudioRecorder和AVAudioPlayer可以实现语音的录制和播放功能demo下载

    AVAudioRecorder

    AVAudioRecorder 的初始化方法是

    - (nullable instancetype)initWithURL:(NSURL *)url settings:(NSDictionary<NSString *, id> *)settings error:(NSError **)outError;
    
    • url: 录制的语音文件保存的路径,文件的类型是由这个参数值的file extension推测的。
    • settings: 对audio recored的设置。在iOS7中,默认的设置是
    { AVFormatIDKey = 1819304813;  
    AVLinearPCMBitDepthKey = 16;
    AVLinearPCMIsBigEndianKey = 0;
    AVLinearPCMIsFloatKey = 0; 
    AVLinearPCMIsNonInterleaved = 0;
    AVNumberOfChannelsKey = 2; 
    AVSampleRateKey = 44100;}
    

    下面的三个key适用于所有的语音格式:
    AVFormatIDKey:格式的标识,它对应的是个枚举值。

    CF_ENUM(AudioFormatID)
    {
        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',
        kAudioFormatAMR_WB                  = 'sawb',
        kAudioFormatAudible                 = 'AUDB',
        kAudioFormatiLBC                    = 'ilbc',
        kAudioFormatDVIIntelIMA             = 0x6D730011,
        kAudioFormatMicrosoftGSM            = 0x6D730031,
        kAudioFormatAES3                    = 'aes3',
        kAudioFormatEnhancedAC3             = 'ec-3'
    };
    

    AVSampleRateKey: 采样率,44.1kHZ和标准的CD Audio是相同的,除非你需要一个高保真的录音,你不需要这样高的采样率,大部分的音频软件只能特定的速率像32KHZ,24KHZ,16KHZ,12KHZ.8KHZ是电话采样率,对一般的录音已经足够了。
    AVNumberOfChannelsKey:通道数。设成2的话是双声道。iPhone只有一个麦克风,一个单声道的通道足够了,它把你的数据需求削减了一半。
    参考

    开始录音的代码:

    
        NSString * url = NSTemporaryDirectory();
        url = [url stringByAppendingString:[NSString stringWithFormat:@"%f.wav", [[NSDate date] timeIntervalSince1970]]];
        NSMutableDictionary * settings = @{}.mutableCopy;
        [settings setObject:[NSNumber numberWithFloat:8000.0] forKey:AVSampleRateKey];
        [settings setObject:[NSNumber numberWithInt: kAudioFormatLinearPCM] forKey:AVFormatIDKey];  
        [settings setObject:@1 forKey:AVNumberOfChannelsKey];//设置成一个通道,iPnone只有一个麦克风,一个通道已经足够了
        [settings setObject:@16 forKey:AVLinearPCMBitDepthKey];//采样的位数
        self.audioRecorder = [[AVAudioRecorder  alloc] initWithURL:[NSURL fileURLWithPath:url] settings:settings error:&error];
        self.audioRecorder.delegate = self;
        [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryRecord error:nil];
        self.audioRecorder.meteringEnabled = YES;
        BOOL success = [self.audioRecorder record];
        if (success) {
            NSLog(@"录音开始成功");
        }else{
            NSLog(@"录音开始失败");
        }
    

    遇到的问题

    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryRecord error:nil];
    

    这个是设置AVAudioSession的category的,如果不设置的话,在模拟器上success是YES,但是在真机上是NO。同样,在用AVAudioPlayer播放语音时要设置category为AVAudioSessionCategoryPlayback

    停止录音

        [self.audioRecorder stop];
    

    调用这个方法后,会走下面的代理方法

    -(void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag{
        NSURL * url = recorder.url;
    }
    

    获取录音过程中的分贝

    要在录音过程中获取分贝数,要在录音前先把AVAudioRecorder的属性meteringEnabled设置成YES.
    在录音开始后,可以设置一个定时器获取分贝数

    _metesTimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(setVoiceImage) userInfo:nil repeats:YES];
    -(void)setVoiceImage{
        if (self.audioRecorder.isRecording) {
            [self.audioRecorder updateMeters];
            float peakPower = [self.audioRecorder peakPowerForChannel:0];
            NSLog(@"%f", peakPower);
        }
    }
    

    AVAudioRecorderaveragePowerForChannelpeakPowerForChannel方法返回的是分贝数据,数值在-160 – 0之间

    播放语音

    可以将录音后获取的url传入下面的方法中:

    - (void)playAudioWithURL:(NSURL *)url{
        [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
        NSError * error;
        self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
        self.audioPlayer.delegate = self;
        BOOL success = [self.audioPlayer play];
        if (success) {
            NSLog(@"播放成功");
        }else{
            NSLog(@"播放失败");
        }
    }
    

    我在demo里封装了一个ZMAudioManager的类,方便进行语音的播放和录制:
    开始录音

    [[ZMAudioManager shareInstance] startRecordingWithFileName:[NSString stringWithFormat:@"%f.wav", [[NSDate date] timeIntervalSince1970]] completion:^(NSError *error) {
        if (error) {
    
        else{
    
        }
    }];
    

    停止录音,recordPath是录音文件存放的路径,aDuration是录音时长

     [[ZMAudioManager  shareInstance] stopRecordingWithType:ZMAudioRecordeAMRType completion:^(NSString *recordPath, NSInteger aDuration, NSError *error) {
            if (error) {
                UIAlertView *a = [[UIAlertView alloc] initWithTitle:@"error" message:error.domain delegate:nil cancelButtonTitle:@"确定" otherButtonTitles: nil];
                [a show];
            }else{
               
     }];
    

    播放录音,audioPath是录音文件存放的路径,录音播放完后会走completion回调

     [[ZMAudioManager shareInstance] playAudioWithPath:audioPath completion:^(NSError *error) {
     
     
      }];
    

    在实际开发中,考虑到要和android之间通信,android支持amr,不支持wav;iOS支持wav,不支持amr。通常iOS客户端会进行amr和wav的互相转换。
    在demo里EMVoiceConverter文件包含了wav和amr互相转换的方法:

    + (int)amrToWav:(NSString*)_amrPath wavSavePath:(NSString*)_savePath;
    
    + (int)wavToAmr:(NSString*)_wavPath amrSavePath:(NSString*)_savePath;
    

    相关文章

      网友评论

      • 问夕阙:我改成 kAudioFormatMPEGLayer3 这个mp3的格式 为什么AVAudioRecorder它创建的对象就是空的?这是什么问题?
        你大赟哥:@zziazm 大佬url改成.mp3也不对还是nil
        zziazm:你需要把初始化方法里的url后缀改成.mp3
      • CMD独白:弄了好几天了,在模拟器上可以显示录音时长,在真机上就不行,原来是没有加这句话
        [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryRecord error:nil];
      • Zcocoa:[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryRecord error:nil];想要同时录音并且在喇叭播放应该怎么设置?
      • 63f2dd559f52:作者怎么不换成语音条的形式去播放,这样我就可以直接用了,哈哈
      • 9d426ee34834:真机会崩溃 ,找了 半天也没找到原因
        63f2dd559f52:提示语音功能不能用,在 plist 文件里添加Privacy - Microphone Usage Description 就可以了
      • 凯文Kevin21:FirstViewController.h 和FirstViewController.m 找不到。。。
        zziazm:@七秒小鱼人重新上传了,应该可以了

      本文标题:iOS 使用AVFoundation实现语音的录制和播放

      本文链接:https://www.haomeiwen.com/subject/xntzsttx.html