现场录音和播放的Andr​​oid和螺纹和放大器;回调处理 [英] Live Audio Recording and Playing in Android and Thread & callback handling

查看:231
本文介绍了现场录音和播放的Andr​​oid和螺纹和放大器;回调处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要录制的现场录音和播放it.As就用户界面有关的应用程序,只是有三个按钮,一个用于开始录制和流媒体的,一个是打了pre记录文件,比上一个用于停止当前任务(记录/播放)。为了这个目的我已经使用的 AudioRecord AudioTrack 类录制和播放分别。我的计划看起来像......

I want to record the live audio and play it.As far as UI is concerned the app just has three buttons and one for starting the recording and streaming it, one for playing a pre recorded file and than the last one for stopping the current task(recording / playing). For that purpose I have used AudioRecord and AudioTrack classes for recording and playing respectively. My Program looks like....

/ **  * @author阿米特  *  * /

/** * @author amit * */

public class AudioRecorder extends Activity {
    private String LOG_TAG = null;

    /* variables which are required to generate and manage the UI of the App */
    // private RecordButton mRecordButton = null;
    private Button recordBtn, stopBtn, playBtn;

    /*
     * variables which are required for the actual functioning of the recording
     * and playing
     */
    private AudioRecord recorder = null;
    private AudioTrack player = null;
    private AudioManager audioManager = null;
    private int recorderBufSize, recordingSampleRate;
    private int trackBufSize;
    private short[] audioData;
    private boolean isRecording = false, isPlaying = false;
    private Thread startRecThread;

    private AudioRecord.OnRecordPositionUpdateListener posUpdateListener;

    /**
     * constructor method for initializing the variables
     */
    public AudioRecorder() {
        super();
        LOG_TAG = "Constructor";
        recorderBufSize = recordingSampleRate = trackBufSize = 0;

        // init function will initialize all the necessary variables ...
        init();

        if (recorder != null && player != null) {
            Log.e(LOG_TAG, "recorder and player initialized");
            audioData = new short[recorderBufSize / 2]; // since we r reading shorts

        } else {
            Log.e(LOG_TAG, "Problem inside init function ");
        }
        posUpdateListener = new AudioRecord.OnRecordPositionUpdateListener() {
            int numShortsRead = 0;

            @Override
            public void onPeriodicNotification(AudioRecord rec) {
                // TODO Auto-generated method stub
//              String LOG_TAG = Thread.currentThread().getName();
//               Log.e(LOG_TAG, "inside position listener");
                audioData = new short[recorderBufSize / 2]; // divide by 2 since now we are reading shorts 
                numShortsRead = rec.read(audioData, 0, audioData.length);
                player.write(audioData, 0, numShortsRead);

            }

            @Override
            public void onMarkerReached(AudioRecord recorder) {
                // TODO Auto-generated method stub
                Log.e(LOG_TAG, "Marker Reached");
            }
        };
        // listener will be called every time 160 frames are reached
        recorder.setPositionNotificationPeriod(160);
        recorder.setRecordPositionUpdateListener(posUpdateListener);

        Log.e(LOG_TAG, "inside constructor");
    }

    private void init() {
        LOG_TAG = "initFunc";
        // int[] mSampleRates = new int[] { 8000, 11025, 22050, 44100 };
        short audioFormat = AudioFormat.ENCODING_PCM_16BIT;
        // for (int rate : mSampleRates) {
        this.recordingSampleRate = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC);
        try {
            // Log.d(LOG_TAG, "Attempting rate " + rate + "Hz, bits: " +
            // audioFormat);
            int bufrSize = AudioRecord.getMinBufferSize(this.recordingSampleRate,
                    AudioFormat.CHANNEL_IN_MONO, audioFormat);

                // lets find out the minimum required size for AudioTrack
            int audioTrackBufSize = AudioTrack.getMinBufferSize(this.recordingSampleRate,
                    AudioFormat.CHANNEL_OUT_MONO, audioFormat);

            if (bufrSize != AudioRecord.ERROR_BAD_VALUE
                    && bufrSize != AudioRecord.ERROR) {
                // check if we can instantiate and have a success
                if(audioTrackBufSize >= bufrSize){
                    this.recorderBufSize = audioTrackBufSize;
                }else{
                    this.recorderBufSize = bufrSize;
                }

                AudioRecord rec = new AudioRecord(
                        MediaRecorder.AudioSource.DEFAULT, this.recordingSampleRate,
                        AudioFormat.CHANNEL_IN_MONO, audioFormat, this.recorderBufSize);

                if (rec != null
                        && rec.getState() == AudioRecord.STATE_INITIALIZED) {

                    // storing variables for future use . . .
//                  this.recordingSampleRate = rate;
//                  this.recorderBufSize = bufrSize;

                    Log.e(LOG_TAG,
                            "Returning..(rate:channelConfig:audioFormat:recorderBufSize)"
                                    + this.recordingSampleRate + ":" + AudioFormat.CHANNEL_IN_MONO
                                    + ":" + audioFormat + ":" + this.recorderBufSize);

                    // Now create an instance of the AudioTrack
//                  int audioTrackBufSize = AudioTrack.getMinBufferSize(rate,
//                          AudioFormat.CHANNEL_OUT_MONO, audioFormat);

                    Log.e(LOG_TAG, "Audio Record / Track / Final buf size :" + bufrSize + "/ " +audioTrackBufSize + "/ "+this.recorderBufSize);


                    this.player = new AudioTrack(AudioManager.STREAM_MUSIC,
                            this.recordingSampleRate, AudioFormat.CHANNEL_OUT_MONO, audioFormat,
                            this.recorderBufSize, AudioTrack.MODE_STREAM);

                    this.recorder = rec;
                    this.player.stop();
                    this.player.flush();
                    this.player.setPlaybackRate(this.recordingSampleRate);
                    return;
                }
            }
        } catch (IllegalArgumentException e) {
            Log.d(LOG_TAG, this.recordingSampleRate + "Exception, keep trying.", e);
        } catch (Exception e) {
            Log.e(LOG_TAG, this.recordingSampleRate + "Some Exception!!", e);
        }
        // for loop for channel config ended here. . . .
        // for loop for audioFormat ended here. . .
        // }// for loop for sampleRate
        return;
    }

    private void startPlaying() {
        LOG_TAG = "startPlaying";

        Log.e(LOG_TAG, "start Playing");
    }

    private void stopPlaying() {
        LOG_TAG = "stopPlaying";

        Log.e(LOG_TAG, "stop Playing");
    }

    private void startRecording() {
        LOG_TAG = "startRecording"; 

        /* start a separate recording thread from here . . . */
        startRecThread = new Thread() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                android.os.Process
                        .setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
//              String LOG_TAG = Thread.currentThread().getName();
                if(recorder.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING){
                    recorder.startRecording();
                }
//              Log.e(LOG_TAG, "running" +recorder.getRecordingState());
                while (recorder.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) {
                    recorder.read(audioData, 0, audioData.length);
                    try {

                         Thread.sleep(1000); // sleep for 2s
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        Log.e("run Method", "recorder thread is interrupted");
                        e.printStackTrace();
                    }
                }
            }
        };
        setVolumeControlStream(AudioManager.STREAM_MUSIC);
        audioManager.setSpeakerphoneOn(false);
        player.flush();     
        player.play();
        startRecThread.start();

        Log.e(LOG_TAG, "start Recording");
    }

    private void stopRecording() {
        LOG_TAG = "stopRecording";
        recorder.stop();

        if (startRecThread != null && startRecThread.isAlive()) {           
            startRecThread.destroy();
            startRecThread = null;
        }

        player.stop();
        player.flush();
        Log.e(LOG_TAG, "stop Recording");
    }

    private void stop() {
        if (isRecording) {
            isRecording = false;
            stopRecording();
        }
        if (isPlaying) {
            isPlaying = false;
            stopPlaying();
        }
        recordBtn.setEnabled(true);
        playBtn.setEnabled(true);
    }

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        LOG_TAG = "onCreate";
//      Log.e(LOG_TAG, "Create Called");
        // getting the audio service
        audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
        LinearLayout ll = new LinearLayout(this);

        // creating Buttons one by one . . . .
        // button to start the recording process
        recordBtn = new Button(this);
        recordBtn.setText("Record");
        recordBtn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                recordBtn.setEnabled(false);
                playBtn.setEnabled(false);
                isRecording = true;
                startRecording();
            }
        });
        // single button to stop recording and playing as applicable
        stopBtn = new Button(this);
        stopBtn.setText("Stop");
        stopBtn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                stop();
            }
        });
        // button to play the recorded sound
        playBtn = new Button(this);
        playBtn.setText("Play");
        playBtn.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                // reverse the isPlaying
                isPlaying = true;
                recordBtn.setEnabled(false);
                playBtn.setEnabled(false);
                startPlaying();
            }
        });

        ll.addView(recordBtn, new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT, 1));

        ll.addView(playBtn, new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT, 1));

        ll.addView(stopBtn, new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT, 1));

        setContentView(ll);
    }

    @Override
    protected void onDestroy() {
        // Clean up code . ..
        super.onDestroy();
        if (recorder != null)
            recorder.release();
        if (startRecThread!=null && startRecThread.isAlive())
            startRecThread.destroy();
        if (recorder != null)
            recorder.release();
        if (player != null)
            player.release();
        startRecThread = null;
        recorder = null;
        player = null;
        recordBtn = null;
        stopBtn = null;
        playBtn = null;
        audioData = null;
        System.gc();
    }

}

正如你可能会看到 startPlaying() stopPlaying()的功能还没有实现,以便让不会说话关于他们。目前,我只是想记录和播放完蛋了。但是,当我运行程序的时候会播放录制的声音,但声音似乎从远处传来。另一个问题是,应用程序的UI线程挂起虽然我有一个单独的线程读取音频。请帮助....

As you might see that startPlaying() and stopPlaying() functions are not yet implemented so lets not talk about them. Currently I am just trying to record and play thats it. But, When I run the program It plays the recorded audio but the audio appears coming from a distance. Another problem is that UI thread of the app hangs though I have a separate thread for reading the Audio . Please help....

推荐答案

如果您的要求是当它被记录应该发挥(指环回音响),在while循环线程,要存储记录的数据(audioData缓冲溶液),还有本身就可以用它复制到播放器对象中的while循环(player.write(audioData,0,numShortsRead);)。你说喜欢你的UI线程被卡住了,这可能是因为你是音频记录线程的加倍重视。

If your requirement is while it is recording it should play(means looping back audio), In your while loop thread, you are storing the recorded data (audioData bufer), there itself you can copy it to player object with in the while loop (player.write(audioData, 0, numShortsRead);). You said like your UI thread is stuck, it might be because of you are giving more priority to Audio record thread.

检查下面我用上面的循环回收要求的code

Check the below the code which I used for above loop back requirement

boolean m_isRun=true;
public void loopback() {
        // Prepare the AudioRecord & AudioTrack
        try {
            buffersize = AudioRecord.getMinBufferSize(SAMPLE_RATE,
                    AudioFormat.CHANNEL_CONFIGURATION_MONO,
                    AudioFormat.ENCODING_PCM_16BIT);

            if (buffersize <= BUF_SIZE) {
                buffersize = BUF_SIZE;
            }
            Log.i(LOG_TAG,"Initializing Audio Record and Audio Playing objects");

            m_record = new AudioRecord(MediaRecorder.AudioSource.MIC,
                    SAMPLE_RATE, AudioFormat.CHANNEL_CONFIGURATION_MONO,
                    AudioFormat.ENCODING_PCM_16BIT, buffersize * 1);

            m_track = new AudioTrack(AudioManager.STREAM_ALARM,
                    SAMPLE_RATE, AudioFormat.CHANNEL_CONFIGURATION_MONO,
                    AudioFormat.ENCODING_PCM_16BIT, buffersize * 1,
                    AudioTrack.MODE_STREAM);

            m_track.setPlaybackRate(SAMPLE_RATE);
        } catch (Throwable t) {
            Log.e("Error", "Initializing Audio Record and Play objects Failed "+t.getLocalizedMessage());
        }

        m_record.startRecording();
        Log.i(LOG_TAG,"Audio Recording started");
        m_track.play();
        Log.i(LOG_TAG,"Audio Playing started");

        while (m_isRun) {
            m_record.read(buffer, 0, BUF_SIZE);
            m_track.write(buffer, 0, buffer.length);
        }

        Log.i(LOG_TAG, "loopback exit");
    }

    private void do_loopback() {
        m_thread = new Thread(new Runnable() {
            public void run() {
                loopback();
            }
        });

还有一件事,如果你的要求是几秒钟的记录,然后播放,在播放你的唱片应该重新开始,你可以做一个延时处理线程具有超时,该线程就可以停止录制复制缓冲区,然后开始录制。

One more thing, If your requirement is record for few seconds and then play, while it is playing your record should start again, you can do that with a delay handler thread with a time out, In that thread you can stop recording copy the buffer, then start recording.

这篇关于现场录音和播放的Andr​​oid和螺纹和放大器;回调处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆