`
kerlubasola
  • 浏览: 675803 次
文章分类
社区版块
存档分类
最新评论

android 录音 Android 使用AudioRecord录音相关和音频文件的封装

 
阅读更多

直接给上个详细的使用Android MediaRecorder进行手机录音解说代码:

package cn.com.chenzheng_java.media;

import java.io.IOException;

import android.app.Activity;
import android.media.MediaRecorder;
import android.os.Bundle;

public class MediaRecordActivity extends Activity {
	MediaRecorder mediaRecorder ;
	@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        mediaRecorder = new MediaRecorder();
        record();
    }
    
	/**
	 * 开始录制
	 */
    private void record(){
    	/**
    	 * mediaRecorder.setAudioSource设置声音来源。
    	 * MediaRecorder.AudioSource这个内部类详细的介绍了声音来源。
    	 * 该类中有许多音频来源,不过最主要使用的还是手机上的麦克风,MediaRecorder.AudioSource.MIC
    	 */
    	mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    	/**
    	 * mediaRecorder.setOutputFormat代表输出文件的格式。该语句必须在setAudioSource之后,在prepare之前。
    	 * OutputFormat内部类,定义了音频输出的格式,主要包含MPEG_4、THREE_GPP、RAW_AMR……等。
    	 */
    	mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
    	/**
    	 * mediaRecorder.setAddioEncoder()方法可以设置音频的编码
    	 * AudioEncoder内部类详细定义了两种编码:AudioEncoder.DEFAULT、AudioEncoder.AMR_NB
    	 */
    	mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
    	/**
    	 * 设置录音之后,保存音频文件的位置
    	 */
    	mediaRecorder.setOutputFile("file:///sdcard/myvido/a.3pg");
    	
    	/**
    	 * 调用start开始录音之前,一定要调用prepare方法。
    	 */
    	try {
			mediaRecorder.prepare();
			mediaRecorder.start();
		}
        catch (IllegalStateException e) {
			e.printStackTrace();
		}
        catch (IOException e) {
			e.printStackTrace();
		}
    }
    
    /***
     * 此外,还有和MediaRecorder有关的几个参数与方法,我们一起来看一下:
     * sampleRateInHz :音频的采样频率,每秒钟能够采样的次数,采样率越高,音质越高。
     * 给出的实例是44100、22050、11025但不限于这几个参数。例如要采集低质量的音频就可以使用4000、8000等低采样率
     * 
     * channelConfig :声道设置:android支持双声道立体声和单声道。MONO单声道,STEREO立体声
     * 
     * recorder.stop();停止录音
     * recorder.reset();  重置录音 ,会重置到setAudioSource这一步
     * recorder.release(); 解除对录音资源的占用
     */
}




微笑android中AudioRecord采集音频的参数说明

android中采集音频的apiandroid.media.AudioRecord

其中构造器的几个参数就是标准的声音采集参数

以下是参数的含义解释

public AudioRecord (int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)

Since:API Level 3

Class constructor.

Parameters

audioSource

sampleRateInHz

channelConfig

audioFormat

bufferSizeInBytes

the recording source. SeeMediaRecorder.AudioSourcefor recording source definitions.

音频源:指的是从哪里采集音频。这里我们当然是从麦克风采集音频,所以此参数的值为MIC

the sample rate expressed in Hertz. Examples of rates are (but not limited to) 44100, 22050 and 11025.

采样率:音频的采样频率,每秒钟能够采样的次数,采样率越高,音质越高。给出的实例是441002205011025但不限于这几个参数。例如要采集低质量的音频就可以使用40008000等低采样率。

describes the configuration of the audio channels. SeeCHANNEL_IN_MONOandCHANNEL_IN_STEREO

声道设置:android支持双声道立体声和单声道。MONO单声道,STEREO立体声

the format in which the audio data is represented. SeeENCODING_PCM_16BITandENCODING_PCM_8BIT

编码制式和采样大小:采集来的数据当然使用PCM编码(脉冲代码调制编码,即PCM编码。PCM通过抽样、量化、编码三个步骤将连续变化的模拟信号转换为数字编码。) android支持的采样大小16bit或者8bit。当然采样大小越大,那么信息量越多,音质也越高,现在主流的采样大小都是16bit,在低质量的语音传输的时候8bit足够了。

the total size (in bytes) of the buffer where audio data is written to during the recording. New audio data can be read from this buffer in smaller chunks than this size. SeegetMinBufferSize(int, int, int)to determine the minimum required buffer size for the successful creation of an AudioRecord instance. Using values smaller than getMinBufferSize() will result in an initialization failure.

采集数据需要的缓冲区的大小,如果不知道最小需要的大小可以在getMinBufferSize()查看。

采集到的数据保存在一个byteBuffer中,可以使用流将其读出。亦可保存成为文件的形式


Android 使用AudioRecord录音相关和音频文件的封装

分类:Android流媒体学习

在Android中录音可以用MediaRecord录音,操作比较简单。但是不够专业,就是不能对音频进行处理。如果要进行音频的实时的处理或者音频的一些封装

就可以用AudioRecord来进行录音了。

这里给出一段代码。实现了AudioRecord的录音和WAV格式音频的封装。

用AudioTrack和AudioTrack类可以进行边录边播,可以参考:http://blog.sina.com.cn/s/blog_6309e1ed0100j1rw.html

我们这里的代码没有播放。但是有封装和详解,如下:

  1. packagecom.ppmeet;
  2. importjava.io.File;
  3. importjava.io.FileInputStream;
  4. importjava.io.FileNotFoundException;
  5. importjava.io.FileOutputStream;
  6. importjava.io.IOException;
  7. importandroid.app.Activity;
  8. importandroid.graphics.PixelFormat;
  9. importandroid.media.AudioFormat;
  10. importandroid.media.AudioRecord;
  11. importandroid.media.MediaRecorder;
  12. importandroid.os.Bundle;
  13. importandroid.view.View;
  14. importandroid.view.View.OnClickListener;
  15. importandroid.view.Window;
  16. importandroid.view.WindowManager;
  17. importandroid.widget.Button;
  18. /**
  19. *classname:TestAudioRecord<BR>
  20. *classdescription:用AudioRecord来进行录音<BR>
  21. *PS:<BR>
  22. *
  23. *@version1.002011/09/21
  24. *@authorCODYY)peijiangping
  25. */
  26. publicclassTestAudioRecordextendsActivity{
  27. //音频获取源
  28. privateintaudioSource=MediaRecorder.AudioSource.MIC;
  29. //设置音频采样率,44100是目前的标准,但是某些设备仍然支持22050,16000,11025
  30. privatestaticintsampleRateInHz=44100;
  31. //设置音频的录制的声道CHANNEL_IN_STEREO为双声道,CHANNEL_CONFIGURATION_MONO为单声道
  32. privatestaticintchannelConfig=AudioFormat.CHANNEL_IN_STEREO;
  33. //音频数据格式:PCM16位每个样本。保证设备支持。PCM8位每个样本。不一定能得到设备支持。
  34. privatestaticintaudioFormat=AudioFormat.ENCODING_PCM_16BIT;
  35. //缓冲区字节大小
  36. privateintbufferSizeInBytes=0;
  37. privateButtonStart;
  38. privateButtonStop;
  39. privateAudioRecordaudioRecord;
  40. privatebooleanisRecord=false;//设置正在录制的状态
  41. //AudioName裸音频数据文件
  42. privatestaticfinalStringAudioName="/sdcard/love.raw";
  43. //NewAudioName可播放的音频文件
  44. privatestaticfinalStringNewAudioName="/sdcard/new.wav";
  45. publicvoidonCreate(BundlesavedInstanceState){
  46. super.onCreate(savedInstanceState);
  47. getWindow().setFormat(PixelFormat.TRANSLUCENT);//让界面横屏
  48. requestWindowFeature(Window.FEATURE_NO_TITLE);//去掉界面标题
  49. getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
  50. WindowManager.LayoutParams.FLAG_FULLSCREEN);
  51. //重新设置界面大小
  52. setContentView(R.layout.main);
  53. init();
  54. }
  55. privatevoidinit(){
  56. Start=(Button)this.findViewById(R.id.start);
  57. Stop=(Button)this.findViewById(R.id.stop);
  58. Start.setOnClickListener(newTestAudioListener());
  59. Stop.setOnClickListener(newTestAudioListener());
  60. creatAudioRecord();
  61. }
  62. privatevoidcreatAudioRecord(){
  63. //获得缓冲区字节大小
  64. bufferSizeInBytes=AudioRecord.getMinBufferSize(sampleRateInHz,
  65. channelConfig,audioFormat);
  66. //创建AudioRecord对象
  67. audioRecord=newAudioRecord(audioSource,sampleRateInHz,
  68. channelConfig,audioFormat,bufferSizeInBytes);
  69. }
  70. classTestAudioListenerimplementsOnClickListener{
  71. @Override
  72. publicvoidonClick(Viewv){
  73. if(v==Start){
  74. startRecord();
  75. }
  76. if(v==Stop){
  77. stopRecord();
  78. }
  79. }
  80. }
  81. privatevoidstartRecord(){
  82. audioRecord.startRecording();
  83. //让录制状态为true
  84. isRecord=true;
  85. //开启音频文件写入线程
  86. newThread(newAudioRecordThread()).start();
  87. }
  88. privatevoidstopRecord(){
  89. close();
  90. }
  91. privatevoidclose(){
  92. if(audioRecord!=null){
  93. System.out.println("stopRecord");
  94. isRecord=false;//停止文件写入
  95. audioRecord.stop();
  96. audioRecord.release();//释放资源
  97. audioRecord=null;
  98. }
  99. }
  100. classAudioRecordThreadimplementsRunnable{
  101. @Override
  102. publicvoidrun(){
  103. writeDateTOFile();//往文件中写入裸数据
  104. copyWaveFile(AudioName,NewAudioName);//给裸数据加上头文件
  105. }
  106. }
  107. /**
  108. *这里将数据写入文件,但是并不能播放,因为AudioRecord获得的音频是原始的裸音频,
  109. *如果需要播放就必须加入一些格式或者编码的头信息。但是这样的好处就是你可以对音频的裸数据进行处理,比如你要做一个爱说话的TOM
  110. *猫在这里就进行音频的处理,然后重新封装所以说这样得到的音频比较容易做一些音频的处理。
  111. */
  112. privatevoidwriteDateTOFile(){
  113. //new一个byte数组用来存一些字节数据,大小为缓冲区大小
  114. byte[]audiodata=newbyte[bufferSizeInBytes];
  115. FileOutputStreamfos=null;
  116. intreadsize=0;
  117. try{
  118. Filefile=newFile(AudioName);
  119. if(file.exists()){
  120. file.delete();
  121. }
  122. fos=newFileOutputStream(file);//建立一个可存取字节的文件
  123. }catch(Exceptione){
  124. e.printStackTrace();
  125. }
  126. while(isRecord==true){
  127. readsize=audioRecord.read(audiodata,0,bufferSizeInBytes);
  128. if(AudioRecord.ERROR_INVALID_OPERATION!=readsize){
  129. try{
  130. fos.write(audiodata);
  131. }catch(IOExceptione){
  132. e.printStackTrace();
  133. }
  134. }
  135. }
  136. try{
  137. fos.close();//关闭写入流
  138. }catch(IOExceptione){
  139. e.printStackTrace();
  140. }
  141. }
  142. //这里得到可播放的音频文件
  143. privatevoidcopyWaveFile(StringinFilename,StringoutFilename){
  144. FileInputStreamin=null;
  145. FileOutputStreamout=null;
  146. longtotalAudioLen=0;
  147. longtotalDataLen=totalAudioLen+36;
  148. longlongSampleRate=sampleRateInHz;
  149. intchannels=2;
  150. longbyteRate=16*sampleRateInHz*channels/8;
  151. byte[]data=newbyte[bufferSizeInBytes];
  152. try{
  153. in=newFileInputStream(inFilename);
  154. out=newFileOutputStream(outFilename);
  155. totalAudioLen=in.getChannel().size();
  156. totalDataLen=totalAudioLen+36;
  157. WriteWaveFileHeader(out,totalAudioLen,totalDataLen,
  158. longSampleRate,channels,byteRate);
  159. while(in.read(data)!=-1){
  160. out.write(data);
  161. }
  162. in.close();
  163. out.close();
  164. }catch(FileNotFoundExceptione){
  165. e.printStackTrace();
  166. }catch(IOExceptione){
  167. e.printStackTrace();
  168. }
  169. }
  170. /**
  171. *这里提供一个头信息。插入这些信息就可以得到可以播放的文件。
  172. *为我为啥插入这44个字节,这个还真没深入研究,不过你随便打开一个wav
  173. *音频的文件,可以发现前面的头文件可以说基本一样哦。每种格式的文件都有
  174. *自己特有的头文件。
  175. */
  176. privatevoidWriteWaveFileHeader(FileOutputStreamout,longtotalAudioLen,
  177. longtotalDataLen,longlongSampleRate,intchannels,longbyteRate)
  178. throwsIOException{
  179. byte[]header=newbyte[44];
  180. header[0]='R';//RIFF/WAVEheader
  181. header[1]='I';
  182. header[2]='F';
  183. header[3]='F';
  184. header[4]=(byte)(totalDataLen&0xff);
  185. header[5]=(byte)((totalDataLen>>8)&0xff);
  186. header[6]=(byte)((totalDataLen>>16)&0xff);
  187. header[7]=(byte)((totalDataLen>>24)&0xff);
  188. header[8]='W';
  189. header[9]='A';
  190. header[10]='V';
  191. header[11]='E';
  192. header[12]='f';//'fmt'chunk
  193. header[13]='m';
  194. header[14]='t';
  195. header[15]='';
  196. header[16]=16;//4bytes:sizeof'fmt'chunk
  197. header[17]=0;
  198. header[18]=0;
  199. header[19]=0;
  200. header[20]=1;//format=1
  201. header[21]=0;
  202. header[22]=(byte)channels;
  203. header[23]=0;
  204. header[24]=(byte)(longSampleRate&0xff);
  205. header[25]=(byte)((longSampleRate>>8)&0xff);
  206. header[26]=(byte)((longSampleRate>>16)&0xff);
  207. header[27]=(byte)((longSampleRate>>24)&0xff);
  208. header[28]=(byte)(byteRate&0xff);
  209. header[29]=(byte)((byteRate>>8)&0xff);
  210. header[30]=(byte)((byteRate>>16)&0xff);
  211. header[31]=(byte)((byteRate>>24)&0xff);
  212. header[32]=(byte)(2*16/8);//blockalign
  213. header[33]=0;
  214. header[34]=16;//bitspersample
  215. header[35]=0;
  216. header[36]='d';
  217. header[37]='a';
  218. header[38]='t';
  219. header[39]='a';
  220. header[40]=(byte)(totalAudioLen&0xff);
  221. header[41]=(byte)((totalAudioLen>>8)&0xff);
  222. header[42]=(byte)((totalAudioLen>>16)&0xff);
  223. header[43]=(byte)((totalAudioLen>>24)&0xff);
  224. out.write(header,0,44);
  225. }
  226. @Override
  227. protectedvoidonDestroy(){
  228. close();
  229. super.onDestroy();
  230. }
  231. }

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Android入门(9)AudioRecord和AudioTrack类的使用

(2010-05-07 09:07:05

<wbr><wbr><wbr>AudioRecord和AudioTrack类是Android获取和播放音频流的重要类,放置在android.media包中。与该包中的MediaRecorder和MediaPlayer类不同,AudioRecord和AudioTrack类在获取和播放音频数据流时无需通过文件保存和文件读取,可以动态地直接获取和播放音频流,在实时处理音频数据流时非常有用。</wbr></wbr></wbr>

<wbr><wbr><wbr>当然,如果用户只想录音后写入文件或从文件中取得音频流进行播放,那么直接使用MediaRecorder和MediaPlayer类是首选方案,因为这两个类使用非常方便,而且成功率很高。而AudioRecord和AudioTrack类的使用却比较复杂,我们发现很多人都不能成功地使用这两个类,甚至认为Android的这两个类是不能工作的。</wbr></wbr></wbr>

<wbr><wbr><wbr>其实,AudioRecord和AudioTrack类的使用虽然比较复杂,但是可以工作,我们不仅可以很好地使用了这两个类,而且还通过套接字(Socket)实现了音频数据的网络传输,做到了一端使用AudioRecord获取音频流然后通过套接字传输出去,而另一端通过套接字接收后使用AudioTrack类播放。</wbr></wbr></wbr>

<wbr><wbr><wbr>下面是我们对AudioRecord和AudioTrack类在使用方面的经验总结:</wbr></wbr></wbr>

<wbr><wbr><wbr>(1)创建AudioRecord和AudioTrack类对象:创建这两个类的对象比较复杂,通过对文档的反复和仔细理解,并通过多次失败的尝试,并在北理工的某个Android大牛的网上的文章启发下,我们也最终成功地创建了这两个类的对象。创建<span style="word-wrap:normal; word-break:normal">AudioRecord和AudioTrack类对象的代码如下:</span></wbr></wbr></wbr>

AudioRecord类:

<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>m_in_buf_size =AudioRecord.getMinBufferSize(8000,<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>AudioFormat.CHANNEL_CONFIGURATION_MONO,<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>AudioFormat.ENCODING_PCM_16BIT);<br><wbr><wbr><wbr><br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>m_in_rec = new AudioRecord(MediaRecorder.AudioSource.MIC,<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>8000,<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>AudioFormat.CHANNEL_CONFIGURATION_MONO,<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>AudioFormat.ENCODING_PCM_16BIT,<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>m_in_buf_size) ;</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

AudioTrack类:

<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>m_out_buf_size = android.media.AudioTrack.getMinBufferSize(8000,<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>AudioFormat.CHANNEL_CONFIGURATION_MONO,<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>AudioFormat.ENCODING_PCM_16BIT);</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>m_out_trk = new AudioTrack(AudioManager.STREAM_MUSIC, 8000,<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>AudioFormat.CHANNEL_CONFIGURATION_MONO,<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>AudioFormat.ENCODING_PCM_16BIT,<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>m_out_buf_size,<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>AudioTrack.MODE_STREAM);</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><span style="word-wrap:normal; word-break:normal">(2)关于AudioRecord和AudioTrack类的监听函数,不用也行。</span></wbr></wbr></wbr>

<wbr></wbr>

<wbr><wbr><wbr>(3)调试方面,包括初始化后看logcat信息,以确定类的工作状态,初始化是否成功等。</wbr></wbr></wbr>

<wbr><wbr><wbr><wbr><wbr>编写好代码,没有语法错误,调用模拟器运行、调试代码时,logcat发挥了很好的功用。刚调试时,经常会出现模拟器显示出现异常,这时我们可以在代码的一些关键语句后添加如Log.d("test1","OK");这样的语句进行标识,出现异常时我们就可以在logcat窗口观察代码执行到哪里出现异常,然后进行相应的修改、调试。模拟器不会出现异常时,又遇到了录放音的问题。录音方面,刚开始选择将语音编码数据存放在多个固定大小的文件中进行传送,但是这种情况下会出现声音断续的现象,而且要反复的建立文件,比较麻烦,后来想到要进行网上传输,直接将语音编码数据以数据流的形式传送,经过验证,这种方法可行并且使代码更加简洁。放音方面,将接收到的数据流存放在一个数组中,然后将数组中数据写到AudioTrack中。刚开始只是“嘟”几声,经过检查发现只是把数据写一次,加入循环,让数据反复写到AudioTrack中,就可以听到正常的语音了。接下来的工作主要是改善话音质量与话音延迟,在进行通话的过程中,观察</wbr></wbr></wbr></wbr></wbr>logcat窗口,发现向数组中写数据时会出现Bufferflow的情况,于是把重心转移到数组大小的影响上,经过试验,发现 AudioRecord一次会读640个数据,然后就对录音和放音中有数组的地方进行实验修改。AudioRecord和AudioTrack进行实例化时,参数中各有一个数组大小,经过试验这个数组大小和AudioRecord和AudioTrack能正常实例化所需的最小Buffer大小(即上面实例化时的m_in_buf_size和m_out_buf_size参数)相等且服务器方进行缓存数据的数组尺寸是上述数值的2倍时,语音质量最好。由于录音和放音的速度不一致,受到北理工大牛的启发,在录音方面,将存放录音数据的数组放到LinkedList中,当LinkedList中数组个数达到2(这个也是经过试验验证话音质量最好时的数据)时,将先录好的数组中数据传送出去。经过上述反复试验和修改,最终使双方通话质量较好,且延时较短(大概有2秒钟)。

<wbr><wbr><wbr>(4)通过套接字传输和接收数据</wbr></wbr></wbr>

<wbr><wbr><wbr><wbr>数据传送部分,使用的是套接字。通信双方,通过不同的端口向服务器发送请求,与服务器连接上后,开始通话向服务器发送数据,服务器通过一个套接字接收到一方的数据后,先存在一个数组中,然后将该数组中数据以数据流的形式再通过另一个套接字传送到另一方。这样就实现了双方数据的传送。</wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr>(5)代码架构</wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr><wbr>为避免反复录入和读取数据占用较多资源,使程序在进行录放音时不能执行其他命令,故将录音和放音各写成一个线程类,然后在主程序中,通过MENU控制通话的开始、停止、结束。</wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr><wbr><span style="word-wrap:normal; word-break:normal">最后说明,AudioRecord和AudioTrack类可以用,只是稍微复杂些。以下贴出双方通信的源码,希望对大家有所帮助:</span></wbr></wbr></wbr></wbr></wbr>

主程序Daudioclient:

package cn.Daudioclient;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

public class Daudioclient extends Activity {
<wbr><br><wbr><wbr><wbr><wbr>public static final int MENU_START_ID = Menu.FIRST ;<br><wbr><wbr><wbr>public static final int MENU_STOP_ID = Menu.FIRST + 1 ;<br><wbr><wbr><wbr>public static final int MENU_EXIT_ID = Menu.FIRST + 2 ;<br><wbr><br><wbr><wbr><wbr>protected Saudioserver<wbr><wbr><wbr><wbr>m_player ;<br><wbr><wbr><wbr>protected Saudioclient<wbr><wbr><wbr><wbr>m_recorder ;<br><wbr><br><wbr><wbr><wbr><br><wbr><wbr><wbr>@Override<br><wbr><wbr><wbr>public void onCreate(Bundle savedInstanceState) {<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>super.onCreate(savedInstanceState);<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>setContentView(R.layout.main);<br><wbr><wbr><wbr>}<br><wbr><wbr><wbr><br><wbr><wbr><wbr>public boolean onCreateOptionsMenu(Menu aMenu)<br><wbr><wbr><wbr>{<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>boolean res = super.onCreateOptionsMenu(aMenu) ;</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr><wbr><wbr><wbr>aMenu.add(0, MENU_START_ID, 0, "START") ;<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>aMenu.add(0, MENU_STOP_ID, 0, "STOP") ;<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>aMenu.add(0, MENU_EXIT_ID, 0, "EXIT") ;</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr><wbr><wbr><wbr>return res ;<br><wbr><wbr><wbr>}</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><br><wbr><wbr><wbr>public boolean onOptionsItemSelected(MenuItem aMenuItem)<br><wbr><wbr><wbr>{<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>switch (aMenuItem.getItemId()) {<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>case MENU_START_ID:<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>{<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>m_player = new Saudioserver() ;<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>m_recorder = new Saudioclient() ;</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>m_player.init() ;<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>m_recorder.init() ;</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>m_recorder.start() ;<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>m_player.start() ;<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>}<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>break ;<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>case MENU_STOP_ID:<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>{<wbr><wbr><br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>m_recorder.free() ;<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>m_player.free() ;</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>m_player = null ;<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>m_recorder = null ;<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>}<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>break ;<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>case MENU_EXIT_ID:<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>{<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>int pid = android.os.Process.myPid() ;<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>android.os.Process.killProcess(pid) ;<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>}<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>break ;<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>default:<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>break ;<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>}</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr><wbr><wbr><wbr>return super.onOptionsItemSelected(aMenuItem);<br><wbr><wbr><wbr>}<br> }</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

录音程序Saudioclient:

package cn.Daudioclient;

import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.LinkedList;

import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.util.Log;

public class Saudioclient extends Thread
{
<wbr><br><wbr><wbr><wbr>protected AudioRecord m_in_rec ;<wbr><br><wbr><wbr><wbr>protected int<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>m_in_buf_size ;<br><wbr><wbr><wbr>protected byte []<wbr><wbr><wbr><wbr>m_in_bytes ;<br><wbr><wbr><wbr>protected boolean<wbr><wbr><wbr><wbr>m_keep_running ;<br><wbr><wbr><wbr>protected Socket<wbr><wbr><wbr><wbr><wbr>s;<br><wbr><wbr><wbr>protected DataOutputStream dout;<br><wbr><wbr><wbr>protected LinkedList&lt;byte[]&gt;<wbr>m_in_q ;<br><wbr><wbr><br><wbr><wbr><wbr>public void run()<br><wbr>{<br><wbr><wbr><wbr><wbr><wbr>try<br><wbr><wbr><wbr><wbr><wbr>{<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>byte [] bytes_pkg ;<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>m_in_rec.startRecording() ;<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>while(m_keep_running)<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>{<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>m_in_rec.read(m_in_bytes, 0, m_in_buf_size) ;<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>bytes_pkg = m_in_bytes.clone() ;<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>if(m_in_q.size() &gt;= 2)<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>{<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>dout.write(m_in_q.removeFirst() , 0, m_in_q.removeFirst() .length);<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>}<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>m_in_q.add(bytes_pkg) ;<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>}<br><wbr><wbr><wbr><wbr><br><wbr><wbr><wbr><wbr><wbr><wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

在Android中录音可以用MediaRecord录音,操作比较简单。但是不够专业,就是不能对音频进行处理。如果要进行音频的实时的处理或者音频的一些封装

就可以用AudioRecord来进行录音了。

这里给出一段代码。实现了AudioRecord的录音和WAV格式音频的封装。

用AudioTrack和AudioTrack类可以进行边录边播,可以参考:http://blog.sina.com.cn/s/blog_6309e1ed0100j1rw.html

我们这里的代码没有播放。但是有封装和详解,如下:

  1. packagecom.ppmeet;
  2. importjava.io.File;
  3. importjava.io.FileInputStream;
  4. importjava.io.FileNotFoundException;
  5. importjava.io.FileOutputStream;
  6. importjava.io.IOException;
  7. importandroid.app.Activity;
  8. importandroid.graphics.PixelFormat;
  9. importandroid.media.AudioFormat;
  10. importandroid.media.AudioRecord;
  11. importandroid.media.MediaRecorder;
  12. importandroid.os.Bundle;
  13. importandroid.view.View;
  14. importandroid.view.View.OnClickListener;
  15. importandroid.view.Window;
  16. importandroid.view.WindowManager;
  17. importandroid.widget.Button;
  18. /**
  19. *classname:TestAudioRecord<BR>
  20. *classdescription:用AudioRecord来进行录音<BR>
  21. *PS:<BR>
  22. *
  23. *@version1.002011/09/21
  24. *@authorCODYY)peijiangping
  25. */
  26. publicclassTestAudioRecordextendsActivity{
  27. //音频获取源
  28. privateintaudioSource=MediaRecorder.AudioSource.MIC;
  29. //设置音频采样率,44100是目前的标准,但是某些设备仍然支持22050,16000,11025
  30. privatestaticintsampleRateInHz=44100;
  31. //设置音频的录制的声道CHANNEL_IN_STEREO为双声道,CHANNEL_CONFIGURATION_MONO为单声道
  32. privatestaticintchannelConfig=AudioFormat.CHANNEL_IN_STEREO;
  33. //音频数据格式:PCM16位每个样本。保证设备支持。PCM8位每个样本。不一定能得到设备支持。
  34. privatestaticintaudioFormat=AudioFormat.ENCODING_PCM_16BIT;
  35. //缓冲区字节大小
  36. privateintbufferSizeInBytes=0;
  37. privateButtonStart;
  38. privateButtonStop;
  39. privateAudioRecordaudioRecord;
  40. privatebooleanisRecord=false;//设置正在录制的状态
  41. //AudioName裸音频数据文件
  42. privatestaticfinalStringAudioName="/sdcard/love.raw";
  43. //NewAudioName可播放的音频文件
  44. privatestaticfinalStringNewAudioName="/sdcard/new.wav";
  45. publicvoidonCreate(BundlesavedInstanceState){
  46. super.onCreate(savedInstanceState);
  47. getWindow().setFormat(PixelFormat.TRANSLUCENT);//让界面横屏
  48. requestWindowFeature(Window.FEATURE_NO_TITLE);//去掉界面标题
  49. getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
  50. WindowManager.LayoutParams.FLAG_FULLSCREEN);
  51. //重新设置界面大小
  52. setContentView(R.layout.main);
  53. init();
  54. }
  55. privatevoidinit(){
  56. Start=(Button)this.findViewById(R.id.start);
  57. Stop=(Button)this.findViewById(R.id.stop);
  58. Start.setOnClickListener(newTestAudioListener());
  59. Stop.setOnClickListener(newTestAudioListener());
  60. creatAudioRecord();
  61. }
  62. privatevoidcreatAudioRecord(){
  63. //获得缓冲区字节大小
  64. bufferSizeInBytes=AudioRecord.getMinBufferSize(sampleRateInHz,
  65. channelConfig,audioFormat);
  66. //创建AudioRecord对象
  67. audioRecord=newAudioRecord(audioSource,sampleRateInHz,
  68. channelConfig,audioFormat,bufferSizeInBytes);
  69. }
  70. classTestAudioListenerimplementsOnClickListener{
  71. @Override
  72. publicvoidonClick(Viewv){
  73. if(v==Start){
  74. startRecord();
  75. }
  76. if(v==Stop){
  77. stopRecord();
  78. }
  79. }
  80. }
  81. privatevoidstartRecord(){
  82. audioRecord.startRecording();
  83. //让录制状态为true
  84. isRecord=true;
  85. //开启音频文件写入线程
  86. newThread(newAudioRecordThread()).start();
  87. }
  88. privatevoidstopRecord(){
  89. close();
  90. }
  91. privatevoidclose(){
  92. if(audioRecord!=null){
  93. System.out.println("stopRecord");
  94. isRecord=false;//停止文件写入
  95. audioRecord.stop();
  96. audioRecord.release();//释放资源
  97. audioRecord=null;
  98. }
  99. }
  100. classAudioRecordThreadimplementsRunnable{
  101. @Override
  102. publicvoidrun(){
  103. writeDateTOFile();//往文件中写入裸数据
  104. copyWaveFile(AudioName,NewAudioName);//给裸数据加上头文件
  105. }
  106. }
  107. /**
  108. *这里将数据写入文件,但是并不能播放,因为AudioRecord获得的音频是原始的裸音频,
  109. *如果需要播放就必须加入一些格式或者编码的头信息。但是这样的好处就是你可以对音频的裸数据进行处理,比如你要做一个爱说话的TOM
  110. *猫在这里就进行音频的处理,然后重新封装所以说这样得到的音频比较容易做一些音频的处理。
  111. */
  112. privatevoidwriteDateTOFile(){
  113. //new一个byte数组用来存一些字节数据,大小为缓冲区大小
  114. byte[]audiodata=newbyte[bufferSizeInBytes];
  115. FileOutputStreamfos=null;
  116. intreadsize=0;
  117. try{
  118. Filefile=newFile(AudioName);
  119. if(file.exists()){
  120. file.delete();
  121. }
  122. fos=newFileOutputStream(file);//建立一个可存取字节的文件
  123. }catch(Exceptione){
  124. e.printStackTrace();
  125. }
  126. while(isRecord==true){
  127. readsize=audioRecord.read(audiodata,0,bufferSizeInBytes);
  128. if(AudioRecord.ERROR_INVALID_OPERATION!=readsize){
  129. try{
  130. fos.write(audiodata);
  131. }catch(IOExceptione){
  132. e.printStackTrace();
  133. }
  134. }
  135. }
  136. try{
  137. fos.close();//关闭写入流
  138. }catch(IOExceptione){
  139. e.printStackTrace();
  140. }
  141. }
  142. //这里得到可播放的音频文件
  143. privatevoidcopyWaveFile(StringinFilename,StringoutFilename){
  144. FileInputStreamin=null;
  145. FileOutputStreamout=null;
  146. longtotalAudioLen=0;
  147. longtotalDataLen=totalAudioLen+36;
  148. longlongSampleRate=sampleRateInHz;
  149. intchannels=2;
  150. longbyteRate=16*sampleRateInHz*channels/8;
  151. byte[]data=newbyte[bufferSizeInBytes];
  152. try{
  153. in=newFileInputStream(inFilename);
  154. out=newFileOutputStream(outFilename);
  155. totalAudioLen=in.getChannel().size();
  156. totalDataLen=totalAudioLen+36;
  157. WriteWaveFileHeader(out,totalAudioLen,totalDataLen,
  158. longSampleRate,channels,byteRate);
  159. while(in.read(data)!=-1){
  160. out.write(data);
  161. }
  162. in.close();
  163. out.close();
  164. }catch(FileNotFoundExceptione){
  165. e.printStackTrace();
  166. }catch(IOExceptione){
  167. e.printStackTrace();
  168. }
  169. }
  170. /**
  171. *这里提供一个头信息。插入这些信息就可以得到可以播放的文件。
  172. *为我为啥插入这44个字节,这个还真没深入研究,不过你随便打开一个wav
  173. *音频的文件,可以发现前面的头文件可以说基本一样哦。每种格式的文件都有
  174. *自己特有的头文件。
  175. */
  176. privatevoidWriteWaveFileHeader(FileOutputStreamout,longtotalAudioLen,
  177. longtotalDataLen,longlongSampleRate,intchannels,longbyteRate)
  178. throwsIOException{
  179. byte[]header=newbyte[44];
  180. header[0]='R';//RIFF/WAVEheader
  181. header[1]='I';
  182. header[2]='F';
  183. header[3]='F';
  184. header[4]=(byte)(totalDataLen&0xff);
  185. header[5]=(byte)((totalDataLen>>8)&0xff);
  186. header[6]=(byte)((totalDataLen>>16)&0xff);
  187. header[7]=(byte)((totalDataLen>>24)&0xff);
  188. header[8]='W';
  189. header[9]='A';
  190. header[10]='V';
  191. header[11]='E';
  192. header[12]='f';//'fmt'chunk
  193. header[13]='m';
  194. header[14]='t';
  195. header[15]='';
  196. header[16]=16;//4bytes:sizeof'fmt'chunk
  197. header[17]=0;
  198. header[18]=0;
  199. header[19]=0;
  200. header[20]=1;//format=1
  201. header[21]=0;
  202. header[22]=(byte)channels;
  203. header[23]=0;
  204. header[24]=(byte)(longSampleRate&0xff);
  205. header[25]=(byte)((longSampleRate>>8)&0xff);
  206. header[26]=(byte)((longSampleRate>>16)&0xff);
  207. header[27]=(byte)((longSampleRate>>24)&0xff);
  208. header[28]=(byte)(byteRate&0xff);
  209. header[29]=(byte)((byteRate>>8)&0xff);
  210. header[30]=(byte)((byteRate>>16)&0xff);
  211. header[31]=(byte)((byteRate>>24)&0xff);
  212. header[32]=(byte)(2*16/8);//blockalign
  213. header[33]=0;
  214. header[34]=16;//bitspersample
  215. header[35]=0;
  216. header[36]='d';
  217. header[37]='a';
  218. header[38]='t';
  219. header[39]='a';
  220. header[40]=(byte)(totalAudioLen&0xff);
  221. header[41]=(byte)((totalAudioLen>>8)&0xff);
  222. header[42]=(byte)((totalAudioLen>>16)&0xff);
  223. header[43]=(byte)((totalAudioLen>>24)&0xff);
  224. out.write(header,0,44);
  225. }
  226. @Override
  227. protectedvoidonDestroy(){
  228. close();
  229. super.onDestroy();
  230. }
  231. }
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics