/* 2. TX Playback Config */
audio_cfg.dai_route = AUDIO_ROUTE_PLAYBACK;
audio_cfg.dai_cfg.i2s.word_size = SAMPLE_BIT_WIDTH_TX;
audio_cfg.dai_cfg.i2s.frame_clk_freq = SAMPLE_FREQ_TX;
audio_cfg.dai_cfg.i2s.mem_slab = &mem_slab_tx;
audio_cfg.dai_cfg.i2s.block_size = BLOCK_SIZE_TX;
audio_codec_configure(tx_dev, &audio_cfg);
k_msleep(500);
if (!init_buttons()) return 0;
if (!device_is_ready(i2s_dev_rx) || !device_is_ready(i2s_dev_tx)) {
printk("SAI2 Devices are not ready\n");
return 0;
}
/* 3. Setings for I2S/SAI */
config_rx.word_size = SAMPLE_BIT_WIDTH_RX;
config_rx.channels = NUMBER_OF_CHANNELS;
config_rx.format = I2S_FMT_DATA_FORMAT_I2S;
config_rx.options = I2S_OPT_BIT_CLK_MASTER | I2S_OPT_FRAME_CLK_MASTER;
config_rx.timeout = TIMEOUT;
/* RX I2S config */
config_rx.frame_clk_freq = SAMPLE_FREQ_RX;
config_rx.mem_slab = &mem_slab_rx;
config_rx.block_size = BLOCK_SIZE_RX;
i2s_configure(i2s_dev_rx, I2S_DIR_RX, &config_rx);
/* TX I2S config */
config_tx = config_rx;
config_tx.word_size = SAMPLE_BIT_WIDTH_TX;
config_tx.frame_clk_freq = SAMPLE_FREQ_TX;
config_tx.mem_slab = &mem_slab_tx;
config_tx.block_size = BLOCK_SIZE_TX;
i2s_configure(i2s_dev_tx, I2S_DIR_TX, &config_tx);
#ifndef MY_CODE
/* 1. Set explicit volume to safe maximum level (100%) */
audio_property_value_t vol_val = { .vol = 100 };
audio_codec_set_property(tx_dev, AUDIO_PROPERTY_OUTPUT_VOLUME, AUDIO_CHANNEL_ALL, vol_val);
audio_codec_set_property(rx_dev, AUDIO_PROPERTY_INPUT_VOLUME, AUDIO_CHANNEL_ALL, vol_val);
/* 2. Explicitly disable output channel mutes */
audio_property_value_t mute_val = { .mute = false };
audio_codec_set_property(tx_dev, AUDIO_PROPERTY_OUTPUT_MUTE, AUDIO_CHANNEL_ALL, mute_val);
audio_codec_set_property(rx_dev, AUDIO_PROPERTY_INPUT_MUTE, AUDIO_CHANNEL_ALL, mute_val);
audio_codec_start_output(rx_dev);
#endif
/* 4. Main cycle */
while (1) {
k_sem_take(&toggle_transfer, K_FOREVER);
if (!streaming) {
if (!prepare_transfer(i2s_dev_rx, i2s_dev_tx)) {
printk("Failed to prepare TX buffers\n");
continue;
}
if (!trigger_command(i2s_dev_rx, i2s_dev_tx, I2S_TRIGGER_START)) {
continue;
}
streaming = true;
printk("Stream started\n");
} else {
if (!trigger_command(i2s_dev_rx, i2s_dev_tx, I2S_TRIGGER_DROP)) {
continue;
}
streaming = false;
printk("Stream stopped\n");
}
while (streaming && k_sem_take(&toggle_transfer, K_NO_WAIT) != 0) {
void *rx_block = NULL;
void *tx_block = NULL;
size_t rx_size;
int ret;
/* Read RX (16 kHz) */
ret = i2s_read(i2s_dev_rx, &rx_block, &rx_size);
if (ret < 0) {
printk("i2s_read failed: %d\n", ret);
break;
}
/* Proccess rx data */
process_block_data(rx_block, SAMPLES_PER_BLOCK_RX);
/* Allocate TX block(32 kHz) */
ret = k_mem_slab_alloc(&mem_slab_tx, &tx_block, K_NO_WAIT);
if (ret < 0) {
printk("Failed to allocate TX block: %d\n", ret);
k_mem_slab_free(&mem_slab_rx, rx_block);
break;
}
/* Upsample to 32kHz */
audio_upsample_to_32k((const int16_t *)rx_block, (int32_t *)tx_block,
NUMBER_OF_CHANNELS, SAMPLE_FREQ_RX);
k_mem_slab_free(&mem_slab_rx, rx_block);
/* Send to TX (32 kHz) */
ret = i2s_write(i2s_dev_tx, tx_block, BLOCK_SIZE_TX);
if (ret < 0) {
printk("i2s_write failed: %d\n", ret);
k_mem_slab_free(&mem_slab_tx, tx_block);
break;
}
}
}
return 0;
}