liblo  0.30
lo_cpp.h
Go to the documentation of this file.
1 
2 #ifndef _LO_CPP_H_
3 #define _LO_CPP_H_
4 
5 #include <lo/lo.h>
6 #include <lo/lo_throw.h>
7 
8 #include <functional>
9 #include <memory>
10 #include <list>
11 #include <algorithm>
12 #include <unordered_map>
13 #include <string>
14 #include <sstream>
15 #include <initializer_list>
16 
40 #define LO_ADD_METHOD_RT(ht, argtypes, args, rt, r, r1, r2) \
41  template <typename H> \
42  Method add_method(const string_type path, const string_type types, \
43  H&& h, rt* _unused=0) \
44  { \
45  std::string key(path.s() + "," + types.s()); \
46  _handlers[key].push_front( \
47  std::unique_ptr<handler>(new handler_type<r ht>(h))); \
48  lo_method m = _add_method(path, types, \
49  [](const char *path, const char *types, \
50  lo_arg **argv, int argc, void *msg, \
51  void *data)->int \
52  { \
53  r1 (*static_cast<handler_type<r ht>*>(data)) args; \
54  r2; \
55  }, _handlers[key].front().get()); \
56  _handlers[key].front()->method = m; \
57  return m; \
58  }
59 
60 #define RT_INT(argtypes) \
61  typename std::enable_if<std::is_same<decltype(h argtypes), int>::value, void>::type
62 #define RT_VOID(argtypes) \
63  typename std::enable_if<std::is_same<decltype(h argtypes), void>::value, void>::type
64 
65 #define LO_ADD_METHOD(ht, argtypes, args) \
66  LO_ADD_METHOD_RT(ht, argtypes, args, \
67  RT_INT(argtypes), int, return,); \
68  LO_ADD_METHOD_RT(ht, argtypes, args, \
69  RT_VOID(argtypes), void, , return 0)
70 
71 namespace lo {
72 
73  // Helper classes to allow polymorphism on "const char *",
74  // "std::string", and "int".
75  class string_type {
76  public:
77  string_type(const char *s=0) { _s = s; }
78  string_type(const std::string &s) { _s = s.c_str(); }
79  operator const char*() const { return _s; }
80  std::string s() const { return _s?_s:""; }
81  const char *_s;
82  };
83 
84  class num_string_type : public string_type {
85  public:
86  num_string_type(const char *s) : string_type(s) {}
87  num_string_type(const std::string &s) : string_type(s) {}
88  num_string_type(int n) { std::ostringstream ss; ss << n;
89  _p.reset(new std::string(ss.str())); _s = _p->c_str(); }
90  std::unique_ptr<std::string> _p;
91  };
92 
93  class ServerThread;
94 
96  class Method
97  {
98  public:
99  Method(lo_method m) : method(m) {}
100  operator lo_method() const
101  { return method; }
102  protected:
103  lo_method method;
104  };
105 
108  class Address
109  {
110  public:
111  Address(const string_type &host, const num_string_type &port,
112  int proto=LO_UDP)
113  { address = lo_address_new_with_proto(proto, host, port); owned=true; }
114 
115  Address(const string_type &url)
116  { address = lo_address_new_from_url(url); owned=true; }
117 
118  Address(lo_address a, bool _owned=true)
119  { address = a; owned=_owned; }
120 
121  ~Address()
122  { if (address && owned) lo_address_free(address); }
123 
124  Address& operator=(Address b) { b.swap(*this); return *this; }
125  void swap(Address& b) throw () { std::swap(this->address, b.address); }
126 
127  int ttl() const
128  { return lo_address_get_ttl(address); }
129 
130  void set_ttl(int ttl)
131  { lo_address_set_ttl(address, ttl); }
132 
133  int send(const string_type &path) const
134  { return lo_send(address, path, ""); }
135 
136  // In these functions we append "$$" to the type string, which
137  // simply instructs lo_message_add_varargs() not to use
138  // LO_MARKER checking at the end of the argument list.
139  int send(const string_type &path, const string_type type, ...) const
140  {
141  va_list q;
142  va_start(q, type);
144  std::string t = type.s() + "$$";
145  lo_message_add_varargs(m, t.c_str(), q);
146  int r = lo_send_message(address, path, m);
147  lo_message_free(m);
148  return r;
149  }
150 
151  int send(lo_timetag ts, const string_type &path,
152  const string_type type, ...) const
153  {
154  va_list q;
155  va_start(q, type);
157  std::string t = std::string(type) + "$$";
158  lo_message_add_varargs(m, t.c_str(), q);
159  lo_bundle b = lo_bundle_new(ts);
160  lo_bundle_add_message(b, path, m);
161  int r = lo_send_bundle(address, b);
163  return r;
164  }
165 
166  int send(const string_type &path, lo_message m) const
167  { return lo_send_message(address, path, m); }
168 
169  int send(lo_bundle b)
170  { return lo_send_bundle(address, b); }
171 
172  int send_from(lo::ServerThread &from, const string_type &path,
173  const string_type type, ...) const;
174 
175  int send_from(lo_server from, const string_type &path,
176  const string_type type, ...) const
177  {
178  va_list q;
179  va_start(q, type);
181  std::string t = std::string(type) + "$$";
182  lo_message_add_varargs(m, t.c_str(), q);
183  int r = lo_send_message_from(address, from, path, m);
184  lo_message_free(m);
185  return r;
186  }
187 
188  int send_from(lo_server from, lo_timetag ts,
189  const string_type &path,
190  const string_type type, ...) const
191  {
192  va_list q;
193  va_start(q, type);
195  std::string t = std::string(type) + "$$";
196  lo_message_add_varargs(m, t.c_str(), q);
197  lo_bundle b = lo_bundle_new(ts);
198  lo_bundle_add_message(b, path, m);
199  int r = lo_send_bundle_from(address, from, b);
201  return r;
202  }
203 
204  int send_from(lo_server from, const string_type &path, lo_message m) const
205  { return lo_send_message_from(address, from, path, m); }
206 
207  int send_from(lo::ServerThread &from, lo_bundle b) const;
208 
209  int send_from(lo_server from, lo_bundle b) const
210  { return lo_send_bundle_from(address, from, b); }
211 
212  int get_errno() const
213  { return lo_address_errno(address); }
214 
215  std::string errstr() const
216  { auto s(lo_address_errstr(address)); return std::string(s?s:""); }
217 
218  std::string hostname() const
219  { auto s(lo_address_get_hostname(address)); return std::string(s?s:""); }
220 
221  std::string port() const
222  { auto s(lo_address_get_port(address)); return std::string(s?s:""); }
223 
224  int protocol() const
225  { return lo_address_get_protocol(address); }
226 
227  std::string url() const
228  {
229  char* s(lo_address_get_url(address));
230  std::string result(s?s:"");
231  free(s);
232  return result;
233  }
234 
235  std::string iface() const
236  { auto s(lo_address_get_iface(address)); return std::string(s?s:""); }
237 
238  void set_iface(const string_type &iface, const string_type &ip)
239  { lo_address_set_iface(address, iface, ip); }
240 
241  int set_tcp_nodelay(int enable)
242  { return lo_address_set_tcp_nodelay(address, enable); }
243 
244  int set_stream_slip(int enable)
245  { return lo_address_set_stream_slip(address, enable); }
246 
247  operator lo_address() const
248  { return address; }
249 
250  protected:
251  lo_address address;
252  bool owned;
253  };
254 
256  class Message
257  {
258  public:
259  Message()
260  : message(lo_message_new()) { lo_message_incref(message); }
261 
263  : message(m) { if (m) { lo_message_incref(m); } }
264 
265  Message(const Message &m)
266  : message(m.message) { if (m.message)
267  lo_message_incref(m.message); }
268 
269  Message(const string_type types, ...)
270  {
271  message = lo_message_new();
272  lo_message_incref(message);
273  va_list q;
274  va_start(q, types);
275  std::string t(std::string(types)+"$$");
276  add_varargs(t.c_str(), q);
277  }
278 
279  ~Message()
280  { if (message) lo_message_free(message); }
281 
282  Message& operator=(Message m) { m.swap(*this); return *this; }
283  void swap(Message& m) throw () { std::swap(this->message, m.message); }
284 
285  int add(const string_type types, ...)
286  {
287  va_list q;
288  va_start(q, types);
289  std::string t(std::string(types)+"$$");
290  return add_varargs(t.c_str(), q);
291  }
292 
293  int add_varargs(const string_type &types, va_list ap)
294  { return lo_message_add_varargs(message, types, ap); }
295 
296  int add_int32(int32_t a)
297  { return lo_message_add_int32(message, a); }
298 
299  int add_float(float a)
300  { return lo_message_add_float(message, a); }
301 
302  int add_string(const string_type &a)
303  { return lo_message_add_string(message, a); }
304 
305  int add_blob(lo_blob a)
306  { return lo_message_add_blob(message, a); }
307 
308  int add_int64(int64_t a)
309  { return lo_message_add_int64(message, a); }
310 
311  int add_timetag(lo_timetag a)
312  { return lo_message_add_timetag(message, a); }
313 
314  int add_double(double a)
315  { return lo_message_add_double(message, a); }
316 
317  int add_symbol(const string_type &a)
318  { return lo_message_add_symbol(message, a); }
319 
320  int add_char(char a)
321  { return lo_message_add_char(message, a); }
322 
323  int add_midi(uint8_t a[4])
324  { return lo_message_add_midi(message, a); }
325 
326  int add_bool(bool b)
327  { if (b)
328  return lo_message_add_true(message);
329  else
330  return lo_message_add_false(message); }
331 
332  int add_true()
333  { return lo_message_add_true(message); }
334 
335  int add_false()
336  { return lo_message_add_false(message); }
337 
338  int add_nil()
339  { return lo_message_add_nil(message); }
340 
341  int add_infinitum()
342  { return lo_message_add_infinitum(message); }
343 
344  // Note, for polymorphic versions of "add", below, we can't do
345  // this for "string" or "symbol" types, since it is ambiguous
346  // with "add(types, ...)" above.
347 
348  int add(int32_t a)
349  { return lo_message_add_int32(message, a); }
350 
351  int add(float a)
352  { return lo_message_add_float(message, a); }
353 
354  int add(lo_blob a)
355  { return lo_message_add_blob(message, a); }
356 
357  int add(int64_t a)
358  { return lo_message_add_int64(message, a); }
359 
360  int add(lo_timetag a)
361  { return lo_message_add_timetag(message, a); }
362 
363  int add(double a)
364  { return lo_message_add_double(message, a); }
365 
366  int add(char a)
367  { return lo_message_add_char(message, a); }
368 
369  int add(uint8_t a[4])
370  { return lo_message_add_midi(message, a); }
371 
372  int add(bool b)
373  { if (b)
374  return lo_message_add_true(message);
375  else
376  return lo_message_add_false(message); }
377 
378  Address source() const
379  { return Address(lo_message_get_source(message), false); }
380 
381  lo_timetag timestamp() const
382  { return lo_message_get_timestamp(message); }
383 
384  std::string types() const
385  { auto s(lo_message_get_types(message)); return std::string(s?s:""); }
386 
387  int argc() const
388  { return lo_message_get_argc(message); }
389 
390  lo_arg **argv() const
391  { return lo_message_get_argv(message); }
392 
393  size_t length(const string_type &path) const
394  { return lo_message_length(message, path); }
395 
396  void *serialise(const string_type &path, void *to, size_t *size) const
397  { return lo_message_serialise(message, path, to, size); }
398 
399  typedef std::pair<int, Message> maybe;
400 
401  static
402  maybe deserialise(void *data, size_t size)
403  { int result = 0;
404  lo_message m = lo_message_deserialise(data, size, &result);
405  return maybe(result, m); }
406 
407  void print() const
408  { lo_message_pp(message); }
409 
410  lo::Message clone() const
411  { return lo::Message(lo_message_clone(message)); }
412 
413  operator lo_message() const
414  { return message; }
415 
416  protected:
417  lo_message message;
418  };
419 
421  class Server
422  {
423  public:
425  Server(lo_server s) : server(s) {}
426 
428  template <typename E>
429  Server(const num_string_type &port, E&& e)
430  : Server(lo_server_new(port,
431  [](int num, const char *msg, const char *where){
432  auto h = static_cast<handler_error*>(lo_error_get_context());
433  if (h) (*h)(num, msg, where);
434  }))
435  {
436  if (server) {
437  lo_server_set_error_context(server,
438  (_error_handler = std::unique_ptr<handler>(
439  new handler_error(e))).get());
440  }
441  }
442 
444  template <typename E>
445  Server(const num_string_type &port, int proto, E&& e=0)
446  : Server(lo_server_new_with_proto(port, proto,
447  [](int num, const char *msg, const char *where){
448  auto h = static_cast<handler_error*>(lo_error_get_context());
449  (*h)(num, msg, where);
450  }))
451  {
452  if (server) {
453  lo_server_set_error_context(server,
454  (_error_handler = std::unique_ptr<handler>(
455  new handler_error(e))).get());
456  }
457  }
458 
461  template <typename E>
462  Server(const string_type &group, const num_string_type &port,
463  const string_type &iface=0, const string_type &ip=0, E&& e=0)
464  : Server((!iface._s || !ip._s)
465  ? lo_server_new_multicast_iface(group, port, iface, ip,
466  [](int num, const char *msg, const char *where){
467  auto h = static_cast<handler_error*>(lo_error_get_context());
468  (*h)(num, msg, where);
469  })
470  : lo_server_new_multicast(group, port,
471  [](int num, const char *msg, const char *where){
472  auto h = static_cast<handler_error*>(lo_error_get_context());
473  (*h)(num, msg, where);
474  }))
475  {
476  if (server) {
477  lo_server_set_error_context(server,
478  (_error_handler = std::unique_ptr<handler>(
479  new handler_error(e))).get());
480  }
481  }
482 
484  Server(const num_string_type &port, lo_err_handler err_h=0)
485  : Server(lo_server_new(port, err_h)) {}
486 
488  Server(const num_string_type &port, int proto, lo_err_handler err_h=0)
489  : Server(lo_server_new_with_proto(port, proto, err_h)) {}
490 
493  Server(const string_type &group, const num_string_type &port,
494  const string_type &iface="", const string_type &ip="", lo_err_handler err_h=0)
495  : Server((iface._s || ip._s)
496  ? lo_server_new_multicast_iface(group, port,
497  iface, ip, err_h)
498  : lo_server_new_multicast(group, port, err_h)) {}
499 
501  virtual ~Server()
502  { if (server) lo_server_free(server); }
503 
504  bool is_valid() const { return server!=nullptr; }
505 
506  // Regular old liblo method handlers
507 
510  Method add_method(const string_type &path, const string_type &types,
511  lo_method_handler h, void *data) const
512  { return _add_method(path, types, h, data); }
513 
514  // Alternative callback prototypes
515 
518  LO_ADD_METHOD( (const char*, const char*, lo_arg**, int),
519  ((char*)0, (char*)0, (lo_arg**)0, (int)0),
520  (path, types, argv, argc) );
521 
524  LO_ADD_METHOD( (const char*, lo_arg**, int),
525  ((char*)0, (lo_arg**)0, (int)0),
526  (types, argv, argc) );
527  LO_ADD_METHOD( (const char*, lo_arg**, int, const Message&),
528  ((char*)0, (lo_arg**)0, (int)0, Message((lo_message)0)),
529  (types, argv, argc, Message(msg)) );
530  LO_ADD_METHOD( (const char*, const Message&),
531  ((char*)0, Message((lo_message)0)),
532  (path, Message(msg)) );
533  LO_ADD_METHOD( (lo_arg**, int), ((lo_arg**)0, (int)0), (argv, argc) )
534  LO_ADD_METHOD( (lo_arg**, int, const Message& ),
535  ((lo_arg**)0, (int)0, Message((lo_message)0)),
536  (argv, argc, Message(msg)) );
537  LO_ADD_METHOD( (const Message&),
538  (Message((lo_message)0)),
539  (Message(msg)) );
540  LO_ADD_METHOD( (), (), () );
541 
542  int del_method(const string_type &path, const string_type &typespec)
543  {
544  _handlers.erase(path.s() + "," + typespec.s());
545  lo_server_del_method(server, path, typespec);
546  return 0;
547  }
548 
549  int del_method(const lo_method& m)
550  {
551  for (auto &i : _handlers) {
552  std::remove_if(i.second.begin(), i.second.end(),
553  [&](std::unique_ptr<handler>& h){return h->method == m;});
554  }
555  return lo_server_del_lo_method(server, m);
556  }
557 
558  int dispatch_data(void *data, size_t size)
559  { return lo_server_dispatch_data(server, data, size); }
560 
561  int wait(int timeout)
562  { return lo_server_wait(server, timeout); }
563 
564  int recv()
565  { return lo_server_recv(server); }
566 
567  int recv(int timeout)
568  { return lo_server_recv_noblock(server, timeout); }
569 
570  int add_bundle_handlers(lo_bundle_start_handler sh,
572  void *user_data)
573  {
574  return lo_server_add_bundle_handlers(server, sh, eh, user_data);
575  }
576 
577  template <typename S, typename E>
578  int add_bundle_handlers(S&& s, E&& e)
579  {
580  _bundle_handlers.reset(new std::pair<handler_bundle_start,
581  handler_bundle_end>(
582  handler_bundle_start(s),
583  handler_bundle_end(e)));
585  server,
586  [](lo_timetag time, void *user_data)->int{
587  auto h = (std::pair<handler_bundle_start,
588  handler_bundle_end>*) user_data;
589  h->first(time);
590  return 0;
591  },
592  [](void *user_data)->int{
593  auto h = (std::pair<handler_bundle_start,
594  handler_bundle_end>*) user_data;
595  h->second();
596  return 0;
597  },
598  _bundle_handlers.get());
599  }
600 
601  int socket_fd() const
602  { return lo_server_get_socket_fd(server); }
603 
604  int port() const
605  { return lo_server_get_port(server); }
606 
607  int protocol() const
608  { return lo_server_get_protocol(server); }
609 
610  std::string url() const
611  {
612  char* s(lo_server_get_url(server));
613  std::string result(s?s:"");
614  free(s);
615  return result;
616  }
617 
618  int enable_queue(int queue_enabled,
619  int dispatch_remaining=1)
620  { return lo_server_enable_queue(server,
621  queue_enabled,
622  dispatch_remaining); }
623 
624  int events_pending() const
625  { return lo_server_events_pending(server); }
626 
627  double next_event_delay() const
628  { return lo_server_next_event_delay(server); }
629 
630  operator lo_server() const
631  { return server; }
632 
633  protected:
634  lo_server server;
635 
636  friend class ServerThread;
637 
638  struct handler { Method method; handler(Method m):method(m){} };
639  template <typename T>
640  class handler_type : public handler, public std::function<T> {
641  public: template<typename H>handler_type(H&& h, Method m=0)
642  : handler(m), std::function<T>(h) {}
643  };
644  typedef handler_type<void(int, const char *, const char *)> handler_error;
645  typedef handler_type<void(int, const std::string&, const std::string&)> handler_error_s;
646  typedef handler_type<void(lo_timetag)> handler_bundle_start;
647  typedef handler_type<void()> handler_bundle_end;
648 
649  // Keep std::functions here so they are freed correctly
650  std::unordered_map<std::string,
651  std::list<std::unique_ptr<handler>>> _handlers;
652  std::unique_ptr<handler> _error_handler;
653  std::unique_ptr<std::pair<handler_bundle_start,
654  handler_bundle_end>> _bundle_handlers;
655 
656  virtual Method _add_method(const char *path, const char *types,
657  lo_method_handler h, void *data) const
658  {
659  return lo_server_add_method(server, path, types, h, data);
660  }
661  };
662 
664  class ServerThread : public Server
665  {
666  public:
667  ServerThread(const num_string_type &port, lo_err_handler err_h=0)
668  : Server(0)
669  { server_thread = lo_server_thread_new(port, err_h);
670  if (server_thread)
671  server = lo_server_thread_get_server(server_thread); }
672 
673  template <typename E>
674  ServerThread(const num_string_type &port, E&& e)
675  : Server(0)
676  {
677  server_thread = lo_server_thread_new(port,
678  [](int num, const char *msg, const char *where){
679  auto h = static_cast<handler_error*>(lo_error_get_context());
680  // TODO: Can't call "e" yet since error context is not yet
681  // provided, port unavailable errors will not be reported!
682  if (h) (*h)(num, msg, where);});
683  if (server_thread) {
684  server = lo_server_thread_get_server(server_thread);
685  auto h = new handler_error(e);
686  _error_handler.reset(h);
687  lo_server_thread_set_error_context(server_thread, h);
688  lo_server_set_error_context(server,
689  (_error_handler = std::unique_ptr<handler>(
690  new handler_error(e))).get());
691  }
692  }
693 
694  ServerThread(const num_string_type &port, int proto, lo_err_handler err_h)
695  : Server(0)
696  { server_thread = lo_server_thread_new_with_proto(port, proto, err_h);
697  if (server_thread)
698  server = lo_server_thread_get_server(server_thread); }
699 
700  template <typename E>
701  ServerThread(const num_string_type &port, int proto, E&& e)
702  : Server(0)
703  {
704  server_thread = lo_server_thread_new_with_proto(port, proto,
705  [](int num, const char *msg, const char *where){
706  auto h = static_cast<handler_error*>(lo_error_get_context());
707  // TODO: Can't call "e" yet since error context is not yet
708  // provided, port unavailable errors will not be reported!
709  if (h) (*h)(num, msg, where);});
710  if (server_thread) {
711  server = lo_server_thread_get_server(server_thread);
712  auto h = new handler_error(e);
713  _error_handler.reset(h);
714  lo_server_thread_set_error_context(server_thread, h);
715  lo_server_set_error_context(server,
716  (_error_handler = std::unique_ptr<handler>(
717  new handler_error(e))).get());
718  }
719  }
720 
721  ServerThread(const string_type &group, const num_string_type &port,
722  const string_type &iface, const string_type &ip,
723  lo_err_handler err_h=0) : Server(0)
724  { if (iface._s || ip._s)
725  server_thread = lo_server_thread_new_multicast_iface(group, port,
726  iface, ip, err_h);
727  else
728  server_thread = lo_server_thread_new_multicast(group, port, err_h);
729  if (server_thread)
730  server = lo_server_thread_get_server(server_thread); }
731 
732  virtual ~ServerThread()
733  { server = 0;
734  if (server_thread) lo_server_thread_free(server_thread); }
735 
736  template <typename I, typename C>
737  auto set_callbacks(I&& init, C&& cleanup)
738  -> typename std::enable_if<
739  std::is_same<decltype(init()), int>::value, void>::type
740  {
741  if (server_thread) {
742  _cb_handlers.reset(new handler_cb_pair(init, cleanup));
743  lo_server_thread_set_callbacks(server_thread,
744  [](lo_server_thread s, void *c){
745  auto cb = (handler_cb_pair*)c;
746  return (cb->first)();
747  },
748  [](lo_server_thread s, void *c){
749  auto cb = (handler_cb_pair*)c;
750  (cb->second)();
751  }, _cb_handlers.get());
752  }
753  }
754 
755  template <typename I, typename C>
756  auto set_callbacks(I&& init, C&& cleanup)
757  -> typename std::enable_if<
758  std::is_same<decltype(init()), void>::value, void>::type
759  {
760  if (server_thread) {
761  _cb_handlers.reset(
762  (handler_cb_pair*)new handler_cb_pair_void(init, cleanup));
763  lo_server_thread_set_callbacks(server_thread,
764  [](lo_server_thread s, void *c){
765  auto cb = (handler_cb_pair_void*)c;
766  (cb->first)(); return 0;
767  },
768  [](lo_server_thread s, void *c){
769  auto cb = (handler_cb_pair_void*)c;
770  (cb->second)();
771  }, _cb_handlers.get());
772  }
773  }
774 
775  void start() { lo_server_thread_start(server_thread); }
776  void stop() { lo_server_thread_stop(server_thread); }
777 
778  operator lo_server_thread() const
779  { return server_thread; }
780 
781  protected:
782  lo_server_thread server_thread;
783 
784  typedef std::pair<handler_type<int()>,handler_type<void()>> handler_cb_pair;
785  typedef std::pair<handler_type<void()>,handler_type<void()>> handler_cb_pair_void;
786  std::unique_ptr<handler_cb_pair> _cb_handlers;
787 
788  // Regular old liblo method handlers
789  virtual Method _add_method(const char *path, const char *types,
790  lo_method_handler h, void *data) const
791  {
792  return lo_server_thread_add_method(server_thread, path, types, h, data);
793  }
794  };
795 
796  // This function needed since lo::ServerThread doesn't
797  // properly auto-upcast to lo::Server -> lo_server. (Because
798  // both lo_server and lo_serverthread are typedef'd as void*)
799  inline
800  int Address::send_from(lo::ServerThread &from, const string_type &path,
801  const string_type type, ...) const
802  {
803  va_list q;
804  va_start(q, type);
805  lo_message m = lo_message_new();
806  std::string t = std::string(type) + "$$";
807  lo_message_add_varargs(m, t.c_str(), q);
808  lo_server s = static_cast<lo::Server&>(from);
809  int r = lo_send_message_from(address, s, path, m);
810  lo_message_free(m);
811  return r;
812  }
813 
814  inline
815  int Address::send_from(lo::ServerThread &from, lo_bundle b) const
816  {
817  lo_server s = static_cast<lo::Server&>(from);
818  return lo_send_bundle_from(address, s, b);
819  }
820 
822  class Blob
823  {
824  public:
825  Blob(int32_t size, const void *data=0)
826  : blob(lo_blob_new(size, data)) {}
827 
828  template <typename T>
829  Blob(const T &t)
830  : blob(lo_blob_new(t.size()*sizeof(t[0]), &t[0])) {}
831 
832  virtual ~Blob()
833  { lo_blob_free(blob); }
834 
835  Blob& operator=(Blob b) { b.swap(*this); return *this; }
836  void swap(Blob& b) throw () { std::swap(this->blob, b.blob); }
837 
838  uint32_t datasize() const
839  { return lo_blob_datasize(blob); }
840 
841  void *dataptr() const
842  { return lo_blob_dataptr(blob); }
843 
844  uint32_t size() const
845  { return lo_blobsize(blob); }
846 
847  operator lo_blob() const
848  { return blob; };
849 
850  protected:
851  lo_blob blob;
852  };
853 
855  struct PathMsg
856  {
857  PathMsg() {}
858  PathMsg(const string_type _path, const Message& _msg)
859  : path(_path), msg(_msg) {}
860  std::string path;
861  Message msg;
862  };
863 
865  class Bundle
866  {
867  public:
868  template <typename T>
869  struct ElementT
870  {
871  ElementT()
872  : type((lo_element_type)0), pm("", 0), bundle((lo_bundle)0) {}
873  ElementT(const string_type _path, const Message& _msg)
874  : type(LO_ELEMENT_MESSAGE),
875  pm(PathMsg(_path, _msg)),
876  bundle((lo_bundle)0) {}
877  ElementT(const T& _bundle)
878  : type(LO_ELEMENT_BUNDLE), pm("", 0), bundle(_bundle) {}
879  lo_element_type type;
880  PathMsg pm;
881  T bundle;
882  };
883  typedef ElementT<Bundle> Element;
884 
885  Bundle() { bundle = lo_bundle_new(LO_TT_IMMEDIATE); lo_bundle_incref(bundle); }
886 
887  Bundle(lo_timetag tt)
888  : bundle(lo_bundle_new(tt)) { lo_bundle_incref(bundle); }
889 
890  Bundle(lo_bundle b)
891  : bundle(b) { if (b) { lo_bundle_incref(b); } }
892 
893  Bundle(const string_type &path, lo_message m,
895  : bundle(lo_bundle_new(tt))
896  {
897  lo_bundle_incref(bundle);
898  lo_bundle_add_message(bundle, path, m);
899  }
900 
901  Bundle(const std::initializer_list<Element> &elements,
903  : bundle(lo_bundle_new(tt))
904  {
905  lo_bundle_incref(bundle);
906  for (auto const &e : elements) {
907  if (e.type == LO_ELEMENT_MESSAGE) {
908  lo_bundle_add_message(bundle, e.pm.path.c_str(), e.pm.msg);
909  }
910  else if (e.type == LO_ELEMENT_BUNDLE) {
911  lo_bundle_add_bundle(bundle, e.bundle);
912  }
913  }
914  }
915 
916  Bundle(const Bundle &b)
917  : Bundle((lo_bundle)b) {}
918 
919  ~Bundle()
920  { if (bundle) lo_bundle_free_recursive(bundle); }
921 
922  Bundle& operator=(Bundle b) { b.swap(*this); return *this; }
923  void swap(Bundle& b) throw () { std::swap(this->bundle, b.bundle); }
924 
925  int add(const string_type &path, lo_message m)
926  { return lo_bundle_add_message(bundle, path, m); }
927 
928  int add(const lo_bundle b)
929  { return lo_bundle_add_bundle(bundle, b); }
930 
931  size_t length() const
932  { return lo_bundle_length(bundle); }
933 
934  unsigned int count() const
935  { return lo_bundle_count(bundle); }
936 
937  lo_message get_message(int index, const char **path=0) const
938  { return lo_bundle_get_message(bundle, index, path); }
939 
940  Message get_message(int index, std::string &path) const
941  { const char *p;
942  lo_message m=lo_bundle_get_message(bundle, index, &p);
943  path = p?p:0;
944  return Message(m); }
945 
946  PathMsg get_message(int index) const
947  { const char *p;
948  lo_message m = lo_bundle_get_message(bundle, index, &p);
949  return PathMsg(p?p:0, m); }
950 
951  Bundle get_bundle(int index) const
952  { return lo_bundle_get_bundle(bundle, index); }
953 
954  Element get_element(int index, const char **path=0) const
955  {
956  switch (lo_bundle_get_type(bundle, index)) {
957  case LO_ELEMENT_MESSAGE: {
958  const char *p;
959  lo_message m = lo_bundle_get_message(bundle, index, &p);
960  return Element(p, m);
961  }
962  case LO_ELEMENT_BUNDLE:
963  return Element(lo_bundle_get_bundle(bundle, index));
964  default:
965  return Element();
966  }
967  }
968 
969  lo_timetag timestamp()
970  { return lo_bundle_get_timestamp(bundle); }
971 
972  void *serialise(void *to, size_t *size) const
973  { return lo_bundle_serialise(bundle, to, size); }
974 
975  void print() const
976  { lo_bundle_pp(bundle); }
977 
978  operator lo_bundle() const
979  { return bundle; }
980 
981  protected:
982  lo_bundle bundle;
983  };
984 
986  inline std::string version() {
987  char str[32];
988  lo_version(str, 32, 0, 0, 0, 0, 0, 0, 0);
989  return std::string(str);
990  }
991 
993  inline lo_timetag now() { lo_timetag tt; lo_timetag_now(&tt); return tt; }
994 
996  inline lo_timetag immediate() { return LO_TT_IMMEDIATE; }
997 };
998 
1001 #endif // _LO_CPP_H_
Class representing an OSC method, proxy for lo_method.
Definition: lo_cpp.h:96
lo_server lo_server_new_multicast(const char *group, const char *port, lo_err_handler err_h)
Create a new server instance, and join a UDP multicast group.
lo_message lo_bundle_get_message(lo_bundle b, int index, const char **path)
Gets a message contained within a bundle.
Class representing an OSC message, proxy for lo_message.
Definition: lo_cpp.h:256
void lo_bundle_free_messages(lo_bundle b)
Obsolete, use lo_bundle_free_recursive instead.
int lo_message_add_char(lo_message m, char a)
Append a data item and typechar of the specified type to a message. See lo_message_add_int32() for de...
lo_timetag lo_bundle_get_timestamp(lo_bundle b)
Get the timestamp associated with a bundle.
lo_timetag lo_message_get_timestamp(lo_message m)
Returns the timestamp (lo_timetag *) of a bundled incoming message.
int lo_message_add_nil(lo_message m)
Append a data item and typechar of the specified type to a message. See lo_message_add_int32() for de...
lo_server_thread lo_server_thread_new(const char *port, lo_err_handler err_h)
Create a new server thread to handle incoming OSC messages.
int lo_message_add_blob(lo_message m, lo_blob a)
Append a data item and typechar of the specified type to a message. See lo_message_add_int32() for de...
lo_message lo_message_clone(lo_message m)
Create a new lo_message object by cloning an already existing one.
lo_server lo_server_new(const char *port, lo_err_handler err_h)
Create a new server instance.
void lo_server_thread_set_callbacks(lo_server_thread st, lo_server_thread_init_callback init, lo_server_thread_cleanup_callback cleanup, void *user_data)
Set an init and/or a cleanup function to the specifed server thread.
Class representing an OSC blob, proxy for lo_blob.
Definition: lo_cpp.h:822
int lo_message_get_argc(lo_message m)
Return the message argument count.
Union used to read values from incoming messages.
Definition: lo_osc_types.h:104
int lo_server_add_bundle_handlers(lo_server s, lo_bundle_start_handler sh, lo_bundle_end_handler eh, void *user_data)
Add bundle notification handlers to the specified server.
lo_element_type
An enumeration of bundle element types liblo can handle.
Definition: lo_osc_types.h:48
lo_element_type lo_bundle_get_type(lo_bundle b, int index)
Gets the element type contained within a bundle.
int lo_bundle_add_message(lo_bundle b, const char *path, lo_message m)
Adds an OSC message to an existing bundle.
void lo_bundle_incref(lo_bundle b)
Add one to a bundle's reference count.
lo_server_thread lo_server_thread_new_multicast_iface(const char *group, const char *port, const char *iface, const char *ip, lo_err_handler err_h)
Create a new server thread instance, and join a UDP multicast group, optionally specifying which netw...
const char * lo_address_errstr(lo_address a)
Return the error string from the last failed lo_send() or lo_address_new() call.
int lo_server_enable_queue(lo_server s, int queue_enabled, int dispatch_remaining)
Toggle event queue. If queueing is enabled, timetagged messages that are sent in advance of the curre...
int lo_send_bundle(lo_address targ, lo_bundle b)
Send a lo_bundle object to address targ.
A structure to store OSC TimeTag values.
Definition: lo_osc_types.h:35
int lo_message_add_timetag(lo_message m, lo_timetag a)
Append a data item and typechar of the specified type to a message. See lo_message_add_int32() for de...
int lo_server_thread_start(lo_server_thread st)
Start the server thread.
int lo_message_add_string(lo_message m, const char *a)
Append a data item and typechar of the specified type to a message. See lo_message_add_int32() for de...
Method add_method(const string_type &path, const string_type &types, lo_method_handler h, void *data) const
Definition: lo_cpp.h:510
int lo_message_add_infinitum(lo_message m)
Append a data item and typechar of the specified type to a message. See lo_message_add_int32() for de...
void lo_server_del_method(lo_server s, const char *path, const char *typespec)
Delete an OSC method from the specified server.
Server(const num_string_type &port, int proto, E &&e=0)
Definition: lo_cpp.h:445
Class representing a server thread, proxy for lo_server_thread.
Definition: lo_cpp.h:664
lo_address lo_message_get_source(lo_message m)
Returns the source (lo_address) of an incoming message.
int lo_send_bundle_from(lo_address targ, lo_server serv, lo_bundle b)
Send a lo_bundle object to address targ from address of serv.
int lo_send_message_from(lo_address targ, lo_server serv, const char *path, lo_message msg)
Send a lo_message object to target targ from address of serv.
void lo_blob_free(lo_blob b)
Free the memory taken by a blob.
void lo_message_free(lo_message m)
Free memory allocated by lo_message_new() and any subsequent lo_message_add_int32 lo_message_add*() c...
Server(const num_string_type &port, int proto, lo_err_handler err_h=0)
Definition: lo_cpp.h:488
lo_bundle lo_bundle_new(lo_timetag tt)
Create a new bundle object.
void(* lo_err_handler)(int num, const char *msg, const char *where)
A callback function to receive notification of an error in a server or server thread.
Definition: lo_types.h:105
int lo_message_add_double(lo_message m, double a)
Append a data item and typechar of the specified type to a message. See lo_message_add_int32() for de...
int(* lo_method_handler)(const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data)
A callback function to receive notification of matching message arriving in the server or server thre...
Definition: lo_types.h:134
void lo_server_free(lo_server s)
Free up memory used by the lo_server object.
Server(const num_string_type &port, lo_err_handler err_h=0)
Definition: lo_cpp.h:484
Server(const string_type &group, const num_string_type &port, const string_type &iface=0, const string_type &ip=0, E &&e=0)
Definition: lo_cpp.h:462
lo_arg ** lo_message_get_argv(lo_message m)
Return the message arguments. Do not free the returned data.
lo_address lo_address_new_from_url(const char *url)
Create a lo_address object from an OSC URL.
#define LO_TT_IMMEDIATE
A timetag constant representing "now".
Definition: lo_osc_types.h:151
void lo_bundle_pp(lo_bundle b)
Pretty-print a lo_bundle object.
lo_address lo_address_new_with_proto(int proto, const char *host, const char *port)
Declare an OSC destination, given IP address and port number, specifying protocol.
lo_message lo_message_new(void)
Create a new lo_message object.
Class representing an OSC destination address, proxy for lo_address.
Definition: lo_cpp.h:108
const char * lo_address_get_port(lo_address a)
Return the port/service name of a lo_address object.
LO_ADD_METHOD((const char *, const char *, lo_arg **, int),((char *) 0,(char *) 0,(lo_arg **) 0,(int) 0),(path, types, argv, argc))
int lo_address_get_protocol(lo_address a)
Return the protocol of a lo_address object.
lo_method lo_server_thread_add_method(lo_server_thread st, const char *path, const char *typespec, lo_method_handler h, const void *user_data)
Add an OSC method to the specifed server thread.
size_t lo_message_length(lo_message m, const char *path)
Return the length of a message in bytes.
lo_server lo_server_new_multicast_iface(const char *group, const char *port, const char *iface, const char *ip, lo_err_handler err_h)
Create a new server instance, and join a UDP multicast group, optionally specifying which network int...
int lo_send_message(lo_address targ, const char *path, lo_message msg)
Send a lo_message object to target targ.
int lo_message_add_int64(lo_message m, int64_t a)
Append a data item and typechar of the specified type to a message. See lo_message_add_int32() for de...
Definition: lo_cpp.h:71
void * lo_bundle_serialise(lo_bundle b, void *to, size_t *size)
Serialise the bundle object to an area of memory and return a pointer to the serialised form...
int lo_message_add_int32(lo_message m, int32_t a)
Append a data item and typechar of the specified type to a message.
int lo_address_set_stream_slip(lo_address t, int enable)
Set outgoing stream connections (e.g., TCP) to be transmitted using the SLIP packetizing protocol...
lo_bundle lo_bundle_get_bundle(lo_bundle b, int index)
Gets a nested bundle contained within a bundle.
const char * lo_address_get_iface(lo_address t)
Get the name of the network interface assigned to an OSC address.
int lo_address_set_tcp_nodelay(lo_address t, int enable)
Set the TCP_NODELAY flag on outgoing TCP connections.
lo_message lo_message_deserialise(void *data, size_t size, int *result)
Deserialise a raw OSC message and return a new lo_message object. Opposite of lo_message_serialise()...
Class representing an OSC path (std::string) and lo::Message pair.
Definition: lo_cpp.h:855
int lo_address_get_ttl(lo_address t)
Get the Time-to-Live value for a given target address.
const char * lo_address_get_hostname(lo_address a)
Return the hostname of a lo_address object.
int lo_message_add_true(lo_message m)
Append a data item and typechar of the specified type to a message. See lo_message_add_int32() for de...
Server(lo_server s)
Definition: lo_cpp.h:425
int lo_server_recv_noblock(lo_server s, int timeout)
Look for an OSC message waiting to be received.
int lo_bundle_add_bundle(lo_bundle b, lo_bundle n)
Adds an OSC bundle to an existing bundle.
void * lo_blob
A object to store an opaque binary data object.
Definition: lo_types.h:52
char * lo_server_get_url(lo_server s)
Return an OSC URL that can be used to contact the server.
void * lo_address
A reference to an OSC service.
Definition: lo_types.h:45
lo_server lo_server_new_with_proto(const char *port, int proto, lo_err_handler err_h)
Create a new server instance, specifying protocol.
int lo_server_get_port(lo_server s)
Return the port number that the server has bound to.
Class representing a local OSC server, proxy for lo_server.
Definition: lo_cpp.h:421
void lo_address_set_ttl(lo_address t, int ttl)
Set the Time-to-Live value for a given target address.
double lo_server_next_event_delay(lo_server s)
Return the time in seconds until the next scheduled event.
lo_server lo_server_thread_get_server(lo_server_thread st)
Return the lo_server for a lo_server_thread.
int(* lo_bundle_start_handler)(lo_timetag time, void *user_data)
A callback function to receive notification of a bundle being dispatched by the server or server thre...
Definition: lo_types.h:155
size_t lo_bundle_length(lo_bundle b)
Return the length of a bundle in bytes.
int lo_message_add_midi(lo_message m, uint8_t a[4])
Append a data item and typechar of the specified type to a message. See lo_message_add_int32() for de...
int lo_message_add_varargs(lo_message m, const char *types, va_list ap)
Append a varargs list to a message.
char * lo_address_get_url(lo_address a)
Return a URL representing an OSC address.
Class representing an OSC bundle, proxy for lo_bundle.
Definition: lo_cpp.h:865
int lo_server_get_socket_fd(lo_server s)
Return the file descriptor of the server socket.
lo_server_thread lo_server_thread_new_with_proto(const char *port, int proto, lo_err_handler err_h)
Create a new server thread to handle incoming OSC messages, specifying protocol.
virtual ~Server()
Definition: lo_cpp.h:501
int lo_server_dispatch_data(lo_server s, void *data, size_t size)
Dispatch a raw block of memory containing an OSC message.
void * lo_server_thread
An object representing a thread containing an OSC server.
Definition: lo_types.h:92
void * lo_message
A low-level object used to represent messages passed over OSC.
Definition: lo_types.h:60
void lo_address_free(lo_address t)
Free the memory used by the lo_address object.
int lo_server_del_lo_method(lo_server s, lo_method m)
Delete a specific OSC method from the specified server.
lo_server_thread lo_server_thread_new_multicast(const char *group, const char *port, lo_err_handler err_h)
Create a new server thread to handle incoming OSC messages, and join a UDP multicast group...
int lo_server_events_pending(lo_server s)
Return true if there are scheduled events (eg. from bundles) waiting to be dispatched by the server...
Server(const num_string_type &port, E &&e)
Definition: lo_cpp.h:429
void lo_bundle_free_recursive(lo_bundle b)
Frees the memory taken by a bundle object and its messages and nested bundles recursively.
int lo_server_get_protocol(lo_server s)
Return the protocol that the server is using.
int lo_server_thread_stop(lo_server_thread st)
Stop the server thread.
lo_blob lo_blob_new(int32_t size, const void *data)
Create a new OSC blob type.
uint32_t lo_blob_datasize(lo_blob b)
Return the amount of valid data in a lo_blob object.
int lo_server_recv(lo_server s)
Block, waiting for an OSC message to be received.
int(* lo_bundle_end_handler)(void *user_data)
A callback function to receive notification of a bundle dispatch being completed by the server or ser...
Definition: lo_types.h:166
Server(const string_type &group, const num_string_type &port, const string_type &iface="", const string_type &ip="", lo_err_handler err_h=0)
Definition: lo_cpp.h:493
void * lo_server
An object representing an instance of an OSC server.
Definition: lo_types.h:85
void lo_message_incref(lo_message m)
Add one to a message's reference count.
void lo_timetag_now(lo_timetag *t)
Return a timetag for the current time.
int lo_address_set_iface(lo_address t, const char *iface, const char *ip)
Set the network interface to use for a given target address.
int lo_message_add_symbol(lo_message m, const char *a)
Append a data item and typechar of the specified type to a message. See lo_message_add_int32() for de...
char * lo_message_get_types(lo_message m)
Return the message type tag string.
void lo_version(char *verstr, int verstr_size, int *major, int *minor, char *extra, int extra_size, int *lt_major, int *lt_minor, int *lt_bug)
Get information on the version of liblo current in use.
lo_method lo_server_add_method(lo_server s, const char *path, const char *typespec, lo_method_handler h, const void *user_data)
Add an OSC method to the specifed server.
void * lo_message_serialise(lo_message m, const char *path, void *to, size_t *size)
Serialise the lo_message object to an area of memory and return a pointer to the serialised form...
unsigned int lo_bundle_count(lo_bundle b)
Return the number of top-level elements in a bundle.
int lo_message_add_false(lo_message m)
Append a data item and typechar of the specified type to a message. See lo_message_add_int32() for de...
int lo_server_wait(lo_server s, int timeout)
Wait for an OSC message to be received.
int lo_address_errno(lo_address a)
Return the error number from the last failed lo_send() or lo_address_new() call.
int lo_send(lo_address targ, const char *path, const char *type,...)
Send a OSC formatted message to the address specified.
void * lo_blob_dataptr(lo_blob b)
Return a pointer to the start of the blob data to allow contents to be changed.
uint32_t lo_blobsize(lo_blob b)
A function to calculate the amount of OSC message space required by a lo_blob object.
void lo_server_thread_free(lo_server_thread st)
Free memory taken by a server thread.
void * lo_method
An object representing an method on a server.
Definition: lo_types.h:77
void * lo_bundle
A low-level object used to represent bundles of messages passed over OSC.
Definition: lo_types.h:69
int lo_message_add_float(lo_message m, float a)
Append a data item and typechar of the specified type to a message. See lo_message_add_int32() for de...
void lo_message_pp(lo_message m)
Pretty-print a lo_message object.