Asynctask和Handler Thread同时进行?

时间:2013-10-31 13:21:18

标签: android android-asynctask handler fft

我正在使用FFT来实时分析进入麦克风的音频,这在使用asyntask时似乎才有效。我还需要在后台运行另一个线程。这两个项目只需要运行3秒钟。

如果我尝试两者兼顾,ANR会超时。有没有办法让这些一起工作?

我不需要FFT进入asynctask,因为我只写文件而不是显示器。但是,当我从异步任务中提取FFT时,我的toTransform数组会出错。

感谢任何帮助。

public class SoundRecord extends Activity implements OnClickListener {

boolean started = false;
int sampleRate = 8000;

// originally from http://marblemice.blogspot.com/2010/04/generate-and-play-tone-in-android.html
// and modified by Steve Pomeroy <steve@staticfree.info>
private final int duration = 3; // seconds
private final int numSamples = duration * sampleRate;
private final double sample[] = new double[numSamples];
private final double freqOfTone = 1500; // hz
private final byte generatedSnd[] = new byte[2 * numSamples];

Handler handler = new Handler();
Timer timer = new Timer();

public int channelConfiguration = AudioFormat.CHANNEL_IN_MONO; 
public int audioEncoding = AudioFormat.ENCODING_PCM_16BIT; 

//FFT
private RealDoubleFFT transformer;
int blockSize = 256;
Button startStopButton;
int frequency = 8000;
double freq;
String freqValue;
int bufferSize = AudioRecord.getMinBufferSize(frequency,
        channelConfiguration, audioEncoding);

AudioRecord audioRecord = new AudioRecord(
        MediaRecorder.AudioSource.MIC, frequency,
        channelConfiguration, audioEncoding, bufferSize);

GetFrequency recordTask;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_SoundRecord);

    Button button = (Button) findViewById(R.id.start);
    button.setOnClickListener(this);
}




@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.SoundRecord, menu);
    return true;
}

@Override
public void onClick(View v) {
    if (started) {
        started = false;
        recordTask.cancel(true);
    } else {
        final Thread soundout = new Thread(new Runnable() {
            public void run() {
                genTone();
                handler.post(new Runnable() {

                    public void run() {
                        playSound();
                    }
                });
            }
        });
        soundout.start();


    //Analyze frequency
    recordTask = new GetFrequency();
        try {
            recordTask.get();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ExecutionException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


    }
}

void genTone(){
    // fill out the array
    for (int i = 0; i < numSamples; ++i) {
        sample[i] = Math.sin(2 * Math.PI * i / (sampleRate/freqOfTone));
    }

    // convert to 16 bit pcm sound array
    // assumes the sample buffer is normalised.
    int idx = 0;
    for (final double dVal : sample) {
        // scale to maximum amplitude
        final short val = (short) ((dVal * 32767));
        // in 16 bit wav PCM, first byte is the low order byte
        generatedSnd[idx++] = (byte) (val & 0x00ff);
        generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);

    }
}

void playSound(){
    final AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
            sampleRate, AudioFormat.CHANNEL_OUT_MONO,
            AudioFormat.ENCODING_PCM_16BIT, numSamples,
            AudioTrack.MODE_STATIC);
    audioTrack.write(generatedSnd, 0, generatedSnd.length);
    audioTrack.play();
}

private class GetFrequency extends AsyncTask<Void, double[], Void> {
    @Override
    protected Void doInBackground(Void... params) {
        try {
            short[] buffer = new short[blockSize];
            double[] toTransform = new double[blockSize];

            audioRecord.startRecording();

            while (started) {
                int bufferReadResult = audioRecord.read(buffer, 0, blockSize);

                for (int i = 0; i < blockSize && i < bufferReadResult; i++) {
                    toTransform[i] = (double) buffer[i] / 32768.0; // signed // 16 // bit

                }
                transformer.ft(toTransform);
                publishProgress(toTransform); 
                timer.schedule(new TimerTask() {
                 public void run() {
                     handler.post(new Runnable() {
                         public void run() {
                             audioRecord.stop();
                         }
                     });
                    }
                }, 3000); //Stop after 3 seconds
            }
        } catch (Throwable t) {
            Log.e("AudioRecord", "Recording Failed");
        }

        return null;
    }

    protected void onProgressUpdate(double[]... toTransform) {
        File freqFile = new File("/mnt/sdcard/Test APKs/frequency.file");
        File magFile = new File("/mnt/sdcard/Test APKs/magnitude.file");
        int blockSize = 256;
        double[] audioDataDoubles = new double[(blockSize*2)];
        String mydate = java.text.DateFormat.getDateTimeInstance().format(Calendar.getInstance().getTime());

        if (!freqFile.exists())
        {
           try {
              freqFile.createNewFile();
           } catch (IOException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
           }
        }
        if (!magFile.exists())
        {
           try {
              magFile.createNewFile();
           } catch (IOException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
           }
        }

        for ( int x = 0; x < toTransform[0].length; x++) {
            audioDataDoubles[2*x] = toTransform[0][x];
            audioDataDoubles[(2*x)+1] = 0.0;
        }
        double[] re = new double[blockSize];
        double[] im = new double[blockSize];
        double[] magnitude = new double[blockSize];

        // Calculate the Real and imaginary and Magnitude.
        for(int i = 0; i < blockSize; i++){
            // real is stored in first part of array
            re[i] = audioDataDoubles[i*2];
            // imaginary is stored in the sequential part
            im[i] = audioDataDoubles[(2*i)+1];
            // magnitude is calculated by the square root of (imaginary^2 + real^2)
            magnitude[i] = Math.sqrt((re[i] * re[i]) + (im[i]*im[i]));
        }

        double peak = -1.0; 
        // Get the largest magnitude peak
        for(int i = 0; i < blockSize; i++){
            if(peak < magnitude[i])
                peak = magnitude[i];
            String magValue = String.valueOf(peak);
            try {
                BufferedWriter buf = new BufferedWriter(new FileWriter(magFile, true));
                buf.append(mydate + " - " + magValue);
                buf.newLine();
                buf.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
             }
        }
        // calculated the frequency
        freq = (frequency * peak)/blockSize; 
        freqValue = String.valueOf(freq);
        //Toast.makeText(Main.this, freqValue, Toast.LENGTH_SHORT).show();
        try {
            BufferedWriter buf = new BufferedWriter(new FileWriter(freqFile, true));
            buf.append(mydate + " - " + freqValue);
            buf.newLine();
            buf.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

}

1 个答案:

答案 0 :(得分:0)

所有复杂的操作(fft,文件编写等)必须在一个单独的线程中完成。它可能是asynctask或线程,或者更好的是,单独的线程服务。