添加片段和简单的UI元素会大大降低音频处理算法的速度

时间:2017-04-02 13:14:09

标签: android audio

我是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.javaComplex.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;
        }
    }

2 个答案:

答案 0 :(得分:2)

我不确定为什么存在滞后,但是你可以避免这个问题:运行两个异步任务,任务1记录数据并将其存储在一个数组中。第二个异步任务从这个数组中获取块并进行FFT。

答案 1 :(得分:1)

AsyncTask以较低的优先级运行,以确保UI线程保持响应。因此,AsyncTask

中的UI越多,延迟越多

由于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