/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);
}