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

在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); } }

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

实现的效果如下:

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

时间: 2024-09-10 23:17:18

android语音即时通讯之录音、播放功能实现代码的相关文章

详解android环境下的即时通讯_Android

首先了解一下即时通信的概念.通过消息通道 传输消息对象,一个账号发往另外一账号,只要账号在线,可以即时获取到消息,这就是最简单的即使通讯.消息通道可由TCP/IP UDP实现.通俗讲就是把一个人要发送给另外一个人的消息对象(文字,音视频,文件)通过消息通道(C/S实时通信)进行传输的服务.即时通讯应该包括四种形式,在线直传.在线代理.离线代理.离线扩展.在线直传指不经过服务器,直接实现点对点传输.在线代理指消息经过服务器,在服务器实现中转,最后到达目标账号.离线代理指消息经过服务器中转到达目标账

Android Easeui 3.0 即时通讯的问题汇总_Android

 0.关于注册账号就不用说了. 1.创建应用.获取appkey 0.创建应用 1.填写信息 2.获取appkey 2.集成 0.首先新建一个工程 1.这里主要介绍使用easeui来集成环信的即时通讯功能,需要下载sdk 2.把easeui当做依赖导入到工程当中,然后建立依赖关系 3在导入之后可能会出现的问题: 3.0 <uses-permission android:name="android.permission.ACCESS_MOCK_LACATTON> 这个权限报错,在咨询官方

Android Easeui 3.0 即时通讯的问题汇总

0.关于注册账号就不用说了. 1.创建应用.获取appkey 0.创建应用 1.填写信息 2.获取appkey 2.集成 0.首先新建一个工程 1.这里主要介绍使用easeui来集成环信的即时通讯功能,需要下载sdk 2.把easeui当做依赖导入到工程当中,然后建立依赖关系 3在导入之后可能会出现的问题: 3.0 <uses-permission android:name="android.permission.ACCESS_MOCK_LACATTON> 这个权限报错,在咨询官方技

Android BLE与终端通信(四)——实现服务器与客户端即时通讯功能

Android BLE与终端通信(四)--实现服务器与客户端即时通讯功能 前面几篇一直在讲一些基础,其实说实话,蓝牙主要为多的还是一些概念性的东西,当你把概念都熟悉了之后,你会很简单的就可以实现一些逻辑,主要是Socket和I/O流的操作,今天就来一起做一个聊天的小程序,我们都知道,我们实现蓝牙连接,蓝牙是有主从关系的,所以有客户端和服务端之分,我们新建一个工程--BLE_QQ(hh,毕竟是即时通讯嘛,和QQ挨个边) 参考Google的API:http://developer.android.c

Android后台保活实践总结:即时通讯应用无法根治的“顽疾”

前言 Android进程和Service的保活,是困扰Android开发人员的一大顽疾.因涉及到省电和内存管理策略,各厂商基于自家的理解,在自已ROOM发布于都对标准Android发行版作为或多或少的改动,使得应用层程序在处理进程和Service保活问题上变的异常复杂,且很难兼容,因为说不定哪款手机或者哪个版本的省电策略发生改变,那么随之而来的就是进程和Service保活的差异. 在应用场景上,由于即时通讯应用(包括IM聊天应用.消息推送服务等)为了保证消息的全时.实时送达能力,必须要实现进程或

即时通讯-安卓中文本,图片和语音与二进制相互转换的问题

问题描述 安卓中文本,图片和语音与二进制相互转换的问题 如题,最近要做一个即时通讯的APP,要求将文本,图片和语音转换成二进制发送,然后还要接受服务器传过来的二进制再转换成文本,图片或者语音,没做过,不知道该怎么做,求方法 解决方案 就是二进制流数据,这些类型都支持流数据的操作,仔细看看api 解决方案二: 建议采用第三方的SDK来做.http://www.easemob.com/

Android apps浅析02-Android IM:一个类似手机QQ的即时通讯开源实现

Android apps浅析02-Android IM:一个类似手机QQ的即时通讯开源实现 这是Android上的一个简单的IM应用程序运行时,应用程序发出HTTP请求到服务器,在PHP和MySQL,验证,注册和得到其他朋友的状态和数据来实现,那么它与其他设备的其他应用程序通过通信套接字接口.   1. 数据库只要2个表:朋友表和用户表: CREATE TABLE `friends` ( `Id` int(10) unsigned NOT NULL auto_increment, `provid

Android Socket接口实现即时通讯实例代码_Android

Android Socket接口实现即时通讯              最近学习Android 通信的知识,做一个小实例,巩固下学习内容,以下内容是网上找的资料,觉得很不错,知识比较全面,大家看下.  首先了解一下即时通信的概念.通过消息通道 传输消息对象,一个账号发往另外一账号,只要账号在线,可以即时获取到消息,这就是最简单的即使通讯.消息通道可由TCP/IP UDP实现.通俗讲就是把一个人要发送给另外一个人的消息对象(文字,音视频,文件)通过消息通道(C/S实时通信)进行传输的服务.即时通讯

Android Socket接口实现即时通讯实例代码

Android Socket接口实现即时通讯 最近学习Android 通信的知识,做一个小实例,巩固下学习内容,以下内容是网上找的资料,觉得很不错,知识比较全面,大家看下. 首先了解一下即时通信的概念.通过消息通道 传输消息对象,一个账号发往另外一账号,只要账号在线,可以即时获取到消息,这就是最简单的即使通讯.消息通道可由TCP/IP UDP实现.通俗讲就是把一个人要发送给另外一个人的消息对象(文字,音视频,文件)通过消息通道(C/S实时通信)进行传输的服务.即时通讯应该包括四种形式,在线直传.