cs-midi/MIDI_Interfaces/AppleMIDI/vendor/rtpMIDI_Parser_JournalSecti...

181 lines
6.4 KiB
C++

// The recovery journal is the default resiliency tool for unreliable
// transport. In this section, we normatively define the roles that
// senders and receivers play in the recovery journal system.
//
// This section introduces the structure of the recovery journal and
// defines the bitfields of recovery journal headers. Appendices A and
// B complete the bitfield definition of the recovery journal.
//
// The recovery journal has a three-level structure:
//
// o Top-level header.
//
// o Channel and system journal headers. These headers encode recovery
// information for a single voice channel (channel journal) or for
// all system commands (system journal).
//
// o Chapters. Chapters describe recovery information for a single
// MIDI command type.
//
parserReturn decodeJournalSection(RtpBuffer_t &buffer)
{
size_t minimumLen = 0;
conversionBuffer cb;
if (false == _journalSectionComplete)
{
size_t i = 0;
// Minimum size for the Journal section is 3
minimumLen += 3;
if (buffer.size() < minimumLen)
return parserReturn::NotEnoughData;
/* lets get the main flags from the recovery journal header */
uint8_t flags = buffer[i++];
// The 16-bit Checkpoint Packet Seqnum header field codes the sequence
// number of the checkpoint packet for this journal, in network byte
// order (big-endian). The choice of the checkpoint packet sets the
// depth of the checkpoint history for the journal (defined in Appendix A.1).
//
// Receivers may use the Checkpoint Packet Seqnum field of the packet
// that ends a loss event to verify that the journal checkpoint history
// covers the entire loss event. The checkpoint history covers the loss
// event if the Checkpoint Packet Seqnum field is less than or equal to
// one plus the highest RTP sequence number previously received on the
// stream (modulo 2^16).
cb.buffer[0] = buffer[i++];
cb.buffer[1] = buffer[i++];
// uint16_t checkPoint = __ntohs(cb.value16); ; // unused
// (RFC 4695, 5 Recovery Journal Format)
// If A and Y are both zero, the recovery journal only contains its 3-
// octet header and is considered to be an "empty" journal.
if ((flags & RTP_MIDI_JS_FLAG_Y) == 0 && (flags & RTP_MIDI_JS_FLAG_A) == 0)
{
// Big fixed by @hugbug
while (minimumLen-- > 0)
buffer.pop_front();
_journalSectionComplete = true;
return parserReturn::Processed;
}
// By default, the payload format does not use enhanced Chapter C
// encoding. In this default case, the H bit MUST be set to 0 for all
// packets in the stream.
if (flags & RTP_MIDI_JS_FLAG_H)
{
// The H bit indicates if MIDI channels in the stream have been
// configured to use the enhanced Chapter C encoding
}
// The S (single-packet loss) bit appears in most recovery journal
// structures, including the recovery journal header. The S bit helps
// receivers efficiently parse the recovery journal in the common case
// of the loss of a single packet.
if (flags & RTP_MIDI_JS_FLAG_S)
{
// special encoding
}
// If the Y header bit is set to 1, the system journal appears in the
// recovery journal, directly following the recovery journal header.
if (flags & RTP_MIDI_JS_FLAG_Y)
{
minimumLen += 2;
if (buffer.size() < minimumLen)
{
return parserReturn::NotEnoughData;
}
cb.buffer[0] = buffer[i++];
cb.buffer[1] = buffer[i++];
uint16_t systemflags = __ntohs(cb.value16);
uint16_t sysjourlen = systemflags & RTP_MIDI_SJ_MASK_LENGTH;
uint16_t remainingBytes = sysjourlen - 2;
minimumLen += remainingBytes;
if (buffer.size() < minimumLen)
{
return parserReturn::NotEnoughData;
}
i += remainingBytes;
}
// If the A header bit is set to 1, the recovery journal ends with a
// list of (TOTCHAN + 1) channel journals (the 4-bit TOTCHAN header
// field is interpreted as an unsigned integer).
if (flags & RTP_MIDI_JS_FLAG_A)
{
/* At the same place we find the total channels encoded in the channel journal */
_journalTotalChannels = (flags & RTP_MIDI_JS_MASK_TOTALCHANNELS) + 1;
}
while (i-- > 0) // is that the same as while (i--) ??
buffer.pop_front();
_journalSectionComplete = true;
}
// iterate through all the channels specified in header
while (_journalTotalChannels > 0)
{
if (false == _channelJournalSectionComplete) {
if (buffer.size() < 3)
return parserReturn::NotEnoughData;
// 3 bytes for channel journal
cb.buffer[0] = 0x00;
cb.buffer[1] = buffer[0];
cb.buffer[2] = buffer[1];
cb.buffer[3] = buffer[2];
uint32_t chanflags = __ntohl(cb.value32);
bool S_flag = (chanflags & RTP_MIDI_CJ_FLAG_S) == 1;
uint8_t channelNr = (chanflags & RTP_MIDI_CJ_MASK_CHANNEL) >> RTP_MIDI_CJ_CHANNEL_SHIFT;
bool H_flag = (chanflags & RTP_MIDI_CJ_FLAG_H) == 1;
uint8_t chanjourlen = (chanflags & RTP_MIDI_CJ_MASK_LENGTH) >> 8;
if ((chanflags & RTP_MIDI_CJ_FLAG_P)) {
}
if ((chanflags & RTP_MIDI_CJ_FLAG_C)) {
}
if ((chanflags & RTP_MIDI_CJ_FLAG_M)) {
}
if ((chanflags & RTP_MIDI_CJ_FLAG_W)) {
}
if ((chanflags & RTP_MIDI_CJ_FLAG_N)) {
}
if ((chanflags & RTP_MIDI_CJ_FLAG_E)) {
}
if ((chanflags & RTP_MIDI_CJ_FLAG_T)) {
}
if ((chanflags & RTP_MIDI_CJ_FLAG_A)) {
}
_bytesToFlush = chanjourlen;
_channelJournalSectionComplete = true;
}
while (buffer.size() > 0 && _bytesToFlush > 0) {
_bytesToFlush--;
buffer.pop_front();
}
if (_bytesToFlush > 0) {
return parserReturn::NotEnoughData;
}
_journalTotalChannels--;
}
return parserReturn::Processed;
}