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