/*  aKode: Frame-to-Stream Sink

    Copyright (C) 2004 Allan Sandfeld Jensen <kde@carewolf.com>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/

#include <pthread.h>

#include "audioframe.h"
#include "audiobuffer.h"
#include "sink.h"
#include "frametostream_sink.h"

namespace aKode {

struct FrameToStreamSink::private_data
{
    private_data() : buffer(0)
                   , out_sink(0)
                   , running(false)
                   , halt(false)
                   , latest_pos(-1) {};
    AudioBuffer *buffer;
    Sink *out_sink;
    bool running;
    pthread_t streamSink;
    volatile bool halt;
    volatile long latest_pos;
};

// The sink-thread. It is controlled through the two variables
// halt and seek_pos in m_data
static void* run_sink(void* arg) {
    FrameToStreamSink::private_data *m_data = (FrameToStreamSink::private_data*)arg;

    AudioFrame frame;
    bool no_error;
    m_data->halt = false;

    while(true) {
        no_error = m_data->buffer->get(&frame, true);

        if (no_error) {
            no_error = m_data->out_sink->writeFrame(&frame);
        }

        if (!no_error) {
            //if (m_data->inDecoder->error() || m_data->inDecoder->eof()) {
                m_data->halt = true;
                m_data->running = false;
                return (void*)-1;
            //}
        }

        if (m_data->halt) break;
    }

    m_data->running=false;
    return (void*)0;
}

FrameToStreamSink::FrameToStreamSink(Sink *out_sink){
    m_data = new private_data;
    m_data->out_sink = out_sink;
}

FrameToStreamSink::~FrameToStreamSink() {
    halt();
    delete m_data;
}

void FrameToStreamSink::writeStream(AudioBuffer* buffer)
{
    m_data->buffer = buffer;
    if (pthread_create(&m_data->streamSink, 0, run_sink, m_data) == 0) {
        m_data->running = true;
    }
}

void FrameToStreamSink::halt() {
    m_data->halt = true;
    if (m_data->running) {
        m_data->buffer->release();
        pthread_join(m_data->streamSink, 0);
        m_data->buffer = 0;
    }
}

long FrameToStreamSink::position() {
    if (m_data->running) {
        return m_data->latest_pos;
    }
    return -1;
}

int FrameToStreamSink::setAudioConfiguration(const AudioConfiguration *config) {
    return m_data->out_sink->setAudioConfiguration(config);
}

const AudioConfiguration* FrameToStreamSink::audioConfiguration() const {
    return m_data->out_sink->audioConfiguration();
}

} // namespace
