使用AudioRecord和AudioTrack来录制和播放音频
1.使用AudioRecord录制原始音频
除了通过意图启动录音机和使用MediaRecorder之外,Android还提供了第三种方法来捕获音频:使用成为AudioRecord的类。AudioRecord是三种方法里最灵活的(因为允许访问原始音频流),但是它拥有的内置功能也是最少的,如不会自动压缩音频。
使用AudioRecord的基础知识非常简单。我们只需要构造一个AudioRecord类型的对象,并传入各种不同的配置参数。
需要指定的第一个值是音频源。下面使用的值与用于MediaRecorder的值相同,其在MediaRecorder.AudioSource中定义。实际上,这意味着可以使用MediaRecorder.AudioSource.MIC。
int audioSource=MediaRecorder.AudioSource.MIC;
录制的采样率
int frequency = 11025;
捕获的音频通道的数量
-
AudioFormat.CHANNEL_CONFIGURATION_MONO;//channelConfiguration
-
AudioFormat.CHANNEL_CONFIGURATION_STEREO;
-
AudioFormat.CHANNEL_CONFIGURATION_INVALID;
-
AudioFormat.CHANNEL_CONFIGURATION_DEFAULT;
音频的格式
-
AudioFormat.ENCODING_DEFAULT;//audioEncoding
-
AudioFormat.ENCODING_INVALID;
-
AudioFormat.ENCODING_PCM_16BIT;
-
AudioFormat.ENCODING_PCM_8BIT;
最后,需要指定的是第五个值是缓冲区大小。实际上可以查询AudioRecord类以获得最小缓冲区大小,查询方式是调用getMinBufferSize静态方法,同时传入采样率、通道配置以及音频格式。
int bufferSize = AudioTrack.getMinBufferSize(frequency,channelConfiguration, audioEncoding);
-
AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, frequency,
-
channelConfiguration, audioEncoding, bufferSize);
并不保存捕获的音频
-
File path = new File(
-
Environment.getExternalStorageDirectory().getAbsolutePath()
-
+ "/AudioRecorder/files/");
-
path.mkdirs();
-
try
-
{
-
recordingFile = File.createTempFile("recording", ".pcm", path);
-
} catch (IOException e)
-
{
-
throw new RuntimeException("Couldn't create file on SD card", e);
-
}
性能和便利
-
DataOutputStream dos = new DataOutputStream(
-
new BufferedOutputStream(new FileOutputStream(
-
recordingFile)));
将采用比AudioRecord对象的缓冲区更小的数组,从而在确保将音频读出来之前缓冲区没有被填满。
short[] audiodata = new short[bufferSize / 4];
-
while (isRecording)
-
{
-
int bufferReadResult = audioRecord.read(buffer, 0,bufferSize);
-
for (int i = 0; i < bufferReadResult; i++)
-
{
-
dos.writeShort(buffer[i]);
-
}
-
}
2.使用AudioTrack来播放原始音频
AudioTrack允许播放AudioRecord捕获的原始音频类,而它们并不能使用MediaPlayer对象播放。
为了构造一个AudioTrack对象,需要传入以下一系列配置变量来描述待播放的音频
第一个参数是流类型。可能的值定义为AudioManager类的常量。例如
AudioManager.STREAM_MUSIC//正常播放音乐的音频流
第三个参数是通道配置。可能的值与构造AudioRecord的值相同。
第四个参数是音频格式。可能的值与构造AudioRecord的值相同。
第五个参数是将在对象中用于存储音频的缓冲区大小。为了确定使用最小的缓冲区大小,可以调用getMinBufferSize方法,同时传入采样率、通道配置和音频格式。
最后一个参数是模式。可能的值定义为AudioTrack类中的常量。
-
AudioTrack.MODE_STATIC://在播放发生之前将所有的音频数据转移到AudioTrack对象
-
AudioTrack.MODE_STREAM://在播放的同时将音频数据持续地转移到AudioTrack对象。
-
AudioTrack audioTrack = new AudioTrack(
-
AudioManager.STREAM_MUSIC, frequency,
-
channelConfiguration, audioEncoding, bufferSize,
-
AudioTrack.MODE_STREAM);
-
DataInputStream dis = new DataInputStream(
-
new BufferedInputStream(new FileInputStream(
-
recordingFile)));
-
audioTrack.play();
-
-
while (isPlaying && dis.available() > 0)
-
{
-
int i = 0;
-
while (dis.available() > 0 && i < audiodata.length)
-
{
-
audiodata[i] = dis.readShort();
-
i++;
-
}
-
audioTrack.write(audiodata, 0, audiodata.length);
-
}
-
-
dis.close();
-
-
public class AltAudioRecorder extends Activity implements OnClickListener
-
{
-
-
RecordAudio recordTask;
-
PlayAudio playTask;
-
-
Button startRecordingButton, stopRecordingButton, startPlaybackButton,
-
stopPlaybackButton;
-
TextView statusText;
-
-
File recordingFile;
-
-
boolean isRecording = false;
-
boolean isPlaying = false;
-
-
int frequency = 11025;
-
int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
-
int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
-
-
@Override
-
public void onCreate(Bundle savedInstanceState)
-
{
-
super.onCreate(savedInstanceState);
-
setContentView(R.layout.main);
-
-
statusText = (TextView) this.findViewById(R.id.StatusTextView);
-
-
startRecordingButton = (Button) this
-
.findViewById(R.id.StartRecordingButton);
-
stopRecordingButton = (Button) this
-
.findViewById(R.id.StopRecordingButton);
-
startPlaybackButton = (Button) this
-
.findViewById(R.id.StartPlaybackButton);
-
stopPlaybackButton = (Button) this
-
.findViewById(R.id.StopPlaybackButton);
-
-
startRecordingButton.setOnClickListener(this);
-
stopRecordingButton.setOnClickListener(this);
-
startPlaybackButton.setOnClickListener(this);
-
stopPlaybackButton.setOnClickListener(this);
-
-
stopRecordingButton.setEnabled(false);
-
startPlaybackButton.setEnabled(false);
-
stopPlaybackButton.setEnabled(false);
-
-
File path = new File(
-
Environment.getExternalStorageDirectory().getAbsolutePath()
-
+ "/Android/data/AudioRecorder/files/");
-
path.mkdirs();
-
try
-
{
-
recordingFile = File.createTempFile("recording", ".pcm", path);
-
} catch (IOException e)
-
{
-
throw new RuntimeException("Couldn't create file on SD card", e);
-
}
-
}
-
-
public void onClick(View v)
-
{
-
if (v == startRecordingButton)
-
{
-
record();
-
} else if (v == stopRecordingButton)
-
{
-
stopRecording();
-
} else if (v == startPlaybackButton)
-
{
-
play();
-
} else if (v == stopPlaybackButton)
-
{
-
stopPlaying();
-
}
-
}
-
-
public void play()
-
{
-
startPlaybackButton.setEnabled(true);
-
-
playTask = new PlayAudio();
-
playTask.execute();
-
-
stopPlaybackButton.setEnabled(true);
-
}
-
-
public void stopPlaying()
-
{
-
isPlaying = false;
-
stopPlaybackButton.setEnabled(false);
-
startPlaybackButton.setEnabled(true);
-
}
-
-
public void record()
-
{
-
startRecordingButton.setEnabled(false);
-
stopRecordingButton.setEnabled(true);
-
-
// For Fun
-
startPlaybackButton.setEnabled(true);
-
-
recordTask = new RecordAudio();
-
recordTask.execute();
-
}
-
-
public void stopRecording()
-
{
-
isRecording = false;
-
}
-
-
private class PlayAudio extends AsyncTask<Void, Integer, Void>
-
{
-
@Override
-
protected Void doInBackground(Void... params)
-
{
-
isPlaying = true;
-
-
int bufferSize = AudioTrack.getMinBufferSize(frequency,
-
channelConfiguration, audioEncoding);
-
short[] audiodata = new short[bufferSize / 4];
-
-
try
-
{
-
DataInputStream dis = new DataInputStream(
-
new BufferedInputStream(new FileInputStream(
-
recordingFile)));
-
-
AudioTrack audioTrack = new AudioTrack(
-
AudioManager.STREAM_MUSIC, frequency,
-
channelConfiguration, audioEncoding, bufferSize,
-
AudioTrack.MODE_STREAM);
-
-
audioTrack.play();
-
-
while (isPlaying && dis.available() > 0)
-
{
-
int i = 0;
-
while (dis.available() > 0 && i < audiodata.length)
-
{
-
audiodata[i] = dis.readShort();
-
i++;
-
}
-
audioTrack.write(audiodata, 0, audiodata.length);
-
}
-
-
dis.close();
-
-
startPlaybackButton.setEnabled(false);
-
stopPlaybackButton.setEnabled(true);
-
-
} catch (Throwable t)
-
{
-
Log.e("AudioTrack", "Playback Failed");
-
}
-
-
return null;
-
}
-
}
-
-
private class RecordAudio extends AsyncTask<Void, Integer, Void>
-
{
-
@Override
-
protected Void doInBackground(Void... params)
-
{
-
isRecording = true;
-
-
try
-
{
-
DataOutputStream dos = new DataOutputStream(
-
new BufferedOutputStream(new FileOutputStream(
-
recordingFile)));
-
-
int bufferSize = AudioRecord.getMinBufferSize(frequency,
-
channelConfiguration, audioEncoding);
-
-
AudioRecord audioRecord = new AudioRecord(
-
MediaRecorder.AudioSource.MIC, frequency,
-
channelConfiguration, audioEncoding, bufferSize);
-
-
short[] buffer = new short[bufferSize];
-
audioRecord.startRecording();
-
-
int r = 0;
-
while (isRecording)
-
{
-
int bufferReadResult = audioRecord.read(buffer, 0,
-
bufferSize);
-
for (int i = 0; i < bufferReadResult; i++)
-
{
-
dos.writeShort(buffer[i]);
-
}
-
-
publishProgress(new Integer(r));
-
r++;
-
}
-
-
audioRecord.stop();
-
dos.close();
-
} catch (Throwable t)
-
{
-
Log.e("AudioRecord", "Recording Failed");
-
}
-
-
return null;
-
}
-
-
protected void onProgressUpdate(Integer... progress)
-
{
-
statusText.setText(progress[0].toString());
-
}
-
-
protected void onPostExecute(Void result)
-
{
-
startRecordingButton.setEnabled(true);
-
stopRecordingButton.setEnabled(false);
-
startPlaybackButton.setEnabled(true);
-
}
-
}
-
}
文章来源: panda1234lee.blog.csdn.net,作者:panda1234lee,版权归原作者所有,如需转载,请联系作者。
原文链接:panda1234lee.blog.csdn.net/article/details/8774182
- 点赞
- 收藏
- 关注作者
评论(0)