/main/audio.c
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "driver/i2s.h"
#include "esp_log.h"
#include "audio.h"
#include "io.h"
QueueHandle_t audio_queue;
SemaphoreHandle_t audio_access_sem;
void audio_task(void *pvParameters) {
const char TAG[] = "audio_task";
audio_block_t audio_block;
while (1) {
BaseType_t success = xQueueReceive(audio_queue, &audio_block, portMAX_DELAY);
if (success != pdTRUE) {
ESP_LOGE(TAG, "Failed to receive from audio queue");
continue;
}
size_t bytes_written;
esp_err_t e = i2s_write(I2S_NUM_0, audio_block.samples, audio_block.count * 2, &bytes_written, portMAX_DELAY);
if (e != ESP_OK) {
ESP_LOGE(TAG, "error %d", e);
}
if (bytes_written < audio_block.count * 2) {
ESP_LOGE(TAG, "only wrote %d bytes", bytes_written);
} else {
ESP_LOGD(TAG, "wrote %d bytes", bytes_written);
}
free(audio_block.samples);
}
}
int audio_init() {
const char TAG[] = "audio_init";
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
.sample_rate = SAMPLE_RATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.dma_buf_count = I2S_DMA_COUNT,
.dma_buf_len = I2S_DMA_LEN,
.use_apll = false,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 //Interrupt level 1
};
i2s_pin_config_t pin_config = {
.mck_io_num = I2S_MCK_IO,
.bck_io_num = I2S_BCK_IO,
.ws_io_num = I2S_WS_IO,
.data_out_num = I2S_DO_IO,
.data_in_num = I2S_DI_IO //Not used
};
i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL);
i2s_set_pin(I2S_NUM, &pin_config);
i2s_stop(I2S_NUM);
audio_access_sem = xSemaphoreCreateBinary();
if (audio_access_sem == NULL) {
ESP_LOGE(TAG, "Could not create audio access semaphore");
return 0;
}
audio_queue = xQueueCreate(AUDIO_QUEUE_SIZE, sizeof(audio_block_t));
if (audio_queue == NULL) {
ESP_LOGE(TAG, "Could not create audio queue");
return 0;
}
xTaskCreate(audio_task, "audio", 4096, NULL, 10, NULL);
xSemaphoreGive(audio_access_sem);
return 1;
}
int audio_open() {
const char TAG[] = "audio_open";
BaseType_t available = xSemaphoreTake(audio_access_sem, 0);
if (available != pdTRUE) {
ESP_LOGE(TAG, "tried to open audio twice");
return 0;
}
i2s_start(I2S_NUM);
io_audio_enable(true);
return 1;
}
void audio_close() {
i2s_stop(I2S_NUM);
io_audio_enable(false);
xSemaphoreGive(audio_access_sem);
}
void audio_send(uint16_t *buf, size_t n) {
uint16_t* samples = (uint16_t*) malloc(n * 2);
memcpy(samples, buf, n * 2);
audio_block_t block = { samples, n };
xQueueSend(audio_queue, &block, portMAX_DELAY);
}
void audio_send_ptr(uint16_t *buf, size_t n) {
audio_block_t block = { buf, n };
xQueueSend(audio_queue, &block, portMAX_DELAY);
}