android - 在 Android/Eclipse 上使用 3 个 MediaPlayer 对象同步播放音乐

标签 android eclipse synchronization android-mediaplayer

我有什么: 我在我的应用程序中实现了三个 MediaPlayer.Objects。 这三个都是使用线程创建的:

protected void onResume() {
    // Threads
    mTT1 = new TrackThread(this, R.raw.audiofile1, 1, mHandler);
    mTT2 = new TrackThread(this, R.raw.audiofile2, 2, mHandler);
    mTT3 = new TrackThread(this, R.raw.audiofile3, 3, mHandler);
    // start thread
    mTT1.start();
    mTT2.start();
    mTT3.start();
    super.onResume();
}

线程中用于创建的“简化”代码:

public class TrackThread extends Thread implements OnPreparedListener {
...
...
...
 public void run() {
    super.run();
            try {
                mMp.setDataSource(afd.getFileDescriptor(),
                        afd.getStartOffset(), afd.getDeclaredLength());
                mMp.prepare();
            } catch (IllegalArgumentException | IllegalStateException
                    | IOException e) {
                Log.e(TAG, "Unable to play audio queue do to exception: "
                        + e.getMessage(), e);
            }
      }

正如我在几个教程中读到的,“prepare()”方法需要一点时间才能完成。因此,我实现了一个“等待循环”,等待所有 MP 准备好并创建。

“准备和创建”完成后,我启用“开始”按钮,我想同时启动所有 3 个媒体播放器。

我再次使用线程来这样做:

public void onClick(View v) {
    // Button 1
    if (mBtn.getId() == v.getId()) {
                mTT1.startMusic();
                mTT2.startMusic();
                mTT3.startMusic();
    }

线程中的代码:

public class TrackThread extends Thread implements OnPreparedListener {
...
...
...

// start
public void startMusic() {
    if (mMp == null)
        return;
    mMp.start();
}

请注意,上面的代码不是完整代码,但应该足以定义我的问题。

我想要的,我的问题:

所有 MP 都应该同步播放他们的音乐,不幸的是有时当我开始播放音乐时,它们之间会有时间延迟。

MP 必须与 3 个音频文件同时播放(并且完全同步)的时间完全相同

我已经尝试过的:

+) 使用 SoundPool:对于 SoundPool,我的音频文件太大(5 兆字节或更大)

+) seekTo(msec):我想在特定时间寻找每个 MP:例如:0,但这并没有解决问题。

+) 接触到更多的程序员 我也问过这个问题:coderanch.com

我希望有人能帮助我!

提前致谢

最佳答案

这里的瓶颈肯定是准备播放媒体播放器。 Android 框架提供了一种异步方法来执行此加载,因此通过一些同步代码,您应该能够让这些音频源大致同时播放。为避免声音失真,您需要小于 10 毫秒的延迟。

将原子计数器 C 初始化为要加载的事物的数量。

使用 MediaPlayer 中的 prepareAsync() 函数准备所有三个。在调用 prepareAsync 之后,立即使用 setOnPreparedListener(listener) 提供一个监听器。

在此监听器中,递减 C 并检查值。如果该值大于 0,则使用 java 对象 .wait() 函数等待对象。如果该值等于 0,则调用对象上的 notifyAll() 以唤醒所有其他媒体播放器准备好的监听器回调线程。

public void startMediaPlayers(List<MediaPlayer> mediaPlayers) {
     private AtomicInteger counter = new AtomicInteger(mediaPlayers.size());
     Object barrier = new Object();
     /* start off all media players */
     for (MediaPlayer player : mediaPlayers) {
          player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                                @Override
                                public void onPrepared(final MediaPlayer mediaPlayer) {
                                    int value = counter.decrementAndGet();
                                    if (value == 0) {
                                        // all media players are done loading.
                                        // wake up all the ones that are asleep
                                        barrier.notifyAll();
                                    } else {
                                       while (value > 0) {
                                            try {
                                              // wait for everyone else to load
                                              barrier.wait();
                                            } catch (InterruptedException e) {
                                              // ignore
                                            } 
                                       }
                                    }
                                    mediaPlayer.start();
                                    callback.success(true);
                                }
          player.prepareAsync();
     }
}

关于android - 在 Android/Eclipse 上使用 3 个 MediaPlayer 对象同步播放音乐,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30031373/

相关文章:

python - Eclipse、PyDev 语法着色

java - 在 eclipse 中使用 Runtime.getRuntime().exec

c++ - 尝试跨多个进程使用 Boost.Interprocess 消息队列时的断言

swift - 按顺序 Swift 执行任务

file - 唯一标识 NTFS 中的文件/文件夹,即使在移动/重命名之后

java - 使用 MY_SQL 时 Android Java 到 PHP 字符串文字问题

android - 我如何为 Android 应用程序编写 SQLite 查询?

Android:状态栏中的多个通知作为单个列表

android - 单击 ListView 项时如何关闭 AlertDialog

java - 将 JAR Maven 项目包含到 WAR Maven 项目中