DatagramSocket problem


#1

I have the following code in my application:

    int inputPort = 50002;
    int outputPort = 50001;
    bool inBound = inputSocket.bindToPort (inputPort);
    bool outBound = outputSocket.bindToPort (outputPort);
    int inReady = inputSocket.waitUntilReady(true, 5000);
    int outReady = outputSocket.waitUntilReady(false, 5000);

The value of inReady is always 0, while the value of outReady is always 1, even if I swap the port numbers. What could be the reason? I am on Ubuntu.


#2

inReady=1 just means, that no data has arrived yet at port 50002 and therefore the socket is not yet ready for reading without blocking. outReady=1 means, that it’s OK to send data via the outputSocket.

think of waitUntilReady(true,…) as waitUntilThereIsDataAvailableForReading(…) and
waitUntilReady(false, …) as waitUntilItsCoolToWriteDataToTheSocket(…).

There’s no need to wait for readiness after binding the sockets and before calling read()/write() -
if that’s what you where thinking. waitUntilReady is just there as a facility to ask the socket if data is available (or there’s room for more data being send) - note that waitUntilReady has a timeout parameter while read() and write() don’t. Have a look at InterprocessConnection::runThread() for a typical usage pattern. It’s using a TCP socket, but the same principles apply.


#3

Thank you! I have another question. I want to send the input of my audio card via UDP and to receive remote audio. Is it correct to put the following code inside the getNextAudioBlock() function? Also, how can I test this code?

void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill) override
{
   
    if(shouldPlay) // this is given by a "play" button
    {
        const int channel = 0;
        const float* inBuffer = bufferToFill.buffer->getReadPointer(channel, bufferToFill.startSample);
        float* outBuffer = bufferToFill.buffer->getWritePointer(channel, bufferToFill.startSample);           
        inputSocket.read(outBuffer, 128, false);
        outputSocket.write("127.0.0.1", inputPort, inBuffer, 128); 
    }
    else
    {
        bufferToFill.buffer->clear(0, bufferToFill.startSample, bufferToFill.numSamples);
    }

}

#4

I have a few remarks regarding your code:

  1. inBuffer and outBuffer should point to the same location, this means with the current order of your read() and write() calls you won’t send the input to the processor but the data you just received. You could avoid that by switching your read() and write() lines.
  2. I would advise against using OS API calls like socket read/write from the audio thread. Use a lockfree queue / ring buffer to get audio out of the audio thread and do the sending and receiving in another thread. (can’t tell how the method you posted is called)
  3. You have hard-coded your send/read buffer size (128). don’t forget to multiply the number of elements with sizeof(float), i.e numBytesToTransfer = bufferToFill.numSamples * sizeof(float)
  4. Personally I would start with writing a simple udp server in python that just logs the data it receives. If that works, I’d extend it to write the date back to a different port.
  5. of course, I don’t know, what you’re planning to do, but if you’re planning to play the audio on different machines (or different audio interfaces on the same machine), you also need to consider clock drift.

#5

Thank you, I really appreciate your suggestions! Can you provide some references for the second point (lockfree queue / ring buffer)? Please note that latency has to be minimized.


#6

Have a look at the JUCE docs and maybe search the forum. If you just want to route audio between different applications, you should consider Soundflower. one of the more complicated issues I encountered when approaching something similar was to sync the audio on the remote end while keeping latency low. The DAW of course calls your processor from different threads and it is hard to determine where one block ends and the next one starts. But anyhow, Godspeed!