第五十一篇、录音

时间:2022-09-25 06:12:03

录音

在AVFoundation框架中有一个AVAudioRecorder类专门处理录音操作,它同样支持多种音频格式。与AVAudioPlayer类似,你完全可以将它看成是一个录音机控制类,下面是常用的属性和方法:

先来了解下AVAudioRecorder的常用属性:
@property (readonly, getter=isRecording) BOOL recording;//是否正在录音
@property (readonly) NSDictionary<NSString *, id> *settings;//录音配置
@property (readonly) NSURL *url;//录音文件存放URL
@property (readonly) NSTimeInterval currentTime;//录音时长
@property (getter=isMeteringEnabled) BOOL meteringEnabled;//是否监控声波

常用对象方法:
- (BOOL)prepareToRecord;//为录音准备缓冲区
- (BOOL)record;//录音开始,暂停后调用会恢复录音
- (BOOL)recordAtTime:(NSTimeInterval)time;//在指定时间后开始录音
- (BOOL)recordForDuration:(NSTimeInterval) duration;//按指定时长录音
- (BOOL)recordAtTime:(NSTimeInterval)time forDuration:(NSTimeInterval)duration;//上面2个的合体
- (void)pause; //中断录音
- (void)stop; //停止录音
- (BOOL)deleteRecording;//删除录音,必须先停止录音再删除

常用的代理方法:
//录音完成后调用
- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag;//录音编码发送错误时调用
- (void)audioRecorderEncodeErrorDidOccur:(AVAudioRecorder *)recorder error:(NSError *)error;

 

音频

如果播放较大的音频或者要对音频有精确的控制则System Sound Service可能就很难满足实际需求了,通常这种情况会选择使用AVFoundation.framework中的AVAudioPlayer来实现。AVAudioPlayer可以看成一个播放器,它支持多种音频格式,而且能够进行进度、音量、播放速度等控制

AVAudioPlayer的使用比较简单:

1.初始化AVAudioPlayer对象,此时通常指定本地文件路径。

2.设置播放器属性,例如重复次数、音量大小等。

3.调用play方法播放。

 

具体实现:

#import <AVFoundation/AVFoundation.h>
#define kRecordAudioFile @"myRecord.caf"


@interface ViewController ()<AVAudioRecorderDelegate>
{
    NSString *dateName;

}
@property (weak, nonatomic) IBOutlet UITableView *table;

@property (nonatomic,strong) AVAudioRecorder *audioRecorder;//音频录音机
@property (nonatomic,strong) AVAudioPlayer *audioPlayer;//音频播放器,用于播放录音文件


@property(nonatomic,strong) NSMutableArray *spaceData;


@end

@implementation ViewController
#pragma mark - 私有方法
/**
 *  设置音频会话
 */
-(void)setAudioSession{

    AVAudioSession *audioSession=[AVAudioSession sharedInstance];
    //设置为播放和录音状态,以便可以在录制完之后播放录音
    [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
    [audioSession setActive:YES error:nil];
}



/**
 *  取得录音文件设置
 *
 *  @return 录音设置
 */
-(NSDictionary *)getAudioSetting{
    NSMutableDictionary *dicM=[NSMutableDictionary dictionary];
    //设置录音格式
    [dicM setObject:@(kAudioFormatLinearPCM) forKey:AVFormatIDKey];
    //设置录音采样率,8000是电话采样率,对于一般录音已经够了
    [dicM setObject:@(8000) forKey:AVSampleRateKey];
    //设置通道,这里采用单声道
    [dicM setObject:@(1) forKey:AVNumberOfChannelsKey];
    //每个采样点位数,分为8、16、24、32
    [dicM setObject:@(8) forKey:AVLinearPCMBitDepthKey];
    //是否使用浮点数采样
    [dicM setObject:@(YES) forKey:AVLinearPCMIsFloatKey];
    //....其他设置等
    return dicM;
}
/**
 *  取得录音文件保存路径
 *
 *  @return 录音文件路径
 */
-(NSURL *)getPlayPath:(NSString *)title{


    //    static int index = 0;

    NSString *urlStr=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    urlStr=[urlStr stringByAppendingPathComponent:[NSString stringWithFormat:@"%@%@",title,kRecordAudioFile]];
    NSLog(@"play file path:%@",urlStr);
    NSURL *url=[NSURL fileURLWithPath:urlStr];

    return url;
}

/**
 *  以日期为title,来保存录音
 *
 *  @return <#return value description#>
 */
- (NSString *) convertDateFromString
{
    NSDate *date = [NSDate date];
    //    NSLog(@"%@--askl",date);
    //    
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; 
    //zzz表示时区,zzz可以删除,这样返回的日期字符将不包含时区信息。

   [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
   NSString *destDateString = [dateFormatter stringFromDate:date];

    return destDateString;

}

 

长按开始录音,松开停止:

- (void)setClikeSpaceState:(NSString *)aState
{
    NSLog(@"点击语音---");    

    if([aState isEqualToString:@"begin"])
    {
        NSLog(@"begin---");

        dateName = [self convertDateFromString];
        //创建录音文件保存路径
        NSURL *url=[self getPlayPath:dateName];
        //创建录音格式设置
        NSDictionary *setting=[self getAudioSetting];
        //创建录音机
        NSError *error=nil;
        _audioRecorder=[[AVAudioRecorder alloc]initWithURL:url settings:setting error:&error];
        _audioRecorder.delegate=self;
        _audioRecorder.meteringEnabled=YES;//如果要监控声波则必须设置为YES

        if (![self.audioRecorder isRecording]) {
            [self.audioRecorder record];//首次使用应用时如果调用record方法会询问用户是否允许使用麦克风
            //        self.timer.fireDate=[NSDate distantPast];

            NSLog(@"111");
        }


    }else
    {
        NSLog(@"end---");


        /** 停止录音*/
        [self.audioRecorder stop];


        /** 录音地址*/
        NSURL *url = [self getPlayPath:dateName];

        /** 加载数据*/

        AVAudioPlayer   *audioPlayer1 = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];

        Model *model = [[Model alloc]init];
        model.duration = [NSString stringWithFormat:@"%.f",audioPlayer1.duration];
        model.spacePath = dateName;



        /** table 刷新*/
        [self.spaceData addObject:model];
        [self.table reloadData];


        /** table 滚动到当前row*/

        [self.table selectRowAtIndexPath:[NSIndexPath indexPathForRow:(self.spaceData.count - 1) inSection:0] animated:YES scrollPosition:UITableViewScrollPositionTop];






    }
}

 

点击播放:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{


    Model *model = self.spaceData[indexPath.row];    

    /** 播放录音*/
    NSURL *url=[self getPlayPath:model.spacePath];
    NSError *error=nil;
    _audioPlayer=[[AVAudioPlayer alloc]initWithContentsOfURL:url error:&error];
    _audioPlayer.numberOfLoops=0;

    [_audioPlayer prepareToPlay];
    [self.audioPlayer play];

    NSLog(@"%.0f---aaaa",_audioPlayer.duration);

    /** UIImage动画数组*/
    NSMutableArray   *imgData = [NSMutableArray array];
    for(int i=0;i<4;i++)
    {
        UIImage *aImage = [UIImage imageNamed:[NSString stringWithFormat:@"chat_receiver_audio_playing00%d",i]];
        [imgData addObject:aImage];

    }

    TwoTableViewCell *twoCell = [self.table cellForRowAtIndexPath:indexPath];




    /** 点击动画*/

    [twoCell.speak  setAnimationImages:imgData];
    //        [twoCell.speak setAnimationRepeatCount:1];
    [twoCell.speak setAnimationDuration:1];
    [twoCell.speak startAnimating];

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)([model.duration intValue] * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

        [twoCell.speak stopAnimating];

    });

}