How to tell when AudioTrack object has finished playing?

TalkieTalk picture TalkieTalk · Sep 4, 2010 · Viewed 8.8k times · Source

I'm trying to play a PCM file in Android using the AudioTrack class. I can get the file to play just fine, but I cannot reliably tell when playback has finished. AudioTrack.getPlayState says playback has stopped when it hasn't finished playing. I'm having the same problem with AudioTrack.setNotificationMarkerPosition, and I'm pretty sure my marker is set to the end of the file (although I'm not completely sure I'm doing it right). Likewise, playback continues when getPlaybackHeadPosition is at the end of the file and has stopped incrementing. Can anyone help?

Answer

John picture John · Jul 11, 2011

I found that using audioTrack.setNotificationMarkerPosition(audioLength) and audioTrack.setPlaybackPositionUpdateListener worked for me. See the following code:

    // Get the length of the audio stored in the file (16 bit so 2 bytes per short)
    // and create a short array to store the recorded audio.
    int audioLength = (int) (pcmFile.length() / 2);
    short[] audioData = new short[audioLength];
    DataInputStream dis = null;

    try {
        // Create a DataInputStream to read the audio data back from the saved file.
        InputStream is = new FileInputStream(pcmFile);
        BufferedInputStream bis = new BufferedInputStream(is);
        dis = new DataInputStream(bis);

        // Read the file into the music array.
        int i = 0;
        while (dis.available() > 0) {
            audioData[i] = dis.readShort();
            i++;
        }

        // Create a new AudioTrack using the same parameters as the AudioRecord.
        audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, RECORDER_SAMPLE_RATE, RECORDER_CHANNEL_OUT,
                                    RECORDER_AUDIO_ENCODING, audioLength, AudioTrack.MODE_STREAM);
        audioTrack.setNotificationMarkerPosition(audioLength);
        audioTrack.setPlaybackPositionUpdateListener(new OnPlaybackPositionUpdateListener() {
            @Override
            public void onPeriodicNotification(AudioTrack track) {
                // nothing to do
            }
            @Override
            public void onMarkerReached(AudioTrack track) {
                Log.d(LOG_TAG, "Audio track end of file reached...");
                messageHandler.sendMessage(messageHandler.obtainMessage(PLAYBACK_END_REACHED));
            }
        });

        // Start playback
        audioTrack.play();

        // Write the music buffer to the AudioTrack object
        audioTrack.write(audioData, 0, audioLength);

    } catch (Exception e) {
        Log.e(LOG_TAG, "Error playing audio.", e);
    } finally {
        if (dis != null) {
            try {
                dis.close();
            } catch (IOException e) {
                // don't care
            }
        }
    }