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

Play music synchronous using 3 MediaPlayer Objects on Android/Eclipse

我有: 我在我的应用程序中实现了三个 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();
}

"simplified" 线程中用于创建的代码:

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()" 方法需要一点时间才能完成。因此我实现了一个 "Waiting loop" 等待所有 MP 准备和创建。

"prepare and create" 完成后,我启用“开始”按钮,我想同时启动所有 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 必须与 3 个音频文件同时播放(并且完全同步)的时间完全相同

我已经尝试过的:

+) 使用 SoundPool:对于 SoundPool

,我的音频文件太大(5MB 或更大)

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

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

希望有人能帮助我!

提前致谢

因为没有人能帮助我,所以我自己找到了解决方案。 MediaPlayer 没有满足我的要求,但是 Android JETPlayer 结合 JETCreator 满足了。

注意:安装 Python 以使用 JETCreator 非常棘手,因此 关注 this tutorial。请注意 python 和 wxpython 的版本,并非所有版本都支持 JETCreator。

我用过:

  • Python 版本 2.5.4 (python-2.5.4.msi)
  • wxPython 2.8 (wxPython2.8-win32-unicode-2.8.7.1-py25.exe)

对于那些不知道如何实现 Jetplayer 手表的人 this video (在第 5 分钟,他开始对 Jetplayer 进行编程)。 不幸的是,我不会说法语,所以我只是遵循了对我有用的代码。

使用 Android JETCreator 您可以创建自己的 JET 文件并将它们用作您的资源。

有用的链接:

这里的瓶颈肯定是准备播放媒体播放器。 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();
     }
}