1 /* -*- Mode: C ; c-basic-offset: 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.
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
)
58 , _server_responding(false)
59 , _server_started(false)
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);
68 if (!_server_responding
) {
74 jack_proxy::~jack_proxy()
79 jack_proxy::update_attached()
81 bool was_started
= _server_started
;
82 _server_started
= is_started();
84 if (!_server_responding
) {
86 signal_stopped
.emit();
91 if (_server_started
&& !was_started
) {
92 signal_started
.emit();
96 if (!_server_started
&& was_started
) {
97 signal_stopped
.emit();
104 jack_proxy::on_jack_appeared()
106 info_msg("JACK appeared.");
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;
129 jack_proxy::dbus_message_hook(
130 DBusConnection
* connection
,
131 DBusMessage
* message
,
134 const char *object_name
;
135 const char *old_owner
;
136 const char *new_owner
;
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
;
176 bool response_expected
,
179 DBusMessage
** reply_ptr_ptr
,
184 va_start(ap
, in_type
);
186 _server_responding
= patchage_dbus_call_valist(
198 return _server_responding
;
202 jack_proxy::is_started()
204 DBusMessage
* reply_ptr
;
207 if (!call(false, JACKDBUS_IFACE_CONTROL
, "IsStarted", &reply_ptr
, DBUS_TYPE_INVALID
)) {
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.");
220 dbus_message_unref(reply_ptr
);
227 jack_proxy::start_server()
229 DBusMessage
* reply_ptr
;
231 if (!call(false, JACKDBUS_IFACE_CONTROL
, "StartServer", &reply_ptr
, DBUS_TYPE_INVALID
)) {
235 dbus_message_unref(reply_ptr
);
242 jack_proxy::stop_server()
244 DBusMessage
* reply_ptr
;
246 if (!call(false, JACKDBUS_IFACE_CONTROL
, "StopServer", &reply_ptr
, DBUS_TYPE_INVALID
)) {
250 dbus_message_unref(reply_ptr
);
252 if (!_server_started
) {
253 _server_started
= false;
254 signal_stopped
.emit();
259 jack_proxy::buffer_size()
261 DBusMessage
* reply_ptr
;
262 dbus_uint32_t buffer_size
;
264 if (_server_responding
&& !_server_started
) {
268 if (!call(true, JACKDBUS_IFACE_CONTROL
, "GetBufferSize", &reply_ptr
, DBUS_TYPE_INVALID
)) {
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.");
279 dbus_message_unref(reply_ptr
);
284 return 4096; // something fake, patchage needs it to match combobox value
289 jack_proxy::set_buffer_size(uint32_t size
)
291 DBusMessage
* reply_ptr
;
292 dbus_uint32_t buffer_size
;
296 if (!call(true, JACKDBUS_IFACE_CONTROL
, "SetBufferSize", &reply_ptr
, DBUS_TYPE_UINT32
, &buffer_size
, DBUS_TYPE_INVALID
)) {
300 dbus_message_unref(reply_ptr
);
307 jack_proxy::sample_rate()
309 DBusMessage
* reply_ptr
;
312 if (!call(true, JACKDBUS_IFACE_CONTROL
, "GetSampleRate", &reply_ptr
, DBUS_TYPE_INVALID
)) {
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.");
323 dbus_message_unref(reply_ptr
);
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
)) {
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.");
346 dbus_message_unref(reply_ptr
);
355 DBusMessage
* reply_ptr
;
358 if (_server_responding
&& !_server_started
) {
362 if (!call(true, JACKDBUS_IFACE_CONTROL
, "GetXruns", &reply_ptr
, DBUS_TYPE_INVALID
)) {
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.");
373 dbus_message_unref(reply_ptr
);
380 jack_proxy::reset_xruns()
382 DBusMessage
* reply_ptr
;
384 if (!call(true, JACKDBUS_IFACE_CONTROL
, "ResetXruns", &reply_ptr
, DBUS_TYPE_INVALID
)) {
388 dbus_message_unref(reply_ptr
);
393 jack_proxy::get_dsp_load()
395 DBusMessage
* reply_ptr
;
398 if (_server_responding
&& !_server_started
) {
402 if (!call(true, JACKDBUS_IFACE_CONTROL
, "GetLoad", &reply_ptr
, DBUS_TYPE_INVALID
)) {
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.");
413 dbus_message_unref(reply_ptr
);
419 jack_proxy::error_msg(const std::string
& msg
) const
421 _app
->error_msg((std::string
)"[JACKDBUS] " + msg
);
425 jack_proxy::info_msg(const std::string
& msg
) const
427 _app
->info_msg((std::string
)"[JACKDBUS] " + msg
);