android - 在 Android 中,如何同步录音和同步播放?

标签 android audio synchronization media-player mediarecorder

我正在尝试编写一个函数,在后台播放乐器时录制用户的声音。

我已经相当成功地让 2 个 MediaPlayer 几乎同时启动。使用 Threads 和 CyclicBarrier,我已经能够在每个 5 毫秒内启动 2 个 MediaPlayer,这听起来很不错。

问题是每当我尝试同时启动 MediaRecorder 和 MediaPlayer 时,它们之间会有明显的延迟。这是有问题的,因为当我播放录制的音频和乐器时,它们彼此不同步,因为录制的开始时间与播放器不同。

这是我尝试用于记录器和播放器的函数和 2 个线程。对于篇幅,我深表歉意,但如果有人有更好的想法,我将不胜感激:

private void onRecord(boolean start) {
    if (start) {
       final CyclicBarrier recordBarrier = new CyclicBarrier(2);
       final CyclicBarrier postrecordBarrier = new CyclicBarrier(2);
       Thread beatTask = new Thread(new RecordBeatPlayTask(recordBarrier, postrecordBarrier), "Thread 1");
       Thread recordTask = new Thread(new RecordVoiceRecordTask(recordBarrier, postrecordBarrier), "Thread 2");

       beatTask.start();
       recordTask.start();
    } 
    else {
            mRecorder.stop();
            mRecordBeatPlayer.stop();

            mRecorder.release();
            mRecorder = null;
            mRecordBeatPlayer.release();
            mRecordBeatPlayer = null;
    }
}

private static class RecordVoiceRecordTask implements Runnable {

    private CyclicBarrier barrier;
    private CyclicBarrier barrier2;

    public RecordVoiceRecordTask(CyclicBarrier barrier, CyclicBarrier barrier2) {
        this.barrier = barrier;
        this.barrier2 = barrier2;
    }

    public void run() {
        try {
            mRecorder = new MediaRecorder();
            mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
            mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
            mRecorderPath = Environment.getExternalStorageDirectory().getAbsolutePath();
            mRecorderPath += "/HypeHopRecording.mp4";
            mRecorder.setOutputFile(mRecorderPath);
            mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
            try {
                mRecorder.prepare();
            } catch (IOException e) {
                Log.e("Recorder failed", "prepare() failed");
            }
            barrier.await();
            mRecorder.start();
            barrier2.await();
            System.out.println(Thread.currentThread().getName() + " has crossed the barrier");
        } catch (InterruptedException ex) {
            Logger.getLogger(RecordActivity.class.getName()).log(Level.SEVERE, null, ex);
        } catch (BrokenBarrierException ex) {
            Logger.getLogger(RecordActivity.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

private static class RecordBeatPlayTask implements Runnable {

    private CyclicBarrier barrier;
    private CyclicBarrier barrier2;

    public RecordBeatPlayTask(CyclicBarrier barrier, CyclicBarrier barrier2) {
        this.barrier = barrier;
        this.barrier2 = barrier2;
    }

    public void run() {
        try {
            mRecordBeatPlayer = new MediaPlayer();

            try {
                mRecordBeatPlayer.setDataSource(mBeatPath);
                mRecordBeatPlayer.prepare();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (SecurityException e) {
                e.printStackTrace();
            } catch (IllegalStateException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            barrier.await();
            mRecordBeatPlayer.start();
            barrier2.await();
            System.out.println(Thread.currentThread().getName() + " has crossed the barrier");
        } catch (InterruptedException ex) {
            Logger.getLogger(RecordActivity.class.getName()).log(Level.SEVERE, null, ex);
        } catch (BrokenBarrierException ex) {
            Logger.getLogger(RecordActivity.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

最佳答案

基本上,'mRecordBeatPlayer.start()' 和用户可以听到声音之间有延迟,你必须测试这个延迟。

关于android - 在 Android 中,如何同步录音和同步播放?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26417771/

相关文章:

android - 将调整大小的位图加载到 byte[] 数组中

iOS - 在应用程序后台运行的异步时钟

date - 同步系统时间和日期的批处理文件

c - 什么时候可以使用 cond var 来同步它自己的销毁/取消映射?

安卓 : Application does not seek into layout-land when the device changes his orientation

java - Android 如何更改电影大小 GIF

c# - C#如何从网络摄像头和麦克风录制视频或音频并将其上传到Web服务器

html - 音频标签在 Safari 中不起作用

linux - 锁定每个 CPU 变量

通过 App Store 或 Google Play 下载 Android 应用程序时无法运行 - ANR