#include "audio.h"

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/time.h>

extern "C"
{
    #include "../src/libsm64.h"
    #include "context.h"
}

static SDL_AudioDeviceID dev;

pthread_t gSoundThread;

long long timeInMilliseconds(void)
{
    struct timeval tv;
    gettimeofday(&tv, nullptr);

    return (long long)tv.tv_sec * 1000 + tv.tv_usec / 1000;
}

void *audio_thread(void *keepAlive)
{
    // from https://github.com/ckosmic/libsm64/blob/audio/src/libsm64.c#L535-L555
    // except keepAlive is a null pointer here, so don't use it

    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, nullptr);
    pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, nullptr);

    long long currentTime = timeInMilliseconds();
    long long targetTime = 0;
    while (1)
    {
        //if(!*((bool*)keepAlive)) return nullptr;

        int16_t audioBuffer[544 * 2 * 2];
        uint32_t numSamples = sm64_audio_tick(SDL_GetQueuedAudioSize(dev) / 4, 1100, audioBuffer);
        if (SDL_GetQueuedAudioSize(dev) / 4 < 6000)
            SDL_QueueAudio(dev, audioBuffer, numSamples * 2 * 4);

        targetTime = currentTime + 33;
        while (timeInMilliseconds() < targetTime)
        {
            usleep(100);
            //if(!*((bool*)keepAlive)) return nullptr;
        }
        currentTime = timeInMilliseconds();
    }
}

void audio_init()
{
    if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
    {
        fprintf(stderr, "SDL_InitSubSystem(SDL_INIT_AUDIO) failed: %s\n", SDL_GetError());
        return;
    }

    SDL_AudioSpec want, have;
    SDL_zero(want);
    want.freq = 32000;
    want.format = AUDIO_S16;
    want.channels = 2;
    want.samples = 512;
    want.callback = nullptr;
    dev = SDL_OpenAudioDevice(nullptr, 0, &want, &have, 0);
    if (dev == 0)
    {
        fprintf(stderr, "SDL_OpenAudio error: %s\n", SDL_GetError());
        return;
    }
    SDL_PauseAudioDevice(dev, 0);

    // it's best to run audio in a separate thread
    pthread_create(&gSoundThread, nullptr, audio_thread, nullptr);
}

