我是android的新手,我正在尝试构建一个用于录制音频的APP,进行FFT以获得频谱。
完整音频的缓冲区大小为155 * 2048 即155 * AudioRecord.getMinBufferSize(44100,mono_channel,PCM_16bit)
记录器中的每个块都是2048个短路,我将short类型转换为double类型并将其传递给FFT库。该库返回了我将用于构建频谱的实部和虚部。然后我将每个块附加到一个数组。
现在问题在于:
在app 1中,没有UI元素或片段只是一个简单的基本按钮,它连接到一个执行异步任务的侦听器,用于从Audio.Recorder读取块,并按块进行FFT(每个块= 2048短)。对于采样率为44100的155个块的这个过程(记录和FFT)应该花费7秒(2048 * 155/44100),但任务大约需要9秒,这是2秒的延迟(这是可以接受的)。
在app 2中有7个片段,其中包含登录和注册屏幕,其中每个片段彼此分开并链接到主要活动。这里相同的代码在40-45秒内完成155 * 2048个块的任务(记录和fft),这意味着滞后时间高达33-37秒。这种滞后对我来说太过分了。应用程序2中存在如此多延迟的原因是什么?如何减少它?
以下是FFT库代码和复杂类型代码 FFT.java,Complex.java
我的申请代码
private boolean is_recording = false;
private AudioRecord recorder = null;
int minimum_buffer_size = AudioRecord.getMinBufferSize(SAMPLE_RATE,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT);
int bufferSize = 155 * AudioRecord.getMinBufferSize(SAMPLE_RATE,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT);
private static final int SAMPLE_RATE = 44100;
private Thread recordingThread = null;
short[] audioBuffer = new short[bufferSize];
MainTask recordTask;
double finalData[];
Complex[] fftArray;
boolean recieved = false;
int data_trigger_point = 10;
int trigger_count = 0;
double previous_level_1 ;
double previous_level_2 ;
double previous_level_3 ;
int no_of_chunks_to_be_send = 30;
int count = 0;
short[] sendingBuffer = new short[minimum_buffer_size * no_of_chunks_to_be_send];
public static final int RequestPermissionCode = 1;
mButton = (ImageButton) view.findViewById(R.id.submit);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (is_recording) {
mButton.setBackgroundResource(R.drawable.play);
stopRecodringWithoutTone();
}
else {
mButton.setBackgroundResource(R.drawable.wait);
is_recording = true;
recordTask = new MainTask();
recordTask.execute();
}
}
});
public class MainTask extends AsyncTask<Void, int[], Void> {
@Override
protected Void doInBackground(Void... arg0) {
try {
recorder = new AudioRecord(
MediaRecorder.AudioSource.DEFAULT,
SAMPLE_RATE,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT,
minimum_buffer_size);
recorder.startRecording();
short[] buffer_recording = new short[minimum_buffer_size];
int recieve_counter = 0;
while (is_recording) {
if (count < bufferSize) {
int bufferReadResult = recorder.read(buffer_recording, 0, minimum_buffer_size);
System.arraycopy(buffer_recording, 0, audioBuffer, count, buffer_recording.length);
count += bufferReadResult;
System.out.println(count);
finalData = convert_to_double(buffer_recording);
int [] magnitudes = processFFT(finalData);
}
else {
stopRecording();
}
}
}
catch (Throwable t) {
t.printStackTrace();
Log.e("V1", "Recording Failed");
}
return null;
}
@Override
protected void onProgressUpdate(int[]... magnitudes) {
}
}
private int[] processFFT(double [] data){
Complex[] fftTempArray = new Complex[finalData.length];
for (int i=0; i<finalData.length; i++)
{
fftTempArray[i] = new Complex(finalData[i], 0);
}
fftArray = FFT.fft(fftTempArray);
int [] magnitude = new int[fftArray.length/2];
for (int i=0; i< fftArray.length/2; i++) {
magnitude[i] = (int) fftArray[i].abs();
}
return magnitude;
}
private double[] convert_to_double(short data[]) {
double[] transformed = new double[data.length];
for (int j=0;j<data.length;j++) {
transformed[j] = (double)data[j];
}
return transformed;
}
private void stopRecording() {
if (null != recorder) {
recorder.stop();
postAudio(audioBuffer);
recorder.release();
is_recording = false;
recorder = null;
recordingThread = null;
count = 0;
recieved = false;
}
}
答案 0 :(得分:2)
我不确定为什么存在滞后,但是你可以避免这个问题:运行两个异步任务,任务1记录数据并将其存储在一个数组中。第二个异步任务从这个数组中获取块并进行FFT。
答案 1 :(得分:1)
AsyncTask以较低的优先级运行,以确保UI线程保持响应。因此,AsyncTask
由于Android使用的Linux cgroup安排了BACKGROUND
线程优先级,因此您将面临延迟。
如果你选择THREAD_PRIORITY_BACKGROUND + THREAD_PRIORITY_MORE_FAVORABLE
你的帖子将被提升10%的限制。
所以你的代码看起来像这样:
protected final Void doInBackground(Void... arg0) {
Process.setThreadPriority(THREAD_PRIORITY_BACKGROUND + THREAD_PRIORITY_MORE_FAVORABLE);
...//your code here
}
如果由于某些原因导致doInBackground
的下一次调用无效,因为默认情况下Android会重置优先级。在这种情况下,请尝试使用Process.THREAD_PRIORITY_FOREGROUND