欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

iOS录音方法实用详解

程序员文章站 2023-10-17 14:10:11
本文将涉及到以下内容: 一、搭建长按录音ui效果; 二、使用avaudiorecorder录音; 三、使用avaudioplayer播放,并添加播放动画; 四、使用lame将caf音频转化为mp3;...

本文将涉及到以下内容:

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

二、使用avaudiorecorder录音;

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

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

五、将mp3 转化为 base64编码;

六、查看录音文件大小;

七、删除语音文件;

 

--------------------------

 

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

页面样式效果如下:

其中:

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

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

2、其他控件比较简单。

 

核心代码

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框架,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);
    }
    
}


五、将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(@"删除失败");
        }
    }
}