10
votes

Been having a bit of trouble over the last few days trying to get this to work. But what I want is we have an application that sends raw data over the network. I then read this binary data in and want to save it to a wav(any audio) file. Might look at compression later.

So the problematic code:

byte[] allBytes = ...
InputStream b_in = new ByteArrayInputStream(allBytes);

try
{
     AudioFormat format = new AudioFormat(8000f, 16, 1, true, true);
     AudioInputStream stream = new AudioInputStream(b_in, format, allBytes.length);
     //AudioInputStream stream = AudioSystem.getAudioInputStream(b_in);                

Have tried to use the above statement as well but i get the exception: javax.sound.sampled.UnsupportedAudioFileException: could not get audio input stream from stream. So what I think is happening is that because my stream is raw audio data and does not have a wave header this is throwing an exception?

File newPath = new File(SystemConfiguration.getLatest().voiceNetworkPathDirectory + currentPhoneCall.fileName);
if (!AudioSystem.isFileTypeSupported(Type.WAVE, stream))
{
    Logger.error("Audio System file type not supported");
}

AudioSystem.write(stream, Type.WAVE, newPath);

The file does successfully write but it is all static, Do I need to create a wave header on the output using the something like this. When I look at the outputted wav file in notepad and it does seem to have a header as it starts with 'RIFF'.

Do I need to add a fake header into my input stream? Should i just create my own output header and just save it with a binary writer?

3
Something is wrong with your post. You're missing data/formatting.user845279
How about compare to other valid WAVE files? When you select one of them, copy the data after the header and then place the raw data onto code to your array allBytes. After running your code, you can simply compare the 2 wave files. If it's not the same, then either code is bad or you need to understand the wave format beter.The Original Android
the length argument in constructor of AudioInputStream should be a frame length value instead of data length. frame-length = data-length / channel / sample-size-in-byteLiuYan 刘研
Hi Liu Yan. I tried setting your frame length but it made it worse. It ended up putting like nothing except the header into the wav file, leaving out all the binary data. Would you mind putting brackets. is it : frame-length = ( data-length / channel ) / sample-size-in-bytes or frame-length = ( data-length * sample-size-in-bytes) / channeluser1434177

3 Answers

6
votes

So I ended up getting it working, not really sure why but this is the code that is working:

InputStream b_in = new ByteArrayInputStream(resultArray);
try {
        DataOutputStream dos = new DataOutputStream(new FileOutputStream(
                "C:\\filename.bin"));
        dos.write(resultArray);
        AudioFormat format = new AudioFormat(8000f, 16, 1, true, false);
        AudioInputStream stream = new AudioInputStream(b_in, format,
                resultArray.length);
        File file = new File("C:\\file.wav");
        AudioSystem.write(stream, Type.WAVE, file);
        Logger.info("File saved: " + file.getName() + ", bytes: "
                + resultArray.length)

So it must have been my signed/unsigned/ little endian settings. What I ended up doing was saving the data to a binary file. Then importing that file as raw data in audacity. This told me everything except the rate which I already new. The only issue I have now is to do with the header calculation. I save the binary data which generates a 4 second wav but it only ever has 2 seconds of sound. Its as if it is calculating my header wrong. I'm not sure if it is to do with the frame-length that LiuYan mentioned.

If I have an array length of 160. Does this mean I have a framelength of 10? 160 / 1 / 16. If I do this then I only store 10 bytes of data into my binary file.

1
votes

It's hard to know from your description where the error is, but to answer your questions, when you see 'RIFF' when you open the file that does mean it has a header. Trying to build you own header is possible but a bit time consuming (and unnecessary since you've got one).

Now, when reading, it is safest to get the format from the file itself, rather than trying to specify it manually -- that will be less error prone. There is sample code for that here:

http://www.jsresources.org/examples/SimpleAudioPlayer.java.html

When writing, you say "The file does successfully write but it is all static" -- have you confirmed that with something other than your own java code? Maybe I am not understanding correctly, but it sounds like you are trying to record and playback WAV files with fresh java code, and if that's the case, it's hard to tell if something is going wrong with the recording or the playback.

You should start with a vanilla format (16 bits, stereo, uncompressed, 44,100 kHz) so you can open the file in media player or quicktime or something and verify that the recording worked. Once that works, you can try to change the SR and so on. Here is some sample code for recording. Start with that, verify that it works, and then move on to something more complex:

http://www.jsresources.org/examples/SimpleAudioRecorder.java.html

0
votes

Try setting the Encoding and frame size and frame rate of AudioFormat.

new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
                  8000f,
                  16,
                  1,
                  2, // frameSize
                  8000f,// frameRate
                  false);