1

我正在开发一个应用程序来通过啁啾信号发送文本。基本上,我让用户有机会编写文本,并选择开始频率、最终频率和其他一些关于要发送的位之间的时间间隔和持续时间的选项。

在应用程序中,我将文本拆分为字符,将它们转换为 ASCII 整数,将这些整数转换为二进制文件,然后使用啁啾信号(在 Big Endian 中)发送它们,从初始频率到最终频率的 5 毫秒啁啾声(向下到向上) ) 发送 1,并从最终频率到初始频率。(从上到下)发送 0。

它非常简单并且可以正常工作,但是在按几次发送按钮后,它崩溃了,并且我在 logcat 中收到以下错误消息:

07-08 15:09:58.036: E/AudioTrack(8747): AudioFlinger could not create track, status: -12 
07-08 15:09:58.036: E/AudioTrack-JNI(8747): Error initializing AudioTrack
07-08 15:09:58.036: E/AudioTrack-Java(8747): [ android.media.AudioTrack ] Error code -20 when initializing AudioTrack.
07-08 15:09:58.044: W/dalvikvm(8747): threadid=13: thread exiting with uncaught exception (group=0x40f77930)
07-08 15:09:58.051: E/AndroidRuntime(8747): FATAL EXCEPTION: Thread-445
07-08 15:09:58.051: E/AndroidRuntime(8747): java.lang.IllegalStateException:play() called on uninitialized AudioTrack.
07-08 15:09:58.051: E/AndroidRuntime(8747):     at android.media.AudioTrack.play(AudioTrack.java:883)
07-08 15:09:58.051: E/AndroidRuntime(8747):     at android.nacho.UltraSoundSender.AudioDevice.<init>(AudioDevice.java:19)
07-08 15:09:58.051: E/AndroidRuntime(8747):     at android.nacho.UltraSoundSender.ChirpGenerator.playDOWN(ChirpGenerator.java:104)
07-08 15:09:58.051: E/AndroidRuntime(8747):     at android.nacho.UltraSoundSender.UltraSoundSender$1$1.run(UltraSoundSender.java:61)
07-08 15:09:58.051: E/AndroidRuntime(8747):     at java.lang.Thread.run(Thread.java:856)

我使用的三个代码如下:

public class UltraSoundSender extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ultra_sound_sender);


        Button btnCode = (Button) findViewById(R.id.btnCode);
        btnCode.setOnClickListener(new OnClickListener() {

            //@Override
            public void onClick(View arg0) {            


                new Thread( new Runnable( ) 
                {
                   public void run( )
                   {   


                       String word= ((EditText)findViewById(R.id.Line)).getText().toString();
                       int IniFreq=Integer.parseInt(((EditText)findViewById(R.id.IniFreq)).getText().toString());
                       int FinFreq=Integer.parseInt(((EditText)findViewById(R.id.FinFreq)).getText().toString());
                       int bitLength=Integer.parseInt(((EditText)findViewById(R.id.bitLength)).getText().toString());
                       int bitGap=Integer.parseInt(((EditText)findViewById(R.id.bitGap)).getText().toString());

                       Integer digits[]= new Integer[64];
                       int NumChar= word.length();

                       //This split the string in chars
                       for(int i = 0; i <  NumChar ; i++){

                           digits[i]=(int)word.charAt(i);

                            }


                       double impulseDuration = 250; //not negotiable
                       int Delay=(int) (bitGap-((int)impulseDuration*0.8));
                       for(int IndexChar= 0; IndexChar< NumChar ; IndexChar++)
                       {

                            new ChirpGenerator().playDOWN(IniFreq*1000, FinFreq*1000, impulseDuration, digits[IndexChar], bitLength );
                            try {
                                Thread.sleep(Delay); //Time diference since whe generate one bit and the next one
                            } catch (InterruptedException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
                       }
                       Thread.currentThread().interrupt();

                      // enableButton(true);
                   }

                } ).start();

            }
        });


}

    //Enable/disable button
    private void enableButton(boolean isEnable)
    {
        ((Button)findViewById(R.id.btnCode)).setEnabled(isEnable);

}



    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_ultra_sound_sender, menu);
        return true;


    }
}

package android.nacho.UltraSoundSender;

public class ChirpGenerator {

    private AudioDevice device;


    public ChirpGenerator() {
        device = new AudioDevice( );
    }

/**
 * 
 * @param initialFreq in Hz
 * @param finalFreq in Hz
 * @param impulseDuration in ms
 */


    void playDOWN(int initialFreq, int finalFreq, double impulseDuration, int Code, int LengthBit) {

        AudioDevice device = new AudioDevice( );
        //int LengthBit=6; //In milliseconds
        int LengthBitInSamples = LengthBit*44; //That would means every bit is 5 millisecs length
        int NumberOfBits= 8;
        int LimitOfInterestingSamples=NumberOfBits*LengthBitInSamples;

        double k = (double)(finalFreq - initialFreq) / (LengthBit/1000.0); //This should be the corret one, but works better with 5 milliseconds
        float samples[] = new float[1024];
        double currentFreq = finalFreq; //Because it goes from up to down
        double phase;
        double t;
        int j = 0;
        int CountBits = 0;
        int IndexBit=1;
        Integer digits[]= new Integer[64];  

        //int Code = 45;

        for(int n=NumberOfBits, m=1; n>0; m++, n--) //To ID from 0 to 7 -> just 8 devices in the network
        {

            digits[m]=Code%2;
            Code/=2;
            System.out.println("Valor de digits"+digits[m]);

        }



        for (int i = 0; i < (int)(impulseDuration/1000.0 * AudioDevice.SAMPLING_RATE); i++, CountBits++) {

            if(i>LimitOfInterestingSamples)
            {
                samples[j++] = 0;

            }
            else{   

                if(CountBits>LengthBitInSamples)
                {
                    CountBits=0;
                    if(IndexBit<NumberOfBits) 
                    IndexBit++;


                }

                if(digits[IndexBit]==1) //This means 1
                {

                    t = (double)CountBits / (double)AudioDevice.SAMPLING_RATE;
                    currentFreq = initialFreq + 0.5 * k * t;
                    phase = 2.0 * Math.PI * (currentFreq) * t;

                }
                else{ //This means 0

                    t = (double)CountBits / (double)AudioDevice.SAMPLING_RATE;
                    currentFreq = finalFreq - 0.5 * k * t;
                    phase = 2.0 * Math.PI * (currentFreq) * t;
                }


                samples[j++] = (float)Math.sin(phase);

            } 

            if (j == 1024) {
                device.writeSamples( samples );
                j = 0;
            }

        }//for

    }



}

package android.nacho.UltraSoundSender;

import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;

public class AudioDevice
{
    public static final int SAMPLING_RATE = 44100; //44100;
   AudioTrack track;
   short[] buffer = new short[1024];

   public AudioDevice( )
   {
      int minSize =AudioTrack.getMinBufferSize( SAMPLING_RATE, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT );        
      track = new AudioTrack( AudioManager.STREAM_MUSIC, SAMPLING_RATE, 
                                        AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, 
                                        minSize, AudioTrack.MODE_STREAM);
      track.play();   
      int nativeSampleRate = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC);

      int sampleRate = track.getSampleRate();

   }       

   public void writeSamples(float[] samples) 
   {    
      fillBuffer( samples );
      track.write( buffer, 0, samples.length );
   }

   private void fillBuffer( float[] samples )
   {
      if( buffer.length < samples.length )
         buffer = new short[samples.length];

      for( int i = 0; i < samples.length; i++ )
         buffer[i] = (short)Math.round(samples[i] * (float)Short.MAX_VALUE);
   }
}

谁能告诉我为什么应用程序在我执行几次时会崩溃?谢谢

4

1 回答 1

2

似乎您在使用完 AudioTrack 实例后并没有关闭它。完成啁啾后,您应该关闭并取消您的 audioTrack 实例。

于 2013-07-15T20:32:55.890 回答