//
//  BufferRegulator.hpp
//  SwitchboardSDK
//
//  Created by Balázs Kiss on 2022. 02. 16..
//  Copyright © 2022. Synervoz Inc. All rights reserved.
//

#pragma once

#include "RingBuffer.hpp"

#include <buffer/AudioData.hpp>
#include <memory>

namespace switchboard::audio {

using AudioCallbackFunction = bool (*)(
    float** buffers,
    unsigned int inputChannels,
    unsigned int outputChannels,
    unsigned int numberOfFrames,
    unsigned int sampleRate,
    void* userPointer
);

/**
 * BufferRegulator class.
 * @brief This class can be used to turn variable sized audio buffer stream into a stabilized constant length audio buffer stream.
 * @details The BufferRegulator's process function can receive any number of frames, but the callback function is always called with outputBufferMs long buffers.
 */
class BufferRegulator {
public:
    /**
     * @brief Creates a BufferRegulator instance.
     *
     * @param outputBufferMs Buffer duration that is received by the callback function.
     * @param audioCallback The callback function that receives the duration regulated audio buffers.
     */
    BufferRegulator(unsigned int outputBufferMs, AudioCallbackFunction audioCallback);

    /**
     * @brief Resets the buffer regulator's internal state.
     */
    void reset();

    /**
     * @brief The audio process function.
     * @details When sample rate changes, the BufferRegulator resets its state and clears its internal buffers.
     *
     * @param buffers [inout] The audio buffer.
     * @param inputChannels Number of input channels.
     * @param outputChannels Number of output channels.
     * @param sampleRate Sample rate of audio data.
     * @param userPointer Custom pointer that is passed to the callback function.
     *
     * @returns true if audio data has been written to buffer, false otherwise.
     */
    bool process(
        float** buffers,
        unsigned int inputChannels,
        unsigned int outputChannels,
        unsigned int numberOfFrames,
        unsigned int sampleRate,
        void* userPointer
    );

private:
    unsigned int outputBufferMs;
    AudioCallbackFunction audioCallback;

    std::unique_ptr<RingBuffer<float>> captureBuffer;
    std::unique_ptr<RingBuffer<float>> renderBuffer;
    unsigned int previousSampleRate;
    unsigned int previousNumberOfInputChannels;
    unsigned int previousNumberOfOutputChannels;

    buffer::AudioData<float> tempBufferChannel0;
    buffer::AudioData<float> tempBufferChannel1;
    buffer::AudioData<float> tempMonoBuffer;
    buffer::AudioData<float> tempInterleavedBuffer;
};

}
