【问题标题】:Multiple AudioTracks, Single Thread or Multiple?多个音轨,单线程还是多个?
【发布时间】:2011-11-22 11:31:31
【问题描述】:

在我的应用程序中,我将创建多个音轨,其中一些需要同时播放。我将使用MODE_STREAM 并在应用程序运行时写入数据。声音将动态生成,这就是我使用音轨而不是其他任何东西的原因。 我有 4 个选择,我相信:

  1. 异步任务
  2. 一个 UI 线程和一个管理所有 AudioTrack 播放的线程
  3. 一个 UI 线程和每个 AudioTrack 一个线程
  4. 一个 UI 线程和一个 Thread Pool

四种方法中哪一种是管理多个 AudioTrack 的最佳方式?

我认为线程池是要走的路,但我并不肯定,因为我还没有真正使用过它。

任何建议将不胜感激

【问题讨论】:

  • 你是用什么方法实现的?
  • @burakk 我在应用程序上从未走多远,因为(至少在当时)Android 中的音频延迟非常糟糕(而且我缺乏经验)。如果我现在这样做,我会有一个后台线程,因为来自不同线程的同时音频处理是一个愚蠢的想法。而且,我认为使用一个AudioTrack 并正确设置数据(频率和诸如此类)来组合声音将是尝试播放多个音轨的方法。如果您对 Android 音频开发感兴趣,请查看 columbia.edu andraudio mailing list
  • 感谢您的快速回复。我已经开发了一个可以同时播放两个流的应用程序。我有两个服务,每个服务都在一个单独的线程中实例化一个 AudioTrack。正如我在stackoverflow.com/questions/27493521/… 的 SO 问题中所问的那样,我想知道处理两个以上流的最佳方法是什么。我不想为每个人写一个服务。
  • 我不是音频或硬件 i/o 方面的专家,但我相信当您添加流时,拥塞会增加,这可能会导致意外/不需要的结果。不过我可能错了。如果到时候你还没有得到答复,我明天再看看你的 Q。

标签: android multithreading audio threadpool


【解决方案1】:

为每个 AudioTrack 创建一个 AsyncTask,并使用 Executor 执行它们(在我的 Android 4.4 上,如果没有使用 Executor,则只会执行第一个任务)。 这是一个将麦克风信号流式传输到 AudioTrack 并将音频文件流并行传输到另一个 AudioTrack 的示例。

/** Task for streaming file recording to speaker. */
private class PlayerTask extends AsyncTask<Null, Null, Null> {
    private short[] buffer;
    private int bufferSize;
    private final AudioTrack audioTrack;
    ...
    @Override
    protected Null doInBackground(final Null... params) {
        ...
        while (!isCancelled()) {
            audioTrack.write(buffer, 0, bufferSize);
        }
        ...
    }
}

/** Task for streaming microphone to speaker. */
private class MicTask extends AsyncTask<Null, Null, Null> {
    private short[] buffer;
    private int bufferSize;
    private final AudioTrack audioTrack;
    ...
    @Override
    protected Null doInBackground(final Null... params) {
        ...
        while (!isCancelled()) {
            audioTrack.write(buffer, 0, bufferSize);
        }
        ...
    }
}

/** On the UI-thread starting both tasks in parallel to hear
    both sources on the speaker. **/
PlayerTask playerTask = new PlayerTask();
playerTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new Null());

MicTask micTask = new MicTask();
micTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new Null());

【讨论】:

    【解决方案2】:

    为简单起见,我只是在每次播放 AudioTrack 时创建一个新线程。

    但是,不管它真的没关系。我发现当尝试一次播放多个 AudioTrack 时,会发出噼啪声/断断续续的声音。我认为这只是 Android 系统的问题,而不是我的应用程序的问题。

    从 API 级别 9(姜饼)开始,我可以将会话 id 应用于音轨,我相信这可以让我使用 SoundPool 播放它,这应该会使同时播放多个 AudioTrack 更加流畅。

    目前,由于2.2还有很多用户,而且我没有姜饼设备,我将把这个项目搁置到以后。

    【讨论】:

      【解决方案3】:

      我认为你最好的选择是 AsyncTask。

      【讨论】:

      • 我担心的是 AsyncTask 创建了一个工作线程,如果说,4 个 AudioTrack 正在一个工作线程上运行,这可能会使它们阻塞整个线程吗?
      • 另一个问题是 AsyncTask The task can be executed only once 根据文档。那么我能否通过 onTouch 事件动态更改 AudioTrack 信息?我目前也缺乏使用 AsyncTask 的经验,因为我发布的一个应用程序不需要它。
      • 可以通过调用“AsyncTask task = new AsyncTask(); task.execute();多次执行任务
      • 好的,谢谢。但这仍然会为重复的任务创建带来很多不必要的开销,不是吗?
      猜你喜欢
      • 1970-01-01
      • 2014-10-12
      • 1970-01-01
      • 1970-01-01
      • 2018-08-16
      • 1970-01-01
      • 1970-01-01
      • 2012-02-06
      • 1970-01-01
      相关资源
      最近更新 更多