简体   繁体   中英

How to loop audio with AudioTrack?

I have a program that records a pcm file and saves it. The path to this file is stored in a variable called pcmFile . I would like to change this code so that it plays the PCM file in a seamless loop until the thread is stopped (by changing isPlaying to false).

I have an AudioManager class like this:

public class AudioManager  {
   static final String TAG = "AudioRecorder";

   boolean isPlaying = false;
   static final int frequency = 16000;
   private static final String AUDIO_RECORDER_FOLDER = "4TRACK";
   static final int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
   static final int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
   int playBufSize;

   AudioTrack audioTrack;

   String filename;
   File pcmFile;

   public AudioManager() {    
        playBufSize=AudioTrack.getMinBufferSize(frequency,
                channelConfiguration, audioEncoding);

        audioTrack = new AudioTrack(android.media.AudioManager.STREAM_MUSIC, frequency,
                channelConfiguration, audioEncoding,
                playBufSize, AudioTrack.MODE_STREAM);

        audioTrack.setStereoVolume(0.7f, 0.7f);
    }

    public void startPlaying() {
        isPlaying = true;
        new PlayThread().start();
    }

    public void stopPlaying() {
        isPlaying = false;
    }

    private String getFilename(){
        String filepath = Environment.getExternalStorageDirectory().getPath();
        File file = new File(filepath,AUDIO_RECORDER_FOLDER);

        return (file.getAbsolutePath() + "/" + filename + ".pcm");
    }

    class PlayThread extends Thread {
        public void run() {
            try {
                System.out.println("~~Playing audio");
                byte[] buffer = new byte[playBufSize];
                BufferedInputStream bis = new BufferedInputStream(new FileInputStream(pcmFile), playBufSize);

                audioTrack.play();

                int readSize = -1;
                while (isPlaying && (readSize = bis.read(buffer)) != -1) {
                    audioTrack.write(buffer, 0, readSize);
                }
                audioTrack.stop();
                MainActivity main = (MainActivity) ctx;
                main.audioStopped();
                System.out.println("~~No longer playing");
                bis.close();
            } catch (Throwable t) {
                t.printStackTrace();
            }
        }
    }
}

The important part here is the PlayThread class. Right now it plays a pcm file perfectly. How can I adjust this code so that it plays a PCM file in a loop?

I can see that you are calling the main.audioStopped function from your MainActivity which notifies the media has stopped playing I suppose. You can easily handle the repeat in that audioStopped function of your MainActivity .

I have modified the AudioManager class as follows. Which takes the context and the fileName of the audio which is required to be played in the constructor. This helps you to create the instance of AudioManager from your MainActivity and hence, you can start the audio all over again when the audio is finished playing.

public class AudioManager {
    static final String TAG = "AudioRecorder";

    Context ctx;
    public static boolean isPlaying = false;
    static final int frequency = 16000;
    private static final String AUDIO_RECORDER_FOLDER = "4TRACK";
    static final int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
    static final int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
    int playBufSize;

    AudioTrack audioTrack;

    String filename;
    File pcmFile;

    public AudioManager(Context ctx, String fileName) {
        this.ctx = ctx;
        this.filename = fileName;

        playBufSize = AudioTrack.getMinBufferSize(frequency,
                channelConfiguration, audioEncoding);

        audioTrack = new AudioTrack(android.media.AudioManager.STREAM_MUSIC, frequency,
                channelConfiguration, audioEncoding,
                playBufSize, AudioTrack.MODE_STREAM);

        audioTrack.setStereoVolume(0.7f, 0.7f);
        startPlaying();
    }

    public void startPlaying() {
        isPlaying = true;
        new PlayThread().start();
    }

    private String getFilename() {
        String filepath = Environment.getExternalStorageDirectory().getPath();
        File file = new File(filepath, AUDIO_RECORDER_FOLDER);

        return file.getAbsolutePath() + "/" + filename + ".pcm";
    }

    class PlayThread extends Thread {
        public void run() {
            try {
                System.out.println("~~Playing audio");
                byte[] buffer = new byte[playBufSize];
                BufferedInputStream bis = new BufferedInputStream(new FileInputStream(getFilename()), playBufSize);

                audioTrack.play();

                int readSize = -1;
                while (isPlaying && (readSize = bis.read(buffer)) != -1) {
                    audioTrack.write(buffer, 0, readSize);
                }
                audioTrack.stop();

                MainActivity main = (MainActivity) ctx;
                main.audioStopped();
                System.out.println("~~No longer playing");
                bis.close();
            } catch (Throwable t) {
                t.printStackTrace();
            }
        }
    }
}

And from the MainActivity , check the value of the isPlaying first and repeat starting the thread when it is found true .

public void audioStopped() {
    if (AudioManager.isPlaying) {
        AudioManager am = new AudioManager(this, pcmFileName);
    } else {
        // Do something else
    }
}

Hope that helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM