Merge /gui/jack_proxy.cpp to jack_proxy.c
[ladish.git] / gui / jack_proxy.cpp
blobbaa862b8f28388c0e34280cc6942a21bc22defda
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2008, 2009 Nedko Arnaudov <nedko@arnaudov.name>
7 **************************************************************************
8 * This file contains code that interface with JACK through D-Bus
9 **************************************************************************
11 * LADI Session Handler is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * LADI Session Handler is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
23 * or write to the Free Software Foundation, Inc.,
24 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include "common.h"
29 #include <cassert>
30 #include <cstring>
31 #include <set>
32 #include <iostream>
34 #include <glib.h>
35 #include <dbus/dbus.h>
36 #include <dbus/dbus-glib.h>
37 #include <dbus/dbus-glib-lowlevel.h>
39 #include "Patchage.hpp"
40 #include "jack_proxy.hpp"
41 #include "dbus_helpers.h"
43 #define JACKDBUS_SERVICE "org.jackaudio.service"
44 #define JACKDBUS_OBJECT "/org/jackaudio/Controller"
45 #define JACKDBUS_IFACE_CONTROL "org.jackaudio.JackControl"
47 #define JACKDBUS_PORT_FLAG_INPUT 0x00000001
48 #define JACKDBUS_PORT_FLAG_OUTPUT 0x00000002
49 #define JACKDBUS_PORT_FLAG_PHYSICAL 0x00000004
50 #define JACKDBUS_PORT_FLAG_CAN_MONITOR 0x00000008
51 #define JACKDBUS_PORT_FLAG_TERMINAL 0x00000010
53 #define JACKDBUS_PORT_TYPE_AUDIO 0
54 #define JACKDBUS_PORT_TYPE_MIDI 1
56 jack_proxy::jack_proxy(Patchage* app)
57 : _app(app)
58 , _server_responding(false)
59 , _server_started(false)
60 , _graph_version(0)
61 , _max_dsp_load(0.0)
63 patchage_dbus_add_match("type='signal',interface='" DBUS_INTERFACE_DBUS "',member=NameOwnerChanged,arg0='" JACKDBUS_SERVICE "'");
64 patchage_dbus_add_filter(dbus_message_hook, this);
66 update_attached();
68 if (!_server_responding) {
69 return;
74 jack_proxy::~jack_proxy()
78 void
79 jack_proxy::update_attached()
81 bool was_started = _server_started;
82 _server_started = is_started();
84 if (!_server_responding) {
85 if (was_started) {
86 signal_stopped.emit();
88 return;
91 if (_server_started && !was_started) {
92 signal_started.emit();
93 return;
96 if (!_server_started && was_started) {
97 signal_stopped.emit();
98 return;
103 void
104 jack_proxy::on_jack_appeared()
106 info_msg("JACK appeared.");
107 update_attached();
111 void
112 jack_proxy::on_jack_disappeared()
114 info_msg("JACK disappeared.");
116 // we are not calling update_attached() here, because it will activate jackdbus
118 _server_responding = false;
120 if (_server_started) {
121 signal_stopped.emit();
124 _server_started = false;
128 DBusHandlerResult
129 jack_proxy::dbus_message_hook(
130 DBusConnection* connection,
131 DBusMessage* message,
132 void* jack_driver)
134 const char *object_name;
135 const char *old_owner;
136 const char *new_owner;
138 assert(jack_driver);
139 jack_proxy* me = reinterpret_cast<jack_proxy*>(jack_driver);
141 //me->info_msg("dbus_message_hook() called.");
143 // Handle signals we have subscribed for in attach()
145 if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
146 if (!dbus_message_get_args( message, &g_dbus_error,
147 DBUS_TYPE_STRING, &object_name,
148 DBUS_TYPE_STRING, &old_owner,
149 DBUS_TYPE_STRING, &new_owner,
150 DBUS_TYPE_INVALID)) {
151 me->error_msg(str(boost::format("dbus_message_get_args() failed to extract "
152 "NameOwnerChanged signal arguments (%s)") % g_dbus_error.message));
153 dbus_error_free(&g_dbus_error);
154 return DBUS_HANDLER_RESULT_HANDLED;
157 if ((std::string)object_name != JACKDBUS_SERVICE)
159 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
162 if (old_owner[0] == '\0') {
163 me->on_jack_appeared();
164 } else if (new_owner[0] == '\0') {
165 me->on_jack_disappeared();
168 return DBUS_HANDLER_RESULT_HANDLED;
171 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
174 bool
175 jack_proxy::call(
176 bool response_expected,
177 const char* iface,
178 const char* method,
179 DBusMessage** reply_ptr_ptr,
180 int in_type, ...)
182 va_list ap;
184 va_start(ap, in_type);
186 _server_responding = patchage_dbus_call_valist(
187 response_expected,
188 JACKDBUS_SERVICE,
189 JACKDBUS_OBJECT,
190 iface,
191 method,
192 reply_ptr_ptr,
193 in_type,
194 ap);
196 va_end(ap);
198 return _server_responding;
201 bool
202 jack_proxy::is_started()
204 DBusMessage* reply_ptr;
205 dbus_bool_t started;
207 if (!call(false, JACKDBUS_IFACE_CONTROL, "IsStarted", &reply_ptr, DBUS_TYPE_INVALID)) {
208 return false;
211 if (!dbus_message_get_args(reply_ptr, &g_dbus_error,
212 DBUS_TYPE_BOOLEAN, &started,
213 DBUS_TYPE_INVALID)) {
214 dbus_message_unref(reply_ptr);
215 dbus_error_free(&g_dbus_error);
216 error_msg("decoding reply of IsStarted failed.");
217 return false;
220 dbus_message_unref(reply_ptr);
222 return started;
226 void
227 jack_proxy::start_server()
229 DBusMessage* reply_ptr;
231 if (!call(false, JACKDBUS_IFACE_CONTROL, "StartServer", &reply_ptr, DBUS_TYPE_INVALID)) {
232 return;
235 dbus_message_unref(reply_ptr);
237 update_attached();
241 void
242 jack_proxy::stop_server()
244 DBusMessage* reply_ptr;
246 if (!call(false, JACKDBUS_IFACE_CONTROL, "StopServer", &reply_ptr, DBUS_TYPE_INVALID)) {
247 return;
250 dbus_message_unref(reply_ptr);
252 if (!_server_started) {
253 _server_started = false;
254 signal_stopped.emit();
258 uint32_t
259 jack_proxy::buffer_size()
261 DBusMessage* reply_ptr;
262 dbus_uint32_t buffer_size;
264 if (_server_responding && !_server_started) {
265 goto fail;
268 if (!call(true, JACKDBUS_IFACE_CONTROL, "GetBufferSize", &reply_ptr, DBUS_TYPE_INVALID)) {
269 goto fail;
272 if (!dbus_message_get_args(reply_ptr, &g_dbus_error, DBUS_TYPE_UINT32, &buffer_size, DBUS_TYPE_INVALID)) {
273 dbus_message_unref(reply_ptr);
274 dbus_error_free(&g_dbus_error);
275 error_msg("decoding reply of GetBufferSize failed.");
276 goto fail;
279 dbus_message_unref(reply_ptr);
281 return buffer_size;
283 fail:
284 return 4096; // something fake, patchage needs it to match combobox value
288 bool
289 jack_proxy::set_buffer_size(uint32_t size)
291 DBusMessage* reply_ptr;
292 dbus_uint32_t buffer_size;
294 buffer_size = size;
296 if (!call(true, JACKDBUS_IFACE_CONTROL, "SetBufferSize", &reply_ptr, DBUS_TYPE_UINT32, &buffer_size, DBUS_TYPE_INVALID)) {
297 return false;
300 dbus_message_unref(reply_ptr);
302 return true;
306 float
307 jack_proxy::sample_rate()
309 DBusMessage* reply_ptr;
310 double sample_rate;
312 if (!call(true, JACKDBUS_IFACE_CONTROL, "GetSampleRate", &reply_ptr, DBUS_TYPE_INVALID)) {
313 return false;
316 if (!dbus_message_get_args(reply_ptr, &g_dbus_error, DBUS_TYPE_DOUBLE, &sample_rate, DBUS_TYPE_INVALID)) {
317 dbus_message_unref(reply_ptr);
318 dbus_error_free(&g_dbus_error);
319 error_msg("decoding reply of GetSampleRate failed.");
320 return false;
323 dbus_message_unref(reply_ptr);
325 return sample_rate;
329 bool
330 jack_proxy::is_realtime()
332 DBusMessage* reply_ptr;
333 dbus_bool_t realtime;
335 if (!call(true, JACKDBUS_IFACE_CONTROL, "IsRealtime", &reply_ptr, DBUS_TYPE_INVALID)) {
336 return false;
339 if (!dbus_message_get_args(reply_ptr, &g_dbus_error, DBUS_TYPE_BOOLEAN, &realtime, DBUS_TYPE_INVALID)) {
340 dbus_message_unref(reply_ptr);
341 dbus_error_free(&g_dbus_error);
342 error_msg("decoding reply of IsRealtime failed.");
343 return false;
346 dbus_message_unref(reply_ptr);
348 return realtime;
352 size_t
353 jack_proxy::xruns()
355 DBusMessage* reply_ptr;
356 dbus_uint32_t xruns;
358 if (_server_responding && !_server_started) {
359 return 0;
362 if (!call(true, JACKDBUS_IFACE_CONTROL, "GetXruns", &reply_ptr, DBUS_TYPE_INVALID)) {
363 return 0;
366 if (!dbus_message_get_args(reply_ptr, &g_dbus_error, DBUS_TYPE_UINT32, &xruns, DBUS_TYPE_INVALID)) {
367 dbus_message_unref(reply_ptr);
368 dbus_error_free(&g_dbus_error);
369 error_msg("decoding reply of GetXruns failed.");
370 return 0;
373 dbus_message_unref(reply_ptr);
375 return xruns;
379 void
380 jack_proxy::reset_xruns()
382 DBusMessage* reply_ptr;
384 if (!call(true, JACKDBUS_IFACE_CONTROL, "ResetXruns", &reply_ptr, DBUS_TYPE_INVALID)) {
385 return;
388 dbus_message_unref(reply_ptr);
392 float
393 jack_proxy::get_dsp_load()
395 DBusMessage* reply_ptr;
396 double load;
398 if (_server_responding && !_server_started) {
399 return 0.0;
402 if (!call(true, JACKDBUS_IFACE_CONTROL, "GetLoad", &reply_ptr, DBUS_TYPE_INVALID)) {
403 return 0.0;
406 if (!dbus_message_get_args(reply_ptr, &g_dbus_error, DBUS_TYPE_DOUBLE, &load, DBUS_TYPE_INVALID)) {
407 dbus_message_unref(reply_ptr);
408 dbus_error_free(&g_dbus_error);
409 error_msg("decoding reply of GetLoad failed.");
410 return 0.0;
413 dbus_message_unref(reply_ptr);
415 return load;
418 void
419 jack_proxy::error_msg(const std::string& msg) const
421 _app->error_msg((std::string)"[JACKDBUS] " + msg);
424 void
425 jack_proxy::info_msg(const std::string& msg) const
427 _app->info_msg((std::string)"[JACKDBUS] " + msg);