/main/flac.c
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/stream_buffer.h"
#include "esp_log.h"
#include "FLAC/stream_decoder.h"
#include "audio.h"
#include "file.h"
#include "play.h"
#include "flac.h"
FLAC__StreamDecoderReadStatus flac_read_callback(const FLAC__StreamDecoder *sd, FLAC__byte buffer[], size_t *bytes, void *client_data) {
StreamBufferHandle_t sb = (StreamBufferHandle_t) client_data;
size_t n = xStreamBufferReceive(sb, buffer, *bytes, portMAX_DELAY);
*bytes = n;
// Check the abort semaphore
uint32_t abort = ulTaskNotifyTake(pdFALSE, 0);
if (abort) {
return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
}
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
}
FLAC__StreamDecoderWriteStatus flac_write_callback(const FLAC__StreamDecoder* sd, const FLAC__Frame* frame, const FLAC__int32* const buffer[], void* client_data) {
// FLAC header block size is the number of 16-bit stereo samples (4 bytes per sample)
uint16_t* outbuf = malloc(256 * sizeof(uint16_t));
if (outbuf == NULL) {
ESP_LOGE("flac_write_callback", "Failed to allocate output buffer");
heap_caps_print_heap_info(MALLOC_CAP_8BIT);
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
}
int c = 0;
for (int i = 0; i < frame->header.blocksize; i++) {
outbuf[c ] = (uint16_t) buffer[0][i];
outbuf[c+1] = (uint16_t) buffer[1][i];
c += 2;
if (c == 256) {
audio_send_ptr(outbuf, 256);
outbuf = malloc(256 * sizeof(uint16_t));
if (outbuf == NULL) {
ESP_LOGE("flac_write_callback", "Failed to reallocate output buffer");
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
}
c = 0;
}
}
audio_send_ptr(outbuf, c);
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
void flac_error_callback(const FLAC__StreamDecoder *sd, FLAC__StreamDecoderErrorStatus status, void *client_data) {
ESP_LOGE("flac_error_callback", "%d", status);
}
void play_flac(void *pvParameters) {
const char TAG[] = "play_flac";
play_parameters_t* pp = (play_parameters_t*) pvParameters;
StreamBufferHandle_t sb = xStreamBufferCreate(4096, 2048);
file_reader_open(pp->filename);
file_reader_subscribe(sb);
file_reader_start();
if (!audio_open()) {
ESP_LOGE(TAG, "audio not available");
}
free(pp);
FLAC__StreamDecoder *sd = FLAC__stream_decoder_new();
if (sd == NULL) {
ESP_LOGE(TAG, "Could not allocate FLAC decoder");
return;
}
FLAC__StreamDecoderInitStatus s = FLAC__stream_decoder_init_stream(
sd,
flac_read_callback,
NULL,
NULL,
NULL,
NULL,
flac_write_callback,
NULL,
flac_error_callback,
sb
);
if (s != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
ESP_LOGE(TAG, "Could not initialize FLAC decoder: %d", s);
return;
}
while (FLAC__stream_decoder_process_single(sd)) {
if (ulTaskNotifyTake(pdTRUE, 0)) {
break;
}
}
FLAC__stream_decoder_delete(sd);
audio_close();
file_reader_stop();
file_reader_close();
vTaskDelete(NULL);
}