here it is the juce_linux_JackAudio.cpp
actually it is tested under linux only, but since it is possible to write a jack client for windows and mac also, this could be easily moved in a shared place.
/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions
Copyright 2004-7 by Raw Material Software ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the
GNU General Public License, as published by the Free Software Foundation;
either version 2 of the License, or (at your option) any later version.
JUCE is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JUCE; if not, visit www.gnu.org/licenses or write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
------------------------------------------------------------------------------
If you'd like to release a closed-source product which uses JUCE, commercial
licenses are also available: visit www.rawmaterialsoftware.com/juce for
more information.
==============================================================================
*/
#include "../../../juce_Config.h"
#if JUCE_BUILD_GUI_CLASSES
#if JUCE_JACK
#include "linuxincludes.h"
//==============================================================================
/* Got an include error here? If so, you've either not got jack-audio-connection-kit
installed, or you've not got your paths set up correctly to find its header files.
If you don't have the jack-audio-connection-kit library and don't want to build
Juce with low latency audio support, just disable the JUCE_JACK flag in juce_Config.h
*/
#include <jack/jack.h>
#include <jack/transport.h>
//==============================================================================
#include "../../../src/juce_core/basics/juce_StandardHeader.h"
BEGIN_JUCE_NAMESPACE
#include "../../../src/juce_appframework/audio/devices/juce_AudioIODeviceType.h"
#include "../../../src/juce_core/threads/juce_Thread.h"
#include "../../../src/juce_core/threads/juce_ScopedLock.h"
#include "../../../src/juce_core/basics/juce_Time.h"
#include "../../../src/juce_core/io/files/juce_File.h"
#include "../../../src/juce_core/io/files/juce_FileInputStream.h"
#include "../../../src/juce_core/basics/juce_Singleton.h"
#include "../../../src/juce_appframework/audio/dsp/juce_AudioDataConverters.h"
#include "../../../src/juce_appframework/audio/dsp/juce_AudioSampleBuffer.h"
static const int maxNumChans = 64;
static const char* defaultJackAudioDeviceName = "JuceJack";
//==============================================================================
class JackAudioIODevice : public AudioIODevice
{
public:
JackAudioIODevice (const String& deviceName)
: AudioIODevice (deviceName, T("JACK")),
isOpen_ (false),
isStarted (false),
selectedDeviceName (deviceName),
callback (0),
totalNumberOfInputChannels (0),
totalNumberOfOutputChannels (0),
client (0),
emptyBuffer (1, 4096)
{
jack_status_t status;
client = jack_client_open (defaultJackAudioDeviceName, JackNoStartServer, &status);
if (client == 0)
{
if (status & JackServerFailed || status & JackServerError)
printf ("Unable to connect to JACK server\n");
if (status & JackVersionError)
printf ("Client's protocol version does not match\n");
if (status & JackInvalidOption)
printf ("The operation contained an invalid or unsupported option\n");
if (status & JackNameNotUnique)
printf ("The desired client name was not unique\n");
if (status & JackNoSuchClient)
printf ("Requested client does not exist\n");
if (status & JackInitFailure)
printf ("Unable to initialize client\n");
}
else
{
jack_set_error_function (JackAudioIODevice::errorCallback);
// open input ports
StringArray inputChannels (getInputChannelNames());
for (int i = 0; i < inputChannels.size(); i++)
{
String inputName;
inputName << "in_" << (++totalNumberOfInputChannels);
jack_port_t* input =
jack_port_register (client, (const char*) inputName, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
inputPorts.add (input);
}
// open output ports
StringArray outputChannels (getOutputChannelNames());
for (int i = 0; i < outputChannels.size (); i++)
{
String outputName;
outputName << "out_" << (++totalNumberOfOutputChannels);
jack_port_t* output =
jack_port_register (client, (const char*) outputName, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
/* XXX - HOW TO KNOW THIS HERE IF IT'S THE APPLICATION CALLBACK THAT IS INTRODUCING LATENCY ? */
// jack_port_set_latency (output, 0);
outputPorts.add (output);
}
}
}
~JackAudioIODevice()
{
if (client)
{
close ();
jack_client_close (client);
client = 0;
}
}
const StringArray getOutputChannelNames()
{
StringArray inputNames;
const char** ports = jack_get_ports (client, 0, 0, /* JackPortIsPhysical | */ JackPortIsInput);
if (ports && ports[0])
{
int j = 0;
while (ports[j])
{
String portName (ports[j++]);
if (portName.upToFirstOccurrenceOf (T(":"), false, false) == selectedDeviceName)
inputNames.add (portName.fromFirstOccurrenceOf (T(":"), false, false));
}
free (ports);
}
return inputNames;
}
const StringArray getInputChannelNames()
{
StringArray outputNames;
const char** ports = jack_get_ports (client, 0, 0, /* JackPortIsPhysical | */ JackPortIsOutput);
if (ports && ports[0])
{
int j = 0;
while (ports[j])
{
String portName (ports[j++]);
if (portName.upToFirstOccurrenceOf (T(":"), false, false) == selectedDeviceName)
outputNames.add (portName.fromFirstOccurrenceOf (T(":"), false, false));
}
free (ports);
}
return outputNames;
}
int getNumSampleRates()
{
return client ? 1 : 0;
}
double getSampleRate (int index)
{
return client ? jack_get_sample_rate (client) : 0;
}
int getNumBufferSizesAvailable()
{
return client ? 1 : 0;
}
int getBufferSizeSamples (int index)
{
return client ? jack_get_buffer_size (client) : 0;
}
int getDefaultBufferSize()
{
return client ? jack_get_buffer_size (client) : 0;
}
const String open (const BitArray& inputChannels,
const BitArray& outputChannels,
double sampleRate,
int bufferSizeSamples)
{
if (! client)
{
return T("JACK error: client not started as jack server running");
}
close();
// activate client !
jack_set_process_callback (client, JackAudioIODevice::processCallback, this);
jack_on_shutdown (client, JackAudioIODevice::shutdownCallback, this);
jack_activate (client);
isOpen_ = true;
// auto connect inputs
if (inputChannels.getHighestBit() >= 0)
{
const char** ports = jack_get_ports (client, 0, 0, /* JackPortIsPhysical | */ JackPortIsOutput);
if (ports && ports[0])
{
int numInputChannels = inputChannels.getHighestBit () + 1;
for (int i = 0; i < numInputChannels; ++i)
{
if (ports[i])
{
String portName (ports[i]);
if (inputChannels[i] && portName.upToFirstOccurrenceOf (T(":"), false, false) == selectedDeviceName)
{
int error = jack_connect (client, ports[i], jack_port_name ((jack_port_t*) inputPorts[i]));
if (error)
printf ("Cannot connect input port %d (%s) >> %d \n", i, ports[i], error);
}
}
}
free (ports);
}
}
// auto connect outputs
if (outputChannels.getHighestBit() >= 0)
{
const char** ports = jack_get_ports (client, 0, 0, /* JackPortIsPhysical | */ JackPortIsInput);
if (ports && ports[0])
{
int numOutputChannels = outputChannels.getHighestBit () + 1;
for (int i = 0; i < numOutputChannels; ++i)
{
if (ports[i])
{
String portName (ports[i]);
if (outputChannels[i] && portName.upToFirstOccurrenceOf (T(":"), false, false) == selectedDeviceName)
{
int error = jack_connect (client, jack_port_name ((jack_port_t*) outputPorts[i]), ports[i]);
if (error)
printf ("Cannot connect output port %d (%s) >> %d \n", i, ports[i], error);
}
}
}
free (ports);
}
}
return String::empty;
}
void close()
{
stop();
if (client)
{
jack_deactivate (client);
jack_set_process_callback (client, JackAudioIODevice::processCallback, 0);
jack_on_shutdown (client, JackAudioIODevice::shutdownCallback, 0);
}
isOpen_ = false;
}
bool isOpen()
{
return isOpen_;
}
int getCurrentBufferSizeSamples()
{
return getBufferSizeSamples (0);
}
double getCurrentSampleRate()
{
return getSampleRate (0);
}
int getCurrentBitDepth()
{
return 32;
}
const BitArray getActiveOutputChannels() const
{
BitArray outputBits;
for (int i = 0; i < outputPorts.size(); i++) {
if (jack_port_connected ((jack_port_t*) outputPorts [i]))
outputBits.setBit (i);
}
return outputBits;
}
const BitArray getActiveInputChannels() const
{
BitArray inputBits;
for (int i = 0; i < inputPorts.size(); i++) {
if (jack_port_connected ((jack_port_t*) inputPorts [i]))
inputBits.setBit (i);
}
return inputBits;
}
int getOutputLatencyInSamples()
{
int latency = 0;
for (int i = 0; i < outputPorts.size(); i++)
latency = jmax (latency, (int) jack_port_get_total_latency (client, (jack_port_t*) outputPorts [i]));
return latency;
}
int getInputLatencyInSamples()
{
int latency = 0;
for (int i = 0; i < inputPorts.size(); i++)
latency = jmax (latency, (int) jack_port_get_total_latency (client, (jack_port_t*) inputPorts [i]));
return latency;
}
void start (AudioIODeviceCallback* callback_)
{
if (! isOpen_)
callback_ = 0;
callback = callback_;
if (callback != 0)
callback->audioDeviceAboutToStart (this);
isStarted = (callback != 0);
}
void process (int numSamples)
{
int i, numActiveInChans = 0, numActiveOutChans = 0;
for (i = 0; i < totalNumberOfInputChannels; ++i)
{
jack_default_audio_sample_t *in =
(jack_default_audio_sample_t *) jack_port_get_buffer (
(jack_port_t*) inputPorts.getUnchecked(i), numSamples);
if (in != 0)
inChans [numActiveInChans++] = (float*) in;
}
while (numActiveInChans < totalNumberOfInputChannels)
inChans [numActiveInChans++] = emptyBuffer.getSampleData (0, 0);
for (i = 0; i < totalNumberOfOutputChannels; ++i)
{
jack_default_audio_sample_t *out =
(jack_default_audio_sample_t *) jack_port_get_buffer (
(jack_port_t*) outputPorts.getUnchecked(i), numSamples);
if (out != 0)
outChans [numActiveOutChans++] = (float*) out;
}
i = 0;
while (numActiveOutChans < totalNumberOfOutputChannels)
outChans [numActiveOutChans++] = emptyBuffer.getSampleData (++i, 0);
if (callback != 0)
{
callback->audioDeviceIOCallback ((const float**) inChans,
numActiveInChans,
outChans,
numActiveOutChans,
numSamples);
}
else
{
for (int i = 0; i < totalNumberOfOutputChannels; ++i)
zeromem (outChans[i], sizeof (float) * numSamples);
}
}
void stop()
{
AudioIODeviceCallback* const oldCallback = callback;
start (0);
if (oldCallback != 0)
oldCallback->audioDeviceStopped();
}
bool isPlaying()
{
return isStarted;
}
const String getLastError()
{
return String::empty;
}
private:
static void threadInitCallback (void* callbackArgument)
{
printf ("jack started");
}
static void shutdownCallback (void* callbackArgument)
{
printf ("jack shutdown");
JackAudioIODevice* device = (JackAudioIODevice*) callbackArgument;
if (device)
device->close ();
}
static int processCallback (jack_nframes_t nframes, void* callbackArgument)
{
JackAudioIODevice* device = (JackAudioIODevice*) callbackArgument;
if (device)
device->process (nframes);
return 0;
}
static void errorCallback (const char *msg)
{
printf ("%s\n", msg);
}
bool isOpen_, isStarted;
String selectedDeviceName;
AudioIODeviceCallback* callback;
float* inChans [maxNumChans];
int totalNumberOfInputChannels;
float* outChans [maxNumChans];
int totalNumberOfOutputChannels;
jack_client_t *client;
VoidArray inputPorts;
VoidArray outputPorts;
AudioSampleBuffer emptyBuffer;
};
//==============================================================================
class JackAudioIODeviceType : public AudioIODeviceType
{
public:
//==============================================================================
JackAudioIODeviceType()
: AudioIODeviceType (T("JACK")),
hasScanned (false)
{
}
~JackAudioIODeviceType()
{
}
//==============================================================================
void scanForDevices()
{
printf ("JackAudioIODeviceType::scanForDevices\n");
hasScanned = true;
names.clear();
// open a dummy client
jack_status_t status;
jack_client_t* client;
const char** ports = 0;
client = jack_client_open ("JackAndMrHide", JackNoStartServer, &status);
if (client == 0)
{
if (status & JackServerFailed || status & JackServerError)
printf ("Unable to connect to JACK server\n");
if (status & JackVersionError)
printf ("Client's protocol version does not match\n");
if (status & JackInvalidOption)
printf ("The operation contained an invalid or unsupported option\n");
if (status & JackNameNotUnique)
printf ("The desired client name was not unique\n");
if (status & JackNoSuchClient)
printf ("Requested client does not exist\n");
if (status & JackInitFailure)
printf ("Unable to initialize client\n");
}
else
{
// scan for output devices
ports = jack_get_ports (client, 0, 0, /* JackPortIsPhysical | */ JackPortIsOutput);
if (ports && ports[0])
{
int j = 0;
while (ports [j])
{
String clientName (ports [j++]);
clientName = clientName.upToFirstOccurrenceOf (T(":"), false, false);
if (clientName != String (defaultJackAudioDeviceName))
names.add (clientName);
}
free (ports);
}
// scan for input devices
ports = jack_get_ports (client, 0, 0, /* JackPortIsPhysical | */ JackPortIsInput);
if (ports && ports[0])
{
int j = 0;
while (ports [j])
{
String clientName (ports [j++]);
clientName = clientName.upToFirstOccurrenceOf (T(":"), false, false);
if (clientName != String (defaultJackAudioDeviceName))
names.add (clientName);
}
free (ports);
}
jack_client_close (client);
}
}
const StringArray getDeviceNames (const bool /*preferInputNames*/) const
{
jassert (hasScanned); // need to call scanForDevices() before doing this
StringArray namesCopy (names);
namesCopy.removeDuplicates (true);
return namesCopy;
}
const String getDefaultDeviceName (const bool /*preferInputNames*/,
const int /*numInputChannelsNeeded*/,
const int /*numOutputChannelsNeeded*/) const
{
jassert (hasScanned); // need to call scanForDevices() before doing this
return names[0];
}
AudioIODevice* createDevice (const String& deviceName)
{
jassert (hasScanned); // need to call scanForDevices() before doing this
const int index = names.indexOf (deviceName);
if (index >= 0)
return new JackAudioIODevice (deviceName);
return 0;
}
//==============================================================================
juce_UseDebuggingNewOperator
private:
StringArray names;
bool hasScanned;
JackAudioIODeviceType (const JackAudioIODeviceType&);
const JackAudioIODeviceType& operator= (const JackAudioIODeviceType&);
};
//==============================================================================
AudioIODeviceType* juce_createJackAudioIODeviceType()
{
return new JackAudioIODeviceType();
}
END_JUCE_NAMESPACE
//==============================================================================
#else // if JACK is turned off..
#include "../../../src/juce_core/basics/juce_StandardHeader.h"
BEGIN_JUCE_NAMESPACE
#include "../../../src/juce_appframework/audio/devices/juce_AudioIODeviceType.h"
AudioIODeviceType* juce_createJackAudioIODeviceType() { return 0; }
END_JUCE_NAMESPACE
#endif
#endif
it needs also you put this lines in juce_AudioIODeviceType.cpp and tweaks juce_Config.h by putting JUCE_JACK define (besides JUCE_ALSA)
//==============================================================================
extern AudioIODeviceType* juce_createDefaultAudioIODeviceType();
#if JUCE_WIN32 && JUCE_ASIO
extern AudioIODeviceType* juce_createASIOAudioIODeviceType();
#endif
#if JUCE_WIN32 && JUCE_WDM_AUDIO
extern AudioIODeviceType* juce_createWDMAudioIODeviceType();
#endif
#if JUCE_LINUX && JUCE_JACK
extern AudioIODeviceType* juce_createJackAudioIODeviceType();
#endif
//==============================================================================
void AudioIODeviceType::createDeviceTypes (OwnedArray <AudioIODeviceType>& list)
{
AudioIODeviceType* const defaultDeviceType = juce_createDefaultAudioIODeviceType();
if (defaultDeviceType != 0)
list.add (defaultDeviceType);
#if JUCE_WIN32 && JUCE_ASIO
list.add (juce_createASIOAudioIODeviceType());
#endif
#if JUCE_WIN32 && JUCE_WDM_AUDIO
list.add (juce_createWDMAudioIODeviceType());
#endif
#if JUCE_LINUX && JUCE_JACK
list.add (juce_createJackAudioIODeviceType());
#endif
}
hope it will be included in the main trunk 
(EDIT)