aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backends/midi/alsa.cpp76
1 files changed, 51 insertions, 25 deletions
diff --git a/backends/midi/alsa.cpp b/backends/midi/alsa.cpp
index 2b36cdc3cf..4f73d7384b 100644
--- a/backends/midi/alsa.cpp
+++ b/backends/midi/alsa.cpp
@@ -48,6 +48,17 @@
#define my_snd_seq_open(seqp) snd_seq_open(seqp, SND_SEQ_OPEN)
#endif
+#define perm_ok(pinfo,bits) ((snd_seq_port_info_get_capability(pinfo) & (bits)) == (bits))
+
+static int check_permission(snd_seq_port_info_t *pinfo)
+{
+ if (perm_ok(pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE)) {
+ if (!(snd_seq_port_info_get_capability(pinfo) & SND_SEQ_PORT_CAP_NO_EXPORT))
+ return 1;
+ }
+ return 0;
+}
+
/*
* parse address string
*/
@@ -109,7 +120,41 @@ int MidiDriver_ALSA::open() {
}
if (seq_client != SND_SEQ_ADDRESS_SUBSCRIBERS) {
- // subscribe to MIDI port
+ // Subscribe to MIDI port. Prefer one that doesn't already have
+ // any connections, unless we've forced a port number already.
+ if (seq_port == -1) {
+ snd_seq_client_info_t *cinfo;
+ snd_seq_port_info_t *pinfo;
+
+ snd_seq_client_info_alloca(&cinfo);
+ snd_seq_port_info_alloca(&pinfo);
+
+ snd_seq_get_any_client_info(seq_handle, seq_client, cinfo);
+
+ int first_port = -1;
+ int found_port = -1;
+
+ snd_seq_port_info_set_client(pinfo, seq_client);
+ snd_seq_port_info_set_port(pinfo, -1);
+ while (found_port == -1 && snd_seq_query_next_port(seq_handle, pinfo) >= 0) {
+ if (check_permission(pinfo)) {
+ if (first_port == -1)
+ first_port = snd_seq_port_info_get_port(pinfo);
+ if (found_port == -1 && snd_seq_port_info_get_write_use(pinfo) == 0)
+ found_port = snd_seq_port_info_get_port(pinfo);
+ }
+ }
+
+ if (found_port == -1) {
+ // Should we abort here? For now, use the first
+ // available port.
+ seq_port = first_port;
+ warning("MidiDriver_ALSA: All ports on client %d (%s) are already in use", seq_client, snd_seq_client_info_get_name(cinfo));
+ } else {
+ seq_port = found_port;
+ }
+ }
+
if (snd_seq_connect_to(seq_handle, my_port, seq_client, seq_port) < 0) {
error("Can't subscribe to MIDI port (%d:%d) see README for help", seq_client, seq_port);
}
@@ -217,23 +262,21 @@ void MidiDriver_ALSA::send_event(int do_flush) {
class AlsaDevice {
public:
- AlsaDevice(Common::String name, MusicType mt, int client, int port);
+ AlsaDevice(Common::String name, MusicType mt, int client);
Common::String getName();
MusicType getType();
int getClient();
- int getPort();
private:
Common::String _name;
MusicType _type;
int _client;
- int _port;
};
typedef Common::List<AlsaDevice> AlsaDevices;
-AlsaDevice::AlsaDevice(Common::String name, MusicType mt, int client, int port)
- : _name(name), _type(mt), _client(client), _port(port) {
+AlsaDevice::AlsaDevice(Common::String name, MusicType mt, int client)
+ : _name(name), _type(mt), _client(client) {
}
Common::String AlsaDevice::getName() {
@@ -248,10 +291,6 @@ int AlsaDevice::getClient() {
return _client;
}
-int AlsaDevice::getPort() {
- return _port;
-}
-
class AlsaMusicPlugin : public MusicPluginObject {
public:
const char *getName() const {
@@ -270,17 +309,6 @@ private:
static int parse_addr(const char *arg, int *client, int *port);
};
-#define perm_ok(pinfo,bits) ((snd_seq_port_info_get_capability(pinfo) & (bits)) == (bits))
-
-static int check_permission(snd_seq_port_info_t *pinfo)
-{
- if (perm_ok(pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE)) {
- if (!(snd_seq_port_info_get_capability(pinfo) & SND_SEQ_PORT_CAP_NO_EXPORT))
- return 1;
- }
- return 0;
-}
-
AlsaDevices AlsaMusicPlugin::getAlsaDevices() const {
AlsaDevices devices;
snd_seq_t *seq_handle;
@@ -306,9 +334,7 @@ AlsaDevices AlsaMusicPlugin::getAlsaDevices() const {
// TODO: Can we figure out the appropriate music type?
MusicType type = MT_GM;
int client = snd_seq_client_info_get_client(cinfo);
- int port = snd_seq_port_info_get_port(pinfo);
-
- devices.push_back(AlsaDevice(name, type, client, port));
+ devices.push_back(AlsaDevice(name, type, client));
}
}
}
@@ -395,7 +421,7 @@ Common::Error AlsaMusicPlugin::createInstance(MidiDriver **mididriver, MidiDrive
if (device.getCompleteId().equals(MidiDriver::getDeviceString(dev, MidiDriver::kDeviceId))) {
found = true;
seq_client = d->getClient();
- seq_port = d->getPort();
+ seq_port = -1;
break;
}
}