Line 0
Link Here
|
|
|
1 |
/* |
2 |
* ALSA Patch Bay |
3 |
* |
4 |
* Copyright (C) 2002 Robert Ham (node@users.sourceforge.net) |
5 |
* |
6 |
* You have permission to use this file under the GNU General |
7 |
* Public License, version 2 or later. See the file COPYING |
8 |
* for the full text. |
9 |
* |
10 |
*/ |
11 |
|
12 |
#include <unistd.h> |
13 |
#include <stdio.h> |
14 |
#include <errno.h> |
15 |
|
16 |
#include "jack-driver.h" |
17 |
#include "jack-addr.h" |
18 |
#include "misc.h" |
19 |
#include "plugin.h" |
20 |
#include "ui.h" |
21 |
|
22 |
#include <cstring> |
23 |
namespace APB { |
24 |
namespace Jack { |
25 |
|
26 |
static int |
27 |
jackGraphOrderCallback (void * data) |
28 |
{ |
29 |
char refresh = 1; |
30 |
ssize_t err; |
31 |
int refreshWriteFile = *(int *)data; |
32 |
|
33 |
err = write (refreshWriteFile, &refresh, sizeof (refresh)); |
34 |
if (err == -1) |
35 |
{ |
36 |
std::cerr << "error writing to refresh pipe: " |
37 |
<< strerror (errno) |
38 |
<< std::endl; |
39 |
return 1; |
40 |
} |
41 |
|
42 |
return 0; |
43 |
} |
44 |
|
45 |
Driver:: Driver (const std::string& title, int * argc, char *** argv) |
46 |
{ |
47 |
char * client_name; |
48 |
char * ptr; |
49 |
|
50 |
client_name = strdup (title.c_str ()); |
51 |
ptr = client_name; |
52 |
while ( (ptr = strchr (ptr, ' ')) ) |
53 |
*ptr = '_'; |
54 |
|
55 |
_jackClient = jack_client_new (client_name); |
56 |
if (!_jackClient) |
57 |
{ |
58 |
std::cerr << __FUNCTION__ |
59 |
<< ": could not connect to jackd" |
60 |
<< std::endl; |
61 |
abort (); |
62 |
} |
63 |
|
64 |
free (client_name); |
65 |
|
66 |
jack_set_graph_order_callback (_jackClient, &jackGraphOrderCallback, &_refreshWriteFile); |
67 |
|
68 |
jack_activate (_jackClient); |
69 |
} |
70 |
|
71 |
Driver:: ~Driver () |
72 |
{ |
73 |
jack_deactivate (_jackClient); |
74 |
|
75 |
jack_client_close (_jackClient); |
76 |
} |
77 |
|
78 |
std::string |
79 |
Driver:: findClientName (const APB::Addr * addr) const |
80 |
{ |
81 |
const Addr * a = (const Addr *) addr; |
82 |
|
83 |
return std::string (a->client ()); |
84 |
} |
85 |
|
86 |
std::string |
87 |
Driver:: findPortName (const APB::Addr * addr) const |
88 |
{ |
89 |
const Addr * a = (const Addr *) addr; |
90 |
|
91 |
return std::string (a->port ()); |
92 |
} |
93 |
|
94 |
const std::list<APB::Addr *>& |
95 |
Driver:: getReadPorts () |
96 |
{ |
97 |
return _readPorts; |
98 |
} |
99 |
|
100 |
const std::list<APB::Addr *>& |
101 |
Driver:: getWritePorts () |
102 |
{ |
103 |
return _writePorts; |
104 |
} |
105 |
|
106 |
const std::list<const APB::Subscription *>& |
107 |
Driver:: getSubscriptions () |
108 |
{ |
109 |
static std::list<const APB::Subscription *> subs; |
110 |
|
111 |
subs.clear (); |
112 |
for (std::list<APB::Subscription *>::iterator i = _subscriptions.begin (); |
113 |
i != _subscriptions.end(); |
114 |
++i) |
115 |
{ |
116 |
if ((*i)->from () == 0) |
117 |
std::cerr << DEBUG_STRING << "null from()" << std::endl; |
118 |
if ((*i)->to () == 0) |
119 |
std::cerr << DEBUG_STRING << "null to()" << std::endl; |
120 |
subs.push_back (*i); |
121 |
} |
122 |
|
123 |
return subs; |
124 |
} |
125 |
|
126 |
void |
127 |
Driver:: refreshPorts () |
128 |
{ |
129 |
refreshPortList (_readPorts, JackPortIsOutput); |
130 |
refreshPortList (_writePorts, JackPortIsInput); |
131 |
refreshSubscriptions (); |
132 |
} |
133 |
|
134 |
void |
135 |
Driver:: refreshPortList (std::list<APB::Addr *>& portList, enum JackPortFlags flags) |
136 |
{ |
137 |
for (std::list<APB::Addr *>::iterator ad = portList.begin(); |
138 |
ad != portList.end (); |
139 |
++ad) |
140 |
{ |
141 |
/* delete *ad; */ |
142 |
} |
143 |
portList.clear (); |
144 |
|
145 |
const char ** jack_ports = jack_get_ports (_jackClient, NULL, NULL, flags); |
146 |
|
147 |
if (!jack_ports) |
148 |
return; |
149 |
|
150 |
Addr * addr; |
151 |
for (unsigned long i = 0; jack_ports[i]; ++i) |
152 |
{ |
153 |
addr = new Addr (std::string (jack_ports[i]), this); |
154 |
|
155 |
portList.push_back (addr); |
156 |
} |
157 |
|
158 |
free (jack_ports); |
159 |
} |
160 |
|
161 |
Addr * |
162 |
Driver:: findWritePort (const char * portName) |
163 |
{ |
164 |
Addr * addr; |
165 |
std::string port_name (portName); |
166 |
for (std::list<APB::Addr *>::const_iterator writeAddrIter = _writePorts.begin (); |
167 |
writeAddrIter != _writePorts.end (); |
168 |
writeAddrIter++) |
169 |
{ |
170 |
addr = (Addr *) *writeAddrIter; |
171 |
|
172 |
if (port_name == addr->getName ()) |
173 |
return addr; |
174 |
} |
175 |
|
176 |
return 0; |
177 |
} |
178 |
|
179 |
void |
180 |
Driver:: refreshSubscriptions () |
181 |
{ |
182 |
for (std::list<APB::Subscription *>::iterator s = _subscriptions.begin (); |
183 |
s != _subscriptions.end (); |
184 |
++s) |
185 |
{ |
186 |
delete *s; |
187 |
} |
188 |
_subscriptions.clear (); |
189 |
|
190 |
jack_port_t * port; |
191 |
Addr * addr; |
192 |
const char ** connections; |
193 |
|
194 |
for (std::list<APB::Addr *>::const_iterator readAddrIter = _readPorts.begin (); |
195 |
readAddrIter != _readPorts.end (); |
196 |
++readAddrIter) |
197 |
{ |
198 |
addr = (Addr *) *readAddrIter; |
199 |
port = jack_port_by_name (_jackClient, addr->portName ()); |
200 |
|
201 |
if (!port) |
202 |
{ |
203 |
std::cerr << __FUNCTION__ |
204 |
<< ": could not find port '" |
205 |
<< addr->portName () |
206 |
<< "'" |
207 |
<< std::endl; |
208 |
continue; |
209 |
} |
210 |
|
211 |
connections = jack_port_get_all_connections (_jackClient, port); |
212 |
|
213 |
if (!connections) |
214 |
continue; |
215 |
|
216 |
for (unsigned long i = 0; connections[i]; ++i) |
217 |
{ |
218 |
Addr * waddr = findWritePort (connections[i]); |
219 |
|
220 |
if (!waddr) |
221 |
continue; |
222 |
|
223 |
Subscription * sub = new Subscription (addr, waddr); |
224 |
_subscriptions.push_back (sub); |
225 |
} |
226 |
|
227 |
free (connections); |
228 |
} |
229 |
} |
230 |
|
231 |
void |
232 |
Driver:: subscribePorts (const APB::Addr * readAddr, const APB::Addr * writeAddr) |
233 |
{ |
234 |
Addr * raddr = (Addr *) readAddr; |
235 |
Addr * waddr = (Addr *) writeAddr; |
236 |
|
237 |
int err = jack_connect (_jackClient, raddr->portName (), waddr->portName ()); |
238 |
|
239 |
if (err) |
240 |
{ |
241 |
throw Exception ("Jack server could not connect ports"); |
242 |
} |
243 |
|
244 |
_ui->log (std::string ("Subscribed ports '") + raddr->portName () + "' and '" |
245 |
+ waddr->portName () + "'"); |
246 |
} |
247 |
|
248 |
void |
249 |
Driver:: subscribeClients (const APB::Addr * readAddr, const APB::Addr * writeAddr) |
250 |
{ |
251 |
Addr * raddr; |
252 |
Addr * waddr = NULL; |
253 |
std::string rclient (((const Addr *)readAddr)->client ()); |
254 |
std::string wclient (((const Addr *)writeAddr)->client ()); |
255 |
|
256 |
unsigned long rcount = 0; |
257 |
for (std::list<APB::Addr *>::iterator riter = _readPorts.begin (); |
258 |
riter != _readPorts.end (); |
259 |
++riter) |
260 |
{ |
261 |
raddr = (Addr *) *riter; |
262 |
if (raddr->client() == rclient) |
263 |
{ |
264 |
unsigned long wcount = 0; |
265 |
std::list<APB::Addr *>::iterator witer; |
266 |
for (witer = _writePorts.begin (); |
267 |
witer != _writePorts.end (); |
268 |
++witer) |
269 |
{ |
270 |
waddr = (Addr *) *witer; |
271 |
if (waddr->client() == wclient) |
272 |
{ |
273 |
if (wcount == rcount) |
274 |
break; |
275 |
|
276 |
++wcount; |
277 |
} |
278 |
} |
279 |
|
280 |
if (witer == _writePorts.end () || wcount != rcount) |
281 |
continue; |
282 |
|
283 |
subscribePorts (raddr, waddr); |
284 |
|
285 |
rcount++; |
286 |
} |
287 |
} |
288 |
} |
289 |
|
290 |
void |
291 |
Driver:: removeSubscription (const Subscription * sub) |
292 |
{ |
293 |
Addr * raddr = (Addr *) sub->from (); |
294 |
Addr * waddr = (Addr *) sub->to (); |
295 |
|
296 |
int err = jack_disconnect (_jackClient, raddr->portName (), waddr->portName ()); |
297 |
|
298 |
if (err) |
299 |
{ |
300 |
throw Exception ("Jack server could not disconnect ports"); |
301 |
} |
302 |
|
303 |
_ui->log (std::string ("Removed subscription ") + sub->getName ()); |
304 |
} |
305 |
|
306 |
} /* namespace Jack */ |
307 |
|
308 |
class JackPlugin : public DriverPlugin |
309 |
{ |
310 |
public: |
311 |
virtual Driver * getDriver (const std::string& title, int * argc, char *** argv); |
312 |
}; |
313 |
|
314 |
|
315 |
Driver * |
316 |
JackPlugin:: getDriver (const std::string& title, int * argc, char *** argv) |
317 |
{ |
318 |
return new Jack::Driver (title, argc, argv); |
319 |
} |
320 |
|
321 |
} /* namespace APB */ |
322 |
|
323 |
APB::DriverPlugin * |
324 |
getDriverPlugin () |
325 |
{ |
326 |
return new APB::JackPlugin (); |
327 |
} |
328 |
|
329 |
/* EOF */ |
330 |
|