//
//  AudioRenderer.cpp
//  HighwayDash
//
//  Created by John Ryland on 18/02/2016.
//  Copyright © 2016 John Ryland. All rights reserved.
//

#include "AudioRenderer.h"
#include "Log.h"
#include <QAudioOutput>
#include <vector>


struct AudioRenderer::Pimpl
{
    // private implementation details here
    QIODevice     *m_audioDevice;
    QAudioOutput  *m_audioUnit;
};


AudioRenderer::AudioRenderer()
    : m_pimpl(std::unique_ptr<Pimpl>(new Pimpl()))
{
    m_pimpl->m_audioUnit = nullptr;
    m_pimpl->m_audioDevice = nullptr;
}


AudioRenderer::~AudioRenderer()
{
    delete m_pimpl->m_audioUnit;
}


void AudioRenderer::initialize(SampleRate a_rate, BitsPerChannel a_bitsPerChannel, Channels a_channels)
{
    QAudioFormat format;
    // Set up the format, eg.
    format.setSampleRate(a_rate);
    format.setChannelCount(a_channels);
    format.setSampleSize(a_bitsPerChannel);
    format.setCodec("audio/pcm");
    format.setByteOrder(QAudioFormat::LittleEndian);
    format.setSampleType(QAudioFormat::SignedInt);

    QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
    if (!info.isFormatSupported(format)) {
      Log(LL_Warn, "AUDIO", "Raw audio format not supported by backend, cannot play audio.");
      return;
    }

    delete m_pimpl->m_audioUnit;
    m_pimpl->m_audioUnit = new QAudioOutput(format, this);
    m_pimpl->m_audioUnit->setNotifyInterval(50);
    m_pimpl->m_audioUnit->setBufferSize(100000);//in bytes
    m_pimpl->m_audioUnit->setVolume(0.3);
    connect(m_pimpl->m_audioUnit, SIGNAL(notify()), this, SLOT(writeMoreData()));
}


void AudioRenderer::start()
{
    if (m_pimpl->m_audioUnit)
    {
      m_pimpl->m_audioDevice = m_pimpl->m_audioUnit->start();
      writeMoreData();        
    }
}


void AudioRenderer::stop()
{
     m_pimpl->m_audioUnit->stop();
}
    

void AudioRenderer::writeMoreData()
{
    int nbBytes = m_pimpl->m_audioUnit->bytesFree();
    if (nbBytes > 0 && m_pimpl->m_audioDevice)
    {
        std::vector<char> buf;
        buf.resize(nbBytes);
        renderSamples(buf.data(), buf.size()/2);
        m_pimpl->m_audioDevice->write(buf.data(), buf.size());
    }
}
