From 59a63a08f99e1cb17ba5775afa4ad514cc5b163f Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Sat, 5 Aug 2017 15:03:06 +0200 Subject: ALSA backend RT-safe MIDI buffer allocation --- libs/backends/alsa/alsa_audiobackend.cc | 51 +++++++++++++++++---------------- libs/backends/alsa/alsa_audiobackend.h | 8 ++---- libs/backends/alsa/alsa_midi.h | 4 +++ libs/backends/alsa/alsa_rawmidi.cc | 10 ++----- libs/backends/alsa/alsa_sequencer.cc | 14 ++++----- 5 files changed, 42 insertions(+), 45 deletions(-) diff --git a/libs/backends/alsa/alsa_audiobackend.cc b/libs/backends/alsa/alsa_audiobackend.cc index 9d3dc96f43..e7cdfedcb9 100644 --- a/libs/backends/alsa/alsa_audiobackend.cc +++ b/libs/backends/alsa/alsa_audiobackend.cc @@ -77,6 +77,8 @@ AlsaAudioBackend::AlsaAudioBackend (AudioEngine& e, AudioBackendInfo& info) pthread_mutex_init (&_port_callback_mutex, 0); _input_audio_device_info.valid = false; _output_audio_device_info.valid = false; + + _port_connection_queue.reserve (128); } AlsaAudioBackend::~AlsaAudioBackend () @@ -1693,11 +1695,11 @@ AlsaAudioBackend::midi_event_get ( if (event_index >= source.size ()) { return -1; } - AlsaMidiEvent * const event = source[event_index].get (); + AlsaMidiEvent const& event = source[event_index]; - timestamp = event->timestamp (); - size = event->size (); - *buf = event->data (); + timestamp = event.timestamp (); + size = event.size (); + *buf = event.data (); return 0; } @@ -1708,15 +1710,18 @@ AlsaAudioBackend::midi_event_put ( const uint8_t* buffer, size_t size) { assert (buffer && port_buffer); + if (size >= MaxAlsaMidiEventSize) { + return -1; + } AlsaMidiBuffer& dst = * static_cast(port_buffer); - if (dst.size () && (pframes_t)dst.back ()->timestamp () > timestamp) { #ifndef NDEBUG + if (dst.size () && (pframes_t)dst.back ().timestamp () > timestamp) { // nevermind, ::get_buffer() sorts events fprintf (stderr, "AlsaMidiBuffer: it's too late for this event. %d > %d\n", - (pframes_t)dst.back ()->timestamp (), timestamp); -#endif + (pframes_t)dst.back ().timestamp (), timestamp); } - dst.push_back (boost::shared_ptr(new AlsaMidiEvent (timestamp, buffer, size))); +#endif + dst.push_back (AlsaMidiEvent (timestamp, buffer, size)); return 0; } @@ -1949,7 +1954,7 @@ AlsaAudioBackend::main_process_thread () AlsaMidiIn *rm = _rmidi_in.at(i); void *bptr = (*it)->get_buffer(0); pframes_t time; - uint8_t data[64]; // match MaxAlsaEventSize in alsa_rawmidi.cc + uint8_t data[MaxAlsaMidiEventSize]; size_t size = sizeof(data); midi_clear(bptr); while (rm->recv_event (time, data, size)) { @@ -1983,7 +1988,7 @@ AlsaAudioBackend::main_process_thread () AlsaMidiOut *rm = _rmidi_out.at(i); rm->sync_time (clock1); for (AlsaMidiBuffer::const_iterator mit = src->begin (); mit != src->end (); ++mit) { - rm->send_event ((*mit)->timestamp(), (*mit)->data(), (*mit)->size()); + rm->send_event (mit->timestamp (), mit->data (), mit->size ()); } } @@ -2321,13 +2326,18 @@ AlsaMidiPort::AlsaMidiPort (AlsaAudioBackend &b, const std::string& name, PortFl { _buffer[0].clear (); _buffer[1].clear (); + _buffer[2].clear (); + + _buffer[0].reserve(256); + _buffer[1].reserve(256); + _buffer[2].reserve(256); } AlsaMidiPort::~AlsaMidiPort () { } struct MidiEventSorter { - bool operator() (const boost::shared_ptr& a, const boost::shared_ptr& b) { - return *a < *b; + bool operator() (AlsaMidiEvent const& a, AlsaMidiEvent const& b) { + return a < b; } }; @@ -2341,7 +2351,7 @@ void* AlsaMidiPort::get_buffer (pframes_t /* nframes */) ++i) { const AlsaMidiBuffer * src = static_cast(*i)->const_buffer (); for (AlsaMidiBuffer::const_iterator it = src->begin (); it != src->end (); ++it) { - (_buffer[_bufperiod]).push_back (boost::shared_ptr(new AlsaMidiEvent (**it))); + (_buffer[_bufperiod]).push_back (*it); } } std::stable_sort ((_buffer[_bufperiod]).begin (), (_buffer[_bufperiod]).end (), MidiEventSorter()); @@ -2352,10 +2362,8 @@ void* AlsaMidiPort::get_buffer (pframes_t /* nframes */) AlsaMidiEvent::AlsaMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size) : _size (size) , _timestamp (timestamp) - , _data (0) { - if (size > 0) { - _data = (uint8_t*) malloc (size); + if (size > 0 && size < MaxAlsaMidiEventSize) { memcpy (_data, data, size); } } @@ -2363,14 +2371,9 @@ AlsaMidiEvent::AlsaMidiEvent (const pframes_t timestamp, const uint8_t* data, si AlsaMidiEvent::AlsaMidiEvent (const AlsaMidiEvent& other) : _size (other.size ()) , _timestamp (other.timestamp ()) - , _data (0) { - if (other.size () && other.const_data ()) { - _data = (uint8_t*) malloc (other.size ()); - memcpy (_data, other.const_data (), other.size ()); + if (other._size > 0) { + assert (other._size < MaxAlsaMidiEventSize); + memcpy (_data, other._data, other._size); } }; - -AlsaMidiEvent::~AlsaMidiEvent () { - free (_data); -}; diff --git a/libs/backends/alsa/alsa_audiobackend.h b/libs/backends/alsa/alsa_audiobackend.h index 97cba16ba5..c175a1950b 100644 --- a/libs/backends/alsa/alsa_audiobackend.h +++ b/libs/backends/alsa/alsa_audiobackend.h @@ -50,19 +50,17 @@ class AlsaMidiEvent { public: AlsaMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size); AlsaMidiEvent (const AlsaMidiEvent& other); - ~AlsaMidiEvent (); size_t size () const { return _size; }; pframes_t timestamp () const { return _timestamp; }; - const unsigned char* const_data () const { return _data; }; - unsigned char* data () { return _data; }; + const uint8_t* data () const { return _data; }; bool operator< (const AlsaMidiEvent &other) const { return timestamp () < other.timestamp (); }; private: size_t _size; pframes_t _timestamp; - uint8_t *_data; + uint8_t _data[MaxAlsaMidiEventSize]; }; -typedef std::vector > AlsaMidiBuffer; +typedef std::vector AlsaMidiBuffer; class AlsaPort { protected: diff --git a/libs/backends/alsa/alsa_midi.h b/libs/backends/alsa/alsa_midi.h index 254835591f..7aa2af95c3 100644 --- a/libs/backends/alsa/alsa_midi.h +++ b/libs/backends/alsa/alsa_midi.h @@ -26,6 +26,10 @@ #include "pbd/ringbuffer.h" #include "ardour/types.h" +/* max bytes per individual midi-event + * events larger than this are ignored */ +#define MaxAlsaMidiEventSize (64) + namespace ARDOUR { class AlsaMidiIO { diff --git a/libs/backends/alsa/alsa_rawmidi.cc b/libs/backends/alsa/alsa_rawmidi.cc index 8d2420a6cb..68d8808679 100644 --- a/libs/backends/alsa/alsa_rawmidi.cc +++ b/libs/backends/alsa/alsa_rawmidi.cc @@ -28,10 +28,6 @@ using namespace ARDOUR; -/* max bytes per individual midi-event - * events larger than this are ignored */ -#define MaxAlsaRawEventSize (64) - #ifndef NDEBUG #define _DEBUGPRINT(STR) fprintf(stderr, STR); #else @@ -123,7 +119,7 @@ AlsaRawMidiOut::main_process_thread () while (_running) { bool have_data = false; struct MidiEventHeader h(0,0); - uint8_t data[MaxAlsaRawEventSize]; + uint8_t data[MaxAlsaMidiEventSize]; const uint32_t read_space = _rb->read_space(); @@ -133,7 +129,7 @@ AlsaRawMidiOut::main_process_thread () break; } assert (read_space >= h.size); - if (h.size > MaxAlsaRawEventSize) { + if (h.size > MaxAlsaMidiEventSize) { _rb->increment_read_idx (h.size); _DEBUGPRINT("AlsaRawMidiOut: MIDI event too large!\n"); continue; @@ -280,7 +276,7 @@ AlsaRawMidiIn::main_process_thread () continue; } - uint8_t data[MaxAlsaRawEventSize]; + uint8_t data[MaxAlsaMidiEventSize]; uint64_t time = g_get_monotonic_time(); ssize_t err = snd_rawmidi_read (_device, data, sizeof(data)); diff --git a/libs/backends/alsa/alsa_sequencer.cc b/libs/backends/alsa/alsa_sequencer.cc index a9c3adf4fa..036ea5abc6 100644 --- a/libs/backends/alsa/alsa_sequencer.cc +++ b/libs/backends/alsa/alsa_sequencer.cc @@ -27,10 +27,6 @@ using namespace ARDOUR; -/* max bytes per individual midi-event - * events larger than this are ignored */ -#define MaxAlsaSeqEventSize (64) - #ifndef NDEBUG #define _DEBUGPRINT(STR) fprintf(stderr, STR); #else @@ -130,12 +126,12 @@ AlsaSeqMidiOut::main_process_thread () _running = true; bool need_drain = false; snd_midi_event_t *alsa_codec = NULL; - snd_midi_event_new (MaxAlsaSeqEventSize, &alsa_codec); + snd_midi_event_new (MaxAlsaMidiEventSize, &alsa_codec); pthread_mutex_lock (&_notify_mutex); while (_running) { bool have_data = false; struct MidiEventHeader h(0,0); - uint8_t data[MaxAlsaSeqEventSize]; + uint8_t data[MaxAlsaMidiEventSize]; const uint32_t read_space = _rb->read_space(); @@ -145,7 +141,7 @@ AlsaSeqMidiOut::main_process_thread () break; } assert (read_space >= h.size); - if (h.size > MaxAlsaSeqEventSize) { + if (h.size > MaxAlsaMidiEventSize) { _rb->increment_read_idx (h.size); _DEBUGPRINT("AlsaSeqMidiOut: MIDI event too large!\n"); continue; @@ -240,7 +236,7 @@ AlsaSeqMidiIn::main_process_thread () _running = true; bool do_poll = true; snd_midi_event_t *alsa_codec = NULL; - snd_midi_event_new (MaxAlsaSeqEventSize, &alsa_codec); + snd_midi_event_new (MaxAlsaMidiEventSize, &alsa_codec); while (_running) { @@ -275,7 +271,7 @@ AlsaSeqMidiIn::main_process_thread () break; } - uint8_t data[MaxAlsaSeqEventSize]; + uint8_t data[MaxAlsaMidiEventSize]; snd_midi_event_reset_decode (alsa_codec); ssize_t size = snd_midi_event_decode (alsa_codec, data, sizeof(data), event); -- cgit v1.2.3