mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
JACK: Fix bug where input and output devices were reversed
This commit is contained in:
parent
33f34273d4
commit
8fc1c1abae
3 changed files with 175 additions and 127 deletions
|
|
@ -36,9 +36,11 @@ static void* juce_loadJackFunction (const char* const name)
|
|||
#define JUCE_DECL_JACK_FUNCTION(return_type, fn_name, argument_types, arguments) \
|
||||
return_type fn_name argument_types \
|
||||
{ \
|
||||
using ReturnType = return_type; \
|
||||
typedef return_type (*fn_type) argument_types; \
|
||||
static fn_type fn = (fn_type) juce_loadJackFunction (#fn_name); \
|
||||
return (fn != nullptr) ? ((*fn) arguments) : (return_type) 0; \
|
||||
jassert (fn != nullptr); \
|
||||
return (fn != nullptr) ? ((*fn) arguments) : ReturnType(); \
|
||||
}
|
||||
|
||||
#define JUCE_DECL_VOID_JACK_FUNCTION(fn_name, argument_types, arguments) \
|
||||
|
|
@ -46,6 +48,7 @@ static void* juce_loadJackFunction (const char* const name)
|
|||
{ \
|
||||
typedef void (*fn_type) argument_types; \
|
||||
static fn_type fn = (fn_type) juce_loadJackFunction (#fn_name); \
|
||||
jassert (fn != nullptr); \
|
||||
if (fn != nullptr) (*fn) arguments; \
|
||||
}
|
||||
|
||||
|
|
@ -57,6 +60,7 @@ JUCE_DECL_JACK_FUNCTION (int, jack_deactivate, (jack_client_t* client), (client)
|
|||
JUCE_DECL_JACK_FUNCTION (jack_nframes_t, jack_get_buffer_size, (jack_client_t* client), (client))
|
||||
JUCE_DECL_JACK_FUNCTION (jack_nframes_t, jack_get_sample_rate, (jack_client_t* client), (client))
|
||||
JUCE_DECL_VOID_JACK_FUNCTION (jack_on_shutdown, (jack_client_t* client, void (*function)(void* arg), void* arg), (client, function, arg))
|
||||
JUCE_DECL_VOID_JACK_FUNCTION (jack_on_info_shutdown, (jack_client_t* client, JackInfoShutdownCallback function, void* arg), (client, function, arg))
|
||||
JUCE_DECL_JACK_FUNCTION (void* , jack_port_get_buffer, (jack_port_t* port, jack_nframes_t nframes), (port, nframes))
|
||||
JUCE_DECL_JACK_FUNCTION (jack_nframes_t, jack_port_get_total_latency, (jack_client_t* client, jack_port_t* port), (client, port))
|
||||
JUCE_DECL_JACK_FUNCTION (jack_port_t* , jack_port_register, (jack_client_t* client, const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size), (client, port_name, port_type, flags, buffer_size))
|
||||
|
|
@ -70,6 +74,9 @@ JUCE_DECL_JACK_FUNCTION (jack_port_t* , jack_port_by_id, (jack_client_t* client,
|
|||
JUCE_DECL_JACK_FUNCTION (int, jack_port_connected, (const jack_port_t* port), (port))
|
||||
JUCE_DECL_JACK_FUNCTION (int, jack_port_connected_to, (const jack_port_t* port, const char* port_name), (port, port_name))
|
||||
JUCE_DECL_JACK_FUNCTION (int, jack_set_xrun_callback, (jack_client_t* client, JackXRunCallback xrun_callback, void* arg), (client, xrun_callback, arg))
|
||||
JUCE_DECL_JACK_FUNCTION (int, jack_port_flags, (const jack_port_t* port), (port))
|
||||
JUCE_DECL_JACK_FUNCTION (jack_port_t*, jack_port_by_name, (jack_client_t* client, const char* name), (client, name))
|
||||
JUCE_DECL_VOID_JACK_FUNCTION (jack_free, (void* ptr), (ptr))
|
||||
|
||||
#if JUCE_DEBUG
|
||||
#define JACK_LOGGING_ENABLED 1
|
||||
|
|
@ -115,56 +122,56 @@ namespace
|
|||
struct JackPortIterator
|
||||
{
|
||||
JackPortIterator (jack_client_t* const client, const bool forInput)
|
||||
: ports (nullptr), index (-1)
|
||||
{
|
||||
if (client != nullptr)
|
||||
ports = juce::jack_get_ports (client, nullptr, nullptr,
|
||||
forInput ? JackPortIsOutput : JackPortIsInput);
|
||||
// (NB: This looks like it's the wrong way round, but it is correct!)
|
||||
}
|
||||
|
||||
~JackPortIterator()
|
||||
{
|
||||
::free (ports);
|
||||
ports.reset (juce::jack_get_ports (client, nullptr, nullptr,
|
||||
forInput ? JackPortIsInput : JackPortIsOutput));
|
||||
}
|
||||
|
||||
bool next()
|
||||
{
|
||||
if (ports == nullptr || ports [index + 1] == nullptr)
|
||||
if (ports == nullptr || ports.get()[index + 1] == nullptr)
|
||||
return false;
|
||||
|
||||
name = CharPointer_UTF8 (ports[++index]);
|
||||
clientName = name.upToFirstOccurrenceOf (":", false, false);
|
||||
name = CharPointer_UTF8 (ports.get()[++index]);
|
||||
return true;
|
||||
}
|
||||
|
||||
const char** ports;
|
||||
int index;
|
||||
String name;
|
||||
String clientName;
|
||||
};
|
||||
String getClientName() const
|
||||
{
|
||||
return name.upToFirstOccurrenceOf (":", false, false);
|
||||
}
|
||||
|
||||
class JackAudioIODeviceType;
|
||||
static Array<JackAudioIODeviceType*> activeDeviceTypes;
|
||||
String getChannelName() const
|
||||
{
|
||||
return name.fromFirstOccurrenceOf (":", false, false);
|
||||
}
|
||||
|
||||
struct Free
|
||||
{
|
||||
void operator() (const char** ptr) const noexcept { juce::jack_free (ptr); }
|
||||
};
|
||||
|
||||
std::unique_ptr<const char*, Free> ports;
|
||||
int index = -1;
|
||||
String name;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class JackAudioIODevice : public AudioIODevice
|
||||
{
|
||||
public:
|
||||
JackAudioIODevice (const String& deviceName,
|
||||
const String& inId,
|
||||
const String& outId)
|
||||
: AudioIODevice (deviceName, "JACK"),
|
||||
inputId (inId),
|
||||
outputId (outId),
|
||||
deviceIsOpen (false),
|
||||
callback (nullptr),
|
||||
totalNumberOfInputChannels (0),
|
||||
totalNumberOfOutputChannels (0)
|
||||
JackAudioIODevice (const String& inName,
|
||||
const String& outName,
|
||||
std::function<void()> notifyIn)
|
||||
: AudioIODevice (outName.isEmpty() ? inName : outName, "JACK"),
|
||||
inputName (inName),
|
||||
outputName (outName),
|
||||
notifyChannelsChanged (std::move (notifyIn))
|
||||
{
|
||||
jassert (deviceName.isNotEmpty());
|
||||
jassert (outName.isNotEmpty() || inName.isNotEmpty());
|
||||
|
||||
jack_status_t status;
|
||||
jack_status_t status = {};
|
||||
client = juce::jack_client_open (JUCE_JACK_CLIENT_NAME, JackNoStartServer, &status);
|
||||
|
||||
if (client == nullptr)
|
||||
|
|
@ -202,7 +209,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
~JackAudioIODevice()
|
||||
~JackAudioIODevice() override
|
||||
{
|
||||
close();
|
||||
if (client != nullptr)
|
||||
|
|
@ -212,19 +219,19 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
StringArray getChannelNames (bool forInput) const
|
||||
StringArray getChannelNames (const String& clientName, bool forInput) const
|
||||
{
|
||||
StringArray names;
|
||||
|
||||
for (JackPortIterator i (client, forInput); i.next();)
|
||||
if (i.clientName == getName())
|
||||
names.add (i.name.fromFirstOccurrenceOf (":", false, false));
|
||||
if (i.getClientName() == clientName)
|
||||
names.add (i.getChannelName());
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
StringArray getOutputChannelNames() override { return getChannelNames (false); }
|
||||
StringArray getInputChannelNames() override { return getChannelNames (true); }
|
||||
StringArray getOutputChannelNames() override { return getChannelNames (outputName, true); }
|
||||
StringArray getInputChannelNames() override { return getChannelNames (inputName, false); }
|
||||
|
||||
Array<double> getAvailableSampleRates() override
|
||||
{
|
||||
|
|
@ -250,6 +257,20 @@ public:
|
|||
int getCurrentBufferSizeSamples() override { return client != nullptr ? static_cast<int> (juce::jack_get_buffer_size (client)) : 0; }
|
||||
double getCurrentSampleRate() override { return client != nullptr ? static_cast<int> (juce::jack_get_sample_rate (client)) : 0; }
|
||||
|
||||
template <typename Fn>
|
||||
void forEachClientChannel (const String& clientName, bool isInput, Fn&& fn)
|
||||
{
|
||||
auto index = 0;
|
||||
|
||||
for (JackPortIterator i (client, isInput); i.next();)
|
||||
{
|
||||
if (i.getClientName() != clientName)
|
||||
continue;
|
||||
|
||||
fn (i.ports.get()[i.index], index);
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
String open (const BigInteger& inputChannels, const BigInteger& outputChannels,
|
||||
double /* sampleRate */, int /* bufferSizeSamples */) override
|
||||
|
|
@ -263,38 +284,55 @@ public:
|
|||
lastError.clear();
|
||||
close();
|
||||
|
||||
xruns = 0;
|
||||
xruns.store (0, std::memory_order_relaxed);
|
||||
juce::jack_set_process_callback (client, processCallback, this);
|
||||
juce::jack_set_port_connect_callback (client, portConnectCallback, this);
|
||||
juce::jack_on_shutdown (client, shutdownCallback, this);
|
||||
juce::jack_on_info_shutdown (client, infoShutdownCallback, this);
|
||||
juce::jack_set_xrun_callback (client, xrunCallback, this);
|
||||
juce::jack_activate (client);
|
||||
deviceIsOpen = true;
|
||||
|
||||
if (! inputChannels.isZero())
|
||||
{
|
||||
for (JackPortIterator i (client, true); i.next();)
|
||||
forEachClientChannel (inputName, false, [&] (const char* portName, int index)
|
||||
{
|
||||
if (inputChannels [i.index] && i.clientName == getName())
|
||||
{
|
||||
int error = juce::jack_connect (client, i.ports[i.index], juce::jack_port_name ((jack_port_t*) inputPorts[i.index]));
|
||||
if (error != 0)
|
||||
JUCE_JACK_LOG ("Cannot connect input port " + String (i.index) + " (" + i.name + "), error " + String (error));
|
||||
}
|
||||
}
|
||||
if (! inputChannels[index])
|
||||
return;
|
||||
|
||||
jassert (index < inputPorts.size());
|
||||
|
||||
const auto* source = portName;
|
||||
const auto* inputPort = inputPorts[index];
|
||||
|
||||
jassert (juce::jack_port_flags (juce::jack_port_by_name (client, source)) & JackPortIsOutput);
|
||||
jassert (juce::jack_port_flags (inputPort) & JackPortIsInput);
|
||||
|
||||
auto error = juce::jack_connect (client, source, juce::jack_port_name (inputPort));
|
||||
if (error != 0)
|
||||
JUCE_JACK_LOG ("Cannot connect input port " + String (index) + " (" + portName + "), error " + String (error));
|
||||
});
|
||||
}
|
||||
|
||||
if (! outputChannels.isZero())
|
||||
{
|
||||
for (JackPortIterator i (client, false); i.next();)
|
||||
forEachClientChannel (outputName, true, [&] (const char* portName, int index)
|
||||
{
|
||||
if (outputChannels [i.index] && i.clientName == getName())
|
||||
{
|
||||
int error = juce::jack_connect (client, juce::jack_port_name ((jack_port_t*) outputPorts[i.index]), i.ports[i.index]);
|
||||
if (error != 0)
|
||||
JUCE_JACK_LOG ("Cannot connect output port " + String (i.index) + " (" + i.name + "), error " + String (error));
|
||||
}
|
||||
}
|
||||
if (! outputChannels[index])
|
||||
return;
|
||||
|
||||
jassert (index < outputPorts.size());
|
||||
|
||||
const auto* outputPort = outputPorts[index];
|
||||
const auto* destination = portName;
|
||||
|
||||
jassert (juce::jack_port_flags (outputPort) & JackPortIsOutput);
|
||||
jassert (juce::jack_port_flags (juce::jack_port_by_name (client, destination)) & JackPortIsInput);
|
||||
|
||||
auto error = juce::jack_connect (client, juce::jack_port_name (outputPort), destination);
|
||||
if (error != 0)
|
||||
JUCE_JACK_LOG ("Cannot connect output port " + String (index) + " (" + portName + "), error " + String (error));
|
||||
});
|
||||
}
|
||||
|
||||
updateActivePorts();
|
||||
|
|
@ -308,12 +346,15 @@ public:
|
|||
|
||||
if (client != nullptr)
|
||||
{
|
||||
juce::jack_deactivate (client);
|
||||
const auto result = juce::jack_deactivate (client);
|
||||
jassert (result == 0);
|
||||
ignoreUnused (result);
|
||||
|
||||
juce::jack_set_xrun_callback (client, xrunCallback, nullptr);
|
||||
juce::jack_set_process_callback (client, processCallback, nullptr);
|
||||
juce::jack_set_port_connect_callback (client, portConnectCallback, nullptr);
|
||||
juce::jack_on_shutdown (client, shutdownCallback, nullptr);
|
||||
juce::jack_on_info_shutdown (client, infoShutdownCallback, nullptr);
|
||||
}
|
||||
|
||||
deviceIsOpen = false;
|
||||
|
|
@ -347,7 +388,7 @@ public:
|
|||
bool isPlaying() override { return callback != nullptr; }
|
||||
int getCurrentBitDepth() override { return 32; }
|
||||
String getLastError() override { return lastError; }
|
||||
int getXRunCount() const noexcept override { return xruns; }
|
||||
int getXRunCount() const noexcept override { return xruns.load (std::memory_order_relaxed); }
|
||||
|
||||
BigInteger getActiveOutputChannels() const override { return activeOutputChannels; }
|
||||
BigInteger getActiveInputChannels() const override { return activeInputChannels; }
|
||||
|
|
@ -357,7 +398,7 @@ public:
|
|||
int latency = 0;
|
||||
|
||||
for (int i = 0; i < outputPorts.size(); i++)
|
||||
latency = jmax (latency, (int) juce::jack_port_get_total_latency (client, (jack_port_t*) outputPorts [i]));
|
||||
latency = jmax (latency, (int) juce::jack_port_get_total_latency (client, outputPorts[i]));
|
||||
|
||||
return latency;
|
||||
}
|
||||
|
|
@ -367,14 +408,36 @@ public:
|
|||
int latency = 0;
|
||||
|
||||
for (int i = 0; i < inputPorts.size(); i++)
|
||||
latency = jmax (latency, (int) juce::jack_port_get_total_latency (client, (jack_port_t*) inputPorts [i]));
|
||||
latency = jmax (latency, (int) juce::jack_port_get_total_latency (client, inputPorts[i]));
|
||||
|
||||
return latency;
|
||||
}
|
||||
|
||||
String inputId, outputId;
|
||||
String inputName, outputName;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
class MainThreadDispatcher : private AsyncUpdater
|
||||
{
|
||||
public:
|
||||
explicit MainThreadDispatcher (JackAudioIODevice& device) : ref (device) {}
|
||||
~MainThreadDispatcher() override { cancelPendingUpdate(); }
|
||||
|
||||
void updateActivePorts()
|
||||
{
|
||||
if (MessageManager::getInstance()->isThisTheMessageThread())
|
||||
handleAsyncUpdate();
|
||||
else
|
||||
triggerAsyncUpdate();
|
||||
}
|
||||
|
||||
private:
|
||||
void handleAsyncUpdate() override { ref.updateActivePorts(); }
|
||||
|
||||
JackAudioIODevice& ref;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
void process (const int numSamples)
|
||||
{
|
||||
int numActiveInChans = 0, numActiveOutChans = 0;
|
||||
|
|
@ -382,17 +445,17 @@ private:
|
|||
for (int i = 0; i < totalNumberOfInputChannels; ++i)
|
||||
{
|
||||
if (activeInputChannels[i])
|
||||
if (jack_default_audio_sample_t* in
|
||||
= (jack_default_audio_sample_t*) juce::jack_port_get_buffer ((jack_port_t*) inputPorts.getUnchecked(i), static_cast<jack_nframes_t> (numSamples)))
|
||||
inChans [numActiveInChans++] = (float*) in;
|
||||
if (auto* in = (jack_default_audio_sample_t*) juce::jack_port_get_buffer (inputPorts.getUnchecked (i),
|
||||
static_cast<jack_nframes_t> (numSamples)))
|
||||
inChans[numActiveInChans++] = (float*) in;
|
||||
}
|
||||
|
||||
for (int i = 0; i < totalNumberOfOutputChannels; ++i)
|
||||
{
|
||||
if (activeOutputChannels[i])
|
||||
if (jack_default_audio_sample_t* out
|
||||
= (jack_default_audio_sample_t*) juce::jack_port_get_buffer ((jack_port_t*) outputPorts.getUnchecked(i), static_cast<jack_nframes_t> (numSamples)))
|
||||
outChans [numActiveOutChans++] = (float*) out;
|
||||
if (auto* out = (jack_default_audio_sample_t*) juce::jack_port_get_buffer (outputPorts.getUnchecked (i),
|
||||
static_cast<jack_nframes_t> (numSamples)))
|
||||
outChans[numActiveOutChans++] = (float*) out;
|
||||
}
|
||||
|
||||
const ScopedLock sl (callbackLock);
|
||||
|
|
@ -406,7 +469,7 @@ private:
|
|||
else
|
||||
{
|
||||
for (int i = 0; i < numActiveOutChans; ++i)
|
||||
zeromem (outChans[i], sizeof (float) * static_cast<size_t> (numSamples));
|
||||
zeromem (outChans[i], static_cast<size_t> (numSamples) * sizeof (float));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -431,11 +494,11 @@ private:
|
|||
BigInteger newOutputChannels, newInputChannels;
|
||||
|
||||
for (int i = 0; i < outputPorts.size(); ++i)
|
||||
if (juce::jack_port_connected ((jack_port_t*) outputPorts.getUnchecked(i)))
|
||||
if (juce::jack_port_connected (outputPorts.getUnchecked (i)))
|
||||
newOutputChannels.setBit (i);
|
||||
|
||||
for (int i = 0; i < inputPorts.size(); ++i)
|
||||
if (juce::jack_port_connected ((jack_port_t*) inputPorts.getUnchecked(i)))
|
||||
if (juce::jack_port_connected (inputPorts.getUnchecked (i)))
|
||||
newInputChannels.setBit (i);
|
||||
|
||||
if (newOutputChannels != activeOutputChannels
|
||||
|
|
@ -451,14 +514,15 @@ private:
|
|||
if (oldCallback != nullptr)
|
||||
start (oldCallback);
|
||||
|
||||
sendDeviceChangedCallback();
|
||||
if (notifyChannelsChanged != nullptr)
|
||||
notifyChannelsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
static void portConnectCallback (jack_port_id_t, jack_port_id_t, int, void* arg)
|
||||
{
|
||||
if (JackAudioIODevice* device = static_cast<JackAudioIODevice*> (arg))
|
||||
device->updateActivePorts();
|
||||
device->mainThreadDispatcher.updateActivePorts();
|
||||
}
|
||||
|
||||
static void threadInitCallback (void* /* callbackArgument */)
|
||||
|
|
@ -477,82 +541,76 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
static void infoShutdownCallback (jack_status_t code, const char* reason, void* arg)
|
||||
{
|
||||
jassert (code == 0);
|
||||
ignoreUnused (code);
|
||||
|
||||
JUCE_JACK_LOG ("Shutting down with message:");
|
||||
JUCE_JACK_LOG (reason);
|
||||
ignoreUnused (reason);
|
||||
|
||||
shutdownCallback (arg);
|
||||
}
|
||||
|
||||
static void errorCallback (const char* msg)
|
||||
{
|
||||
JUCE_JACK_LOG ("JackAudioIODevice::errorCallback " + String (msg));
|
||||
ignoreUnused (msg);
|
||||
}
|
||||
|
||||
static void sendDeviceChangedCallback();
|
||||
|
||||
bool deviceIsOpen;
|
||||
jack_client_t* client;
|
||||
bool deviceIsOpen = false;
|
||||
jack_client_t* client = nullptr;
|
||||
String lastError;
|
||||
AudioIODeviceCallback* callback;
|
||||
AudioIODeviceCallback* callback = nullptr;
|
||||
CriticalSection callbackLock;
|
||||
|
||||
HeapBlock<float*> inChans, outChans;
|
||||
int totalNumberOfInputChannels;
|
||||
int totalNumberOfOutputChannels;
|
||||
Array<void*> inputPorts, outputPorts;
|
||||
int totalNumberOfInputChannels = 0;
|
||||
int totalNumberOfOutputChannels = 0;
|
||||
Array<jack_port_t*> inputPorts, outputPorts;
|
||||
BigInteger activeInputChannels, activeOutputChannels;
|
||||
|
||||
int xruns;
|
||||
std::atomic<int> xruns { 0 };
|
||||
|
||||
std::function<void()> notifyChannelsChanged;
|
||||
MainThreadDispatcher mainThreadDispatcher { *this };
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class JackAudioIODeviceType;
|
||||
|
||||
class JackAudioIODeviceType : public AudioIODeviceType
|
||||
{
|
||||
public:
|
||||
JackAudioIODeviceType()
|
||||
: AudioIODeviceType ("JACK"),
|
||||
hasScanned (false)
|
||||
{
|
||||
activeDeviceTypes.add (this);
|
||||
}
|
||||
|
||||
~JackAudioIODeviceType()
|
||||
{
|
||||
activeDeviceTypes.removeFirstMatchingValue (this);
|
||||
}
|
||||
: AudioIODeviceType ("JACK")
|
||||
{}
|
||||
|
||||
void scanForDevices()
|
||||
{
|
||||
hasScanned = true;
|
||||
inputNames.clear();
|
||||
inputIds.clear();
|
||||
outputNames.clear();
|
||||
outputIds.clear();
|
||||
|
||||
if (juce_libjackHandle == nullptr) juce_libjackHandle = dlopen ("libjack.so.0", RTLD_LAZY);
|
||||
if (juce_libjackHandle == nullptr) juce_libjackHandle = dlopen ("libjack.so", RTLD_LAZY);
|
||||
if (juce_libjackHandle == nullptr) return;
|
||||
|
||||
jack_status_t status;
|
||||
jack_status_t status = {};
|
||||
|
||||
// open a dummy client
|
||||
if (jack_client_t* const client = juce::jack_client_open ("JuceJackDummy", JackNoStartServer, &status))
|
||||
if (auto* const client = juce::jack_client_open ("JuceJackDummy", JackNoStartServer, &status))
|
||||
{
|
||||
// scan for output devices
|
||||
for (JackPortIterator i (client, false); i.next();)
|
||||
{
|
||||
if (i.clientName != (JUCE_JACK_CLIENT_NAME) && ! inputNames.contains (i.clientName))
|
||||
{
|
||||
inputNames.add (i.clientName);
|
||||
inputIds.add (i.ports [i.index]);
|
||||
}
|
||||
}
|
||||
if (i.getClientName() != (JUCE_JACK_CLIENT_NAME) && ! inputNames.contains (i.getClientName()))
|
||||
inputNames.add (i.getClientName());
|
||||
|
||||
// scan for input devices
|
||||
for (JackPortIterator i (client, true); i.next();)
|
||||
{
|
||||
if (i.clientName != (JUCE_JACK_CLIENT_NAME) && ! outputNames.contains (i.clientName))
|
||||
{
|
||||
outputNames.add (i.clientName);
|
||||
outputIds.add (i.ports [i.index]);
|
||||
}
|
||||
}
|
||||
if (i.getClientName() != (JUCE_JACK_CLIENT_NAME) && ! outputNames.contains (i.getClientName()))
|
||||
outputNames.add (i.getClientName());
|
||||
|
||||
juce::jack_client_close (client);
|
||||
}
|
||||
|
|
@ -581,8 +639,8 @@ public:
|
|||
jassert (hasScanned); // need to call scanForDevices() before doing this
|
||||
|
||||
if (JackAudioIODevice* d = dynamic_cast<JackAudioIODevice*> (device))
|
||||
return asInput ? inputIds.indexOf (d->inputId)
|
||||
: outputIds.indexOf (d->outputId);
|
||||
return asInput ? inputNames.indexOf (d->inputName)
|
||||
: outputNames.indexOf (d->outputName);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -596,30 +654,19 @@ public:
|
|||
const int outputIndex = outputNames.indexOf (outputDeviceName);
|
||||
|
||||
if (inputIndex >= 0 || outputIndex >= 0)
|
||||
return new JackAudioIODevice (outputIndex >= 0 ? outputDeviceName
|
||||
: inputDeviceName,
|
||||
inputIds [inputIndex],
|
||||
outputIds [outputIndex]);
|
||||
return new JackAudioIODevice (inputDeviceName, outputDeviceName,
|
||||
[this] { callDeviceChangeListeners(); });
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void portConnectionChange() { callDeviceChangeListeners(); }
|
||||
|
||||
private:
|
||||
StringArray inputNames, outputNames, inputIds, outputIds;
|
||||
bool hasScanned;
|
||||
StringArray inputNames, outputNames;
|
||||
bool hasScanned = false;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JackAudioIODeviceType)
|
||||
};
|
||||
|
||||
void JackAudioIODevice::sendDeviceChangedCallback()
|
||||
{
|
||||
for (int i = activeDeviceTypes.size(); --i >= 0;)
|
||||
if (JackAudioIODeviceType* d = activeDeviceTypes[i])
|
||||
d->portConnectionChange();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_JACK()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue