Send I2S audio from A2DP sink to A2DP Source and then to Bluetooth Speaker

maxsch
Posts: 1
Joined: Tue Dec 22, 2020 8:47 am

Send I2S audio from A2DP sink to A2DP Source and then to Bluetooth Speaker

Postby maxsch » Wed Dec 23, 2020 1:47 pm

Dear all,

I am building a kind of Bluetooth audio extender. The setup includes two ESP32. The idea is to receive
an a2dp audio stream with ESP32#1, send it via i2s to ESP32#2 and from there via Bluetooth to a Bluetooth speaker.

ESP32 #1 (Audio Sink):

A classical A2DP audio sink. Receiving audio data via Bluetooth and sends the audio via I2S

Configuration:

Code: Select all

 i2s_config_t i2s_config = {

        .mode = I2S_MODE_MASTER | I2S_MODE_TX,                                  // Only TX
        .sample_rate = 44100,
        .bits_per_sample = 16,
        .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,                           //2-channels
        .communication_format = I2S_COMM_FORMAT_I2S_MSB,
        .dma_buf_count = 6,
        .dma_buf_len = 60,
        .intr_alloc_flags = 0,                                                  //Default interrupt priority
        .tx_desc_auto_clear = true                                              //Auto clear tx descriptor on underflow
    };

    i2s_driver_install(0, &i2s_config, 0, NULL);
    i2s_pin_config_t pin_config = {
        .bck_io_num = CONFIG_EXAMPLE_I2S_BCK_PIN,
        .ws_io_num = CONFIG_EXAMPLE_I2S_LRCK_PIN,
        .data_out_num = CONFIG_EXAMPLE_I2S_DATA_PIN,
        .data_in_num = -1                                                       //Not used
    };

    i2s_set_pin(0, &pin_config);

This works and I can also listen to the audio when connecting a PCM5102 DA converter.


ESP32 #2 (Audio Source):

This ESP32 is connected to the I2S bus as SLAVE. The goal is to receive the audio stream from ESP32#1 and send it to a Bluetooth speaker.
I can see that there are many examples where the source of the I2S signal is a microphone or SD Cards, but I could not find an example
which takes a I2S signal and sends it via Bluetooth A2DP to a speaker. I was experimenting a lot and since I was not successful I thought
I post here and see if someone can point me into the right direction. Here is what I have done so far w/o success:

Configuration:

Code: Select all

 static const int i2s_num = 0; // i2s port number

    static const i2s_config_t i2s_config = {
        .mode = I2S_MODE_SLAVE | I2S_MODE_RX,
        .sample_rate = 44100,
        .bits_per_sample = 16,
        .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
        .communication_format = I2S_COMM_FORMAT_I2S,
        .intr_alloc_flags = 0, // default interrupt priority
        .dma_buf_count = 8,
        .dma_buf_len = 64,
        .use_apll = false
    };


    static const i2s_pin_config_t pin_config = {
        .bck_io_num = 26,
        .ws_io_num = 22,
        .data_out_num = -1,
        .data_in_num = 25
    };

    i2s_driver_install(i2s_num, &i2s_config, 0, NULL);   //install and start i2s driver
    i2s_set_pin(i2s_num, &pin_config);
The pin_config is correct and corresponds to the I2S pins of module #1

I assume the magic has to happen here:

Code: Select all

static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len)
{
    if (len < 0 || data == NULL) {
        return 0;
    }

    size_t bytes_read = 0;
    //int a = bytes_read;
    //int b = (int)data;
    
    i2s_read(0, data, SIZE???, &bytes_read, portMAX_DELAY);
    //ESP_LOGI(BT_AV_TAG, "bytes read: %d ", a);
    //ESP_LOGI(BT_AV_TAG, "data:%d ",b);
    return len;
}

I do have several problems here:

1. I am not sure if I can directly handover the I2S data w/o putting it into a buffer
2. I could not find a good documentation about the parameters of i2s_read and so I am lost on what to put there for e.g. SIZE
3. The return value is int32_t len. Where do I get this from? Maybe sizeof(data)?
4. I have problems to understand the bytes_read variable. Seems like that there is not usage for it.

Can anybody kindly help me out here?
Thank you very much in advance
Mike

Klhnikov
Posts: 2
Joined: Sat Nov 19, 2022 12:06 am

Re: Send I2S audio from A2DP sink to A2DP Source and then to Bluetooth Speaker

Postby Klhnikov » Sat Nov 19, 2022 11:19 pm

Hi did you manage to make it works ?
I'm trying to do an A2DP source from I2S/ADC too but the sound is or very noisy, "chunked" (like if you keep turning on and off)...
I presume there is an endiannes correction to do, it looks like the data format is very important... (but changing "communication_format" in i2s setup changes nothing at all...)
Also it looks like the audio frequencies are shifted up (about 2 tones upper)...

here is my data reading plus sending to ringbuffer

Code: Select all

	size_t bytes_read;
	char* i2s_read_buff[ADC_BUF_LEN];
	
	while (1) {
		i2s_read(0, (void*)i2s_read_buff, ADC_BUF_LEN, &bytes_read, portMAX_DELAY);
		// send to ring buffer
		if (xRingbufferSend(buf_handle, i2s_read_buff, bytes_read, pdMS_TO_TICKS(1000)) != pdTRUE) {
			printf("ERROR WRITING\n");
		}
	}
and here is the A2DP callback

Code: Select all

	size_t item_size = 0;
	char *buffer = (char *)xRingbufferReceiveUpTo(buf_handle, &item_size, pdMS_TO_TICKS(1000), len / 2);
	if (item_size == 0 || buffer == NULL) {
		return 0;
	}
	// copy data over
	for (int i = 0; i < item_size; i++)
	{
		char v1 = buffer[2 * i];
		char v2 = buffer[2 * i + 1];
		data[4 * i] = v1;
		data[4 * i + 1] = v2;
		data[4 * i + 2] = v1;
		data[4 * i + 3] = v2;
	}
	// remove buffer
	vRingbufferReturnItem(buf_handle, (void *)buffer);
This code works but gives a very bad sound...

Who is online

Users browsing this forum: No registered users and 101 guests