0

My android OS is Android M. Nexus 6. I implemented a AndroidSpeakerWriter as

public class AndroidSpeakerWriter {

    private final static String TAG= "AndroidSpeakerWriter";

    private AudioTrack audioTrack;

    short[] buffer;

    public AndroidSpeakerWriter() {
        buffer = new short[1024];
    }


    public void init(int sampleRateInHZ){
        int minBufferSize = AudioTrack.getMinBufferSize(sampleRateInHZ,
            AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
        audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRateInHZ,
            AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, minBufferSize,
            AudioTrack.MODE_STREAM); // 0-static 1-stream
    }   

    public void fillBuffer(short[] samples) {
        if (buffer.length<samples.length) {
            buffer = new short[samples.length];
        }
        System.arraycopy(samples, 0, buffer, 0, samples.length);
    }

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

    public void stop() {
        audioTrack.stop();
    }

    public void play() {
        audioTrack.play();
     }
}

Then I just send samples when I click a button

public void play(final short[] signal) {
    if (signal == null){
        Log.d(TAG, "play: a null signal");
        return;
    }
    Thread t = new Thread(new Runnable() {
        @Override
        public void run() {
            android.os.Process
                    .setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
            androidSpeakerWriter.play();
            androidSpeakerWriter.writeSamples(signal);
            androidSpeakerWriter.stop();
        }
    });
    t.start();
}

The problem is the device does not beep every time I click the button. Sometimes it works, sometimes it doesn't. There is no such a problem when I run this on an old nexus galaxy phone android 4.3. Anybody has encountered a similar problem? Thanks in advance for any help.

One thing is that currently my beep is pretty short (256 samples), not even close to the minBufferSize.

The bufferSizeInBytes in the constructor of AudioTrack for static mode should be the audio sample length you wanna play according to the vague document. So is it still has a minimal size constraint on the buffer even for static mode? Why a nexus galaxy can play a 256 sample audio in static mode and a nexus 6 can not.

I use AudioManager to get the native buffer size/ sampling rate nexus galaxy: 144/44100 nexus 6: 192/48000

I found those related:

Community
  • 1
  • 1
Syi
  • 108
  • 1
  • 6

1 Answers1

0

I believe it is caused by improper synchronization between thread. Your androidSpeakerWriter instance is running continously in different thread calling play(), writeSamples(), stop() respectively. Click of button will trigger creation of new thread with same androidSpeakerWriter instance.

So while Thread A is executing androidSpeakerWriter.play(), Thread B might be executing androidSpeakerWriter.writeSamples() which might overwrite current audio data being played.

Try

synchronized(androidSpeakerWriter) {
        androidSpeakerWriter.play();
        androidSpeakerWriter.writeSamples(signal);
        androidSpeakerWriter.stop();
}

MODE_STREAM is used if you must play long audio data that will not fit into memory. If you need to play short audio file such beep sound, you can use MODE_STATIC when creating AudioTrack. then change your playback code such following:

synchronized(androidSpeakerWriter) {
        androidSpeakerWriter.writeSamples(signal);
        androidSpeakerWriter.play();
}
Zamrony P. Juhara
  • 5,222
  • 2
  • 24
  • 40
  • Thank you for the help. I tried. It does not help much. The interesting thing is that when i run the same app on another device. There is no such problem. – Syi Feb 22 '16 at 14:46