How best to communicate between 2 JUCE Apps with low latency


#1

Hi,

I have been investigating different options for communicating between two JUCE apps - one will be a JUCE Plugin acting as a CLIENT, the other will be a JUCE Application
acting as a SERVER. This is on OSX for the time being. Eventually windows too.

I have a strong feeling that VST and AudioUnit sequencer makers who provide a 64 bit mode and provide a 32 bit “bridge” for older 32 bit plugins have to be doing something similar to this. And i assume they ( Apple with Logic for example ) must be doing it in a manner that doesnt penalise the CPU or add much latency.

Basically i use shared memory to pass audio blocks from server to client, and have been experimenting with different ways to send a COMMAND to the server from the plugin to go and
generate the next audio block. The client plugin will first stuff MIDI into a shared memory area before sending the command.

Given that for sample blok sizes of 64 we’re talking only a window of around 1.5 ms between each audio “fetch”, this means i need a fast and reliable interprocess mechanism.

IPC seems to give very high latencies and is dependent on whats going onGUI wise,
Using a UNIX USER SIGNAL gives low latencies but needs very good thread-safe coding.
I tried using a SIGNAL to wake a regular thread, and let the thread do the processing work - but this was very slow and dependent on the App event loop.
I tried using a timer to do a POLL , which was set to 1ms, which gives lowish latencies that are quite consistent but not as low as SIGNAL.

Is it possible to have timers in JUCE with intervals less than a millisecond ?

Using A pure loop gave good latencies but only if one doesnt yield much CPU time to the OS inside the loop, which wastes CPU.

Does anyone have suggestions as to the best REAL-TIME scheme for this in OSX + JUCE ?

Incidentally this has to be a PULL architecture. A push scheme wont work.

Any thoughts ?

Dan


#2

Another issue I have in connection to this is I need to find a way for the plugin to efficiently “block” during a request for a new audioblock from the server ( inside getNextAudioBlock() )
until it receives an indication that the server has completed refilling the audio buffers in shared memory.

Currently all i do is use a wait loop to test a shared memory “ready” flag. There is a Yield() inside the loop to ensure we dont hog all the CPU while waiting, but I’m not convinced this is the most efficient way of waiting around. The client “block” or “poll” is effectively inside an audio callback invoked by the VST host, so i dont see any way i can use threads to help out.

Any thoughts ?


#3

On Windows you can use a named Semaphore. I’m pretty sure every platform has its own similar interprocess-communications device.


#4

thats more to do with sharing data across processes - which i’ve solved.

My issue is more about hoq quickly i can get my “target” process ( server ) to respond to a “prod” from my client.


#5

thats more to do with sharing data across processes - which i’ve solved.[/quote]

No…semaphores are not for sharing data they are for synchronization. From MSDN:

The idea is the your server process has a thread that blocks on the semaphore, and the client signals the semaphore to “wake up” the server (usually after putting some data into a queue via shared memory).

You can also block on a named pipe, which allows you to wait for data.

This is all under Windows. Not sure about other platforms.


#6

Don’t reinvent the wheel.
With Juce’s code, you can use either:

  • socket (StreamingSocket with waitUntilReadable() in a Thread loop)
  • InterprocessConnection (NamedPipe), with blocking read (that’s using Pipes or Unix socket depending on your platform)

The latency you’ll get will be the smallest you can get in a cross platform way.
If you even want to reduce this latency to the absolute minimum, set your waiting thread priority to the maximum (realtime).
That way, as soon as the condition is met, the kernel will stop your process and wake up the other process (on a decent computer, that’s in the microsecond order)


#7

[quote=“X-Ryl669”]Don’t reinvent the wheel.
With Juce’s code, you can use either:

  • socket (StreamingSocket with waitUntilReadable() in a Thread loop)
  • InterprocessConnection (NamedPipe), with blocking read (that’s using Pipes or Unix socket depending on your platform)

The latency you’ll get will be the smallest you can get in a cross platform way.
If you even want to reduce this latency to the absolute minimum, set your waiting thread priority to the maximum (realtime).
That way, as soon as the condition is met, the kernel will stop your process and wake up the other process (on a decent computer, that’s in the microsecond order)[/quote]

yjos wpmt wprlk ( for ME ) because the waiting process is the one that generates the CoreAudio callback and is not under my control ( its owned by the OS and cant be paused )


#8

Can’t you create an extra thread from within your CoreAudio callback and use that for interprocess communication, and let the extra thread talk to your CoreAudio callback using traditional thread synchronization?


#9

Can’t you create an extra thread from within your CoreAudio callback and use that for interprocess communication, and let the extra thread talk to your CoreAudio callback using traditional thread synchronization?[/quote]

but then the extra thread will be the one to block, but I dont want the CoreAudio callback to be continuing - it needs to be waiting too, until audio is ready at the server end.


#10

Then all of the proposed techniques in this thread should work for you from within the CoreAudio thread - try not to block for too long!