Optimize automation-event process splitting
[ardour.git] / gtk2_ardour / nsmclient.cc
1
2 /*******************************************************************************/
3 /* Copyright (C) 2012 Jonathan Moore Liles                                     */
4 /*                                                                             */
5 /* This program is free software; you can redistribute it and/or modify it     */
6 /* under the terms of the GNU General Public License as published by the       */
7 /* Free Software Foundation; either version 2 of the License, or (at your      */
8 /* option) any later version.                                                  */
9 /*                                                                             */
10 /* This program is distributed in the hope that it will be useful, but WITHOUT */
11 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       */
12 /* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for   */
13 /* more details.                                                               */
14 /*                                                                             */
15 /* You should have received a copy of the GNU General Public License along     */
16 /* with This program; see the file COPYING.  If not,write to the Free Software */
17 /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
18 /*******************************************************************************/
19
20 #include "nsmclient.h"
21 #include <string.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24 #include <stdlib.h>
25
26 #ifndef COMPILER_MSVC
27 #pragma GCC diagnostic ignored "-Wunused-parameter"
28 #else
29 #include <process.h>  // Needed for 'getpid()'
30
31 #include <lo/lo_osc_types.h>
32 #define LO_TT_IMMEDIATE lo_get_tt_immediate()
33 lo_timetag lo_get_tt_immediate() { lo_timetag tt = {0U,1U}; return tt; }
34 #endif
35
36 namespace NSM
37 {
38
39 /************************/
40 /* OSC Message Handlers */
41 /************************/
42
43 #undef OSC_REPLY
44 #undef OSC_REPLY_ERR
45
46 #define OSC_REPLY(value) lo_send_from( ((NSM::Client*)user_data)->nsm_addr, ((NSM::Client*)user_data)->_server, LO_TT_IMMEDIATE, "/reply", "ss", path, value)
47
48 #define OSC_REPLY_ERR(errcode, value) lo_send_from( ((NSM::Client*)user_data)->nsm_addr, ((NSM::Client*)user_data)->_server, LO_TT_IMMEDIATE, "/error", "sis", path, errcode, value)
49
50         Client::Client ()
51         {
52                 nsm_addr = 0;
53                 _nsm_client_id = 0;
54                 _nsm_client_path = 0;
55                 _session_manager_name = 0;
56                 nsm_url = "";
57                 nsm_is_active = false;
58                 _server = 0;
59                 _st = 0;
60         }
61
62         Client::~Client ()
63         {
64                 if (_st) {
65                         stop();
66                 }
67
68                 if (_st) {
69                         lo_server_thread_free (_st);
70                 } else {
71                         lo_server_free (_server);
72                 }
73         }
74
75         void
76         Client::announce (const char *application_name, const char *capabilities, const char *process_name)
77         {
78
79                 lo_address to = lo_address_new_from_url (nsm_url);
80
81                 if (!to)
82                 {
83                         return;
84                 }
85
86                 int pid = (int)getpid();
87
88                 lo_send_from (to, _server, LO_TT_IMMEDIATE, "/nsm/server/announce", "sssiii",
89                             application_name,
90                             capabilities,
91                             process_name,
92                             1, /* api_major_version */
93                             0, /* api_minor_version */
94                             pid);
95
96                 lo_address_free (to);
97         }
98
99         void
100         Client::progress (float p)
101         {
102                 if (nsm_is_active)
103                 {
104                         lo_send_from (nsm_addr, _server, LO_TT_IMMEDIATE, "/nsm/client/progress", "f", p);
105                 }
106         }
107
108         void
109         Client::is_dirty (void)
110         {
111                 if (nsm_is_active)
112                 {
113                         lo_send_from (nsm_addr, _server, LO_TT_IMMEDIATE, "/nsm/client/is_dirty", "");
114                 }
115         }
116
117         void
118         Client::is_clean (void)
119         {
120                 if (nsm_is_active)
121                 {
122                         lo_send_from (nsm_addr, _server, LO_TT_IMMEDIATE, "/nsm/client/is_clean", "");
123                 }
124         }
125
126         void
127         Client::message (int priority, const char *msg)
128         {
129                 if (nsm_is_active)
130                 {
131                         lo_send_from (nsm_addr, _server, LO_TT_IMMEDIATE, "/nsm/client/message", "is", priority, msg);
132                 }
133         }
134
135
136         void
137         Client::broadcast (lo_message msg)
138         {
139                 if (nsm_is_active)
140                 {
141                         lo_send_message_from (nsm_addr, _server, "/nsm/server/broadcast", msg);
142                 }
143         }
144
145         void
146         Client::check (int timeout)
147         {
148                 if (lo_server_wait (_server, timeout)) {
149                         while (lo_server_recv_noblock (_server, 0));
150                 }
151         }
152
153         void
154         Client::start ()
155         {
156                 lo_server_thread_start (_st);
157         }
158
159         void
160         Client::stop ()
161         {
162                 lo_server_thread_stop (_st);
163         }
164
165         int
166         Client::init (const char *nsm_url)
167         {
168                 this->nsm_url = nsm_url;
169
170                 lo_address addr = lo_address_new_from_url (nsm_url);
171                 int proto = lo_address_get_protocol (addr);
172                 lo_address_free (addr);
173
174                 _server = lo_server_new_with_proto (NULL, proto, NULL);
175
176                 if (!_server) {
177                         return -1;
178                 }
179
180                 lo_server_add_method (_server, "/error", "sis", &Client::osc_error, this);
181                 lo_server_add_method (_server, "/reply", "ssss", &Client::osc_announce_reply, this);
182                 lo_server_add_method (_server, "/nsm/client/open", "sss", &Client::osc_open, this);
183                 lo_server_add_method (_server, "/nsm/client/save", "", &Client::osc_save, this);
184                 lo_server_add_method (_server, "/nsm/client/session_is_loaded", "", &Client::osc_session_is_loaded, this);
185                 lo_server_add_method (_server, NULL, NULL, &Client::osc_broadcast, this);
186
187                 return 0;
188         }
189
190         int
191         Client::init_thread (const char *nsm_url)
192         {
193                 this->nsm_url = nsm_url;
194
195                 lo_address addr = lo_address_new_from_url (nsm_url);
196                 int proto = lo_address_get_protocol (addr);
197                 lo_address_free (addr);
198
199                 _st = lo_server_thread_new_with_proto (NULL, proto, NULL);
200                 _server = lo_server_thread_get_server (_st);
201
202                 if  (! _server || ! _st) {
203                         return -1;
204                 }
205
206                 lo_server_thread_add_method (_st, "/error", "sis", &Client::osc_error, this);
207                 lo_server_thread_add_method (_st, "/reply", "ssss", &Client::osc_announce_reply, this);
208                 lo_server_thread_add_method (_st, "/nsm/client/open", "sss", &Client::osc_open, this);
209                 lo_server_thread_add_method (_st, "/nsm/client/save", "", &Client::osc_save, this);
210                 lo_server_thread_add_method (_st, "/nsm/client/session_is_loaded", "", &Client::osc_session_is_loaded, this);
211                 lo_server_thread_add_method (_st, NULL, NULL, &Client::osc_broadcast, this);
212
213                 return 0;
214         }
215
216 /************************/
217 /* OSC Message Handlers */
218 /************************/
219
220         int
221         Client::osc_broadcast  (const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data)
222         {
223                 return ((NSM::Client*)user_data)->command_broadcast (path, msg);
224         }
225
226         int
227         Client::osc_save  (const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data)
228         {
229                 char *out_msg = NULL;
230
231                 int r = ((NSM::Client*)user_data)->command_save(&out_msg);
232
233                 if  (r) {
234                         OSC_REPLY_ERR (r, (out_msg ? out_msg : ""));
235                 } else {
236                         OSC_REPLY ("OK");
237                 }
238
239                 if (out_msg) {
240                         free (out_msg);
241                 }
242
243                 return 0;
244         }
245
246         int
247         Client::osc_open (const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data)
248         {
249                 char *out_msg = NULL;
250
251                 NSM::Client *nsm = (NSM::Client*)user_data;
252
253                 nsm->_nsm_client_id = strdup (&argv[2]->s);
254                 nsm->_nsm_client_path = strdup (&argv[0]->s);
255
256                 int r = ((NSM::Client*)user_data)->command_open (&argv[0]->s, &argv[1]->s, &argv[2]->s, &out_msg);
257
258                 if (r) {
259                         OSC_REPLY_ERR (r, (out_msg ? out_msg : ""));
260                 } else {
261                         OSC_REPLY ("OK");
262                 }
263
264                 if (out_msg) {
265                         free(out_msg);
266                 }
267
268                 return 0;
269         }
270
271         int
272         Client::osc_session_is_loaded (const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data)
273         {
274                 NSM::Client *nsm = (NSM::Client*)user_data;
275
276                 nsm->command_session_is_loaded();
277
278                 return 0;
279         }
280
281         int
282         Client::osc_error (const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data)
283         {
284                 if (strcmp (&argv[0]->s, "/nsm/server/announce")) {
285                         return -1;
286                 }
287
288                 NSM::Client *nsm = (NSM::Client*)user_data;
289
290
291                 nsm->nsm_is_active = false;
292
293                 nsm->command_active (nsm->nsm_is_active);
294
295                 return 0;
296         }
297
298         int
299         Client::osc_announce_reply (const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data)
300         {
301                 if (strcmp (&argv[0]->s, "/nsm/server/announce")) {
302                         return -1;
303                 }
304
305                 NSM::Client *nsm = (NSM::Client*)user_data;
306
307                 nsm->nsm_is_active = true;
308                 nsm->_session_manager_name = strdup (&argv[2]->s);
309                 nsm->nsm_addr = lo_address_new_from_url (lo_address_get_url (lo_message_get_source (msg)));
310
311                 nsm->command_active (nsm->nsm_is_active);
312
313                 return 0;
314         }
315 };