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