final int audioBufferSize = SAMPLE_RATE * CHANNEL_NUM;
// 初始化数组,用于暂存原始音频采样数据
audioBytes = new byte[audioBufferSize];
// 创建一个定时任务,任务的内容是定时做音频采样,再把采样数据交给帧录制器处理
sampleTask = new ScheduledThreadPoolExecutor(1);
}
/**
- 程序结束前,释放音频相关的资源
*/
public void releaseOutputResource() {
// 结束的标志,避免采样的代码在whlie循环中不退出
isFinish = true;
// 结束定时任务
sampleTask.shutdown();
// 停止数据线
line.stop();
// 关闭数据线
line.close();
}
/**
-
启动定时任务,每秒执行一次,采集音频数据给帧录制器
-
@param frameRate
*/
public void startSample(double frameRate) {
// 启动定时任务,每秒执行一次,采集音频数据给帧录制器
sampleTask.scheduleAtFixedRate((Runnable) new Runnable() {
@Override
public void run() {
try
{
int nBytesRead = 0;
while (nBytesRead == 0 && !isFinish) {
// 音频数据是从数据线中取得的
nBytesRead = line.read(audioBytes, 0, line.available());
}
// 如果nBytesRead<1,表示isFinish标志被设置true,此时该结束了
if (nBytesRead<1) {
return;
}
// 采样数据是16比特,也就是2字节,对应的数据类型就是short,
// 所以准备一个short数组来接受原始的byte数组数据
// short是2字节,所以数组长度就是byte数组长度的二分之一
int nSamplesRead = nBytesRead / 2;
short[] samples = new short[nSamplesRead];
// 两个byte放入一个short中的时候,谁在前谁在后?这里用LITTLE_ENDIAN指定拜访顺序,
ByteBuffer.wrap(audioBytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(samples);
// 将short数组转为ShortBuffer对象,因为帧录制器的入参需要该类型
ShortBuffer sBuff = ShortBuffer.wrap(samples, 0, nSamp