samer@0
|
1 /*
|
samer@0
|
2 * Copyright (C) 2009 Samer Abdallah
|
samer@0
|
3 *
|
samer@0
|
4 * This program is free software; you can redistribute it and/or modify
|
samer@0
|
5 * it under the terms of the GNU General Public License as published by
|
samer@0
|
6 * the Free Software Foundation; either version 2 of the License, or
|
samer@0
|
7 * (at your option) any later version.
|
samer@0
|
8 *
|
samer@0
|
9 * This program is distributed in the hope that it will be useful,
|
samer@0
|
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
samer@0
|
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
samer@0
|
12 * GNU General Public License for more details.
|
samer@0
|
13 *
|
samer@0
|
14 */
|
samer@0
|
15
|
samer@0
|
16 #include <SWI-Stream.h>
|
samer@0
|
17 #include <SWI-Prolog.h>
|
samer@0
|
18
|
samer@0
|
19 #include <stdio.h>
|
samer@0
|
20 #include <string.h>
|
samer@0
|
21 #include <math.h>
|
samer@0
|
22 #include <lo/lo.h>
|
samer@0
|
23
|
samer@0
|
24 // ---------------------------------------------------------------------------
|
samer@0
|
25
|
samer@0
|
26 // Reimplementation of lo_server_thread to all calls to
|
samer@0
|
27 // Prolog from the server thread.
|
samer@0
|
28
|
samer@0
|
29 typedef struct _my_server_thread {
|
samer@0
|
30 lo_server s;
|
samer@0
|
31 pthread_t thread;
|
samer@4
|
32 int timeout;
|
samer@0
|
33 volatile int active;
|
samer@0
|
34 volatile int done;
|
samer@0
|
35 } *my_server_thread;
|
samer@0
|
36
|
samer@0
|
37 int my_server_thread_start(my_server_thread st);
|
samer@0
|
38 int my_server_thread_stop(my_server_thread st);
|
samer@4
|
39 int my_server_thread_run(my_server_thread st);
|
samer@0
|
40 void my_server_thread_free(my_server_thread st);
|
samer@0
|
41 my_server_thread my_server_thread_new(const char *port, lo_err_handler err_h);
|
samer@0
|
42
|
samer@0
|
43 // ---------------------------------------------------------------------------
|
samer@0
|
44
|
samer@0
|
45 // BLOB to hold a lo_address
|
samer@0
|
46 static PL_blob_t addr_blob;
|
samer@0
|
47
|
samer@0
|
48 // BLOB to hold server thread
|
samer@0
|
49 static PL_blob_t server_blob;
|
samer@0
|
50
|
samer@0
|
51 static predicate_t call3, call5;
|
samer@0
|
52 static atom_t osc_immed;
|
samer@0
|
53 static functor_t osc_ts_2;
|
samer@0
|
54 static functor_t int_1, float_1, double_1, string_1;
|
samer@0
|
55
|
samer@0
|
56 install_t install();
|
samer@0
|
57
|
samer@0
|
58 foreign_t mk_address( term_t host, term_t port, term_t addr);
|
samer@2
|
59 foreign_t split_address( term_t addr, term_t host, term_t port);
|
samer@0
|
60 foreign_t is_address( term_t addr);
|
samer@0
|
61 foreign_t send_osc_now( term_t addr, term_t msg, term_t args);
|
samer@0
|
62 foreign_t send_osc_at( term_t addr, term_t msg, term_t args, term_t time);
|
samer@0
|
63 foreign_t send_osc_from_at( term_t serv, term_t addr, term_t msg, term_t args, term_t time);
|
samer@0
|
64 foreign_t send_timestamped( term_t addr, term_t msg, term_t args, term_t sec, term_t frac);
|
samer@0
|
65 foreign_t now( term_t sec, term_t frac);
|
samer@0
|
66 foreign_t time_to_ts( term_t time, term_t sec, term_t frac);
|
samer@0
|
67 foreign_t time_from_ts( term_t time, term_t sec, term_t frac);
|
samer@0
|
68
|
samer@0
|
69 // OSC server predicates
|
samer@0
|
70 foreign_t mk_server( term_t port, term_t server);
|
samer@0
|
71 foreign_t start_server( term_t server);
|
samer@0
|
72 foreign_t stop_server( term_t server);
|
samer@0
|
73 foreign_t del_handler( term_t server, term_t msg, term_t types);
|
samer@0
|
74 foreign_t add_handler( term_t server, term_t msg, term_t types, term_t handler);
|
samer@0
|
75 foreign_t add_handler_x( term_t server, term_t msg, term_t types, term_t handler);
|
samer@0
|
76 foreign_t run_server( term_t server);
|
samer@0
|
77
|
samer@0
|
78
|
samer@0
|
79 // BLOB functions
|
samer@0
|
80 int addr_release(atom_t a) {
|
samer@0
|
81 PL_blob_t *type;
|
samer@0
|
82 size_t len;
|
samer@0
|
83 void *p=PL_blob_data(a,&len,&type);
|
samer@0
|
84 if (p) lo_address_free(*(lo_address *)p);
|
samer@0
|
85 return TRUE;
|
samer@0
|
86 }
|
samer@0
|
87
|
samer@0
|
88 int addr_write(IOSTREAM *s, atom_t a, int flags) {
|
samer@0
|
89 PL_blob_t *type;
|
samer@0
|
90 size_t len;
|
samer@0
|
91 lo_address *p=(lo_address *)PL_blob_data(a,&len,&type);
|
samer@0
|
92 if (p) {
|
samer@0
|
93 const char *host = lo_address_get_hostname(*p);
|
samer@0
|
94 const char *port = lo_address_get_port(*p);
|
samer@0
|
95 if (host!=NULL && port!=NULL) {
|
samer@0
|
96 Sfprintf(s,"osc_address<%s:%s>",host,port);
|
samer@0
|
97 } else {
|
samer@0
|
98 Sfprintf(s,"osc_address<invalid>");
|
samer@0
|
99 }
|
samer@0
|
100 }
|
samer@0
|
101 return TRUE;
|
samer@0
|
102 }
|
samer@0
|
103
|
samer@0
|
104 int server_release(atom_t a) {
|
samer@0
|
105 PL_blob_t *type;
|
samer@0
|
106 size_t len;
|
samer@0
|
107 void *p=PL_blob_data(a,&len,&type);
|
samer@0
|
108 if (p) my_server_thread_free(*(my_server_thread *)p);
|
samer@0
|
109 return TRUE;
|
samer@0
|
110 }
|
samer@0
|
111
|
samer@0
|
112 int server_write(IOSTREAM *s, atom_t a, int flags) {
|
samer@0
|
113 PL_blob_t *type;
|
samer@0
|
114 size_t len;
|
samer@0
|
115 my_server_thread *p=(my_server_thread *)PL_blob_data(a,&len,&type);
|
samer@0
|
116 if (p) {
|
samer@0
|
117 char *url=lo_server_get_url((*p)->s);
|
samer@0
|
118 Sfprintf(s,"osc_server<%s>",url);
|
samer@0
|
119 free(url);
|
samer@0
|
120 }
|
samer@0
|
121 return TRUE;
|
samer@0
|
122 }
|
samer@0
|
123
|
samer@0
|
124 install_t install() {
|
samer@2
|
125 PL_register_foreign("osc_now", 2, (void *)now, 0);
|
samer@2
|
126 PL_register_foreign("time_to_ts", 3, (void *)time_to_ts, 0);
|
samer@2
|
127 PL_register_foreign("time_from_ts", 3, (void *)time_from_ts, 0);
|
samer@2
|
128 PL_register_foreign("osc_mk_address", 3, (void *)mk_address, 0);
|
samer@2
|
129 PL_register_foreign("osc_split_address",3, (void *)split_address, 0);
|
samer@2
|
130 PL_register_foreign("osc_is_address", 1, (void *)is_address, 0);
|
samer@2
|
131 PL_register_foreign("osc_send_now", 3, (void *)send_osc_now, 0);
|
samer@2
|
132 PL_register_foreign("osc_send_at", 4, (void *)send_osc_at, 0);
|
samer@0
|
133 PL_register_foreign("osc_send_from_at", 5, (void *)send_osc_from_at, 0);
|
samer@0
|
134 PL_register_foreign("osc_mk_server", 2, (void *)mk_server, 0);
|
samer@0
|
135 PL_register_foreign("osc_start_server", 1, (void *)start_server, 0);
|
samer@0
|
136 PL_register_foreign("osc_stop_server", 1, (void *)stop_server, 0);
|
samer@0
|
137 PL_register_foreign("osc_run_server", 1, (void *)run_server, 0);
|
samer@0
|
138 PL_register_foreign("osc_del_method", 3, (void *)del_handler, 0);
|
samer@0
|
139 PL_register_foreign("osc_add_method", 4, (void *)add_handler, 0);
|
samer@0
|
140 PL_register_foreign("osc_add_method_x", 4, (void *)add_handler_x, 0);
|
samer@0
|
141
|
samer@0
|
142 addr_blob.magic = PL_BLOB_MAGIC;
|
samer@0
|
143 addr_blob.flags = PL_BLOB_UNIQUE;
|
samer@0
|
144 addr_blob.name = "osc_address";
|
samer@0
|
145 addr_blob.acquire = 0;
|
samer@0
|
146 addr_blob.release = addr_release;
|
samer@0
|
147 addr_blob.write = addr_write;
|
samer@0
|
148 addr_blob.compare = 0;
|
samer@0
|
149
|
samer@0
|
150 server_blob.magic = PL_BLOB_MAGIC;
|
samer@0
|
151 server_blob.flags = PL_BLOB_UNIQUE;
|
samer@0
|
152 server_blob.name = "osc_server";
|
samer@0
|
153 server_blob.acquire = 0;
|
samer@0
|
154 server_blob.release = server_release;
|
samer@0
|
155 server_blob.write = server_write;
|
samer@0
|
156 server_blob.compare = 0;
|
samer@0
|
157
|
samer@0
|
158 call3 = PL_predicate("call",3,"user");
|
samer@0
|
159 call5 = PL_predicate("call",5,"user");
|
samer@0
|
160 osc_immed = PL_new_atom("osc_immed");
|
samer@0
|
161 osc_ts_2 = PL_new_functor(PL_new_atom("osc_ts"),2);
|
samer@0
|
162 int_1 = PL_new_functor(PL_new_atom("int"),1);
|
samer@0
|
163 float_1 = PL_new_functor(PL_new_atom("float"),1);
|
samer@0
|
164 double_1 = PL_new_functor(PL_new_atom("double"),1);
|
samer@0
|
165 string_1 = PL_new_functor(PL_new_atom("string"),1);
|
samer@0
|
166 }
|
samer@0
|
167
|
samer@0
|
168 // throws a Prolog exception to signal type error
|
samer@0
|
169 static int type_error(term_t actual, const char *expected)
|
samer@0
|
170 {
|
samer@0
|
171 term_t ex = PL_new_term_ref();
|
samer@0
|
172 int rc;
|
samer@0
|
173
|
samer@0
|
174 rc = PL_unify_term(ex, PL_FUNCTOR_CHARS, "error", 2,
|
samer@0
|
175 PL_FUNCTOR_CHARS, "type_error", 2,
|
samer@0
|
176 PL_CHARS, expected,
|
samer@0
|
177 PL_TERM, actual,
|
samer@0
|
178 PL_VARIABLE);
|
samer@0
|
179
|
samer@0
|
180 return PL_raise_exception(ex);
|
samer@0
|
181 }
|
samer@0
|
182
|
samer@0
|
183 static int osc_error(int errno, const char *errmsg, const char *msg)
|
samer@0
|
184 {
|
samer@0
|
185 term_t ex = PL_new_term_ref();
|
samer@0
|
186 int rc;
|
samer@0
|
187
|
samer@0
|
188 rc=PL_unify_term(ex, PL_FUNCTOR_CHARS, "error", 1,
|
samer@0
|
189 PL_FUNCTOR_CHARS, "osc_error", 3,
|
samer@0
|
190 PL_INTEGER, errno,
|
samer@0
|
191 PL_CHARS, errmsg,
|
samer@0
|
192 PL_CHARS, msg==NULL ? "none" : msg);
|
samer@0
|
193
|
samer@0
|
194 return PL_raise_exception(ex);
|
samer@0
|
195 }
|
samer@0
|
196
|
samer@0
|
197 static int arg_error(const char *type, term_t arg)
|
samer@0
|
198 {
|
samer@0
|
199 term_t ex = PL_new_term_ref();
|
samer@0
|
200 int rc;
|
samer@0
|
201
|
samer@0
|
202 rc=PL_unify_term(ex, PL_FUNCTOR_CHARS, "error", 1,
|
samer@0
|
203 PL_FUNCTOR_CHARS, "arg_error", 2,
|
samer@0
|
204 PL_CHARS, type,
|
samer@0
|
205 PL_TERM, arg);
|
samer@0
|
206
|
samer@0
|
207 return PL_raise_exception(ex);
|
samer@0
|
208 }
|
samer@0
|
209
|
samer@0
|
210 // put lo_address into a Prolog BLOB
|
samer@0
|
211 static int unify_addr(term_t addr,lo_address a) {
|
samer@0
|
212 return PL_unify_blob(addr, &a, sizeof(lo_address), &addr_blob);
|
samer@0
|
213 }
|
samer@0
|
214
|
samer@0
|
215 // get lo_address from BLOB
|
samer@0
|
216 static int get_addr(term_t addr, lo_address *a)
|
samer@0
|
217 {
|
samer@0
|
218 PL_blob_t *type;
|
samer@0
|
219 size_t len;
|
samer@0
|
220 lo_address *a1;
|
samer@0
|
221
|
samer@0
|
222 PL_get_blob(addr, (void **)&a1, &len, &type);
|
samer@0
|
223 if (type != &addr_blob) {
|
samer@0
|
224 return type_error(addr, "osc_address");
|
samer@0
|
225 } else {
|
samer@0
|
226 *a=*a1;
|
samer@0
|
227 return TRUE;
|
samer@0
|
228 }
|
samer@0
|
229 }
|
samer@0
|
230
|
samer@0
|
231 // put lo_address into a Prolog BLOB
|
samer@0
|
232 static int unify_server(term_t server,my_server_thread s) {
|
samer@0
|
233 return PL_unify_blob(server, &s, sizeof(my_server_thread), &server_blob);
|
samer@0
|
234 }
|
samer@0
|
235
|
samer@0
|
236 // get my_server_thread from BLOB
|
samer@0
|
237 static int get_server(term_t server, my_server_thread *a)
|
samer@0
|
238 {
|
samer@0
|
239 PL_blob_t *type;
|
samer@0
|
240 size_t len;
|
samer@0
|
241 my_server_thread *a1;
|
samer@0
|
242
|
samer@0
|
243 PL_get_blob(server, (void **)&a1, &len, &type);
|
samer@0
|
244 if (type != &server_blob) {
|
samer@0
|
245 return type_error(server, "osc_server");
|
samer@0
|
246 } else {
|
samer@0
|
247 *a=*a1;
|
samer@0
|
248 return TRUE;
|
samer@0
|
249 }
|
samer@0
|
250 }
|
samer@0
|
251
|
samer@0
|
252 // get Prolog (Unix) time value and convert to OSC timestamp
|
samer@0
|
253 static int get_prolog_time(term_t time, lo_timetag *ts) {
|
samer@0
|
254 double t, ft;
|
samer@0
|
255 int ok = PL_get_float(time, &t);
|
samer@0
|
256
|
samer@0
|
257 ft=floor(t);
|
samer@0
|
258 ts->sec = ((uint32_t)ft)+2208988800u;
|
samer@0
|
259 ts->frac = (uint32_t)(4294967296.0*(t-ft));
|
samer@0
|
260 return ok;
|
samer@0
|
261 }
|
samer@0
|
262
|
samer@0
|
263 static int get_timetag(term_t sec, term_t frac, lo_timetag *ts) {
|
samer@0
|
264 int64_t s, f;
|
samer@0
|
265 int ok = PL_get_int64(sec, &s) && PL_get_int64(frac, &f);
|
samer@0
|
266 ts->sec = s;
|
samer@0
|
267 ts->frac = f;
|
samer@0
|
268 return ok;
|
samer@0
|
269 }
|
samer@0
|
270
|
samer@0
|
271
|
samer@0
|
272 static int get_msg(term_t msg, char **m) {
|
samer@0
|
273 int rc=PL_get_chars(msg, m, CVT_ATOM | CVT_STRING);
|
samer@0
|
274 if (rc && strcmp(*m,"any")==0) *m=NULL;
|
samer@0
|
275 return rc;
|
samer@0
|
276 }
|
samer@0
|
277
|
samer@0
|
278 // parse a list of Prolog terms and add arguments to an OSC message
|
samer@0
|
279 static int add_msg_args(lo_message msg, term_t list)
|
samer@0
|
280 {
|
samer@0
|
281 term_t head=PL_new_term_ref();
|
samer@0
|
282
|
samer@0
|
283 // copy term ref so as not to modify original
|
samer@0
|
284 list=PL_copy_term_ref(list);
|
samer@0
|
285
|
samer@0
|
286 while (PL_get_list(list,head,list)) {
|
samer@0
|
287 atom_t name;
|
samer@0
|
288 int rc, arity;
|
samer@0
|
289 const char *type;
|
samer@0
|
290
|
samer@0
|
291 if (!PL_get_name_arity(head,&name,&arity)) return type_error(head,"term");
|
samer@0
|
292 type=PL_atom_chars(name);
|
samer@0
|
293 switch (arity) {
|
samer@0
|
294 case 1: {
|
samer@0
|
295 term_t a1=PL_new_term_ref();
|
samer@0
|
296 rc=PL_get_arg(1,head,a1); // !!!! check return value
|
samer@0
|
297
|
samer@0
|
298 if (!strcmp(type,"int")) {
|
samer@0
|
299 int x;
|
samer@0
|
300 if (!PL_get_integer(a1,&x)) return type_error(a1,"integer");
|
samer@0
|
301 lo_message_add_int32(msg,x);
|
samer@0
|
302 } else if (!strcmp(type,"double")) {
|
samer@0
|
303 double x;
|
samer@0
|
304 if (!PL_get_float(a1,&x)) return type_error(a1,"float");
|
samer@0
|
305 lo_message_add_double(msg,x);
|
samer@0
|
306 } else if (!strcmp(type,"string")) {
|
samer@0
|
307 char *x;
|
samer@0
|
308 if (!PL_get_chars(a1,&x,CVT_ATOM|CVT_STRING)) return type_error(a1,"string");
|
samer@0
|
309 lo_message_add_string(msg,x);
|
samer@0
|
310 } else if (!strcmp(type,"symbol")) {
|
samer@0
|
311 char *x;
|
samer@0
|
312 if (!PL_get_chars(a1,&x,CVT_ATOM)) return type_error(a1,"atom");
|
samer@0
|
313 lo_message_add_symbol(msg,x);
|
samer@0
|
314 } else if (!strcmp(type,"float")) {
|
samer@0
|
315 double x;
|
samer@0
|
316 if (!PL_get_float(a1,&x)) return type_error(a1,"float");
|
samer@0
|
317 lo_message_add_float(msg,(float)x);
|
samer@0
|
318 } else {
|
samer@0
|
319 return arg_error(type,head);
|
samer@0
|
320 }
|
samer@0
|
321
|
samer@0
|
322 break;
|
samer@0
|
323 }
|
samer@0
|
324 case 0: {
|
samer@0
|
325 if (!strcmp(type,"true")) lo_message_add_true(msg);
|
samer@0
|
326 else if (!strcmp(type,"false")) lo_message_add_false(msg);
|
samer@0
|
327 else if (!strcmp(type,"nil")) lo_message_add_nil(msg);
|
samer@0
|
328 else if (!strcmp(type,"inf")) lo_message_add_infinitum(msg);
|
samer@0
|
329 break;
|
samer@0
|
330 }
|
samer@0
|
331 }
|
samer@0
|
332 }
|
samer@0
|
333 if (!PL_get_nil(list)) return type_error(list,"nil");
|
samer@0
|
334 return TRUE;
|
samer@0
|
335 }
|
samer@0
|
336
|
samer@0
|
337 static int send_msg_timestamped(lo_address a, lo_timetag *ts, char *path, term_t args)
|
samer@0
|
338 {
|
samer@0
|
339 lo_message msg=lo_message_new();
|
samer@0
|
340 lo_bundle bun=lo_bundle_new(*ts);
|
samer@0
|
341
|
samer@0
|
342 if (add_msg_args(msg,args)) {
|
samer@0
|
343 int ret;
|
samer@0
|
344
|
samer@0
|
345 lo_bundle_add_message(bun,path,msg);
|
samer@0
|
346 ret = lo_send_bundle(a,bun);
|
samer@0
|
347 lo_message_free(msg);
|
samer@0
|
348 lo_bundle_free(bun);
|
samer@0
|
349 if (ret==-1) {
|
samer@0
|
350 return osc_error(lo_address_errno(a),lo_address_errstr(a),path);
|
samer@0
|
351 } else {
|
samer@0
|
352 return TRUE;
|
samer@0
|
353 }
|
samer@0
|
354 } else return FALSE;
|
samer@0
|
355 }
|
samer@0
|
356
|
samer@0
|
357 static int send_msg_timestamped_from(lo_address a, lo_server s, lo_timetag *ts, char *path, term_t args)
|
samer@0
|
358 {
|
samer@0
|
359 lo_message msg=lo_message_new();
|
samer@0
|
360 lo_bundle bun=lo_bundle_new(*ts);
|
samer@0
|
361
|
samer@0
|
362 if (add_msg_args(msg,args)) {
|
samer@0
|
363 int ret;
|
samer@0
|
364
|
samer@0
|
365 lo_bundle_add_message(bun,path,msg);
|
samer@0
|
366 ret = lo_send_bundle_from(a,s,bun);
|
samer@0
|
367 lo_message_free(msg);
|
samer@0
|
368 lo_bundle_free(bun);
|
samer@0
|
369 if (ret==-1) {
|
samer@0
|
370 return osc_error(lo_address_errno(a),lo_address_errstr(a),path);
|
samer@0
|
371 } else {
|
samer@0
|
372 return TRUE;
|
samer@0
|
373 }
|
samer@0
|
374 } else return FALSE;
|
samer@0
|
375 }
|
samer@0
|
376
|
samer@0
|
377 static int send_msg(lo_address a, char *path, term_t args)
|
samer@0
|
378 {
|
samer@0
|
379 lo_message msg=lo_message_new();
|
samer@0
|
380
|
samer@0
|
381 if (add_msg_args(msg,args)) {
|
samer@0
|
382 if (lo_send_message(a,path,msg)==-1) {
|
samer@0
|
383 lo_message_free(msg);
|
samer@0
|
384 return osc_error(lo_address_errno(a),lo_address_errstr(a),path);
|
samer@0
|
385 } else {
|
samer@0
|
386 lo_message_free(msg);
|
samer@0
|
387 return TRUE;
|
samer@0
|
388 }
|
samer@0
|
389 } else return FALSE;
|
samer@0
|
390 }
|
samer@0
|
391
|
samer@0
|
392 foreign_t mk_address(term_t host, term_t port, term_t addr) {
|
samer@0
|
393 char *h, *p;
|
samer@0
|
394
|
samer@0
|
395 if (PL_get_chars(host, &h, CVT_ATOM | CVT_STRING)) {
|
samer@0
|
396 if (PL_get_chars(port, &p, CVT_INTEGER)) {
|
samer@0
|
397 lo_address a = lo_address_new(h,p);
|
samer@0
|
398 return unify_addr(addr,a);
|
samer@0
|
399 } else {
|
samer@0
|
400 return type_error(port,"integer");
|
samer@0
|
401 }
|
samer@0
|
402 } else {
|
samer@0
|
403 return type_error(host,"atom");
|
samer@0
|
404 }
|
samer@0
|
405 }
|
samer@0
|
406
|
samer@2
|
407 foreign_t split_address(term_t addr, term_t host, term_t port) {
|
samer@2
|
408 lo_address a;
|
samer@2
|
409 const char *h, *p;
|
samer@2
|
410
|
samer@2
|
411 return get_addr(addr,&a)
|
samer@2
|
412 && (h=lo_address_get_hostname(a))!=NULL
|
samer@2
|
413 && (p=lo_address_get_port(a))!=NULL
|
samer@2
|
414 && PL_unify_atom_chars(host,h)
|
samer@2
|
415 && PL_unify_integer(port,atoi(p));
|
samer@2
|
416 }
|
samer@2
|
417
|
samer@0
|
418 foreign_t now(term_t sec, term_t frac) {
|
samer@0
|
419 lo_timetag ts;
|
samer@0
|
420 int64_t s, f;
|
samer@0
|
421
|
samer@0
|
422 lo_timetag_now(&ts);
|
samer@0
|
423 s=ts.sec; f=ts.frac;
|
samer@0
|
424 return PL_unify_int64(sec,s) && PL_unify_int64(frac,f);
|
samer@0
|
425 }
|
samer@0
|
426
|
samer@0
|
427 foreign_t time_to_ts(term_t time, term_t sec, term_t frac) {
|
samer@0
|
428 lo_timetag ts;
|
samer@0
|
429
|
samer@0
|
430 return get_prolog_time(time,&ts) &&
|
samer@0
|
431 PL_unify_int64(sec,ts.sec) &&
|
samer@0
|
432 PL_unify_int64(frac,ts.frac);
|
samer@0
|
433 }
|
samer@0
|
434
|
samer@0
|
435 foreign_t time_from_ts(term_t time, term_t sec, term_t frac) {
|
samer@0
|
436 lo_timetag ts;
|
samer@0
|
437
|
samer@0
|
438 return get_timetag(sec,frac,&ts) &&
|
samer@0
|
439 PL_unify_float(time, (double)(ts.sec-2208988800u) + ts.frac/4294967296.0);
|
samer@0
|
440 }
|
samer@0
|
441
|
samer@0
|
442
|
samer@0
|
443
|
samer@0
|
444 // set current random state structure to values in Prolog term
|
samer@0
|
445 foreign_t is_address(term_t addr) {
|
samer@0
|
446 PL_blob_t *type;
|
samer@0
|
447 return PL_is_blob(addr,&type) && type==&addr_blob;
|
samer@0
|
448 }
|
samer@0
|
449
|
samer@0
|
450 foreign_t send_osc_from_at(term_t serv, term_t addr, term_t msg, term_t args, term_t time) {
|
samer@0
|
451 my_server_thread s;
|
samer@0
|
452 lo_address a;
|
samer@0
|
453 lo_timetag ts;
|
samer@0
|
454 char *m;
|
samer@0
|
455
|
samer@0
|
456 return get_addr(addr,&a) &&
|
samer@0
|
457 get_server(serv,&s) &&
|
samer@0
|
458 get_prolog_time(time,&ts) &&
|
samer@0
|
459 get_msg(msg, &m) &&
|
samer@0
|
460 send_msg_timestamped_from(a,s->s,&ts,m,args);
|
samer@0
|
461 }
|
samer@0
|
462
|
samer@0
|
463 foreign_t send_osc_at(term_t addr, term_t msg, term_t args, term_t time) {
|
samer@0
|
464 lo_address a;
|
samer@0
|
465 lo_timetag ts;
|
samer@0
|
466 char *m;
|
samer@0
|
467
|
samer@0
|
468 return get_addr(addr,&a) &&
|
samer@0
|
469 get_prolog_time(time,&ts) &&
|
samer@0
|
470 get_msg(msg, &m) &&
|
samer@0
|
471 send_msg_timestamped(a,&ts,m,args);
|
samer@0
|
472 }
|
samer@0
|
473
|
samer@0
|
474 foreign_t send_timestamped(term_t addr, term_t msg, term_t args, term_t secs, term_t frac) {
|
samer@0
|
475 lo_address a;
|
samer@0
|
476 lo_timetag ts;
|
samer@0
|
477 char *m;
|
samer@0
|
478
|
samer@0
|
479 return get_addr(addr,&a) &&
|
samer@0
|
480 get_timetag(secs,frac,&ts) &&
|
samer@0
|
481 get_msg(msg, &m) &&
|
samer@0
|
482 send_msg_timestamped(a,&ts,m,args);
|
samer@0
|
483 }
|
samer@0
|
484
|
samer@0
|
485
|
samer@0
|
486
|
samer@0
|
487 foreign_t send_osc_now(term_t addr, term_t msg, term_t args) {
|
samer@0
|
488 lo_address a;
|
samer@0
|
489 char *m;
|
samer@0
|
490
|
samer@0
|
491 return get_addr(addr,&a) &&
|
samer@0
|
492 get_msg(msg, &m) &&
|
samer@0
|
493 send_msg(a,m,args);
|
samer@0
|
494 }
|
samer@0
|
495
|
samer@0
|
496
|
samer@0
|
497
|
samer@0
|
498 /*
|
samer@0
|
499 * Server Bits
|
samer@0
|
500 */
|
samer@0
|
501
|
samer@0
|
502 static void prolog_thread_func(void *data);
|
samer@0
|
503
|
samer@0
|
504 // parse a list of type terms and encode as a NULL terminated
|
samer@0
|
505 // string where each character encodes the type of one argument.
|
samer@0
|
506 static int get_types_list(term_t list, char *typespec, int len)
|
samer@0
|
507 {
|
samer@0
|
508 term_t head=PL_new_term_ref();
|
samer@0
|
509 int count=0;
|
samer@0
|
510
|
samer@0
|
511 // copy term ref so as not to modify original
|
samer@0
|
512 list=PL_copy_term_ref(list);
|
samer@0
|
513
|
samer@0
|
514 while (PL_get_list(list,head,list) && count<len) {
|
samer@0
|
515 atom_t name;
|
samer@0
|
516 int arity;
|
samer@0
|
517 const char *type;
|
samer@0
|
518
|
samer@0
|
519 if (!PL_get_name_arity(head,&name,&arity)) return type_error(head,"term");
|
samer@0
|
520 type=PL_atom_chars(name);
|
samer@0
|
521 switch (arity) {
|
samer@0
|
522 case 1: {
|
samer@0
|
523 if (!strcmp(type,"int")) {
|
samer@0
|
524 typespec[count++]='i';
|
samer@0
|
525 } else if (!strcmp(type,"double")) {
|
samer@0
|
526 typespec[count++]='d';
|
samer@0
|
527 } else if (!strcmp(type,"string")) {
|
samer@0
|
528 typespec[count++]='s';
|
samer@0
|
529 } else if (!strcmp(type,"symbol")) {
|
samer@0
|
530 typespec[count++]='S';
|
samer@0
|
531 } else if (!strcmp(type,"float")) {
|
samer@0
|
532 typespec[count++]='f';
|
samer@0
|
533 }
|
samer@0
|
534 break;
|
samer@0
|
535 }
|
samer@0
|
536 case 0: {
|
samer@0
|
537 if (!strcmp(type,"true")) typespec[count++]='T';
|
samer@0
|
538 else if (!strcmp(type,"false")) typespec[count++]='F';
|
samer@0
|
539 else if (!strcmp(type,"nil")) typespec[count++]='N';
|
samer@0
|
540 else if (!strcmp(type,"inf")) typespec[count++]='I';
|
samer@0
|
541 break;
|
samer@0
|
542 }
|
samer@0
|
543 }
|
samer@0
|
544 }
|
samer@0
|
545 typespec[count]=0;
|
samer@0
|
546 if (!PL_get_nil(list)) return type_error(list,"nil");
|
samer@0
|
547 return TRUE;
|
samer@0
|
548 }
|
samer@0
|
549
|
samer@0
|
550 // parse a term representing argument types - types can be a list
|
samer@0
|
551 // as accepted by get_types_list() above or the atom 'any'
|
samer@0
|
552 static int get_types(term_t types, char *buffer, int len, char **typespec)
|
samer@0
|
553 {
|
samer@0
|
554 if (PL_is_list(types)) {
|
samer@0
|
555 *typespec=buffer;
|
samer@0
|
556 return get_types_list(types,buffer,len);
|
samer@0
|
557 } else if (PL_is_atom(types)) {
|
samer@0
|
558 char *a;
|
samer@0
|
559 if (PL_get_atom_chars(types,&a) && strcmp(a,"any")==0) {
|
samer@0
|
560 *typespec=NULL; return TRUE;
|
samer@0
|
561 } else return type_error(types,"list or 'any'");
|
samer@0
|
562 } else return type_error(types,"list or 'any'");
|
samer@0
|
563 }
|
samer@0
|
564
|
samer@0
|
565 // handler server error
|
samer@0
|
566 static void server_error(int num, const char *msg, const char *path) {
|
samer@0
|
567 osc_error(num,msg,path);
|
samer@0
|
568 }
|
samer@0
|
569
|
samer@0
|
570 // handle the /plosc/stop message for the synchronous server loop
|
samer@0
|
571 // in run_stoppable_server() and hence osc_run_server/1
|
samer@0
|
572 static int stop_handler(const char *path, const char *types, lo_arg **argv,
|
samer@0
|
573 int argc, lo_message msg, void *user_data)
|
samer@0
|
574 {
|
samer@0
|
575 my_server_thread s=(my_server_thread)user_data;
|
samer@0
|
576 s->active=0;
|
samer@0
|
577 return 1;
|
samer@0
|
578 }
|
samer@0
|
579
|
samer@0
|
580 // get message arguments and unify given term with list of arg terms
|
samer@0
|
581 static int unify_msg_args(term_t list, const char *types, lo_arg **argv, int argc)
|
samer@0
|
582 {
|
samer@0
|
583 int i, rc=0;
|
samer@0
|
584 for (i=0; i<argc; i++) {
|
samer@0
|
585 term_t head=PL_new_term_ref();
|
samer@0
|
586 term_t tail=PL_new_term_ref();
|
samer@0
|
587 if (!PL_unify_list(list,head,tail)) PL_fail;
|
samer@0
|
588 switch (types[i]) {
|
samer@0
|
589 case 'i': rc=PL_unify_term(head,PL_FUNCTOR, int_1, PL_INT,argv[i]->i); break;
|
samer@0
|
590 case 'f': rc=PL_unify_term(head,PL_FUNCTOR, float_1, PL_FLOAT,(double)argv[i]->f); break;
|
samer@0
|
591 case 'd': rc=PL_unify_term(head,PL_FUNCTOR, double_1, PL_DOUBLE,argv[i]->d); break;
|
samer@0
|
592 case 's': rc=PL_unify_term(head,PL_FUNCTOR, string_1, PL_CHARS,&argv[i]->s); break;
|
samer@0
|
593 case 'h': rc=PL_unify_term(head,PL_FUNCTOR_CHARS,"int64",1,PL_INT64,argv[i]->h); break;
|
samer@0
|
594 case 'c': rc=PL_unify_term(head,PL_FUNCTOR_CHARS,"char",1,PL_INT,(int)argv[i]->c); break;
|
samer@0
|
595 case 'S': rc=PL_unify_term(head,PL_FUNCTOR_CHARS,"symbol",1,PL_CHARS,&argv[i]->S); break;
|
samer@0
|
596 case 'T': rc=PL_unify_term(head,PL_FUNCTOR_CHARS,"true",0); break;
|
samer@0
|
597 case 'F': rc=PL_unify_term(head,PL_FUNCTOR_CHARS,"false",0); break;
|
samer@0
|
598 case 'N': rc=PL_unify_term(head,PL_FUNCTOR_CHARS,"nil",0); break;
|
samer@0
|
599 case 'I': rc=PL_unify_term(head,PL_FUNCTOR_CHARS,"inf",0); break;
|
samer@0
|
600 case 'b': rc=PL_unify_term(head,PL_FUNCTOR_CHARS,"blob",0); break;
|
samer@0
|
601 case 't': rc=PL_unify_term(head,PL_FUNCTOR_CHARS,"timetag",2,
|
samer@0
|
602 PL_INT64,(int64_t)argv[i]->t.sec,
|
samer@0
|
603 PL_INT64,(int64_t)argv[i]->t.frac);
|
samer@0
|
604 break;
|
samer@0
|
605 case 'm': rc=PL_unify_term(head,PL_FUNCTOR_CHARS,"midi",4,
|
samer@0
|
606 PL_INT,(int)argv[i]->m[0], PL_INT,(int)argv[i]->m[1],
|
samer@0
|
607 PL_INT,(int)argv[i]->m[2], PL_INT,(int)argv[i]->m[3]);
|
samer@0
|
608 break;
|
samer@0
|
609 }
|
samer@0
|
610 if (!rc) PL_fail;
|
samer@0
|
611 list=tail;
|
samer@0
|
612 }
|
samer@0
|
613 return PL_unify_nil(list);
|
samer@0
|
614 }
|
samer@0
|
615
|
samer@0
|
616 // handle OSC message by calling the associated Prolog goal
|
samer@0
|
617 static int prolog_handler(const char *path, const char *types, lo_arg **argv,
|
samer@0
|
618 int argc, lo_message msg, void *user_data)
|
samer@0
|
619 {
|
samer@0
|
620 term_t goal = PL_new_term_ref();
|
samer@0
|
621 term_t term0 = PL_new_term_refs(3);
|
samer@0
|
622
|
samer@0
|
623
|
samer@0
|
624 PL_recorded((record_t)user_data,goal); // retrieve the goal term
|
samer@0
|
625 PL_put_term(term0,goal); // term_t goal encoded in user_data
|
samer@0
|
626 PL_put_atom_chars(term0+1,path);
|
samer@0
|
627
|
samer@0
|
628 return !( unify_msg_args(PL_copy_term_ref(term0+2),types,argv,argc)
|
samer@0
|
629 && PL_call_predicate(NULL,PL_Q_NORMAL,call3,term0));
|
samer@0
|
630 }
|
samer@0
|
631
|
samer@0
|
632 static int prolog_handler_x(const char *path, const char *types, lo_arg **argv,
|
samer@0
|
633 int argc, lo_message msg, void *user_data)
|
samer@0
|
634 {
|
samer@0
|
635 term_t goal = PL_new_term_ref();
|
samer@0
|
636 term_t term0 = PL_new_term_refs(5);
|
samer@3
|
637 int rc;
|
samer@0
|
638
|
samer@0
|
639 lo_timetag ts = lo_message_get_timestamp(msg);
|
samer@0
|
640 lo_address sender = lo_message_get_source(msg);
|
samer@3
|
641 lo_address sender_copy;
|
samer@3
|
642
|
samer@3
|
643 {
|
samer@3
|
644 const char *host=lo_address_get_hostname(sender);
|
samer@3
|
645 const char *port=lo_address_get_port(sender);
|
samer@3
|
646 sender_copy=lo_address_new(host,port);
|
samer@3
|
647 }
|
samer@0
|
648
|
samer@0
|
649 PL_recorded((record_t)user_data,goal); // retrieve the goal term
|
samer@0
|
650 PL_put_term(term0,goal); // term_t goal encoded in user_data
|
samer@0
|
651 PL_put_atom_chars(term0+3,path);
|
samer@0
|
652
|
samer@3
|
653
|
samer@3
|
654 if (ts.sec==0u) rc=PL_put_atom(term0+2,osc_immed);
|
samer@0
|
655 else {
|
samer@0
|
656 rc=PL_unify_term( term0+2, PL_FUNCTOR, osc_ts_2,
|
samer@0
|
657 PL_INT64, (int64_t)ts.sec,
|
samer@0
|
658 PL_INT64, (int64_t)ts.frac);
|
samer@0
|
659 }
|
samer@3
|
660
|
samer@0
|
661 // PL_put_float(term0+2, (double)(ts.sec-2208988800u) + ts.frac/4294967296.0);
|
samer@0
|
662
|
samer@0
|
663 return !( rc
|
samer@3
|
664 && unify_addr(term0+1,sender_copy)
|
samer@3
|
665 // && PL_put_atom_chars(term0+1,"orac")
|
samer@0
|
666 && unify_msg_args(PL_copy_term_ref(term0+4),types,argv,argc)
|
samer@0
|
667 && PL_call_predicate(NULL,PL_Q_NORMAL,call5,term0));
|
samer@0
|
668 }
|
samer@0
|
669
|
samer@0
|
670 /*
|
samer@0
|
671 static int generic_handler(const char *path, const char *types, lo_arg **argv,
|
samer@0
|
672 int argc, lo_message msg, void *user_data)
|
samer@0
|
673 {
|
samer@0
|
674 int i;
|
samer@0
|
675
|
samer@0
|
676 printf("path: <%s>\n", path);
|
samer@0
|
677 for (i=0; i<argc; i++) {
|
samer@0
|
678 printf("arg %d '%c' ", i, types[i]);
|
samer@0
|
679 lo_arg_pp(types[i], argv[i]);
|
samer@0
|
680 printf("\n");
|
samer@0
|
681 }
|
samer@0
|
682 printf("\n");
|
samer@0
|
683 fflush(stdout);
|
samer@0
|
684 return 1;
|
samer@0
|
685 }
|
samer@0
|
686
|
samer@0
|
687 static int verbose_prolog_handler(const char *path, const char *types, lo_arg **argv,
|
samer@0
|
688 int argc, lo_message msg, void *user_data)
|
samer@0
|
689 {
|
samer@0
|
690 generic_handler(path,types,argv,argc,msg,user_data);
|
samer@0
|
691 prolog_handler(path,types,argv,argc,msg,user_data);
|
samer@0
|
692 return 1;
|
samer@0
|
693 }
|
samer@0
|
694 */
|
samer@0
|
695
|
samer@0
|
696 // run OSC server in this thread but with an extra message handler
|
samer@0
|
697 // to allow the /plosc/stop message to terminate the loop.
|
samer@4
|
698 static int run_stoppable_server(my_server_thread s)
|
samer@0
|
699 {
|
samer@0
|
700 lo_server_add_method(s->s, "/plosc/stop", NULL, stop_handler, (void *)s);
|
samer@4
|
701 my_server_thread_run(s);
|
samer@0
|
702 lo_server_del_method(s->s,"/plosc/stop",NULL);
|
samer@0
|
703 return TRUE;
|
samer@0
|
704 }
|
samer@0
|
705
|
samer@0
|
706 foreign_t mk_server(term_t port, term_t server)
|
samer@0
|
707 {
|
samer@0
|
708 char *p;
|
samer@0
|
709
|
samer@0
|
710 if (PL_get_chars(port, &p, CVT_INTEGER)) {
|
samer@0
|
711 my_server_thread s = my_server_thread_new(p, server_error);
|
samer@0
|
712 if (s) return unify_server(server,s);
|
samer@0
|
713 else return FALSE;
|
samer@0
|
714 } else {
|
samer@0
|
715 return type_error(port,"integer");
|
samer@0
|
716 }
|
samer@0
|
717 }
|
samer@0
|
718
|
samer@0
|
719 foreign_t add_handler_x(term_t server, term_t msg, term_t types, term_t goal)
|
samer@0
|
720 {
|
samer@0
|
721 my_server_thread s;
|
samer@0
|
722 lo_method method;
|
samer@0
|
723 char *pattern, *typespec;
|
samer@0
|
724 char buffer[256]; // !! space for up to 255 arguments
|
samer@0
|
725 int rc;
|
samer@0
|
726
|
samer@0
|
727 rc = get_server(server,&s)
|
samer@0
|
728 && get_msg(msg,&pattern)
|
samer@0
|
729 && get_types(types,buffer,256,&typespec);
|
samer@0
|
730
|
samer@0
|
731 if (rc) {
|
samer@0
|
732 record_t goal_record=PL_record(goal);
|
samer@0
|
733 method = lo_server_add_method(s->s, pattern, typespec, prolog_handler_x, (void *)goal_record);
|
samer@0
|
734 }
|
samer@0
|
735 return rc;
|
samer@0
|
736 }
|
samer@0
|
737
|
samer@0
|
738 foreign_t add_handler(term_t server, term_t msg, term_t types, term_t goal)
|
samer@0
|
739 {
|
samer@0
|
740 my_server_thread s;
|
samer@0
|
741 lo_method method;
|
samer@0
|
742 char *pattern, *typespec;
|
samer@0
|
743 char buffer[256]; // !! space for up to 255 arguments
|
samer@0
|
744 int rc;
|
samer@0
|
745
|
samer@0
|
746 rc = get_server(server,&s)
|
samer@0
|
747 && get_msg(msg,&pattern)
|
samer@0
|
748 && get_types(types,buffer,256,&typespec);
|
samer@0
|
749
|
samer@0
|
750 if (rc) {
|
samer@0
|
751 record_t goal_record=PL_record(goal);
|
samer@0
|
752 method = lo_server_add_method(s->s, pattern, typespec, prolog_handler, (void *)goal_record);
|
samer@0
|
753 }
|
samer@0
|
754 return rc;
|
samer@0
|
755 }
|
samer@0
|
756
|
samer@0
|
757 foreign_t del_handler(term_t server, term_t msg, term_t types)
|
samer@0
|
758 {
|
samer@0
|
759 my_server_thread s;
|
samer@0
|
760 char *pattern, *typespec;
|
samer@0
|
761 char buffer[256]; // !! space for up to 255 arguments
|
samer@0
|
762 int rc;
|
samer@0
|
763
|
samer@0
|
764 rc = get_server(server,&s)
|
samer@0
|
765 && get_msg(msg,&pattern)
|
samer@0
|
766 && get_types(types,buffer,256,&typespec);
|
samer@0
|
767
|
samer@0
|
768 if (rc) lo_server_del_method(s->s,pattern,typespec);
|
samer@0
|
769 return rc;
|
samer@0
|
770 }
|
samer@0
|
771
|
samer@0
|
772 foreign_t start_server( term_t server)
|
samer@0
|
773 {
|
samer@0
|
774 my_server_thread s;
|
samer@0
|
775 return get_server(server,&s) && (my_server_thread_start(s)==0);
|
samer@0
|
776 }
|
samer@0
|
777
|
samer@0
|
778 foreign_t stop_server( term_t server)
|
samer@0
|
779 {
|
samer@0
|
780 my_server_thread s;
|
samer@0
|
781 return get_server(server,&s) && (my_server_thread_stop(s)==0);
|
samer@0
|
782 }
|
samer@0
|
783
|
samer@0
|
784 foreign_t run_server( term_t server)
|
samer@0
|
785 {
|
samer@0
|
786 my_server_thread s;
|
samer@0
|
787 printf("running OSC server synchronously...\n");
|
samer@4
|
788 return get_server(server,&s) && run_stoppable_server(s);
|
samer@0
|
789 }
|
samer@0
|
790
|
samer@0
|
791
|
samer@0
|
792 // -------------------------------------------------------------------------
|
samer@0
|
793 // my_server_thread implementation
|
samer@0
|
794
|
samer@0
|
795 my_server_thread my_server_thread_new(const char *port, lo_err_handler err_h)
|
samer@0
|
796 {
|
samer@0
|
797 my_server_thread st = malloc(sizeof(struct _my_server_thread));
|
samer@0
|
798 st->s = lo_server_new(port, err_h);
|
samer@4
|
799 st->timeout= 100; // will check st->active at 10Hz.
|
samer@0
|
800 st->active = 0;
|
samer@0
|
801 st->done = 0;
|
samer@0
|
802
|
samer@0
|
803 if (!st->s) {
|
samer@0
|
804 free(st);
|
samer@0
|
805 return NULL;
|
samer@0
|
806 }
|
samer@0
|
807 return st;
|
samer@0
|
808 }
|
samer@0
|
809
|
samer@0
|
810 void my_server_thread_free(my_server_thread st)
|
samer@0
|
811 {
|
samer@0
|
812 if (st) {
|
samer@0
|
813 if (st->active) {
|
samer@0
|
814 my_server_thread_stop(st);
|
samer@0
|
815 }
|
samer@0
|
816 lo_server_free(st->s);
|
samer@0
|
817 }
|
samer@0
|
818 free(st);
|
samer@0
|
819 }
|
samer@0
|
820
|
samer@0
|
821 int my_server_thread_stop(my_server_thread st)
|
samer@0
|
822 {
|
samer@0
|
823 int result;
|
samer@0
|
824
|
samer@0
|
825 if (st->active) {
|
samer@0
|
826 st->active = 0; // Signal thread to stop
|
samer@0
|
827
|
samer@0
|
828 result = pthread_join( st->thread, NULL );
|
samer@0
|
829 if (result) {
|
samer@0
|
830 fprintf(stderr,"Failed to stop thread: pthread_join(), %s",strerror(result));
|
samer@0
|
831 return -result;
|
samer@0
|
832 }
|
samer@0
|
833 }
|
samer@0
|
834
|
samer@0
|
835 return 0;
|
samer@0
|
836 }
|
samer@0
|
837
|
samer@0
|
838
|
samer@0
|
839 int my_server_thread_start(my_server_thread st)
|
samer@0
|
840 {
|
samer@0
|
841 int result;
|
samer@0
|
842
|
samer@0
|
843 if (!st->active) {
|
samer@0
|
844 st->active = 1;
|
samer@0
|
845 st->done = 0;
|
samer@0
|
846
|
samer@0
|
847 // Create the server thread
|
samer@0
|
848 result = pthread_create(&(st->thread), NULL, (void *)&prolog_thread_func, st);
|
samer@0
|
849 if (result) {
|
samer@0
|
850 fprintf(stderr, "Failed to create thread: pthread_create(), %s",
|
samer@0
|
851 strerror(result));
|
samer@0
|
852 return -result;
|
samer@0
|
853 }
|
samer@0
|
854
|
samer@0
|
855 }
|
samer@0
|
856 return 0;
|
samer@0
|
857 }
|
samer@0
|
858
|
samer@4
|
859 int my_server_thread_run(my_server_thread st)
|
samer@0
|
860 {
|
samer@4
|
861 int timeout=st->timeout;
|
samer@4
|
862
|
samer@0
|
863 st->active = 1;
|
samer@0
|
864 st->done = 0;
|
samer@0
|
865 while (st->active) {
|
samer@0
|
866 lo_server_recv_noblock(st->s, timeout);
|
samer@0
|
867 }
|
samer@0
|
868 st->done = 1;
|
samer@0
|
869 return 0;
|
samer@0
|
870 }
|
samer@0
|
871
|
samer@0
|
872 // code for the asynchronous server loop
|
samer@0
|
873 // we must create and attach a new Prolog engine to enable
|
samer@0
|
874 // calls to Prolog from this thread.
|
samer@0
|
875 static void prolog_thread_func(void *data)
|
samer@0
|
876 {
|
samer@0
|
877 my_server_thread st = (my_server_thread)data;
|
samer@0
|
878
|
samer@0
|
879 printf("OSC server started.\n");
|
samer@0
|
880 PL_thread_attach_engine(NULL);
|
samer@4
|
881 my_server_thread_run(st);
|
samer@0
|
882 PL_thread_destroy_engine();
|
samer@0
|
883 printf("OSC server stopped.\n");
|
samer@0
|
884 pthread_exit(NULL);
|
samer@0
|
885 }
|
samer@0
|
886
|