nRF5340 LE Audio "sw_codec_lc3: LC3 enc_bitrate is 0" error

Hey!

I'm working on a LE Audio project utilizing the nRF5340, where I need to stream audio both from and to the nRF and I have encountered the error "sw_codec_lc3: LC3 enc_bitrate is 0". It only occurs when I enable bidirectional communication ("CONFIG_STREAM_BIDIRECTIONAL=y") and when my phone tries to output sound via BLE. If configured to use unidirectional communication, everything works fine, there is audio playback through the nRF. (Which is great! Thanks to everyone who worked on zephyr and the sdk, it is really pleasant to use!)


Given this is is an application specific project, I couldn't simply re-use the DK pinout and set of ICs. All notable hardware changes are:

- Exchanged Codec to: DA7212 (uses I2C instead of SPI), wrote a hardware driver lib that replaces the cirrus one
- Removed most LEDs, except for one RGB one, removed all instances of other LEDs being used
- Removed all power monitoring (INAxx), the SD card and USB
- Removed all buttons and all instances of them being used in software
- Different UART pinout.

To implement these I've adapted the nRF5340 Audio DK devicetree, this has worked well. I don't think my error lies in here. Same goes with the DA7212 codec lib, it just configures the HW codec, not the LC3. Anyhow, here is the UART log:

HL [00:07:20.494,445] <inf> main: Connected
HL [00:07:22.662,994] <inf> main: Security changed
HL [00:07:25.482,543] <inf> bt_content_ctrl_media: Discovery of MCS finished
HL [00:07:29.442,047] <inf> bt_rend_vol: Volume = 153, mute state = 0
HL [00:07:31.632,415] <inf> unicast_server: LC3 codec config for sink:
HL [00:07:31.632,415] <inf> unicast_server:     Frequency: 48000 Hz
HL [00:07:31.632,415] <inf> unicast_server:     Duration: 10000 us
HL [00:07:31.632,415] <inf> unicast_server:     Channel allocation: 0x1
HL [00:07:31.632,415] <inf> unicast_server:     Octets per frame: 120 (96000 bps)
HL [00:07:31.632,446] <inf> unicast_server:     Frames per SDU: 1
HL [00:07:31.632,904] <dbg> main: le_audio_msg_sub_thread: Received event = 1, current state = 1
HL [00:07:31.632,904] <dbg> main: le_audio_msg_sub_thread: LE audio config received
HL [00:07:31.632,934] <dbg> main: le_audio_msg_sub_thread:      Sampling rate: 48000 Hz
HL [00:07:31.632,934] <dbg> main: le_audio_msg_sub_thread:      Bitrate (compressed): 96000 bps
HL [00:07:31.632,934] <dbg> main: le_audio_msg_sub_thread:      Direction: 1
HL [00:07:31.632,965] <dbg> audio_system: audio_system_config_set: Encoder: 0, Decoder: 48000, Bits: 0
HL [00:07:31.692,413] <dbg> main: le_audio_msg_sub_thread: Received event = 2, current state = 1
HL [00:07:31.692,413] <dbg> main: le_audio_msg_sub_thread: Set presentation delay
HL [00:07:31.692,413] <inf> main: Presentation delay 10000 us is set by initiator
HL [00:07:31.751,953] <wrn> bt_ascs: CCID 2 is unknown
HL [00:07:31.954,681] <inf> unicast_server: Stream 0x20009dc4 started
HL [00:07:31.954,864] <dbg> main: le_audio_msg_sub_thread: Received event = 3, current state = 1
HL [00:07:31.954,864] <dbg> main: le_audio_msg_sub_thread: LE audio evt streaming
HL [00:07:31.959,136] <dbg> sw_codec_select: sw_codec_init: Encode: 0Hz 16bits 10000us 0bps 1 channel(s)
HL [00:07:31.959,136] <err> sw_codec_lc3: LC3 enc_bitrate is 0
HL [00:07:31.959,136] <err> audio_system: Failed to set up codec
HL [00:07:31.959,136] <err> audio_system: ERR_CHK Err_code: [-22] @ line: 396
HL [00:07:31.959,167] <err> os: r0/a1:  0x00000003  r1/a2:  0x00000008  r2/a3:  0x00000007
HL [00:07:31.959,167] <err> os: r3/a4:  0x0005557b r12/ip:  0x20002510 r14/lr:  0x00055605
HL [00:07:31.959,167] <err> os:  xpsr:  0x41100000
HL [00:07:31.959,197] <err> os: s[ 0]:  0x200012f0  s[ 1]:  0x0005579f  s[ 2]:  0xffffffea  s[ 3]:  0x00000004
HL [00:07:31.959,197] <err> os: s[ 4]:  0x2000c730  s[ 5]:  0x2000c710  s[ 6]:  0xffffffea  s[ 7]:  0x2000c710
HL [00:07:31.959,197] <err> os: s[ 8]:  0x2000c730  s[ 9]:  0x00000000  s[10]:  0x00001900  s[11]:  0x000557eb
HL [00:07:31.959,228] <err> os: s[12]:  0x2000c730  s[13]:  0x00064554  s[14]:  0xffffffea  s[15]:  0x0000018c
HL [00:07:31.959,228] <err> os: fpscr:  0x00000000
HL [00:07:31.959,228] <err> os: Faulting instruction address (r15/pc): 0x000048b6
HL [00:07:31.959,228] <err> os: >>> ZEPHYR FATAL ERROR 3: Kernel oops on CPU 0
HL [00:07:31.959,259] <err> os: Current thread: 0x20001a88 (LE_AUDIO_MSG_SUB)
HL [00:07:31.959,259] <err> error_handler: Caught system error -- reason 3. Entering infinite loop



Here are the changes to my proj.conf

# Enable I2S
CONFIG_AUDIO_SOURCE_I2S=y
CONFIG_AUDIO_SOURCE_USB=n

CONFIG_TRANSPORT_BIS=n
CONFIG_TRANSPORT_CIS=y

# enable bidirectional communication
CONFIG_STREAM_BIDIRECTIONAL=y


LC3_BITRATE is set to 32000 in src/audio/Kconfig.defaults

config LC3_BITRATE
	default 32000



Oh, and I use my nRF in Unicast Server mode. West version 1.2.0, nRF SDK 2.6.0

Any ideas on why I could get this bitrate error?

Parents
  • Hi

    It seems in the debug log that it says what exactly it's causing this issue:

    HL [00:07:31.959,136] <err> audio_system: Failed to set up codec
    HL [00:07:31.959,136] <err> audio_system: ERR_CHK Err_code: [-22] @ line: 396

    On my end in NCS 2.6.1 nothing is on line 396 of audio_system.c. Have you made any changes here? What is on line 396 on your end in audio_system.c. Error code -22 points to an invalid argument being used, so what have you inputted here exactly?

    Best regards,

    Simon

  • Hey,

    I just rechecked and I made a mistake, I'm on 2.6.0. (I will edit my original post in this regard)

    Please find a screenshot of line 396 of audio_system.c attached:



    Best
    Jana

  • Then sw_codec_init() seems to include some invalid argument in your application then. Please check what you're inputting here. However the unmodified 2.6.0 version of this file also doesn't match yours, so please let me know if you've made any changes to the audio_system.c file in your project/SDK.

    Best regards,

    Simon

  • Thank you for your input! It helps a lot

    I don't think I have made any significant changes, I have commented out the USB include and, if there were LED calls, I have removed them. (USB is not being used or compiled)

    /*
     * Copyright (c) 2018 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    
    #include "audio_system.h"
    
    #include <zephyr/kernel.h>
    #include <zephyr/shell/shell.h>
    
    #include "macros_common.h"
    #include "sw_codec_select.h"
    #include "audio_datapath.h"
    #include "audio_i2s.h"
    #include "data_fifo.h"
    #include "hw_codec.h"
    #include "tone.h"
    #include "contin_array.h"
    #include "pcm_stream_channel_modifier.h"
    //#include "audio_usb.h"
    #include "streamctrl.h"
    
    #include <zephyr/logging/log.h>
    LOG_MODULE_REGISTER(audio_system, CONFIG_AUDIO_SYSTEM_LOG_LEVEL);
    
    #define FIFO_TX_BLOCK_COUNT (CONFIG_FIFO_FRAME_SPLIT_NUM * CONFIG_FIFO_TX_FRAME_COUNT)
    #define FIFO_RX_BLOCK_COUNT (CONFIG_FIFO_FRAME_SPLIT_NUM * CONFIG_FIFO_RX_FRAME_COUNT)
    
    #define DEBUG_INTERVAL_NUM     1000
    #define TEST_TONE_BASE_FREQ_HZ 1000
    
    K_THREAD_STACK_DEFINE(encoder_thread_stack, CONFIG_ENCODER_STACK_SIZE);
    
    DATA_FIFO_DEFINE(fifo_tx, FIFO_TX_BLOCK_COUNT, WB_UP(BLOCK_SIZE_BYTES));
    DATA_FIFO_DEFINE(fifo_rx, FIFO_RX_BLOCK_COUNT, WB_UP(BLOCK_SIZE_BYTES));
    
    static K_SEM_DEFINE(sem_encoder_start, 0, 1);
    
    static struct k_thread encoder_thread_data;
    static k_tid_t encoder_thread_id;
    
    static struct k_poll_signal encoder_sig;
    
    static struct k_poll_event encoder_evt =
    	K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL, K_POLL_MODE_NOTIFY_ONLY, &encoder_sig);
    
    static struct sw_codec_config sw_codec_cfg;
    /* Buffer which can hold max 1 period test tone at 1000 Hz */
    static int16_t test_tone_buf[CONFIG_AUDIO_SAMPLE_RATE_HZ / 1000];
    static size_t test_tone_size;
    
    static bool sample_rate_valid(uint32_t sample_rate_hz)
    {
    	if (sample_rate_hz == 16000 || sample_rate_hz == 24000 || sample_rate_hz == 48000) {
    		return true;
    	}
    
    	return false;
    }
    
    static void audio_gateway_configure(void)
    {
    	if (IS_ENABLED(CONFIG_SW_CODEC_LC3)) {
    		sw_codec_cfg.sw_codec = SW_CODEC_LC3;
    	} else {
    		ERR_CHK_MSG(-EINVAL, "No codec selected");
    	}
    
    #if (CONFIG_STREAM_BIDIRECTIONAL)
    	sw_codec_cfg.decoder.enabled = true;
    	sw_codec_cfg.decoder.num_ch = 1;
    	sw_codec_cfg.decoder.channel_mode = SW_CODEC_MONO;
    #endif /* (CONFIG_STREAM_BIDIRECTIONAL) */
    
    	if (IS_ENABLED(CONFIG_MONO_TO_ALL_RECEIVERS)) {
    		sw_codec_cfg.encoder.num_ch = 1;
    	} else {
    		sw_codec_cfg.encoder.num_ch = 2;
    	}
    
    	sw_codec_cfg.encoder.channel_mode =
    		(sw_codec_cfg.encoder.num_ch == 1) ? SW_CODEC_MONO : SW_CODEC_STEREO;
    	sw_codec_cfg.encoder.enabled = true;
    }
    
    static void audio_headset_configure(void)
    {
    	if (IS_ENABLED(CONFIG_SW_CODEC_LC3)) {
    		sw_codec_cfg.sw_codec = SW_CODEC_LC3;
    	} else {
    		ERR_CHK_MSG(-EINVAL, "No codec selected");
    	}
    
    #if (CONFIG_STREAM_BIDIRECTIONAL)
    	sw_codec_cfg.encoder.enabled = true;
    	sw_codec_cfg.encoder.num_ch = 1;
    	sw_codec_cfg.encoder.channel_mode = SW_CODEC_MONO;
    #endif /* (CONFIG_STREAM_BIDIRECTIONAL) */
    
    	sw_codec_cfg.decoder.num_ch = 1;
    	sw_codec_cfg.decoder.channel_mode = SW_CODEC_MONO;
    
    	if (IS_ENABLED(CONFIG_SD_CARD_PLAYBACK)) {
    		/* Need an extra decoder channel to decode data from SD card */
    		sw_codec_cfg.decoder.num_ch++;
    	}
    
    	sw_codec_cfg.decoder.enabled = true;
    }
    
    static void encoder_thread(void *arg1, void *arg2, void *arg3)
    {
    	int ret;
    	uint32_t blocks_alloced_num;
    	uint32_t blocks_locked_num;
    
    	int debug_trans_count = 0;
    	size_t encoded_data_size = 0;
    
    	void *tmp_pcm_raw_data[CONFIG_FIFO_FRAME_SPLIT_NUM];
    	char pcm_raw_data[FRAME_SIZE_BYTES];
    
    	static uint8_t *encoded_data;
    	static size_t pcm_block_size;
    	static uint32_t test_tone_finite_pos;
    
    	while (1) {
    		/* Don't start encoding until the stream needing it has started */
    		ret = k_poll(&encoder_evt, 1, K_FOREVER);
    
    		/* Get PCM data from I2S */
    		/* Since one audio frame is divided into a number of
    		 * blocks, we need to fetch the pointers to all of these
    		 * blocks before copying it to a continuous area of memory
    		 * before sending it to the encoder
    		 */
    		for (int i = 0; i < CONFIG_FIFO_FRAME_SPLIT_NUM; i++) {
    			ret = data_fifo_pointer_last_filled_get(&fifo_rx, &tmp_pcm_raw_data[i],
    								&pcm_block_size, K_FOREVER);
    			ERR_CHK(ret);
    			memcpy(pcm_raw_data + (i * BLOCK_SIZE_BYTES), tmp_pcm_raw_data[i],
    			       pcm_block_size);
    
    			data_fifo_block_free(&fifo_rx, tmp_pcm_raw_data[i]);
    		}
    
    		if (sw_codec_cfg.encoder.enabled) {
    			if (test_tone_size) {
    				/* Test tone takes over audio stream */
    				uint32_t num_bytes;
    				char tmp[FRAME_SIZE_BYTES / 2];
    
    				ret = contin_array_create(tmp, FRAME_SIZE_BYTES / 2, test_tone_buf,
    							  test_tone_size, &test_tone_finite_pos);
    				ERR_CHK(ret);
    
    				ret = pscm_copy_pad(tmp, FRAME_SIZE_BYTES / 2,
    						    CONFIG_AUDIO_BIT_DEPTH_BITS, pcm_raw_data,
    						    &num_bytes);
    				ERR_CHK(ret);
    			}
    
    			ret = sw_codec_encode(pcm_raw_data, FRAME_SIZE_BYTES, &encoded_data,
    					      &encoded_data_size);
    
    			ERR_CHK_MSG(ret, "Encode failed");
    		}
    
    		/* Print block usage */
    		if (debug_trans_count == DEBUG_INTERVAL_NUM) {
    			ret = data_fifo_num_used_get(&fifo_rx, &blocks_alloced_num,
    						     &blocks_locked_num);
    			ERR_CHK(ret);
    			LOG_DBG(COLOR_CYAN "RX alloced: %d, locked: %d" COLOR_RESET,
    				blocks_alloced_num, blocks_locked_num);
    			debug_trans_count = 0;
    		} else {
    			debug_trans_count++;
    		}
    
    		if (sw_codec_cfg.encoder.enabled) {
    			streamctrl_send(encoded_data, encoded_data_size,
    					sw_codec_cfg.encoder.num_ch);
    		}
    		STACK_USAGE_PRINT("encoder_thread", &encoder_thread_data);
    	}
    }
    
    void audio_system_encoder_start(void)
    {
    	LOG_DBG("Encoder started");
    	k_poll_signal_raise(&encoder_sig, 0);
    }
    
    void audio_system_encoder_stop(void)
    {
    	k_poll_signal_reset(&encoder_sig);
    }
    
    int audio_system_encode_test_tone_set(uint32_t freq)
    {
    	int ret;
    
    	if (freq == 0) {
    		test_tone_size = 0;
    		return 0;
    	}
    
    	if (IS_ENABLED(CONFIG_AUDIO_TEST_TONE)) {
    		ret = tone_gen(test_tone_buf, &test_tone_size, freq, CONFIG_AUDIO_SAMPLE_RATE_HZ,
    			       1);
    		ERR_CHK(ret);
    	} else {
    		LOG_ERR("Test tone is not enabled");
    		return -ENXIO;
    	}
    
    	if (test_tone_size > sizeof(test_tone_buf)) {
    		return -ENOMEM;
    	}
    
    	return 0;
    }
    
    int audio_system_encode_test_tone_step(void)
    {
    	int ret;
    	static uint32_t test_tone_hz;
    
    	if (CONFIG_AUDIO_BIT_DEPTH_BITS != 16) {
    		LOG_WRN("Tone gen only supports 16 bits");
    		return -ECANCELED;
    	}
    
    	if (test_tone_hz == 0) {
    		test_tone_hz = TEST_TONE_BASE_FREQ_HZ;
    	} else if (test_tone_hz >= TEST_TONE_BASE_FREQ_HZ * 4) {
    		test_tone_hz = 0;
    	} else {
    		test_tone_hz = test_tone_hz * 2;
    	}
    
    	if (test_tone_hz != 0) {
    		LOG_INF("Test tone set at %d Hz", test_tone_hz);
    	} else {
    		LOG_INF("Test tone off");
    	}
    
    	ret = audio_system_encode_test_tone_set(test_tone_hz);
    	if (ret) {
    		LOG_ERR("Failed to generate test tone");
    		return ret;
    	}
    
    	return 0;
    }
    
    int audio_system_config_set(uint32_t encoder_sample_rate_hz, uint32_t encoder_bitrate,
    			    uint32_t decoder_sample_rate_hz)
    {
    
    	LOG_DBG("Encoder: %d, Decoder: %d, Bits: %d", encoder_sample_rate_hz, decoder_sample_rate_hz, encoder_bitrate);
    
    	if (sample_rate_valid(encoder_sample_rate_hz)) {
    		sw_codec_cfg.encoder.sample_rate_hz = encoder_sample_rate_hz;
    	} else if (encoder_sample_rate_hz) {
    		LOG_ERR("%d is not a valid sample rate", encoder_sample_rate_hz);
    		return -EINVAL;
    	}
    
    	if (sample_rate_valid(decoder_sample_rate_hz)) {
    		sw_codec_cfg.decoder.sample_rate_hz = decoder_sample_rate_hz;
    	} else if (decoder_sample_rate_hz) {
    		LOG_ERR("%d is not a valid sample rate", decoder_sample_rate_hz);
    		return -EINVAL;
    	}
    
    	if (encoder_bitrate) {
    		sw_codec_cfg.encoder.bitrate = encoder_bitrate;
    	}
    
    	return 0;
    }
    
    /* This function is only used on gateway using USB as audio source and bidirectional stream */
    int audio_system_decode(void const *const encoded_data, size_t encoded_data_size, bool bad_frame)
    {
    	int ret;
    	uint32_t blocks_alloced_num;
    	uint32_t blocks_locked_num;
    	static int debug_trans_count;
    	static void *tmp_pcm_raw_data[CONFIG_FIFO_FRAME_SPLIT_NUM];
    	static void *pcm_raw_data;
    	size_t pcm_block_size;
    
    	if (!sw_codec_cfg.initialized) {
    		/* Throw away data */
    		/* This can happen when using play/pause since there might be
    		 * some packages left in the buffers
    		 */
    		LOG_DBG("Trying to decode while codec is not initialized");
    		return -EPERM;
    	}
    
    	ret = data_fifo_num_used_get(&fifo_tx, &blocks_alloced_num, &blocks_locked_num);
    	if (ret) {
    		return ret;
    	}
    
    	uint8_t free_blocks_num = FIFO_TX_BLOCK_COUNT - blocks_locked_num;
    
    	/* If not enough space for a full frame, remove oldest samples to make room */
    	if (free_blocks_num < CONFIG_FIFO_FRAME_SPLIT_NUM) {
    		void *old_data;
    		size_t size;
    
    		for (int i = 0; i < (CONFIG_FIFO_FRAME_SPLIT_NUM - free_blocks_num); i++) {
    			ret = data_fifo_pointer_last_filled_get(&fifo_tx, &old_data, &size,
    								K_NO_WAIT);
    			if (ret == -ENOMSG) {
    				/* If there are no more blocks in FIFO, break */
    				break;
    			}
    
    			data_fifo_block_free(&fifo_tx, old_data);
    		}
    	}
    
    	for (int i = 0; i < CONFIG_FIFO_FRAME_SPLIT_NUM; i++) {
    		ret = data_fifo_pointer_first_vacant_get(&fifo_tx, &tmp_pcm_raw_data[i], K_FOREVER);
    		if (ret) {
    			return ret;
    		}
    	}
    
    	ret = sw_codec_decode(encoded_data, encoded_data_size, bad_frame, &pcm_raw_data,
    			      &pcm_block_size);
    	if (ret) {
    		LOG_ERR("Failed to decode");
    		return ret;
    	}
    
    	/* Split decoded frame into CONFIG_FIFO_FRAME_SPLIT_NUM blocks */
    	for (int i = 0; i < CONFIG_FIFO_FRAME_SPLIT_NUM; i++) {
    		memcpy(tmp_pcm_raw_data[i], (char *)pcm_raw_data + (i * (BLOCK_SIZE_BYTES)),
    		       BLOCK_SIZE_BYTES);
    
    		ret = data_fifo_block_lock(&fifo_tx, &tmp_pcm_raw_data[i], BLOCK_SIZE_BYTES);
    		if (ret) {
    			LOG_ERR("Failed to lock block");
    			return ret;
    		}
    	}
    	if (debug_trans_count == DEBUG_INTERVAL_NUM) {
    		ret = data_fifo_num_used_get(&fifo_tx, &blocks_alloced_num, &blocks_locked_num);
    		if (ret) {
    			return ret;
    		}
    		LOG_DBG(COLOR_MAGENTA "TX alloced: %d, locked: %d" COLOR_RESET, blocks_alloced_num,
    			blocks_locked_num);
    		debug_trans_count = 0;
    	} else {
    		debug_trans_count++;
    	}
    
    	return 0;
    }
    
    /**@brief Initializes the FIFOs, the codec, and starts the I2S
     */
    void audio_system_start(void)
    {
    	int ret;
    
    	if (CONFIG_AUDIO_DEV == HEADSET) {
    		audio_headset_configure();
    	} else if (CONFIG_AUDIO_DEV == GATEWAY) {
    		audio_gateway_configure();
    	} else {
    		LOG_ERR("Invalid CONFIG_AUDIO_DEV: %d", CONFIG_AUDIO_DEV);
    		ERR_CHK(-EINVAL);
    	}
    
    	if (!fifo_tx.initialized) {
    		ret = data_fifo_init(&fifo_tx);
    		ERR_CHK_MSG(ret, "Failed to set up tx FIFO");
    	}
    
    	if (!fifo_rx.initialized) {
    		ret = data_fifo_init(&fifo_rx);
    		ERR_CHK_MSG(ret, "Failed to set up rx FIFO");
    	}
    	LOG_DBG(COLOR_CYAN "Init codec");
    	ret = sw_codec_init(sw_codec_cfg);
    	ERR_CHK_MSG(ret, "Failed to set up codec");
    
    	sw_codec_cfg.initialized = true;
    
    	if (sw_codec_cfg.encoder.enabled && encoder_thread_id == NULL) {
    		encoder_thread_id = k_thread_create(
    			&encoder_thread_data, encoder_thread_stack, CONFIG_ENCODER_STACK_SIZE,
    			(k_thread_entry_t)encoder_thread, NULL, NULL, NULL,
    			K_PRIO_PREEMPT(CONFIG_ENCODER_THREAD_PRIO), 0, K_NO_WAIT);
    		ret = k_thread_name_set(encoder_thread_id, "ENCODER");
    		ERR_CHK(ret);
    	}
    
    #if ((CONFIG_AUDIO_SOURCE_USB) && (CONFIG_AUDIO_DEV == GATEWAY))
    	ret = audio_usb_start(&fifo_tx, &fifo_rx);
    	ERR_CHK(ret);
    #else
    	ret = hw_codec_default_conf_enable();
    	ERR_CHK(ret);
    
    	ret = audio_datapath_start(&fifo_rx);
    	ERR_CHK(ret);
    #endif /* ((CONFIG_AUDIO_SOURCE_USB) && (CONFIG_AUDIO_DEV == GATEWAY))) */
    }
    
    void audio_system_stop(void)
    {
    	int ret;
    
    	if (!sw_codec_cfg.initialized) {
    		LOG_WRN("Codec already unitialized");
    		return;
    	}
    
    	LOG_DBG("Stopping codec");
    
    #if ((CONFIG_AUDIO_DEV == GATEWAY) && CONFIG_AUDIO_SOURCE_USB)
    	audio_usb_stop();
    #else
    	ret = hw_codec_soft_reset();
    	ERR_CHK(ret);
    
    	ret = audio_datapath_stop();
    	ERR_CHK(ret);
    #endif /* ((CONFIG_AUDIO_DEV == GATEWAY) && CONFIG_AUDIO_SOURCE_USB) */
    
    	ret = sw_codec_uninit(sw_codec_cfg);
    	ERR_CHK_MSG(ret, "Failed to uninit codec");
    	sw_codec_cfg.initialized = false;
    
    	data_fifo_empty(&fifo_rx);
    	data_fifo_empty(&fifo_tx);
    }
    
    int audio_system_fifo_rx_block_drop(void)
    {
    	int ret;
    	void *temp;
    	size_t temp_size;
    
    	ret = data_fifo_pointer_last_filled_get(&fifo_rx, &temp, &temp_size, K_NO_WAIT);
    	if (ret) {
    		LOG_WRN("Failed to get last filled block");
    		return -ECANCELED;
    	}
    
    	data_fifo_block_free(&fifo_rx, temp);
    
    	LOG_DBG("Block dropped");
    	return 0;
    }
    
    int audio_system_decoder_num_ch_get(void)
    {
    	return sw_codec_cfg.decoder.num_ch;
    }
    
    int audio_system_init(void)
    {
    	int ret;
    
    #if ((CONFIG_AUDIO_DEV == GATEWAY) && (CONFIG_AUDIO_SOURCE_USB))
    
    	ret = audio_usb_init();
    	if (ret) {
    		LOG_ERR("Failed to initialize USB: %d", ret);
    		return ret;
    	}
    #else
    
    	ret = audio_datapath_init();
    	if (ret) {
    		LOG_ERR("Failed to initialize audio datapath: %d", ret);
    		return ret;
    	}
    
    	ret = hw_codec_init();
    	if (ret) {
    		LOG_ERR("Failed to initialize HW codec: %d", ret);
    		return ret;
    	}
    #endif
    
    	k_poll_signal_init(&encoder_sig);
    
    	return 0;
    }
    
    static int cmd_audio_system_start(const struct shell *shell, size_t argc, const char **argv)
    {
    	ARG_UNUSED(argc);
    	ARG_UNUSED(argv);
    
    	audio_system_start();
    
    	shell_print(shell, "Audio system started");
    
    	return 0;
    }
    
    static int cmd_audio_system_stop(const struct shell *shell, size_t argc, const char **argv)
    {
    	ARG_UNUSED(argc);
    	ARG_UNUSED(argv);
    
    	audio_system_stop();
    
    	shell_print(shell, "Audio system stopped");
    
    	return 0;
    }
    
    SHELL_STATIC_SUBCMD_SET_CREATE(audio_system_cmd,
    			       SHELL_COND_CMD(CONFIG_SHELL, start, NULL, "Start the audio system",
    					      cmd_audio_system_start),
    			       SHELL_COND_CMD(CONFIG_SHELL, stop, NULL, "Stop the audio system",
    					      cmd_audio_system_stop),
    			       SHELL_SUBCMD_SET_END);
    
    SHELL_CMD_REGISTER(audio_system, &audio_system_cmd, "Audio system commands", NULL);
    

    It is being built as "Headset", i.e. "audio_headset_configure(void)" is being called. CONFIG_STREAM_BIDIRECTIONAL is set to y, sw_codec_cfg should hence be correct?

  • After some more debugging I noticed that sw_codec_cfg.encoder.sample_rate_hz is never set via audio_system_config_set(uint32_t encoder_sample_rate_hz, uint32_t encoder_bitrate, uint32_t decoder_sample_rate_hz)

    I'm afraid that I'm a rather low-level embedded developer, I usually work on the peripheral and hardware level. This is all somewhat unusual territory for me. I'm sorry for that!

    Edit:

    It seems that in this call in unicast_server/main.c never is called with BT_AUDIO_DIR_SOURCE, this is an error on my phones side then? My goal is to have bidirectional audio to my phone, just like a headset with a microphone, am I still missing something here, some config I am missing?

    case LE_AUDIO_EVT_CONFIG_RECEIVED:
    			LOG_DBG("LE audio config received");
    
    			ret = unicast_client_config_get(msg.conn, msg.dir, &bitrate_bps,
    							&sampling_rate_hz);
    			if (ret) {
    				LOG_WRN("Failed to get config: %d", ret);
    				break;
    			}
    
    			if (msg.dir == BT_AUDIO_DIR_SINK) {
    				ret = audio_system_config_set(sampling_rate_hz, bitrate_bps,
    							      VALUE_NOT_SET);
    				ERR_CHK(ret);
    			} else if (msg.dir == BT_AUDIO_DIR_SOURCE) {
    				ret = audio_system_config_set(VALUE_NOT_SET, VALUE_NOT_SET,
    							      sampling_rate_hz);
    				ERR_CHK(ret);
    			}
    
    			break;

  • Hello,

    Thank you for your extreme patience with this. I have been out of office for some time but now I am back.

    nya said:
    I'm afraid that I'm a rather low-level embedded developer, I usually work on the peripheral and hardware level. This is all somewhat unusual territory for me. I'm sorry for that!

    No need to apologize - we've all been new to the field, and we are happy to help! :) 

    nya said:
    It seems that in this call in unicast_server/main.c never is called with BT_AUDIO_DIR_SOURCE, this is an error on my phones side then? My goal is to have bidirectional audio to my phone, just like a headset with a microphone, am I still missing something here, some config I am missing?

    Which phone are you using for these tests, and are you using the native BLE application in the operating system, or are you making your own app on the smartphone as well?

    Best regards,
    Karl

Reply
  • Hello,

    Thank you for your extreme patience with this. I have been out of office for some time but now I am back.

    nya said:
    I'm afraid that I'm a rather low-level embedded developer, I usually work on the peripheral and hardware level. This is all somewhat unusual territory for me. I'm sorry for that!

    No need to apologize - we've all been new to the field, and we are happy to help! :) 

    nya said:
    It seems that in this call in unicast_server/main.c never is called with BT_AUDIO_DIR_SOURCE, this is an error on my phones side then? My goal is to have bidirectional audio to my phone, just like a headset with a microphone, am I still missing something here, some config I am missing?

    Which phone are you using for these tests, and are you using the native BLE application in the operating system, or are you making your own app on the smartphone as well?

    Best regards,
    Karl

Children
  • Hey Karl, thank you for your answer!

    > Which phone are you using for these tests, and are you using the native BLE application in the operating system, or are you making your own app on the smartphone as well?

    Well, this is embarrassing. I was about to answer "I use YouTube for playback" when I got the thought that maybe, just very very maybe, similarly to classical Bluetooth Audio, LE Audio uses different "types of stream" (there are probably better words for that) for uni- and bidirectional audio. So, instead of firstly testing playback, I directly tested bidirectional audio by calling my other phone and, guess what, it works. I probably worked the whole time, it's just that when bidirectional audio is enabled, unidirectional audio will fail.

    That's still a bug? It's just a missing feature? Not sure, but this seems to be much more fixable and most important, usable.

    Thanks for your input! Your message was literally what got me to think about this in that way and test it differently.

Related