aboutsummaryrefslogtreecommitdiffhomepage
path: root/backends/rtpmidi.h
blob: e88530f85196626a43f6610e1b26810887638328 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
#ifndef _WIN32
#include <sys/socket.h>
#endif
#include "midimonster.h"

MM_PLUGIN_API int init();
static int rtpmidi_configure(char* option, char* value);
static int rtpmidi_configure_instance(instance* instance, char* option, char* value);
static int rtpmidi_instance(instance* inst);
static channel* rtpmidi_channel(instance* instance, char* spec, uint8_t flags);
static uint32_t rtpmidi_interval();
static int rtpmidi_set(instance* inst, size_t num, channel** c, channel_value* v);
static int rtpmidi_handle(size_t num, managed_fd* fds);
static int rtpmidi_start(size_t n, instance** inst);
static int rtpmidi_shutdown(size_t n, instance** inst);

#define RTPMIDI_PACKET_BUFFER 8192
#define RTPMIDI_DEFAULT_HOST "::"
#define RTPMIDI_DEFAULT4_HOST "0.0.0.0"
#define RTPMIDI_MDNS_PORT "5353"
#define RTPMIDI_HEADER_MAGIC 0x80
#define RTPMIDI_HEADER_TYPE 0x61
#define RTPMIDI_GET_TYPE(a) ((a) & 0x7F)
#define RTPMIDI_DEFAULT_NAME "MIDIMonster"
#define RTPMIDI_SERVICE_INTERVAL 1000
#define RTPMIDI_MDNS_DOMAIN "_apple-midi._udp.local."
#define RTPMIDI_DNSSD_DOMAIN "_services._dns-sd._udp.local."
#define RTPMIDI_ANNOUNCE_INTERVAL (60 * 1000)

#define DNS_POINTER(a) (((a) & 0xC0) == 0xC0)
#define DNS_LABEL_LENGTH(a) ((a) & 0x3F)
#define DNS_OPCODE(a) (((a) & 0x78) >> 3)
#define DNS_RESPONSE(a) ((a) & 0x80)

#define EPN_NRPN 8
#define EPN_PARAMETER_HI 4
#define EPN_PARAMETER_LO 2
#define EPN_VALUE_HI 1

enum /*_rtpmidi_channel_type*/ {
	none = 0,
	note = 0x90,
	pressure = 0xA0,
	cc = 0xB0,
	program = 0xC0,
	aftertouch = 0xD0,
	pitchbend = 0xE0,
	rpn = 0xF1,
	nrpn = 0xF2
};

typedef enum /*_rtpmidi_instance_mode*/ {
	unconfigured = 0,
	direct,
	apple
} rtpmidi_instance_mode;

typedef union {
	struct {
		uint8_t pad[4];
		uint8_t type;
		uint8_t channel;
		uint16_t control;
	} fields;
	uint64_t label;
} rtpmidi_channel_ident;

typedef struct /*_rtpmidi_peer*/ {
	struct sockaddr_storage dest;
	socklen_t dest_len;
	//uint32_t ssrc;
	uint8_t active; //marked for reuse
	uint8_t learned; //learned / configured peer (learned peers are marked inactive on session shutdown)
	uint8_t connected; //currently in active session
	ssize_t invite; //invite-list index for apple-mode learned peers (used to track ipv6/ipv4 overlapping invitations)
} rtpmidi_peer;

typedef struct /*_rtpmidi_instance_data*/ {
	rtpmidi_instance_mode mode;

	int fd;
	int control_fd;
	uint16_t control_port; /*convenience member set by rtpmidi_bind_instance*/

	size_t peers;
	rtpmidi_peer* peer;
	uint32_t ssrc;
	uint16_t sequence;

	uint8_t epn_tx_short;
	uint16_t epn_control[16];
	uint16_t epn_value[16];
	uint8_t epn_status[16];

	//apple-midi config
	char* accept;
	uint64_t last_announce;

	//direct mode config
	uint8_t learn_peers;
} rtpmidi_instance_data;

typedef struct /*rtpmidi_invited_peer*/ {
	instance* inst;
	size_t invites;
	char** name;
} rtpmidi_invite;

typedef struct /*_rtpmidi_addr*/ {
	int family;
	//this is actually a fair bit too big, but whatever
	uint8_t addr[sizeof(struct sockaddr_storage)];
} rtpmidi_addr;

typedef enum {
	apple_invite = 0x494E, //IN
	apple_accept = 0x4F4B, //OK
	apple_reject = 0x4E4F, //NO
	apple_leave = 0x4259, //BY
	apple_sync = 0x434B, //CK
	apple_feedback = 0x5253 //RS
} applemidi_command;

typedef struct /*_dns_name*/ {
	size_t alloc;
	char* name;
	size_t length;
} dns_name;

#pragma pack(push, 1)
typedef struct /*_apple_session_command*/ {
	uint16_t res1;
	uint16_t command;
	uint32_t version;
	uint32_t token;
	uint32_t ssrc;
	//char* name
} apple_command;

typedef struct /*_apple_session_sync*/ {
	uint16_t res1;
	uint16_t command;
	uint32_t ssrc;
	uint8_t count;
	uint8_t res2[3];
	uint64_t timestamp[3];
} apple_sync_frame;

typedef struct /*_apple_session_feedback*/ {
	uint16_t res1;
	uint8_t command[2];
	uint32_t ssrc;
	uint32_t sequence;
} apple_journal_feedback;

typedef struct /*_rtp_midi_header*/ {
	uint8_t vpxcc;
	uint8_t mpt;
	uint16_t sequence;
	uint32_t timestamp;
	uint32_t ssrc;
} rtpmidi_header;

typedef struct /*_rtp_midi_command*/ {
	uint8_t flags;
	uint8_t length;
} rtpmidi_command_header;

typedef struct /*_dns_header*/ {
	uint16_t id;
	uint8_t flags[2];
	uint16_t questions;
	uint16_t answers;
	uint16_t servers;
	uint16_t additional;
} dns_header;

typedef struct /*_dns_question*/ {
	uint16_t qtype;
	uint16_t qclass;
} dns_question;

typedef struct /*_dns_rr*/ {
	uint16_t rtype;
	uint16_t rclass;
	uint32_t ttl;
	uint16_t data;
} dns_rr;

typedef struct /*_dns_rr_srv*/ {
	uint16_t priority;
	uint16_t weight;
	uint16_t port;
} dns_rr_srv;
#pragma pack(pop)