I using AudioTrack in static mode to reproduce the same signal over and over again.
I have followed the example in here and sometimes it works perfectly, but sometimes it throws this error and it produces no sound:
AudioTrack: start called from a thread
01-23 15:26:16.902: W/libutils.threads(1133): Thread (this=0x3973b8): don't call waitForExit() from this Thread object's thread. It's a guaranteed deadlock!
This is the source code. I'm trying to ensure that I call stop and reload the data for the next "play" execution.
public class SoundPlayer {
// originally from http://marblemice.blogspot.com/2010/04/generate-and-play-tone-in-android.html
private int numSamples;
private double sample[];
private byte generatedSnd[];
private AudioTrack audioTrack;
public SoundPlayer(float duration, int sampleRate, double freqOfTone) {
super();
this.numSamples = (int) (duration * sampleRate);
this.sample = new double[numSamples];
this.generatedSnd = new byte[2 * numSamples];
// 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);
}
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);
}
public void playSound() {
if ( audioTrack.getPlayState() == (AudioTrack.PLAYSTATE_PLAYING | AudioTrack.PLAYSTATE_PAUSED )) {
audioTrack.stop();
audioTrack.reloadStaticData();
}
Log.i("Audio", "playState: " + audioTrack.getPlayState());
audioTrack.play();
audioTrack.stop();
audioTrack.reloadStaticData();
}
}
If we open the android source code, it does not explains a lot:
void AudioTrack::start()
{
sp<AudioTrackThread> t = mAudioTrackThread;
LOGV("start");
if (t != 0) {
if (t->exitPending()) {
if (t->requestExitAndWait() == WOULD_BLOCK) {
LOGE("AudioTrack::start called from thread");
return;
}
}
t->mLock.lock();
}
Does anyone know how to handle this?
I had a similar problem once.
Simply put, if you happen to have stuff running in more than one thread you have to make sure that creating the
AudioTrack
and callingplay()
andstop()
on it must happen in the same thread.However, it doesn't mean that you have to create the audio samples in that thread, too. In case you use static audio data (
AudioTrack.MODE_STATIC
) you can preload or generate them elsewhere and then use it even multiple times throughout the lifetime of your app.