实现语音数据实时采集 播放资料Word格式.docx

上传人:b****6 文档编号:20217360 上传时间:2023-01-20 格式:DOCX 页数:17 大小:20.47KB
下载 相关 举报
实现语音数据实时采集 播放资料Word格式.docx_第1页
第1页 / 共17页
实现语音数据实时采集 播放资料Word格式.docx_第2页
第2页 / 共17页
实现语音数据实时采集 播放资料Word格式.docx_第3页
第3页 / 共17页
实现语音数据实时采集 播放资料Word格式.docx_第4页
第4页 / 共17页
实现语音数据实时采集 播放资料Word格式.docx_第5页
第5页 / 共17页
点击查看更多>>
下载资源
资源描述

实现语音数据实时采集 播放资料Word格式.docx

《实现语音数据实时采集 播放资料Word格式.docx》由会员分享,可在线阅读,更多相关《实现语音数据实时采集 播放资料Word格式.docx(17页珍藏版)》请在冰豆网上搜索。

实现语音数据实时采集 播放资料Word格式.docx

/开始录制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;

/录音文件播放对象privateintfrequence=8000;

/定义音频编码(16位)privateintbufferSize=-1;

/播放缓冲大小2、初始化AudioTrack对象(初始化一次,该对象可重复使用)/获取缓冲大小bufferSize=AudioTrack.getMinBufferSize(frequence,channelInConfig,audioEncoding);

/实例AudioTracktrack=newAudioTrack(AudioManager.STREAM_MUSIC,frequence,channelInConfig,audioEncoding,bufferSize,AudioTrack.MODE_STREAM);

3、使用AudioTrack播放语音数据。

/将语音数据写入即可。

track.write(dataArray,buffer,len);

问题一:

由于目前的项目是实时采集,实时发送,所以需要考虑到包的大小,经测试,我们使用160个byte作为一个包传递可以做到比较良好的播放效果(也就是将一份buffer拆分成四个发送)。

处理代码如下:

/将数据通过监听接口回调出去if(audioRecordingCallback!

=null)intoffset=result%MAX_DATA_LENGTH0?

1:

0;

/将一个buffer拆分成几份小数据包MAX_DATA_LENGTH为包的最大byte数for(inti=0;

iresult)length=result-i*MAX_DATA_LENGTH;

/写到回调接口audioRecordingCallback.onRecording(buffer,i*MAX_DATA_LENGTH,length);

问题二:

有时候传输的过来播放声音会一卡一卡的,为了解决这样的问题,暂时使用了语音双缓冲机制来解决,问题优化很明显。

代码和示意图如下:

双缓冲示意图【有朋友说要源码,那我就贴下】【声音采集的源码】/*实时音频录制处理类*记得申明系统权限:

MODIFY_AUDIO_SETTINGS、RECORD_AUDIO*使用实例代码:

*audioRecoderHandler=newAudioRecoderHandler(this);

*audioRecoderHandler.startRecord(newAudioRecordingCallback()*&

#064;

Override*publicvoidonStopRecord(StringsavedPath)*&

Override*publicvoidonRecording(bytedata,intstartIndex,intlength)*/TODO录制监听。

处理data即可。

立即播放or发送出去,随你。

*);

*author李长军*/SuppressWarnings(deprecation)publicclassAudioRecoderHandlerprivateContextcontext=null;

/*录音数据单次回调数组最大为多少*/privatestaticintMAX_DATA_LENGTH=160;

privateAudioRecordaudioRecord;

/录音对象privatebooleanisRecording=false;

/标记是否正在录音中privateintfrequence=8000;

/定义采样通道(过时,但是使用其他的又不行privateintaudioEncoding=AudioFormat.ENCODING_PCM_16BIT;

/录制的缓冲数组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!

=null)cacheFile=context.getExternalFilesDir(android.os.Environment.DIRECTORY_MUSIC);

if(cacheFile=null)Toast.makeText(context,您的SD卡不可用,Toast.LENGTH_SHORT).show();

elsepath=cacheFile.getAbsolutePath()+/+commonSharedpreferenceHelper.getCurrentUserID()+/record;

/创建文件夹newFile(path).mkdirs();

returnpath;

/*录制音频的任务类*author李长军*/privateclassRecordTaskextendsAsyncTaskprivateAudioRecordingCallbackaudioRecordingCallback=null;

publicRecordTask(AudioRecordingCallbackaudioRecordingCallback)this.audioRecordingCallback=oRecordingCallback;

OverrideprotectedvoidonPreExecute()/根据定义好的几个配置,来获取合适的缓冲大小/intbufferSize=800;

/设置录制标记为trueOverrideprotectedvoidonPostExecute(Stringresult)audioRecord=null;

if(result=null)lastCacheFile=null;

elselastCacheFile=newFile(result);

if(audioRecordingCallback!

=null)audioRecordingCallback.onStopRecord(result);

OverrideprotectedStringdoInBackground(String.params)StringcacheDir=getOutputDir();

StringtempFileName=null;

/输出的文件流DataOutputStreamdataOutputStream=null;

/如果设置了要保存历史录音文件,则创建临时文件if(shouldSaveAudio&

cacheDir!

=null)tempFileName=cacheDir+/+System.currentTimeMillis();

cacheFile=newFile(pFileName);

trydataOutputStream=newDataOutputStream(newBufferedOutputStream(newFileOutputStream(cacheFile);

catch(FileNotFoundExceptione)e.printStackTrace();

/开始录制while(isRecording)/录制的内容放置到了buffer中,result代表存储长度intresult=audioRecord.read(buffer,0,buffer.length);

/如果设置需要保存录音文件if(shouldSaveAudio&

dataOutputStream!

=null)for(inti=0;

i0?

for(inti=0;

audioRecordingCallback.onRecording(buffer,i*MAX_DATA_LENGTH,length);

if(dataOutputStream!

=null)trydataOutputStream.close();

catch(IOExceptione)e.printStackTrace();

returntempFileName;

/*监听录制过程,用于实时获取录音数据*author李长军*/publicstaticinterfaceAudioRecordingCallback/*录音数据获取回调*paramdata*数据数组对象*paramstartIndex*数据其开始*paramlength*数据的结尾*/publicvoidonRecording(bytedata,intstartIndex,intlength);

/*录音结束后的回调*paramsavedPath*录音文件存储的路径*/publicvoidonStopRecord(StringsavedPath);

/*释放资源*/publicvoidrelease()if(audioRecord!

=null)audioRecord.release();

audioRecord=null;

【声音播放的源码】/*实时音频播放处理类*使用示例代码如下:

*audioPlayerHandler=newAudioPlayerHandler();

*audioPlayerHandler.prepare();

/播放前需要prepare。

可以重复prepare*/直接将需要播放的数据传入即可*audioPlayerHandler.onPlaying(data,0,data.length);

*author李长军*/SuppressWarnings(deprecation)publicclassAudioPlayerHandlerimplementsRunnableprivateAudioTracktrack=null;

/录音文件播放对象privatebooleanisPlaying=false;

/播放缓冲大小/使用双缓冲机制privateByteArrayOutputStreambufferStream0=newByteArrayOutputStream();

privateByteArrayOutputStreambufferStream1=newByteArrayOutputStream();

privateintcurrentBuffer=-1;

/记录当前哪个buffer填充完毕,并正在播放中。

-1表示都没有。

0表示第一个,1表示第二个/互斥信号量privateSemaphoresemaphore=newSemaphore

(1);

/是否释放资源的标志位privatebooleanrelease=false;

publicAudioPlayerHandler()/获取缓冲大小bufferSize=AudioTrack.getMinBufferSize(frequence,channelInConfig,audioEncoding);

try/默认需要抢占一个信号量。

防止播放进程执行semaphore.acquire();

catch(InterruptedExceptione)e.printStackTrace();

/开启播放线程newThread(this).start();

/*播放,当有新数据传入时,*paramdata*语音byte数组*paramstartIndex*开始的偏移量*paramlength*数据长度*/publicsynchronizedvoidonPlaying(bytedata,intstartIndex,intlength)if(AudioTrack.ERROR_BAD_VALUE=bufferSize)/初始化错误return;

switch(currentBuffer)case0:

bufferStream1.write(data,startIndex,length);

/如果缓冲区不够大,暂时不往下执行if(bufferStream1.size()bufferSize)if(bufferStream0.size()bufferSize)if(bufferStream1.size()=0)currentBuffer=0;

semaphore.release();

break;

default:

/*准备播放*/publicvoidprepare()if(track!

!

isPlaying)track.play();

isPlaying=true;

/*停止播放*/publicvoidstop()if(track!

=null)track.stop();

isPlaying=false;

/*释放资源*/publicvoidrelease()release=true;

if(track!

=null)track.release();

track=null;

trybufferStream0.close();

bufferStream0=null;

Overridepublicvoidrun()while(true)trysemaphore.acquire();

/如果资源释放了,则不再执行if(release)return;

if(currentBuffer=-1)continue;

/如果当前是第一个buff填充完毕if(currentBuffer=0)runPlay(bufferStream0);

/如果当前是第二个buff填充完毕elseif(currentBuffer=1)runPlay(bufferStream1);

/*执行播放语音*parambufferStream*/privatevoidrunPlay(ByteArrayOutputStreambufferStream)intdataSize=bufferStream.size();

bytedataArray=bufferStream.toByteArray();

intcount=dataSize/bufferSize;

/将数据按照buffer的大小可以切分的份数intoffset=dataSize%bufferSize=0?

0:

1;

/如果有余数,则还得循环一次for(inti=0;

idataSize)len=dataSize-i*bufferSize;

elselen=bufferSize;

track.write(dataArray,i*bufferSize,len);

bufferStream.reset();

/重置Stream

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 经管营销 > 经济市场

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1