1 |
/**************************************************************************** |
2 |
GLASHCtl - a simple tray applet for controlling lashd |
3 |
|
4 |
Copyright (C) 2006 Lars Luthman <lars.luthman@gmail.com> |
5 |
|
6 |
This program is free software; you can redistribute it and/or modify |
7 |
it under the terms of the GNU General Public License as published by |
8 |
the Free Software Foundation; either version 3 of the License, or |
9 |
(at your option) any later version. |
10 |
|
11 |
This program is distributed in the hope that it will be useful, |
12 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 |
GNU General Public License for more details. |
15 |
|
16 |
You should have received a copy of the GNU General Public License |
17 |
along with this program; if not, write to the Free Software Foundation, |
18 |
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 |
****************************************************************************/ |
20 |
|
21 |
#include <iostream> |
22 |
|
23 |
#include <glibmm.h> |
24 |
|
25 |
#include "jackwrapper.hpp" |
26 |
|
27 |
|
28 |
using namespace std; |
29 |
using namespace Glib; |
30 |
using namespace sigc; |
31 |
|
32 |
|
33 |
JACKWrapper::JACKWrapper(const std::string& client_name) |
34 |
: m_client(0) { |
35 |
|
36 |
if (m_client = jack_client_open(client_name.c_str(), JackNullOption, 0)) { |
37 |
sem_init(&m_portreg_sem, 0, 0); |
38 |
signal_timeout().connect(mem_fun(*this, &JACKWrapper::check_portreg), 100); |
39 |
jack_set_port_registration_callback(m_client, |
40 |
&JACKWrapper::port_registration_callback, |
41 |
this); |
42 |
jack_set_graph_order_callback(m_client, |
43 |
&JACKWrapper::graph_order_callback, this); |
44 |
jack_activate(m_client); |
45 |
|
46 |
signal_timeout().connect(mem_fun(*this, &JACKWrapper::force_check), 4000); |
47 |
} |
48 |
|
49 |
} |
50 |
|
51 |
|
52 |
JACKWrapper::~JACKWrapper() { |
53 |
if (m_client) { |
54 |
jack_deactivate(m_client); |
55 |
jack_client_close(m_client); |
56 |
sem_destroy(&m_portreg_sem); |
57 |
} |
58 |
} |
59 |
|
60 |
|
61 |
void JACKWrapper::connect(const std::string& output, const std::string& input) { |
62 |
if (m_client) |
63 |
jack_connect(m_client, output.c_str(), input.c_str()); |
64 |
} |
65 |
|
66 |
|
67 |
void JACKWrapper::disconnect(const std::string& output, |
68 |
const std::string& input) { |
69 |
if (m_client) |
70 |
jack_disconnect(m_client, output.c_str(), input.c_str()); |
71 |
} |
72 |
|
73 |
|
74 |
bool JACKWrapper::force_check() { |
75 |
if (m_client) |
76 |
sem_post(&m_portreg_sem); |
77 |
return true; |
78 |
} |
79 |
|
80 |
|
81 |
void JACKWrapper::port_registration_callback(jack_port_id_t, int, void* arg) { |
82 |
sem_post(&static_cast<JACKWrapper*>(arg)->m_portreg_sem); |
83 |
} |
84 |
|
85 |
|
86 |
int JACKWrapper::graph_order_callback(void* arg) { |
87 |
sem_post(&static_cast<JACKWrapper*>(arg)->m_portreg_sem); |
88 |
} |
89 |
|
90 |
|
91 |
bool JACKWrapper::check_portreg() { |
92 |
if (!sem_trywait(&m_portreg_sem)) { |
93 |
|
94 |
const char** ports = jack_get_ports(m_client, 0, 0, 0); |
95 |
if (ports) { |
96 |
|
97 |
// check for new or removed ports |
98 |
|
99 |
// mark all old ones as gone |
100 |
map<string, PortInfo>::iterator iter; |
101 |
for (iter = m_ports.begin(); iter != m_ports.end(); ++iter) |
102 |
iter->second.flag = false; |
103 |
|
104 |
// add new ports to our map and mark old ones as still here |
105 |
for (int i = 0; ports[i]; ++i) { |
106 |
jack_port_t* port = jack_port_by_name(m_client, ports[i]); |
107 |
PortInfo* pi = 0; |
108 |
if (m_ports.find(ports[i]) == m_ports.end()) { |
109 |
if (port) { |
110 |
m_ports[ports[i]].type = jack_port_type(port); |
111 |
if (jack_port_flags(port) & JackPortIsInput) { |
112 |
signal_input_added(ports[i], m_ports[ports[i]].type); |
113 |
m_ports[ports[i]].is_input = true; |
114 |
} |
115 |
else { |
116 |
signal_output_added(ports[i], m_ports[ports[i]].type); |
117 |
m_ports[ports[i]].is_input = false; |
118 |
} |
119 |
} |
120 |
} |
121 |
pi = &m_ports[ports[i]]; |
122 |
pi->flag = true; |
123 |
} |
124 |
|
125 |
// remove unregistered ports from our map |
126 |
for (iter = m_ports.begin(); iter != m_ports.end(); ) { |
127 |
if (iter->second.flag == false) { |
128 |
map<string, PortInfo>::iterator iter2 = iter; |
129 |
++iter; |
130 |
if (iter2->second.is_input) |
131 |
signal_input_removed(iter2->first); |
132 |
else |
133 |
signal_output_removed(iter2->first); |
134 |
m_ports.erase(iter2); |
135 |
} |
136 |
else |
137 |
++iter; |
138 |
} |
139 |
|
140 |
|
141 |
free(ports); |
142 |
} |
143 |
|
144 |
|
145 |
// check for new or removed connections for all output ports |
146 |
|
147 |
map<string, PortInfo>::iterator piter; |
148 |
for (piter = m_ports.begin(); piter != m_ports.end(); ++piter) { |
149 |
if (!piter->second.is_input) { |
150 |
|
151 |
jack_port_t* port = jack_port_by_name(m_client, piter->first.c_str()); |
152 |
if (port) { |
153 |
|
154 |
const char** connections = jack_port_get_all_connections(m_client, |
155 |
port); |
156 |
if (connections) { |
157 |
|
158 |
// mark all connections as gone |
159 |
map<string, bool>::iterator pciter; |
160 |
for (pciter = piter->second.connections.begin(); |
161 |
pciter != piter->second.connections.end(); ++pciter) |
162 |
pciter->second = false; |
163 |
|
164 |
// find new connections and mark old ones that are still here |
165 |
for (int c = 0; connections[c]; ++c) { |
166 |
if (piter->second.connections.find(connections[c]) == |
167 |
piter->second.connections.end()) { |
168 |
signal_connected(piter->first, connections[c]); |
169 |
} |
170 |
piter->second.connections[connections[c]] = true; |
171 |
} |
172 |
|
173 |
// remove all connections that are not here anymore |
174 |
for (pciter = piter->second.connections.begin(); |
175 |
pciter != piter->second.connections.end(); ) { |
176 |
if (pciter->second == false) { |
177 |
map<string, bool>::iterator tmp = pciter; |
178 |
++pciter; |
179 |
signal_disconnected(piter->first, tmp->first); |
180 |
piter->second.connections.erase(tmp); |
181 |
} |
182 |
else |
183 |
++pciter; |
184 |
} |
185 |
|
186 |
free(connections); |
187 |
} |
188 |
|
189 |
// if there are no connections, clear all old ones |
190 |
else { |
191 |
map<string, bool>::iterator pciter; |
192 |
for (pciter = piter->second.connections.begin(); |
193 |
pciter != piter->second.connections.end(); ++pciter) |
194 |
signal_disconnected(piter->first, pciter->first); |
195 |
piter->second.connections.clear(); |
196 |
} |
197 |
|
198 |
} |
199 |
} |
200 |
} |
201 |
|
202 |
|
203 |
|
204 |
} |
205 |
} |
206 |
|
207 |
|
208 |
|