summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfalkTX <falktx@gmail.com>2017-08-10 17:44:21 +0200
committerfalkTX <falktx@gmail.com>2017-08-10 17:44:21 +0200
commit2ad48419a7012b35e5e394530638686c825be4ba (patch)
tree9cbb6cdd700b133de7f43326e1a1acce56b1ee08
parent9c929bef39e1fc63c40519eeaf126418cb65f2e5 (diff)
downloadjack2-2ad48419a7012b35e5e394530638686c825be4ba.tar.gz
Add support for internal session filesinternal-session-file
Thanks to Timo Wischer for the initial work
-rw-r--r--common/JackControlAPI.cpp11
-rw-r--r--common/JackControlAPI.h4
-rw-r--r--common/JackInternalSessionLoader.cpp176
-rw-r--r--common/JackInternalSessionLoader.h46
-rw-r--r--common/JackServer.cpp11
-rw-r--r--common/JackServer.h3
-rw-r--r--common/Jackdmp.cpp22
-rw-r--r--common/jack/control.h14
-rw-r--r--common/wscript3
-rw-r--r--man/jackd.027
10 files changed, 312 insertions, 5 deletions
diff --git a/common/JackControlAPI.cpp b/common/JackControlAPI.cpp
index a733f5d9..4d597e7d 100644
--- a/common/JackControlAPI.cpp
+++ b/common/JackControlAPI.cpp
@@ -1364,6 +1364,17 @@ SERVER_EXPORT bool jackctl_server_unload_internal(
}
}
+SERVER_EXPORT bool jackctl_server_load_session_file(
+ jackctl_server * server_ptr,
+ const char * file)
+{
+ if (!server_ptr || !file || !server_ptr->engine) {
+ return false;
+ }
+
+ return (server_ptr->engine->LoadInternalSessionFile(file) >= 0);
+}
+
SERVER_EXPORT bool jackctl_server_add_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
{
if (server_ptr && server_ptr->engine) {
diff --git a/common/JackControlAPI.h b/common/JackControlAPI.h
index d9529388..2de4451a 100644
--- a/common/JackControlAPI.h
+++ b/common/JackControlAPI.h
@@ -236,6 +236,10 @@ SERVER_EXPORT bool jackctl_server_unload_internal(
jackctl_server * server,
jackctl_internal * internal);
+SERVER_EXPORT bool jackctl_server_load_session_file(
+ jackctl_server * server_ptr,
+ const char * file);
+
SERVER_EXPORT bool jackctl_server_add_slave(jackctl_server_t * server,
jackctl_driver_t * driver);
diff --git a/common/JackInternalSessionLoader.cpp b/common/JackInternalSessionLoader.cpp
new file mode 100644
index 00000000..5a438e72
--- /dev/null
+++ b/common/JackInternalSessionLoader.cpp
@@ -0,0 +1,176 @@
+/*
+Copyright (C) 2017 Timo Wischer
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include <fstream>
+#include "JackInternalSessionLoader.h"
+#include "JackLockedEngine.h"
+
+
+namespace Jack
+{
+
+JackInternalSessionLoader::JackInternalSessionLoader(JackServer* const server) :
+ fServer(server)
+{
+}
+
+int JackInternalSessionLoader::Load(const char* file)
+{
+ std::ifstream infile(file);
+
+ if (!infile.is_open()) {
+ jack_error("JACK internal session file %s does not exist or cannot be opened for reading.", file);
+ return -1;
+ }
+
+ std::string line;
+ int linenr = -1;
+ while (std::getline(infile, line))
+ {
+ linenr++;
+
+ std::istringstream iss(line);
+
+ std::string command;
+ if ( !(iss >> command) ) {
+ /* ignoring empty line or line only filled with spaces */
+ continue;
+ }
+
+ /* convert command to lower case to accept any case of the letters in the command */
+ std::transform(command.begin(), command.end(), command.begin(), ::tolower);
+
+ if ( (command.compare("c") == 0) || (command.compare("con") == 0) ) {
+ ConnectPorts(iss, linenr);
+ } else if ( (command.compare("l") == 0) || (command.compare("load") == 0) ) {
+ LoadClient(iss, linenr);
+#if 0
+ /* NOTE: c++11 only */
+ } else if (command.front() == '#') {
+#else
+ } else if (command[0] == '#') {
+#endif
+ /* ignoring commented lines.
+ * The # can be followed by non spaces.
+ * Therefore only compare the first letter of the command.
+ */
+ } else {
+ jack_error("JACK internal session file %s line %u contains unkown command '%s'. Ignoring the line!", file, linenr, line.c_str());
+ }
+ }
+
+ return 0;
+}
+
+void JackInternalSessionLoader::LoadClient(std::istringstream& iss, const int linenr)
+{
+ std::string client_name;
+ if ( !(iss >> client_name) ) {
+ jack_error("Cannot read client name from internal session file line %u '%s'. Ignoring the line!", linenr, iss.str().c_str());
+ return;
+ }
+
+ std::string lib_name;
+ if ( !(iss >> lib_name) ) {
+ jack_error("Cannot read client library name from internal session file line %u '%s'. Ignoring the line!", linenr, iss.str().c_str());
+ return;
+ }
+
+ /* get the rest of the line */
+ std::string parameters;
+ if ( std::getline(iss, parameters) ) {
+ /* remove the leading spaces */
+ const std::size_t start = parameters.find_first_not_of(" \t");
+ if (start == std::string::npos) {
+ /* Parameters containing only spaces.
+ * Use empty parameter string.
+ */
+ parameters = "";
+ } else {
+ parameters = parameters.substr(start);
+ }
+ }
+
+
+ /* jackctl_server_load_internal() can not be used
+ * because it calls jack_internal_initialize()
+ * instead of jack_initialize()
+ */
+ int status = 0;
+ int refnum = 0;
+ if (fServer->InternalClientLoad1(client_name.c_str(), lib_name.c_str(), parameters.c_str(), (JackLoadName|JackUseExactName|JackLoadInit), &refnum, -1, &status) < 0) {
+ /* Due to the JackUseExactName option JackNameNotUnique will always handled as a failure.
+ * See JackEngine::ClientCheck().
+ */
+ if (status & JackNameNotUnique) {
+ jack_error("Internal client name `%s' not unique", client_name.c_str());
+ }
+ /* An error message for JackVersionError will already
+ * be printed by JackInternalClient::Open().
+ * Therefore no need to handle it here.
+ */
+
+ jack_error("Cannot load client %s from internal session file line %u. Ignoring the line!", client_name.c_str(), linenr);
+ return;
+ }
+
+ /* status has not to be checked for JackFailure
+ * because JackServer::InternalClientLoad1() will return a value < 0
+ * and this is handled by the previouse if-clause.
+ */
+
+ jack_info("Internal client %s successfully loaded", client_name.c_str());
+}
+
+void JackInternalSessionLoader::ConnectPorts(std::istringstream& iss, const int linenr)
+{
+ std::string src_port;
+ if ( !(iss >> src_port) ) {
+ jack_error("Cannot read first port from internal session file line %u '%s'. Ignoring the line!",
+ linenr, iss.str().c_str());
+ return;
+ }
+
+ std::string dst_port;
+ if ( !(iss >> dst_port) ) {
+ jack_error("Cannot read second port from internal session file line %u '%s'. Ignoring the line!",
+ linenr, iss.str().c_str());
+ return;
+ }
+
+ /* use the client reference of the source port */
+ const jack_port_id_t src_port_index = fServer->GetGraphManager()->GetPort(src_port.c_str());
+ if (src_port_index >= NO_PORT) {
+ jack_error("Source port %s does not exist! Ignoring internal session file line %u '%s'.",
+ src_port.c_str(), linenr, iss.str().c_str());
+ return;
+ }
+ const int src_refnum = fServer->GetGraphManager()->GetOutputRefNum(src_port_index);
+
+ if (fServer->GetEngine()->PortConnect(src_refnum, src_port.c_str(), dst_port.c_str()) < 0) {
+ jack_error("Cannot connect ports of internal session file line %u '%s'.\n"
+ "Possibly the destination port does not exist. Ignoring the line!",
+ linenr, iss.str().c_str());
+ return;
+ }
+
+ jack_info("Ports connected: %s -> %s", src_port.c_str(), dst_port.c_str());
+}
+
+}
diff --git a/common/JackInternalSessionLoader.h b/common/JackInternalSessionLoader.h
new file mode 100644
index 00000000..e594d398
--- /dev/null
+++ b/common/JackInternalSessionLoader.h
@@ -0,0 +1,46 @@
+/*
+Copyright (C) 2017 Timo Wischer
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#ifndef __JackInternalSessionLoader__
+#define __JackInternalSessionLoader__
+
+#include <string>
+#include <sstream>
+#include "JackServer.h"
+
+
+namespace Jack
+{
+
+class JackInternalSessionLoader
+{
+public:
+ JackInternalSessionLoader(JackServer* const server);
+ int Load(const char* file);
+
+private:
+ void LoadClient(std::istringstream& iss, const int linenr);
+ void ConnectPorts(std::istringstream& iss, const int linenr);
+
+ JackServer* const fServer;
+};
+
+} // end of namespace
+
+#endif
diff --git a/common/JackServer.cpp b/common/JackServer.cpp
index 1fd26754..5e88cf48 100644
--- a/common/JackServer.cpp
+++ b/common/JackServer.cpp
@@ -33,6 +33,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include "JackInternalClient.h"
#include "JackError.h"
#include "JackMessageBuffer.h"
+#include "JackInternalSessionLoader.h"
const char * jack_get_self_connect_mode_description(char mode);
@@ -225,6 +226,16 @@ int JackServer::InternalClientLoadAux(JackLoadableInternalClient* client, const
}
}
+//-----------------------
+// Internal session file
+//-----------------------
+
+int JackServer::LoadInternalSessionFile(const char* file)
+{
+ JackInternalSessionLoader loader(this);
+ return loader.Load(file);
+}
+
//---------------------------
// From request thread : API
//---------------------------
diff --git a/common/JackServer.h b/common/JackServer.h
index 473f88ff..9cfc9605 100644
--- a/common/JackServer.h
+++ b/common/JackServer.h
@@ -86,6 +86,9 @@ class SERVER_EXPORT JackServer
// Internals clients
int InternalClientLoad1(const char* client_name, const char* so_name, const char* objet_data, int options, int* int_ref, int uuid, int* status);
int InternalClientLoad2(const char* client_name, const char* so_name, const JSList * parameters, int options, int* int_ref, int uuid, int* status);
+
+ // Internal session file
+ int LoadInternalSessionFile(const char* file);
// Transport management
int ReleaseTimebase(int refnum);
diff --git a/common/Jackdmp.cpp b/common/Jackdmp.cpp
index 7eea2815..3d634346 100644
--- a/common/Jackdmp.cpp
+++ b/common/Jackdmp.cpp
@@ -162,7 +162,7 @@ static void print_server_drivers(jackctl_server_t *server, FILE* file)
const JSList * node_ptr = jackctl_server_get_drivers_list(server);
fprintf(file, "Available backends:\n");
-
+
while (node_ptr) {
jackctl_driver_t* driver = (jackctl_driver_t *)node_ptr->data;
fprintf(file, " %s (%s)\n", jackctl_driver_get_name(driver), (jackctl_driver_get_type(driver) == JackMaster) ? "master" : "slave");
@@ -176,7 +176,7 @@ static void print_server_internals(jackctl_server_t *server, FILE* file)
const JSList * node_ptr = jackctl_server_get_internals_list(server);
fprintf(file, "Available internals:\n");
-
+
while (node_ptr) {
jackctl_internal_t* internal = (jackctl_internal_t *)node_ptr->data;
fprintf(file, " %s\n", jackctl_internal_get_name(internal));
@@ -202,6 +202,7 @@ static void usage(FILE* file, jackctl_server_t *server, bool full = true)
" [ --port-max OR -p maximum-number-of-ports]\n"
" [ --slave-backend OR -X slave-backend-name ]\n"
" [ --internal-client OR -I internal-client-name ]\n"
+ " [ --internal-session-file OR -C internal-session-file ]\n"
" [ --verbose OR -v ]\n"
#ifdef __linux__
" [ --clocksource OR -c [ h(pet) | s(ystem) ]\n"
@@ -232,7 +233,7 @@ static void usage(FILE* file, jackctl_server_t *server, bool full = true)
" -d master-backend-name [ ... master-backend args ... ]\n"
" jackdmp -d master-backend-name --help\n"
" to display options for each master backend\n\n");
-
+
if (full) {
print_server_drivers(server, file);
print_server_internals(server, file);
@@ -265,7 +266,7 @@ int main(int argc, char** argv)
print_version();
}
}
- const char *options = "-d:X:I:P:uvshrRL:STFl:t:mn:p:"
+ const char *options = "-d:X:I:P:uvshrRL:STFl:t:mn:p:C:"
"a:"
#ifdef __linux__
"c:"
@@ -276,6 +277,7 @@ int main(int argc, char** argv)
#ifdef __linux__
{ "clock-source", 1, 0, 'c' },
#endif
+ { "internal-session-file", 1, 0, 'C' },
{ "loopback-driver", 1, 0, 'L' },
{ "audio-driver", 1, 0, 'd' },
{ "midi-driver", 1, 0, 'X' },
@@ -301,6 +303,7 @@ int main(int argc, char** argv)
int i,opt = 0;
int option_index = 0;
+ char* internal_session_file = NULL;
char* master_driver_name = NULL;
char** master_driver_args = NULL;
int master_driver_nargs = 1;
@@ -443,6 +446,10 @@ int main(int argc, char** argv)
}
break;
+ case 'C':
+ internal_session_file = optarg;
+ break;
+
case 'P':
param = jackctl_get_parameter(server_parameters, "realtime-priority");
if (param != NULL) {
@@ -606,6 +613,13 @@ int main(int argc, char** argv)
}
}
+ if (internal_session_file != NULL) {
+ if (!jackctl_server_load_session_file(server_ctl, internal_session_file)) {
+ fprintf(stderr, "Internal session file %s cannot be loaded!\n", internal_session_file);
+ goto stop_server;
+ }
+ }
+
notify_server_start(server_name);
notify_sent = true;
return_value = 0;
diff --git a/common/jack/control.h b/common/jack/control.h
index 33cd77b1..220fd6fb 100644
--- a/common/jack/control.h
+++ b/common/jack/control.h
@@ -257,6 +257,20 @@ jackctl_server_unload_internal(
jackctl_internal_t * internal);
/**
+ * Call this function to load a session file.
+ * (can be used when the server is running)
+ *
+ * @param server server object handle
+ * @param file the session file to load, containing a list of
+ * internal clients and connections to be made.
+ *
+ * @return success status: true - success, false - fail
+ */
+bool jackctl_server_load_session_file(
+ jackctl_server * server_ptr,
+ const char * file);
+
+/**
* Call this function to add a slave in the driver slave list.
* (cannot be used when the server is running that is between
* jackctl_server_start and jackctl_server_stop)
diff --git a/common/wscript b/common/wscript
index 6a559d7d..081f6b71 100644
--- a/common/wscript
+++ b/common/wscript
@@ -221,6 +221,7 @@ def build(bld):
'JackExternalClient.cpp',
'JackFreewheelDriver.cpp',
'JackInternalClient.cpp',
+ 'JackInternalSessionLoader.cpp',
'JackServer.cpp',
'JackThreadedDriver.cpp',
'JackRestartThreadedDriver.cpp',
@@ -244,7 +245,7 @@ def build(bld):
'JackMidiReceiveQueue.cpp',
'JackMidiSendQueue.cpp',
'JackMidiUtil.cpp',
- 'JackMidiWriteQueue.cpp'
+ 'JackMidiWriteQueue.cpp',
]
if bld.env['IS_LINUX']:
diff --git a/man/jackd.0 b/man/jackd.0
index 2fcdcd2a..876166b8 100644
--- a/man/jackd.0
+++ b/man/jackd.0
@@ -90,6 +90,33 @@ Prevent JACK from ever kicking out clients because they were too slow.
This cancels the effect any specified timeout value, but JACK and its clients are
still subject to the supervision of the watchdog thread or its equivalent.
.TP
+\fB\-C, \-\-internal-session-file \fIinternal-session-file\fR
+.br
+Load internal clients and connections from \fIinternal-session-file\fR.
+Each line of this configuration file starts with a command.
+The following commands are available:
+.br
+\fBl(oad)\fR \fIclient-name lib-name client-args\fR
+.br
+With this command an internal JACK client will be instantiated.
+\fIclient-name\fR and \fIlib-name\fR cannot contain spaces.
+The rest of the line will be interpreted as \fIclient-args\fR and
+sent to the client library.
+.br
+\fBc(on)\fR \fIsource-port destination-port\fR
+.br
+With this command a source port will be connected to a destination port.
+\fIsource-port\fR and \fIdestination-port\fR cannot contain spaces.
+.br
+Comments are allowed, they start with \fB#\fR.
+.br
+An example configuration could look like the following:
+.br
+ l inprocess1 inprocess
+ l amp1 jalv http://lv2plug.in/plugins/eg-amp
+.br
+ c amp:out system:playback_1
+.TP
\fB\-u, \-\-unlock\fR
.br
Unlock libraries GTK+, QT, FLTK, Wine.