I’m experimenting with AudioTrack class. Basically, my app has to generate a sound when the user touches a specific object on screen. I’ve used this example as a guide.
My app seems to work as it should but usually after touching the screen for about a minute it crashes:
07-02 20:40:53.459: E/AndroidRuntime(11973): FATAL EXCEPTION: Thread-10
07-02 20:40:53.459: E/AndroidRuntime(11973): java.lang.IllegalStateException: play() called on uninitialized AudioTrack.
07-02 20:40:53.459: E/AndroidRuntime(11973): at android.media.AudioTrack.play(AudioTrack.java:824)
07-02 20:40:53.459: E/AndroidRuntime(11973): at com.mysounds_experimental.SoundThread.playSound(SoundThread.java:108)
07-02 20:40:53.459: E/AndroidRuntime(11973): at com.mysounds_experimental.SoundThread.run(SoundThread.java:69)
Methods from class that generates sounds
public void initAudioTrack() {
int bufferSize = AudioTrack.getMinBufferSize(sampleRate
, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
audioTrack = new AudioTrack(
AudioManager.STREAM_MUSIC
, sampleRate
, AudioFormat.CHANNEL_CONFIGURATION_MONO
, AudioFormat.ENCODING_PCM_16BIT
, bufferSize
, AudioTrack.MODE_STREAM);
}
private void playSound(){
audioTrack.write(generatedSnd, 0, numSamples);
audioTrack.play();
}
public void stopPlaying() {
audioTrack.flush();
audioTrack.stop();
audioTrack.release();
}
@Override
public void run() {
while (mRun) {
try{
Thread.sleep(200);
while(soundCycle){
if(freqOfTone != -1f) {
generateTone();
playSound();
Thread.sleep(200);
}
}
} catch(InterruptedException e){
// soundCycle = false;
// soundPool.stop(BEEP);
}
}
}
This is a method from a custom view my thread is used
@Override
public boolean onTouchEvent(final MotionEvent ev) {
int currentXPosition = (int) ev.getX();
int currentYPosition = (int) ev.getY();
if(ev.getX() < smBitmap.getWidth())
if(ev.getY() < smBitmap.getHeight()){
tempCol = smBitmap.getPixel(currentXPosition, currentYPosition);
}
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
sThread.freqOfTone = getFreqPreset(tempCol);
if(col != tempCol){
// sThread.initAudioTrack();
sThread.interrupt();
if(shouldInit) {
shouldInit = false;
sThread.initAudioTrack();
}
sThread.soundCycle = true;
col = tempCol;
invalidate();
}
break;
}
case MotionEvent.ACTION_MOVE: {
sThread.freqOfTone = getFreqPreset(tempCol);
if (tempCol == -1 || tempCol == 0) {
sThread.soundCycle = false;
shouldInit = true;
// sThread.stopPlaying();
sThread.interrupt();
invalidate();
} else {
if(col != tempCol){
sThread.interrupt();
col = tempCol;
invalidate();
}else {
sThread.soundCycle = true;
col = tempCol;
invalidate();
}
}
break;
}// case ACTION_MOVE
case MotionEvent.ACTION_UP: {
sThread.soundCycle = false;
shouldInit = true;
// sThread.stopPlaying();
sThread.interrupt();
col = -1;
mActivePointerId = INVALID_POINTER_ID;
break;
}// case ACTION_UP
}
return true;
}
Any ideas why is this happening?
I would think that you need to call
play()before you callwrite().But I’ve also noticed that when you create lots of
AudioTrackinstances even if you think you’re cleaning everything up write, sometimes aplay()fails to work, and the track is uninitialized.You will want to try…catch this
IllegalStateException, and avoiding callingwrite()untilplay()works without throwing an exception.