@@ -600,9 +600,37 @@ void AppleMIDISession<UdpClass, Settings, Platform>::writeRtpMidiToAllParticipan
600600template <class UdpClass , class Settings , class Platform >
601601void AppleMIDISession<UdpClass, Settings, Platform>::writeRtpMidiBuffer (Participant<Settings>* participant)
602602{
603+ const auto bufferLen = outMidiBuffer.size ();
604+
603605 Rtp rtp;
604- rtp.vpxcc = 0b10000000 ; // TODO: fun with flags
605- rtp.mpayload = PAYLOADTYPE_RTPMIDI; // TODO: set or unset marker
606+
607+ // First octet
608+ rtp.vpxcc = ((RTP_VERSION_2) << 6 ); // RTP version 2
609+ rtp.vpxcc &= ~RTP_P_FIELD; // no padding
610+ rtp.vpxcc &= ~RTP_X_FIELD; // no extension
611+ // No CSRC
612+
613+ // second octet
614+ rtp.mpayload = PAYLOADTYPE_RTPMIDI;
615+
616+ /*
617+ // The behavior of the 1-bit M field depends on the media type of the
618+ // stream. For native streams, the M bit MUST be set to 1 if the MIDI
619+ // command section has a non-zero LEN field and MUST be set to 0
620+ // otherwise. For mpeg4-generic streams, the M bit MUST be set to 1 for
621+ // all packets (to conform to [RFC3640]).
622+ if (bufferLen != 0)
623+ rtp.mpayload |= RTP_M_FIELD;
624+ else
625+ rtp.mpayload &= ~RTP_M_FIELD;
626+ */
627+ // Both https://developer.apple.com/library/archive/documentation/Audio/Conceptual/MIDINetworkDriverProtocol/MIDI/MIDI.html
628+ // and https://tools.ietf.org/html/rfc6295#section-2.1 indicate that the M field needs to be set
629+ // if the len in the MIDI section is NON-ZERO.
630+ // However, doing so on, MacOS does not take the given MIDI commands
631+ // Clear the M field
632+ rtp.mpayload &= ~RTP_M_FIELD;
633+
606634 rtp.ssrc = ssrc;
607635
608636 // https://developer.apple.com/library/ios/documentation/CoreMidi/Reference/MIDIServices_Reference/#//apple_ref/doc/uid/TP40010316-CHMIDIServiceshFunctions-SW30
@@ -647,27 +675,30 @@ void AppleMIDISession<UdpClass, Settings, Platform>::writeRtpMidiBuffer(Particip
647675 // write rtp header
648676 dataPort.write ((uint8_t *)&rtp, sizeof (rtp));
649677
650- const auto bufferLen = outMidiBuffer.size ();
651-
652678 // Write rtpMIDI section
653679 RtpMIDI_t rtpMidi;
654680
681+ // 0 1 2 3
682+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
683+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
684+ // |B|J|Z|P|LEN... | MIDI list ... |
685+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
686+
687+ rtpMidi.flags = 0 ;
688+ rtpMidi.flags &= ~RTP_MIDI_CS_FLAG_J; // no journal, clear J-FLAG
689+ rtpMidi.flags &= ~RTP_MIDI_CS_FLAG_Z; // no Delta Time 0 field, clear Z flag
690+ rtpMidi.flags &= ~RTP_MIDI_CS_FLAG_P; // no phantom flag
691+
655692 if (bufferLen <= 0x0F )
656693 { // Short header
657- rtpMidi.flags = (uint8_t )bufferLen;
658- // rtpMidi.flags &= RTP_MIDI_CS_FLAG_B; // TODO: set or clear these flags (no journal)
659- // rtpMidi.flags &= RTP_MIDI_CS_FLAG_J;
660- // rtpMidi.flags &= RTP_MIDI_CS_FLAG_Z;
661- // rtpMidi.flags &= RTP_MIDI_CS_FLAG_P;
694+ rtpMidi.flags |= (uint8_t )bufferLen;
695+ rtpMidi.flags &= ~RTP_MIDI_CS_FLAG_B; // short header, clear B-FLAG
662696 dataPort.write (rtpMidi.flags );
663697 }
664698 else
665699 { // Long header
666- rtpMidi.flags = (uint8_t )(bufferLen >> 8 );
667- rtpMidi.flags |= RTP_MIDI_CS_FLAG_B; // set B-FLAG for long header
668- // rtpMidi.flags &= RTP_MIDI_CS_FLAG_J;
669- // rtpMidi.flags &= RTP_MIDI_CS_FLAG_Z;
670- // rtpMidi.flags &= RTP_MIDI_CS_FLAG_P;
700+ rtpMidi.flags |= (uint8_t )(bufferLen >> 8 );
701+ rtpMidi.flags |= RTP_MIDI_CS_FLAG_B; // set B-FLAG for long header
671702 dataPort.write (rtpMidi.flags );
672703 dataPort.write ((uint8_t )(bufferLen));
673704 }
0 commit comments