实现语音数据实时采集 播放Word文件下载.docx
《实现语音数据实时采集 播放Word文件下载.docx》由会员分享,可在线阅读,更多相关《实现语音数据实时采集 播放Word文件下载.docx(17页珍藏版)》请在冰豆网上搜索。
channelInConfig,audioEncoding);
//实例化AudioRecord
audioRecord=newAudioRecord(MediaRecorder.AudioSource.MIC,
frequence,channelInConfig,audioEncoding,bufferSize);
//定义缓冲数组
buffer=newbyte[bufferSize];
3、准备开始录制,使用循环不断读取数据。
audioRecord.startRecording();
//开始录制
isRecording=true;
//设置录制标记为true
while(isRecording){
//录制的内容放置到了buffer中,result代表存储长度
intresult=audioRecord.read(buffer,0,buffer.length);
/*.....result为buffer中录制数据的长度(貌似基本上都是640)。
剩下就是处理buffer了,是发送出去还是直接播放,这个随便你。
*/
}
//录制循环结束后,记得关闭录制!
!
if(audioRecord!
=null){
audioRecord.stop();
二、AudioTrack代码实现介绍如下:
1、声明播放相关配置。
privateAudioTracktrack=null;
//录音文件播放对象
privateintbufferSize=-1;
//播放缓冲大小
2、初始化AudioTrack对象(初始化一次,该对象可重复使用)
//获取缓冲大小
bufferSize=AudioTrack.getMinBufferSize(frequence,channelInConfig,
audioEncoding);
//实例AudioTrack
track=newAudioTrack(AudioManager.STREAM_MUSIC,frequence,
channelInConfig,audioEncoding,bufferSize,
AudioTrack.MODE_STREAM);
3、使用AudioTrack播放语音数据。
//将语音数据写入即可。
track.write(dataArray,buffer,len);
问题一:
由于目前的项目是实时采集,实时发送,所以需要考虑到包的大小,经测试,我们使用160个byte作为一个包传递可以做到比较良好的播放效果(也就是将一份buffer拆分成四个发送)。
处理代码如下:
//将数据通过监听接口回调出去
if(audioRecordingCallback!
intoffset=result%MAX_DATA_LENGTH>
0?
1:
0;
//将一个buffer拆分成几份小数据包MAX_DATA_LENGTH为包的最大byte数
for(inti=0;
i<
result/MAX_DATA_LENGTH+offset;
i++){
intlength=MAX_DATA_LENGTH;
if((i+1)*MAX_DATA_LENGTH>
result){
length=result-i*MAX_DATA_LENGTH;
}
//写到回调接口
audioRecordingCallback.onRecording(buffer,i
*MAX_DATA_LENGTH,length);
问题二:
有时候传输的过来播放声音会一卡一卡的,为了解决这样的问题,暂时使用了语音双缓冲机制来解决,问题优化很明显。
代码和示意图如下:
双缓冲示意图
【有朋友说要源码,那我就贴下】
【声音采集的源码】
/**
*实时音频录制处理类<
br/>
*记得申明系统权限:
MODIFY_AUDIO_SETTINGS、RECORD_AUDIO<
*使用实例代码:
*
*<
pre>
*audioRecoderHandler=newAudioRecoderHandler(this);
*audioRecoderHandler.startRecord(newAudioRecordingCallback(){
*&
#064;
Override
*publicvoidonStopRecord(StringsavedPath){
*}
*publicvoidonRecording(byte[]data,intstartIndex,intlength){
*//TODO录制监听。
处理data即可。
立即播放or发送出去,随你。
*});
/pre>
*@author李长军
*/
@SuppressWarnings("
deprecation"
)
publicclassAudioRecoderHandler{
privateContextcontext=null;
/**
*录音数据单次回调数组最大为多少
privatestaticintMAX_DATA_LENGTH=160;
privateAudioRecordaudioRecord;
privatebooleanisRecording=false;
//标记是否正在录音中
privateintfrequence=8000;
privateintchannelInConfig=AudioFormat.CHANNEL_CONFIGURATION_MONO;
//定义采样通道(过时,但是使用其他的又不行
privateintaudioEncoding=AudioFormat.ENCODING_PCM_16BIT;
privatebyte[]buffer=null;
privateFilelastCacheFile=null;
//记录上次录制的文件名
privateCommonSharedpreferenceHelpercommonSharedpreferenceHelper;
privatebooleanshouldSaveAudio=false;
//标记是否保存录音历史记录
publicAudioRecoderHandler(Contextcontext){
if(context==null){
thrownewRuntimeException("
Contextcouldnotbenull!
"
);
this.context=context;
commonSharedpreferenceHelper=CommonSharedpreferenceHelper
.getInstance(context);
*设置处理对象是否保存录音历史记录(如果设置为false表示不保存)
*@paramshouldSaveAudio
*true表示保存(默认),false不保存,onStopRecord回调将会返回null
publicvoidsetShouldSaveAudio(booleanshouldSaveAudio){
this.shouldSaveAudio=shouldSaveAudio;
*开始录制音频
*@paramcallBackListener
*录制过程中的回调函数
publicvoidstartRecord(AudioRecordingCallbackaudioRecordingCallback){
RecordTasktask=newRecordTask(audioRecordingCallback);
task.execute();
//开始执行
*停止录制
publicvoidstoppRecord(){
isRecording=false;
*删除上次录制的文件(一般是用户取消发送导致删除上次录制的内容)
*@returntrue表示删除成功,false表示删除失败,一般是没有上次录制的文件,或者文件已经被删除了
publicbooleandeleteLastRecordFile(){
booleansuccess=false;
if(lastCacheFile!
=null&
&
lastCacheFile.exists()){
success=lastCacheFile.delete();
returnsuccess;
*获取音频文件的缓存地址(获取的地址都是可以直接存储的,也就是文件夹已建立好),需要注意的是,缓存地址和用户的ID有关
*@return音频文件的缓存地址路径,如果获取失败,返回null
privateStringgetOutputDir(){
Stringpath=null;
FilecacheFile=null;
if(context!
cacheFile=context
.getExternalFilesDir(android.os.Environment.DIRECTORY_MUSIC);
if(cacheFile==null){
Toast.makeText(context,"
您的SD卡不可用"
Toast.LENGTH_SHORT).show();
}else{
path=cacheFile.getAbsolutePath()+"
/"
+commonSharedpreferenceHelper.getCurrentUserID()
+"
/record"
;
//创建文件夹
newFile(path).mkdirs();
returnpath;
*录制音频的任务类
privateclassRecordTaskextendsAsyncTask<
String,Integer,String>
{
privateAudioRecordingCallbackaudioRecordingCallback=null;
publicRecordTask(AudioRecordingCallbackaudioRecordingCallback){
this.audioRecordingCallback=oRecordingCallback;
@Override
protectedvoidonPreExecute(){
//根据定义好的几个配置,来获取合适的缓冲大小
//intbufferSize=800;
intbufferSize=AudioRecord.getMinBufferSize(frequence,
//实例化AudioRecord
audioRecord=newAudioRecord(MediaRecorder.AudioSource.MIC,
//定义缓冲数组
buffer=newbyte[bufferSize];
audioRecord.startRecording();
isRecording=true;
protectedvoidonPostExecute(Stringresult){
audioRecord=null;
if(result==null){
lastCacheFile=null;
lastCacheFile=newFile(result);
if(audioRecordingCallback!
audioRecordingCallback.onStopRecord(result);
protectedStringdoInBackground(String...params){
StringcacheDir=getOutputDir();
StringtempFileName=null;
//输出的文件流
DataOutputStreamdataOutputStream=null;
//如果设置了要保存历史录音文件,则创建临时文件
if(shouldSaveAudio&
cacheDir!
tempFileName=cacheDir+"
+System.currentTimeMillis();
cacheFile=newFile(pFileName);
try{
dataOutputStream=newDataOutputStream(
newBufferedOutputStream(newFileOutputStream(
cacheFile)));
}catch(FileNotFoundExceptione){
e.printStackTrace();
//开始录制
while(isRecording){
//录制的内容放置到了buffer中,result代表存储长度
intresult=audioRecord.read(buffer,0,buffer.length);
//如果设置需要保存录音文件
dataOutputStream!
result;
//将录制到的内容放置到文件中
dataOutputStream.write(buffer[i]);
}catch(IOExceptione){
//将数据回调出去
if(audioRecord!
if(dataOutputStream!
dataOutputStream.close();
returntempFileName;
*监听录制过程,用于实时获取录音数据
publicstaticinterfaceAudioRecordingCallback{
*录音数据获取回调
*@paramdata
*数据数组对象
*@paramstartIndex
*数据其开始
*@paramlength
*数据的结尾
publicvoidonRecording(byte[]data,intstartIndex,intlength);
*录音结束后的回调
*@paramsavedPath
*录音文件存储的路径
publicvoidonStopRecord(StringsavedPath);
*释放资源
publicvoidrelease(){
audioRecord.release();
【声音播放的源码】
*实时音频播放处理类<
*使用示例代码如下:
*audioPlayerHandler=newAudioPlayerHandler();
*audioPlayerHandler.prepare();
//播放前需要prepare。
可以重复prepare
*//直接将需要播放的数据传入即可
*audioPlayerHandler.onPlaying(data,0,data.length);
publicclassAudioPlayerHandlerimplementsRunnable{
privateAudioTracktrack=null;
privatebooleanisPlaying=false;
privateintbufferSize=-1;
//使用双缓冲机制
privateByteArrayOutputStreambufferStream0=newByteArrayOutputStream();
privateByteArrayOutputStreambufferStream1=newByteArrayOutputStream();
privateintcurrentBuffer=-1;
//记录当前哪个buffer填充完毕,并正在播放中。
-1表示都没有。
0表示第一个,1表示第二个
//互斥信号量
privateSemaphoresemaphore=newSemaphore
(1);
//是否释放资源的标志位
privatebooleanrelease=false;
publicAudioPlayerHandler(){
//获取缓冲大小
bufferSize=AudioTrack.getMinBufferSize(frequence,channelInCo