使用AudioRecord和AudioTrack来录制和播放音频

举报
ShaderJoy 发表于 2021/12/29 23:59:51 2021/12/29
【摘要】 1.使用AudioRecord录制原始音频 除了通过意图启动录音机和使用MediaRecorder之外,Android还提供了第三种方法来捕获音频:使用成为AudioRecord的类。AudioRecord是三种方法里最灵活的(因为允许访问原始音频流),但是它拥有的内置功能也是最少的,如不会自动压缩音频。 使用AudioRecord...
1.使用AudioRecord录制原始音频

除了通过意图启动录音机和使用MediaRecorder之外,Android还提供了第三种方法来捕获音频:使用成为AudioRecord的类。AudioRecord是三种方法里最灵活的(因为允许访问原始音频流),但是它拥有的内置功能也是最少的,如不会自动压缩音频。

使用AudioRecord的基础知识非常简单。我们只需要构造一个AudioRecord类型的对象,并传入各种不同的配置参数。

需要指定的第一个值是音频源。下面使用的值与用于MediaRecorder的值相同,其在MediaRecorder.AudioSource中定义。实际上,这意味着可以使用MediaRecorder.AudioSource.MIC。

int audioSource=MediaRecorder.AudioSource.MIC;
 
录制的采样率

int frequency = 11025;
 

捕获的音频通道的数量

  
  1. AudioFormat.CHANNEL_CONFIGURATION_MONO;//channelConfiguration
  2. AudioFormat.CHANNEL_CONFIGURATION_STEREO;
  3. AudioFormat.CHANNEL_CONFIGURATION_INVALID;
  4. AudioFormat.CHANNEL_CONFIGURATION_DEFAULT;
音频的格式


  
  1. AudioFormat.ENCODING_DEFAULT;//audioEncoding
  2. AudioFormat.ENCODING_INVALID;
  3. AudioFormat.ENCODING_PCM_16BIT;
  4. AudioFormat.ENCODING_PCM_8BIT;

最后,需要指定的是第五个值是缓冲区大小。实际上可以查询AudioRecord类以获得最小缓冲区大小,查询方式是调用getMinBufferSize静态方法,同时传入采样率、通道配置以及音频格式。

int bufferSize = AudioTrack.getMinBufferSize(frequency,channelConfiguration, audioEncoding);
 


  
  1. AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, frequency,
  2. channelConfiguration, audioEncoding, bufferSize);
并不保存捕获的音频


  
  1. File path = new File(
  2. Environment.getExternalStorageDirectory().getAbsolutePath()
  3. + "/AudioRecorder/files/");
  4. path.mkdirs();
  5. try
  6. {
  7. recordingFile = File.createTempFile("recording", ".pcm", path);
  8. } catch (IOException e)
  9. {
  10. throw new RuntimeException("Couldn't create file on SD card", e);
  11. }
性能和便利


  
  1. DataOutputStream dos = new DataOutputStream(
  2. new BufferedOutputStream(new FileOutputStream(
  3. recordingFile)));
将采用比AudioRecord对象的缓冲区更小的数组,从而在确保将音频读出来之前缓冲区没有被填满。

short[] audiodata = new short[bufferSize / 4];
 


  
  1. while (isRecording)
  2. {
  3. int bufferReadResult = audioRecord.read(buffer, 0,bufferSize);
  4. for (int i = 0; i < bufferReadResult; i++)
  5. {
  6. dos.writeShort(buffer[i]);
  7. }
  8. }


2.使用AudioTrack来播放原始音频

AudioTrack允许播放AudioRecord捕获的原始音频类,而它们并不能使用MediaPlayer对象播放。

为了构造一个AudioTrack对象,需要传入以下一系列配置变量来描述待播放的音频

第一个参数是流类型。可能的值定义为AudioManager类的常量。例如

AudioManager.STREAM_MUSIC//正常播放音乐的音频流
 

第三个参数是通道配置。可能的值与构造AudioRecord的值相同。

第四个参数是音频格式。可能的值与构造AudioRecord的值相同。

第五个参数是将在对象中用于存储音频的缓冲区大小。为了确定使用最小的缓冲区大小,可以调用getMinBufferSize方法,同时传入采样率、通道配置和音频格式。

最后一个参数是模式。可能的值定义为AudioTrack类中的常量。


  
  1. AudioTrack.MODE_STATIC://在播放发生之前将所有的音频数据转移到AudioTrack对象
  2. AudioTrack.MODE_STREAM://在播放的同时将音频数据持续地转移到AudioTrack对象。

  
  1. AudioTrack audioTrack = new AudioTrack(
  2. AudioManager.STREAM_MUSIC, frequency,
  3. channelConfiguration, audioEncoding, bufferSize,
  4. AudioTrack.MODE_STREAM);


  
  1. DataInputStream dis = new DataInputStream(
  2. new BufferedInputStream(new FileInputStream(
  3. recordingFile)));


  
  1. audioTrack.play();
  2. while (isPlaying && dis.available() > 0)
  3. {
  4. int i = 0;
  5. while (dis.available() > 0 && i < audiodata.length)
  6. {
  7. audiodata[i] = dis.readShort();
  8. i++;
  9. }
  10. audioTrack.write(audiodata, 0, audiodata.length);
  11. }
  12. dis.close();



  
  1. public class AltAudioRecorder extends Activity implements OnClickListener
  2. {
  3. RecordAudio recordTask;
  4. PlayAudio playTask;
  5. Button startRecordingButton, stopRecordingButton, startPlaybackButton,
  6. stopPlaybackButton;
  7. TextView statusText;
  8. File recordingFile;
  9. boolean isRecording = false;
  10. boolean isPlaying = false;
  11. int frequency = 11025;
  12. int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
  13. int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
  14. @Override
  15. public void onCreate(Bundle savedInstanceState)
  16. {
  17. super.onCreate(savedInstanceState);
  18. setContentView(R.layout.main);
  19. statusText = (TextView) this.findViewById(R.id.StatusTextView);
  20. startRecordingButton = (Button) this
  21. .findViewById(R.id.StartRecordingButton);
  22. stopRecordingButton = (Button) this
  23. .findViewById(R.id.StopRecordingButton);
  24. startPlaybackButton = (Button) this
  25. .findViewById(R.id.StartPlaybackButton);
  26. stopPlaybackButton = (Button) this
  27. .findViewById(R.id.StopPlaybackButton);
  28. startRecordingButton.setOnClickListener(this);
  29. stopRecordingButton.setOnClickListener(this);
  30. startPlaybackButton.setOnClickListener(this);
  31. stopPlaybackButton.setOnClickListener(this);
  32. stopRecordingButton.setEnabled(false);
  33. startPlaybackButton.setEnabled(false);
  34. stopPlaybackButton.setEnabled(false);
  35. File path = new File(
  36. Environment.getExternalStorageDirectory().getAbsolutePath()
  37. + "/Android/data/AudioRecorder/files/");
  38. path.mkdirs();
  39. try
  40. {
  41. recordingFile = File.createTempFile("recording", ".pcm", path);
  42. } catch (IOException e)
  43. {
  44. throw new RuntimeException("Couldn't create file on SD card", e);
  45. }
  46. }
  47. public void onClick(View v)
  48. {
  49. if (v == startRecordingButton)
  50. {
  51. record();
  52. } else if (v == stopRecordingButton)
  53. {
  54. stopRecording();
  55. } else if (v == startPlaybackButton)
  56. {
  57. play();
  58. } else if (v == stopPlaybackButton)
  59. {
  60. stopPlaying();
  61. }
  62. }
  63. public void play()
  64. {
  65. startPlaybackButton.setEnabled(true);
  66. playTask = new PlayAudio();
  67. playTask.execute();
  68. stopPlaybackButton.setEnabled(true);
  69. }
  70. public void stopPlaying()
  71. {
  72. isPlaying = false;
  73. stopPlaybackButton.setEnabled(false);
  74. startPlaybackButton.setEnabled(true);
  75. }
  76. public void record()
  77. {
  78. startRecordingButton.setEnabled(false);
  79. stopRecordingButton.setEnabled(true);
  80. // For Fun
  81. startPlaybackButton.setEnabled(true);
  82. recordTask = new RecordAudio();
  83. recordTask.execute();
  84. }
  85. public void stopRecording()
  86. {
  87. isRecording = false;
  88. }
  89. private class PlayAudio extends AsyncTask<Void, Integer, Void>
  90. {
  91. @Override
  92. protected Void doInBackground(Void... params)
  93. {
  94. isPlaying = true;
  95. int bufferSize = AudioTrack.getMinBufferSize(frequency,
  96. channelConfiguration, audioEncoding);
  97. short[] audiodata = new short[bufferSize / 4];
  98. try
  99. {
  100. DataInputStream dis = new DataInputStream(
  101. new BufferedInputStream(new FileInputStream(
  102. recordingFile)));
  103. AudioTrack audioTrack = new AudioTrack(
  104. AudioManager.STREAM_MUSIC, frequency,
  105. channelConfiguration, audioEncoding, bufferSize,
  106. AudioTrack.MODE_STREAM);
  107. audioTrack.play();
  108. while (isPlaying && dis.available() > 0)
  109. {
  110. int i = 0;
  111. while (dis.available() > 0 && i < audiodata.length)
  112. {
  113. audiodata[i] = dis.readShort();
  114. i++;
  115. }
  116. audioTrack.write(audiodata, 0, audiodata.length);
  117. }
  118. dis.close();
  119. startPlaybackButton.setEnabled(false);
  120. stopPlaybackButton.setEnabled(true);
  121. } catch (Throwable t)
  122. {
  123. Log.e("AudioTrack", "Playback Failed");
  124. }
  125. return null;
  126. }
  127. }
  128. private class RecordAudio extends AsyncTask<Void, Integer, Void>
  129. {
  130. @Override
  131. protected Void doInBackground(Void... params)
  132. {
  133. isRecording = true;
  134. try
  135. {
  136. DataOutputStream dos = new DataOutputStream(
  137. new BufferedOutputStream(new FileOutputStream(
  138. recordingFile)));
  139. int bufferSize = AudioRecord.getMinBufferSize(frequency,
  140. channelConfiguration, audioEncoding);
  141. AudioRecord audioRecord = new AudioRecord(
  142. MediaRecorder.AudioSource.MIC, frequency,
  143. channelConfiguration, audioEncoding, bufferSize);
  144. short[] buffer = new short[bufferSize];
  145. audioRecord.startRecording();
  146. int r = 0;
  147. while (isRecording)
  148. {
  149. int bufferReadResult = audioRecord.read(buffer, 0,
  150. bufferSize);
  151. for (int i = 0; i < bufferReadResult; i++)
  152. {
  153. dos.writeShort(buffer[i]);
  154. }
  155. publishProgress(new Integer(r));
  156. r++;
  157. }
  158. audioRecord.stop();
  159. dos.close();
  160. } catch (Throwable t)
  161. {
  162. Log.e("AudioRecord", "Recording Failed");
  163. }
  164. return null;
  165. }
  166. protected void onProgressUpdate(Integer... progress)
  167. {
  168. statusText.setText(progress[0].toString());
  169. }
  170. protected void onPostExecute(Void result)
  171. {
  172. startRecordingButton.setEnabled(true);
  173. stopRecordingButton.setEnabled(false);
  174. startPlaybackButton.setEnabled(true);
  175. }
  176. }
  177. }




文章来源: panda1234lee.blog.csdn.net,作者:panda1234lee,版权归原作者所有,如需转载,请联系作者。

原文链接:panda1234lee.blog.csdn.net/article/details/8774182

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。