Add JackProxyDriver

This driver is very similar to the JackNetDriver, but instead of connecting
through the network, it connects to its upstream server through standard jack
API. So it can only reach local servers which must be running as the same user
or in promiscuous mode.

The main use case is the multi-user, multi-session, shared workstation:

 - a classic server with hw driver is launched system-wide at boot time, in
   promiscuous mode, optionaly restricted to the audio group
 - in each user session, a jackdbus server is automatically started with
   JackProxyDriver as master driver, automatically connected to the
   system-wide one
 - optionaly, each user run PulseAudio with a pulse-jack bridge
This commit is contained in:
Cédric Schieli 2014-10-10 22:17:17 +02:00
parent 1cd25cb975
commit 8f6c3c6d1f
6 changed files with 796 additions and 0 deletions

608
common/JackProxyDriver.cpp Normal file
View File

@ -0,0 +1,608 @@
/*
Copyright (C) 2014 Cédric Schieli
This program is free software; you can redistribute it and/or
modify it 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.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "JackCompilerDeps.h"
#include "driver_interface.h"
#include "JackEngineControl.h"
#include "JackLockedEngine.h"
#include "JackWaitCallbackDriver.h"
#include "JackProxyDriver.h"
using namespace std;
namespace Jack
{
JackProxyDriver::JackProxyDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table,
const char* upstream, const char* promiscuous,
char* client_name, bool auto_connect, bool auto_save)
: JackRestarterDriver(name, alias, engine, table)
{
jack_log("JackProxyDriver::JackProxyDriver upstream %s", upstream);
assert(strlen(upstream) < JACK_CLIENT_NAME_SIZE);
strcpy(fUpstream, upstream);
assert(strlen(client_name) < JACK_CLIENT_NAME_SIZE);
strcpy(fClientName, client_name);
if (promiscuous) {
fPromiscuous = strdup(promiscuous);
}
fAutoConnect = auto_connect;
fAutoSave = auto_save;
}
JackProxyDriver::~JackProxyDriver()
{
if (fHandle) {
UnloadJackModule(fHandle);
}
}
int JackProxyDriver::LoadClientLib()
{
// Already loaded
if (fHandle) {
return 0;
}
fHandle = LoadJackModule(JACK_PROXY_CLIENT_LIB);
if (!fHandle) {
return -1;
}
LoadSymbols();
return 0;
}
//open, close, attach and detach------------------------------------------------------
int JackProxyDriver::Open(jack_nframes_t buffer_size,
jack_nframes_t samplerate,
bool capturing,
bool playing,
int inchannels,
int outchannels,
bool monitor,
const char* capture_driver_name,
const char* playback_driver_name,
jack_nframes_t capture_latency,
jack_nframes_t playback_latency)
{
fDetectPlaybackChannels = (outchannels == -1);
fDetectCaptureChannels = (inchannels == -1);
if (LoadClientLib() != 0) {
jack_error("Cannot dynamically load client library !");
return -1;
}
return JackWaiterDriver::Open(buffer_size, samplerate,
capturing, playing,
inchannels, outchannels,
monitor,
capture_driver_name, playback_driver_name,
capture_latency, playback_latency);
}
int JackProxyDriver::Close()
{
FreePorts();
return JackWaiterDriver::Close();
}
// Attach and Detach are defined as empty methods: port allocation is done when driver actually start (that is in Init)
int JackProxyDriver::Attach()
{
return 0;
}
int JackProxyDriver::Detach()
{
return 0;
}
//init and restart--------------------------------------------------------------------
/*
JackProxyDriver is wrapped in a JackWaitCallbackDriver decorator that behaves
as a "dummy driver, until Initialize method returns.
*/
bool JackProxyDriver::Initialize()
{
jack_log("JackProxyDriver::Initialize");
// save existing local connections if needed
if (fAutoSave) {
SaveConnections(0);
}
// new loading, but existing client, restart the driver
if (fClient) {
jack_info("JackProxyDriver restarting...");
jack_client_close(fClient);
}
FreePorts();
// display some additional infos
jack_info("JackProxyDriver started in %s mode.",
(fEngineControl->fSyncMode) ? "sync" : "async");
do {
jack_status_t status;
char *old = NULL;
if (fPromiscuous) {
// as we are fiddling with the environment variable content, save it
const char* tmp = getenv("JACK_PROMISCUOUS_SERVER");
if (tmp) {
old = strdup(tmp);
}
// temporary enable promiscuous mode
if (setenv("JACK_PROMISCUOUS_SERVER", fPromiscuous, 1) < 0) {
free(old);
jack_error("Error allocating memory.");
return false;
}
}
jack_info("JackProxyDriver connecting to %s", fUpstream);
fClient = jack_client_open(fClientName, static_cast<jack_options_t>(JackNoStartServer|JackServerName), &status, fUpstream);
if (fPromiscuous) {
// restore previous environment variable content
if (old) {
if (setenv("JACK_PROMISCUOUS_SERVER", old, 1) < 0) {
free(old);
jack_error("Error allocating memory.");
return false;
}
free(old);
} else {
unsetenv("JACK_PROMISCUOUS_SERVER");
}
}
// the connection failed, try again later
if (!fClient) {
JackSleep(1000000);
}
} while (!fClient);
jack_info("JackProxyDriver connected to %s", fUpstream);
// we are connected, let's register some callbacks
jack_on_shutdown(fClient, shutdown_callback, this);
if (jack_set_process_callback(fClient, process_callback, this) != 0) {
jack_error("Cannot set process callback.");
return false;
}
if (jack_set_buffer_size_callback(fClient, bufsize_callback, this) != 0) {
jack_error("Cannot set buffer size callback.");
return false;
}
if (jack_set_sample_rate_callback(fClient, srate_callback, this) != 0) {
jack_error("Cannot set sample rate callback.");
return false;
}
if (jack_set_port_connect_callback(fClient, connect_callback, this) != 0) {
jack_error("Cannot set port connect callback.");
return false;
}
// detect upstream physical playback ports if needed
if (fDetectPlaybackChannels) {
fPlaybackChannels = CountIO(JACK_DEFAULT_AUDIO_TYPE, JackPortIsPhysical | JackPortIsOutput);
}
// detect upstream physical capture ports if needed
if (fDetectCaptureChannels) {
fCaptureChannels = CountIO(JACK_DEFAULT_AUDIO_TYPE, JackPortIsPhysical | JackPortIsInput);
}
if (AllocPorts() != 0) {
jack_error("Can't allocate ports.");
return false;
}
bufsize_callback(jack_get_buffer_size(fClient));
srate_callback(jack_get_sample_rate(fClient));
// restore local connections if needed
if (fAutoSave) {
LoadConnections(0);
}
// everything is ready, start upstream processing
if (jack_activate(fClient) != 0) {
jack_error("Cannot activate jack client.");
return false;
}
// connect upstream ports if needed
if (fAutoConnect) {
ConnectPorts();
}
return true;
}
int JackProxyDriver::Stop()
{
if (fClient && (jack_deactivate(fClient) != 0)) {
jack_error("Cannot deactivate jack client.");
return -1;
}
return 0;
}
//client callbacks---------------------------------------------------------------------------
int JackProxyDriver::process_callback(jack_nframes_t nframes, void* arg)
{
assert(static_cast<JackProxyDriver*>(arg));
return static_cast<JackProxyDriver*>(arg)->Process();
}
int JackProxyDriver::bufsize_callback(jack_nframes_t nframes, void* arg)
{
assert(static_cast<JackProxyDriver*>(arg));
return static_cast<JackProxyDriver*>(arg)->bufsize_callback(nframes);
}
int JackProxyDriver::bufsize_callback(jack_nframes_t nframes)
{
if (JackTimedDriver::SetBufferSize(nframes) == 0) {
return -1;
}
JackDriver::NotifyBufferSize(nframes);
return 0;
}
int JackProxyDriver::srate_callback(jack_nframes_t nframes, void* arg)
{
assert(static_cast<JackProxyDriver*>(arg));
return static_cast<JackProxyDriver*>(arg)->srate_callback(nframes);
}
int JackProxyDriver::srate_callback(jack_nframes_t nframes)
{
if (JackTimedDriver::SetSampleRate(nframes) == 0) {
return -1;
}
JackDriver::NotifySampleRate(nframes);
return 0;
}
void JackProxyDriver::connect_callback(jack_port_id_t a, jack_port_id_t b, int connect, void* arg)
{
assert(static_cast<JackProxyDriver*>(arg));
static_cast<JackProxyDriver*>(arg)->connect_callback(a, b, connect);
}
void JackProxyDriver::connect_callback(jack_port_id_t a, jack_port_id_t b, int connect)
{
jack_port_t* port;
int i;
// skip port if not our own
port = jack_port_by_id(fClient, a);
if (!jack_port_is_mine(fClient, port)) {
port = jack_port_by_id(fClient, b);
if (!jack_port_is_mine(fClient, port)) {
return;
}
}
for (i = 0; i < fCaptureChannels; i++) {
if (fUpstreamPlaybackPorts[i] == port) {
fUpstreamPlaybackPortConnected[i] = connect;
}
}
for (i = 0; i < fPlaybackChannels; i++) {
if (fUpstreamCapturePorts[i] == port) {
fUpstreamCapturePortConnected[i] = connect;
}
}
}
void JackProxyDriver::shutdown_callback(void* arg)
{
assert(static_cast<JackProxyDriver*>(arg));
static_cast<JackProxyDriver*>(arg)->RestartWait();
}
//jack ports and buffers--------------------------------------------------------------
int JackProxyDriver::CountIO(const char* type, int flags)
{
int count = 0;
const char** ports = jack_get_ports(fClient, NULL, type, flags);
if (ports != NULL) {
while (ports[count]) { count++; }
jack_free(ports);
}
return count;
}
int JackProxyDriver::AllocPorts()
{
jack_log("JackProxyDriver::AllocPorts fBufferSize = %ld fSampleRate = %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate);
char proxy[REAL_JACK_PORT_NAME_SIZE];
int i;
fUpstreamPlaybackPorts = new jack_port_t* [fCaptureChannels];
fUpstreamPlaybackPortConnected = new int [fCaptureChannels];
for (i = 0; i < fCaptureChannels; i++) {
snprintf(proxy, sizeof(proxy), "%s:to_client_%d", fClientName, i + 1);
fUpstreamPlaybackPorts[i] = jack_port_register(fClient, proxy, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0);
if (fUpstreamPlaybackPorts[i] == NULL) {
jack_error("driver: cannot register upstream port %s", proxy);
return -1;
}
fUpstreamPlaybackPortConnected[i] = 0;
}
fUpstreamCapturePorts = new jack_port_t* [fPlaybackChannels];
fUpstreamCapturePortConnected = new int [fPlaybackChannels];
for (i = 0; i < fPlaybackChannels; i++) {
snprintf(proxy, sizeof(proxy), "%s:from_client_%d", fClientName, i + 1);
fUpstreamCapturePorts[i] = jack_port_register(fClient, proxy, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0);
if (fUpstreamCapturePorts[i] == NULL) {
jack_error("driver: cannot register upstream port %s", proxy);
return -1;
}
fUpstreamCapturePortConnected[i] = 0;
}
// local ports are registered here
return JackAudioDriver::Attach();
}
int JackProxyDriver::FreePorts()
{
jack_log("JackProxyDriver::FreePorts");
int i;
for (i = 0; i < fCaptureChannels; i++) {
if (fCapturePortList[i] > 0) {
fEngine->PortUnRegister(fClientControl.fRefNum, fCapturePortList[i]);
fCapturePortList[i] = 0;
}
if (fUpstreamPlaybackPorts && fUpstreamPlaybackPorts[i]) {
fUpstreamPlaybackPorts[i] = NULL;
}
}
for (i = 0; i < fPlaybackChannels; i++) {
if (fPlaybackPortList[i] > 0) {
fEngine->PortUnRegister(fClientControl.fRefNum, fPlaybackPortList[i]);
fPlaybackPortList[i] = 0;
}
if (fUpstreamCapturePorts && fUpstreamCapturePorts[i]) {
fUpstreamCapturePorts[i] = NULL;
}
}
delete[] fUpstreamPlaybackPorts;
delete[] fUpstreamPlaybackPortConnected;
delete[] fUpstreamCapturePorts;
delete[] fUpstreamCapturePortConnected;
fUpstreamPlaybackPorts = NULL;
fUpstreamPlaybackPortConnected = NULL;
fUpstreamCapturePorts = NULL;
fUpstreamCapturePortConnected = NULL;
return 0;
}
void JackProxyDriver::ConnectPorts()
{
jack_log("JackProxyDriver::ConnectPorts");
const char** ports = jack_get_ports(fClient, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortIsPhysical | JackPortIsOutput);
if (ports != NULL) {
for (int i = 0; i < fCaptureChannels && ports[i]; i++) {
jack_connect(fClient, ports[i], jack_port_name(fUpstreamPlaybackPorts[i]));
}
jack_free(ports);
}
ports = jack_get_ports(fClient, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortIsPhysical | JackPortIsInput);
if (ports != NULL) {
for (int i = 0; i < fPlaybackChannels && ports[i]; i++) {
jack_connect(fClient, jack_port_name(fUpstreamCapturePorts[i]), ports[i]);
}
jack_free(ports);
}
}
//driver processes--------------------------------------------------------------------
int JackProxyDriver::Read()
{
// take the time at the beginning of the cycle
JackDriver::CycleTakeBeginTime();
int i;
void *from, *to;
size_t buflen = sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize;
for (i = 0; i < fCaptureChannels; i++) {
if (fUpstreamPlaybackPortConnected[i]) {
from = jack_port_get_buffer(fUpstreamPlaybackPorts[i], fEngineControl->fBufferSize);
to = GetInputBuffer(i);
memcpy(to, from, buflen);
}
}
return 0;
}
int JackProxyDriver::Write()
{
int i;
void *from, *to;
size_t buflen = sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize;
for (i = 0; i < fPlaybackChannels; i++) {
if (fUpstreamCapturePortConnected[i]) {
to = jack_port_get_buffer(fUpstreamCapturePorts[i], fEngineControl->fBufferSize);
from = GetOutputBuffer(i);
memcpy(to, from, buflen);
}
}
return 0;
}
//driver loader-----------------------------------------------------------------------
#ifdef __cplusplus
extern "C"
{
#endif
SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor()
{
jack_driver_desc_t * desc;
jack_driver_desc_filler_t filler;
jack_driver_param_value_t value;
desc = jack_driver_descriptor_construct("proxy", JackDriverMaster, "proxy backend", &filler);
strcpy(value.str, DEFAULT_UPSTREAM);
jack_driver_descriptor_add_parameter(desc, &filler, "upstream", 'u', JackDriverParamString, &value, NULL, "Name of the upstream jack server", NULL);
strcpy(value.str, "");
jack_driver_descriptor_add_parameter(desc, &filler, "promiscuous", 'p', JackDriverParamString, &value, NULL, "Promiscuous group", NULL);
value.i = -1;
jack_driver_descriptor_add_parameter(desc, &filler, "input-ports", 'C', JackDriverParamInt, &value, NULL, "Number of audio input ports", "Number of audio input ports. If -1, audio physical input from the master");
jack_driver_descriptor_add_parameter(desc, &filler, "output-ports", 'P', JackDriverParamInt, &value, NULL, "Number of audio output ports", "Number of audio output ports. If -1, audio physical output from the master");
strcpy(value.str, "proxy");
jack_driver_descriptor_add_parameter(desc, &filler, "client-name", 'n', JackDriverParamString, &value, NULL, "Name of the jack client", NULL);
value.i = false;
jack_driver_descriptor_add_parameter(desc, &filler, "use-username", 'U', JackDriverParamBool, &value, NULL, "Use current username as client name", NULL);
value.i = false;
jack_driver_descriptor_add_parameter(desc, &filler, "auto-connect", 'c', JackDriverParamBool, &value, NULL, "Auto connect proxy to upstream system ports", NULL);
value.i = false;
jack_driver_descriptor_add_parameter(desc, &filler, "auto-save", 's', JackDriverParamBool, &value, NULL, "Save/restore connection state when restarting", NULL);
return desc;
}
SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
{
char upstream[JACK_CLIENT_NAME_SIZE + 1];
char promiscuous[JACK_CLIENT_NAME_SIZE + 1] = {0};
char client_name[JACK_CLIENT_NAME_SIZE + 1];
jack_nframes_t period_size = 1024; // to be used while waiting for master period_size
jack_nframes_t sample_rate = 48000; // to be used while waiting for master sample_rate
int capture_ports = -1;
int playback_ports = -1;
const JSList* node;
const jack_driver_param_t* param;
bool auto_connect = false;
bool auto_save = false;
bool use_promiscuous = false;
// Possibly use env variable for upstream name
const char* default_upstream = getenv("JACK_PROXY_UPSTREAM");
strcpy(upstream, (default_upstream) ? default_upstream : DEFAULT_UPSTREAM);
// Possibly use env variable for upstream promiscuous
const char* default_promiscuous = getenv("JACK_PROXY_PROMISCUOUS");
strcpy(promiscuous, (default_promiscuous) ? default_promiscuous : "");
// Possibly use env variable for client name
const char* default_client_name = getenv("JACK_PROXY_CLIENT_NAME");
strcpy(client_name, (default_client_name) ? default_client_name : DEFAULT_CLIENT_NAME);
#ifdef WIN32
const char* username = getenv("USERNAME");
#else
const char* username = getenv("LOGNAME");
#endif
for (node = params; node; node = jack_slist_next(node)) {
param = (const jack_driver_param_t*) node->data;
switch (param->character)
{
case 'u' :
assert(strlen(param->value.str) < JACK_CLIENT_NAME_SIZE);
strcpy(upstream, param->value.str);
break;
case 'p':
assert(strlen(param->value.str) < JACK_CLIENT_NAME_SIZE);
use_promiscuous = true;
strcpy(promiscuous, param->value.str);
break;
case 'C':
capture_ports = param->value.i;
break;
case 'P':
playback_ports = param->value.i;
break;
case 'n' :
assert(strlen(param->value.str) < JACK_CLIENT_NAME_SIZE);
strncpy(client_name, param->value.str, JACK_CLIENT_NAME_SIZE);
break;
case 'U' :
if (username && *username) {
assert(strlen(username) < JACK_CLIENT_NAME_SIZE);
strncpy(client_name, username, JACK_CLIENT_NAME_SIZE);
}
case 'c':
auto_connect = true;
break;
case 's':
auto_save = true;
break;
}
}
try {
Jack::JackDriverClientInterface* driver = new Jack::JackWaitCallbackDriver(
new Jack::JackProxyDriver("system", "proxy_pcm", engine, table, upstream, use_promiscuous ? promiscuous : NULL, client_name, auto_connect, auto_save));
if (driver->Open(period_size, sample_rate, 1, 1, capture_ports, playback_ports, false, "capture_", "playback_", 0, 0) == 0) {
return driver;
} else {
delete driver;
return NULL;
}
} catch (...) {
return NULL;
}
}
#ifdef __cplusplus
}
#endif
}

181
common/JackProxyDriver.h Normal file
View File

@ -0,0 +1,181 @@
/*
Copyright (C) 2014 Cédric Schieli
This program is free software; you can redistribute it and/or
modify it 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.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __JackProxyDriver__
#define __JackProxyDriver__
#include "JackTimedDriver.h"
#define DEFAULT_UPSTREAM "default" /*!< Default upstream Jack server to connect to */
#define DEFAULT_CLIENT_NAME "proxy" /*!< Default client name to use when connecting to upstream Jack server */
#ifdef __APPLE__
#define JACK_PROXY_CLIENT_LIB "libjack.0.dylib"
#elif defined(WIN32)
#ifdef _WIN64
#define JACK_PROXY_CLIENT_LIB "libjack64.dll"
#else
#define JACK_PROXY_CLIENT_LIB "libjack.dll"
#endif
#else
#define JACK_PROXY_CLIENT_LIB "libjack.so.0"
#endif
#define PROXY_DEF_SYMBOL(ret,name,...) ret (*name) (__VA_ARGS__)
#define PROXY_LOAD_SYMBOL(ret,name,...) name = (ret (*) (__VA_ARGS__)) GetJackProc(fHandle, #name); assert(name)
namespace Jack
{
/*! \Brief This class describes the Proxy Backend
It uses plain Jack API to connect to an upstream server. The latter is
either running as the same user, or is running in promiscuous mode.
The main use case is the multi-user, multi-session, shared workstation:
- a classic server with hw driver is launched system-wide at boot time, in
promiscuous mode, optionaly restricted to the audio group
- in each user session, a jackdbus server is automatically started with
JackProxyDriver as master driver, automatically connected to the
system-wide one
- optionaly, each user run PulseAudio with a pulse-jack bridge
*/
class JackProxyDriver : public JackRestarterDriver
{
private:
char fUpstream[JACK_CLIENT_NAME_SIZE]; /*<! the upstream server name */
char fClientName[JACK_CLIENT_NAME_SIZE]; /*<! client name to use when connecting */
const char* fPromiscuous; /*<! if not null, group or gid to use for promiscuous mode */
//jack data
jack_client_t* fClient; /*<! client handle */
jack_port_t** fUpstreamCapturePorts; /*<! ports registered for capture in the upstream server */
jack_port_t** fUpstreamPlaybackPorts; /*<! ports registered for playback in the upstream server */
int* fUpstreamCapturePortConnected; /*<! map of capture ports connected upstream, for optimization purpose */
int* fUpstreamPlaybackPortConnected; /*<! map of playback ports connected upstream, for optimization purpose */
bool fAutoSave; /*<! wether the local connections should be saved/restored when upstream connection is restarted */
bool fAutoConnect; /*<! wether the upstream ports should be automatically connected to upstream physical ports */
bool fDetectPlaybackChannels; /*<! wether the number of playback ports registered should match the number of upstream physical playback ports */
bool fDetectCaptureChannels; /*<! wether the number of capture ports registered should match the number of upstream physical capture ports */
bool Initialize(); /*<! establish upstream connection and register the client callbacks */
int AllocPorts(); /*<! register local and upstream ports */
int FreePorts(); /*<! unregister local ports */
void ConnectPorts(); /*<! connect upstream ports to physical ones */
int CountIO(const char*, int); /*<! get the number of upstream ports of a specific type */
// client callbacks
static int process_callback(jack_nframes_t, void*);
static int bufsize_callback(jack_nframes_t, void*);
static int srate_callback(jack_nframes_t, void*);
static void connect_callback(jack_port_id_t, jack_port_id_t, int, void*);
static void shutdown_callback(void*);
// indirect member callbacks
int bufsize_callback(jack_nframes_t);
int srate_callback(jack_nframes_t);
void connect_callback(jack_port_id_t, jack_port_id_t, int);
JACK_HANDLE fHandle; /*<! handle to the jack client library */
// map needed client library symbols as members to override those from the jackserver library
PROXY_DEF_SYMBOL(jack_client_t*, jack_client_open, const char*, jack_options_t, jack_status_t*, ...);
PROXY_DEF_SYMBOL(int, jack_set_process_callback, jack_client_t*, JackProcessCallback, void*);
PROXY_DEF_SYMBOL(int, jack_set_buffer_size_callback, jack_client_t*, JackBufferSizeCallback, void*);
PROXY_DEF_SYMBOL(int, jack_set_sample_rate_callback, jack_client_t*, JackSampleRateCallback, void*);
PROXY_DEF_SYMBOL(int, jack_set_port_connect_callback, jack_client_t*, JackPortConnectCallback, void*);
PROXY_DEF_SYMBOL(void, jack_on_shutdown, jack_client_t*, JackShutdownCallback, void*);
PROXY_DEF_SYMBOL(jack_nframes_t, jack_get_buffer_size, jack_client_t*);
PROXY_DEF_SYMBOL(jack_nframes_t, jack_get_sample_rate, jack_client_t*);
PROXY_DEF_SYMBOL(int, jack_activate, jack_client_t*);
PROXY_DEF_SYMBOL(int, jack_deactivate, jack_client_t*);
PROXY_DEF_SYMBOL(jack_port_t*, jack_port_by_id, jack_client_t*, jack_port_id_t);
PROXY_DEF_SYMBOL(int, jack_port_is_mine, const jack_client_t*, const jack_port_t*);
PROXY_DEF_SYMBOL(const char**, jack_get_ports, jack_client_t*, const char*, const char*, unsigned long);
PROXY_DEF_SYMBOL(void, jack_free, void*);
PROXY_DEF_SYMBOL(jack_port_t*, jack_port_register, jack_client_t*, const char*, const char*, unsigned long, unsigned long);
PROXY_DEF_SYMBOL(int, jack_port_unregister, jack_client_t*, jack_port_t*);
PROXY_DEF_SYMBOL(void*, jack_port_get_buffer, jack_port_t*, jack_nframes_t);
PROXY_DEF_SYMBOL(int, jack_connect, jack_client_t*, const char*, const char*);
PROXY_DEF_SYMBOL(const char*, jack_port_name, const jack_port_t*);
PROXY_DEF_SYMBOL(int, jack_client_close, jack_client_t*);
/*! load the needed library symbols */
void LoadSymbols()
{
PROXY_LOAD_SYMBOL(jack_client_t*, jack_client_open, const char*, jack_options_t, jack_status_t*, ...);
PROXY_LOAD_SYMBOL(int, jack_set_process_callback, jack_client_t*, JackProcessCallback, void*);
PROXY_LOAD_SYMBOL(int, jack_set_buffer_size_callback, jack_client_t*, JackBufferSizeCallback, void*);
PROXY_LOAD_SYMBOL(int, jack_set_sample_rate_callback, jack_client_t*, JackSampleRateCallback, void*);
PROXY_LOAD_SYMBOL(int, jack_set_port_connect_callback, jack_client_t*, JackPortConnectCallback, void*);
PROXY_LOAD_SYMBOL(void, jack_on_shutdown, jack_client_t*, JackShutdownCallback, void*);
PROXY_LOAD_SYMBOL(jack_nframes_t, jack_get_buffer_size, jack_client_t*);
PROXY_LOAD_SYMBOL(jack_nframes_t, jack_get_sample_rate, jack_client_t*);
PROXY_LOAD_SYMBOL(int, jack_activate, jack_client_t*);
PROXY_LOAD_SYMBOL(int, jack_deactivate, jack_client_t*);
PROXY_LOAD_SYMBOL(jack_port_t*, jack_port_by_id, jack_client_t*, jack_port_id_t);
PROXY_LOAD_SYMBOL(int, jack_port_is_mine, const jack_client_t*, const jack_port_t*);
PROXY_LOAD_SYMBOL(const char**, jack_get_ports, jack_client_t*, const char*, const char*, unsigned long);
PROXY_LOAD_SYMBOL(void, jack_free, void*);
PROXY_LOAD_SYMBOL(jack_port_t*, jack_port_register, jack_client_t*, const char*, const char*, unsigned long, unsigned long);
PROXY_LOAD_SYMBOL(int, jack_port_unregister, jack_client_t*, jack_port_t*);
PROXY_LOAD_SYMBOL(void*, jack_port_get_buffer, jack_port_t*, jack_nframes_t);
PROXY_LOAD_SYMBOL(int, jack_connect, jack_client_t*, const char*, const char*);
PROXY_LOAD_SYMBOL(const char*, jack_port_name, const jack_port_t*);
PROXY_LOAD_SYMBOL(int, jack_client_close, jack_client_t*);
}
int LoadClientLib(); /*!< load the client library */
public:
JackProxyDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table,
const char* upstream, const char* promiscuous, char* client_name, bool auto_connect, bool auto_save);
virtual ~JackProxyDriver();
int Open(jack_nframes_t buffer_size,
jack_nframes_t samplerate,
bool capturing,
bool playing,
int inchannels,
int outchannels,
bool monitor,
const char* capture_driver_name,
const char* playback_driver_name,
jack_nframes_t capture_latency,
jack_nframes_t playback_latency);
int Close();
int Stop();
int Attach();
int Detach();
int Read();
int Write();
};
}
#endif

View File

@ -91,3 +91,4 @@ def build(bld):
'../common/netjack.c',
'../common/netjack_packet.c' ], ["SAMPLERATE", "CELT"])
create_jack_driver_obj(bld, 'proxy', '../common/JackProxyDriver.cpp')

View File

@ -87,3 +87,5 @@ def build(bld):
create_jack_driver_obj(bld, 'netone', [ '../common/JackNetOneDriver.cpp',
'../common/netjack.c',
'../common/netjack_packet.c' ], "SAMPLERATE CELT" )
create_jack_driver_obj(bld, 'proxy', '../common/JackProxyDriver.cpp')

View File

@ -35,3 +35,5 @@ def build(bld):
create_jack_driver_obj(bld, 'net', '../common/JackNetDriver.cpp')
create_jack_driver_obj(bld, 'loopback', '../common/JackLoopbackDriver.cpp')
create_jack_driver_obj(bld, 'proxy', '../common/JackProxyDriver.cpp')

View File

@ -65,3 +65,5 @@ def build(bld):
create_jack_driver_obj(bld, 'netone', [ '../common/JackNetOneDriver.cpp',
'../common/netjack.c',
'../common/netjack_packet.c' ], ["SAMPLERATE", "CELT"] )
create_jack_driver_obj(bld, 'proxy', '../common/JackProxyDriver.cpp')