当前位置: 首页 > 面试题库 >

Android音频编程的噩梦-声音池,配乐Arrghh?

卫寒
2023-03-14
问题内容

我已经构建了一个简单的音乐音序器Android应用程序,可以播放多个音频文件。

最初,我是使用SoundPool播放mp3文件的,它在2.3.4下与旧的HTC Droid Incredible完美配合。然后,我在运行4.3的Galaxy
Nexus上进行了测试,其性能令人震惊。整个地方都有音频定时,并且有小故障/咔嗒声/爆裂声。

因此,我花了几天的时间使用包括MP3解码器的AudioTrack制作一个播放器,并使它在Galaxy和HTC上都能正常工作。现在,我刚刚在Nexus
4(运行4.3)上对其进行了测试,性能非常糟糕-时机到处都是。SoundPool甚至在此设备上提供更好的性能。

我真的很沮丧,不知道该怎么做才能完成我的应用程序,因此,如果有人可以帮助我,我将非常感激。我在下面放了一些音频播放器的代码示例。我已经尝试了所有我能想到的一切,包括更改缓冲区大小,使用缓冲区AudioTrack.MODE_STATIC等。新的Google设备具有低延迟音频,因此,在我的旧机器人上,一切正常的工作方式真是太奇怪了!

提前致谢

/**
* 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;
        }
    }

}

问题答案:

就像用户harikris建议的那样,我强烈建议您使用OpenSL ES库将所有音频播放和处理代码移至Android NDK,以获得最佳性能。

据我了解,AudioTrack API建立在OpenSL ES缓冲区队列音频播放器之上。因此,您可以通过直接与NDK合作,编写从Java /
Android层调用以处理声音的C代码来提高性能

上面提到的本地音频示例包含的代码将向您展示如何直接从URI播放声音文件。以我的经验,这种方法的结果要好于静态模式下的AudioTrack。

通常,Soundpool保留用于可以从内存播放的非常短的声音,它不是定序器的可扩展解决方案,尤其是在引入大文件时。

以下是一些有助于我完成应用程序工作的链接:-有关适用于Android的OpenSL
ES的常规信息:http :
//mobilepearls.com/labs/native-android-
api/opensles/

-带有一些出色示例代码的Android音频博客:http : //audioprograming.wordpress.com

编辑:旧的移动珍珠链接似乎已关闭。这是一个有效的方法:http : //mobilepearls.com/labs/native-android-
api/ndk/docs/opensles/index.html



 类似资料:
  • 在Microsoft Windows中,声音、音乐与视讯的综合运用是一个重要的进步。对多媒体的支持起源于1991年所谓的Microsoft Windows多媒体延伸功能(Multimedia Extensions to Microsoft Windows)。1992年,Windows 3.1的发布使得对多媒体的支持成为另一类API。最近几年,CD-ROM驱动器和声卡-在90年代初期还很少见-已成为

  • 我在android上使用APPRTCdemo应用程序。我试着让它播放来自另一个同龄人的声音,音量与Android设置中设置的音量一样大。因此,如果用户将设备静音,则不会听到音频。我几乎尝试了每一个Android API调用,但似乎对音量没有任何影响。以下是我尝试过的东西:AudioManager AudioManager=(AudioManager)_context.getSystemServic

  • 问一下Xamarin.Forms便携里面Xamarin.Forms的音频怎么播放 正如我所知,有依赖服务,我看到了一些示例,只有iOS和Android,但没有Windows Phone 8.1/Windows 8.1和UWP。

  • 我正在为android开发一个音乐钢琴应用程序,在这个应用程序中我想记录用户通过点击钢琴按钮播放的声音。我在用soundpool弹钢琴。现在,对于录音,android给了我们两个API:MediaRecorder和AudioreCorder。但是对于这两者,我们都必须设置mediareCorder.audioSource。我不想从麦克风录制声音,因为用户声音可以包括在内,更重要的是录音质量下降。然

  • 目前oc率100%,继续保持😁。 因为自身在绿盟实习,这里纯玩啥也不用干,问了下学长的意见就不去了,打算狠狠带薪沉淀了,过俩月all in大厂。 -----我是一条分割线------ 一面: 》自我介绍 说了下自己的学校,专业,年级,工作室负责的事,最近在学的东西,微服务,cs课程比如raft。 》展示下自己最值的一提的项目 我选的是一个raft相关的项目,把6.824移植出来弄了个高可用的kv