当前位置: 移动技术网 > IT编程>移动开发>Android > android语音即时通讯之录音、播放功能实现代码

android语音即时通讯之录音、播放功能实现代码

2019年07月24日  | 移动技术网IT编程  | 我要评论

依依电影院,全城热恋20140601,谷开来图片

在android中,实现录音与语音播放的功能算是比较简单的,但是作为参考,还是很有必要将语音相关的知识做一个简要的记录。

首先,在android中,支持录音支持两种方式。主要包括:字节流模式和文件流模式。用文件流模式进行录音操作比较简单,而且相对来说,因为其封装性比较好,录制下的文件也会比较小。但是相对于文件流模式,就没有字节流模式那么灵活,但是想要用好字节流模式还是需要下一点功夫的。

下面开始介绍文件流模式的语音操作:

文件流模式

我们来看录音部分的实现,首先我们实现开始录音的部分:

在正式编码之前,还是需要对其进行一个简要的说明。一般来说,录音功能的实现是在jin层,而在这一层中,是用单线程实现的。如果我们在编码的对录音api进行多线程操作,会导致程序直接闪退,并且我们是无法在java层对其异常进行捕获的。所以,我们必须使用单线程以保证录音的正常运行。

一般来说,开始录音的步骤也就三个,代码如下:

releaserecord();//释放可能没释放的录音相关资源
if (!dostartrecord()) {//真正的开始录音的函数,开始录音成功返回true,否则返回false
  recordfail(); //开始失败,向用户提示开始录音失败
}

接下来我们来看看上述三个方法的实现:
实现是释放相关资源的方法releaserecord:

 if (mmediarecorder != null) {
      mmediarecorder.release();
      mmediarecorder = null;
}

其中的mmediarecorder 的mediarecorder的全局变量。
接下来是真正实现开始录音的实现逻辑dostartrecord()

 private boolean dostartrecord() {
    try {
      mmediarecorder = new mediarecorder();

      maudiofile = new file(environment.getexternalstoragedirectory().getabsolutepath() + "/voice/"
          + system.currenttimemillis() + ".m4a");
      maudiofile.getparentfile().mkdirs();
      maudiofile.createnewfile();

      //设置从麦克风采集声音
      mmediarecorder.setaudiosource(mediarecorder.audiosource.mic);

      //保存文件为mp4的格式
      mmediarecorder.setoutputformat(mediarecorder.outputformat.mpeg_4);

      //设置所有android系统都支持的采样频率
      mmediarecorder.setaudiosamplingrate(44100);

      //设置acc的编码方式
      mmediarecorder.setaudioencoder(mediarecorder.audioencoder.aac);

      //设置比较好的音质
      mmediarecorder.setaudioencodingbitrate(96000);

      mmediarecorder.setoutputfile(maudiofile.getabsolutepath());

      mmediarecorder.prepare();
      mmediarecorder.start();

      mstartrecordtime = system.currenttimemillis();

    } catch (ioexception | runtimeexception e) {
      e.printstacktrace();
      return false;
    }finally {
      if(maudiorecord != null){
        maudiorecord.release();
      }
    }

    return true;
  }

这一部分代码比较多,但是关键部分我都给出了注释,相信理解起来也不算难吧。这一部分我们实现的主要是在sdcrad根目录下新建一个voice的目录,然后在新建一个以==.m4a==为后缀名的文件。在配置maudiorecord的相关参数后,将收集到的录音存放到之前的文件中。如果一切都顺利的话,就返回true ,表示开始录音成功。

最后就是提示用户录音实现的逻辑recordfail

maudiofile = null;
    mhandler.postdelayed(new runnable() {
      @override
      public void run() {
        toast.maketext(vioceactivity.this, "录音失败", toast.length_short).show();
      }
    }, 100);

这里的逻辑比较简单,但是值得注意的是,因为我们开始录音方法是在一个非主线程的线程中执行的,所以我们需要借助hander来实现界面提示的效果。这里的mhander是一个局部变量,其初始化放在oncreate()方法中。

mhandler = new handler(looper.getmainlooper());

综上,开始录音的所有逻辑已经全部实现。接下来实现的是结束录音的实现逻辑:
主题的逻辑如下:

if (!dostoprecord()) {//实现 停止录音的真正逻辑,成功返回true,否则返回false
          recordfail();//提示用户录音失败
        }

这里的dostoprecord实现逻辑如下:

 mmediarecorder.stop();
      mendrecordtime = system.currenttimemillis();

      final int seond = (int) ((mendrecordtime - mstartrecordtime) / 1000);

      if (seond < 3) {
        recordfail();
        return false;
      } else {
        mhandler.post(new runnable() {
          @override
          public void run() {
            mtext.settext("录音" + seond + "成功!");
          }
        });
      }
    } catch (runtimeexception e) {
      e.printstacktrace();
      return false;
    }
    return true;

其实我们实现停止录音的逻辑也很简单,首先调用mmediarecorder.stop();停止录音,然后对录音时间是否大于3s进行判断,若大于3s,则表示录音有效,提示用户,录音成功。

综上,我们文件流的录音的所有代码已经实现完毕。接下来我们实现对其进行播放。如果需要参考全部的代码,请戳这里。

private void doplay(file maudiofile) {
    //配置播放器 mediaplayer
    mmediaplayer = new mediaplayer();

    try{

      //设置声音文件
      mmediaplayer.setdatasource(maudiofile.getabsolutepath());

      //设置监听回调
      mmediaplayer.setoncompletionlistener(new mediaplayer.oncompletionlistener() {
        @override
        public void oncompletion(mediaplayer mp) {
          stopplay();
        }
      });

      //设置出错的监听器
      mmediaplayer.setonerrorlistener(new mediaplayer.onerrorlistener() {
        @override
        public boolean onerror(mediaplayer mp, int what, int extra) {
          playfail();
          //提示用户
          stopplay();
          //释放播放器
          return true;
        }
      });

      //配置音量,是否循环
      mmediaplayer.setvolume(1,1);
      mmediaplayer.setlooping(false);

      mmediaplayer.prepare();
      mmediaplayer.start();
    }catch (exception e){
      e.printstacktrace();
      playfail();
      stopplay();
    }
  }

整体来说,基于文件的录音是比较容易实现的。下面介绍如何通过字节流模式实现录音。

字节流模式录音

开始录音:主要逻辑startrecord2()的实现

private boolean startrecord2() {
    try {
      maudiofile2 = new file(environment.getexternalstoragedirectory().getabsolutepath() + "/voice/"
          + system.currenttimemillis() + ".pcm");
      maudiofile2.getparentfile().mkdirs();
      maudiofile2.createnewfile();

      mfileoutputstream = new fileoutputstream(maudiofile2);
      //配置audiorecord

      //从麦克风采集数据
      int audiosource = mediarecorder.audiosource.mic;

      //采集频率
      int samplerate = 44100;

      //单声道输入
      int channelconfig = audioformat.channel_in_mono;

      //设置pcm(脉冲编码调制 pulse code modulation)编码格式
      int audioformat = audioformat.encoding_pcm_16bit;

      //计算audiorecord 内存buffer最小的大小
      int minbuffersize = audiorecord.getminbuffersize(samplerate,channelconfig,audioformat);
      //创建audiorecord对象
      maudiorecord = new audiorecord(audiosource,samplerate,channelconfig,audioformat,math.max(buffer_size,minbuffersize));

      maudiorecord.startrecording();
      mstartrecordtime = system.currenttimemillis();

      //循环读取数据,写到输出流中
      while(misrecord){
        int read = maudiorecord.read(mbuffer,0,buffer_size);
        if(read >0 ){
          //读取文件写到文件中
          mfileoutputstream.write(mbuffer,0,read);
        }else{
          return false;
        }
      }

    } catch (ioexception | runtimeexception e) {
      e.printstacktrace();
      return false;
    }

    //停止录音
    return true;
  }

停止录音的dostoprecord()实现:

private boolean dostoprecord() {
    try {

      mmediarecorder.stop();
      mendrecordtime = system.currenttimemillis();

      final int seond = (int) ((mendrecordtime - mstartrecordtime) / 1000);

      if (seond < 3) {
        recordfail();
        return false;
      } else {
        mhandler.post(new runnable() {
          @override
          public void run() {
            mtext.settext("录音" + seond + "成功!");
          }
        });
      }
    } catch (runtimeexception e) {
      e.printstacktrace();
      return false;
    }
    return true;
  }

对其中相关参数的说名:

 private boolean misrecord = false;
  private final int buffer_size = 2048;//缓存区的大小
  private byte[] mbuffer;
  private fileoutputstream mfileoutputstream;
  private audiorecord maudiorecord;
  private file maudiofile2;

接下来,实现的是对其字节流模式录制的文件进行播放:doplay2()主题类的实现:

private void doplay2(file maudiofile) {

    //声音类型,扬声器播放
    int steamtype = audiomanager.stream_music;

    //采样频率
    int samplerate = 44100;

    //mono 表示单声道 录音输入单声道 播放也使用单声道
    int channelconfig = audioformat.channel_out_mono;

    //录音使用16bit 所以播放也使用同样的格式
    int audioformat = audioformat.encoding_pcm_16bit;

    //流模式
    int mode = audiotrack.mode_stream;

    //计算需要最小buffer的大小
    int minbuffersize =audiotrack.getminbuffersize(samplerate,channelconfig,audioformat);

    audiotrack audiotrack = new audiotrack(steamtype,samplerate,channelconfig,audioformat,
        math.max(minbuffersize,buffer_size),mode);

    //从文件流中读取数据
    fileinputstream inputstream = null;

    try{
      inputstream = new fileinputstream(maudiofile2);
      int read;
      //循环读取数据,写到播放器去播放
      audiotrack.play();
      while((read = inputstream.read(mbuffer)) > 0){
        int ret = audiotrack.write(mbuffer,0,read);
      switch (ret){
        case audiotrack.error:
        case audiotrack.error_bad_value:
        case audiotrack.error_invalid_operation:
        case audiotrack.error_dead_object:
            playfail();
            return ;
        default:
          break;
      }
      }

    }catch (exception e){
      e.printstacktrace();
    }finally {
      misplaying = false;

      if(inputstream != null)
        closequietly(inputstream);
      resetquietly(audiotrack);
    }

  }

千言万语肯定不如直接代码来的直接了当,所以的代码实现点这里

实现的效果如下:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网