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);
_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<AlsaMidiBuffer*>(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<AlsaMidiEvent>(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<AlsaMidiEvent>& a, const boost::shared_ptr<AlsaMidiEvent>& 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<const AlsaMidiPort*>(*i)->const_buffer ();
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());
@ -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);
};

View File

@ -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<boost::shared_ptr<AlsaMidiEvent> > AlsaMidiBuffer;
typedef std::vector<AlsaMidiEvent> AlsaMidiBuffer;
class AlsaPort {
protected:

View File

@ -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 {

View File

@ -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));

View File

@ -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);