gtkIOStream  1.7.0
GTK+ << C++ IOStream operators for GTK+. Now with ORBing, numerical computation, audio client and more ...
JackPortMonitor.C
Go to the documentation of this file.
1 /* Copyright 2000-2018 Matt Flax <flatmax@flatmax.org>
2  This file is part of GTK+ IOStream class set
3 
4  GTK+ IOStream is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8 
9  GTK+ IOStream is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You have received a copy of the GNU General Public License
15  along with GTK+ IOStream
16  */
17 #include "JackPortMonitor.H"
18 
19 void JackPortMonitor::init(bool monitorPorts) {
20  init(monitorPorts, false); // start by default not autoconnecting network clients - this is a good security decision.
21 }
22 
23 void JackPortMonitor::init(bool monitorPorts, bool autoConnectNetClientsIn){
24  autoConnectNetClients=autoConnectNetClientsIn; // start not in silent mode
25  if (!client) // the client has to exist to monitor port connections
27  if (monitorPorts)
29  if (jack_activate(client))
31 
34  run(); // run the auto connection thread
35  }
36  reSyncPorts();
38 }
39 
40 
42  int res=JackBase::disconnect();
43  for (vector<JackBaseWithPortNames *>::iterator kc=knownClients.begin(); kc!=knownClients.end(); ++kc)
44  (*kc)->setClient(client);
45  return res;
46 }
47 
48 int JackPortMonitor::connect(const string &clientName_, const string &serverName) {
49  int res=JackBase::connect(clientName_, serverName);
50  for (vector<JackBaseWithPortNames *>::iterator kc=knownClients.begin(); kc!=knownClients.end(); ++kc)
51  (*kc)->setClient(client);
52  return res;
53 }
54 
56  cout<<"JackPortMonitor::autoConnectNetClientsPorts"<<endl;
57  if (client) {
58  vector<string> slavePorts; // find all ports with the '_slave_' in their names.
59  if (getPortListAndCount((JackPortFlags)(JackPortIsInput), &slavePorts, "_slave_", NULL)<0)
60  JackDebug().evaluateError(JACK_NETPORT_AUTOCONNECT_ERROR, "Problem finding input (writeable) ports. Skipping input ports.");
61  if (getPortListAndCount((JackPortFlags)(JackPortIsOutput), &slavePorts, "_slave_", NULL)<0)
62  JackDebug().evaluateError(JACK_NETPORT_AUTOCONNECT_ERROR, "Problem finding output (readable) ports. Skipping output ports.");
63 
64  // Find the list of unique client names
65  vector<string> uniqueClientNames; // find a unique set of client names.
66  for (vector<string>::iterator pn=slavePorts.begin(); pn!=slavePorts.end(); ++pn) {
67  //cout<<"JackPortMonitor::autoConnectNetClientsPorts : found port "<<*pn<<endl;
68  string cn=clientNameFromPortName(*pn);
69  if (cn.size() && find(uniqueClientNames.begin(), uniqueClientNames.end(), cn.c_str()) == uniqueClientNames.end()) // if not present, then add to the list
70  uniqueClientNames.push_back(cn);
71  }
72 
73  // For each unique client name, attempt to auto-connect ports to the system.
74  for (vector<string>::iterator cn=uniqueClientNames.begin(); cn!=uniqueClientNames.end(); ++cn){
75  connectPorts("system", *cn);
76  connectPorts(*cn, "system");
77  }
78  }
79 }
80 
82  while (running()){ // while this thread is running - wait to be told to scan and connect network connections.
83  cond.lock(); // lock the mutex and wait until ready.
84  cond.wait();
85  cond.unLock();
87  }
88  return NULL;
89 }
90 
92  if (client) {
96  } else
98 }
99 
101  if (jack_set_port_rename_callback(client, reinterpret_cast<JackPortRenameCallback>(jackPortRenameCallback), this)!=NO_ERROR)
102  JackDebug().evaluateError(JACK_PORT_CALLBACK_SETUP_ERROR, " jack_set_port_rename_callback.");
103 }
104 
106  if (jack_set_port_registration_callback(client, (JackPortRegistrationCallback)jackPortRegistrationCallback, this)!=NO_ERROR)
107  JackDebug().evaluateError(JACK_PORT_CALLBACK_SETUP_ERROR, " jack_set_port_registration_callback.");
108 }
109 
111  if (jack_set_port_connect_callback(client, reinterpret_cast<JackPortConnectCallback>(jackPortConnectCallback), this)!=NO_ERROR)
112  JackDebug().evaluateError(JACK_PORT_CALLBACK_SETUP_ERROR, " jack_set_port_connect_callback.");
113 }
114 
115 void JackPortMonitor::breakDownPortsToClients(vector<jack_port_t *> &ports) {
116  for (vector<jack_port_t *>::iterator p=ports.begin(); p!=ports.end(); ++p) {
117  CompareStrings cs(clientNameFromPort(*p)); // get the client name and create a functor which can compare a client pointer's client name to a client name string
118  vector<JackBaseWithPortNames *>::iterator kc;
120  // first check that this client is known ... if not then make it known
121  kc=find_if(knownClients.begin(), knownClients.end(), cs);
122  if (kc==knownClients.end()) { // if at the end, then it doesn't exist, so add
123  knownClients.push_back(c=new JackBaseWithPortNames); // TODO : check memory creation here for errors.
124  c->setClientName(cs.cn);
125  c->setClient(client);
127  } else // already exists
128  c=*kc;
129  // c now points to the client, so add it to the set of known ports.
130  if (&ports==&inputPorts) {
131  c->addInputPort(*p);
132  c->inputPortNamesAndConnections[jack_port_short_name(*p)]=map<string, vector<string> >(); // each input port starts with an empty list of connections
133  } else {
134  c->addOutputPort(*p);
135  c->outputPortNames.push_back(jack_port_short_name(*p));
136  }
137  }
138 }
139 
140 void JackPortMonitor::reSyncPorts(JackPortFlags flags) {
141  vector<jack_port_t *> *portsIO; // work out whether we are finding input or output ports and point to them.
142  (flags==JackPortIsInput) ? portsIO=&inputPorts : portsIO=&outputPorts;
143 
144  // start with the number of physical ports and add them to the known list of ports
145  getPortListAndCount((JackPortFlags)(JackPortIsPhysical|flags), portsIO, NULL, NULL);
146 
147  // find input and output ports which aren't physical and add.
148  vector<jack_port_t *> ports;
149  getPortListAndCount(flags, &ports, NULL, NULL);
150  for (vector<jack_port_t *>::iterator p=ports.begin(); p!=ports.end(); ++p)
151  if(std::find(portsIO->begin(), portsIO->end(), *p) == portsIO->end()) // if not already present. i.e. not a physical input port then add
152  portsIO->push_back(*p);
153 
154  // Add the known ports to the list of known clients, this involves associating each port with the client object and setting their input and output ports.
155  breakDownPortsToClients(*portsIO);
156 }
157 
159  //cout<<"JackPortMonitor::reSyncPorts"<<endl;
161  if (knownClients.size()>0) { // remove any known clients.
162  for (int i=0; i<knownClients.size(); i++)
163  delete knownClients[i];
164  knownClients.resize(0);
165  }
166 
167  if (client) { // recreate known clients
168  reSyncPorts(JackPortIsInput); // get input ports and break down to client/port objects.
169  reSyncPorts(JackPortIsOutput); // get output ports and break down to client/port objects.
170  } else
172 }
173 
175  //cout<<"JackPortMonitor::reSyncConnections"<<endl;
176  vector<JackBaseWithPortNames *>::iterator kc;
177  for (kc=knownClients.begin(); kc!=knownClients.end(); ++kc)
178  (*kc)->findInputConnections(); // find all of the connections from inputs for each client.
179 }
180 
182  bool monitorPorts=true;
183  init(monitorPorts);
184 }
185 
187  init(monitorPorts);
188 }
189 
190 JackPortMonitor::JackPortMonitor(bool monitorPorts, bool autoConnectNetClientsIn) : JackBase(JACK_PORT_MONITOR_CLIENT_NAME) {
191  init(monitorPorts, autoConnectNetClientsIn);
192 }
193 
194 JackPortMonitor::JackPortMonitor(string clientName_) : JackBase(clientName_) {
195  bool monitorPorts=true;
196  init(monitorPorts);
197 }
198 
199 JackPortMonitor::JackPortMonitor(string clientName_, bool monitorPorts) : JackBase(clientName_) {
200  init(monitorPorts);
201 }
202 
203 JackPortMonitor::JackPortMonitor(string clientName_, bool monitorPorts, bool autoConnectNetClientsIn) : JackBase(clientName_) {
204  init(monitorPorts, autoConnectNetClientsIn);
205 }
206 
207 
208 JackPortMonitor::JackPortMonitor(string clientName_, string serverName) : JackBase (clientName_, serverName) {
209  bool monitorPorts=true;
210  init(monitorPorts);
211 }
212 
213 JackPortMonitor::JackPortMonitor(string clientName_, string serverName, bool monitorPorts) : JackBase (clientName_, serverName) {
214  init(monitorPorts);
215 }
216 
217 JackPortMonitor::JackPortMonitor(string clientName_, string serverName, bool monitorPorts, bool autoConnectNetClientsIn) : JackBase (clientName_, serverName) {
218  init(monitorPorts, autoConnectNetClientsIn);
219 }
220 
222 
223 void JackPortMonitor::print(ostream &os) {
224  os<<"=== "<<inputPorts.size()<<" input ports, "<<outputPorts.size()<<" output ports ===\n";
225  map<string, map<string, vector<string> > >::iterator p; // the input port iterator
226  for (vector<JackBaseWithPortNames*>::iterator kc=knownClients.begin(); kc!=knownClients.end(); ++kc) {
227  //int cnCnt=(*kc)->getClientName().size();
228  //cout<<(*kc)->getClientName()<<":\n";
229  p=(*kc)->inputPortNamesAndConnections.begin(); // start the input port iterator at the beginning
230  for (int i=0; i<max((*kc)->inputPortNamesAndConnections.size(), (*kc)->outputPortNames.size()); i++) {
231  if ((*kc)->inputPortNamesAndConnections.size()>i) {
232  os<<'\t'<<(*p).first<<"\t\t"; // the port name is the map key
233  p++;
234  } else
235  os<<"\t\t\t";
236  if ((*kc)->outputPortNames.size()>i)
237  os<<(*kc)->outputPortNames[i]<<'\n';
238  else
239  os<<'\n';
240  }
241  }
242 
243  os<<"\n=== Connections ===\n";
244  for (vector<JackBaseWithPortNames*>::iterator kc=knownClients.begin(); kc!=knownClients.end(); ++kc) {
245  os<<(*kc)->getClientName()<<":\n";
246  for (p=(*kc)->inputPortNamesAndConnections.begin(); p!=(*kc)->inputPortNamesAndConnections.end(); ++p) { // iterate through each client's port connections
247  os<<(*p).first<<" ---> {";
248  map<string, vector<string> >::iterator pcs; // The port connections which are connected to p
249  for (pcs=(*p).second.begin(); pcs!=(*p).second.end(); ++pcs) { // for each client/port connection, print it.
250  if (pcs!=(*p).second.begin())
251  os<<", ";
252  os<<(*pcs).first<<"(";
253  for (vector<string>::iterator pn=(*pcs).second.begin(); pn!=(*pcs).second.end(); ++pn) { // Iterate through the connected client's port names
254  if (pn!=(*pcs).second.begin())
255  os<<", ";
256  os<<*pn;
257  }
258  os<<")";
259  }
260  os<<"}\n";
261  }
262  }
263 }
vector< string > outputPortNames
The output port names.
Definition: JackBase.H:674
bool autoConnectNetClients
When true, autoconnect networked client&#39;s ports to the system ports.
virtual int disconnect(void)
Definition: JackBase.H:254
string clientNameFromPort(jack_port_id_t p)
Definition: JackBase.H:470
#define JACK_CLIENT_NULL_ERROR
client is null
Definition: JackBase.H:46
virtual int connect(string clientName_)
Definition: JackBase.H:369
string clientNameFromPortName(string fullPortName)
Definition: JackBase.H:489
int getPortListAndCount(JackPortFlags flags, vector< jack_port_t *> *ports, const char *portNamePattern, const char *typeNamePattern)
Definition: JackBase.H:159
#define JACK_PORT_CALLBACK_SETUP_ERROR
error when trying to connect the port monitoring callbacks
Definition: JackBase.H:47
virtual int evaluateError(int errorNum)
Definition: Debug.H:132
virtual void print(ostream &os)
bool running()
Definition: Thread.H:228
float p
virtual int connect(string clientName_)
virtual void reSyncPorts(void)
Definition: JackBase.H:196
string cn
The string to compare against.
virtual int disconnect(void)
void init()
Definition: JackBase.H:92
#define NO_ERROR
There is no error.
Definition: Debug.H:33
static void jackPortConnectCallback(jack_port_id_t a, jack_port_id_t b, int connect, void *arg)
virtual int run(int priority=0)
Definition: Thread.H:263
virtual void breakDownPortsToClients(vector< jack_port_t *> &ports)
virtual void * threadMain(void)
void addInputPort(jack_port_t *inP)
Definition: JackBase.H:545
void connectPortRenameCallback(void)
vector< JackBaseWithPortNames * > knownClients
A vector of clients and their ports both ids and names.
#define JACK_NETPORT_AUTOCONNECT_ERROR
error when trying to connect network ports automatically.
Definition: JackBase.H:54
int unLock()
Definition: Thread.H:325
static void jackPortRegistrationCallback(jack_port_id_t port, int reg, void *arg)
virtual void reSyncPorts(void)
virtual void reSyncConnections(void)
Cond cond
Definition: Thread.H:441
jack_client_t * client
The jack client.
Definition: JackBase.H:108
static void jackPortRenameCallback(jack_port_id_t port, const char *oldName, const char *newName, void *arg)
#define JACK_PORT_MONITOR_CLIENT_NAME
The name to give port monitoring clients.
vector< jack_port_t * > inputPorts
The input ports.
Definition: JackBase.H:118
bool connect1To1
When true, then connections are made in a 1 to 1 manner. When False, then connections are made in an ...
Definition: JackBase.H:208
virtual void autoConnectNetClientsPorts(void)
void connectPortRegistrationCallback(void)
void connectPortMonitoringCallbacks(void)
void setClient(jack_client_t *c)
Definition: JackBase.H:651
#define JACK_ACTIVATE_ERROR
Couldn&#39;t activate the client with the server.
Definition: JackBase.H:39
void wait()
Definition: Thread.H:361
map< string, map< string, vector< string > > > inputPortNamesAndConnections
The input port names which map to a vector of the connected clients and each of their connected ports...
Definition: JackBase.H:673
vector< jack_port_t * > outputPorts
The output ports.
Definition: JackBase.H:119
int connectPorts(const string inName, const string outName)
Definition: JackBase.H:591
int lock()
Definition: Thread.H:295
virtual void setClientName(string cn)
Definition: JackBase.H:443
void addOutputPort(jack_port_t *outP)
Definition: JackBase.H:552
void connectPortConnectCallback(void)
gtkIOStream: /tmp/gtkiostream/src/JackPortMonitor.C Source File
GTK+ IOStream  Beta