/*  This file is part of the KDE project
    Copyright (C) 2006 Matthias Kretz <kretz@kde.org>
    Copyright (C) 2006-2007 Tim Beaulen <tbscope@gmail.com>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    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., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#include "audiooutput.h"

#include "qbtgstreamer/qbtgstreamerbin.h"
#include "qbtgstreamer/qbtgstreamerelementfactory.h"

#include <QVector>
#include <QString>

#include <kdebug.h>

//#include <config.h>
//#include <config-phonon.h>

/*
 * This class manages the inputs for an audio consumer.
 * It does:
 *  - mixing
 *  - audio conversion/resampling
 *  - providing upstream with sinkpads.
 *
 *  +-------------------------------------------------------------+
 *  |                                                             |
 *  | +---------+  +----------+  +--------+  +-------+            |
 *  --| convert |--| resample |--| volume |--| adder |  +-------+ |
 *  | +---------+  +----------+  +--------+  |       |  | sink  | |
 *  |                                        |       |--|       | |
 *  | +---------+  +----------+  +--------+  |       |  |       | |
 *  --| convert |--| resample |--| volume |--|       |  +-------+ |
 *  | +---------+  +----------+  +--------+  +-------+            |
 *  |                                                             |
 *  +-------------------------------------------------------------+
 *
 *  The sink element can be any element with a sinkpad and is created by calling
 *  the vmethod get_element.
 */
namespace Phonon
{
namespace GStreamer
{
AudioOutput::AudioOutput(QObject *parent)
    : AbstractAudioOutput( parent )
    , m_device( 1 )
    , d(new AudioOutputPrivate)
{
    kDebug(611) << k_funcinfo << endl;
}

AudioOutput::~AudioOutput()
{
    delete d;
}

qreal AudioOutput::volume() const
{
    return m_volume;
}

int AudioOutput::outputDevice() const
{
    return m_device;
}

void AudioOutput::setVolume(qreal newVolume)
{
    if (m_volume == newVolume)
        return;

    kDebug(611) << k_funcinfo << endl;

    m_volume = newVolume;

    QbtGStreamerElement *volume = d->element->elementByName("volume%d");

    if (!volume)
        return;

    kDebug(611) << "Found volume element '" << volume->name() << "'" << endl;

    emit volumeChanged(m_volume);
}

bool AudioOutput::setOutputDevice(int newDevice)
{
    m_device = newDevice;

    // TODO: Add code to actually change the output device.
    return true;
}

QbtGStreamerGhostPad *AudioOutput::requestSinkPad()
{
    return d->requestSinkPad();
}

void AudioOutput::releaseSinkPad(QbtGStreamerGhostPad *pad)
{
    d->releaseSinkPad(pad);
}

QbtGStreamerElement *AudioOutputPrivate::getElement()
{
    kDebug(611) << k_funcinfo << endl;

    QbtGStreamerBin *elem;
    QbtGStreamerElement *snk;
    QbtGStreamerElement *convert;
    QbtGStreamerElement *volume;
    QbtGStreamerPad *pad;
    QbtGStreamerPad *ghost;

    kDebug(611) << "Making element 'autoaudiosink'" << endl;
    snk = QbtGStreamerElementFactory::makeElement("autoaudiosink", "");
    kDebug(611) << "autoaudiosink name = " << snk->name() << endl;
    if (!snk) {
        kWarning(611) << "Could not create the element 'autoaudiosink'" << endl;
        return 0;
    }

    convert = QbtGStreamerElementFactory::makeElement("audioconvert", "");
    kDebug(611) << "audioconvert name = " << convert->name() << endl;
    if (!convert) {
        kWarning(611) << "Could not create the element 'audioconvert'" << endl;
        return 0;
    }

    volume = QbtGStreamerElementFactory::makeElement("volume", "");
    kDebug(611) << "volume name = " << volume->name() << endl;
    if (!volume) {
        kWarning(611) << "Could not create the element 'volume'" << endl;
        return 0;
    }

    elem = new QbtGStreamerBin(QString::Null());
    elem->addElement(convert);
    elem->addElement(volume);
    elem->addElement(snk);

    convert->link(volume);
    volume->link(snk);

    pad = convert->pad("sink");
    ghost = new QbtGStreamerGhostPad("sink", pad);

    ghost->setActive(true);
    elem->addPad(ghost);

    sink = elem;

    return elem;
}

bool AudioOutputPrivate::setup()
{
    kDebug(611) << k_funcinfo << endl;

    pipeline = Pipeline::instance();

    if (!getElement())
        return false;

    sink = getElement();
    if (!sink) {
        kWarning(611) << "Could not create sink element!" << endl;
        return false;
    }

    QbtGStreamerBin *bin = new QbtGStreamerBin("");

    bin->addElement(sink);
    
    adder = QbtGStreamerElementFactory::makeElement("adder", "");

    bin->addElement(adder);

    kDebug(611) << "Linking adder and sink" << endl;
    adder->link(sink);

    element = bin;
    element->setState(QbtGStreamerStatePaused);
    
    pipeline->add(element);

    return true;
}

QbtGStreamerGhostPad *AudioOutputPrivate::requestSinkPad()
{
    kDebug(611) << k_funcinfo << endl;

    QbtGStreamerPad *pad;
    QbtGStreamerGhostPad *result;

    pad = adder->requestPad("sink%d");
    if (!pad) {
        kWarning(611) << "Could not get a sink request pad from adder" << endl;
        return 0;
    }

    result = new QbtGStreamerGhostPad(pad->name(), pad);

    /* activate and add to element */
    result->setActive(true);
    element->addPad(result);

    return result;
}

void AudioOutputPrivate::releaseSinkPad(QbtGStreamerGhostPad *pad)
{
    kDebug(611) << k_funcinfo << endl;

    /* release the pad */
    kDebug(611) << "[ " << pad << "] Getting the target pad" << endl;
    QbtGStreamerPad *target;
    target = pad->target();

    kDebug(611) << "[ " << pad << "] Target = " << target << " - target name = " << target->name() << endl;

    kDebug(611) << "[ " << pad << "] Releasing the target request pad from adder" << endl;
    adder->releaseRequestPad(target);

    kDebug(611) << "[ " << pad << "] Deactivating the pad" << endl;
    pad->setActive(false);

    kDebug(611) << "[ " << pad << "] Removing the pad" << endl;
    element->removePad(pad);
}

}} //namespace Phonon::GStreamer

#include "audiooutput.moc"
// vim: sw=4 ts=4 et
