美文网首页
Android 录音MediaRecorder到AudioRec

Android 录音MediaRecorder到AudioRec

作者: 易瑞 | 来源:发表于2017-08-13 18:18 被阅读0次

    研究录音是源于即时通讯的项目。写出一个即时通讯很简单,但是写好一个即时通讯就不是一件容易的事,比如聊天中语音的加入。接下来就来描述一下自己对语音的见解和处理方式。

    首先写到语音,当然首当其冲的是运用到网上百分之八九十的处理方案MediaRecorder,这个也是我首先用到的方式,主要是由于以前写过接入环信的项目,它里面所提供的就是MediaRecorder。大概的来介绍一下这个类的几个常用方法吧。

    Initial:初始状态,当使用new()方法创建一个MediaRecorder对象或者调用了reset()方法时,该MediaRecorder对象处于Initial状态。在设定视频源或者音频源之后将转换为Initialized状态。另外,在除Released状态外的其它状态通过调用reset()方法都可以使MediaRecorder进入该状态。

    Initialized:已初始化状态,可以通过在Initial状态调用setAudioSource()或setVideoSource()方法进入该状态。在这个状态可以通过setOutputFormat()方法设置输出格式,此时MediaRecorder转换为DataSourceConfigured状态。另外,通过reset()方法进入Initial状态。

    DataSourceConfigured:数据源配置状态,这期间可以设定编码方式、输出文件、屏幕旋转、预览显示等等。可以在Initialized状态通过setOutputFormat()方法进入该状态。另外,可以通过reset()方法回到Initial状态,或者通过prepare()方法到达Prepared状态。

    Prepared:就绪状态,在DataSourceConfigured状态通过prepare()方法进入该状态。在这个状态可以通过start()进入录制状态。另外,可以通过reset()方法回到Initialized状态。

    Recording:录制状态,可以在Prepared状态通过调用start()方法进入该状态。另外,它可以通过stop()方法或reset()方法回到Initial状态。

    Released:释放状态(官方文档给出的词叫做Idle state 空闲状态),可以通过在Initial状态调用release()方法来进入这个状态,这时将会释放所有和MediaRecorder对象绑定的资源。

    Error:错误状态,当错误发生的时候进入这个状态,它可以通过reset()方法进入Initial状态

    这个MediaRecorder的主要是有停供的方法来进行编码语音,好处自然就是方便,另外一个就是它所编译的语音文件体积非常小。大概有AAC和ARM用得比较多,环信使用的就是ARM的编码方式。其实我觉得差别不是很大,都不是特别好的录音,对于项目要求不高的可以考虑下,下面我也会粘贴出工具类,方便使用(EaseVoiceRecorder),对了,忘了说,它还提供通道设置setAudioChannels  1是单声道 2是多声道;setAudioSamplingRate采样率,网上说的是越大越好,但是我选了很多中个人觉得16000比较适中。

    importjava.io.File;

    importjava.io.IOException;

    importjava.util.Date;

    importandroid.content.Context;

    importandroid.content.pm.PackageManager;

    importandroid.media.MediaRecorder;

    importandroid.os.Handler;

    importandroid.os.SystemClock;

    importandroid.text.format.Time;

    importandroid.util.Log;

    importcom.lvgou.distribution.driect.entity.EMError;

    importcom.lvgou.distribution.utils.PathUtil;

    publicclassEaseVoiceRecorder{

    MediaRecorderrecorder;

    staticfinalStringPREFIX="voice";

    staticfinalStringEXTENSION=".mp3";

    Stringuid;

    privatebooleanisRecording=false;

    privatelongstartTime=-4;

    privateStringvoiceFilePath=null;

    privateStringvoiceFileName=null;

    privateFilefile;

    privateHandlerhandler;

    privateContextmContext;

    //    public EaseVoiceRecorder(Handler handler) {

    //        this.handler = handler;

    //    }

    publicEaseVoiceRecorder(){

    }

    /**

    * @param appContext

    * @param userId    传入userId 用于标示 名称

    * @return

    */

    publicStringstartRecording(ContextappContext,StringuserId){

    mContext=appContext;

    file=null;

    startTime=-4;

    try{

    // need to create recorder every time, otherwise, will got exception

    // from setOutputFile when try to reuse

    if(recorder!=null){

    recorder.release();

    recorder=null;

    }

    recorder=newMediaRecorder();

    recorder.setAudioSource(MediaRecorder.AudioSource.MIC);

    //            recorder.setOutputFormat(MediaRecorder.OutputFormat.AAC_ADTS);

    //            recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);

    //            recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);

    //            recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);

    /*//          方案一

    recorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB);

    recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);

    recorder.setAudioChannels(2); // MONO

    recorder.setAudioSamplingRate(16000); // 8000Hz*/

    //          方案二

    recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);

    recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);

    recorder.setAudioChannels(2);

    recorder.setAudioSamplingRate(16000);

    /*//            方案三

    recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);

    recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);*/

    //            recorder.setAudioEncodingBitRate(64); // seems if change this to

    // 128, still got same file

    // size.

    // one easy way is to use temp file

    // file = File.createTempFile(PREFIX + userId, EXTENSION,

    // User.getVoicePath());

    voiceFileName=getVoiceFileName(userId);

    voiceFilePath=PathUtil.getInstance().getVoicePath()+"/"+voiceFileName;

    file=newFile(voiceFilePath);

    recorder.setOutputFile(file.getAbsolutePath());

    recorder.prepare();

    isRecording=true;

    recorder.start();

    }catch(IOExceptione){

    }

    newThread(newRunnable(){

    @Override

    publicvoidrun(){

    try{

    while(isRecording){

    //                        android.os.Message msg = new android.os.Message();

    //                        msg.what = recorder.getMaxAmplitude() * 13 / 0x7FFF;

    //                        handler.sendMessage(msg);

    SystemClock.sleep(100);

    }

    }catch(Exceptione){

    // from the crash report website, found one NPE crash from

    // one android 4.0.4 htc phone

    // maybe handler is null for some reason

    }

    }

    }).start();

    startTime=newDate().getTime();

    returnfile==null?null:file.getAbsolutePath();

    }

    /**

    * stop the recoding

    *

    * @return seconds of the voice recorded

    */

    publicvoiddiscardRecording(){

    if(recorder!=null){

    try{

    recorder.stop();

    recorder.release();

    recorder=null;

    if(file!=null&&file.exists()&&!file.isDirectory()){

    file.delete();

    }

    }catch(IllegalStateExceptione){

    }catch(RuntimeExceptione){

    }

    isRecording=false;

    }

    }

    publicintgetRatio(){

    if(recorder!=null){

    intratio=recorder.getMaxAmplitude()/600;

    returnratio;

    }

    return-1;

    }

    publicintstopRecoding(){

    if(recorder!=null){

    isRecording=false;

    if(startTime>-1){

    try{

    recorder.stop();

    recorder.release();

    }catch(Exceptione){

    e.printStackTrace();

    }

    recorder=null;

    }

    intseconds=(int)(newDate().getTime()-startTime)/1000;

    if(seconds>0){

    if(file==null||!file.exists()||!file.isFile()){

    returnEMError.FILE_INVALID;

    }

    if(file.length()==0){

    file.delete();

    returnEMError.FILE_INVALID;

    }

    }

    returnseconds;

    }

    return0;

    }

    protectedvoidfinalize()throwsThrowable{

    super.finalize();

    if(recorder!=null){

    recorder.release();

    }

    }

    privateStringgetVoiceFileName(Stringuid){

    Timenow=newTime();

    now.setToNow();

    this.uid=uid;

    returnuid+now.toString().substring(0,15)+EXTENSION;

    }

    publicbooleanisRecording(){

    returnisRecording;

    }

    publicStringgetVoiceFilePath(){

    returnvoiceFilePath;

    }

    publicStringgetVoiceTargetFilePath(){

    Timenow=newTime();

    now.setToNow();

    returnPathUtil.getInstance().getVoicePath()+"/"+uid+now.toString().substring(0,15)+".mp3";

    }

    publicStringgetVoiceFileName(){

    returnvoiceFileName;

    }

    }

    EaseVoiceRecorder.java

    体积这么小而且这么方便,很大的一个缺点,也是我放弃的理由,就是录下的音质不太好,总感觉被什么笼罩着在。因此就开始寻求其它的解决方式,接下来就引用到了AudioRecord。主要是因为ios也是在使用这个所以就尝试着加入它来试试。大概描述一下简单工作流程:

    1.创建一个数据流。

    2.构造一个AudioRecord对象,其中需要的最小录音缓存buffer大小可以通过getMinBufferSize方法得到。如果buffer容量过小,将导致对象构造的失败。

    3.初始化一个buffer,该buffer大于等于AudioRecord对象用于写声音数据的buffer大小。

    4.开始录音。

    5.从AudioRecord中读取声音数据到初始化buffer,将buffer中数据导入数据流。

    6.停止录音。

    7.关闭数据流。

    首先遇到的问题是录音下来的东西是不能播放的,就是PCM格式的音频文件,也就是通常遇到的raw文件。简单的来说就是裸音。如果需要播放的话,必须要给裸数据加上头文件。这样得到的就是WAV格式的音频的文件,也是是电脑上经常使用的无损音质了,但是对于这么好的音质,引来的第一大问题就是文件体积比较大简单来说录音10秒大概就有四百多KB的大小。这可能对于即时通讯的项目是不行的,先粘贴出工具类先,方便大家其它地方有用到。

    importandroid.media.AudioFormat;

    importandroid.media.AudioRecord;

    importandroid.os.Environment;

    importandroid.text.format.Time;

    importandroid.util.Log;

    importjava.io.File;

    importjava.io.FileInputStream;

    importjava.io.FileNotFoundException;

    importjava.io.FileOutputStream;

    importjava.io.IOException;

    importjava.util.Date;

    importstaticcom.lvgou.distribution.driect.AudioFileFunc.isSdcardExit;

    /**

    * Created by Administrator on 2017/6/12.

    */

    publicclassChatAudioRecord{

    // 缓冲区字节大小

    privateintbufferSizeInBytes=0;

    //AudioName裸音频数据文件 ,麦克风

    privateStringAudioName="";

    //NewAudioName可播放的音频文件

    privateStringNewAudioName="";

    privateAudioRecordaudioRecord;

    privatebooleanisRecord=false;// 设置正在录制的状态

    publicbooleanisRecording(){

    returnisRecord;

    }

    privatestaticChatAudioRecordmInstance;

    privateChatAudioRecord(){

    }

    publicsynchronizedstaticChatAudioRecordgetInstance(){

    if(mInstance==null)

    mInstance=newChatAudioRecord();

    returnmInstance;

    }

    publicStringgetVoiceFilePath(){

    /* try {

    execute(new File(NewAudioName),myuid);

    Log.e("lkhfkhsdfg", "--------"+NewAudioName );

    return NewAudioName;

    } catch (Exception e) {

    e.printStackTrace();

    Log.e("lkhfkhsdfg", "---------"+e );

    }

    return "";*/

    //        writeMP3();

    returnNewAudioName;

    }

    privateStringmyuid="";

    publicintstartRecordAndFile(Stringuid){

    //判断是否有外部存储设备sdcard

    if(isSdcardExit()){

    if(isRecord){

    returnErrorCode.E_STATE_RECODING;

    }else{

    if(audioRecord==null)

    myuid=uid;

    creatAudioRecord(uid);

    audioRecord.startRecording();

    // 让录制状态为true

    isRecord=true;

    // 开启音频文件写入线程

    newThread(newAudioRecordThread()).start();

    startTime=newDate().getTime();

    returnErrorCode.SUCCESS;

    }

    }else{

    returnErrorCode.E_NOSDCARD;

    }

    }

    privatelongstartTime=-4;

    publicintstopRecordAndFile(){

    close();

    intseconds=(int)(newDate().getTime()-startTime)/1000;

    returnseconds;

    }

    publiclonggetRecordFileSize(){

    returnAudioFileFunc.getFileSize(NewAudioName);

    }

    privatevoidclose(){

    if(audioRecord!=null){

    System.out.println("stopRecord");

    isRecord=false;//停止文件写入

    audioRecord.stop();

    audioRecord.release();//释放资源

    audioRecord=null;

    }

    }

    privateStringuid="";

    staticfinalStringEXTENSION=".mp3";

    privateStringgetVoiceFileName(Stringuid,Stringnamess){

    Timenow=newTime();

    now.setToNow();

    this.uid=uid;

    returnuid+now.toString().substring(0,15)+namess;

    }

    privatefinalstaticStringAUDIO_RAW_FILENAME="RawAudio.raw";

    privatefinalstaticStringAUDIO_WAV_FILENAME="FinalAudio.wav";

    publicfinalstaticStringAUDIO_AMR_FILENAME="FinalAudio.amr";

    publicStringgetRawFilePath(StringuserId){

    StringmAudioRawPath="";

    if(isSdcardExit()){

    StringfileBasePath=Environment.getExternalStorageDirectory().getAbsolutePath();

    mAudioRawPath=fileBasePath+"/"+getVoiceFileName(userId,AUDIO_RAW_FILENAME);

    }

    returnmAudioRawPath;

    }

    /**

    * 获取编码后的WAV格式音频文件路径

    * @return

    */

    publicStringgetWavFilePath(StringuserId){

    StringmAudioWavPath="";

    if(isSdcardExit()){

    StringfileBasePath=Environment.getExternalStorageDirectory().getAbsolutePath();

    mAudioWavPath=fileBasePath+"/"+getVoiceFileName(userId,AUDIO_WAV_FILENAME);

    }

    returnmAudioWavPath;

    }

    privatevoidcreatAudioRecord(StringuserId){

    // 获取音频文件路径

    AudioName=getRawFilePath(userId);

    //        voiceFilePath= voiceFilePath = PathUtil.getInstance().getVoicePath() + "/" + voiceFileName;

    //        NewAudioName = AudioFileFunc.getWavFilePath();

    NewAudioName=getWavFilePath(userId);

    // 获得缓冲区字节大小

    bufferSizeInBytes=AudioRecord.getMinBufferSize(AudioFileFunc.AUDIO_SAMPLE_RATE,

    AudioFormat.CHANNEL_IN_STEREO,AudioFormat.ENCODING_PCM_16BIT);

    // 创建AudioRecord对象

    audioRecord=newAudioRecord(AudioFileFunc.AUDIO_INPUT,AudioFileFunc.AUDIO_SAMPLE_RATE,

    AudioFormat.CHANNEL_IN_STEREO,AudioFormat.ENCODING_PCM_16BIT,bufferSizeInBytes);

    }

    classAudioRecordThreadimplementsRunnable{

    @Override

    publicvoidrun(){

    writeDateTOFile();//往文件中写入裸数据

    copyWaveFile(AudioName,NewAudioName);//给裸数据加上头文件

    //            writeMP3();

    }

    }

    /**

    * 这里将数据写入文件,但是并不能播放,因为AudioRecord获得的音频是原始的裸音频,

    * 如果需要播放就必须加入一些格式或者编码的头信息。但是这样的好处就是你可以对音频的 裸数据进行处理,比如你要做一个爱说话的TOM

    * 猫在这里就进行音频的处理,然后重新封装 所以说这样得到的音频比较容易做一些音频的处理。

    */

    privatevoidwriteDateTOFile(){

    // new一个byte数组用来存一些字节数据,大小为缓冲区大小

    byte[]audiodata=newbyte[bufferSizeInBytes];

    FileOutputStreamfos=null;

    intreadsize=0;

    try{

    Filefile=newFile(AudioName);

    if(file.exists()){

    file.delete();

    }

    fos=newFileOutputStream(file);// 建立一个可存取字节的文件

    }catch(Exceptione){

    e.printStackTrace();

    }

    while(isRecord==true){

    readsize=audioRecord.read(audiodata,0,bufferSizeInBytes);

    if(AudioRecord.ERROR_INVALID_OPERATION!=readsize&&fos!=null){

    try{

    fos.write(audiodata);

    }catch(IOExceptione){

    e.printStackTrace();

    }

    }

    }

    try{

    if(fos!=null)

    fos.close();// 关闭写入流

    }catch(IOExceptione){

    e.printStackTrace();

    }

    }

    // 这里得到可播放的音频文件

    privatevoidcopyWaveFile(StringinFilename,StringoutFilename){

    FileInputStreamin=null;

    FileOutputStreamout=null;

    longtotalAudioLen=0;

    longtotalDataLen=totalAudioLen+36;

    longlongSampleRate=AudioFileFunc.AUDIO_SAMPLE_RATE;

    intchannels=2;

    longbyteRate=16*AudioFileFunc.AUDIO_SAMPLE_RATE*channels/8;

    byte[]data=newbyte[bufferSizeInBytes];

    try{

    in=newFileInputStream(inFilename);

    out=newFileOutputStream(outFilename);

    totalAudioLen=in.getChannel().size();

    totalDataLen=totalAudioLen+36;

    WriteWaveFileHeader(out,totalAudioLen,totalDataLen,

    longSampleRate,channels,byteRate);

    while(in.read(data)!=-1){

    out.write(data);

    }

    in.close();

    out.close();

    }catch(FileNotFoundExceptione){

    e.printStackTrace();

    }catch(IOExceptione){

    e.printStackTrace();

    }

    }

    /**

    * 这里提供一个头信息。插入这些信息就可以得到可以播放的文件。

    * 为我为啥插入这44个字节,这个还真没深入研究,不过你随便打开一个wav

    * 音频的文件,可以发现前面的头文件可以说基本一样哦。每种格式的文件都有

    * 自己特有的头文件。

    */

    privatevoidWriteWaveFileHeader(FileOutputStreamout,longtotalAudioLen,

    longtotalDataLen,longlongSampleRate,intchannels,longbyteRate)

    throwsIOException{

    byte[]header=newbyte[44];

    header[0]='R';// RIFF/WAVE header

    header[1]='I';

    header[2]='F';

    header[3]='F';

    header[4]=(byte)(totalDataLen&0xff);

    header[5]=(byte)((totalDataLen>>8)&0xff);

    header[6]=(byte)((totalDataLen>>16)&0xff);

    header[7]=(byte)((totalDataLen>>24)&0xff);

    header[8]='W';

    header[9]='A';

    header[10]='V';

    header[11]='E';

    header[12]='f';// 'fmt ' chunk

    header[13]='m';

    header[14]='t';

    header[15]=' ';

    header[16]=16;// 4 bytes: size of 'fmt ' chunk

    header[17]=0;

    header[18]=0;

    header[19]=0;

    header[20]=1;// format = 1

    header[21]=0;

    header[22]=(byte)channels;

    header[23]=0;

    header[24]=(byte)(longSampleRate&0xff);

    header[25]=(byte)((longSampleRate>>8)&0xff);

    header[26]=(byte)((longSampleRate>>16)&0xff);

    header[27]=(byte)((longSampleRate>>24)&0xff);

    header[28]=(byte)(byteRate&0xff);

    header[29]=(byte)((byteRate>>8)&0xff);

    header[30]=(byte)((byteRate>>16)&0xff);

    header[31]=(byte)((byteRate>>24)&0xff);

    header[32]=(byte)(2*16/8);// block align

    header[33]=0;

    header[34]=16;// bits per sample

    header[35]=0;

    header[36]='d';

    header[37]='a';

    header[38]='t';

    header[39]='a';

    header[40]=(byte)(totalAudioLen&0xff);

    header[41]=(byte)((totalAudioLen>>8)&0xff);

    header[42]=(byte)((totalAudioLen>>16)&0xff);

    header[43]=(byte)((totalAudioLen>>24)&0xff);

    out.write(header,0,44);

    }

    }

    ChatAudioRecord.java

    接下来就来处理体积大这个问题,首先我用到的是lame,就是去网上找到mp3lame.so库,然后修改它的mk文件,将其引入到项目中,其实也就是在录音的过程中将音频文件的编码改成mp3格式。于是就在github上找了相关的文章

    https://github.com/search?q=android+mp3+&type=Repositories&ref=searchresults

    https://github.com/yhirano/Mp3VoiceRecorderSampleForAndroid

    关于使用,只需要项目中的libmp3lame.so文件,和com.uraroji.garage.android.lame包下的SimpleLame.java文件和RecMicToMp3.java文件,注意SimpleLame.java必须放在com.uraroji.garage.android.lame包下。

    但是对于按照它的操作出现的问题就是

    这一下就尴尬了,然后在网上找了一些解决方式,后来报错就是找不到so库的错,接着我又将so库复制到其它的几个文件夹里面还是相同的问题,我然后就去修改那些.h和.c文件。希望在这里找到一些解药,对于一个多年没接触C语言的人来说,那个里面的调用着实让我看不懂。因此就放弃了这条路。

    接着就是VoAACEncorder,这个方式,我也记不得是在github上哪个项目弄下来的。首先是它的demo可以运行,并且音质也很不错,基本就是AAC的音频格式,并且这个格式的体积并不大,我录了120秒的音频文件大概就只有470kb左右的大小吧,当我看到这里的时候认定自己选择的就是这个,接下来就想方设法的研究出来然后插入到自己项目中。主要的就是jni中so库的试用,github里的项目是ec编写的,但是对于现在这个as称道的时代,还是一个一个复制吧。就两个so文件libAacEncoder.so和libVoAACEncoder.so。方法也就那几个,我也粘贴出util.

    首先出现的问题就和lame后面那个一样,找不到so库,

    这对于一个使用jni不熟练的人来说确实是个难题。其实这个问题的原因就是那个java文件中的native方法,native标识的方法就是调用C语言的地方,由于没有找到指定的位子。但是,对于标识指定位子的文件就是so库里面的mk文件里面标识的,这个对于我们来说是不方便编辑和更改的,但是我们可以更改外部编写有native方法文件的包名啊。按照mk文件里的包名进行重新创造。首先在我的一台测试机上运行成功,也能正常录音,但是当我换一台测试机的时候,又报了一个错,就是缺少64位的so库。这个问题就很尴尬了啊,提供的是armeabi里面的so啊,这个应该是32位和64位通用的啊,然后我发现我还有一些其它的文件夹,安卓在寻找so文件的时候是会优先寻找和自己匹配的文件夹下的so,没有找打就会报错。接着我就引入了armeabi-v7a包,在这个下面把armeabi里面的so文件拷贝过来,这个也就是处理兼容性问题的地方。然后就能顺利运行和录音了。但是还是存在一个缺点,对于即时通讯的项目是录音完成后马上发送的,这个录音的结构来说是边录边转码的,很有可能在你没转码成功的情况下就进行发送,这就导致服务器那边出现找不到文件的错误。我的处理方式是在录音完成后会停顿一秒,然后再进行发送,这样就大大降低了发送失败的次数。但偶尔还是会存在失败,接着我就在失败返回监听的方法里面再次将失败了的文件重新发送,如果还是失败,那么我就告诉用户失败了,在消息后面加一个红色边框里面是感叹号,让用户自己点击后重新发送,目前这样的处理方式是没有出现过失败的了。

    importandroid.text.format.Time;

    importandroid.util.Log;

    importcom.lvgou.distribution.utils.PathUtil;

    importjava.util.Date;

    importlwx.linin.aac.VoAAC;

    /**

    * Created by Administrator on 2017/6/14.

    */

    publicclassACCVoiceRecorder{

    privateintsampleRateInHz=16000;

    privateVoAACaac;

    privateStringfileName;

    staticfinalStringEXTENSION=".mp3";

    privateStringuid="";

    privatelongstartTime=-4;

    privatebooleanisRecording=false;//是否正在录音

    privateStringvoiceFilePath;

    publicACCVoiceRecorder(){

    }

    publicStringgetVoiceFilePath(){

    returnvoiceFilePath;

    }

    publicvoidstartRecording(StringuserId){

    fileName=getVoiceFileName(userId);

    voiceFilePath=PathUtil.getInstance().getVoicePath()+"/"+fileName;

    Log.e("aslkdfhakshfd","------------"+voiceFilePath);

    aac=newVoAAC(voiceFilePath);

    aac.sampleRateInHz(sampleRateInHz);

    aac.start();

    startTime=newDate().getTime();

    isRecording=true;

    }

    privateStringgetVoiceFileName(Stringuid){

    Timenow=newTime();

    now.setToNow();

    this.uid=uid;

    returnuid+now.toString().substring(0,15)+EXTENSION;

    }

    publicintstopRecoding(){

    intseconds=(int)(newDate().getTime()-startTime)/1000;

    aac.stop();

    isRecording=false;

    returnseconds;

    }

    publicvoiddiscardRecording(){

    stopRecoding();

    }

    publicbooleanisRecording(){

    returnisRecording;

    }

    publicStringgetVoiceFileName(){

    returnfileName;

    }

    }

    csdn项目地址:http://blog.csdn.net/greatdaocaoren/article/details/73433527

    相关文章

      网友评论

          本文标题:Android 录音MediaRecorder到AudioRec

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