Android的音频节目的噩梦 - 的Soundpool,audiotrack arrghh?噩梦、音频、节目、Android

2023-09-06 02:39:37 作者:享受寂寞

我已经建立了一个简单的音乐编曲的Andr​​oid应用程序可以播放多种音频文件。

我原来用的Soundpool播放MP3文件和它的工作完全可以在2.3.4与旧宏达电Droid Incredible。然后,我测试了它在运行4.3的Galaxy Nexus和表现得可怕。音频的地方所有的时间和有毛刺/咔嗒/噼噗声。

于是,我花了好几天使用AudioTrack包括MP3德codeR使玩家得到它在两个星系和HTC正常使用。现在,我刚刚测试了一台Nexus 4(4.3运行)和性能是可怕的 - 时间是所有的地方。的Soundpool甚至提供此设备上更好的表现。

我真的很沮丧,不知道该怎么做才能完成我的应用程序,所以我真的AP preciate如果有人可以帮助我。我已经把我的音频播放器的一些code样品如下。我用尽了一切我能想到的,包括改变缓冲区的大小,使用 AudioTrack.MODE_STATIC 等新的谷歌器件具有低延迟的音频所以很奇怪,怎么一切工作方式在我的旧Droid的更好!

在此先感谢

  / **
*扮演检查
* /
公共无效playNote(串音符,浮动体积)
{
    PlayThread oldThread = threadMap.get(注);
    如果(oldThread!= NULL){
        //取消计时器
        如果(oldThread.timer!= NULL){
            oldThread.timer.cancel();
            oldThread.timer.purge();
            oldThread.timer = NULL;
        }
        //停止
        oldThread.requestStop();
        threadMap.remove(注);
    }

    如果在复调音乐//播放
    如果(threadMap.size()&其中; POLYPHONY){
        PlayThread线程=新PlayThread(注,体积);
        thread.start();
        threadMap.put(注意,螺纹);
    }
}


/ **
*停止记
* /
公共无效stopNote(串音符,诠释fadeDurationInMs)
{
    PlayThread线程= threadMap.get(注);
    如果(线程!= NULL){
        thread.fadeOut(fadeDurationInMs);
        threadMap.remove(注);
    }
}


/ **
*停止所有
* /
公共无效stopAllPlaying(INT fadeDurationInMs)
{
    对于(PlayThread螺纹:threadMap.values​​()){
        如果(线程!= NULL){
            thread.fadeOut(fadeDurationInMs);
        }
    }
    threadMap.clear();
}


/ **
* PlayThread
* /
私有类PlayThread继承Thread
{
    串音符;
    浮动卷;
    浮动fadeVol;
    布尔停止;
    AudioTrack audioTrack;
    定时器定时;

    / **
    *构造函数
    * /
    公共PlayThread(串音符,浮动体积)
    {
        超();
        this.note =注;
        this.vol =卷;
        this.fadeVol =卷;
    }

    / **
    * 跑
    * /
    公共无效的run()
    {
        尝试 {
            android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);

            //创建缓冲区
            INT BUFFERSIZE = AudioTrack.getMinBufferSize(SAMPLE_RATE,渠道,AudioFormat.ENCODING_PCM_16BIT);
            Log.v(Constants.TAG,最小缓冲区大小=+ BUFFERSIZE);

            BUFFERSIZE = BUFFERSIZE * 2;

            byte []的缓冲区=新的字节[BUFFERSIZE]

            // AudioTrack
            audioTrack =新AudioTrack(AudioManager.STREAM_MUSIC,SAMPLE_RATE,渠道,AudioFormat.ENCODING_PCM_16BIT,缓冲区大小,AudioTrack.MODE_STREAM);
            audioTrack.setStereoVolume(第一卷,第二卷);
            audioTrack.play();

            //获取字节数据
            byte []的byteData = sampleMap.get(注);

            //转换为输入流
            输入的InputStream =新ByteArrayInputStream的(byteData);

            //写audioTrack
            INT读取动作= 0;
            而(停止与放大器;!&安培;!(读取动作= input.read(缓冲))=  -  1){
                    audioTrack.write(缓冲液,0,读取动作);
            }

            //完成后...
            audioTrack.stop();
            audioTrack.release();
            input.close();
            killThread(本);
        }
        赶上(例外五){}
    }

    / **
    *设置音量
    * /
    私人同步无效setVol(浮动newVol)
    {
        audioTrack.setStereoVolume(newVol,newVol);
    }

    / **
    *更新卷
    * /
    私人同步无效lowerVol()
    {
        fadeVol  -  = 0.01;
        如果(fadeVol℃,)体积= 0;
        audioTrack.setStereoVolume(fadeVol,fadeVol);
    }

    / **
    * 消退
    * /
    市民同步无效淡出(INT fadeDurationInMs)
    {
        //开始递减量
        如果(fadeDurationInMs大于0){
            定时器=新的定时器(真正的);
            TimerTask的TimerTask的=新的TimerTask()
            {
                @覆盖
                公共无效的run()
                {
                    //如果运行时线程打死
                    尝试 {
                        //降低音量
                        lowerVol();
                    }
                    赶上(例外五){}

                    //停止时,音量达到0
                    如果(fadeVol&所述; = 0){
                        如果(定时器!= NULL){
                            timer.cancel();
                            timer.purge();
                        }
                        停止= TRUE;
                    }
                }
            };

            //计算延时,则设置为1,如果零
            INT延迟=(INT)(fadeDurationInMs /(体积* 100));
            如果(延迟== 0)延迟= 1;

            timer.schedule(TimerTask的,延迟,延迟);
        }
    }

    / **
    *请求停止
    * /
    市民同步无效requestStop()
    {
        //停止单击/弹出停止采样时,
        setVol(0.01F);
        setVol(0.005f);
        停止= TRUE;
    }

    / **
    *杀死线程
    * /
    私人同步无效killThread(线程theThread)
    {
        如果(theThread!= NULL){
            theThread = NULL;
        }
    }

}
 

解决方案

如用户harikris建议,我会强烈建议您使用OpenSL ES库以获得最佳性能将所有的音频播放和处理code到Android NDK

据我了解,在AudioTrack API是建立在OpenSL ES缓冲队列音频播放器的顶部。所以,你也许可以通过直接与NDK的工作,写一个从你的Java / Android的一层叫的声音工作,C $ C $Ç提高性能。

以上提到的纯音频示例包含code,它会告诉你如何直接从一个URI播放声音文件。根据我的经验,此方法的结果比AudioTrack静态模式更好。

的Soundpool一般为可以从内存中发挥其不是你的音序器一个可扩展的解决方案,特别是如果你引进大文件很短的声音保留。

下面是帮助我与我的应用程序的一些链接: 在OpenSL ES针对Android - 一般信息: http://mobilepearls.com/labs/native-android-api/opensles/

- 一个Android的音频博客有一些很好的例子,code: HTTP://audioprograming.word$p$pss.com

编辑: 旧手机珍珠的链接似乎已关闭。这里是一个正在运行的:http://mobilepearls.com/labs/native-android-api/ndk/docs/opensles/index.html

新媒体岗位必备的5款软件,学会了月薪不低于3万

I've built a simple music sequencer Android app that plays multiple audio files.

Originally I was using SoundPool to play mp3 files and it worked perfectly on 2.3.4 with an old HTC Droid Incredible. Then I tested it on a Galaxy Nexus running 4.3 and the performance was horrendous. The audio timing all over the place and there were glitches/clicks/pops.

So I spent several days making a player using AudioTrack including an mp3 decoder and got it working perfectly on both the Galaxy and the HTC. Now I've just tested it on a Nexus 4 (running 4.3) and the performance is terrible - the timing is all over the place. SoundPool even offers better performance on this device.

I'm really frustrated and don't know what to do to finish my app so I would really appreciate if someone could help me out. I've put some code samples of my audio player below. I've tried everything I can think of including changing the buffer size, using AudioTrack.MODE_STATIC etc. The new Google devices have low latency audio so it's very strange how everything works way better on my old droid!

Thanks in advance

/**
* Play note
*/
public void playNote(String note, float vol)
{
    PlayThread oldThread = threadMap.get(note);
    if(oldThread != null) {
        //Cancel timer
        if(oldThread.timer != null) {
            oldThread.timer.cancel();
            oldThread.timer.purge();
            oldThread.timer = null;
        }
        //Stop
        oldThread.requestStop();
        threadMap.remove(note);
    }

    //Play if within Polyphony
    if(threadMap.size() < POLYPHONY) {
        PlayThread thread = new PlayThread(note, vol);
        thread.start();
        threadMap.put(note, thread);
    }       
}


/**
* Stop note
*/
public void stopNote(String note, int fadeDurationInMs)
{   
    PlayThread thread = threadMap.get(note);
    if(thread != null) {
        thread.fadeOut(fadeDurationInMs);
        threadMap.remove(note);
    }
}


/**
* Stop all
*/
public void stopAllPlaying(int fadeDurationInMs)
{
    for(PlayThread thread : threadMap.values()) {
        if(thread != null) {
            thread.fadeOut(fadeDurationInMs);
        }
    }
    threadMap.clear();
}


/**
* PlayThread
*/
private class PlayThread extends Thread
{
    String note;
    float vol;
    float fadeVol;
    boolean stop;
    AudioTrack audioTrack;
    Timer timer;

    /**
    * Constructor
    */
    public PlayThread(String note, float vol)
    {
        super();
        this.note = note;
        this.vol = vol;
        this.fadeVol = vol;
    }

    /**
    * Run
    */
    public void run()
    {
        try {
            android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);

            //Create buffer
            int bufferSize = AudioTrack.getMinBufferSize(SAMPLE_RATE, CHANNELS, AudioFormat.ENCODING_PCM_16BIT);
            Log.v(Constants.TAG, "min buffersize = " + bufferSize);

            bufferSize = bufferSize * 2;

            byte[] buffer = new byte[bufferSize];

            //AudioTrack
            audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, SAMPLE_RATE, CHANNELS, AudioFormat.ENCODING_PCM_16BIT, bufferSize, AudioTrack.MODE_STREAM);
            audioTrack.setStereoVolume(vol, vol);
            audioTrack.play();

            //Get byte data
            byte[] byteData = sampleMap.get(note);

            //Convert to input stream
            InputStream input = new ByteArrayInputStream(byteData);

            //Write to audioTrack
            int bytesRead = 0;
            while(!stop && (bytesRead = input.read(buffer)) != -1) {
                    audioTrack.write(buffer, 0, bytesRead);
            }

            //When finished...
            audioTrack.stop();
            audioTrack.release();
            input.close();
            killThread(this);
        }
        catch(Exception e) {}
    }

    /**
    * Set volume
    */
    private synchronized void setVol(float newVol)
    {
        audioTrack.setStereoVolume(newVol, newVol);
    }

    /**
    * Update volume
    */
    private synchronized void lowerVol()
    {
        fadeVol -= 0.01;
        if(fadeVol < 0) vol = 0;
        audioTrack.setStereoVolume(fadeVol, fadeVol);
    }

    /**
    * Fade out
    */
    public synchronized void fadeOut(int fadeDurationInMs)
    {
        //Start decreasing volume
        if(fadeDurationInMs > 0) {
            timer = new Timer(true);
            TimerTask timerTask = new TimerTask()
            {
                @Override
                public void run()
                {
                    //If thread killed while running
                    try {
                        //Lower volume
                        lowerVol();
                    }
                    catch (Exception e) {}

                    //Stop when volume reaches 0
                    if(fadeVol <= 0) {
                        if(timer != null) {
                            timer.cancel();
                            timer.purge();
                        }
                        stop = true;
                    }
                }
            };

            //Calculate delay, set to 1 if zero
            int delay = (int) (fadeDurationInMs / (vol * 100)); 
            if(delay == 0) delay = 1;

            timer.schedule(timerTask, delay, delay);
        }
    }

    /**
    * Request stop
    */
    public synchronized void requestStop()
    {
        //Stop click/pop when stopping sample
        setVol(0.01f);
        setVol(0.005f);
        stop = true;
    }

    /**
    * Kill Thread
    */
    private synchronized void killThread(Thread theThread)
    {
        if(theThread != null) {
            theThread = null;
        }
    }

}

解决方案

Like user harikris suggests, I would highly recommend you move all your audio playback and processing code to Android NDK using the OpenSL ES library for the best performance.

As I understand, the AudioTrack API is built on top of OpenSL ES Buffer Queue Audio Player. So you could probably improve performance by working directly with the NDK, writing C code that is called from your Java/Android layer to work with the sound.

The native-audio example mentioned above contains code that will show you how to play a sound file directly from a URI. In my experience, the results from this method are better than AudioTrack in Static Mode.

Soundpool is generally reserved for very short sounds that can be played from memory and its not a scalable solution for your sequencer especially if you introduce large files.

Here are some links that have helped me out with my applications: -General Information on OpenSL ES for Android: http://mobilepearls.com/labs/native-android-api/opensles/

-An Android audio blog with some great example code: http://audioprograming.wordpress.com

Edit: The old mobile pearl link appears to be down. Here's a working one:http://mobilepearls.com/labs/native-android-api/ndk/docs/opensles/index.html

 
精彩推荐
图片推荐