8000 Create driver_applemidiv6.c · g-coder/midikit@846930e · GitHub
[go: up one dir, main page]

Skip to content

Commit 846930e

Browse files
committed
Create driver_applemidiv6.c
Testing applemidi drivers for IPv6 connections.
1 parent aac0778 commit 846930e

File tree

1 file changed

+343
-0
lines changed

1 file changed

+343
-0
lines changed

test/driver_applemidiv6.c

Lines changed: 343 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,343 @@
1+
#include <stdlib.h>
2+
#include <unistd.h>
3+
#include <arpa/inet.h>
4+
#include <sys/select.h>
5+
#include <sys/time.h>
6+
#include "test.h"
7+
#include "midi/type.h"
8+
#include "midi/port.h"
9+
#include "midi/event.h"
10+
#include "midi/driver.h"
11+
#include "midi/message.h"
12+
#include "midi/runloop.h"
13+
#include "driver/applemidi/applemidi.h"
14+
15+
#define CLIENT_SSRC 0x5d72fb43
16+
17+
#define CLIENT_ADDRESS "::1"
18+
19+
#define CLIENT_CONTROL_PORT 5104
20+
#define CLIENT_RTP_PORT CLIENT_CONTROL_PORT + 1
21+
22+
#define SERVER_ADDRESS CLIENT_ADDRESS
23+
#define SERVER_CONTROL_PORT 5204
24+
#define SERVER_RTP_PORT SERVER_CONTROL_PORT + 1
25+
26+
static struct MIDIDriverAppleMIDI * driver = NULL;
27+
28+
static int client_control_socket = 0;
29+
static int client_rtp_socket = 0;
30+
31+
static struct sockaddr_in6 client_addr;
32+
static struct sockaddr_in6 server_addr;
33+
34+
static int _fillin_invitation_accepted( unsigned char * buf ) {
35+
buf[0] = 0xff;
36+
buf[1] = 0xff;
37+
buf[2] = 'O';
38+
buf[3] = 'K';
39+
/* leave version & token as is */
40+
buf[12] = 0xff & (CLIENT_SSRC >> 24);
41+
buf[13] = 0xff & (CLIENT_SSRC >> 16);
42+
buf[14] = 0xff & (CLIENT_SSRC >> 8);
43+
buf[15] = 0xff & CLIENT_SSRC;
44+
buf[16] = 'T';
45+
buf[17] = 'e';
46+
buf[18] = 's';
47+
buf[19] = 't';
48+
buf[20] = '\0';
49+
return 0;
50+
}
51+
52+
static int _fillin_sync( unsigned char * buf, int count ) {
53+
int offset = 12 + (8*count);
54+
struct timeval tv = { 0, 0 };
55+
unsigned long long ts;
56+
gettimeofday( &tv, NULL );
57+
ts = tv.tv_sec * 1000 + tv.tv_usec;
58+
59+
buf[0] = 0xff;
60+
buf[1] = 0xff;
61+
buf[2] = 'C';
62+
buf[3] = 'K';
63+
buf[4] = 0xff & (CLIENT_SSRC >> 24);
64+
buf[5] = 0xff & (CLIENT_SSRC >> 16);
65+
buf[6] = 0xff & (CLIENT_SSRC >> 8);
66+
buf[7] = 0xff & CLIENT_SSRC;
67+
buf[8] = count;
68+
buf[9] = 0;
69+
buf[10] = 0;
70+
buf[11] = 0;
71+
72+
buf[offset+0] = (ts >> 56) & 0xff;
73+
buf[offset+1] = (ts >> 48) & 0xff;
74+
buf[offset+2] = (ts >> 40) & 0xff;
75+
buf[offset+3] = (ts >> 32) & 0xff;
76+
buf[offset+4] = (ts >> 24) & 0xff;
77+
buf[offset+5] = (ts >> 16) & 0xff;
78+
buf[offset+6] = (ts >> 8) & 0xff;
79+
buf[offset+7] = ts & 0xff;
80+
return 0;
81+
}
82+
83+
static int _check_socket_in( int fd ) {
84+
static struct timeval tv = { 1, 0 };
85+
static fd_set fds;
86+
FD_ZERO( &fds );
87+
FD_SET( fd, &fds );
88+
select( fd+1, &fds, NULL, NULL, &tv );
89+
return FD_ISSET( fd, &fds );
90+
}
91+
92+
static int _n_msg = 0;
93+
static int _receive( void * target, void * source, struct MIDITypeSpec * type, void * data ) {
94+
struct MIDIMessage * message;
95+
char * buffer;
96+
int i;
97+
if( target != &_n_msg ) {
98+
printf( "Incorrect port target.\n" );
99+
}
100+
101+
if( type == MIDIMessageType ) {
102+
message = data;
103+
printf( "Received message!\n" );
104+
MIDIMessageRelease( message );
105+
_n_msg++;
106+
} else if( type == MIDIEventType ) {
107+
printf( "Received event!\n" );
108+
} else {
109+
buffer = data;
110+
printf( "Received unknown type '%p':\n", type );
111+
if( type == NULL ) return 0;
112+
for( i=0; i<type->size; i++ ) {
113+
if( (i+1)%8 == 0 || (i+1) == type->size ) {
114+
if( buffer[i-(i%8)] < 128 ) {
115+
printf( "0x%02x | %s\n", buffer[i], buffer+i-(i%8) );
116+
} else {
117+
printf( "0x%02x\n", buffer[i] );
118+
}
119+
} else {
120+
printf( "0x%02x ", buffer[i] );
121+
}
122+
}
123+
return 1;
124+
}
125+
return 0;
126+
}
127+
128+
static struct MIDIPort * _port;
129+
130+
/**
131+
* Test that AppleMIDI sessions can be created.
132+
*/
133+
int test001_applemidiv6( void ) {
134+
unsigned char buf[32];
135+
struct MIDIPort * port;
136+
char straddr[INET6_ADDRSTRLEN];
137+
138+
driver = MIDIDriverAppleMIDICreate( "My MIDI Session", SERVER_CONTROL_PORT );
139+
ASSERT_NOT_EQUAL( driver, NULL, "Could not create AppleMIDI driver." );
140+
141+
ASSERT_NO_ERROR( MIDIDriverGetPort( driver, &port ), "Could not get driver port." );
142+
143+
_port = MIDIPortCreate( "AppleMIDI test port", MIDI_PORT_IN, &_n_msg, &_receive );
144+
ASSERT_NOT_EQUAL( _port, NULL, "Could not create test port." );
145+
146+
ASSERT_NO_ERROR( MIDIPortConnect( port, _port ), "Could not connect ports." );
147+
148+
client_control_socket = socket( PF_INET6, SOCK_DGRAM, 0 );
149+
ASSERT_NOT_EQUAL( client_control_socket, 0, "Could not create control socket." );
150+
client_rtp_socket = socket( PF_INET6, SOCK_DGRAM, 0 );
151+
ASSERT_NOT_EQUAL( client_rtp_socket, 0, "Could not create RTP socket." );
152+
153+
client_addr.sin6_family = AF_INET6;
154+
client_addr.sin6_addr = in6addr_any;
155+
156+
client_addr.sin6_port = htons( CLIENT_CONTROL_PORT );
157+
ASSERT_NO_ERROR( bind( client_control_socket, (struct sockaddr *) &client_addr, sizeof(client_addr) ),
158+
"Could not bind control socket." );
159+
160+
client_addr.sin6_port = htons( CLIENT_RTP_PORT );
161+
ASSERT_NO_ERROR( bind( client_rtp_socket, (struct sockaddr *) &client_addr, sizeof(client_addr) ),
162+
"Could not bind rtp socket." );
163+
164+
ASSERT_NO_ERROR( MIDIDriverAppleMIDIAddPeer( driver, CLIENT_ADDRESS, CLIENT_CONTROL_PORT ),
165+
"Could not add client." );
166+
167+
/* hope for invitation on control socket */
168+
ASSERT( _check_socket_in( client_control_socket ), "Expected message on client control socket." );
169+
recv( client_control_socket, &(buf[0]), sizeof(buf), 0 );
170+
171+
/* check packet header */
172+
ASSERT_EQUAL( buf[0], 0xff, "Received wrong AppleMIDI signature." );
173+
ASSERT_EQUAL( buf[1], 0xff, "Received wrong AppleMIDI signature." );
174+
ASSERT_EQUAL( buf[2], 'I', "Received wrong AppleMIDI command." );
175+
ASSERT_EQUAL( buf[3], 'N', "Received wrong AppleMIDI command." );
176+
177+
_fillin_invitation_accepted( &(buf[0]) );
178+
179+
server_addr.sin6_family = AF_INET6;
180+
inet_pton(AF_INET6, "::1",
181+
&(server_addr.sin6_addr));
182+
server_addr.sin6_port = htons( SERVER_CONTROL_PORT );
183+
184+
sendto( client_control_socket, &(buf[0]), 21, 0,
185+
(struct sockaddr *) &server_addr, sizeof(server_addr) );
186+
187+
ASSERT_NO_ERROR( MIDIDriverAppleMIDIReceive( driver ), "Could not receive accepted invitation on control port." );
188+
189+
/* the driver should now have sent an invitation on the rtp port */
190+
ASSERT( _check_socket_in( client_rtp_socket ), "Expected message on client control socket." );
191+
recv( client_rtp_socket, &(buf[0]), sizeof(buf), 0 );
192+
193+
ASSERT_EQUAL( buf[0], 0xff, "Received wrong AppleMIDI signature." );
194+
ASSERT_EQUAL( buf[1], 0xff, "Received wrong AppleMIDI signature." );
195+
ASSERT_EQUAL( buf[2], 'I', "Received wrong AppleMIDI command." );
196+
ASSERT_EQUAL( buf[3], 'N', "Received wrong AppleMIDI command." );
197+
198+
_fillin_invitation_accepted( &(buf[0]) );
199+
200+
server_addr.sin6_port = htons( SERVER_RTP_PORT );
201+
printf( "send ok to %s:%i\n", inet_ntop( AF_INET6, &server_addr.sin6_addr, straddr, sizeof(straddr)), htons( server_addr.sin6_port ) );
202+
203+
sendto( client_rtp_socket, &(buf[0]), 21, 0,
204+
(struct sockaddr *) &server_addr, sizeof(server_addr) );
205+
206+
ASSERT_NO_ERROR( MIDIDriverAppleMIDIReceive( driver ), "Could not receive accepted invitation on RTP port." );
207+
208+
return 0;
209+
}
210+
211+
/**
212+
* Test that the AppleMIDI sockets can be accessed.
213+
*/
214+
int test002_applemidiv6( void ) {
215+
int server_control_socket, server_rtp_socket;
216+
217+
ASSERT_NO_ERROR( MIDIDriverAppleMIDIGetControlSocket( driver, &server_control_socket ), "Could not get control socket." );
218+
ASSERT_NO_ERROR( MIDIDriverAppleMIDIGetRTPSocket( driver, &server_rtp_socket ), "Could not get rtp socket." );
219+
220+
return 0;
221+
}
222+
223+
/**
224+
* Test that the AppleMIDI driver can be used as a runloop source.
225+
*/
226+
int test003_applemidiv6( void ) {
227+
struct MIDIRunloopSource * source;
228+
struct MIDIRunloop * runloop;
229+
unsigned char buf[36] = { 0 };
230+
231+
runloop = MIDIRunloopCreate( NULL );
232+
ASSERT_NOT_EQUAL( runloop, NULL, "Could not create runloop." );
233+
ASSERT_NO_ERROR( MIDIDriverAppleMIDIGetRunloopSource( driver, &source ), "Could not create runloop source." );
234+
ASSERT_NO_ERROR( MIDIRunloopAddSource( runloop, source ), "Could not add source to runloop." );
235+
ASSERT_NO_ERROR( MIDIRunloopStep( runloop ), "Could not step through runloop." );
236+
ASSERT_NO_ERROR( MIDIRunloopRemoveSource( runloop, source ), "Could not remove source from runloop." );
237+
238+
/* answer sync request */
239+
_fillin_sync( &(buf[0]), 1 );
240+
ASSERT_EQUAL( 36, sendto( client_rtp_socket, &(buf[0]), sizeof(buf), 0,
241+
(struct sockaddr *) &server_addr, sizeof(server_addr) ), "Could not send sync." );
242+
243+
ASSERT_NO_ERROR( MIDIDriverAppleMIDIGetRunloopSource( driver, &source ), "Could not recreate runloop source." );
244+
ASSERT_NO_ERROR( MIDIRunloopAddSource( runloop, source ), "Could not add source to runloop." );
245+
246+
ASSERT_NO_ERROR( MIDIRunloopStep( runloop ), "Could not step through runloop." );
247+
ASSERT_NO_ERROR( MIDIRunloopStep( runloop ), "Could not step through runloop." );
248+
ASSERT( _check_socket_in( client_rtp_socket ), "Expected message on client control socket." );
249+
ASSERT_EQUAL( 36, recv( client_rtp_socket, &(buf[0]), sizeof(buf), 0), "Did not receive synchronization answer." );
250+
ASSERT_NO_ERROR( MIDIRunloopStep( runloop ), "Could not step through runloop." );
251+
ASSERT_NO_ERROR( MIDIRunloopStep( runloop ), "Could not step through runloop." );
252+
ASSERT_NO_ERROR( MIDIRunloopStep( runloop ), "Could not step through runloop." );
253+
254+
MIDIRunloopRelease( runloop );
255+
return 0;
256+
}
257+
258+
/**
259+
* Test that RTP MIDI messages can be sent.
260+
*/
261+
int test004_applemidiv6( void ) {
262+
struct MIDIMessage * messages[3];
263+
unsigned char buffer[128];
264+
unsigned char expect[128] = {
265+
/* RTP header / seqnum, random */
266+
0x80, 0x60, 0x00, 0x00,
267+
/* timestamp, random */
268+
0x00, 0x00, 0x00, 0x00,
269+
/* SSRC */
270+
0x00, 0x00, 0x00, 0x00,
271+
/* MIDI header, Z bit (2) is set */
272+
0x0b,
273+
/* MIDI payload, first timestamp is zero */
274+
0x90, 0x42, 0x68,
275+
0x00, 0xa0, 0x42, 0x78,
276+
0x00, 0x80, 0x42, 0x68
277+
};
278+
int i;
279+
unsigned long long ssrc;
280+
size_t bytes;
281+
MIDIChannel channel = MIDI_CHANNEL_1;
282+
MIDIKey key = 66;
283+
MIDIVelocity velocity = 104;
284+
MIDIPressure pressure = 120;
285+
286+
messages[0] = MIDIMessageCreate( MIDI_STATUS_NOTE_ON );
287+
messages[1] = MIDIMessageCreate( MIDI_STATUS_POLYPHONIC_KEY_PRESSURE );
288+
messages[2] = MIDIMessageCreate( MIDI_STATUS_NOTE_OFF );
289+
MIDIMessageSet( messages[0], MIDI_CHANNEL, sizeof(MIDIChannel), &channel );
290+
MIDIMessageSet( messages[1], MIDI_CHANNEL, sizeof(MIDIChannel), &channel );
291+
MIDIMessageSet( messages[2], MIDI_CHANNEL, sizeof(MIDIChannel), &channel );
292+
MIDIMessageSet( messages[0], MIDI_KEY, sizeof(MIDIKey), &key );
293+
MIDIMessageSet( messages[1], MIDI_KEY, sizeof(MIDIKey), &key );
294+
MIDIMessageSet( messages[2], MIDI_KEY, sizeof(MIDIKey), &key );
295+
MIDIMessageSet( messages[0], MIDI_VELOCITY, sizeof(MIDIVelocity), &velocity );
296+
MIDIMessageSet( messages[1], MIDI_PRESSURE, sizeof(MIDIPressure), &pressure );
297+
MIDIMessageSet( messages[2], MIDI_VELOCITY, sizeof(MIDIVelocity), &velocity );
298+
299+
ASSERT_NO_ERROR( MIDIDriverAppleMIDISendMessage( driver, messages[0] ), "Could not queue midi message 0." );
300+
ASSERT_NO_ERROR( MIDIDriverAppleMIDISendMessage( driver, messages[1] ), "Could not queue midi message 1." );
301+
ASSERT_NO_ERROR( MIDIDriverAppleMIDISendMessage( driver, messages[2] ), "Could not queue midi message 2." );
302+
MIDIMessageRelease( messages[0] ); messages[0] = NULL;
303+
MIDIMessageRelease( messages[1] ); messages[1] = NULL;
304+
MIDIMessageRelease( messages[2] ); messages[2] = NULL;
305+
306+
ASSERT_NO_ERROR( MIDIDriverAppleMIDISend( driver ), "Could not send queued messages." );
307+
308+
ASSERT( _check_socket_in( client_rtp_socket ), "Expected message on client control socket." );
309+
bytes = recv( client_rtp_socket, &(buffer[0]), sizeof(buffer), 0 );
310+
ASSERT_GREATER_OR_EQUAL( bytes, 23, "Could not received RTP MIDI packet from AppleMIDI driver." );
311+
312+
for( i=0; i<bytes; i++ ) {
313+
if( (i+1)%8 == 0 || (i+1) == bytes ) {
314+
printf( "0x%02x\n", buffer[i] );
315+
} else {
316+
printf( "0x%02x ", buffer[i] );
317+
}
318+
}
319+
320+
ssrc = ( buffer[8] << 24)
321+
| ( buffer[9] << 16 )
322+
| ( buffer[10] << 8 )
323+
| ( buffer[11] );
324+
325+
ASSERT_EQUAL( 24, sendto( client_rtp_socket, &(expect[0]), 24, 0,
326+
(struct sockaddr *) &server_addr, sizeof(server_addr) ), "Could not send RTP-MIDI." );
327+
usleep( 1000 );
328+
ASSERT_NO_ERROR( MIDIDriverAppleMIDIReceive( driver ), "Could not receive sent messages." );
329+
ASSERT_EQUAL( _n_msg, 3, "Received wrong number of messages." );
330+
return 0;
331+
}
332+
333+
/**
334+
* Test that AppleMIDI sessions can be torn down and
335+
* clients receive the proper ENDSESSION commands.
336+
*/
337+
int test005_applemidiv6( void ) {
338+
MIDIDriverRelease( driver );
339+
340+
close( client_control_socket );
341+
close( client_rtp_socket );
342+
return 0;
343+
}

0 commit comments

Comments
 (0)
0