Skip to content

Commit

Permalink
Expose BLE-MIDI server as a local ALSA sequencer
Browse files Browse the repository at this point in the history
  • Loading branch information
arkq committed Dec 3, 2023
1 parent f8b5511 commit 1c3c71d
Show file tree
Hide file tree
Showing 11 changed files with 397 additions and 6 deletions.
1 change: 1 addition & 0 deletions NEWS
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
unreleased
==========

- optional support for BLE MIDI 1.0 profile as a GATT server
- command line option to set real-time priority for IO threads
- allow to select individual extended controls in ALSA plug-in
- codec-specific delay adjustment with ALSA control and persistency
Expand Down
6 changes: 5 additions & 1 deletion src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ endif

if ENABLE_MIDI
bluealsa_SOURCES += \
bluez-midi.c
ble-midi.c \
bluez-midi.c \
midi.c
endif

if ENABLE_MPEG
Expand All @@ -111,6 +113,7 @@ endif

AM_CFLAGS = \
@AAC_CFLAGS@ \
@ALSA_CFLAGS@ \
@APTX_CFLAGS@ \
@APTX_HD_CFLAGS@ \
@BLUEZ_CFLAGS@ \
Expand All @@ -127,6 +130,7 @@ AM_CFLAGS = \

LDADD = \
@AAC_LIBS@ \
@ALSA_LIBS@ \
@APTX_HD_LIBS@ \
@APTX_LIBS@ \
@BLUEZ_LIBS@ \
Expand Down
41 changes: 39 additions & 2 deletions src/ba-transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include "bluez.h"
#include "hci.h"
#include "hfp.h"
#include "midi.h"
#include "sco.h"
#include "storage.h"
#include "shared/a2dp-codecs.h"
Expand Down Expand Up @@ -860,12 +861,13 @@ struct ba_transport *ba_transport_new_sco(
#if ENABLE_MIDI

static int transport_acquire_bt_midi(struct ba_transport *t) {
(void)t;
return 0;
return midi_transport_alsa_seq_create(t);
}

static int transport_release_bt_midi(struct ba_transport *t) {

midi_transport_alsa_seq_delete(t);

if (t->midi.ble_fd_write != -1) {
debug("Releasing BLE-MIDI write link: %d", t->midi.ble_fd_write);
close(t->midi.ble_fd_write);
Expand Down Expand Up @@ -893,10 +895,28 @@ struct ba_transport *ba_transport_new_midi(

t->profile = profile;

t->midi.seq_port = -1;
t->midi.ble_fd_write = -1;
t->midi.ble_fd_notify = -1;

int err;
if ((err = snd_midi_event_new(1024, &t->midi.seq_parser)) < 0) {
error("Couldn't create MIDI event decoder: %s", snd_strerror(err));
goto fail;
}

/* Disable MIDI running status generated by the decoder. */
snd_midi_event_no_status(t->midi.seq_parser, 1);

t->acquire = transport_acquire_bt_midi;
t->release = transport_release_bt_midi;

return t;

fail:
ba_transport_unref(t);
errno = -err;
return NULL;
}

#endif
Expand Down Expand Up @@ -1124,6 +1144,12 @@ void ba_transport_unref(struct ba_transport *t) {
free(t->sco.ofono_dbus_path_modem);
#endif
}
#if ENABLE_MIDI
else if (t->profile & BA_TRANSPORT_PROFILE_MIDI) {
if (t->midi.seq_parser != NULL)
snd_midi_event_free(t->midi.seq_parser);
}
#endif

#if DEBUG
/* If IO threads are not terminated yet, we can not go any further.
Expand Down Expand Up @@ -1316,6 +1342,11 @@ void ba_transport_set_codec(
* errno is set to indicate the error. */
int ba_transport_start(struct ba_transport *t) {

#if ENABLE_MIDI
if (t->profile & BA_TRANSPORT_PROFILE_MIDI)
return midi_transport_start(t);
#endif

/* For A2DP Source profile only, it is possible that BlueZ will
* activate the transport following a D-Bus "Acquire" request before the
* client thread has completed the acquisition procedure by initializing
Expand Down Expand Up @@ -1353,6 +1384,12 @@ int ba_transport_start(struct ba_transport *t) {
* to call it from IO thread itself - it will cause deadlock! */
int ba_transport_stop(struct ba_transport *t) {

#if ENABLE_MIDI
if (t->profile & BA_TRANSPORT_PROFILE_MIDI)
// FIXME: Skip thread termination for MIDI profile.
midi_transport_stop(t);
#endif

if (ba_transport_thread_state_check_terminated(&t->thread_enc) &&
ba_transport_thread_state_check_terminated(&t->thread_dec))
return 0;
Expand Down
21 changes: 21 additions & 0 deletions src/ba-transport.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@
#include <stdint.h>
#include <time.h>

#include <alsa/asoundlib.h>

#include "a2dp.h"
#include "ba-device.h"
#include "ba-transport-pcm.h"
#include "ble-midi.h"
#include "bluez.h"
#include "shared/a2dp-codecs.h"

Expand Down Expand Up @@ -264,11 +267,29 @@ struct ba_transport {
#if ENABLE_MIDI
struct {

/* ALSA sequencer. */
snd_seq_t *seq;
/* Associated sequencer port. */
int seq_port;

/* ALSA MIDI event parser. */
snd_midi_event_t *seq_parser;

/* BLE-MIDI input link */
int ble_fd_write;
/* BLE-MIDI output (notification) link */
int ble_fd_notify;

/* BLE-MIDI parser for the incoming data. */
struct ble_midi_dec ble_decoder;
/* BLE-MIDI parser for the outgoing data. */
struct ble_midi_enc ble_encoder;

/* Watch ID associated with the BLE-MIDI link. */
unsigned int watch_id_ble;
/* Watch ID associated with ALSA sequencer. */
unsigned int watch_id_seq;

} midi;
#endif

Expand Down
6 changes: 6 additions & 0 deletions src/bluez-midi.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "bluealsa-config.h"
#include "bluez-iface.h"
#include "dbus.h"
#include "midi.h"
#include "shared/bluetooth.h"
#include "shared/defs.h"
#include "shared/log.h"
Expand Down Expand Up @@ -208,6 +209,8 @@ static void bluez_midi_characteristic_acquire_write(

/* TODO: Find a way to detect "device" disconnection condition. */

midi_transport_start_watch_ble_midi(t);

GUnixFDList *fd_list = g_unix_fd_list_new_from_array(&fds[1], 1);
g_dbus_method_invocation_return_value_with_unix_fd_list(inv,
g_variant_new("(hq)", 0, mtu), fd_list);
Expand Down Expand Up @@ -262,6 +265,7 @@ static void bluez_midi_characteristic_acquire_notify(
debug("New BLE-MIDI notify link (MTU: %u): %d", mtu, fds[0]);
app->notify_acquired = true;
t->midi.ble_fd_notify = fds[0];
ble_midi_encode_set_mtu(&t->midi.ble_encoder, mtu);
t->mtu_write = mtu;

/* Setup IO watch for checking HUP condition on the socket. HUP means
Expand Down Expand Up @@ -377,6 +381,8 @@ GDBusObjectManagerServer *bluez_midi_app_new(
error("Couldn't create local MIDI transport: %s", strerror(errno));
else if (ba_transport_acquire(t) == -1)
error("Couldn't acquire local MIDI transport: %s", strerror(errno));
else if (ba_transport_start(t) == -1)
error("Couldn't start local MIDI transport: %s", strerror(errno));
app->t = t;

GDBusObjectManagerServer *manager = g_dbus_object_manager_server_new(path);
Expand Down
Loading

0 comments on commit 1c3c71d

Please sign in to comment.