ios 音视频播放相关Ios开发学习iOS Developer

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

2016-08-30  本文已影响4855人  zziazm

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

AVAudioRecorder

AVAudioRecorder 的初始化方法是

- (nullable instancetype)initWithURL:(NSURL *)url settings:(NSDictionary<NSString *, id> *)settings error:(NSError **)outError;
{ 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;
上一篇 下一篇

猜你喜欢

热点阅读