/*
   Pure Media Server - A Media Server Sotfware for stage and performing

   Copyright (C) 2012-2013  Santi Noreña libremediaserver@gmail.com

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

   This program 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 General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "libremediaserver.h"

// Esto habrá que cambiarlo para poder utilizar varias instancias
#define PDPORTW 9195

#define PDPORTW_AUDIO 9197
#define PDPORTR_AUDIO 9198

#define SOCKET "/tmp/pmspipe" // Pipe wich PD Video sends the files for preview in the GUI

#define CONF_FILE "lms.conf" // File when saving/restoring the configuration on exit/open


///////////////////////////////////////////////////////////////////
// Struct for the configuration files
///////////////////////////////////////////////////////////////////

struct conf
{
// Video configuration
bool window;
quint16 winpositionx;
quint16 winpositiony;
quint16 winsizex;
quint16 winsizey;
quint16 layer1Add;
bool layer1Check;
quint16 layer2Add;
bool layer2Check;
quint16 layer3Add;
bool layer3Check;
quint16 layer4Add;
bool layer4Check;
quint16 layer5Add;
bool layer5Check;
quint16 layer6Add;
bool layer6Check;
quint16 layer7Add;
bool layer7Check;
quint16 layer8Add;
bool layer8Check;
bool dmx;
quint8 universe;
quint8 ipadd1;
quint8 ipadd2;
quint8 ipadd3;
quint8 ipadd4;
bool videoCheck;

// Audio Configuration
quint16 layer1Add_audio;
bool layer1Check_audio;
quint16 layer2Add_audio;
bool layer2Check_audio;
quint16 layer3Add_audio;
bool layer3Check_audio;
quint16 layer4Add_audio;
bool layer4Check_audio;
quint16 layer5Add_audio;
bool layer5Check_audio;
quint16 layer6Add_audio;
bool layer6Check_audio;
quint16 layer7Add_audio;
bool layer7Check_audio;
quint16 layer8Add_audio;
bool layer8Check_audio;
bool dmx_audio;
quint8 universe_audio;
bool audioCheck;
};

///////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////

libreMediaServer::libreMediaServer(QStringList args, QWidget *parent)
    : QMainWindow(parent),
      m_startvideo(0),
      m_startaudio(0),
      m_pd_video(NULL),
      m_pd_audio(NULL),
      m_pd_write_audio(NULL),
      m_pd_read_audio(NULL),
      m_tcpsocket_audio(NULL),
      m_gui(FALSE)
{
     qDebug() << "********************************************************************************";
     qDebug() <<  QDate::currentDate() << QTime::currentTime();
     // Iniciamos el User Interface
     ui.setupUi(this);
     // Parse the command line options
     if (args.contains("-gui"))
     {
         qDebug()<< "libremediaserver Constructor option GUI detected";
         m_gui = true;
         ui.textEdit->appendPlainText("Pure Data GUI's will be shown");
     }
     if (args.contains("-log"))
     {
         ui.textEdit->appendPlainText("Log to file");
     }
     //Print the version
     QString ver;
     ver = VERSION;
     ui.textEdit->appendPlainText(ver);
     ver = COPYRIGHT;
     ui.textEdit->appendPlainText(ver);
     ver = LICENSE;
     ui.textEdit->appendPlainText(ver);
     qDebug() << VERSION;
     qDebug() << COPYRIGHT;
     qDebug() << LICENSE;
     // Init Unix Local Sockets
     QFile socket(SOCKET);
     if (socket.exists())
     {
        socket.remove();
     }
     m_server_vid = new QLocalServer(this);
     Q_CHECK_PTR(m_server_vid);
     if (!m_server_vid->listen(SOCKET))
     {
         qErrnoWarning("libremediaserver::constructor L132: Can not listen on unix local server");
     }
     connect(m_server_vid, SIGNAL(newConnection()),this, SLOT(newPeer()));
     // Creamos los sockets para mandar paquetes a PD
     m_pd_write_video = new QTcpSocket(this);
     Q_CHECK_PTR(m_pd_write_video);
     connect(m_pd_write_video, SIGNAL(connected()),this, SLOT(newconexion()));
     // Start preview Timer
     m_preview = new QTimer(this);
     Q_CHECK_PTR(m_preview);
     m_preview->start(500);
     connect(m_preview, SIGNAL(timeout()) ,this, SLOT(previewMaster()));
     // The mediaserver object: CITP/MSEx
     m_msex = new msex(this);
     Q_CHECK_PTR(m_msex);
     // Iniciamos olad
     m_ola = new QProcess(this);
     olastart();
     // Conectamos los menus
    connect(ui.actionOpen_conf, SIGNAL(triggered()), this, SLOT(openFile()));
    connect(ui.actionSave_conf, SIGNAL(triggered()), this, SLOT(saveFile()));
    connect(ui.actionChange_Media_Path, SIGNAL(triggered()), this, SLOT(ChangeMediaPath()));
    connect(ui.actionInitMSEX, SIGNAL(triggered()), this, SLOT(initMSEX()));
    connect(ui.actionMake_Thumbs, SIGNAL(triggered()), this, SLOT(makeThumbs()));
    connect(ui.actionLaunch_OLA_Setup,SIGNAL(triggered()),this, SLOT(olasetup()));
    // Load the configuration
    open_start();
    // Connect MSEx Timer
    connect(m_msex,SIGNAL(frameRequest()), this, SLOT(sendFrame())); 
}

///////////////////////////////////////////////////////////////////
// Destructor
///////////////////////////////////////////////////////////////////

libreMediaServer::~libreMediaServer()
{
    save_finish();
    QFile socket(SOCKET);
    socket.remove();
    if (m_pd_write_video != NULL) {
          m_pd_write_video->abort();
          delete m_pd_write_video;
        }
    if (m_server_vid->isListening()) {
        m_server_vid->close();
        delete m_server_vid;
    }
    if (m_pd_video != NULL)
    {
        disconnect(m_pd_video, SIGNAL(finished(int)), this, SLOT(pdrestart()));
        m_pd_video->terminate();
        if (m_pd_video->waitForFinished(30000))
        {
            delete m_pd_video;
        }
    }
    m_ola->close();
    delete m_ola;
    if (m_pd_audio != NULL)
    {
        disconnect(m_pd_audio, SIGNAL(finished(int)), this, SLOT( pdrestart_audio()));
        m_pd_audio->terminate();
        if (m_pd_audio->waitForFinished(30000))
        {
            delete m_pd_audio;
        }
    }
    if (m_pd_write_audio != NULL)
    {
        m_pd_write_audio->close();
        delete m_pd_write_audio;
    }
    if (m_pd_write_audio != NULL)
    {
         m_pd_read_audio->close();
         delete m_pd_read_audio;
    }
    socket.remove();
    qDebug() << "PD Video restarts: " << m_startvideo << " PD Audio restarts: " << m_startaudio;
    qDebug() << QDate::currentDate() << QTime::currentTime();
    qDebug() << "********************************************************************************";
    return;
}

///////////////////////////////////////////////////////////////////
// open/save the last configuration known
///////////////////////////////////////////////////////////////////

// Load the last configuration from the configuration file
void libreMediaServer::open_start()
{
    QFile file(CONF_FILE);
    open(&file);
}

// Save the last configuration to the conf file
void libreMediaServer::save_finish()
{
    QFile file(CONF_FILE);
    save(&file);

}

///////////////////////////////////////////////////////////////////
// Menu File
///////////////////////////////////////////////////////////////////

// Open a configuration File
void libreMediaServer::openFile()
{
    QFileDialog dialog(this);
    if (!dialog.exec())
        return;
    QStringList fileNames;
    fileNames = dialog.selectedFiles();
    QFile file(fileNames.at(0));
    open(&file);
}
// Save configuration File
void libreMediaServer::saveFile()
{
    QFileDialog dialog(this);
    if (!dialog.exec())
        return;
    QStringList fileNames;
    fileNames = dialog.selectedFiles();
    QFile file(fileNames.at(0));
    save(&file);
}
// Change Media path
void libreMediaServer::ChangeMediaPath()
{
    QFileDialog dialog(this);
    dialog.setFileMode(QFileDialog::Directory);
    QStringList fileNames;
    if (!dialog.exec())
        return;
    fileNames = dialog.selectedFiles();
    QString file = fileNames.at(0);
    m_pathmedia = file;
    QString desc = tr("0000 0000 %1;").arg(file);
    if (ui.video->checkState())
    {
        if (!sendPacket(desc.toAscii().constData(),desc.size()))
        {
            errorsending();
        }
    }
    if (ui.audio->checkState())
    {
        if (!sendPacket_audio(desc.toAscii().constData(),desc.size()))
        {
            errorsending_audio();
        }
    }
    desc = tr("Media Path Changed to: %1").arg(m_pathmedia);
    ui.textEdit->appendPlainText(desc.toAscii());
}

///////////////////////////////////////////////////////////////////
// Open/save Subroutines. The real work.
///////////////////////////////////////////////////////////////////

void libreMediaServer::open(QFile *file)
{
    if (!file->open(QIODevice::ReadOnly | QIODevice::Text))
    {
    qDebug()<<("Can not find the configuration file");
    return;
    }
    int size = file->size();
    unsigned char * fileconf = new unsigned char[size];
    memset(fileconf, 0, size);
    fileconf = file->map(0x00, size);
    if (fileconf == 0){
        qDebug()<<("Cannot map the file");
        return;
    }
    conf *packet = (conf *)fileconf;
    // Video configuration
    ui.window->setChecked(packet->window);
    ui.winpositionx->setValue(packet->winpositionx);
    ui.winpositiony->setValue(packet->winpositiony);
    ui.winsizex->setValue(packet->winsizex);
    ui.winsizey->setValue(packet->winsizey);
    ui.layer1Add->setValue(packet->layer1Add);
    ui.layer1Check->setChecked(packet->layer1Check);
    ui.layer2Add->setValue(packet->layer2Add);
    ui.layer2Check->setChecked(packet->layer2Check);
    ui.layer3Add->setValue(packet->layer3Add);
    ui.layer3Check->setChecked(packet->layer3Check);
    ui.layer4Add->setValue(packet->layer4Add);
    ui.layer4Check->setChecked(packet->layer4Check);
    ui.layer5Add->setValue(packet->layer5Add);
    ui.layer5Check->setChecked(packet->layer5Check);
    ui.layer6Add->setValue(packet->layer6Add);
    ui.layer6Check->setChecked(packet->layer6Check);
    ui.layer7Add->setValue(packet->layer7Add);
    ui.layer7Check->setChecked(packet->layer7Check);
    ui.layer8Add->setValue(packet->layer8Add);
    ui.layer8Check->setChecked(packet->layer8Check);
    ui.readDMX->setChecked(packet->dmx);
    ui.universe->setValue(packet->universe);
    ui.ipAddress1->setValue(packet->ipadd1);
    ui.ipAddress2->setValue(packet->ipadd2);
    ui.ipAddress3->setValue(packet->ipadd3);
    ui.ipAddress4->setValue(packet->ipadd4);
    ui.video->setChecked(packet->videoCheck);
    // Audio Configuration
    ui.layer1Add_audio->setValue(packet->layer1Add_audio);
    ui.layer1Check_audio->setChecked(packet->layer1Check_audio);
    ui.layer2Add_audio->setValue(packet->layer2Add_audio);
    ui.layer2Check_audio->setChecked(packet->layer2Check_audio);
    ui.layer3Add_audio->setValue(packet->layer3Add_audio);
    ui.layer3Check_audio->setChecked(packet->layer3Check_audio);
    ui.layer4Add_audio->setValue(packet->layer4Add_audio);
    ui.layer4Check_audio->setChecked(packet->layer4Check_audio);
    ui.layer5Add_audio->setValue(packet->layer5Add_audio);
    ui.layer5Check_audio->setChecked(packet->layer5Check_audio);
    ui.layer6Add_audio->setValue(packet->layer6Add_audio);
    ui.layer6Check_audio->setChecked(packet->layer6Check_audio);
    ui.layer7Add_audio->setValue(packet->layer7Add_audio);
    ui.layer7Check_audio->setChecked(packet->layer7Check_audio);
    ui.layer8Add_audio->setValue(packet->layer8Add_audio);
    ui.layer8Check_audio->setChecked(packet->layer8Check_audio);
    ui.readDMX_audio->setChecked(packet->dmx_audio);
    ui.universe_audio->setValue(packet->universe_audio);
    ui.audio->setChecked(packet->audioCheck);
    // Path to media
    int offset = sizeof(struct conf);
    size = size - offset;
    char * buffer = new char[size];
    memset(buffer, 0, size);
    memcpy(buffer, fileconf+offset, size);
    m_pathmedia = buffer;
    QString desc = tr("Media Path Changed to: %1").arg(m_pathmedia);
    qDebug()<<(desc);
    file->close();
    delete buffer;
//    delete file;
    //    delete fileconf; // Comment due to Seg Fault
}

void libreMediaServer::save(QFile *file)
{
    if (!file->open(QIODevice::WriteOnly | QIODevice::Text))
    {
        qDebug()<<("Can not open file pms.conf");
        return;
    }
    int bufferLen = sizeof(struct conf) + m_pathmedia.size();
    unsigned char *buffer = new unsigned char[bufferLen];
    memset(buffer, 0, bufferLen);
    conf *packet = (conf *)buffer;
    // Video Configuration
    packet->window = ui.window->checkState();
    packet->winpositionx = ui.winpositionx->value();
    packet->winpositiony = ui.winpositiony->value();
    packet->winsizex = ui.winsizex->value();
    packet->winsizey = ui.winsizey->value();
    packet->layer1Add = ui.layer1Add->value();
    packet->layer1Check = ui.layer1Check->checkState();
    packet->layer2Add = ui.layer2Add->value();
    packet->layer2Check = ui.layer2Check->checkState();
    packet->layer3Add = ui.layer3Add->value();
    packet->layer3Check = ui.layer3Check->checkState();
    packet->layer4Add = ui.layer4Add->value();
    packet->layer4Check = ui.layer4Check->checkState();
    packet->layer5Add = ui.layer5Add->value();
    packet->layer5Check = ui.layer5Check->checkState();
    packet->layer6Add = ui.layer6Add->value();
    packet->layer6Check = ui.layer6Check->checkState();
    packet->layer7Add = ui.layer7Add->value();
    packet->layer7Check = ui.layer7Check->checkState();
    packet->layer8Add = ui.layer8Add->value();
    packet->layer8Check = ui.layer8Check->checkState();
    packet->dmx = ui.readDMX->checkState();
    packet->universe = ui.universe->value();
    packet->ipadd1 = ui.ipAddress1->value();
    packet->ipadd2 = ui.ipAddress2->value();
    packet->ipadd3 = ui.ipAddress3->value();
    packet->ipadd4 = ui.ipAddress4->value();
    packet->videoCheck = ui.video->checkState();
    // Audio Configuration
    packet->layer1Add_audio = ui.layer1Add_audio->value();
    packet->layer1Check_audio = ui.layer1Check_audio->checkState();
    packet->layer2Add_audio = ui.layer2Add_audio->value();
    packet->layer2Check_audio = ui.layer2Check_audio->checkState();
    packet->layer3Add_audio = ui.layer3Add_audio->value();
    packet->layer3Check_audio = ui.layer3Check_audio->checkState();
    packet->layer4Add_audio = ui.layer4Add_audio->value();
    packet->layer4Check_audio = ui.layer4Check_audio->checkState();
    packet->layer5Add_audio = ui.layer5Add_audio->value();
    packet->layer5Check_audio = ui.layer5Check_audio->checkState();
    packet->layer6Add_audio = ui.layer6Add_audio->value();
    packet->layer6Check_audio = ui.layer6Check_audio->checkState();
    packet->layer7Add_audio = ui.layer7Add_audio->value();
    packet->layer7Check_audio = ui.layer7Check_audio->checkState();
    packet->layer8Add_audio = ui.layer8Add_audio->value();
    packet->layer8Check_audio = ui.layer8Check_audio->checkState();
    packet->dmx_audio = ui.readDMX_audio->checkState();
    packet->universe_audio = ui.universe_audio->value();
    packet->audioCheck = ui.audio->checkState();
    // Path to media
    int offset = sizeof (struct conf);
    memcpy(buffer+offset, m_pathmedia.toAscii().constData(), m_pathmedia.size());
    int error =  file->write((const char *)buffer, bufferLen);
    QString errorstring = tr("Bytes Write to file %1").arg(error);
    qDebug()<<"Saved file complete:"<<(errorstring);
    file->close();
    delete buffer;
}

///////////////////////////////////////////////////////////////////
// OLA Stuff
///////////////////////////////////////////////////////////////////

void libreMediaServer::olastart()
{
    qDebug()<<("Starting OLA");
    m_ola->start("olad", QStringList()<< "-l 3");
//    connect(ola, SIGNAL(finished(int)), this, SLOT(olastart()));
}

void libreMediaServer::olasetup()
{
    QWebView *view = new QWebView();
    view->load(QUrl("http://localhost:9090/ola.html"));
    view->show();
}

///////////////////////////////////////////////////////////////////
// Menu CITP/MSEx
///////////////////////////////////////////////////////////////////

// Init the CITP/MSEx protocol.
void libreMediaServer::initMSEX()
{
    // Chequeamos si existe el path a los medias
    QDir dir(m_pathmedia);
     if (!dir.exists())
     {
         qDebug()<<("Cannot find the media directory");
         ui.textEdit->appendPlainText("Can not find the media directory in the path given");
         return;
     }
     m_msex->setpath(m_pathmedia);
     if (!m_msex->updatemedia())
     {
         qDebug()<<("Cannot explore the media");
         ui.textEdit->appendPlainText("Can not explore the media in the path given");
         return;
     }
     // Creamos el objeto CITP y el peer information socket
     quint32 ipadd = 0x00000000;
     quint32 i;
     i = ui.ipAddress1->value();
     ipadd = ipadd + (i * 0x1000000);
     i =ui.ipAddress2->value();
     ipadd = ipadd + (i * 0x10000);
     i = ui.ipAddress3->value();
     ipadd = ipadd + (i * 0x100);
     i = ui.ipAddress4->value();
     ipadd = ipadd + i;
     m_msex->startCitp(ipadd);
}

// Generates the thumbs to transmit by CITP/MSEx
void libreMediaServer::makeThumbs()
{
    QString s = "Creating thumbs in ";
    s.append(m_pathmedia);
    s.append(" This operation can take some time...");
    ui.textEdit->appendPlainText(s);
    QProcess *script;
    QStringList arguments;
    arguments << m_pathmedia;
    qDebug() << s.toAscii();
    script->execute("./scripts/make_thumbs.sh", arguments);
}

///////////////////////////////////////////////////////////////////
// Video Controls
///////////////////////////////////////////////////////////////////

// Window Configuration

void libreMediaServer::on_window_stateChanged(int state)
{
    if ((state == 2)) {
       QString desc("0001 0001;");
       if (!sendPacket(desc.toAscii().constData(),desc.size()))
       {
        errorsending();
       }
    }
    if ((state == 0)) {
          QString desc("0001 0000;");
          if (!sendPacket(desc.toAscii().constData(),desc.size()))
          {
           errorsending();
          }
   }
}

void libreMediaServer::on_winpositionx_valueChanged()
{
    int x = ui.winpositionx->value();
    QString desc = tr("0002 %1;").arg(x);
    if (!sendPacket(desc.toAscii().constData(),desc.size()))
            {
             errorsending();
            }
}

void libreMediaServer::on_winpositiony_valueChanged()
{
    int x = ui.winpositiony->value();
    QString desc = tr("3 %1;").arg(x);
    if (!sendPacket(desc.toAscii().constData(),desc.size()))
            {
             errorsending();
            }
}

void libreMediaServer::on_winsizex_valueChanged()
{
    int x = ui.winsizex->value();
    QString desc = tr("4 %1;").arg(x);
    if (!sendPacket(desc.toAscii().constData(),desc.size()))
            {
             errorsending();
            }
}

void libreMediaServer::on_winsizey_valueChanged()
{
    int x = ui.winsizey->value();
    QString desc = tr("5 %1;").arg(x);
    if (!sendPacket(desc.toAscii().constData(),desc.size()))
            {
             errorsending();
            }
}

// DMX address configuration

void libreMediaServer::on_layer1Check_stateChanged (int state)
{
    if ((state == 0))
    {
        QString desc("0011 0000;");
        if (!sendPacket(desc.toAscii().constData(),desc.size()))
                {
                 errorsending();
                }
         return;
    }
    if ((state == 2))
    {
        on_layer1Add_valueChanged();
    }
}

void libreMediaServer::on_layer1Add_valueChanged()
{
   if (ui.layer1Check->isChecked()){
        int x = ui.layer1Add->value();
        QString desc = tr("0011 %1;").arg(x);
        if (!sendPacket(desc.toAscii().constData(),desc.size()))
           {
            errorsending();
           }
    }
}

void libreMediaServer::on_layer2Check_stateChanged (int state)
{
    if ((state == 0))
    {
        QString desc("0012 0000;");
        if (!sendPacket(desc.toAscii().constData(),desc.size()))
                {
                 errorsending();
                }
        return;
    }
    if ((state == 2))
    {
        on_layer2Add_valueChanged();
    }
}

void libreMediaServer::on_layer2Add_valueChanged()
{
   if (ui.layer2Check->isChecked()){
   int x = ui.layer2Add->value();
   QString desc = tr("0012 %1;").arg(x);
   if (!sendPacket(desc.toAscii().constData(),desc.size()))
           {
            errorsending();
           }
   }
}

void libreMediaServer::on_layer3Check_stateChanged (int state)
{
    if ((state == 0))
    {
        QString desc("0013 0000;");
        if (!sendPacket(desc.toAscii().constData(),desc.size()))
                {
                 errorsending();
                }
        return;
    }
    if ((state == 2))
    {
        on_layer3Add_valueChanged();
    }
}

void libreMediaServer::on_layer3Add_valueChanged()
{
   if (ui.layer3Check->isChecked()){
   int x = ui.layer3Add->value();
   QString desc = tr("0013 %1;").arg(x);
   if (!sendPacket(desc.toAscii().constData(),desc.size()))
           {
            errorsending();
           }
  }
}

void libreMediaServer::on_layer4Check_stateChanged (int state)
{
    if ((state == 0))
    {
        QString desc("0014 0000;");
        if (!sendPacket(desc.toAscii().constData(),desc.size()))
                {
                 errorsending();
                }
        return;
    }
    if ((state == 2))
    {
        on_layer4Add_valueChanged();
    }
}

void libreMediaServer::on_layer4Add_valueChanged()
{
   if (ui.layer4Check->isChecked()){
   int x = ui.layer4Add->value();
   QString desc = tr("0014 %1;").arg(x);
   if (!sendPacket(desc.toAscii().constData(),desc.size()))
           {
            errorsending();
           }
   }
}

void libreMediaServer::on_layer5Check_stateChanged (int state)
{
    if ((state == 0))
    {
        QString desc("0015 0000;");
        if (!sendPacket(desc.toAscii().constData(),desc.size()))
                {
                 errorsending();
                }
        return;
    }
    if ((state == 2))
    {
        on_layer5Add_valueChanged();
    }
}

void libreMediaServer::on_layer5Add_valueChanged()
{
   if (ui.layer5Check->isChecked()){
   int x = ui.layer5Add->value();
   QString desc = tr("0015 %1;").arg(x);
   if (!sendPacket(desc.toAscii().constData(),desc.size()))
           {
            errorsending();
           }
    }
}

void libreMediaServer::on_layer6Check_stateChanged (int state)
{
    if ((state == 0))
    {
        QString desc("0016 0000;");
        if (!sendPacket(desc.toAscii().constData(),desc.size()))
                {
                 errorsending();
                }
        return;
    }
    if ((state == 2))
    {
        on_layer6Add_valueChanged();
    }
}

void libreMediaServer::on_layer6Add_valueChanged()
{
   if (ui.layer6Check->isChecked()){
   int x = ui.layer6Add->value();
   QString desc = tr("0016 %1;").arg(x);
   if (!sendPacket(desc.toAscii().constData(),desc.size()))
           {
            errorsending();
           }
   }
}

void libreMediaServer::on_layer7Check_stateChanged (int state)
{
    if ((state == 0))
    {
        QString desc("0017 0000;");
        if (!sendPacket(desc.toAscii().constData(),desc.size()))
                {
                 errorsending();
                }
        return;
    }
    if ((state == 2))
    {
        on_layer7Add_valueChanged();
    }
}

void libreMediaServer::on_layer7Add_valueChanged()
{
   if (ui.layer7Check->isChecked()){
   int x = ui.layer7Add->value();
   QString desc = tr("0017 %1;").arg(x);
   if (!sendPacket(desc.toAscii().constData(),desc.size()))
           {
            errorsending();
           }
   }
}

void libreMediaServer::on_layer8Check_stateChanged (int state)
{
    if ((state == 0))
    {
        QString desc("0018 0000;");
        if (!sendPacket(desc.toAscii().constData(),desc.size()))
                {
                 errorsending();
                }
        return;
    }
    if ((state == 2))
    {
        on_layer8Add_valueChanged();
    }
}

void libreMediaServer::on_layer8Add_valueChanged()
{
   if (ui.layer8Check->isChecked()){
   int x = ui.layer8Add->value();
   QString desc = tr("0018 %1;").arg(x);
   if (!sendPacket(desc.toAscii().constData(),desc.size()))
           {
            errorsending();
           }
  }
}

// Open the connection with OLA and start reading DMX
void libreMediaServer::on_readDMX_stateChanged(int state)
{
    if ((state == 0)) {
        QString desc("0020 0000;");
        if (!sendPacket(desc.toAscii().constData(),desc.size()))
                {
                 errorsending();
                }
        }
    if ((state == 2))
    {
        int x = ui.universe->value();
        QString desc = tr("0021 %1;").arg(x);
        if (!sendPacket(desc.toAscii().constData(),desc.size()))
                {
                 errorsending();
                }
        desc = tr("0020 0001;");
        if (!sendPacket(desc.toAscii().constData(),desc.size()))
                {
                 errorsending();
                }
        }
 }

// Start the video process
void libreMediaServer::on_video_stateChanged(int state)
{
    if ((state == 0))
         {
        disconnect(m_pd_video, SIGNAL(readyReadStandardError()), this, SLOT(stdout()));
        disconnect(m_pd_video, SIGNAL(finished(int)), this, SLOT(pdrestart()));
        m_pd_video->terminate();
        m_pd_video = NULL;
        delete m_pd_video;
    }
    if ((state == 2))
    {
   // Iniciamos Pure Data
   m_pd_video = new QProcess(this);
   pdstart();
   }
}

// Change the Frame Rate
void libreMediaServer::on_fpsRate_valueChanged()
{
    QString desc = tr("0023 %1;").arg(ui.fpsRate->value());
    if (!sendPacket(desc.toAscii().constData(),desc.size()))
            {
        errorsending();
            }
}

///////////////////////////////////////////////////////////////////
// Pure Data Video
///////////////////////////////////////////////////////////////////

// Start the PD Process, open the ports and connects stdout de Pure Data.
void libreMediaServer::pdstart()
{
    if (m_pd_video->state() != 0)
    {
        return;
    }
    // Arrancamos el proceso Pure Data
    QString arguments;
    arguments.append("./puredata/pd -noaudio -lib Gem -stderr -nostdpath -path ./puredata/externals/ -open ./puredata/lms-video.pd ");
    if (!m_gui)
        arguments.append("-nogui");
    m_pd_video->start(arguments);
    if (m_pd_video->waitForStarted(3000)){
        ui.textEdit->appendPlainText("Video Engine started.");
    }
    else
    {
        qWarning("PD Video can not start") ;
        ui.textEdit->appendPlainText("Video Engine can not start!");
        return;
    }
    // Connect the output from PD Video to stdout slot to process it
    connect(m_pd_video, SIGNAL(readyReadStandardError()), this, SLOT(stdout()));
    // Restart PD Video if crash
    connect(m_pd_video, SIGNAL(finished(int)), this, SLOT(pdrestart()));
}

// Restart the Pure Data process if crash. Connected with signal finished of QProcess
void libreMediaServer::pdrestart()
{
    if (m_pd_video->state())
    {
        return;
    }
    save_finish();
    qDebug()<<"********************************************************************************";
    qDebug()<<"PD Video Restarts:" << ++m_startvideo;
    ui.textEdit->appendPlainText("PD Video Restarting.");
    m_pd_write_video->close();

    disconnect(m_pd_video, SIGNAL(finished(int)), this, SLOT(pdrestart()));
    pdstart();

}

// New conexion on TCP Server
void libreMediaServer::newPeer()
{
   m_read_vid = m_server_vid->nextPendingConnection();
   connect(m_read_vid, SIGNAL(readyRead()),
           this, SLOT(newmessage()));
}

// New message in a socket stablished connection
void libreMediaServer::newmessage()
{
    if (m_read_vid == NULL)
    {
        qDebug()<<("Local Socket not created");
        newPeer();
        return;
    }
    QByteArray byteArray;
    byteArray.resize(m_read_vid->bytesAvailable());
    byteArray = m_read_vid->readAll();
    if (byteArray.isEmpty())
    {
        return;
    }
    QPixmap frame;
    switch (byteArray.at(0)) {
    case 11:
        byteArray.remove(0,2);
        if (!frame.loadFromData((byteArray))) {
            qDebug()<<"Layer 1 Convert byte Array to frame failed ";
        }
        ui.layer1Preview->setPixmap(frame);
        break;

    case 12:
        byteArray.remove(0,2);
        if (!frame.loadFromData((byteArray))) {
            qDebug()<<"Layer 2 Convert byte Array to frame failed ";
        }
        ui.layer2Preview->setPixmap(frame);
        break;
    case 13:
        byteArray.remove(0,2);
        if (!frame.loadFromData((byteArray))) {
            qDebug()<<"Layer 3 Convert byte Array to frame failed ";
            break;
        }
        ui.layer3Preview->setPixmap(frame);
        break;
    case 14:
        byteArray.remove(0,2);
        if (!frame.loadFromData(byteArray)) {
            qDebug()<<"Layer 4 Convert byte Array to frame failed ";
            break;
        }
        ui.layer4Preview->setPixmap(frame);
        break;
    case 15:
        byteArray.remove(0,2);
        if (!frame.loadFromData(byteArray)) {
                qDebug()<<"Layer 5 Convert byte Array to frame failed ";
                break;
        }
        ui.layer5Preview->setPixmap(frame);
        break;
    case 16:
        byteArray.remove(0,2);
        if (!frame.loadFromData(byteArray)) {
                qDebug()<<"Layer 6 Convert byte Array to frame failed ";
                break;
        }
                ui.layer6Preview->setPixmap(frame);
        break;
    case 17:
        byteArray.remove(0,2);
        if (!frame.loadFromData(byteArray)) {
                qDebug()<<"Layer 7 Convert byte Array to frame failed ";
                break;
        }
        ui.layer7Preview->setPixmap(frame);
        break;
    case 18:
        byteArray.remove(0,2);
        if (!frame.loadFromData(byteArray)) {
                qDebug()<<"Layer 8 Convert byte Array to frame failed ";
                break;
        }
        ui.layer8Preview->setPixmap(frame);
        break;
    default:
        qDebug()<<"newmessage: Message received but can not identify the cookie";
        break;
    }
}

// Send the configuration to PD
void libreMediaServer::newconexion()
{
    //Mandamos el path
    QString desc = tr("0000 0000 %1;").arg(m_pathmedia);
    if (!sendPacket(desc.toAscii().constData(),desc.size()))
    {
      ui.textEdit->appendPlainText("newconexion: Can not send the path to PD Video");
      return;
    }
    // send the layer adress
    on_layer1Check_stateChanged (ui.layer1Check->checkState());
    on_layer2Check_stateChanged (ui.layer2Check->checkState());
    on_layer3Check_stateChanged (ui.layer3Check->checkState());
    on_layer4Check_stateChanged (ui.layer4Check->checkState());
    on_layer5Check_stateChanged (ui.layer5Check->checkState());
    on_layer6Check_stateChanged (ui.layer6Check->checkState());
    on_layer7Check_stateChanged (ui.layer7Check->checkState());
    on_layer8Check_stateChanged (ui.layer8Check->checkState());
    // send the dmx on/off
    on_readDMX_stateChanged(ui.readDMX->checkState());
    // send the windows info
    on_winpositionx_valueChanged();
    on_winpositiony_valueChanged();
    on_winsizex_valueChanged();
    on_winsizey_valueChanged();
    on_window_stateChanged(ui.window->checkState());
}

// Sends packets to Pure Data video
bool libreMediaServer::sendPacket(const char *buffer, int bufferLen)
{
 if (m_pd_write_video == NULL) {
     qErrnoWarning("sendPacket:Socket not initialized:");
     return false;
 }
 if (QAbstractSocket::ConnectedState != m_pd_write_video->state())
 {
     qErrnoWarning("sendPacket:Socket not conected:");
     return false;
 }
 if (bufferLen != m_pd_write_video->write((const char*)buffer, bufferLen))
 {
     qErrnoWarning("sendPacket:Can not write to socket::");
     return false;
 }
 return true;
}

// Function error sending packets to PD video
void libreMediaServer::errorsending() {
    if (ui.video->checkState())
    {
    qErrnoWarning("errorsending: Can not talk to Pure Data Video!");
    ui.textEdit->appendPlainText("errorsending: Can not send packets to PD Video");
    }
}

///////////////////////////////////////////////////////////////////
// Audio Controls
///////////////////////////////////////////////////////////////////

void libreMediaServer::on_layer1Check_audio_stateChanged (int state)
{
    if ((state == 0))
    {
        QString desc("0011 0000;");
        if (!sendPacket_audio(desc.toAscii().constData(),desc.size()))
                {
                 errorsending_audio();
                }
        return;
    }
    if ((state == 2))
    {
        on_layer1Add_audio_valueChanged();
    }
}

void libreMediaServer::on_layer1Add_audio_valueChanged()
{
   if (ui.layer1Check_audio->isChecked()){
        int x = ui.layer1Add_audio->value();
        QString desc = tr("0011 %1;").arg(x);
        if (!sendPacket_audio(desc.toAscii().constData(),desc.size()))
           {
            errorsending_audio();
           }
    }
}

void libreMediaServer::on_layer2Check_audio_stateChanged (int state)
{
    if ((state == 0))
    {
        QString desc("0012 0000;");
        if (!sendPacket_audio(desc.toAscii().constData(),desc.size()))
                {
                 errorsending_audio();
                }
        return;
    }
    if ((state == 2))
    {
        on_layer2Add_audio_valueChanged();
    }
}

void libreMediaServer::on_layer2Add_audio_valueChanged()
{
   if (ui.layer2Check_audio->isChecked()){
   int x = ui.layer2Add_audio->value();
   QString desc = tr("0012 %1;").arg(x);
   if (!sendPacket_audio(desc.toAscii().constData(),desc.size()))
           {
            errorsending_audio();
           }
   }
}

void libreMediaServer::on_layer3Check_audio_stateChanged (int state)
{
    if ((state == 0))
    {
        QString desc("0013 0000;");
        if (!sendPacket_audio(desc.toAscii().constData(),desc.size()))
                {
                 errorsending_audio();
                }
        return;
    }
    if ((state == 2))
    {
        on_layer3Add_audio_valueChanged();
    }
}

void libreMediaServer::on_layer3Add_audio_valueChanged()
{
   if (ui.layer3Check_audio->isChecked()){
   int x = ui.layer3Add_audio->value();
   QString desc = tr("0013 %1;").arg(x);
   if (!sendPacket_audio(desc.toAscii().constData(),desc.size()))
           {
            errorsending_audio();
           }
  }
}

void libreMediaServer::on_layer4Check_audio_stateChanged (int state)
{
    if ((state == 0))
    {
        QString desc("0014 0000;");
        if (!sendPacket_audio(desc.toAscii().constData(),desc.size()))
                {
                 errorsending_audio();
                }
        return;
    }
    if ((state == 2))
    {
        on_layer4Add_audio_valueChanged();
    }
}

void libreMediaServer::on_layer4Add_audio_valueChanged()
{
   if (ui.layer4Check_audio->isChecked()){
   int x = ui.layer4Add_audio->value();
   QString desc = tr("0014 %1;").arg(x);
   if (!sendPacket_audio(desc.toAscii().constData(),desc.size()))
           {
            errorsending_audio();
           }
   }
}

void libreMediaServer::on_layer5Check_audio_stateChanged (int state)
{
    if ((state == 0))
    {
        QString desc("0015 0000;");
        if (!sendPacket_audio(desc.toAscii().constData(),desc.size()))
                {
                 errorsending_audio();
                }
        return;
    }
    if ((state == 2))
    {
        on_layer5Add_audio_valueChanged();
    }
}

void libreMediaServer::on_layer5Add_audio_valueChanged()
{
   if (ui.layer5Check_audio->isChecked()){
   int x = ui.layer5Add_audio->value();
   QString desc = tr("0015 %1;").arg(x);
   if (!sendPacket_audio(desc.toAscii().constData(),desc.size()))
           {
            errorsending_audio();
           }
    }
}

void libreMediaServer::on_layer6Check_audio_stateChanged (int state)
{
    if ((state == 0))
    {
        QString desc("0016 0000;");
        if (!sendPacket_audio(desc.toAscii().constData(),desc.size()))
                {
                 errorsending_audio();
                }
        return;
    }
    if ((state == 2))
    {
        on_layer6Add_audio_valueChanged();
    }
}

void libreMediaServer::on_layer6Add_audio_valueChanged()
{
   if (ui.layer6Check_audio->isChecked()){
   int x = ui.layer6Add_audio->value();
   QString desc = tr("0016 %1;").arg(x);
   if (!sendPacket_audio(desc.toAscii().constData(),desc.size()))
           {
            errorsending_audio();
           }
   }
}

void libreMediaServer::on_layer7Check_audio_stateChanged (int state)
{
    if ((state == 0))
    {
        QString desc("0017 0000;");
        if (!sendPacket_audio(desc.toAscii().constData(),desc.size()))
                {
                 errorsending_audio();
                }
        return;
    }
    if ((state == 2))
    {
        on_layer7Add_audio_valueChanged();
    }
}

void libreMediaServer::on_layer7Add_audio_valueChanged()
{
   if (ui.layer7Check_audio->isChecked()){
   int x = ui.layer7Add_audio->value();
   QString desc = tr("0017 %1;").arg(x);
   if (!sendPacket_audio(desc.toAscii().constData(),desc.size()))
           {
            errorsending_audio();
           }
   }
}

void libreMediaServer::on_layer8Check_audio_stateChanged (int state)
{
    if ((state == 0))
    {
        QString desc("0018 0000;");
        if (!sendPacket_audio(desc.toAscii().constData(),desc.size()))
                {
                 errorsending_audio();
                }
        return;
    }
    if ((state == 2))
    {
        on_layer8Add_audio_valueChanged();
    }
}

void libreMediaServer::on_layer8Add_audio_valueChanged()
{
   if (ui.layer8Check_audio->isChecked()){
   int x = ui.layer8Add_audio->value();
   QString desc = tr("0018 %1;").arg(x);
   if (!sendPacket_audio(desc.toAscii().constData(),desc.size()))
           {
            errorsending_audio();
           }
  }
}

// Open the connection with OLA and start reading DMX

void libreMediaServer::on_readDMX_audio_stateChanged(int state)
{
    if ((state == 0)) {
        QString desc("0020 0000;");
        if (!sendPacket_audio(desc.toAscii().constData(),desc.size()))
                {
                 errorsending_audio();
                }
        }
    if ((state == 2))
    {
        int x = ui.universe_audio->value();
        QString desc = tr("0021 %1;").arg(x);
        if (!sendPacket_audio(desc.toAscii().constData(),desc.size()))
                {
                 errorsending_audio();
                }
        desc = tr("0020 0001;");
        if (!sendPacket_audio(desc.toAscii().constData(),desc.size()))
                {
                 errorsending_audio();
                }
        }
 }

// Open the audio process

void libreMediaServer::on_audio_stateChanged(int state)
{
    if ((state == 0))
         {
        disconnect(m_pd_audio, SIGNAL(readyReadStandardError()), this, SLOT(stdout_audio()));
        disconnect(m_pd_audio, SIGNAL(finished(int)), this, SLOT(pdrestart_audio()));
        m_pd_audio->terminate();
        m_pd_audio = NULL;
        if (m_pd_write_audio != NULL)
        {
            disconnect(m_pd_write_audio, SIGNAL(connected()),this, SLOT(newconexion_audio()));
            m_pd_write_audio->close();
            delete m_pd_write_audio;
            m_pd_write_audio = NULL;
        }
        if (m_pd_read_audio != NULL)
        {
            disconnect(m_pd_read_audio, SIGNAL(newConnection()),this, SLOT(newPeer_audio()));
            m_pd_read_audio->close();
            delete m_pd_read_audio;
            m_pd_read_audio = NULL;
        }
    }
    if ((state == 2))
    {
   // Iniciamos Pure Data
   m_pd_read_audio = NULL;
   m_pd_write_audio = NULL;
   m_pd_audio = new QProcess(this);
   pdstart_audio();
   }
}

///////////////////////////////////////////////////////////////////
// Pure Data Audio
///////////////////////////////////////////////////////////////////

// Start the PD Process, open the ports and connects stdout de Pure Data.
void libreMediaServer::pdstart_audio()
{
    if (m_pd_audio->state() != 0)
    {
        return;
    }
    // Creamos los sockets para la conexión a Pure Data
    m_pd_write_audio = new QTcpSocket(this);
    Q_CHECK_PTR(m_pd_write_audio);
    connect(m_pd_write_audio, SIGNAL(connected()),this, SLOT(newconexion_audio()));
    m_pd_read_audio = new QTcpServer(this);
    Q_CHECK_PTR(m_pd_read_audio);
    connect(m_pd_read_audio, SIGNAL(newConnection()),this, SLOT(newPeer_audio()));
    if (!m_pd_read_audio)
     {
         qDebug()<<("error TCP Server no creado");
     }
    if (!m_pd_read_audio->listen(QHostAddress::LocalHost, PDPORTR_AUDIO))
    {
    qDebug()<<"error listening tcpServer";
    }
    // Arrancamos el proceso Pure Data
    QString arguments;
    arguments.append("./puredata/pd -alsa -channels 2 -audiodev 1 -stderr -nostdpath -path ./puredata/externals/ -open ./puredata/lms-audio.pd ");
    if (!m_gui)
        arguments.append("-nogui");
    m_pd_audio->start(arguments);
    if (m_pd_audio->waitForStarted(3000)){
        ui.textEdit->appendPlainText("PD Audio started.");
    }
    else
    {
        ui.textEdit->appendPlainText("PD Audio not started!");
        qErrnoWarning("Can not init PD Audio: ");
        return;
    }
    connect(m_pd_audio, SIGNAL(readyReadStandardError()), this, SLOT(stdout_audio()));
}

// Restart the Pure Data process if crash. Connected wit signal finished of QProcess
void libreMediaServer::pdrestart_audio()
{
    save_finish();
    qDebug()<<"Starting PD Audio:" << ++m_startaudio;
    ui.textEdit->appendPlainText("PD audio Restarting...");
    if (m_pd_audio->state())
    {
        return;
    }
    if (m_pd_write_audio != NULL)
    {
        m_pd_write_audio->close();
        disconnect(m_pd_write_audio, SIGNAL(connected()),this, SLOT(newconexion_audio()));
        delete m_pd_write_audio;
    }
    if (m_pd_read_audio != NULL)
    {
        disconnect(m_pd_read_audio, SIGNAL(newConnection()),this, SLOT(newPeer_audio()));
        m_pd_read_audio->close();
        delete m_pd_read_audio;
    }
    disconnect(m_pd_audio, SIGNAL(finished(int)), this, SLOT(pdrestart_audio()));
    m_pd_write_video->close();
    pdstart_audio();
}

// New conexion on TCP Server
void libreMediaServer::newPeer_audio()
{
   m_tcpsocket_audio = m_pd_read_audio->nextPendingConnection();
   connect(m_tcpsocket_audio, SIGNAL(readyRead()),
                this, SLOT(newmessage_audio()));
}

// New message in a TCP socket stablished connection
void libreMediaServer::newmessage_audio()
{
    if (m_tcpsocket_audio == NULL)
    {
        qDebug()<<("tcpsocket audio not created");
        newPeer_audio();
        return;
    }
    QByteArray byteArray = m_tcpsocket_audio->readAll();
    QString string(byteArray);
    if (byteArray.at(0) == 0)
    {
        return;
    }
    QChar layer = string.at(0);
    int i = 9 + m_pathmedia.size();
    string.remove(0,i);
    string.chop(2);
    int val = layer.digitValue();
    switch (val) {
    case 0:
        ui.textEdit->appendPlainText("Loadbang from PD Audio received...");
        // Conectamos a Pure Data para escribir
        m_pd_write_audio->connectToHost(QHostAddress::LocalHost, PDPORTW_AUDIO);
        // Conectamos para reiniciar si PD crash
        connect(m_pd_audio, SIGNAL(finished(int)), this, SLOT(pdrestart_audio()));
        // Mandamos Configuración
        m_pd_write_audio->waitForConnected(30000);
        newconexion_audio();
    case 1:
       ui.layer1_audio->setText(string);
       break;
    case 2:
        ui.layer2_audio->setText(string);
        break;
    case 3:
        ui.layer3_audio->setText(string);
        break;
    case 4:
        ui.layer4_audio->setText(string);
        break;
    case 5:
        ui.layer5_audio->setText(string);
        break;
    case 6:
        ui.layer6_audio->setText(string);
        break;
    case 7:
        ui.layer7_audio->setText(string);
        break;
    case 8:
        ui.layer8_audio->setText(string);
        break;
    }
}

// Send the configuration to PD
void libreMediaServer::newconexion_audio()
{
    if (!(m_pd_write_audio->isOpen())){
        errorsending_audio();
        return;
     }
    qDebug() << "Sending conf to PD Audio";
    QString desc = tr("0000 0000 %1;").arg(m_pathmedia);
    if (!sendPacket_audio(desc.toAscii().constData(),desc.size()))
    {
      errorsending_audio();
      return;
    }
    on_layer1Check_audio_stateChanged (ui.layer1Check_audio->checkState());
    on_layer2Check_audio_stateChanged (ui.layer2Check_audio->checkState());
    on_layer3Check_audio_stateChanged (ui.layer3Check_audio->checkState());
    on_layer4Check_audio_stateChanged (ui.layer4Check_audio->checkState());
    on_layer5Check_audio_stateChanged (ui.layer5Check_audio->checkState());
    on_layer6Check_audio_stateChanged (ui.layer6Check_audio->checkState());
    on_layer7Check_audio_stateChanged (ui.layer7Check_audio->checkState());
    on_layer8Check_audio_stateChanged (ui.layer8Check_audio->checkState());
    on_readDMX_audio_stateChanged(ui.readDMX_audio->checkState());

}

// Sends packets to Pure Data audio
bool libreMediaServer::sendPacket_audio(const char *buffer, int bufferLen)
{
 if (m_pd_write_audio == NULL) {
    return false;
 }
 if (QAbstractSocket::ConnectedState != m_pd_write_audio->state())
 {
    return false;
 }
 if (bufferLen != m_pd_write_audio->write((const char*)buffer, bufferLen))
 {
    return false;
 }
 return true;
}

// Function error sending packets to PD audio
void libreMediaServer::errorsending_audio() {
    if (ui.audio->checkState())
    {
    ui.textEdit->appendPlainText("Can not send packets to PD Audio");
    }
}

///////////////////////////////////////////////////////////////////
// Previews
///////////////////////////////////////////////////////////////////

// GUI
void libreMediaServer::previewMaster()
{
    QPixmap preview = QPixmap::grabWindow(QApplication::desktop()->winId(), ui.winpositionx->value() , ui.winpositiony->value(),ui.winsizex->value(),ui.winsizey->value());
    ui.masterPreview->setPixmap(preview);
}

// CITP/MSEx 1.0
void libreMediaServer::sendFrame()
{
    m_msex->n_timer->stop();
    QPixmap frame = QPixmap::grabWindow(QApplication::desktop()->winId(), ui.winpositionx->value() , ui.winpositiony->value(),ui.winsizex->value(),ui.winsizey->value());
    if (!frame) {
        qDebug()<<"sendFrame: Can not take frame";
        return;
    }
    QImage image = QImage(frame.toImage());
    if (!image.byteCount()) {
        qDebug()<<"sendFrame: Can not convert screen capture to image";
        return;
    }
    image = image.scaledToWidth(88);
    image = image.convertToFormat(QImage::Format_RGB888);
    int bufferLen = image.byteCount();
    int bufferLenTot = sizeof(struct CITP_MSEX_10_StFr ) + bufferLen;
    uchar * buffer = new uchar[bufferLenTot];
    memset(buffer, 0, bufferLenTot);
    CITP_MSEX_10_StFr *packet = (CITP_MSEX_10_StFr *)buffer;
    // CITP header
    packet->CITPMSEXHeader.CITPHeader.Cookie = COOKIE_CITP;
    packet->CITPMSEXHeader.CITPHeader.VersionMajor = 0x01;
    packet->CITPMSEXHeader.CITPHeader.VersionMinor = 0x00;
    packet->CITPMSEXHeader.CITPHeader.Reserved[0] = 0x00;
    packet->CITPMSEXHeader.CITPHeader.Reserved[1] = 0x00;
    packet->CITPMSEXHeader.CITPHeader.MessageSize = bufferLenTot;
    packet->CITPMSEXHeader.CITPHeader.MessagePartCount = 0x01;
    packet->CITPMSEXHeader.CITPHeader.MessagePart = 0x00; // XXX - doc says 0-based?
    packet->CITPMSEXHeader.CITPHeader.ContentType = COOKIE_MSEX;
    // MSEX header
    packet->CITPMSEXHeader.ContentType = COOKIE_MSEX_STFR;
    packet->CITPMSEXHeader.VersionMajor = 0x01;
    packet->CITPMSEXHeader.VersionMinor = 0x00;
    //STFR Content
    packet->FrameBufferSize = bufferLen;
    packet->FrameFormat = 943867730;
    packet->FrameHeight = 64;
    packet->FrameWidth = 88;
    packet->SourceIdentifier = 0x0001;
    // Copiamos los datos del thumbnail
    int offset = sizeof(struct CITP_MSEX_10_StFr);
    memcpy((buffer+offset), image.bits(), bufferLen);
    if (!buffer)
    {
      qDebug() << "sendFrame:create Frame failed";
      return;
    }
    // Mandamos el paquete
    if (!m_msex->sendPacket(buffer, bufferLenTot))
        {
        qDebug() << "sendFrame: transmitFrame failed";
        return;
        }
    m_msex->n_timer->start();
}

// Enable/Disable the GUI Master preview
void libreMediaServer::on_previewMaster_stateChanged (int state)
{
    if ((state == 0)) {
        m_preview->stop();
    }
    if ((state == 2))
    {
        m_preview->start();
    }
}

// Enable/Disable the GUI Layers preview
void libreMediaServer::on_previewLayer_stateChanged (int state)
{
    if ((state == 0)) {
        QString desc = tr("0022 0;");
        if (!sendPacket(desc.toAscii().constData(),desc.size()))
        {
            errorsending();
        }
       }
    if ((state == 2))
    {
        QString desc = tr("0022 1;");
        if (!sendPacket(desc.toAscii().constData(),desc.size()))
        {
            errorsending();
        }
    }
}

///////////////////////////////////////////////////////////////////
// Terminal and Log
////////////////////////////////////////////////////////////////////

// Sacamos la salida de Pure Data Audio en la terminal
void libreMediaServer::stdout_audio() {
    QString out = m_pd_audio->readAllStandardError();
    out.chop(1);
    if (!out.isEmpty())
    {
        qDebug() << "PD Audio: " << out;
    }
}

// Sacamos la salida de Pure Data Video en la terminal. Filtra mensajes para el GUI.
void libreMediaServer::stdout() {
    QByteArray out = m_pd_video->readAllStandardError();
    if (out.size() < 7) {return;}
    out.chop(1);
    if (out.indexOf("ola2pd: Can not read DMX!",0) != -1)
        {
            ui.textEdit->appendPlainText("Can not read DMX data.");
        }
/*    if (out.indexOf("watchdog",0) != -1)
        {
            ui.textEdit->appendPlainText("PD video watchdog detected.");
        }*/
    int j = out.indexOf("togui: ",0);
    if ((j >= 0) && (out.size() > (j+7)))
         {
         int i = m_pathmedia.size() + 16;
         out.remove(0,j);
         switch (out.at(7)) {
             case '0':
                qDebug()<<"Loadbang Video";
                ui.textEdit->appendPlainText("LoadBang Video received.");
                m_pd_write_video->connectToHost(QHostAddress::LocalHost, PDPORTW);
                if (!(m_pd_write_video->waitForConnected(3000))){
                        qDebug()<<"Newconexion failed connect to Host "<< m_pd_write_video->error();
                } else {
                    newconexion();
                }
                break;
             case '1':
                out.remove(0, i);
                out.prepend("Layer 1 playing:");
                ui.textEdit->appendPlainText(out);
                break;
             case '2':
                out.remove(0, i);
                out.prepend("Layer 2 playing:");
                ui.textEdit->appendPlainText(out);
                break;
             case '3':
                out.remove(0,i);
                out.prepend("Layer 3 playing:");
                ui.textEdit->appendPlainText(out);
                break;
             case '4':
                out.remove(0,i);
                out.prepend("Layer 4 playing:");
                ui.textEdit->appendPlainText(out);
                break;
             case '5':
                out.remove(0,i);
                out.prepend("Layer 5 playing:");
                ui.textEdit->appendPlainText(out);
                break;
             case '6':
                out.remove(0,i);
                out.prepend("Layer 6 playing:");
                ui.textEdit->appendPlainText(out);
                break;
             case '7':
                out.remove(0,i);
                out.prepend("Layer 7 playing:");
                ui.textEdit->appendPlainText(out);
                break;
             case '8':
                out.remove(0,i);
                out.prepend("Layer 8 playing:");
                ui.textEdit->appendPlainText(out);
                break;
            case '9':
                out.remove(0,9);
                ui.fpsCounter->display(out.toInt());
                break;
            default:
                qDebug()<<"stdout:Invalid cookie received"<<out;
                break;
             }
        return;
        }
 qDebug() << "PD Video: " << out;
}
