lathoub / Arduino-AppleMIDI-Library

Send and receive MIDI messages over Ethernet (rtpMIDI or AppleMIDI)
Other
309 stars 66 forks source link

Session initiation by Arduino #5

Closed lathoub closed 10 years ago

lathoub commented 10 years ago

Work on adding a way to initiate a session from Arduino? Or at least, give me some suggestions for writing the code myself? My code already has bonjour capabilities, so I know the rtpserver ip.

lathoub commented 10 years ago

I will look into it and come with some suggestions

ghost commented 10 years ago

Thank you a lot!

lathoub commented 10 years ago

First try to have the Arduino initiate the session. All calls and mechanisms are added to the code, but somehow the syncronisation doesnt work (Sync message is send, but peer does not respond - I use Wireshark to monitor the AppleMIDI messages). Admittingly, i'm not sure how the syncronisation timings are calculated (missing documentation) - needs further investigation. But this gives you an idea of what it would look like!

I look forward to your comments

Code below demonstrates how to start the session:

// Create a session and wait for a remote host to connect to us AppleMIDI.begin("test");

// Actively connect to a remote host IPAddress host(192, 168, 1, 142); AppleMIDI.Invite(host, 5004);

ghost commented 10 years ago

Tried with the new code but problems exist indeed. Device shows in the rtpMIDI interface but session is not initiated and thus latency is not shown. I will give a look to the protocol format too. Hoping to solve this issue too! Thanks.

lathoub commented 10 years ago

This is what I found on http://en.wikipedia.org/wiki/RTP_MIDI

Synchronization sequence:

The synchronization sequence allows both session participants to share informations related to their local clocks. This phase allows to compensate the latency induced by the network, and also permits to support the "future timestamping" (see "Latency" chapter below)

The session initiator sends a first message (named CK0) to the remote partner, giving its local time on 64 bits (Note that this is not an absolute time, but a time related to a local reference, generally given in microseconds since the startup of operating system kernel). This time is expressed on 10 kHz sampling clock basis (100 microseconds per increment) The remote partner must answer to this message with a CK1 message, containing its own local time on 64 bits. Both partners then know the difference between their respective clocks and can determine the offset to apply to Timestamp and Deltatime fields in RTP-MIDI protocol. The session initiator finishes this sequence by sending a last message called CK2, containing the local time when it received the CK1 message. This technique allows to compute the average latency of the network, and also to compensate a potential delay introduced by a slow starting thread (this situation can occur with non-realtime operating systems like Linux, Windows or OS X)

Apple recommends to repeat this sequence a few times just after opening the session, in order to get better synchronization accuracy (in case of one of the sequence has been delayed accidentally because of a temporary network overload or a latency peak in a thread activation)

This sequence must repeat cyclically (between 2 and 6 times per minute typically), and always by the session initiator, in order to maintain long term synchronization accuracy by compensation of local clock drift, and also to detect a loss of communication partner. A partner not answering to multiple CK0 messages shall consider that the remote partner is disconnected. In most cases, session initiators switch their state machine into "Invitation" state in order to re-establish communication automatically as soon as the distant partner reconnects to the network. Some implementations (especially on personal computers) display also an alert message and offer to the user to choose between a new connection attempt or closing the session.

lathoub commented 10 years ago

Bug fixed! (2nd invitation had to send to port 5005, not port 5004) Still: I do not know how to deal with synchronisation from a initiator point of view (in reactor mode the code was made to react to sync requests, not to send them) - is there a document (apart from doc RFC 4695 & 4696) that describes this? (I have noticed code on midikit that might give a clue)

lathoub commented 10 years ago

Can you test if Syncronisation is working? If so, I can start to refine the mechanism to detect loss of session slave (Arduino is session initiator)

ghost commented 10 years ago

Hi, yes, synchronization seems to work. Invite is sent, gets accepted, and sync messages are exchanged (with count = 0, 1, 2 and then back again to 0, as shown in the attached pic). shot_sync

lathoub commented 10 years ago

Thanks for testing!