当我在第22次尝试生成音调时,出现未初始化的AudioTrack异常



我有一个要求,我需要显示一个类似拨号板的屏幕,每当用户按下拨号板按钮时,我必须生成1khz音调(而不是DTMF音调(。

我使用了以下链接中的代码来生成1 khz音调:

使用Android 播放任意音调

当我开始在拨号板屏幕上拨号按钮,直到21次按下时,它成功地生成了音调,但在第22次尝试后,我遇到了应用程序未响应(ANR(错误,我需要关闭应用程序。

以下是我的代码:

 final float duration = 0.3f; // seconds
final int sampleRate = 4000;
final int numSamples = (int)duration * sampleRate + 100;
final double sample[] = new double[numSamples];
final double freqOfTone = 1000; // hz
final byte generatedSnd[] = new byte[2 * numSamples];
final Handler handler = new Handler();

      public void onClick(View v) {
    // TODO Auto-generated method stub
    int id = v.getId();
    playSound();
    }

   private void playSound()
{
    final Thread thread = new Thread(new Runnable() {
        public void run() {
            genTone();
            handler.post(new Runnable() {
                public void run() {
                    playSound1();
                }
            });
        }
    });
    thread.start();

}
 void playSound1(){
     final AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
             sampleRate, AudioFormat.CHANNEL_CONFIGURATION_MONO,
             AudioFormat.ENCODING_PCM_16BIT, numSamples,
             AudioTrack.MODE_STATIC);
         audioTrack.write(generatedSnd, 0, generatedSnd.length);

         audioTrack.play();
 }
void genTone(){
    // fill out the array
    for (int i = 0; i < numSamples; ++i) {
        sample[i] = Math.sin(2 * Math.PI * i / (sampleRate/freqOfTone));
    }
    // convert to 16 bit pcm sound array
    // assumes the sample buffer is normalised.
    int idx = 0;
    for (final double dVal : sample) {
        // scale to maximum amplitude
        final short val = (short) ((dVal * 32767));
        // in 16 bit wav PCM, first byte is the low order byte
        generatedSnd[idx++] = (byte) (val & 0x00ff);
        generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);
    }
}

onClick((方法将在每次我按下拨号盘上的按钮时调用。

通过上面的代码,我在Logcat中得到了这个输出:

05.500 E/AudioFlinger(   85): no more track names available
09-21 05:20:05.500 E/AudioTrack(  133): AudioFlinger could not create track, status: -12
09-21 05:20:05.503 E/SoundPool(  133): Error creating AudioTrack
09-21 05:20:05.535 E/AudioFlinger(   85): no more track names available
09-21 05:20:05.535 E/AudioTrack( 6080): AudioFlinger could not create track, status: -12
09-21 05:20:05.535 E/AudioTrack-JNI( 6080): Error initializing AudioTrack
09-21 05:20:05.535 E/AudioTrack-Java( 6080): [ android.media.AudioTrack ] Error code -20 when initializing AudioTrack.
09-21 05:20:05.535 D/AndroidRuntime( 6080): Shutting down VM
09-21 05:20:05.535 W/dalvikvm( 6080): threadid=1: thread exiting with uncaught exception (group=0x40015578)
09-21 05:20:05.539 E/AndroidRuntime( 6080): FATAL EXCEPTION: main
09-21 05:20:05.539 E/AndroidRuntime( 6080): java.lang.IllegalStateException: play() called on uninitialized AudioTrack.
09-21 05:20:05.539 E/AndroidRuntime( 6080):     at android.media.AudioTrack.play(AudioTrack.java:824)
09-21 05:20:05.539 E/AndroidRuntime( 6080):     at com.android.dial.DialPadScreen.playSound1(DialPadScreen.java:274)
09-21 05:20:05.539 E/AndroidRuntime( 6080):     at com.android.dial.DialPadScreen$1$1.run(DialPadScreen.java:248)
09-21 05:20:05.539 E/AndroidRuntime( 6080):     at android.os.Handler.handleCallback(Handler.java:587)
09-21 05:20:05.539 E/AndroidRuntime( 6080):     at android.os.Handler.dispatchMessage(Handler.java:92)
09-21 05:20:05.539 E/AndroidRuntime( 6080):     at android.os.Looper.loop(Looper.java:123)
09-21 05:20:05.539 E/AndroidRuntime( 6080):     at android.app.ActivityThread.main(ActivityThread.java:3687)
09-21 05:20:05.539 E/AndroidRuntime( 6080):     at java.lang.reflect.Method.invokeNative(Native Method)
09-21 05:20:05.539 E/AndroidRuntime( 6080):     at java.lang.reflect.Method.invoke(Method.java:507)
09-21 05:20:05.539 E/AndroidRuntime( 6080):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:842)
09-21 05:20:05.539 E/AndroidRuntime( 6080):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)
09-21 05:20:05.539 E/AndroidRuntime( 6080):     at dalvik.system.NativeStart.main(Native Method)
09-21 05:20:05.542 E/        (  133): Dumpstate > /data/log/dumpstate_app_error
09-21 05:20:05.542 W/ActivityManager(  133):   Force finishing activity com.android.dial/.DialPadScreen

我打印"audioTrack"的状态,直到第21次我得到值1(state_INITIALIZED(,然后我得到值"0"(state_UNITIALIZEd(。不知道为什么国家会改变。

请帮助我需要做哪些更改来防止我的应用程序中出现此froce关闭问题。或者请建议是否有其他选择。

关于21个成功生成的音调和下一个失败的音调的数量,我认为您必须释放之前创建的调用audioTrack.release()方法的实例。

为了避免IllegalStateException
创建AudioTrack的实例后,您必须测试它是否初始化良好
使用MODE_STATIC模式,如果未正确初始化,则状态为:STATE_UNINITIALIZED,相反,如果正确初始化:STATE_NO_STATIC_DATA,当您调用write方法时,状态将更改为STATE_INITIALIZED
使用MODE_STREAM模式,如果未正确初始化,则状态为:STATE_UNINITIALIZED,相反,如果正确初始化:STATE_INITIALIZED
阅读AudioTrack的来源,我看到了。我觉得这很奇怪,因为构造函数返回的对象不可用,因为它不可能在构造后初始化。

您可以在应用程序的onCreate中创建一个AudioTrack,然后在应用程序启动时调用audioTrack.play(),然后在按下按钮时将数据写入其中。

此外,根据我使用AudioTrack的经验,如果我尝试同时播放多个AudioTrack,它会产生非常糟糕、断断续续的声音,并且会出现滞后。

你可以考虑预先录制声音并使用声音池,因为它可以同时播放多个声音。

或者,从API 9级开始,您可以将会话ID分配给AudioTrack,如果我理解正确,这应该允许您使用SoundPool播放音轨,然后理想情况下您会希望创建静态音轨

将AudioTrack.MODE_STATIC更改为AudioTrack.MODE_STREAM。应该这样做:(

我遇到了类似的问题,我通过将此权限添加到清单文件中来解决它:

    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>

最新更新