From 836f4de4b9e86c685a2c4fc79c41b7b983e90d6f Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Sat, 21 Feb 2026 13:04:02 +0100 Subject: [PATCH 1/2] bulk push_back to Deque, fix typo fix Potential overflow in SSRC generation fix Loop/erase skipping a participant --- src/AppleMIDI.h | 4 ++- src/AppleMIDI.hpp | 60 +++++++++++++++++++++++++++++++-------------- src/utility/Deque.h | 35 ++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 20 deletions(-) diff --git a/src/AppleMIDI.h b/src/AppleMIDI.h index acd1d9a..336c115 100644 --- a/src/AppleMIDI.h +++ b/src/AppleMIDI.h @@ -52,6 +52,7 @@ class AppleMIDISession this->port = port; #ifdef KEEP_SESSION_NAME strncpy(this->localName, sessionName, Settings::MaxSessionNameLen); + this->localName[Settings::MaxSessionNameLen] = '\0'; #endif #ifdef ONE_PARTICIPANT @@ -117,6 +118,7 @@ class AppleMIDISession AppleMIDISession &setName(const char *sessionName) { strncpy(this->localName, sessionName, Settings::MaxSessionNameLen); + this->localName[Settings::MaxSessionNameLen] = '\0'; return *this; }; #else @@ -170,7 +172,7 @@ class AppleMIDISession // this is our SSRC // // NOTE: Arduino random only goes to INT32_MAX (not UINT32_MAX) - this->ssrc = random(1, INT32_MAX) * 2; + this->ssrc = random(1, INT32_MAX / 2) * 2; controlPort.begin(port); dataPort.begin(port + 1); diff --git a/src/AppleMIDI.hpp b/src/AppleMIDI.hpp index 54e860d..a91b090 100644 --- a/src/AppleMIDI.hpp +++ b/src/AppleMIDI.hpp @@ -1,6 +1,7 @@ #pragma once #include "AppleMIDI_Namespace.h" +#include BEGIN_APPLEMIDI_NAMESPACE @@ -17,8 +18,7 @@ size_t AppleMIDISession::readControlPackets() auto bytesRead = controlPort.read(packetBuffer, bytesToRead); packetSize -= bytesRead; - for (auto i = 0; i < bytesRead; i++) - controlBuffer.push_back(packetBuffer[i]); + controlBuffer.push_back(packetBuffer, bytesRead); } return controlBuffer.size(); @@ -65,8 +65,7 @@ size_t AppleMIDISession::readDataPackets() auto bytesRead = dataPort.read(packetBuffer, bytesToRead); packetSize -= bytesRead; - for (auto i = 0; i < bytesRead; i++) - dataBuffer.push_back(packetBuffer[i]); + dataBuffer.push_back(packetBuffer, bytesRead); } return dataBuffer.size(); @@ -149,6 +148,7 @@ void AppleMIDISession::ReceivedControlInvitation(A participant.lastSyncExchangeTime = now; #ifdef KEEP_SESSION_NAME strncpy(participant.sessionName, invitation.sessionName, Settings::MaxSessionNameLen); + participant.sessionName[Settings::MaxSessionNameLen] = '\0'; #endif #ifdef KEEP_SESSION_NAME @@ -690,10 +690,12 @@ void AppleMIDISession::writeRtpMidiBuffer(Particip return; } - // write rtp header - dataPort.write((uint8_t *)&rtp, sizeof(rtp)); + // Write RTP + rtpMIDI in a single packet to reduce overhead. + uint8_t packet[sizeof(Rtp) + 2 + Settings::MaxBufferSize]; + size_t offset = 0; + memcpy(packet + offset, &rtp, sizeof(rtp)); + offset += sizeof(rtp); - // Write rtpMIDI section RtpMIDI_t rtpMidi; // 0 1 2 3 @@ -711,21 +713,22 @@ void AppleMIDISession::writeRtpMidiBuffer(Particip { // Short header rtpMidi.flags |= (uint8_t)bufferLen; rtpMidi.flags &= ~RTP_MIDI_CS_FLAG_B; // short header, clear B-FLAG - dataPort.write(rtpMidi.flags); + packet[offset++] = rtpMidi.flags; } else { // Long header rtpMidi.flags |= (uint8_t)(bufferLen >> 8); rtpMidi.flags |= RTP_MIDI_CS_FLAG_B; // set B-FLAG for long header - dataPort.write(rtpMidi.flags); - dataPort.write((uint8_t)(bufferLen)); + packet[offset++] = rtpMidi.flags; + packet[offset++] = (uint8_t)(bufferLen); } // write out the MIDI Section for (size_t i = 0; i < bufferLen; i++) - dataPort.write(outMidiBuffer[i]); + packet[offset++] = outMidiBuffer[i]; // *No* journal section (Not supported) + dataPort.write(packet, offset); dataPort.endPacket(); dataPort.flush(); @@ -743,19 +746,28 @@ template void AppleMIDISession::manageSynchronization() { #ifndef ONE_PARTICIPANT - for (size_t i = 0; i < participants.size(); i++) + for (size_t i = 0; i < participants.size();) #endif { #ifndef ONE_PARTICIPANT auto pParticipant = &participants[i]; - if (pParticipant->ssrc == 0) continue; + if (pParticipant->ssrc == 0) + { + i++; + continue; + } #else auto pParticipant = &participant; if (pParticipant->ssrc == 0) return; #endif #ifdef APPLEMIDI_INITIATOR if (pParticipant->invitationStatus != Connected) + { +#ifndef ONE_PARTICIPANT + i++; +#endif continue; + } // Only for Initiators that are Connected if (pParticipant->kind == Listener) @@ -772,6 +784,7 @@ void AppleMIDISession::manageSynchronization() sendEndSession(pParticipant); #ifndef ONE_PARTICIPANT participants.erase(i); + continue; #else participant.ssrc = 0; #endif @@ -783,6 +796,9 @@ void AppleMIDISession::manageSynchronization() (pParticipant->synchronizing) ? manageSynchronizationInitiatorInvites(i) : manageSynchronizationInitiatorHeartBeat(pParticipant); } +#endif +#ifndef ONE_PARTICIPANT + i++; #endif } } @@ -882,7 +898,7 @@ template void AppleMIDISession::manageSessionInvites() { #ifndef ONE_PARTICIPANT - for (auto i = 0; i < participants.size(); i++) + for (auto i = 0; i < participants.size();) #endif { #ifndef ONE_PARTICIPANT @@ -893,7 +909,10 @@ void AppleMIDISession::manageSessionInvites() if (pParticipant->kind == Listener) #ifndef ONE_PARTICIPANT + { + i++; continue; + } #else return; #endif @@ -911,7 +930,10 @@ void AppleMIDISession::manageSessionInvites() if (pParticipant->invitationStatus == Connected) #ifndef ONE_PARTICIPANT + { + i++; continue; + } #else return; #endif @@ -930,12 +952,9 @@ void AppleMIDISession::manageSessionInvites() #ifndef ONE_PARTICIPANT participants.erase(i); -#else - participant.ssrc = 0; -#endif -#ifndef ONE_PARTICIPANT continue; #else + participant.ssrc = 0; return; #endif } @@ -964,6 +983,9 @@ void AppleMIDISession::manageSessionInvites() pParticipant->invitationStatus = AwaitingDataInvitationAccepted; } } +#ifndef ONE_PARTICIPANT + i++; +#endif } } @@ -1054,7 +1076,7 @@ void AppleMIDISession::sendEndSession() participants.pop_front(); } #else - if (participant.src != 0) + if (participant.ssrc != 0) { sendEndSession(&participant); participant.ssrc = 0; diff --git a/src/utility/Deque.h b/src/utility/Deque.h index 03848a0..ae20ca2 100644 --- a/src/utility/Deque.h +++ b/src/utility/Deque.h @@ -1,5 +1,7 @@ #pragma once +#include + BEGIN_APPLEMIDI_NAMESPACE template @@ -25,6 +27,7 @@ class Deque { const T & back() const; void push_front(const T &); void push_back(const T &); + size_t push_back(const T *, size_t); void pop_front(); void pop_back(); @@ -124,6 +127,38 @@ void Deque::push_back(const T &value) } } +template +size_t Deque::push_back(const T *values, size_t count) +{ + if (values == nullptr || count == 0) + return 0; + + const size_t available = free(); + if (available == 0) + return 0; + + const size_t toWrite = (count < available) ? count : available; + + if (empty()) + _tail = _head; + + size_t first = toWrite; + if (_head + first > Size) + first = Size - _head; + + memcpy(&_data[_head], values, first * sizeof(T)); + _head = (_head + first) % Size; + + const size_t remaining = toWrite - first; + if (remaining > 0) + { + memcpy(&_data[_head], values + first, remaining * sizeof(T)); + _head = (_head + remaining) % Size; + } + + return toWrite; +} + template void Deque::pop_front() { if (empty()) // if empty, do nothing. From 21e6f640b5911ee4c5d94d1201709e8dfd7fd157 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Sat, 21 Feb 2026 15:53:23 +0100 Subject: [PATCH 2/2] dded a bulk push_back to Deque and switched readControlPackets/readDataPackets to use it --- src/AppleMIDI.hpp | 3 +-- src/utility/Deque.h | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/AppleMIDI.hpp b/src/AppleMIDI.hpp index a91b090..3869045 100644 --- a/src/AppleMIDI.hpp +++ b/src/AppleMIDI.hpp @@ -724,8 +724,7 @@ void AppleMIDISession::writeRtpMidiBuffer(Particip } // write out the MIDI Section - for (size_t i = 0; i < bufferLen; i++) - packet[offset++] = outMidiBuffer[i]; + offset += outMidiBuffer.copy_out(packet + offset, bufferLen); // *No* journal section (Not supported) dataPort.write(packet, offset); diff --git a/src/utility/Deque.h b/src/utility/Deque.h index ae20ca2..a66d117 100644 --- a/src/utility/Deque.h +++ b/src/utility/Deque.h @@ -28,6 +28,7 @@ class Deque { void push_front(const T &); void push_back(const T &); size_t push_back(const T *, size_t); + size_t copy_out(T *, size_t) const; void pop_front(); void pop_back(); @@ -159,6 +160,32 @@ size_t Deque::push_back(const T *values, size_t count) return toWrite; } +template +size_t Deque::copy_out(T *dest, size_t count) const +{ + if (dest == nullptr || count == 0) + return 0; + + const size_t available = size(); + if (available == 0) + return 0; + + const size_t toCopy = (count < available) ? count : available; + const size_t start = (size_t)_tail; + + size_t first = toCopy; + if (start + first > Size) + first = Size - start; + + memcpy(dest, &_data[start], first * sizeof(T)); + + const size_t remaining = toCopy - first; + if (remaining > 0) + memcpy(dest + first, &_data[0], remaining * sizeof(T)); + + return toCopy; +} + template void Deque::pop_front() { if (empty()) // if empty, do nothing.