From a6251b498473c58fe9d33ac98f8b01acf537c979 Mon Sep 17 00:00:00 2001 From: Arkadiusz Bokowy Date: Fri, 3 Jan 2025 19:11:24 +0100 Subject: [PATCH] Allow virtually unlimited BLE-MIDI SysEx messages --- .github/spellcheck-wordlist.txt | 1 + src/ba-transport.c | 2 ++ src/ble-midi.c | 38 ++++++++++++++++++++++++++++----- src/ble-midi.h | 6 ++++-- test/test-ba.c | 2 ++ test/test-ble-midi.c | 22 +++++++++++++------ test/test-io.c | 2 ++ test/test-rfcomm.c | 2 ++ 8 files changed, 62 insertions(+), 13 deletions(-) diff --git a/.github/spellcheck-wordlist.txt b/.github/spellcheck-wordlist.txt index 542cdfeab..0344768d0 100644 --- a/.github/spellcheck-wordlist.txt +++ b/.github/spellcheck-wordlist.txt @@ -261,6 +261,7 @@ SNR spandsp SRA sv +SysEx syslogd systemd TIOCOUTQ diff --git a/src/ba-transport.c b/src/ba-transport.c index f0ace4b63..740d5195a 100644 --- a/src/ba-transport.c +++ b/src/ba-transport.c @@ -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" @@ -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 diff --git a/src/ble-midi.c b/src/ble-midi.c index c1512ef00..8c1445ded 100644 --- a/src/ble-midi.c +++ b/src/ble-midi.c @@ -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. * @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -63,6 +64,27 @@ 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) { @@ -70,6 +92,12 @@ void ble_midi_decode_init(struct ble_midi_dec *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. * @@ -99,8 +127,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; } @@ -209,8 +237,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; diff --git a/src/ble-midi.h b/src/ble-midi.h index 1f9d4bdaa..f0634c209 100644 --- a/src/ble-midi.h +++ b/src/ble-midi.h @@ -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. * @@ -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 */ @@ -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); diff --git a/test/test-ba.c b/test/test-ba.c index c456564e2..e8ba2c51a 100644 --- a/test/test-ba.c +++ b/test/test-ba.c @@ -35,6 +35,7 @@ #include "ba-transport.h" #include "ba-transport-pcm.h" #include "ba-config.h" +#include "ble-midi.h" #include "bluealsa-dbus.h" #include "bluez.h" #include "hfp.h" @@ -49,6 +50,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; } diff --git a/test/test-ble-midi.c b/test/test-ble-midi.c index b4d727045..f6088daf9 100644 --- a/test/test-ble-midi.c +++ b/test/test-ble-midi.c @@ -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. * @@ -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) { @@ -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) { @@ -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) { @@ -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); @@ -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 @@ -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) { diff --git a/test/test-io.c b/test/test-io.c index 31ebc968f..8b1291e0b 100644 --- a/test/test-io.c +++ b/test/test-io.c @@ -79,6 +79,7 @@ #include "ba-rfcomm.h" #include "ba-transport.h" #include "ba-transport-pcm.h" +#include "ble-midi.h" #include "bluealsa-dbus.h" #include "bluez.h" #include "hfp.h" @@ -148,6 +149,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; } diff --git a/test/test-rfcomm.c b/test/test-rfcomm.c index b8cb9df00..b80e3f508 100644 --- a/test/test-rfcomm.c +++ b/test/test-rfcomm.c @@ -32,6 +32,7 @@ #include "ba-rfcomm.h" #include "ba-transport.h" #include "ba-transport-pcm.h" +#include "ble-midi.h" #include "bluealsa-dbus.h" #include "bluez.h" #include "hfp.h" @@ -58,6 +59,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; }