non-session-manager support
[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 #pragma GCC diagnostic ignored "-Wunused-parameter"
27
28 namespace NSM
29 {
30
31 /************************/
32 /* OSC Message Handlers */
33 /************************/
34
35 #undef OSC_REPLY
36 #undef OSC_REPLY_ERR
37
38 #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 )
39
40 #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 )
41
42     Client::Client ( )
43     {
44         nsm_addr = 0;
45         _nsm_client_id = 0;
46         _nsm_client_path = 0;
47         _session_manager_name = 0;
48         nsm_url = "";
49         nsm_is_active = false;
50         _server = 0;
51         _st = 0;
52     }
53
54     Client::~Client ( )
55     {
56         if ( _st )
57             stop();
58         
59         if ( _st )
60             lo_server_thread_free( _st );
61         else
62             lo_server_free ( _server );
63     }
64
65     void
66     Client::announce ( const char *application_name, const char *capabilities, const char *process_name )
67     {
68
69         lo_address to = lo_address_new_from_url( nsm_url );
70
71         if ( ! to )
72         {
73             return;
74         }
75
76         int pid = (int)getpid();
77
78         lo_send_from( to, _server, LO_TT_IMMEDIATE, "/nsm/server/announce", "sssiii",
79                             application_name,
80                             capabilities,
81                             process_name,
82                             1, /* api_major_version */
83                             0, /* api_minor_version */
84                             pid );
85
86         lo_address_free( to );
87     }
88
89     void
90     Client::progress ( float p )
91     {
92         if ( nsm_is_active )
93         {
94             lo_send_from( nsm_addr, _server, LO_TT_IMMEDIATE, "/nsm/client/progress", "f", p );
95         }
96     }
97
98     void
99     Client::is_dirty ( void )
100     {
101         if ( nsm_is_active )
102         {
103             lo_send_from( nsm_addr, _server, LO_TT_IMMEDIATE, "/nsm/client/is_dirty", "" );
104         }
105     }
106
107     void
108     Client::is_clean ( void )
109     {
110         if ( nsm_is_active )
111         {
112             lo_send_from( nsm_addr, _server, LO_TT_IMMEDIATE, "/nsm/client/is_clean", "" );
113         }
114     }
115
116     void
117     Client::message ( int priority, const char *msg )
118     {
119         if ( nsm_is_active )
120         {
121             lo_send_from( nsm_addr, _server, LO_TT_IMMEDIATE, "/nsm/client/message", "is", priority, msg );
122         }
123     }
124
125     
126     void
127     Client::broadcast ( lo_message msg )
128     {
129         if ( nsm_is_active )
130         {
131             lo_send_message_from( nsm_addr, _server, "/nsm/server/broadcast", msg );
132         }
133     }
134
135     void
136     Client::check ( int timeout )
137     {
138         if ( lo_server_wait( _server, timeout ) )
139             while ( lo_server_recv_noblock( _server, 0 ) ) {}
140     }
141
142     void
143     Client::start ( )
144     {
145         lo_server_thread_start( _st );
146     }
147
148     void
149     Client::stop ( )
150     {
151         lo_server_thread_stop( _st );
152     }
153
154     int
155     Client::init ( const char *nsm_url )
156     {
157         this->nsm_url = nsm_url;
158
159         lo_address addr = lo_address_new_from_url( nsm_url );
160         int proto = lo_address_get_protocol( addr );
161         lo_address_free( addr );
162
163         _server = lo_server_new_with_proto( NULL, proto, NULL );
164
165         if ( ! _server )
166             return -1;
167
168         lo_server_add_method( _server, "/error", "sis", &Client::osc_error, this );
169         lo_server_add_method( _server, "/reply", "ssss", &Client::osc_announce_reply, this );
170         lo_server_add_method( _server, "/nsm/client/open", "sss", &Client::osc_open, this );
171         lo_server_add_method( _server, "/nsm/client/save", "", &Client::osc_save, this );
172         lo_server_add_method( _server, "/nsm/client/session_is_loaded", "", &Client::osc_session_is_loaded, this );
173         lo_server_add_method( _server, NULL, NULL, &Client::osc_broadcast, this );
174
175         return 0;
176     }
177
178     int
179     Client::init_thread ( const char *nsm_url )
180     {
181         this->nsm_url = nsm_url;
182
183         lo_address addr = lo_address_new_from_url( nsm_url );
184         int proto = lo_address_get_protocol( addr );
185         lo_address_free( addr );
186         
187         _st = lo_server_thread_new_with_proto( NULL, proto, NULL );
188         _server = lo_server_thread_get_server( _st );
189         
190         if ( ! _server || ! _st )
191             return -1;
192
193         lo_server_thread_add_method( _st, "/error", "sis", &Client::osc_error, this );
194         lo_server_thread_add_method( _st, "/reply", "ssss", &Client::osc_announce_reply, this );
195         lo_server_thread_add_method( _st, "/nsm/client/open", "sss", &Client::osc_open, this );
196         lo_server_thread_add_method( _st, "/nsm/client/save", "", &Client::osc_save, this );
197         lo_server_thread_add_method( _st, "/nsm/client/session_is_loaded", "", &Client::osc_session_is_loaded, this );
198         lo_server_thread_add_method( _st, NULL, NULL, &Client::osc_broadcast, this );
199         
200         return 0;
201     }
202
203 /************************/
204 /* OSC Message Handlers */
205 /************************/
206
207     int
208     Client::osc_broadcast ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
209     {
210         return ((NSM::Client*)user_data)->command_broadcast( path, msg );
211     }
212
213     int
214     Client::osc_save ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
215     {
216         char *out_msg = NULL;
217         
218         int r = ((NSM::Client*)user_data)->command_save(&out_msg);
219
220         if ( r )
221             OSC_REPLY_ERR( r, ( out_msg ? out_msg : "") );
222         else
223             OSC_REPLY( "OK" );
224
225         if ( out_msg )
226             free( out_msg );
227
228          return 0;
229     }
230
231     int
232     Client::osc_open ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
233     {
234         char *out_msg = NULL;
235
236         NSM::Client *nsm = (NSM::Client*)user_data;
237         
238         nsm->_nsm_client_id = strdup( &argv[2]->s );
239         nsm->_nsm_client_path = strdup( &argv[0]->s );
240
241         int r = ((NSM::Client*)user_data)->command_open( &argv[0]->s, &argv[1]->s, &argv[2]->s, &out_msg);
242         
243         if ( r )
244             OSC_REPLY_ERR( r, ( out_msg ? out_msg : "") );
245         else
246             OSC_REPLY( "OK" );
247
248         if ( out_msg )
249             free( out_msg );
250
251         return 0;
252     }
253
254     int
255     Client::osc_session_is_loaded ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
256     {
257         NSM::Client *nsm = (NSM::Client*)user_data;
258
259         nsm->command_session_is_loaded();
260
261         return 0;
262     }
263
264     int
265     Client::osc_error ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
266     {
267         if ( strcmp( &argv[0]->s, "/nsm/server/announce" ) )
268             return -1;
269         
270         NSM::Client *nsm = (NSM::Client*)user_data;
271
272
273         nsm->nsm_is_active = false;
274         
275         nsm->command_active( nsm->nsm_is_active );
276
277         return 0;
278     }
279
280     int
281     Client::osc_announce_reply ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
282     {
283         if ( strcmp( &argv[0]->s, "/nsm/server/announce" ) )
284             return -1;
285        
286         NSM::Client *nsm = (NSM::Client*)user_data;
287
288         nsm->nsm_is_active = true;
289         nsm->_session_manager_name = strdup( &argv[2]->s );
290         nsm->nsm_addr = lo_address_new_from_url( lo_address_get_url( lo_message_get_source( msg ) ));   
291     
292         nsm->command_active( nsm->nsm_is_active );
293
294         return 0;
295     }
296 };