Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions prj.conf
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ CONFIG_BT_USER_PHY_UPDATE=y

CONFIG_BT_CTLR_DATA_LENGTH_MAX=251
CONFIG_BT_BUF_ACL_RX_SIZE=502
CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA=8
CONFIG_BT_BUF_ACL_TX_SIZE=502
CONFIG_BT_L2CAP_TX_MTU=498
CONFIG_BT_CTLR_PHY_2M=y
Expand Down
1 change: 1 addition & 0 deletions prj_fota.conf
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ CONFIG_BT_USER_PHY_UPDATE=y

CONFIG_BT_CTLR_DATA_LENGTH_MAX=251
CONFIG_BT_BUF_ACL_RX_SIZE=502
CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA=8
CONFIG_BT_BUF_ACL_TX_SIZE=502
CONFIG_BT_L2CAP_TX_MTU=498
CONFIG_BT_CTLR_PHY_2M=y
Expand Down
10 changes: 8 additions & 2 deletions src/audio/audio_datapath.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,14 @@ static void (*buffer_play_callback)(void) = NULL;
extern struct k_poll_signal encoder_sig;
extern struct k_poll_event logger_sig;

/* Decimation buffer for SD card logging */
static int16_t decimated_audio[BLOCK_SIZE_BYTES / sizeof(int16_t) / 4]; /* /4 for decimation factor 4 */
/*
* Decimation output for one interleaved stereo audio block.
*
* The decimator supports factors down to 1, so its worst-case output contains
* every input sample. Seal check currently uses factor 3 (48 kHz -> 16 kHz);
* sizing this buffer for the old fixed factor 4 overflowed it on every block.
*/
static int16_t decimated_audio[BLOCK_SIZE_BYTES / sizeof(int16_t)];

// Funktion für den neuen Thread
static void data_thread(void *arg1, void *arg2, void *arg3)
Expand Down
4 changes: 3 additions & 1 deletion src/audio/decimation_filter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,9 @@ int CascadedDecimator::process(const int16_t* input, int16_t* output, uint32_t n
}

if (num_stages_ == 0) {
memcpy(output, input, num_frames * 2 * sizeof(int16_t));
if (output != input) {
memcpy(output, input, num_frames * 2U * sizeof(int16_t));
}
return num_frames;
}

Expand Down
4 changes: 2 additions & 2 deletions src/audio/decimation_filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,8 @@ class CascadedDecimator {
uint8_t num_stages_;
bool configured_;
Decimator stages_[MAX_STAGES];
/* Stage output alternates between this buffer and the caller's output. */
int16_t intermediate_buffer_[MAX_FRAMES];
/* Stage output is interleaved stereo, so each frame needs two samples. */
int16_t intermediate_buffer_[MAX_FRAMES * 2U];
float32_t processing_buffer_[MAX_FRAMES * 2];
};
#endif
Expand Down
38 changes: 31 additions & 7 deletions src/bluetooth/gatt_services/audio_response_service.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@
#include "audio_system.h"
#include "hw_codec.h"

LOG_MODULE_REGISTER(audio_response_service, LOG_LEVEL_DBG);
LOG_MODULE_REGISTER(audio_response_service, CONFIG_LOG_DEFAULT_LEVEL);

#define AUDIO_RESPONSE_CAPTURE_SAMPLES 2048
#define AUDIO_RESPONSE_CAPTURE_SAMPLE_RATE 4000U
#define AUDIO_RESPONSE_INITIAL_DROP 128
#define AUDIO_RESPONSE_DEFAULT_POINTS 9
#define AUDIO_RESPONSE_TRANSFER_CREDITS 1
#define AUDIO_RESPONSE_TRANSFER_CREDIT_DELAY K_MSEC(1)
#define AUDIO_RESPONSE_TRANSFER_TIMEOUT K_SECONDS(30)
#define AUDIO_RESPONSE_STATUS_ENCODED_SIZE 9
#define AUDIO_RESPONSE_RESULT_ENCODED_SIZE (2 + (CONFIG_AUDIO_RESPONSE_MAX_POINTS * 4))
Expand Down Expand Up @@ -88,6 +89,7 @@ static bool result_notifications_enabled;

static struct k_work measurement_work;
static struct k_work measurement_complete_work;
static struct k_work_delayable transfer_ready_work;
static struct k_work_delayable transfer_timeout_work;
K_MUTEX_DEFINE(service_mutex);

Expand Down Expand Up @@ -249,6 +251,7 @@ static void reset_transfer(void)
{
LOG_DBG("Reset transfer state: id=%u active=%d committed=%d received=%u/%u", transfer.id,
transfer.active, transfer.committed, transfer.received_samples, transfer.total_samples);
k_work_cancel_delayable(&transfer_ready_work);
memset(&transfer, 0, sizeof(transfer));
}

Expand Down Expand Up @@ -312,11 +315,12 @@ static ssize_t start_transfer(const audio_response_transfer_start_t *start, uint
LOG_INF("Transfer start requested: id=%u samples=%u rate=%u checksum=0x%08x",
start->transfer_id, start->total_samples, start->sampling_rate, start->checksum);

if (measurement_active || transfer.active || start->total_samples == 0 ||
if (measurement_active || (transfer.active && !transfer.committed) ||
start->total_samples == 0 ||
start->sampling_rate != CONFIG_AUDIO_SAMPLE_RATE_HZ) {
LOG_WRN("Transfer start rejected: measurement_active=%d active=%d samples=%u rate=%u expected_rate=%u",
measurement_active, transfer.active, start->total_samples, start->sampling_rate,
CONFIG_AUDIO_SAMPLE_RATE_HZ);
LOG_WRN("Transfer start rejected: measurement_active=%d active=%d committed=%d samples=%u rate=%u expected_rate=%u",
measurement_active, transfer.active, transfer.committed, start->total_samples,
start->sampling_rate, CONFIG_AUDIO_SAMPLE_RATE_HZ);
return reject_transfer(AUDIO_RESPONSE_TRANSFER_INVALID_STATE,
BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED));
}
Expand Down Expand Up @@ -541,7 +545,7 @@ static ssize_t write_transfer_data(struct bt_conn *conn, const struct bt_gatt_at
}
transfer.received_samples += sample_count;
k_work_reschedule(&transfer_timeout_work, AUDIO_RESPONSE_TRANSFER_TIMEOUT);
(void)notify_transfer_status(AUDIO_RESPONSE_TRANSFER_READY, AUDIO_RESPONSE_TRANSFER_CREDITS);
k_work_reschedule(&transfer_ready_work, AUDIO_RESPONSE_TRANSFER_CREDIT_DELAY);
if (transfer.received_samples == transfer.total_samples) {
LOG_INF("Transfer upload complete: id=%u samples=%u", transfer.id,
transfer.total_samples);
Expand Down Expand Up @@ -759,13 +763,18 @@ static void measurement_work_handler(struct k_work *work)
}
LOG_DBG("Audio datapath acquired: id=%u", pending_config.id);
audio_session.datapath_acquired = true;
audio_session.measurement_codec_enabled = true;
ret = hw_codec_default_conf_enable();
if (ret != 0) {
LOG_ERR("Failed to enable codec for audio response measurement: %d", ret);
goto fail;
}
audio_session.measurement_codec_enabled = true;
LOG_DBG("Codec enabled for audio response measurement: id=%u", pending_config.id);
ret = hw_codec_volume_unmute();
if (ret != 0) {
LOG_ERR("Failed to unmute codec for audio response measurement: %d", ret);
goto fail;
}
ret = audio_datapath_buffer_play(transfer.samples, transfer.total_samples, false,
pending_config.volume, NULL);
if (ret != 0) {
Expand Down Expand Up @@ -849,6 +858,20 @@ static void measurement_complete_work_handler(struct k_work *work)
LOG_DBG("Audio response measurement complete: id=%u", pending_config.id);
}

/**
* Grant the next upload credit after the current GATT write has released its
* incoming ACL buffer.
*/
static void transfer_ready_work_handler(struct k_work *work)
{
k_mutex_lock(&service_mutex, K_FOREVER);
if (transfer.active && !transfer.committed) {
(void)notify_transfer_status(AUDIO_RESPONSE_TRANSFER_READY,
AUDIO_RESPONSE_TRANSFER_CREDITS);
}
k_mutex_unlock(&service_mutex);
}

/**
* Release an incomplete transfer after the protocol timeout.
*/
Expand All @@ -875,6 +898,7 @@ int init_audio_response_service(void)
LOG_INF("Initializing audio response service");
k_work_init(&measurement_work, measurement_work_handler);
k_work_init(&measurement_complete_work, measurement_complete_work_handler);
k_work_init_delayable(&transfer_ready_work, transfer_ready_work_handler);
k_work_init_delayable(&transfer_timeout_work, transfer_timeout_work_handler);
return 0;
}
Loading