oh I missed you audiofilterstream ! However I think it does not fit with my application which expects au AudioDeviceManager etc. Instead I have taken your JackAudioIODevice class and stripped all the ports connection stuff to keep the bare minimum (btw in the shutdown callback, you should set device->client = 0 before calling the close() method, or the application dies with a SIGPIPE):
- Code: Select all
#include "jack_device.hh"
static const char* defaultJackAudioDeviceName = "jackd";
//==============================================================================
class JackAudioIODevice : public AudioIODevice
{
JackClientConfiguration config;
public:
JackAudioIODevice (JackClientConfiguration &config_)
: AudioIODevice (defaultJackAudioDeviceName, T("JACK")),
config(config_),
isOpen_ (false),
isStarted (false),
callback (0),
client (0)
{
for (int i=0; i < config.inputChannels.size(); ++i) {
if (config.inputChannels[i].length() == 0) config.inputChannels.set(i, T("in_")+String(i));
}
for (int i = 0; i < config.outputChannels.size(); i++) {
if (config.outputChannels[i].length() == 0) config.outputChannels.set(i, T("out_")+String(i));
}
jack_status_t status;
client = jack_client_open (config.clientName.toUTF8(), 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);
for (int i=0; i < config.inputChannels.size(); ++i) {
jack_port_t* input =
jack_port_register (client, config.inputChannels[i].toUTF8(), JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
inputPorts.add (input);
}
for (int i = 0; i < config.outputChannels.size(); i++) {
jack_port_t* output =
jack_port_register (client, config.outputChannels[i].toUTF8(), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
outputPorts.add (output);
}
}
inChans = (float**)juce_malloc(config.inputChannels.size() *sizeof(float*));
outChans = (float**)juce_malloc(config.outputChannels.size()*sizeof(float*));
}
~JackAudioIODevice()
{
if (client)
{
close ();
jack_client_close (client);
client = 0;
}
juce_free(inChans);
juce_free(outChans);
}
const StringArray getOutputChannelNames() { return config.outputChannels; }
const StringArray getInputChannelNames() { return config.inputChannels; }
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 server is not running");
}
close();
// activate client !
jack_set_process_callback (client, JackAudioIODevice::processCallback, this);
jack_on_shutdown (client, JackAudioIODevice::shutdownCallback, this);
jack_activate (client);
isOpen_ = true;
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;
outputBits.setRange(0, outputPorts.size(), true);
return outputBits;
}
const BitArray getActiveInputChannels() const
{
BitArray inputBits;
inputBits.setRange(0, inputPorts.size(), true);
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 < inputPorts.size(); ++i)
{
jack_default_audio_sample_t *in =
(jack_default_audio_sample_t *) jack_port_get_buffer (
(jack_port_t*) inputPorts.getUnchecked(i), numSamples);
jassert (in != 0);
inChans [numActiveInChans++] = (float*) in;
}
for (i = 0; i < outputPorts.size(); ++i)
{
jack_default_audio_sample_t *out =
(jack_default_audio_sample_t *) jack_port_get_buffer (
(jack_port_t*) outputPorts.getUnchecked(i), numSamples);
jassert (out != 0);
outChans [numActiveOutChans++] = (float*) out;
}
if (callback != 0)
{
callback->audioDeviceIOCallback ((const float**) inChans,
inputPorts.size(),
outChans,
outputPorts.size(),
numSamples);
}
else
{
for (i = 0; i < outputPorts.size(); ++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;
}
String inputId, outputId;
private:
static void threadInitCallback (void* /*callbackArgument*/)
{
}
static void shutdownCallback (void* callbackArgument)
{
JackAudioIODevice* device = (JackAudioIODevice*) callbackArgument;
if (device)
{
device->client = 0;
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)
{
fprintf (stderr, "Jack error: %s\n", msg);
}
bool isOpen_, isStarted;
AudioIODeviceCallback* callback;
float** inChans;
float** outChans;
jack_client_t *client;
VoidArray inputPorts;
VoidArray outputPorts;
};
//==============================================================================
class JackAudioIODeviceType : public AudioIODeviceType
{
public:
//==============================================================================
JackAudioIODeviceType()
: AudioIODeviceType(T("JACK"))
{
}
~JackAudioIODeviceType()
{
}
//==============================================================================
void scanForDevices()
{
}
const StringArray getDeviceNames (const bool /*wantInputNames*/) const
{
StringArray s;
s.add(defaultJackAudioDeviceName);
return s;
}
int getDefaultDeviceIndex (const bool /*forInput*/) const
{
return 0;
}
bool hasSeparateInputsAndOutputs() const { return false; }
int getIndexOfDevice (AudioIODevice* device, const bool /*asInput*/) const
{
JackAudioIODevice* const d = dynamic_cast <JackAudioIODevice*> (device);
return (d == 0) ? -1 : 0;
}
AudioIODevice* createDevice (const String& /*outputDeviceName*/,
const String& /*inputDeviceName*/)
{
JackClientConfiguration config;
getJackClientConfiguration(config);
return new JackAudioIODevice(config);
return 0;
}
//==============================================================================
juce_UseDebuggingNewOperator
private:
JackAudioIODeviceType (const JackAudioIODeviceType&);
const JackAudioIODeviceType& operator= (const JackAudioIODeviceType&);
};
#ifndef USING_RELAYTOOL_FOR_LIBJACK
#define USING_RELAYTOOL_FOR_LIBJACK 1
#endif
#if USING_RELAYTOOL_FOR_LIBJACK
extern "C" int libjack_is_present;
#endif
namespace juce {
//==============================================================================
AudioIODeviceType* juce_createJackAudioIODeviceType()
{
#if USING_RELAYTOOL_FOR_LIBJACK
/* detect if libjack.so is available using relaytool on linux */
if (!libjack_is_present) return 0;
#endif
/* detect if the jack framework is available on macos
(requires linking with -weak_framework Jackmd) */
if ((void*)&jack_client_open == 0)
return 0;
return new JackAudioIODeviceType();
}
} // namespace juce
and the jack_device.hh file contains:
- Code: Select all
struct JackClientConfiguration {
String clientName;
// size of array = number of input channels. If the strings are empty, default names are chosen (in_1 , in_2 etc)
StringArray inputChannels;
StringArray outputChannels;
};
// user supplied function for jack config
void getJackClientConfiguration(JackClientConfiguration &conf);
That way my application supplies the number of ports it wants , and does not deal at all with connections to other jack ports . I have tested it on macos also and it works (but it is not very useful since jackosx also create a fake coreaudio device)
The relaytool (
http://autopackage.org/apbuild-relaytool.php ) stuff is to build a binary that is not "hardlinked" to libjack.so, the result is equivalent to weak linking on macos