Skip to content

Commit

Permalink
Allow virtually unlimited BLE-MIDI SysEx messages
Browse files Browse the repository at this point in the history
  • Loading branch information
arkq committed Jan 3, 2025
1 parent e00c1a5 commit e6b6da3
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 13 deletions.
2 changes: 2 additions & 0 deletions src/ba-transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "ba-rfcomm.h"
#include "ba-transport-pcm.h"
#include "ba-config.h"
#include "ble-midi.h"
#include "bluealsa-dbus.h"
#include "bluez-iface.h"
#include "bluez.h"
Expand Down Expand Up @@ -882,6 +883,7 @@ void ba_transport_unref(struct ba_transport *t) {
else if (t->profile & BA_TRANSPORT_PROFILE_MIDI) {
if (t->midi.seq_parser != NULL)
snd_midi_event_free(t->midi.seq_parser);
ble_midi_decode_free(&t->midi.ble_decoder);
}
#endif

Expand Down
37 changes: 32 additions & 5 deletions src/ble-midi.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* BlueALSA - ble-midi.c
* Copyright (c) 2016-2024 Arkadiusz Bokowy
* Copyright (c) 2016-2025 Arkadiusz Bokowy
*
* This file is a part of bluez-alsa.
*
Expand Down Expand Up @@ -63,13 +63,40 @@ static size_t ble_midi_message_len(uint8_t status) {
return 0;
}

/**
* Get SysEx buffer which can hold at least additional len bytes. */
static uint8_t *ble_midi_get_sys_buffer(struct ble_midi_dec *bmd, size_t len) {

if (bmd->buffer_sys_len + len <= bmd->buffer_sys_size)
goto final;

uint8_t *tmp = bmd->buffer_sys;
size_t size = bmd->buffer_sys_size + MAX(len, 512);
if ((tmp = realloc(tmp, size * sizeof(*tmp))) == NULL) {
warn("Couldn't resize BLE-MIDI SysEx buffer: %s", strerror(errno));
goto final;
}

bmd->buffer_sys = tmp;
bmd->buffer_sys_size = size;

final:
return bmd->buffer_sys;
}

/**
* Initialize BLE-MIDI decoder. */
void ble_midi_decode_init(struct ble_midi_dec *bmd) {
memset(bmd, 0, sizeof(*bmd));
gettimestamp(&bmd->ts0);
}

/**
* Free BLE-MIDI decoder resources. */
void ble_midi_decode_free(struct ble_midi_dec *bmd) {
free(bmd->buffer_sys);
}

/**
* Decode BLE-MIDI packet.
*
Expand Down Expand Up @@ -99,8 +126,8 @@ int ble_midi_decode(struct ble_midi_dec *bmd, const uint8_t *data, size_t len) {
/* If the system exclusive message was not ended in the previous
* packet we need to reconstruct fragmented message. */
if (bmd->status_sys) {
bm_buffer = bmd->buffer_sys;
bm_buffer_size = sizeof(bmd->buffer_sys);
bm_buffer = ble_midi_get_sys_buffer(bmd, len);
bm_buffer_size = bmd->buffer_sys_size;
bm_buffer_len = bmd->buffer_sys_len;
bm_status = 0xF0;
}
Expand Down Expand Up @@ -209,8 +236,8 @@ int ble_midi_decode(struct ble_midi_dec *bmd, const uint8_t *data, size_t len) {
/* System exclusive message needs to be stored in a dedicated buffer.
* First of all, it can span multiple BLE-MIDI packets. Secondly, it
* can be interleaved with MIDI real-time messages. */
bm_buffer = bmd->buffer_sys;
bm_buffer_size = sizeof(bmd->buffer_sys);
bm_buffer = ble_midi_get_sys_buffer(bmd, len);
bm_buffer_size = bmd->buffer_sys_size;
bm_buffer_len = bmd->buffer_sys_len;
bmd->status_sys = true;
break;
Expand Down
6 changes: 4 additions & 2 deletions src/ble-midi.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* BlueALSA - ble-midi.h
* Copyright (c) 2016-2024 Arkadiusz Bokowy
* Copyright (c) 2016-2025 Arkadiusz Bokowy
*
* This file is a part of bluez-alsa.
*
Expand Down Expand Up @@ -33,7 +33,8 @@ struct ble_midi_dec {
uint8_t buffer_midi[8];
size_t buffer_midi_len;
/* storage for decoded system exclusive message */
uint8_t buffer_sys[256];
uint8_t *buffer_sys;
size_t buffer_sys_size;
size_t buffer_sys_len;

/* reconstructed timestamp value */
Expand Down Expand Up @@ -73,6 +74,7 @@ struct ble_midi_enc {
};

void ble_midi_decode_init(struct ble_midi_dec *bmd);
void ble_midi_decode_free(struct ble_midi_dec *bmd);
int ble_midi_decode(struct ble_midi_dec *bmd, const uint8_t *data, size_t len);

void ble_midi_encode_init(struct ble_midi_enc *bme);
Expand Down
1 change: 1 addition & 0 deletions test/test-ba.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
/* Keep persistent storage in the current directory. */
#define TEST_BLUEALSA_STORAGE_DIR "storage-test-ba"

void ble_midi_decode_free(struct ble_midi_dec *bmd) { (void)bmd; }
int midi_transport_alsa_seq_create(struct ba_transport *t) { (void)t; return 0; }
int midi_transport_alsa_seq_delete(struct ba_transport *t) { (void)t; return 0; }
int midi_transport_start(struct ba_transport *t) { (void)t; return 0; }
Expand Down
22 changes: 16 additions & 6 deletions test/test-ble-midi.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* test-ble-midi.c
* Copyright (c) 2016-2024 Arkadiusz Bokowy
* Copyright (c) 2016-2025 Arkadiusz Bokowy
*
* This file is a part of bluez-alsa.
*
Expand Down Expand Up @@ -185,6 +185,8 @@ CK_START_TEST(test_ble_midi_decode_single_system_exclusive) {
ck_assert_uint_eq(bmd.len, sizeof(midi));
ck_assert_mem_eq(bmd.buffer, midi, sizeof(midi));

ble_midi_decode_free(&bmd);

} CK_END_TEST

CK_START_TEST(test_ble_midi_decode_multiple_system_exclusive) {
Expand All @@ -204,6 +206,8 @@ CK_START_TEST(test_ble_midi_decode_multiple_system_exclusive) {
ck_assert_uint_eq(bmd.len, sizeof(midi));
ck_assert_mem_eq(bmd.buffer, midi, sizeof(midi));

ble_midi_decode_free(&bmd);

} CK_END_TEST

CK_START_TEST(test_ble_midi_decode_multiple_system_exclusive_2) {
Expand All @@ -223,6 +227,8 @@ CK_START_TEST(test_ble_midi_decode_multiple_system_exclusive_2) {
ck_assert_uint_eq(bmd.len, sizeof(midi));
ck_assert_mem_eq(bmd.buffer, midi, sizeof(midi));

ble_midi_decode_free(&bmd);

} CK_END_TEST

CK_START_TEST(test_ble_midi_decode_multiple_system_exclusive_3) {
Expand All @@ -231,11 +237,12 @@ CK_START_TEST(test_ble_midi_decode_multiple_system_exclusive_3) {
ble_midi_decode_init(&bmd);

const uint8_t data1[] = { 0x80, 0x81, 0xF0, 0x01, 0x02, 0x03 };
uint8_t data2[512] = { 0x80, 0x81, 0x77 };
memset(data2 + 3, 0x77, sizeof(data2) - 3);
uint8_t data2[2 + 512] = { 0x80, 0x81, /* ... */ };
memset(data2 + 2, 0x77, sizeof(data2) - 2);
const uint8_t data3[] = { 0x80, 0x81, 0xF7 };
uint8_t midi[sizeof(bmd.buffer_sys)] = { 0xF0, 0x01, 0x02, 0x03, 0x77 };
memset(midi + 5, 0x77, sizeof(midi) - 5);
uint8_t midi[1 + 3 + 512 + 1] = { 0xF0, 0x01, 0x02, 0x03, /* ... */ 0xF7 };
memset(midi + 4, 0x77, sizeof(midi) - 4);
midi[sizeof(midi) - 1] = 0xF7;

ck_assert_int_eq(ble_midi_decode(&bmd, data1, sizeof(data1)), 0);
ck_assert_int_eq(ble_midi_decode(&bmd, data2, sizeof(data2)), 0);
Expand All @@ -245,7 +252,8 @@ CK_START_TEST(test_ble_midi_decode_multiple_system_exclusive_3) {
ck_assert_uint_eq(timespec2ms(&bmd.ts), 1);
ck_assert_uint_eq(bmd.len, sizeof(midi));
ck_assert_mem_eq(bmd.buffer, midi, sizeof(midi));
ck_assert_uint_eq(errno, EMSGSIZE);

ble_midi_decode_free(&bmd);

} CK_END_TEST

Expand All @@ -258,6 +266,8 @@ CK_START_TEST(test_ble_midi_decode_invalid_system_exclusive) {

ck_assert_int_eq(ble_midi_decode(&bmd, data, sizeof(data)), -1);

ble_midi_decode_free(&bmd);

} CK_END_TEST

CK_START_TEST(test_ble_midi_decode_single_running_status) {
Expand Down
1 change: 1 addition & 0 deletions test/test-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ bool bluez_a2dp_set_configuration(const char *current_dbus_sep_path,
return false; }
int ofono_call_volume_update(struct ba_transport *t) {
debug("%s: %p", __func__, t); (void)t; return 0; }
void ble_midi_decode_free(struct ble_midi_dec *bmd) { (void)bmd; }
int midi_transport_alsa_seq_create(struct ba_transport *t) { (void)t; return 0; }
int midi_transport_alsa_seq_delete(struct ba_transport *t) { (void)t; return 0; }
int midi_transport_start(struct ba_transport *t) { (void)t; return 0; }
Expand Down
1 change: 1 addition & 0 deletions test/test-rfcomm.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ static void dbus_update_counters_wait(unsigned int *counter, unsigned int value)
pthread_mutex_unlock(&dbus_update_mtx);
}

void ble_midi_decode_free(struct ble_midi_dec *bmd) { (void)bmd; }
int midi_transport_alsa_seq_create(struct ba_transport *t) { (void)t; return 0; }
int midi_transport_alsa_seq_delete(struct ba_transport *t) { (void)t; return 0; }
int midi_transport_start(struct ba_transport *t) { (void)t; return 0; }
Expand Down

0 comments on commit e6b6da3

Please sign in to comment.