Play raw PCM audio received in UDP packets
Asked Answered
D

1

6

The remote device is sending live raw PCM audio(no header included) in UDP packets and I need to implement a program in java to receive these packets and play them on the PC live. As I know that raw PCM's attributes are 16bit, mono, sampling rate 24KHz, so I tried to add a wav header to this raw PCM audio and play but the problem is I don't have File size of the audio.

I also implemented a program based on this link but it only gives noise in output.

I am bound to use UDP and I can get only raw PCM from remote device, so is their any library or API by which I can play this raw audio on PC?

Deejay answered 30/9, 2015 at 18:53 Comment(3)
This should be very simple (using javax.sound), create an AudioFormat matching the parameters, open a SourceLine for that AudioFormat and write your samples. You don't need to know the length of the audio in advance for playing directly on the line interface.Archimage
Thanks for the answer, I tried that but I get only noise in output when I pass byte array of raw PCM(without header) to it. It plays correctly when I pass bytearray of audio (with header). I am doing all the steps mentioned.Deejay
Then either you mixed big/little endian in the AudioFormat, its not PCM or your receiving code does not get the correct data... or you're not receiving data fast enough and in too little chunks so it sounds like noise when played? You use two threads, one for receiving and one for playing, right? I'll post you an example for simple syntethic playback.Archimage
A
9

Here is a simple example for obtaining an output line and playing PCM on it. When run it plays about a second long annoying beep.

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;

public class RawAudioPlay {

    public static void main(String[] args) {
        try {
            // select audio format parameters
            AudioFormat af = new AudioFormat(24000, 16, 1, true, false);
            DataLine.Info info = new DataLine.Info(SourceDataLine.class, af);
            SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info);

            // generate some PCM data (a sine wave for simplicity)
            byte[] buffer = new byte[64];
            double step = Math.PI / buffer.length;
            double angle = Math.PI * 2;
            int i = buffer.length;
            while (i > 0) {
                double sine = Math.sin(angle);
                int sample = (int) Math.round(sine * 32767);
                buffer[--i] = (byte) (sample >> 8);
                buffer[--i] = (byte) sample;
                angle -= step;
            }

            // prepare audio output
            line.open(af, 4096);
            line.start();
            // output wave form repeatedly
            for (int n=0; n<500; ++n) {
                line.write(buffer, 0, buffer.length);
            }
            // shut down audio
            line.drain();
            line.stop();
            line.close();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

}

You see, its roughly ten lines for handling the line, half of the code is the section "generate PCM" which you can ignore if you get PCM from somehwere else. You need to pay attention to the creation of the correct AudioFormat, screw up the booleans for signed and/or endian and the PCM will sound very garbled, possibly not even recognizable.

Archimage answered 1/10, 2015 at 15:19 Comment(2)
Thanks a lot @Durandlal, I was not receiving correct PCM samples. Now its working fine. Thanks a lot for the help. :)Deejay
@Archimage Instead of generating the PCM data, is there any way to feed the PCM data coming from the remote server ?Jurassic

© 2022 - 2024 — McMap. All rights reserved.