【问题标题】:android audio - soundpool alternativesandroid 音频 - soundpool 替代品
【发布时间】:2012-09-29 12:28:18
【问题描述】:

我喜欢 Android Soundpool 类的简单性,它与我在应用程序中使用的标准音频文件配合得很好。现在我想让用户可以通过指定 sd 卡上的音频文件来指定某些声音。不幸的是,我遇到了 Soundpool 的限制,当声音文件太大时,我会得到一个

AudioFlinger 无法创建音轨。状态:-12

响应。看来我必须切换到 MediaPlayer 但在再次进入 MediaPlayer 的复杂性之前我想问一下是否有可用于 android 的音频库

  • 具有 Soundpool 的简单性,可播放各种声音
  • 在文件大小方面没有 Soundpool 的限制。

非常感谢。

马丁

【问题讨论】:

  • This 问题可能会有所帮助。我认为答案没有提到文件大小(但他们确实提到了替代方案)
  • thx Keyser,我以前看过这个帖子,Jetplayer 似乎不是我要找的

标签: android audio android-mediaplayer


【解决方案1】:

现在我想出了一个非常简单的 AudioPool 类,它可以播放随后使用 MediaPlayer 类添加到其中的音频。这个实现肯定还不成熟,但我只是想分享它,因为它至少给出了一些如何轻松实现它的想法。如果您发现本课程有任何问题,请告诉我们。

用法:

 AudioPool ap = new AudioPool();

 File root = Environment.getExternalStorageDirectory() ;

 int id1 = ap.addAudio(root + "/gong1.mp3");
 int id2 = ap.addAudio(root + "/gong2.mp3");
 int id3 = ap.addAudio(root + "/gong3.mp3"); 

 ap.playAudio(id1);
 ap.playAudio(id3);
 ap.playAudio(id3);
 ap.playAudio(id2);

随后将播放 gong1 -> gong3 -> gong3 -> gong1。因为这基本上是我需要的,所以我把它留在这里......

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.util.Log;

public class AudioPool {

static String TAG = "AudioPool";

MediaPlayer mPlayer;

int mAudioCounter;

int mCurrentId;

HashMap<Integer, String> mAudioMap;

LinkedList<Integer> mAudioQueue;

public AudioPool() {

    mAudioMap = new HashMap<Integer, String>();
    mAudioQueue = new LinkedList<Integer>();
    mAudioCounter = 0;

}

public int addAudio(String path) {
    Log.d(TAG, "adding audio " + path + " to the pool");

    if (mAudioMap.containsValue(path)) {
        return getAudioKey(path);
    }
    mAudioCounter++;
    mAudioMap.put(mAudioCounter, path);
    return mAudioCounter;
}

public boolean playAudio(int id) {

    if (mAudioMap.containsKey(id) == false) {
        return false;
    }

    if (mPlayer == null) {
        setupPlayer();
    }

    if (mPlayer.isPlaying() == false) {
        return prepareAndPlayAudioNow(id);
    } else {
        Log.d(TAG, "adding audio " + id + " to the audio queue");

        mAudioQueue.add(id);
    }
    return true;
}

public Integer[] getAudioIds() {
    return (Integer[]) mAudioMap.keySet().toArray(
            new Integer[mAudioMap.keySet().size()]);
}

public void releaseAudioPlayer() {
    if (mPlayer != null) {
        mPlayer.release();
        mPlayer = null;
    }
}


private boolean prepareAndPlayAudioNow(int id) {
    mCurrentId = id;
    try {
        Log.d(TAG, "playing audio " + id + " now");
        mPlayer.reset();
        mPlayer.setDataSource(mAudioMap.get(id));
        mPlayer.prepare();
        mPlayer.start();
        return true;
    } catch (Exception e) {
        Log.d(TAG, "problems playing audio " + e.getMessage());
        return false;
    }
}

private boolean playAudioAgainNow() {
    try {
        mPlayer.seekTo(0);
        mPlayer.start();
        return true;
    } catch (Exception e) {
        Log.d(TAG, "problems playing audio");
        return false;
    }
}

private void setupPlayer() {
    mPlayer = new MediaPlayer();
    mPlayer.setOnCompletionListener(new OnCompletionListener() {
        @Override
        public void onCompletion(MediaPlayer mp) {
            audioDone();
        }
    });
}

private void audioDone() {

    if (mAudioQueue.size() > 0) {
        Log.d(TAG, mAudioQueue.size() + " audios in queue");
        int nextId = mAudioQueue.removeFirst();

        if (mCurrentId == nextId) {
            playAudioAgainNow();
        } else {
            prepareAndPlayAudioNow(nextId);
        }

    } else {
        releaseAudioPlayer();
    }
}

private int getAudioKey(String path) {
    for (Map.Entry<Integer, String> map : mAudioMap.entrySet()) {
        if (map.getValue().compareTo(path) == 0) {
            return map.getKey();
        }
    }
    return -1;
}

}

【讨论】:

    【解决方案2】:

    感谢dorjeduck 的解决方案,但他的课程基于MediaPlayer,延迟很大。 这是什么意思?这意味着当你调用这些时:

    mPlayer.prepare();
    mPlayer.start();
    

    实际上听到声音的延迟非常明显。例如,当您需要播放一首曲目并立即播放另一首曲目时,即使在高端硬件上也会听到延迟。

    在播放前将所有字节加载到内存中的解决方案,并使用AudioTrack 播放该声音字节。

    我写了SoundPoolCompat,它在后台使用AudioTrack。您可以传递自定义bufferSize,该缓冲区中的所有数据都将被加载到内存中,并像 SoundPool 那样以小延迟播放。所有超过bufferSize 的数据都将按需加载(这会增加延迟,类似于MediaPlayer)。 Api 与SoundPool 非常相似,还添加了从 Uri 加载声音的功能(例如 gdrive)。还有playOnce方法,文件播放后所有资源都会被卸载。

    implementation 'com.olekdia:sound-pool:3.0.2'
    

    https://gitlab.com/olekdia/common/libraries/sound-pool

    【讨论】:

      猜你喜欢
      • 2011-09-22
      • 1970-01-01
      • 2021-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多