atsushieno / managed-midi

[Past project] Cross-platform MIDI processing library for mono and .NET (ALSA, CoreMIDI, Android, WinMM and UWP).

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ALSA: Cannot allocate memory

nametable opened this issue · comments

Host: Raspberry Pi 4
OS: Raspbian
Linux: raspberrypi 5.4.42-v7l+ #1319 SMP Wed May 20 14:12:03 BST 2020 armv7l GNU/Linux
DotNet Sdk: 3.1.300

Everything works fine using the following example code:

var access = MidiAccessManager.Default;
var output = access.OpenOutputAsync(access.Outputs.Last().Id).Result;
output.Send(new byte [] {0xC0, GeneralMidi.Instruments.AcousticGrandPiano}, 0, 2, 0); // There are constant fields for each GM instrument
output.Send(new byte [] {MidiEvent.NoteOn, 0x40, 0x70}, 0, 3, 0); // There are constant fields for each MIDI event
output.Send(new byte [] {MidiEvent.NoteOff, 0x40, 0x70}, 0, 3, 0);
output.Send(new byte [] {MidiEvent.Program, 0x30}, 0, 2, 0); // Strings Ensemble
output.Send(new byte [] {0x90, 0x40, 0x70}, 0, 3, 0);
output.Send(new byte [] {0x80, 0x40, 0x70}, 0, 3, 0);
output.CloseAsync();

However after I run this entire snippet repeatedly for many times (I'm not sure how many), I eventually get this error:
ALSA lib seq_hw.c:466:(snd_seq_hw_open) open /dev/snd/seq failed: Cannot allocate memory

I am wondering if the library is not cleaning up properly or if I should be holding a handle to output globally?

If it helps, I'm attempting to write a Blazor Wasm app with SignalR to be able to control a midi device remotely and I am at the very beginning stages (as in I just got the SignalR demo app running and pasted the above snippet in to run everytime I click a button in the webapp). I was very happy to see my usb midi device light up without very much effort so thank you for your work on this project.

For as far as I can see now, the ManageMidi code here is not at fault, it is the Alsa driver.

I'm guessing here, but it could be that closing the Alsa output device is an asynchronous process internally.
The implementation of CloseAsync suggests that it is synchronous, i.e. that the device is really closed after the method ends and the Alsa library itself also suggests it is synchronous (mind you, I took no more than a minute to look at the Alsa API, but if it is asynchronous, then they failed to mention it).
However, if this is not the case, (I don't know the internal Alsa implementation), then running your code repeatedly and fast after each other, may be trying to open the output device while it is still closing.
This may not be a supported use case for the Alsa driver.

In any case, if I were you, I would indeed hold a global handle to output.
There's no need to open and close it for every note you want to send.