7

When I play a file with the following code:

private void PlayAudioFileViaAudioTrack(int ResId) throws IOException {

    int intSize = android.media.AudioTrack.getMinBufferSize(11025, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);

    AudioTrack at = new AudioTrack(AudioManager.STREAM_MUSIC, 11025, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, intSize,
            AudioTrack.MODE_STREAM);

    int count = 256 * 1024; // 256 kb
    byte[] byteData = null;
    byteData = new byte[(int) count];
    InputStream in = null;
    AssetFileDescriptor fd = null;
    fd = mResources.openRawResourceFd(ResId);
    in = mResources.openRawResource(ResId);

    int bytesRead = 0, amount = 0;
    int size = (int) fd.getLength();
    at.play();
    while (bytesRead < size) {
        amount = in.read(byteData, 0, count);
        if (amount != -1) {
            at.write(byteData, 0, amount);
        }
    }
    in.close();
    at.stop();
    at.release();

}

The only thing I hear is static, white noise. I've checked that my .wav file has the same properties (samplerate,bitrate). I don't have to much knowledge about raw audio data(PCM), so I was wondering if anyone could see what's wrong with my code.

usealbarazer
  • 707
  • 3
  • 10
  • 27

3 Answers3

8

from your code i can see that you just read data from the wav file and just import them to the AudioTrack. Wav files have a small header as you can see here https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ So you have to skip the header and point your file descriptor at the right place where the actual audio data are.

Also when you playing an audio file and you are dealing with byte operations you should take care of the Endianess. Take a look here Using AudioTrack in Android to play a WAV file

Below my code (some checks and the WAV header skip are missing) that works in both Nexus One and Galaxy S with a wav file with frequency 8000Hz and 16 bit encoding.

public void playWav(){
    int minBufferSize = AudioTrack.getMinBufferSize(8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
    int bufferSize = 512;
    AudioTrack at = new AudioTrack(AudioManager.STREAM_MUSIC, 8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, minBufferSize, AudioTrack.MODE_STREAM);
    String filepath = Environment.getExternalStorageDirectory().getAbsolutePath();

    int i = 0;
    byte[] s = new byte[bufferSize];
    try {
        FileInputStream fin = new FileInputStream(filepath + "/REFERENCE.wav");
        DataInputStream dis = new DataInputStream(fin);

        at.play();
        while((i = dis.read(s, 0, bufferSize)) > -1){
            at.write(s, 0, i);

        }
        at.stop();
        at.release();
        dis.close();
        fin.close();

    } catch (FileNotFoundException e) {
        // TODO
        e.printStackTrace();
    } catch (IOException e) {
        // TODO
        e.printStackTrace();
    }       
}
Community
  • 1
  • 1
Manos
  • 2,136
  • 17
  • 28
  • The header would just be enough for a few milliseconds of sound, it should play normal after that. Could you explain to me what you mean with 'take care of the Endianess'? – usealbarazer Sep 15 '11 at 14:01
  • Oh, sorry my mistake about Endianess. I thought that you were reading the data as shorts but you are reading as bytes so endianess it's not a problem here. To be sure I wrote a small program (i can provide the source code) that reads the .wav file and writes it to AudioTrack. It plays the wav file normally at my phone. Perhaps your configuration parameters at the constructor of AudioTrack may be wrong. Have you checked the properties of your wav file? Maybe it has different sampling frequency or encoding. – Manos Sep 16 '11 at 20:32
  • Hmmm, quite strange... I added at my first answer my code. As you can see the way that I handle AudioTrack is the same. The only difference is the file opening and reading. Add some debug messages to logcat to see if something goes wrong at these operations. – Manos Sep 17 '11 at 21:34
  • I'd suggest two more experiments: 1) try zeroing out the buffer and writing it - no white noise must be present in this case; 2) try reversing the shorts (that is, force endian conversion) – Lyth Sep 20 '11 at 08:31
  • @Manos: Nice code. Is it possible to change byte[] s to short[] s? Because I want to compute RMS from that data but it only correct for short[] type. Thanks – John Sep 30 '15 at 15:46
  • @user8264, yeah that it is possible. You have to use the `write()` function of `AudioTrack` that takes as parameter a vector of shorts. – Manos Oct 05 '15 at 18:42
-1

If you have saved file in wav format and want to play it using AudioTrack then follow this code:

             File file=new File(Environment.getExternalStorageDirectory()+"/AudioRecorder/fahim.wav");

               InputStream is;
             DataInputStream         dis = null ;
             BufferedInputStream     bis;

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

            }
            catch (FileNotFoundException e1) 
            {
                ShowToast("fILE NOT FOUND:"+e1.getMessage());
            }

            int i = 0;                                                          //  Read the file into the "music" array
            music=new byte[(int) file.length()];
            try 
            {
                while (dis.available() > 0)
                {
                    music[i] = dis.readByte();                                      //  This assignment does not reverse the order
                    i++;
                }
            } 
            catch (IOException e) 
            {
                ShowToast("I/O Exception:"+e.getMessage());
            }

            try {dis.close();} catch (IOException e) {e.printStackTrace();}

            int minBufferSize = AudioTrack.getMinBufferSize(11025, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);

            AudioTrack at = new AudioTrack(AudioManager.STREAM_MUSIC, 11025, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, minBufferSize, AudioTrack.MODE_STREAM);
            at.play();

            ShowToast("size:"+music.length);
            //*/
            at.write(music, 0, music.length);
Pir Fahim Shah
  • 10,505
  • 1
  • 82
  • 81
-1

That looks WAY more complicated than what I did. I played sounds using this. I think .wav files would work just as well.

MediaPlayer mpPlayProgram = new MediaPlayer();
mpPlayProgram.setDataSource("/sdcard/file.mp3");
mpPlayProgram.prepare();
mpPlayProgram.start();
mpPlayProgram.release();

For static resources, it's even easier:

MediaPlayer mpStart = MediaPlayer.create(this, resID);
mpStart.start();
mpStart.release();
ProjectJourneyman
  • 3,566
  • 1
  • 27
  • 37
  • I'm not using the MediaPlayer class because it's very high level. I'm using AudioTrack, wich is better for what i'm doing. – usealbarazer Sep 14 '11 at 15:41