直接给上个详细的使用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 ;@Overridepublic 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中采集音频的api是android.media.AudioRecord类

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

以下是参数的含义解释

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

Since: API Level 3

Class constructor.

Parameters

audioSource

the recording source. See MediaRecorder.AudioSource for recording source definitions.

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

sampleRateInHz

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

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

channelConfig

describes the configuration of the audio channels. SeeCHANNEL_IN_MONO and CHANNEL_IN_STEREO

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

audioFormat

the format in which the audio data is represented. SeeENCODING_PCM_16BIT and ENCODING_PCM_8BIT

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

bufferSizeInBytes

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. See getMinBufferSize(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

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

[java]  view plain copy
  1. package com.ppmeet;
  2. import java.io.File;
  3. import java.io.FileInputStream;
  4. import java.io.FileNotFoundException;
  5. import java.io.FileOutputStream;
  6. import java.io.IOException;
  7. import android.app.Activity;
  8. import android.graphics.PixelFormat;
  9. import android.media.AudioFormat;
  10. import android.media.AudioRecord;
  11. import android.media.MediaRecorder;
  12. import android.os.Bundle;
  13. import android.view.View;
  14. import android.view.View.OnClickListener;
  15. import android.view.Window;
  16. import android.view.WindowManager;
  17. import android.widget.Button;
  18. /**
  19. * class name:TestAudioRecord<BR>
  20. * class description:用AudioRecord来进行录音<BR>
  21. * PS: <BR>
  22. *
  23. * @version 1.00 2011/09/21
  24. * @author CODYY)peijiangping
  25. */
  26. public class TestAudioRecord extends Activity {
  27. // 音频获取源
  28. private int audioSource = MediaRecorder.AudioSource.MIC;
  29. // 设置音频采样率,44100是目前的标准,但是某些设备仍然支持22050,16000,11025
  30. private static int sampleRateInHz = 44100;
  31. // 设置音频的录制的声道CHANNEL_IN_STEREO为双声道,CHANNEL_CONFIGURATION_MONO为单声道
  32. private static int channelConfig = AudioFormat.CHANNEL_IN_STEREO;
  33. // 音频数据格式:PCM 16位每个样本。保证设备支持。PCM 8位每个样本。不一定能得到设备支持。
  34. private static int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
  35. // 缓冲区字节大小
  36. private int bufferSizeInBytes = 0;
  37. private Button Start;
  38. private Button Stop;
  39. private AudioRecord audioRecord;
  40. private boolean isRecord = false;// 设置正在录制的状态
  41. //AudioName裸音频数据文件
  42. private static final String AudioName = "/sdcard/love.raw";
  43. //NewAudioName可播放的音频文件
  44. private static final String NewAudioName = "/sdcard/new.wav";
  45. public void onCreate(Bundle savedInstanceState) {
  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. private void init() {
  56. Start = (Button) this.findViewById(R.id.start);
  57. Stop = (Button) this.findViewById(R.id.stop);
  58. Start.setOnClickListener(new TestAudioListener());
  59. Stop.setOnClickListener(new TestAudioListener());
  60. creatAudioRecord();
  61. }
  62. private void creatAudioRecord() {
  63. // 获得缓冲区字节大小
  64. bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz,
  65. channelConfig, audioFormat);
  66. // 创建AudioRecord对象
  67. audioRecord = new AudioRecord(audioSource, sampleRateInHz,
  68. channelConfig, audioFormat, bufferSizeInBytes);
  69. }
  70. class TestAudioListener implements OnClickListener {
  71. @Override
  72. public void onClick(View v) {
  73. if (v == Start) {
  74. startRecord();
  75. }
  76. if (v == Stop) {
  77. stopRecord();
  78. }
  79. }
  80. }
  81. private void startRecord() {
  82. audioRecord.startRecording();
  83. // 让录制状态为true
  84. isRecord = true;
  85. // 开启音频文件写入线程
  86. new Thread(new AudioRecordThread()).start();
  87. }
  88. private void stopRecord() {
  89. close();
  90. }
  91. private void close() {
  92. if (audioRecord != null) {
  93. System.out.println("stopRecord");
  94. isRecord = false;//停止文件写入
  95. audioRecord.stop();
  96. audioRecord.release();//释放资源
  97. audioRecord = null;
  98. }
  99. }
  100. class AudioRecordThread implements Runnable {
  101. @Override
  102. public void run() {
  103. writeDateTOFile();//往文件中写入裸数据
  104. copyWaveFile(AudioName, NewAudioName);//给裸数据加上头文件
  105. }
  106. }
  107. /**
  108. * 这里将数据写入文件,但是并不能播放,因为AudioRecord获得的音频是原始的裸音频,
  109. * 如果需要播放就必须加入一些格式或者编码的头信息。但是这样的好处就是你可以对音频的 裸数据进行处理,比如你要做一个爱说话的TOM
  110. * 猫在这里就进行音频的处理,然后重新封装 所以说这样得到的音频比较容易做一些音频的处理。
  111. */
  112. private void writeDateTOFile() {
  113. // new一个byte数组用来存一些字节数据,大小为缓冲区大小
  114. byte[] audiodata = new byte[bufferSizeInBytes];
  115. FileOutputStream fos = null;
  116. int readsize = 0;
  117. try {
  118. File file = new File(AudioName);
  119. if (file.exists()) {
  120. file.delete();
  121. }
  122. fos = new FileOutputStream(file);// 建立一个可存取字节的文件
  123. } catch (Exception e) {
  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 (IOException e) {
  132. e.printStackTrace();
  133. }
  134. }
  135. }
  136. try {
  137. fos.close();// 关闭写入流
  138. } catch (IOException e) {
  139. e.printStackTrace();
  140. }
  141. }
  142. // 这里得到可播放的音频文件
  143. private void copyWaveFile(String inFilename, String outFilename) {
  144. FileInputStream in = null;
  145. FileOutputStream out = null;
  146. long totalAudioLen = 0;
  147. long totalDataLen = totalAudioLen + 36;
  148. long longSampleRate = sampleRateInHz;
  149. int channels = 2;
  150. long byteRate = 16 * sampleRateInHz * channels / 8;
  151. byte[] data = new byte[bufferSizeInBytes];
  152. try {
  153. in = new FileInputStream(inFilename);
  154. out = new FileOutputStream(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 (FileNotFoundException e) {
  165. e.printStackTrace();
  166. } catch (IOException e) {
  167. e.printStackTrace();
  168. }
  169. }
  170. /**
  171. * 这里提供一个头信息。插入这些信息就可以得到可以播放的文件。
  172. * 为我为啥插入这44个字节,这个还真没深入研究,不过你随便打开一个wav
  173. * 音频的文件,可以发现前面的头文件可以说基本一样哦。每种格式的文件都有
  174. * 自己特有的头文件。
  175. */
  176. private void WriteWaveFileHeader(FileOutputStream out, long totalAudioLen,
  177. long totalDataLen, long longSampleRate, int channels, long byteRate)
  178. throws IOException {
  179. byte[] header = new byte[44];
  180. header[0] = 'R'; // RIFF/WAVE header
  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; // 4 bytes: size of '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); // block align
  213. header[33] = 0;
  214. header[34] = 16; // bits per sample
  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. protected void onDestroy() {
  228. close();
  229. super.onDestroy();
  230. }
  231. }

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

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

(2010-05-07 09:07:05

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

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

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

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

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

AudioRecord类:

m_in_buf_size =AudioRecord.getMinBufferSize(8000,
                        AudioFormat.CHANNEL_CONFIGURATION_MONO,
                        AudioFormat.ENCODING_PCM_16BIT);
   
         m_in_rec = new AudioRecord(MediaRecorder.AudioSource.MIC,
         8000,
         AudioFormat.CHANNEL_CONFIGURATION_MONO,
         AudioFormat.ENCODING_PCM_16BIT,
         m_in_buf_size) ;

AudioTrack类:

m_out_buf_size = android.media.AudioTrack.getMinBufferSize(8000,
                          AudioFormat.CHANNEL_CONFIGURATION_MONO,
                          AudioFormat.ENCODING_PCM_16BIT);

m_out_trk = new AudioTrack(AudioManager.STREAM_MUSIC, 8000,
                                       AudioFormat.CHANNEL_CONFIGURATION_MONO,
                                       AudioFormat.ENCODING_PCM_16BIT,
                                       m_out_buf_size,
                                       AudioTrack.MODE_STREAM);

(2)关于AudioRecord和AudioTrack类的监听函数,不用也行。

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

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

(4)通过套接字传输和接收数据

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

(5)代码架构

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

最后说明,AudioRecord和AudioTrack类可以用,只是稍微复杂些。以下贴出双方通信的源码,希望对大家有所帮助:

主程序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 {
 
    public static final int MENU_START_ID = Menu.FIRST ;
    public static final int MENU_STOP_ID = Menu.FIRST + 1 ;
    public static final int MENU_EXIT_ID = Menu.FIRST + 2 ;
 
    protected Saudioserver     m_player ;
    protected Saudioclient     m_recorder ;
 
   
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
   
    public boolean onCreateOptionsMenu(Menu aMenu)
    {
        boolean res = super.onCreateOptionsMenu(aMenu) ;

aMenu.add(0, MENU_START_ID, 0, "START") ;
        aMenu.add(0, MENU_STOP_ID, 0, "STOP") ;
        aMenu.add(0, MENU_EXIT_ID, 0, "EXIT") ;

return res ;
    }

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

m_player.init() ;
                m_recorder.init() ;

m_recorder.start() ;
                m_player.start() ;
               
            }
            break ;
        case MENU_STOP_ID:
            {  
             m_recorder.free() ;
                m_player.free() ;

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

return super.onOptionsItemSelected(aMenuItem);
    }
}

录音程序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
{
 
    protected AudioRecord m_in_rec ; 
    protected int         m_in_buf_size ;
    protected byte []     m_in_bytes ;
    protected boolean     m_keep_running ;
    protected Socket      s;
    protected DataOutputStream dout;
    protected LinkedList<byte[]>  m_in_q ;
  
    public void run()
 {
      try
      {
          byte [] bytes_pkg ;
             m_in_rec.startRecording() ;
             while(m_keep_running)
             {
                 m_in_rec.read(m_in_bytes, 0, m_in_buf_size) ;
                 bytes_pkg = m_in_bytes.clone() ;
                 if(m_in_q.size() >= 2)
                 {
                        dout.write(m_in_q.removeFirst() , 0, m_in_q.removeFirst() .length);
                    }
                    m_in_q.add(bytes_pkg) ;
             }
     
             m_in_rec.stop() ;
             m_in_rec = null ;
             m_in_bytes = null ;
       dout.close();
        
      }
      catch(Exception e)
      {
       e.printStackTrace();
      }
    }
   
    public void init()
    {
     m_in_buf_size =  AudioRecord.getMinBufferSize(8000,
                        AudioFormat.CHANNEL_CONFIGURATION_MONO,
                        AudioFormat.ENCODING_PCM_16BIT);
   
  m_in_rec = new AudioRecord(MediaRecorder.AudioSource.MIC,
  8000,
  AudioFormat.CHANNEL_CONFIGURATION_MONO,
  AudioFormat.ENCODING_PCM_16BIT,
  m_in_buf_size) ;
  
  m_in_bytes = new byte [m_in_buf_size] ;
  
  m_keep_running = true ;
  m_in_q=new LinkedList<byte[]>();
  
     try
     {
   s=new Socket("192.168.1.100",4332);
   dout=new DataOutputStream(s.getOutputStream());
   //new Thread(R1).start();
  }
     catch (UnknownHostException e)
     {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
     catch (IOException e)
     {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

}
   
    public void free()
 {
  m_keep_running = false ;
        try {
            Thread.sleep(1000) ;
        } catch(Exception e) {
            Log.d("sleep exceptions...\n","") ;
        }
 }
}
放音程序Saudioserver:

package cn.Daudioclient;

import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;

import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.util.Log;

public class Saudioserver extends Thread
{  
    protected AudioTrack m_out_trk ;
    protected int        m_out_buf_size ;
    protected byte []    m_out_bytes ;
    protected boolean    m_keep_running ;
 private Socket s;
 private DataInputStream din;
 public void init()
 {
  try
     {
            s=new Socket("192.168.1.100",4331);
            din=new DataInputStream(s.getInputStream());
           
             m_keep_running = true ;
       
           
            m_out_buf_size = AudioTrack.getMinBufferSize(8000,
                             AudioFormat.CHANNEL_CONFIGURATION_MONO,
                             AudioFormat.ENCODING_PCM_16BIT);

m_out_trk = new AudioTrack(AudioManager.STREAM_MUSIC, 8000,
                                       AudioFormat.CHANNEL_CONFIGURATION_MONO,
                                       AudioFormat.ENCODING_PCM_16BIT,
                                       m_out_buf_size,
                                       AudioTrack.MODE_STREAM);
         
            m_out_bytes=new byte[m_out_buf_size];
           
           // new Thread(R1).start();
           
     }
     catch(Exception e)
     {
      e.printStackTrace();
     }
 }
   
 public void free()
 {
  m_keep_running = false ;
        try {
            Thread.sleep(1000) ;
        } catch(Exception e) {
            Log.d("sleep exceptions...\n","") ;
        }
 }
 
  public void run()
  {
   byte [] bytes_pkg = null ;
         m_out_trk.play() ;
         while(m_keep_running) {
             try
             {
              din.read(m_out_bytes);
                 bytes_pkg = m_out_bytes.clone() ;
                 m_out_trk.write(bytes_pkg, 0, bytes_pkg.length) ;
             }
             catch(Exception e)
             {
              e.printStackTrace();
             }
            
         }
        
         m_out_trk.stop() ;
         m_out_trk = null ;
         try {
    din.close();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
}

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

Android AudioRecord 实现音频录制

//由于程序可能用到对手机SD卡的读取,所以在manifest.xml里需要配置对sd卡存取的权限:
// <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
// <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import android.app.Activity;
import android.content.Context;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

import com.telenav.funnl.android.R;
/** 
* 该实例中,我们使用AudioRecord类来完成我们的音频录制程序 
* AudioRecord类,我们可以使用三种不同的read方法来完成录制工作, 
* 每种方法都有其实用的场合 
* 一、实例化一个AudioRecord类我们需要传入几种参数 
* 1、AudioSource:这里可以是MediaRecorder.AudioSource.MIC 
* 2、SampleRateInHz:录制频率,可以为8000hz或者11025hz等,不同的硬件设备这个值不同 
* 3、ChannelConfig:录制通道,可以为udioFormat.CHANNEL_CONFIGURATION_MONO和udioFormat.CHANNEL_CONFIGURATION_STEREO 
* 4、AudioFormat:录制编码格式,可以为AudioFormat.ENCODING_16BIT和BIT,其中16BIT的仿真性比8BIT好,但是需要消耗更多的电量和存储空间 
* 5、BufferSize:录制缓冲大小:可以通过getMinBufferSize来获取 
* 这样我们就可以实例化一个AudioRecord对象了 
* 二、创建一个文件,用于保存录制的内容 
* 同上篇 
* 三、打开一个输出流,指向创建的文件 
* DataOutputStream dos = new DataOutputStream(new BufferedOutputSream(new FileOutputStream(file))) 
* 四、现在就可以开始录制了,我们需要创建一个字节数组来存储从udioRecorder中返回的音频数据,但是 
* 注意,我们定义的数组要小于定义AudioRecord时指定的那个ufferSize 
* short[]buffer = new short[BufferSize/4]; 
* startRecording(); 
* 然后一个循环,调用AudioRecord的read方法实现读取 
* 另外使用MediaPlayer是无法播放使用AudioRecord录制的音频的,为了实现播放,我们需要 
* 使用AudioTrack类来实现 
* AudioTrack类允许我们播放原始的音频数据 


* 一、实例化一个AudioTrack同样要传入几个参数 
* 1、StreamType:在AudioManager中有几个常量,其中一个是TREAM_MUSIC; 
* 2、SampleRateInHz:最好和AudioRecord使用的是同一个值 
* 3、ChannelConfig:同上 
* 4、AudioFormat:同上 
* 5、BufferSize:通过AudioTrack的静态方法getMinBufferSize来获取 
* 6、Mode:可以是AudioTrack.MODE_STREAM和MODE_STATIC,关于这两种不同之处,可以查阅文档 
* 二、打开一个输入流,指向刚刚录制内容保存的文件,然后开始播放,边读取边播放 

* 实现时,音频的录制和播放分别使用两个AsyncTask来完成 
*/ 
public class PCMRecordActivity extends Activity implements OnClickListener{

private TextView stateView;

private Button btnStart,btnStop,btnPlay,btnFinish;

private RecordTask recorder; 
private PlayTask player; 
private File fpath; 
private File audioFile;
private Context context;

private boolean isRecording=true, isPlaying=false; //标记

private int frequence = 16000;//8000; //录制频率,单位hz.这里的值注意了,写的不好,可能实例化AudioRecord对象的时候,会出错。我开始写成11025就不行。这取决于硬件设备 
private int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO; 
private int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;

public void onCreate(Bundle savedInstanceState){ 
super.onCreate(savedInstanceState); 
setContentView(R.layout.my_audio_record);

stateView = (TextView)this.findViewById(R.id.view_state); 
stateView.setText("start recording.."); 
btnStart = (Button)this.findViewById(R.id.btn_start); 
btnStart.setText("start");
btnStart.setOnClickListener(this);
btnStop = (Button)this.findViewById(R.id.btn_stop); 
btnStop.setText("stop");
btnStop.setOnClickListener(this);
btnPlay = (Button)this.findViewById(R.id.btn_play);
btnPlay.setText("play");
btnPlay.setOnClickListener(this);
btnFinish = (Button)this.findViewById(R.id.btn_finish); 
btnFinish.setText("finish");
btnFinish.setOnClickListener(this);
btnStop.setEnabled(false); 
btnPlay.setEnabled(false); 
btnFinish.setEnabled(false);

if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))//手机有SD卡的情况
{
//在这里我们创建一个文件,用于保存录制内容 
fpath = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/data/files/"); 
fpath.mkdirs();//创建文件夹 
}else//手机无SD卡的情况
{
fpath = this.getCacheDir();
}

try { 
//创建临时文件,注意这里的格式为.pcm 
audioFile = File.createTempFile("recording", ".pcm", fpath); 
} catch (IOException e) { 
// TODO Auto-generated catch block 
e.printStackTrace(); 

}

public void onClick(View v){ 
int id = v.getId(); 
switch(id){ 
case R.id.btn_start: 
//开始录制

//这里启动录制任务 
recorder = new RecordTask(); 
recorder.execute();

break; 
case R.id.btn_stop: 
//停止录制 
this.isRecording = false; 
//更新状态 
//在录制完成时设置,在RecordTask的onPostExecute中完成 
break; 
case R.id.btn_play:

player = new PlayTask(); 
player.execute(); 
break; 
case R.id.btn_finish: 
//完成播放 
this.isPlaying = false; 
break;


}

class RecordTask extends AsyncTask<Void, Integer, Void>{ 
@Override 
protected Void doInBackground(Void... arg0) { 
isRecording = true; 
try { 
//开通输出流到指定的文件 
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(audioFile))); 
//根据定义好的几个配置,来获取合适的缓冲大小 
int bufferSize = AudioRecord.getMinBufferSize(frequence, channelConfig, audioEncoding); 
//实例化AudioRecord 
AudioRecord record = new AudioRecord(MediaRecorder.AudioSource.MIC, frequence, channelConfig, audioEncoding, bufferSize); 
//定义缓冲 
short[] buffer = new short[bufferSize];

//开始录制 
record.startRecording();

int r = 0; //存储录制进度 
//定义循环,根据isRecording的值来判断是否继续录制 
while(isRecording){ 
//从bufferSize中读取字节,返回读取的short个数 
//这里老是出现buffer overflow,不知道是什么原因,试了好几个值,都没用,TODO:待解决 
int bufferReadResult = record.read(buffer, 0, buffer.length); 
//循环将buffer中的音频数据写入到OutputStream中 
for(int i=0; i<bufferReadResult; i++){ 
dos.writeShort(buffer[i]); 

publishProgress(new Integer(r)); //向UI线程报告当前进度 
r++; //自增进度值 

//录制结束 
record.stop(); 
Log.v("The DOS available:", "::"+audioFile.length()); 
dos.close(); 
} catch (Exception e) { 
// TODO: handle exception 

return null; 
}

//当在上面方法中调用publishProgress时,该方法触发,该方法在I线程中被执行 
protected void onProgressUpdate(Integer...progress){ 
stateView.setText(progress[0].toString()); 
}

protected void onPostExecute(Void result){ 
btnStop.setEnabled(false); 
btnStart.setEnabled(true); 
btnPlay.setEnabled(true); 
btnFinish.setEnabled(false); 
}

protected void onPreExecute(){ 
//stateView.setText("正在录制"); 
btnStart.setEnabled(false); 
btnPlay.setEnabled(false); 
btnFinish.setEnabled(false); 
btnStop.setEnabled(true); 
}

}

class PlayTask extends AsyncTask<Void, Integer, Void>{ 
@Override 
protected Void doInBackground(Void... arg0) { 
isPlaying = true; 
int bufferSize = AudioTrack.getMinBufferSize(frequence, channelConfig, audioEncoding); 
short[] buffer = new short[bufferSize/4]; 
try { 
//定义输入流,将音频写入到AudioTrack类中,实现播放 
DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream(audioFile))); 
//实例AudioTrack 
AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC, frequence, channelConfig, audioEncoding, bufferSize, AudioTrack.MODE_STREAM); 
//开始播放 
track.play(); 
//由于AudioTrack播放的是流,所以,我们需要一边播放一边读取 
while(isPlaying && dis.available()>0){ 
int i = 0; 
while(dis.available()>0 && i<buffer.length){ 
buffer[i] = dis.readShort(); 
i++; 

//然后将数据写入到AudioTrack中 
track.write(buffer, 0, buffer.length);

}

//播放结束 
track.stop(); 
dis.close(); 
} catch (Exception e) { 
// TODO: handle exception 

return null; 
}

protected void onPostExecute(Void result){ 
btnPlay.setEnabled(true); 
btnFinish.setEnabled(false); 
btnStart.setEnabled(true); 
btnStop.setEnabled(false); 
}

protected void onPreExecute(){ 
btnStart.setEnabled(false); 
btnStop.setEnabled(false); 
btnPlay.setEnabled(false); 
btnFinish.setEnabled(true); 
}


}

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

Android多媒体学:利用AudioRecord类实现自己的音频录制程序 .

  • 博客分类:
  • android

AudioRecord类相对于MediaRecorder来说,更加接近底层,为我们封装的方法也更少。然而实现一个AudioRecord的音频录制程序也很

简单。本实例代码如下:

可惜,本实例测试时有个问题,在录制的时候,会出现buffer over。缓存泄露,待解决。

[java]  view plain copy
  1. package demo.camera;
  2. import java.io.BufferedInputStream;
  3. import java.io.BufferedOutputStream;
  4. import java.io.DataInputStream;
  5. import java.io.DataOutputStream;
  6. import java.io.File;
  7. import java.io.FileInputStream;
  8. import java.io.FileOutputStream;
  9. import java.io.IOException;
  10. import android.app.Activity;
  11. import android.content.ContentValues;
  12. import android.content.Intent;
  13. import android.hardware.Camera.AutoFocusCallback;
  14. import android.media.AudioFormat;
  15. import android.media.AudioManager;
  16. import android.media.AudioRecord;
  17. import android.media.AudioTrack;
  18. import android.media.MediaPlayer;
  19. import android.media.MediaRecorder;
  20. import android.net.Uri;
  21. import android.os.AsyncTask;
  22. import android.os.Bundle;
  23. import android.os.Environment;
  24. import android.provider.MediaStore;
  25. import android.util.Log;
  26. import android.view.View;
  27. import android.widget.Button;
  28. import android.widget.TextView;
  29. /**
  30. * 该实例中,我们使用AudioRecord类来完成我们的音频录制程序
  31. * AudioRecord类,我们可以使用三种不同的read方法来完成录制工作,
  32. * 每种方法都有其实用的场合
  33. * 一、实例化一个AudioRecord类我们需要传入几种参数
  34. * 1、AudioSource:这里可以是MediaRecorder.AudioSource.MIC
  35. * 2、SampleRateInHz:录制频率,可以为8000hz或者11025hz等,不同的硬件设备这个值不同
  36. * 3、ChannelConfig:录制通道,可以为AudioFormat.CHANNEL_CONFIGURATION_MONO和AudioFormat.CHANNEL_CONFIGURATION_STEREO
  37. * 4、AudioFormat:录制编码格式,可以为AudioFormat.ENCODING_16BIT和8BIT,其中16BIT的仿真性比8BIT好,但是需要消耗更多的电量和存储空间
  38. * 5、BufferSize:录制缓冲大小:可以通过getMinBufferSize来获取
  39. * 这样我们就可以实例化一个AudioRecord对象了
  40. * 二、创建一个文件,用于保存录制的内容
  41. * 同上篇
  42. * 三、打开一个输出流,指向创建的文件
  43. * DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)))
  44. * 四、现在就可以开始录制了,我们需要创建一个字节数组来存储从AudioRecorder中返回的音频数据,但是
  45. * 注意,我们定义的数组要小于定义AudioRecord时指定的那个BufferSize
  46. * short[]buffer = new short[BufferSize/4];
  47. * startRecording();
  48. * 然后一个循环,调用AudioRecord的read方法实现读取
  49. * 另外使用MediaPlayer是无法播放使用AudioRecord录制的音频的,为了实现播放,我们需要
  50. * 使用AudioTrack类来实现
  51. * AudioTrack类允许我们播放原始的音频数据
  52. *
  53. *
  54. * 一、实例化一个AudioTrack同样要传入几个参数
  55. * 1、StreamType:在AudioManager中有几个常量,其中一个是STREAM_MUSIC;
  56. * 2、SampleRateInHz:最好和AudioRecord使用的是同一个值
  57. * 3、ChannelConfig:同上
  58. * 4、AudioFormat:同上
  59. * 5、BufferSize:通过AudioTrack的静态方法getMinBufferSize来获取
  60. * 6、Mode:可以是AudioTrack.MODE_STREAM和MODE_STATIC,关于这两种不同之处,可以查阅文档
  61. * 二、打开一个输入流,指向刚刚录制内容保存的文件,然后开始播放,边读取边播放
  62. *
  63. * 实现时,音频的录制和播放分别使用两个AsyncTask来完成
  64. */
  65. public class MyAudioRecord2 extends Activity{
  66. private TextView stateView;
  67. private Button btnStart,btnStop,btnPlay,btnFinish;
  68. private RecordTask recorder;
  69. private PlayTask player;
  70. private File audioFile;
  71. private boolean isRecording=true, isPlaying=false; //标记
  72. private int frequence = 8000; //录制频率,单位hz.这里的值注意了,写的不好,可能实例化AudioRecord对象的时候,会出错。我开始写成11025就不行。这取决于硬件设备
  73. private int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;
  74. private int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
  75. public void onCreate(Bundle savedInstanceState){
  76. super.onCreate(savedInstanceState);
  77. setContentView(R.layout.my_audio_record);
  78. stateView = (TextView)this.findViewById(R.id.view_state);
  79. stateView.setText("准备开始");
  80. btnStart = (Button)this.findViewById(R.id.btn_start);
  81. btnStop = (Button)this.findViewById(R.id.btn_stop);
  82. btnPlay = (Button)this.findViewById(R.id.btn_play);
  83. btnFinish = (Button)this.findViewById(R.id.btn_finish);
  84. btnFinish.setText("停止播放");
  85. btnStop.setEnabled(false);
  86. btnPlay.setEnabled(false);
  87. btnFinish.setEnabled(false);
  88. //在这里我们创建一个文件,用于保存录制内容
  89. File fpath = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/data/files/");
  90. fpath.mkdirs();//创建文件夹
  91. try {
  92. //创建临时文件,注意这里的格式为.pcm
  93. audioFile = File.createTempFile("recording", ".pcm", fpath);
  94. } catch (IOException e) {
  95. // TODO Auto-generated catch block
  96. e.printStackTrace();
  97. }
  98. }
  99. public void onClick(View v){
  100. int id = v.getId();
  101. switch(id){
  102. case R.id.btn_start:
  103. //开始录制
  104. //这里启动录制任务
  105. recorder = new RecordTask();
  106. recorder.execute();
  107. break;
  108. case R.id.btn_stop:
  109. //停止录制
  110. this.isRecording = false;
  111. //更新状态
  112. //在录制完成时设置,在RecordTask的onPostExecute中完成
  113. break;
  114. case R.id.btn_play:
  115. player = new PlayTask();
  116. player.execute();
  117. break;
  118. case R.id.btn_finish:
  119. //完成播放
  120. this.isPlaying = false;
  121. break;
  122. }
  123. }
  124. class RecordTask extends AsyncTask<Void, Integer, Void>{
  125. @Override
  126. protected Void doInBackground(Void... arg0) {
  127. isRecording = true;
  128. try {
  129. //开通输出流到指定的文件
  130. DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(audioFile)));
  131. //根据定义好的几个配置,来获取合适的缓冲大小
  132. int bufferSize = AudioRecord.getMinBufferSize(frequence, channelConfig, audioEncoding);
  133. //实例化AudioRecord
  134. AudioRecord record = new AudioRecord(MediaRecorder.AudioSource.MIC, frequence, channelConfig, audioEncoding, bufferSize);
  135. //定义缓冲
  136. short[] buffer = new short[bufferSize];
  137. //开始录制
  138. record.startRecording();
  139. int r = 0; //存储录制进度
  140. //定义循环,根据isRecording的值来判断是否继续录制
  141. while(isRecording){
  142. //从bufferSize中读取字节,返回读取的short个数
  143. //这里老是出现buffer overflow,不知道是什么原因,试了好几个值,都没用,TODO:待解决
  144. int bufferReadResult = record.read(buffer, 0, buffer.length);
  145. //循环将buffer中的音频数据写入到OutputStream中
  146. for(int i=0; i<bufferReadResult; i++){
  147. dos.writeShort(buffer[i]);
  148. }
  149. publishProgress(new Integer(r)); //向UI线程报告当前进度
  150. r++; //自增进度值
  151. }
  152. //录制结束
  153. record.stop();
  154. Log.v("The DOS available:", "::"+audioFile.length());
  155. dos.close();
  156. } catch (Exception e) {
  157. // TODO: handle exception
  158. }
  159. return null;
  160. }
  161. //当在上面方法中调用publishProgress时,该方法触发,该方法在UI线程中被执行
  162. protected void onProgressUpdate(Integer...progress){
  163. stateView.setText(progress[0].toString());
  164. }
  165. protected void onPostExecute(Void result){
  166. btnStop.setEnabled(false);
  167. btnStart.setEnabled(true);
  168. btnPlay.setEnabled(true);
  169. btnFinish.setEnabled(false);
  170. }
  171. protected void onPreExecute(){
  172. //stateView.setText("正在录制");
  173. btnStart.setEnabled(false);
  174. btnPlay.setEnabled(false);
  175. btnFinish.setEnabled(false);
  176. btnStop.setEnabled(true);
  177. }
  178. }
  179. class PlayTask extends AsyncTask<Void, Integer, Void>{
  180. @Override
  181. protected Void doInBackground(Void... arg0) {
  182. isPlaying = true;
  183. int bufferSize = AudioTrack.getMinBufferSize(frequence, channelConfig, audioEncoding);
  184. short[] buffer = new short[bufferSize/4];
  185. try {
  186. //定义输入流,将音频写入到AudioTrack类中,实现播放
  187. DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream(audioFile)));
  188. //实例AudioTrack
  189. AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC, frequence, channelConfig, audioEncoding, bufferSize, AudioTrack.MODE_STREAM);
  190. //开始播放
  191. track.play();
  192. //由于AudioTrack播放的是流,所以,我们需要一边播放一边读取
  193. while(isPlaying && dis.available()>0){
  194. int i = 0;
  195. while(dis.available()>0 && i<buffer.length){
  196. buffer[i] = dis.readShort();
  197. i++;
  198. }
  199. //然后将数据写入到AudioTrack中
  200. track.write(buffer, 0, buffer.length);
  201. }
  202. //播放结束
  203. track.stop();
  204. dis.close();
  205. } catch (Exception e) {
  206. // TODO: handle exception
  207. }
  208. return null;
  209. }
  210. protected void onPostExecute(Void result){
  211. btnPlay.setEnabled(true);
  212. btnFinish.setEnabled(false);
  213. btnStart.setEnabled(true);
  214. btnStop.setEnabled(false);
  215. }
  216. protected void onPreExecute(){
  217. //stateView.setText("正在播放");
  218. btnStart.setEnabled(false);
  219. btnStop.setEnabled(false);
  220. btnPlay.setEnabled(false);
  221. btnFinish.setEnabled(true);
  222. }
  223. }
  224. }

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

Posted on  2012/05/02

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

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

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

用AudioTrack和AudioTrack类可以进行边录边播,可以参考:http://www.2cto.com/kf/201112/113210.html

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

view source print ?
001 package com.ppmeet;
002  
003 import java.io.File;
004 import java.io.FileInputStream;
005 import java.io.FileNotFoundException;
006 import java.io.FileOutputStream;
007 import java.io.IOException;
008 import android.app.Activity;
009 import android.graphics.PixelFormat;
010 import android.media.AudioFormat;
011 import android.media.AudioRecord;
012 import android.media.MediaRecorder;
013 import android.os.Bundle;
014 import android.view.View;
015 import android.view.View.OnClickListener;
016 import android.view.Window;
017 import android.view.WindowManager;
018 import android.widget.Button;
019 /**
020  
021 * class name:TestAudioRecord
022  
023 * class description:用AudioRecord来进行录音
024  
025 * PS:
026  
027 *
028  
029 * @version 1.00 2011/09/21
030  
031 * @author CODYY)peijiangping
032  
033 */
034  
035 public class TestAudioRecord extends Activity {
036  
037 // 音频获取源
038  
039 private int audioSource = MediaRecorder.AudioSource.MIC;
040  
041 // 设置音频采样率,44100是目前的标准,但是某些设备仍然支持22050,16000,11025
042  
043 private static int sampleRateInHz = 44100;
044  
045 // 设置音频的录制的声道CHANNEL_IN_STEREO为双声道,CHANNEL_CONFIGURATION_MONO为单声道
046  
047 private static int channelConfig = AudioFormat.CHANNEL_IN_STEREO;
048  
049 // 音频数据格式:PCM 16位每个样本。保证设备支持。PCM 8位每个样本。不一定能得到设备支持。
050  
051 private static int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
052  
053 // 缓冲区字节大小  www.2cto.com
054  
055 private int bufferSizeInBytes = 0;
056  
057 private Button Start;
058  
059 private Button Stop;
060  
061 private AudioRecord audioRecord;
062  
063 private boolean isRecord = false;// 设置正在录制的状态
064  
065 //AudioName裸音频数据文件
066  
067 private static final String AudioName = "/sdcard/love.raw";
068  
069 //NewAudioName可播放的音频文件
070  
071 private static final String NewAudioName = "/sdcard/new.wav";
072  
073 public void onCreate(Bundle savedInstanceState) {
074  
075 super.onCreate(savedInstanceState);
076  
077 getWindow().setFormat(PixelFormat.TRANSLUCENT);// 让界面横屏
078  
079 requestWindowFeature(Window.FEATURE_NO_TITLE);// 去掉界面标题
080  
081 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
082  
083 WindowManager.LayoutParams.FLAG_FULLSCREEN);
084  
085 // 重新设置界面大小
086  
087 setContentView(R.layout.main);
088  
089 init();
090  
091 }
092  
093 private void init() {
094  
095 Start = (Button) this.findViewById(R.id.start);
096  
097 Stop = (Button) this.findViewById(R.id.stop);
098  
099 Start.setOnClickListener(new TestAudioListener());
100  
101 Stop.setOnClickListener(new TestAudioListener());
102  
103 creatAudioRecord();
104  
105 }
106  
107 private void creatAudioRecord() {
108  
109 // 获得缓冲区字节大小
110  
111 bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz,
112  
113 channelConfig, audioFormat);
114  
115 // 创建AudioRecord对象
116  
117 audioRecord = new AudioRecord(audioSource, sampleRateInHz,
118  
119 channelConfig, audioFormat, bufferSizeInBytes);
120  
121 }
122  
123 class TestAudioListener implements OnClickListener {
124    @Override
125         public void onClick(View v) {
126             if (v == Start) {
127                 startRecord();
128             }
129             if (v == Stop) {
130                 stopRecord();
131             }
132  
133         }
134  
135     }
136  
137     private void startRecord() {
138         audioRecord.startRecording();
139         // 让录制状态为true
140         isRecord = true;
141         // 开启音频文件写入线程
142         new Thread(new AudioRecordThread()).start();
143     }
144  
145     private void stopRecord() {
146         close();
147     }
148  
149     private void close() {
150         if (audioRecord != null) {
151             System.out.println("stopRecord");
152             isRecord = false;//停止文件写入
153             audioRecord.stop();
154             audioRecord.release();//释放资源
155             audioRecord = null;
156         }
157     }
158  
159     class AudioRecordThread implements Runnable {
160         @Override
161         public void run() {
162             writeDateTOFile();//往文件中写入裸数据
163             copyWaveFile(AudioName, NewAudioName);//给裸数据加上头文件
164         }
165     }
166  
167     /**
168      * 这里将数据写入文件,但是并不能播放,因为AudioRecord获得的音频是原始的裸音频,
169      * 如果需要播放就必须加入一些格式或者编码的头信息。但是这样的好处就是你可以对音频的 裸数据进行处理,比如你要做一个爱说话的TOM
170      * 猫在这里就进行音频的处理,然后重新封装 所以说这样得到的音频比较容易做一些音频的处理。
171      */
172     private void writeDateTOFile() {
173         // new一个byte数组用来存一些字节数据,大小为缓冲区大小
174         byte[] audiodata = new byte[bufferSizeInBytes];
175         FileOutputStream fos = null;
176         int readsize = 0;
177         try {
178             File file = new File(AudioName);
179             if (file.exists()) {
180                 file.delete();
181             }
182             fos = new FileOutputStream(file);// 建立一个可存取字节的文件
183         catch (Exception e) {
184             e.printStackTrace();
185         }
186         while (isRecord == true) {
187             readsize = audioRecord.read(audiodata, 0, bufferSizeInBytes);
188             if (AudioRecord.ERROR_INVALID_OPERATION != readsize) {
189                 try {
190                     fos.write(audiodata);
191                 catch (IOException e) {
192                     e.printStackTrace();
193                 }
194             }
195         }
196         try {
197             fos.close();// 关闭写入流
198         catch (IOException e) {
199             e.printStackTrace();
200         }
201     }
202  
203     // 这里得到可播放的音频文件
204     private void copyWaveFile(String inFilename, String outFilename) {
205         FileInputStream in = null;
206         FileOutputStream out = null;
207         long totalAudioLen = 0;
208         long totalDataLen = totalAudioLen + 36;
209         long longSampleRate = sampleRateInHz;
210         int channels = 2;
211         long byteRate = 16 * sampleRateInHz * channels / 8;
212         byte[] data = new byte[bufferSizeInBytes];
213         try {
214             in = new FileInputStream(inFilename);
215             out = new FileOutputStream(outFilename);
216             totalAudioLen = in.getChannel().size();
217             totalDataLen = totalAudioLen + 36;
218             WriteWaveFileHeader(out, totalAudioLen, totalDataLen,
219                     longSampleRate, channels, byteRate);
220             while (in.read(data) != -1) {
221                 out.write(data);
222             }
223             in.close();
224             out.close();
225         catch (FileNotFoundException e) {
226             e.printStackTrace();
227         catch (IOException e) {
228             e.printStackTrace();
229         }
230     }
231  
232     /**
233      * 这里提供一个头信息。插入这些信息就可以得到可以播放的文件。
234      * 为我为啥插入这44个字节,这个还真没深入研究,不过你随便打开一个wav
235      * 音频的文件,可以发现前面的头文件可以说基本一样哦。每种格式的文件都有
236      * 自己特有的头文件。
237      */
238     private void WriteWaveFileHeader(FileOutputStream out, longtotalAudioLen,
239             long totalDataLen, long longSampleRate, int channels,long byteRate)
240             throws IOException {
241         byte[] header = new byte[44];
242         header[0] = 'R'// RIFF/WAVE header
243         header[1] = 'I';
244         header[2] = 'F';
245         header[3] = 'F';
246         header[4] = (byte) (totalDataLen & 0xff);
247         header[5] = (byte) ((totalDataLen >> <img src="http://www.ieulb.com/wp-includes/images/smilies/icon_cool.gif"alt="8)" class="wp-smiley"> & 0xff);
248         header[6] = (byte) ((totalDataLen >> 16) & 0xff);
249         header[7] = (byte) ((totalDataLen >> 24) & 0xff);
250         header[8] = 'W';
251         header[9] = 'A';
252         header[10] = 'V';
253         header[11] = 'E';
254         header[12] = 'f'// 'fmt ' chunk
255         header[13] = 'm';
256         header[14] = 't';
257         header[15] = ' ';
258         header[16] = 16// 4 bytes: size of 'fmt ' chunk
259         header[17] = 0;
260         header[18] = 0;
261         header[19] = 0;
262         header[20] = 1// format = 1
263         header[21] = 0;
264         header[22] = (byte) channels;
265         header[23] = 0;
266         header[24] = (byte) (longSampleRate & 0xff);
267         header[25] = (byte) ((longSampleRate >> <img src="http://www.ieulb.com/wp-includes/images/smilies/icon_cool.gif"alt="8)" class="wp-smiley"> & 0xff);
268         header[26] = (byte) ((longSampleRate >> 16) & 0xff);
269         header[27] = (byte) ((longSampleRate >> 24) & 0xff);
270         header[28] = (byte) (byteRate & 0xff);
271         header[29] = (byte) ((byteRate >> <img src="http://www.ieulb.com/wp-includes/images/smilies/icon_cool.gif"alt="8)" class="wp-smiley"> & 0xff);
272         header[30] = (byte) ((byteRate >> 16) & 0xff);
273         header[31] = (byte) ((byteRate >> 24) & 0xff);
274         header[32] = (byte) (2 16 8); // block align
275         header[33] = 0;
276         header[34] = 16// bits per sample
277         header[35] = 0;
278         header[36] = 'd';
279         header[37] = 'a';
280         header[38] = 't';
281         header[39] = 'a';
282         header[40] = (byte) (totalAudioLen & 0xff);
283         header[41] = (byte) ((totalAudioLen >> <img src="http://www.ieulb.com/wp-includes/images/smilies/icon_cool.gif"alt="8)" class="wp-smiley"> & 0xff);
284         header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
285         header[43] = (byte) ((totalAudioLen >> 24) & 0xff);
286         out.write(header, 044);
287     }
288  
289     @Override
290     protected void onDestroy() {
291         close();
292         super.onDestroy();
293     }
294 }

http://blog.csdn.net/acu/article/details/7287730

因为上一篇博客代码有点太多,就单开了,这两天主要在看android语音录制和压缩转码相关知识,前端时间看见腾讯官方微博宣布,已经开放出即使聊天软件正在等待审批,但这个直接影响电话运营商,能通过的可能性应该不大,但我对这方面的技术很有兴趣,所以就试试看。其中涉及到很多声音方面的处理问题,在android中有两个类可以录制语音:AudioRecord和MediaRecorder,MediaRecorder主要是录制音频并写入文件,而AudioRecord主要是录制音频流,录制的音频流为pcm格式,关于pcm格式可以自行搜索一下,在传输过程中可以转换为amr格式,但没有相关可以类库有点麻烦,另外iphone不支持播放amr格式音频,如果需要跨两个平台可以使用AAC,压缩比也不错,音质也很好,我还没有测试过,网上评议而已。编码方面大家都推荐speex,我看了一下,需要是用System.loadLibrary加载进speex提供的类库。下面记录一下写的一个边录制边播放的一段代码吧

[java]  view plain copy
  1. package voice.hcent.com;
  2. import java.io.IOException;
  3. import android.app.Activity;
  4. import android.os.Bundle;
  5. import android.os.Looper;
  6. import android.os.Process;
  7. import android.util.Log;
  8. import android.view.MotionEvent;
  9. import android.view.View;
  10. import android.widget.Button;
  11. import android.widget.Toast;
  12. import android.media.AudioFormat;
  13. import android.media.AudioManager;
  14. import android.media.AudioRecord;
  15. import android.media.AudioTrack;
  16. import android.media.MediaRecorder;
  17. public class VoiceHcentActivity extends Activity {
  18. static {
  19. System.loadLibrary("media_jni");
  20. }
  21. public int frequency = 8000;
  22. private int rBufferSize, pBufferSize;
  23. private Button startSpeech;
  24. private AudioRecord recorder;
  25. private VoiceSpeech vspeech;
  26. private AudioTrack player;
  27. private boolean stopSpeech = false;
  28. /** Called when the activity is first created. */
  29. @Override
  30. public void onCreate(Bundle savedInstanceState) {
  31. super.onCreate(savedInstanceState);
  32. setContentView(R.layout.main);
  33. init();
  34. test();
  35. }
  36. public void init(){
  37. try{
  38. startSpeech = (Button)findViewById(R.id.StartSpeech);
  39. //设置播放器缓冲区大小
  40. pBufferSize = AudioTrack.getMinBufferSize(frequency, AudioFormat.CHANNEL_CONFIGURATION_MONO,
  41. AudioFormat.ENCODING_PCM_16BIT);
  42. //获取播放器对象
  43. player = new AudioTrack(AudioManager.STREAM_MUSIC, frequency,
  44. AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,
  45. pBufferSize, AudioTrack.MODE_STREAM);
  46. //设置录音缓冲区大小
  47. rBufferSize = AudioRecord.getMinBufferSize(frequency,
  48. AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
  49. //获取录音机对象
  50. recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
  51. frequency, AudioFormat.CHANNEL_CONFIGURATION_MONO,
  52. AudioFormat.ENCODING_PCM_16BIT, rBufferSize);
  53. }catch (Exception e) {
  54. String msg = "ERROR init: "+e.getStackTrace();
  55. VoiceHcentActivity.this.toastMsg(msg);
  56. }
  57. }
  58. /**
  59. * 开始录音
  60. */
  61. public void startRecord(){
  62. stopSpeech = false;
  63. vspeech = new VoiceSpeech();
  64. vspeech.start();
  65. }
  66. /**
  67. * 结束录音
  68. */
  69. public void stopRecord() {
  70. stopSpeech = true;
  71. }
  72. /**
  73. * 开始播放录音
  74. */
  75. public void startPlay(){
  76. //设置播放器音量
  77. player.setStereoVolume(0.7f, 0.7f);
  78. player.play();
  79. }
  80. /**
  81. * 结束播放录音
  82. */
  83. public void stopPlay(){
  84. player.stop();
  85. }
  86. public void test(){
  87. startSpeech.setOnTouchListener(new View.OnTouchListener() {
  88. public boolean onTouch(View arg0, MotionEvent arg1) {
  89. switch (arg1.getAction()) {
  90. case MotionEvent.ACTION_DOWN: //开始说话
  91. startPlay();
  92. startRecord();
  93. toastMsg("starting record!");
  94. break;
  95. case MotionEvent.ACTION_UP: //停止说话
  96. Log.i("hcent", "111");
  97. stopPlay();
  98. Log.i("hcent", "222");
  99. stopRecord();
  100. toastMsg("stoped record!");
  101. break;
  102. default:
  103. break;
  104. }
  105. return false;
  106. }
  107. });
  108. }
  109. public class VoiceSpeech extends Thread{
  110. @Override
  111. public void run() {
  112. super.run();
  113. try {
  114. byte[] tempBuffer, readBuffer = new byte[rBufferSize];
  115. int bufResult = 0;
  116. recorder.startRecording();
  117. while(!stopSpeech){
  118. bufResult = recorder.read(readBuffer, 0, rBufferSize);
  119. if(bufResult>0 && bufResult%2==0){
  120. tempBuffer = new byte[bufResult];
  121. System.arraycopy(readBuffer, 0, tempBuffer, 0, rBufferSize);
  122. player.write(tempBuffer, 0, tempBuffer.length);
  123. }
  124. Log.d("hcent", "get read:"+bufResult+"___"+readBuffer.length);
  125. }
  126. recorder.stop();
  127. Looper.prepare();
  128. VoiceHcentActivity.this.toastMsg("AudioSpeech have ended!");
  129. Looper.loop();
  130. } catch (Exception e) {
  131. String msg = "ERROR AudioRecord: "+e.getStackTrace();
  132. Looper.prepare();
  133. VoiceHcentActivity.this.toastMsg(msg);
  134. Looper.loop();
  135. }
  136. }
  137. }
  138. @Override
  139. protected void onDestroy(){
  140. player.release();
  141. recorder.release();
  142. super.onDestroy();
  143. Process.killProcess(Process.myPid());
  144. }
  145. public void toastMsg(String msg){
  146. Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
  147. Log.e("hcent", msg);
  148. }
  149. }

android 录音相关推荐

  1. Android录音转为MP2的实现

    Android录音转为MP2的实现 利用Android提供的AudioRecord类以及开源编码库twolame,实现了android手机边录音边编码,录音完成直接得到MP2音频文件.由于Androi ...

  2. Android录音下————AudioRecord源码分析

    Android录音下----AudioRecord源码分析 文章目录 Android录音下----AudioRecord源码分析 一.概述 1.主要分析点 2.储备知识 二.getMinBufferS ...

  3. android 录音的格式,Android录音mp3格式实例详解

    Android录音支持的格式有amr.aac,但这两种音频格式在跨平台上表现并不好. MP3显然才是跨平台的最佳选择. 项目地址 实现思路概述 在分析代码前,我们需要明确几个问题 1. 如何最终生成M ...

  4. Android音频录制方案,Android录音,录制其他App播放的声音

    Android录音,录制其他App播放的声音 从Android10(SDK 29)版本开始,可以设置录音App的源为其他App,这样就可以录制其他App播放的声音 此方案有以下注意几点 设置了源为其他 ...

  5. Android录音amr实时转成MP3格式

    文章目录 MP3 录音使用说明 步骤一:下载NDK,并配置(Mac) 步骤二:修改C代码相关路径,编译成so库 步骤三:应用层代码代码调用系统AudioRecord类开始录音 开始录音 start() ...

  6. Android录音并进行本地转码为MP3

    ** Android录音并进行本地转码 ** 通过安卓手机进行录音, 录音后,使用lame进行转码操作 开发中需要使用这个功能,只是一个简单的进行转码的工具,具体的代码信息如下 项目的基本结构图 1. ...

  7. Android录音-SoundTouch移植到Android

    Android录音-SoundTouch移植到Android 文章目录 Android录音-SoundTouch移植到Android 一.SoundTouch介绍 二.移植SoundTouch(And ...

  8. Androidの录音实现

    Androidの录音实现 1. 录音功能需要使用android.media.MediaRecorder来完成,这里我们列出几个重要的使用方法,也是最常用的录音接口. 1.MediaRecorder r ...

  9. Android录音控件

            做项目一直不得空,好不容易腾出时间,赶紧把过往的知识整理一下,以下是做项目时用到的录音控件,在同事写的基础上修改改成,支持后台录音,页面比较简单.写这个组件之前做了简单的调研,如果有不 ...

  10. Android录音并实时转成MP3格式

    资源点我 jni:音频转成MP3格式的C库,将类名或者路径名改成自己项目路径,通过NDK生成so库. mp3library:录音.格式转换的Library,包括so库和工具类. 步骤一:下载NDK,并 ...

最新文章

  1. jieba库 python2.7 安装_Python中文分词工具大合集:安装、使用和测试
  2. Maven自動化構建工具
  3. 恢复WORD2010的默认模板2011-05-03
  4. 基础-简单的深度优先遍历
  5. android系统内置HttpClient库(WebView+ Http(s)URLConnection(ok-http)+ HttpClient(apache-http))
  6. 单分支 两路分支和多分支的if结构_JavaScript学习笔记(二)-- 分支结构
  7. android firefox x86,Firefox 26桌面版加强安全 移动版支持x86
  8. setuna截图怎么放大缩小_实用的高清截图系列小窍门详解,一章带你“真正学会”截图!...
  9. Java 14中对switch的增强,终于可以不写break了
  10. 显示具体化、显示实例化、隐式实例化
  11. HTTP协议:接口测试_发送请求_post方法
  12. 详解jsPlumb这个javascript的可拖动连线库
  13. GOM 登录器源码及编译教程
  14. 【转】如何读学术论文
  15. 好客租房 — 项目发布以及各种服务集群搭建
  16. 量子前沿英雄谱|引领量子科技三十年:斯坦福NTT教授Yoshihisa Yamamoto
  17. uniapp 点击按钮跳转到当前应用的App Store中
  18. python表格数据_用python读取表格数据
  19. 【三 zedboard 】zedboard完整的pynq
  20. 中国各省市区县一览表java处理

热门文章

  1. 电动牙刷——实现简单的1.2V电机控制设计
  2. 全球及中国环境硫化氢监测器行业发展趋势分析与投资规划研究报告2022-2028年
  3. 【文献阅读】小样本学习综述:A Survey on Few-Shot Learning(Y. Wang, 等人,ArXiv,201904)
  4. Android简单音乐盒,添加音乐播放的 上一首 和 下一首 控制
  5. 每日一首古诗, 每日一个桌面壁纸
  6. 花了几万学费学不会php,终于找到大家学不会PHP开发的原因了!
  7. 2021-04-09 接口与内部类
  8. windows7输入法修复
  9. 如何使用excel文档制作翻页电子书?
  10. 服务器系统的流程图,Excel Server Tutorial