O2 2.0
A communication protocol for interactive music and media applications.
o2lite.h
1// o2lite.h -- header for o2lite library
2//
3// Roger B. Dannenberg
4// July 2020
5
61// Discovery options:
62// o2discovery -- o2's original built-in protocol (default is false)
63// broadcast -- use broadcast to speed things up (default is true)
64// zeroconf -- use ZeroConf for discovery (default is true)
65// clocksync -- o2lite should synchronize with host (can be used with
66// either o2discovery or zeroconf) (default is true)
67// Note that macros are "true" if defined, "false" if undefined, and most
68// are inverted, e.g. O2_NO_O2DISCOVERY rather than
69// O2_O2DISCOVERY, because most options are for disabling features;
70// thus, most macros are undefined.
71// Here are the macros with their default values:
72// O2_NO_O2DISCOVERY -- O2 is not using built-in discovery; (defined)
73// O2_NO_ZEROCONF -- O2 is not using ZeroConf for discovery; (undefined)
74// O2L_NO_BROADCAST -- O2lite does not broadcast to speed up discovery
75// (undefined). This has no effect if O2_NO_O2DISCOVERY, which is
76// defined by default. The ZeroConf protocol ALWAYS uses broadcast
77// (even if O2L_NO_BROADCAST); it's internal to ZeroConf.
78// O2L_NO_CLOCKSYNC -- O2lite does not synchronize with host (undefined)
79
80#include <stdbool.h>
81#include <stdint.h>
82#include <stdio.h>
83// NOTE: more includes below after O2_MALLOC is defined
84
85#ifdef __cplusplus
86extern "C" {
87#endif
88
89#define O2L_VERSION 0x020000
90
91// you can enable/disable O2LDB printing using -DO2LDEBUG=1 or =0
92#if (!defined(O2LDEBUG))
93#ifndef NDEBUG
94// otherwise default is to enable in debug versions
95#define O2LDEBUG 1
96#else
97#define O2LDEBUG 0
98#endif
99#endif
100
101#define O2LDB if (O2LDEBUG)
102
103#define O2LDBV if (O2LDEBUG && verbose)
104
105#if defined(O2_NO_O2DISCOVERY) && !defined(O2L_NO_BROADCAST)
106#define O2L_NO_BROADCAST 1
107#endif
108#if defined(O2_NO_O2DISCOVERY) && defined(O2_NO_ZEROCONF)
109#error O2_NO_O2DISCOVERY and O2_NO_ZEROCONF are both defined - no discovery
110#endif
111
112// default is ZEROCONF, so if necessary, disable O2_NO_O2DISCOVERY:
113#if !defined(O2_NO_O2DISCOVERY) && !defined(O2_NO_ZEROCONF)
114#define O2_NO_O2DISCOVERY
115#if !defined(O2L_NO_BROADCAST)
116#define O2L_NO_BROADCAST
117#endif
118#endif
119
120#define O2_MALLOC malloc
121#define O2_CALLOC calloc
122#define O2_FREE free
123
124#include "o2base.h"
125#include "hostip.h"
126
127#define MAX_MSG_LEN 256
128#define PORT_MAX 16
129
131#define O2L_SUCCESS 0
132
134#define O2L_FAIL -1
135
137#define O2L_ALREADY_RUNNING -5
138
139typedef float o2l_time; // could be double, but this gives 1ms accuracy
140 // for 2.3 hours, or 10ms accuracy for 23 hours
141
142#define O2_UDP_FLAG 0
143#define O2_TCP_FLAG 1
144
145typedef struct o2l_msg {
146 int32_t length; // length of flags, timestamp, address, and the rest
147 int32_t misc; // flags and ttl (see O2msg_data)
148 double timestamp; // regardless of o2l_time, this is O2time = double
149 char address[4];
151
153typedef void (*o2l_handler)(o2l_msg_ptr msg, const char *types,
154 void *data, void *info);
155
157extern int verbose;
158
160extern o2l_time o2l_local_now;
161
162#ifdef ESP32
164void button_poll();
165#endif
166
178void o2l_send_start(const char *address, o2l_time time,
179 const char *types, bool tcp);
180
182void o2l_send();
183
220void o2l_method_new(const char *path, const char *typespec,
221 bool full, o2l_handler h, void *info);
222
224o2l_time o2l_local_time();
225
230o2l_time o2l_time_get();
231
233void o2l_poll();
234
235#if ESP32
240void connect_to_wifi(const char *hostname, const char *ssid, const char *pwd);
241#endif
242
243
262int o2l_initialize(const char *ensemble);
263
265int o2l_finish();
266
268void o2l_add_string(const char *s);
269
271void o2l_add_time(double time);
272
274#define o2l_add_double(x) o2l_add_time(x)
275
277void o2l_add_float(float x);
278
280#define o2l_add_int(i) o2l_add_int32(i)
281
283void o2l_add_int32(int32_t i);
284
296bool o2l_get_error();
297
299double o2l_get_timestamp();
300
302double o2l_get_time();
303
305#define o2l_get_double() o2l_get_time()
306
308float o2l_get_float();
309
311int32_t o2l_get_int32();
312
314#define o2l_get_int(i) o2l_get_int32(i)
315
320char *o2l_get_string();
321
339void o2l_set_services(const char *services);
340
355extern char o2l_remote_ip_port[16];
356
365extern int o2l_bridge_id;
366
367// define IS_BIG_ENDIAN, IS_LITTLE_ENDIAN, and swap64(i),
368// swap32(i), and swap16(i)
369#if WIN32
370#elif ESP32
371// LITTLE_ENDIAN, BYTE_ORDER are defined already
372#define IS_BIG_ENDIAN (BYTE_ORDER != LITTLE_ENDIAN)
373// WIN32 requires predefinition of IS_BIG_ENDIAN=1 or IS_BIG_ENDIAN=0
374#else
375 #ifdef __APPLE__
376 // OS X endian.h is in MacOSX10.8.sdk/usr/include/machine/endian.h:
377 #include "machine/endian.h"
378 #define LITTLE_ENDIAN __DARWIN_LITTLE_ENDIAN
379 #else
380 #include <endian.h>
381 #define LITTLE_ENDIAN __LITTLE_ENDIAN
382 #define BYTE_ORDER __BYTE_ORDER
383 #endif
384 #define IS_BIG_ENDIAN (BYTE_ORDER != LITTLE_ENDIAN)
385#endif
386#define IS_LITTLE_ENDIAN (!(IS_BIG_ENDIAN))
387#if IS_LITTLE_ENDIAN
388#define o2lswap16(i) ((((i) >> 8) & 0xff) | (((i) & 0xff) << 8))
389#define o2lswap32(i) ((((i) >> 24) & 0xff) | (((i) & 0xff0000) >> 8) | \
390 (((i) & 0xff00) << 8) | (((i) & 0xff) << 24))
391#define o2lswap64(i) ((((uint64_t) o2lswap32(i)) << 32) | o2lswap32((i) >> 32))
392#else
393#define o2lswap16(i) (i)
394#define o2lswap32(i) (i)
395#define o2lswap64(i) (i)
396#endif
397
398
399/************************************************************/
400/****************** Discovery API ***************************/
401/************************************************************/
402
403#ifdef WIN32
404#include <winsock2.h>
405#else
406#include <sys/select.h>
407#endif
408
409// There are about 4 different discovery implementations, even for O2lite.
410// To avoid massive amounts of conditional compilation to support each
411// protocol, the implementations are separated into multiple files:
412// o2liteavahi.c -- Avahi (linux only)
413// o2litebonjour.c -- Avahi (Apple, Windows)
414// o2liteo2disc.c -- Apple, Windows, Linux o2 discovery (non-standard)
415// All files use conditional compilation at the top level so they may be
416// compiled and linked together, but you only need to link with one, e.g.
417// o2liteavahi.c for linux, o2litebonjour.c for Apple and Windows.
418//
419// Each file implements these functions which are called from o2lite.c:
420
421// o2ldisc_init() -- called in o2l_initialize() for
422// implementation-specific actions
423int o2ldisc_init(const char *ensemble);
424
425// o2ldisc_poll() -- called before select(), which polls sockets. Here, you
426// can add_socket() to add to the read_set passed to select or poll for
427// timeouts.
428void o2ldisc_poll();
429
430// o2ldisc_events() -- called to check for incoming messages or socket errors
431void o2ldisc_events(fd_set *readset);
432
433/**********************************************************************/
434/* Internal symbols declared for use by Discovery API Implementations */
435/**********************************************************************/
436#ifndef WIN32
437#define INVALID_SOCKET -1
438#define SOCKET_ERROR -1
439typedef int SOCKET; // we use SOCKET to denote the type of a socket
440#endif
441
442extern SOCKET tcp_sock;
443extern const char *o2l_ensemble;
444extern struct sockaddr_in udp_server_sa;
445extern int udp_recv_port;
446extern SOCKET udp_recv_sock;
447
448bool o2l_is_valid_proc_name(const char *name, int port,
449 char *internal_ip, int *udp_port);
450
451int o2l_parse_version(const char *vers, int vers_len);
452
453int o2l_address_init(struct sockaddr_in *sa, const char *ip, int port_num,
454 bool tcp);
455
456void o2l_network_connect(const char *ip, int port);
457
458void o2l_add_socket(SOCKET s);
459
460int o2l_bind_recv_socket(SOCKET sock, int *port);
461
462
463#ifdef __cplusplus
464}
465#endif
Definition: o2lite.h:145