ALSA backend RT-safe MIDI buffer allocation

This commit is contained in:
Robin Gareus 2017-08-05 15:03:06 +02:00
parent 2b7c585dba
commit 59a63a08f9
5 changed files with 42 additions and 45 deletions

View file

@ -77,6 +77,8 @@ AlsaAudioBackend::AlsaAudioBackend (AudioEngine& e, AudioBackendInfo& info)
pthread_mutex_init (&_port_callback_mutex, 0); pthread_mutex_init (&_port_callback_mutex, 0);
_input_audio_device_info.valid = false; _input_audio_device_info.valid = false;
_output_audio_device_info.valid = false; _output_audio_device_info.valid = false;
_port_connection_queue.reserve (128);
} }
AlsaAudioBackend::~AlsaAudioBackend () AlsaAudioBackend::~AlsaAudioBackend ()
@ -1693,11 +1695,11 @@ AlsaAudioBackend::midi_event_get (
if (event_index >= source.size ()) { if (event_index >= source.size ()) {
return -1; return -1;
} }
AlsaMidiEvent * const event = source[event_index].get (); AlsaMidiEvent const& event = source[event_index];
timestamp = event->timestamp (); timestamp = event.timestamp ();
size = event->size (); size = event.size ();
*buf = event->data (); *buf = event.data ();
return 0; return 0;
} }
@ -1708,15 +1710,18 @@ AlsaAudioBackend::midi_event_put (
const uint8_t* buffer, size_t size) const uint8_t* buffer, size_t size)
{ {
assert (buffer && port_buffer); assert (buffer && port_buffer);
if (size >= MaxAlsaMidiEventSize) {
return -1;
}
AlsaMidiBuffer& dst = * static_cast<AlsaMidiBuffer*>(port_buffer); AlsaMidiBuffer& dst = * static_cast<AlsaMidiBuffer*>(port_buffer);
if (dst.size () && (pframes_t)dst.back ()->timestamp () > timestamp) {
#ifndef NDEBUG #ifndef NDEBUG
if (dst.size () && (pframes_t)dst.back ().timestamp () > timestamp) {
// nevermind, ::get_buffer() sorts events // nevermind, ::get_buffer() sorts events
fprintf (stderr, "AlsaMidiBuffer: it's too late for this event. %d > %d\n", fprintf (stderr, "AlsaMidiBuffer: it's too late for this event. %d > %d\n",
(pframes_t)dst.back ()->timestamp (), timestamp); (pframes_t)dst.back ().timestamp (), timestamp);
#endif
} }
dst.push_back (boost::shared_ptr<AlsaMidiEvent>(new AlsaMidiEvent (timestamp, buffer, size))); #endif
dst.push_back (AlsaMidiEvent (timestamp, buffer, size));
return 0; return 0;
} }
@ -1949,7 +1954,7 @@ AlsaAudioBackend::main_process_thread ()
AlsaMidiIn *rm = _rmidi_in.at(i); AlsaMidiIn *rm = _rmidi_in.at(i);
void *bptr = (*it)->get_buffer(0); void *bptr = (*it)->get_buffer(0);
pframes_t time; pframes_t time;
uint8_t data[64]; // match MaxAlsaEventSize in alsa_rawmidi.cc uint8_t data[MaxAlsaMidiEventSize];
size_t size = sizeof(data); size_t size = sizeof(data);
midi_clear(bptr); midi_clear(bptr);
while (rm->recv_event (time, data, size)) { while (rm->recv_event (time, data, size)) {
@ -1983,7 +1988,7 @@ AlsaAudioBackend::main_process_thread ()
AlsaMidiOut *rm = _rmidi_out.at(i); AlsaMidiOut *rm = _rmidi_out.at(i);
rm->sync_time (clock1); rm->sync_time (clock1);
for (AlsaMidiBuffer::const_iterator mit = src->begin (); mit != src->end (); ++mit) { 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[0].clear ();
_buffer[1].clear (); _buffer[1].clear ();
_buffer[2].clear ();
_buffer[0].reserve(256);
_buffer[1].reserve(256);
_buffer[2].reserve(256);
} }
AlsaMidiPort::~AlsaMidiPort () { } AlsaMidiPort::~AlsaMidiPort () { }
struct MidiEventSorter { struct MidiEventSorter {
bool operator() (const boost::shared_ptr<AlsaMidiEvent>& a, const boost::shared_ptr<AlsaMidiEvent>& b) { bool operator() (AlsaMidiEvent const& a, AlsaMidiEvent const& b) {
return *a < *b; return a < b;
} }
}; };
@ -2341,7 +2351,7 @@ void* AlsaMidiPort::get_buffer (pframes_t /* nframes */)
++i) { ++i) {
const AlsaMidiBuffer * src = static_cast<const AlsaMidiPort*>(*i)->const_buffer (); const AlsaMidiBuffer * src = static_cast<const AlsaMidiPort*>(*i)->const_buffer ();
for (AlsaMidiBuffer::const_iterator it = src->begin (); it != src->end (); ++it) { for (AlsaMidiBuffer::const_iterator it = src->begin (); it != src->end (); ++it) {
(_buffer[_bufperiod]).push_back (boost::shared_ptr<AlsaMidiEvent>(new AlsaMidiEvent (**it))); (_buffer[_bufperiod]).push_back (*it);
} }
} }
std::stable_sort ((_buffer[_bufperiod]).begin (), (_buffer[_bufperiod]).end (), MidiEventSorter()); 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) AlsaMidiEvent::AlsaMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size)
: _size (size) : _size (size)
, _timestamp (timestamp) , _timestamp (timestamp)
, _data (0)
{ {
if (size > 0) { if (size > 0 && size < MaxAlsaMidiEventSize) {
_data = (uint8_t*) malloc (size);
memcpy (_data, data, size); memcpy (_data, data, size);
} }
} }
@ -2363,14 +2371,9 @@ AlsaMidiEvent::AlsaMidiEvent (const pframes_t timestamp, const uint8_t* data, si
AlsaMidiEvent::AlsaMidiEvent (const AlsaMidiEvent& other) AlsaMidiEvent::AlsaMidiEvent (const AlsaMidiEvent& other)
: _size (other.size ()) : _size (other.size ())
, _timestamp (other.timestamp ()) , _timestamp (other.timestamp ())
, _data (0)
{ {
if (other.size () && other.const_data ()) { if (other._size > 0) {
_data = (uint8_t*) malloc (other.size ()); assert (other._size < MaxAlsaMidiEventSize);
memcpy (_data, other.const_data (), other.size ()); memcpy (_data, other._data, other._size);
} }
}; };
AlsaMidiEvent::~AlsaMidiEvent () {
free (_data);
};

View file

@ -50,19 +50,17 @@ class AlsaMidiEvent {
public: public:
AlsaMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size); AlsaMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size);
AlsaMidiEvent (const AlsaMidiEvent& other); AlsaMidiEvent (const AlsaMidiEvent& other);
~AlsaMidiEvent ();
size_t size () const { return _size; }; size_t size () const { return _size; };
pframes_t timestamp () const { return _timestamp; }; pframes_t timestamp () const { return _timestamp; };
const unsigned char* const_data () const { return _data; }; const uint8_t* data () const { return _data; };
unsigned char* data () { return _data; };
bool operator< (const AlsaMidiEvent &other) const { return timestamp () < other.timestamp (); }; bool operator< (const AlsaMidiEvent &other) const { return timestamp () < other.timestamp (); };
private: private:
size_t _size; size_t _size;
pframes_t _timestamp; pframes_t _timestamp;
uint8_t *_data; uint8_t _data[MaxAlsaMidiEventSize];
}; };
typedef std::vector<boost::shared_ptr<AlsaMidiEvent> > AlsaMidiBuffer; typedef std::vector<AlsaMidiEvent> AlsaMidiBuffer;
class AlsaPort { class AlsaPort {
protected: protected:

View file

@ -26,6 +26,10 @@
#include "pbd/ringbuffer.h" #include "pbd/ringbuffer.h"
#include "ardour/types.h" #include "ardour/types.h"
/* max bytes per individual midi-event
* events larger than this are ignored */
#define MaxAlsaMidiEventSize (64)
namespace ARDOUR { namespace ARDOUR {
class AlsaMidiIO { class AlsaMidiIO {

View file

@ -28,10 +28,6 @@
using namespace ARDOUR; using namespace ARDOUR;
/* max bytes per individual midi-event
* events larger than this are ignored */
#define MaxAlsaRawEventSize (64)
#ifndef NDEBUG #ifndef NDEBUG
#define _DEBUGPRINT(STR) fprintf(stderr, STR); #define _DEBUGPRINT(STR) fprintf(stderr, STR);
#else #else
@ -123,7 +119,7 @@ AlsaRawMidiOut::main_process_thread ()
while (_running) { while (_running) {
bool have_data = false; bool have_data = false;
struct MidiEventHeader h(0,0); struct MidiEventHeader h(0,0);
uint8_t data[MaxAlsaRawEventSize]; uint8_t data[MaxAlsaMidiEventSize];
const uint32_t read_space = _rb->read_space(); const uint32_t read_space = _rb->read_space();
@ -133,7 +129,7 @@ AlsaRawMidiOut::main_process_thread ()
break; break;
} }
assert (read_space >= h.size); assert (read_space >= h.size);
if (h.size > MaxAlsaRawEventSize) { if (h.size > MaxAlsaMidiEventSize) {
_rb->increment_read_idx (h.size); _rb->increment_read_idx (h.size);
_DEBUGPRINT("AlsaRawMidiOut: MIDI event too large!\n"); _DEBUGPRINT("AlsaRawMidiOut: MIDI event too large!\n");
continue; continue;
@ -280,7 +276,7 @@ AlsaRawMidiIn::main_process_thread ()
continue; continue;
} }
uint8_t data[MaxAlsaRawEventSize]; uint8_t data[MaxAlsaMidiEventSize];
uint64_t time = g_get_monotonic_time(); uint64_t time = g_get_monotonic_time();
ssize_t err = snd_rawmidi_read (_device, data, sizeof(data)); ssize_t err = snd_rawmidi_read (_device, data, sizeof(data));

View file

@ -27,10 +27,6 @@
using namespace ARDOUR; using namespace ARDOUR;
/* max bytes per individual midi-event
* events larger than this are ignored */
#define MaxAlsaSeqEventSize (64)
#ifndef NDEBUG #ifndef NDEBUG
#define _DEBUGPRINT(STR) fprintf(stderr, STR); #define _DEBUGPRINT(STR) fprintf(stderr, STR);
#else #else
@ -130,12 +126,12 @@ AlsaSeqMidiOut::main_process_thread ()
_running = true; _running = true;
bool need_drain = false; bool need_drain = false;
snd_midi_event_t *alsa_codec = NULL; 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); pthread_mutex_lock (&_notify_mutex);
while (_running) { while (_running) {
bool have_data = false; bool have_data = false;
struct MidiEventHeader h(0,0); struct MidiEventHeader h(0,0);
uint8_t data[MaxAlsaSeqEventSize]; uint8_t data[MaxAlsaMidiEventSize];
const uint32_t read_space = _rb->read_space(); const uint32_t read_space = _rb->read_space();
@ -145,7 +141,7 @@ AlsaSeqMidiOut::main_process_thread ()
break; break;
} }
assert (read_space >= h.size); assert (read_space >= h.size);
if (h.size > MaxAlsaSeqEventSize) { if (h.size > MaxAlsaMidiEventSize) {
_rb->increment_read_idx (h.size); _rb->increment_read_idx (h.size);
_DEBUGPRINT("AlsaSeqMidiOut: MIDI event too large!\n"); _DEBUGPRINT("AlsaSeqMidiOut: MIDI event too large!\n");
continue; continue;
@ -240,7 +236,7 @@ AlsaSeqMidiIn::main_process_thread ()
_running = true; _running = true;
bool do_poll = true; bool do_poll = true;
snd_midi_event_t *alsa_codec = NULL; snd_midi_event_t *alsa_codec = NULL;
snd_midi_event_new (MaxAlsaSeqEventSize, &alsa_codec); snd_midi_event_new (MaxAlsaMidiEventSize, &alsa_codec);
while (_running) { while (_running) {
@ -275,7 +271,7 @@ AlsaSeqMidiIn::main_process_thread ()
break; break;
} }
uint8_t data[MaxAlsaSeqEventSize]; uint8_t data[MaxAlsaMidiEventSize];
snd_midi_event_reset_decode (alsa_codec); snd_midi_event_reset_decode (alsa_codec);
ssize_t size = snd_midi_event_decode (alsa_codec, data, sizeof(data), event); ssize_t size = snd_midi_event_decode (alsa_codec, data, sizeof(data), event);