iOS录音方法实用详解(配Demo下载)

 

iOS录音播放Demo下载地址:http://download.csdn.net/detail/lovechris00/9587214

 

本文将涉及到以下内容:

一、搭建长按录音UI效果;

二、使用AVAudioRecorder录音;

三、使用AVAudioPlayer播放,并添加播放动画;

四、使用lame将caf音频转化为mp3;

五、将mp3 转化为 base64编码;

六、查看录音文件大小;

七、删除语音文件;

八、获取录音时长

 


一、搭建长按录音UI效果;

页面样式效果如下:

其中:

1、录音按钮是由两个UIImageView实现,监听手势方法,长按第一层UIImageView时,第二层开始旋转动画;

   这里我想过用UIButton来实现点击录音效果,其中UIControlEventTouchDown可以检测点击下去的效果,UIControlEventTouchUpInside可以检测点击后起来的效果,但是测试点击下去后,没有直接起来,而是将手指移动到其他位置,导致录音无法关闭,所以,还是使用了长按手势来监听。

 

2、其他控件比较简单。

iOS录音方法实用详解(配Demo下载)_第1张图片

 


核心代码

1、长按启动录音;

- (UIImageView *)recordBtn
{
    
    if (!_recordBtn) {
        _recordBtn = [[UIImageView alloc]init];
        _recordBtn.backgroundColor = [UIColor clearColor];
        
        [_recordBtn setImage:[UIImage imageNamed:@"record_norm"]];
        _recordBtn.userInteractionEnabled = YES;//方便添加长按手势
    }
    
    return _recordBtn;
}

 

self.recordBtn.frame = CGRectMake((kSCREEN_WIDTH - btnH)*0.5, CGRectGetMaxY(self.timeLabel.frame) + margin, btnH, btnH);
        self.recordBtn.layer.cornerRadius = self.recordBtn.frame.size.width * 0.5;
        
        [self.recordBtn.layer setMasksToBounds:YES];
        //        [self.recordBtn addTarget:self action:@selector(recordNotice) forControlEvents:UIControlEventTouchDown];
        //        [self.recordBtn addTarget:self action:@selector(stopNotice) forControlEvents:UIControlEventTouchUpInside];
        
        //实例化长按手势监听
        UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleTableviewCellLongPressed:)];
        
        //代理
        longPress.delegate = self;
        longPress.minimumPressDuration = 0.5;
        [self.recordBtn addGestureRecognizer:longPress];

 

//长按事件的实现方法

- (void) handleTableviewCellLongPressed:(UILongPressGestureRecognizer *)gestureRecognizer {
    
    if (gestureRecognizer.state ==  UIGestureRecognizerStateBegan) {
        
        NSLog(@"UIGestureRecognizerStateBegan");
        [self startRecordNotice];
        
    }
    
    if (gestureRecognizer.state == UIGestureRecognizerStateChanged) {
        
    }
    
    if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
        
        NSLog(@"UIGestureRecognizerStateEnded");
        [self stopRecordNotice];
        
    }
    
}

 


2、录音过程中,录音外圈旋转效果

1)初始化

-(UIImageView *)rotateImgView
{
    if (!_rotateImgView) {
        _rotateImgView = [[UIImageView alloc]init];
        _rotateImgView.image = [UIImage imageNamed:@"rcirle_norm"];
        _rotateImgView.frame = CGRectMake(0, 0, btnH, btnH);
        _rotateImgView.center = self.recordBtn.center;
 }
    return _rotateImgView;
}

 

2)动画设置

// 执行动画
- (void)starAnimalWithTime:(CFTimeInterval)time  //time为旋转一周的时间
{
    self.rotateImgView.image = [UIImage imageNamed:@"rcirle_high"];
    
    self.rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    self.rotationAnimation.toValue = [NSNumber numberWithFloat: M_PI * 2.0 ];
    self.rotationAnimation.duration = time;
    self.rotationAnimation.cumulative = YES;
    self.rotationAnimation.repeatCount = HUGE_VALF;
    
    [self.rotateImgView.layer addAnimation:self.rotationAnimation forKey:@"rotationAnimation"];
}

 

3、播放时的动画效果

1)动画设置

#pragma mark - 动画效果

- (void)pictureChangeAnimationSetting
{
    NSArray *picArray = @[[UIImage imageNamed:@"voice1"],
                          [UIImage imageNamed:@"voice2"],
                          [UIImage imageNamed:@"voice3"],];
    
    //    self.imageView.image = [UIImage imageNamed:@"voice1"];
    
    
    //imageView的动画图片是数组images
    self.voiceView.animationImages = picArray;
    //按照原始比例缩放图片,保持纵横比
    self.voiceView.contentMode = UIViewContentModeScaleAspectFit;
    //切换动作的时间3秒,来控制图像显示的速度有多快,
    self.voiceView.animationDuration = 1;
    //动画的重复次数,想让它无限循环就赋成0
    self.voiceView.animationRepeatCount = 0;
    
}

 

2)开启动画

[self.voiceView startAnimating];

 

3)关闭动画

 [self.voiceView.layer removeAllAnimations];
    self.voiceView.image = [UIImage imageNamed:@"voice3"];

 


二、使用AVAudioRecorder录音;

#pragma mark -  Getter
/**
 *  获得录音机对象
 *
 *  @return 录音机对象
 */
-(AVAudioRecorder *)audioRecorder{
    if (!_audioRecorder) {
        //创建录音文件保存路径
        NSURL *url=[NSURL URLWithString:self.cafPathStr];
        //创建录音格式设置
        NSDictionary *setting=[self getAudioSetting];
        //创建录音机
        NSError *error=nil;
        
        _audioRecorder=[[AVAudioRecorder alloc]initWithURL:url settings:setting error:&error];
        _audioRecorder.delegate=self;
        _audioRecorder.meteringEnabled=YES;//如果要监控声波则必须设置为YES
        if (error) {
            NSLog(@"创建录音机对象时发生错误,错误信息:%@",error.localizedDescription);
            return nil;
        }
    }
    return _audioRecorder;
}

 

/**
 *  取得录音文件设置
 *
 *  @return 录音设置
 */
-(NSDictionary *)getAudioSetting{
    //LinearPCM 是iOS的一种无损编码格式,但是体积较为庞大
    //录音设置
    NSMutableDictionary *recordSettings = [[NSMutableDictionary alloc] init];
    //录音格式 无法使用
    [recordSettings setValue :[NSNumber numberWithInt:kAudioFormatLinearPCM] forKey: AVFormatIDKey];
    //采样率
    [recordSettings setValue :[NSNumber numberWithFloat:11025.0] forKey: AVSampleRateKey];//44100.0
    //通道数
    [recordSettings setValue :[NSNumber numberWithInt:2] forKey: AVNumberOfChannelsKey];
    //线性采样位数
    //[recordSettings setValue :[NSNumber numberWithInt:16] forKey: AVLinearPCMBitDepthKey];
    //音频质量,采样质量
    [recordSettings setValue:[NSNumber numberWithInt:AVAudioQualityMin] forKey:AVEncoderAudioQualityKey];
    
    return recordSettings;
}

 

- (void)startRecordNotice{

     if ([self.audioRecorder isRecording]) {
        [self.audioRecorder stop];
    }
   
    [self deleteOldRecordFile];  //如果不删掉,会在原文件基础上录制;虽然不会播放原来的声音,但是音频长度会是录制的最大长度。
    
    AVAudioSession *audioSession=[AVAudioSession sharedInstance];
    [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
    
    
    if (![self.audioRecorder isRecording]) {//0--停止、暂停,1-录制中
        
        [self.audioRecorder record];//首次使用应用时如果调用record方法会询问用户是否允许使用麦克风
        self.countNum = 0;
        NSTimeInterval timeInterval =1 ; //0.1s
        self.timer1 = [NSTimer scheduledTimerWithTimeInterval:timeInterval  target:self selector:@selector(changeRecordTime)  userInfo:nil  repeats:YES];
        
        [self.timer1 fire];
    }
    [self starAnimalWithTime:2.0];
}

 

- (void)stopRecordNotice
{
    NSLog(@"----------结束录音----------");

    [self.audioRecorder stop];
    [self.timer1 invalidate];
   
}

三、使用AVAudioPlayer播放;

这段代码写的不好,暂不分享,欢迎大家分享给我

 


四、使用lame将caf音频转化为mp3;

lame 源码下载地址:https://lame.sourceforge.io/download.php

导入lame框架,import进来头文件即可使用,如果导出后是噪音,需要检查录音的设置

#pragma mark - caf转mp3
- (void)audio_PCMtoMP3
{
    
    @try {
        int read, write;
        
        FILE *pcm = fopen([self.cafPathStr cStringUsingEncoding:1], "rb");  //source 被转换的音频文件位置
        fseek(pcm, 4*1024, SEEK_CUR);                                   //skip file header
        FILE *mp3 = fopen([self.mp3PathStr cStringUsingEncoding:1], "wb");  //output 输出生成的Mp3文件位置
        
        const int PCM_SIZE = 8192;
        const int MP3_SIZE = 8192;
        short int pcm_buffer[PCM_SIZE*2];
        unsigned char mp3_buffer[MP3_SIZE];
        
        lame_t lame = lame_init();
        lame_set_in_samplerate(lame, 11025.0);
        lame_set_VBR(lame, vbr_default);
        lame_init_params(lame);
        
        do {
            read = fread(pcm_buffer, 2*sizeof(short int), PCM_SIZE, pcm);
            if (read == 0)
                write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE);
            else
                write = lame_encode_buffer_interleaved(lame, pcm_buffer, read, mp3_buffer, MP3_SIZE);
            
            fwrite(mp3_buffer, write, 1, mp3);
            
        } while (read != 0);
        
        lame_close(lame);
        fclose(mp3);
        fclose(pcm);
    }
    @catch (NSException *exception) {
        NSLog(@"%@",[exception description]);
    }
    @finally {
        NSLog(@"MP3生成成功: %@",self.mp3PathStr);
    }
    
}

 

使用上述lame转码可能会出现获取时长不准确,最近(18年1月11日)发现是lame转码的问题。由于上传资源不能修改,所以这里补充 lame的转码方法:

http://blog.csdn.net/lovechris00/article/details/79034036

 


五、将mp3 转化为 base64编码;

#pragma mark - 文件转换
// 二进制文件转为base64的字符串
- (NSString *)Base64StrWithMp3Data:(NSData *)data{
    if (!data) {
        NSLog(@"Mp3Data 不能为空");
        return nil;
    }
    //    NSString *str = [data base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
    NSString *str = [data base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
    return str;
}

// base64的字符串转化为二进制文件
- (NSData *)Mp3DataWithBase64Str:(NSString *)str{
    if (str.length ==0) {
        NSLog(@"Mp3DataWithBase64Str:Base64Str 不能为空");
        return nil;
    }
    NSData *data = [[NSData alloc] initWithBase64EncodedString:str options:NSDataBase64DecodingIgnoreUnknownCharacters];
    NSLog(@"Mp3DataWithBase64Str:转换成功");
    return data;
}

 


六、查看录音文件大小;

//单个文件的大小,返回单位为K
- (long long) fileSizeAtPath:(NSString*)filePath{
    
    NSFileManager* manager = [NSFileManager defaultManager];
    
    if ([manager fileExistsAtPath:filePath]){
        
        return [[manager attributesOfItemAtPath:filePath error:nil] fileSize];
        
    }
    
    return 0;
}

 

调用

//计算文件大小
    long long fileSize = [self fileSizeAtPath:self.mp3PathStr]/1024.0;
    NSString *fileSizeStr = [NSString stringWithFormat:@"%lld",fileSize];

七、删除(语音)文件;

-(void)deleteOldRecordFileAtPath:(NSString *)pathStr{
    NSFileManager* fileManager=[NSFileManager defaultManager];
    
    BOOL blHave=[[NSFileManager defaultManager] fileExistsAtPath:pathStr];
    if (!blHave) {
        NSLog(@"不存在");
        return ;
    }else {
        NSLog(@"存在");
        BOOL blDele= [fileManager removeItemAtPath:self.cafPathStr error:nil];
        if (blDele) {
            NSLog(@"删除成功");
        }else {
            NSLog(@"删除失败");
        }
    }
}

 

 


八、获取录音时长

#pragma mark 获取mp3时长(秒)
//返回mp3音频的时间长(n秒,字符串)
- (NSString *)getMp3DataDuration:(NSData *)mp3Data{
    NSError *error = nil;
    AVAudioPlayer *tempPlayer = [[AVAudioPlayer alloc]initWithData:mp3Data error:&error];
    
    int duration = ceilf(tempPlayer.duration);
    NSString *durationStr = [NSString stringWithFormat:@"%d",duration];
    
    NSLog(@"durationStr : %@ ,duration : %d ,error : %@ ",durationStr,duration,error);
    return durationStr;
}

 

使用上述lame转码可能会出现获取时长不准确,最近(18年1月11日)发现是lame转码的问题。由于上传资源不能修改,所以这里补充 lame的转码方法:

http://blog.csdn.net/lovechris00/article/details/79034036

 


 

iOS录音播放Demo下载地址:http://download.csdn.net/detail/lovechris00/9587214

 

 

你可能感兴趣的:(Apple,开发,iOS,录音,AVAudioRecorder)