Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream>
- #include <cstdlib>
- #include <q3network.h>
- #include <qdatetime.h>
- #include <qpainter.h>
- #include <qdir.h>
- #include <qtimer.h>
- #include <q3process.h>
- #include <qstringlist.h>
- #include <q3dict.h>
- #include <q3vbox.h>
- #include <qlayout.h>
- #include <qregexp.h>
- #include <q3url.h>
- #include "recorder.h"
- using namespace std;
- RecorderManager::RecorderManager(QObject */*parent*/, StreamStorage *storage)
- {
- streamStorage = storage;
- recList.setAutoDelete(false);
- kill = false;
- connect ( streamStorage, SIGNAL(storageEvent(int, int, bool)), this, SLOT(slotStorageEvent(int, int, bool)) );
- connect( streamStorage, SIGNAL(recordInserted(ChangedRecord*)), this, SLOT(slotRecordInserted(ChangedRecord*)) );
- connect( streamStorage, SIGNAL(recordUpdated(ChangedRecord*)), this, SLOT(slotRecordUpdated(ChangedRecord*)) );
- connect( streamStorage, SIGNAL(recordRemoved(ChangedRecord*)), this, SLOT(slotRecordRemoved(ChangedRecord*)) );
- QTimer *timer = new QTimer( this );
- connect( timer, SIGNAL(timeout()), this, SLOT(timerEvent()) );
- timer->start(10000, false);
- }
- RecorderManager::~RecorderManager()
- {
- kill = true;
- recList.setAutoDelete(true);
- recList.clear();
- }
- void RecorderManager::timerEvent()
- {
- Recorder *recorder;
- QString errorMessage;
- Q3DictIterator<Recorder> i(recList);
- for(; i.current(); ++i)
- {
- recorder = i.current();
- if (recorder)
- {
- if ( !recorder->checkSchedule(errorMessage) )
- emit scheduleEvent(recorder->recName, errorMessage, false);
- }
- }
- }
- void RecorderManager::slotStorageEvent(int ident, int eventType, bool error)
- {
- if (ident == 105 || error) return;
- if (recList.count() != 0) // no storage event should occur during recording
- cerr << "TARGET warning: storage manipulation during recording" << endl;
- if (eventType == MStorage::loaded)
- {
- if (recList.count() != 0) // no storage event should occur during recording
- stopAllRecordings();
- streamStorage->resetRecordList();
- ValueList values(5);
- while ( streamStorage->getNextRecord(values) )
- {
- if ( values.count() == 5 && values[0] == "recordings" )
- handleNewRecord(values, false); // do not allow overwrite
- }
- }
- }
- void RecorderManager::handleNewRecord(ValueList &values, bool allowOverwrite)
- {
- QString errorMsg;
- bool result = scheduleRecording( values[1], values[2], values[3], values[4], errorMsg, allowOverwrite );
- emit scheduleEvent(values[1], errorMsg, result);
- }
- bool RecorderManager::scheduleRecording(QString name, QString url, QString descr, QString /*handler*/, QString& errorMessage, bool allowOverwrite)
- {
- QDateTime startDt, stopDt;
- bool overwriting = false;
- // swap naming
- QString fileName = url;
- QString recName = name;
- url = descr;
- errorMessage = "";
- // get scheduling info
- if ( !getUTime(recName, startDt, stopDt) )
- {
- errorMessage = "no schedule info";
- return false;
- }
- // ignore old recordings (empty message)
- if (QDateTime::currentDateTime() > stopDt) return false;
- // abort if record file exists and contains data
- QFile file(fileName);
- if (file.exists() && file.size() > 0) // existing recording
- {
- if (!allowOverwrite) // do not overwrite
- {
- errorMessage = "record file exists";
- return false;
- }
- else overwriting = true;
- }
- // claim file, abort on fail
- if ( !file.exists() )
- {
- bool isOpen = file.open(QIODevice::WriteOnly);
- if (isOpen)
- file.close();
- else
- {
- errorMessage = "file access problem";
- return false;
- }
- }
- assignRecorder(recName, url, fileName, startDt, stopDt);
- errorMessage = "scheduled";
- if (overwriting)
- errorMessage += " (to overwrite!)";
- return true;
- }
- void RecorderManager::slotRecordInserted(ChangedRecord* rec)
- {
- if (rec->ident == 105 || rec->error) return;
- if (rec->values[0] == "recordings")
- handleNewRecord(rec->values, false); // do not allow overwrite
- }
- void RecorderManager::slotRecordUpdated(ChangedRecord* rec)
- {
- QDateTime startDt, stopDt;
- QString errorMsg, recName;
- if (rec->ident == 105 || rec->error) return;
- if ( rec->values[0] == "recordings" &&
- !getUTime(rec->values[1], startDt, stopDt) )
- {
- emit scheduleEvent(rec->values[1], "no schedule info", false);
- return;
- }
- // no recording OR recording with parsed startDt, stopDt from here
- Recorder *recorder = recList.find(rec->oldValues[1]);
- if (recorder) // update values
- {
- recList.remove(recorder->recName);
- recorder->startDt = startDt;
- recorder->stopDt = stopDt;
- recorder->recName = rec->values[1];
- recorder->fileName = rec->values[2];
- recorder->url = rec->values[3];
- recorder->handler = rec->values[4];
- recList.insert(recorder->recName, recorder);
- emit scheduleEvent(rec->values[1], "rescheduled", true);
- }
- else
- if (rec->values[0] == "recordings" &&
- QDateTime::currentDateTime() < stopDt ) // try schedule if pending recording
- handleNewRecord(rec->values, true); // allow overwrite
- }
- void RecorderManager::slotRecordRemoved(ChangedRecord* rec)
- {
- if (rec->ident == 105 || rec->error) return;
- // delete file if: folder=recording
- if ( rec->oldValues[0] == "recordings" )
- {
- stopRecording(rec->values[1]);
- QFile(rec->oldValues[2]).remove();
- }
- }
- // returns empty string on fail
- bool createRecordFile(QString& fileName, QString prefix, uint &index)
- {
- fileName = prefix + "_" + QString::number(index);
- QFile file(fileName);
- while ( file.exists() )
- {
- index++;
- fileName = prefix + "_" + QString::number(index);
- file.setName(fileName);
- }
- bool isOpen = file.open(QIODevice::WriteOnly);
- if (isOpen)
- {
- file.close();
- return true;
- }
- return false;
- }
- bool deleteRecordFile(QString fileName)
- {
- return QFile(fileName).remove();
- }
- bool RecorderManager::createStreamItem(QString name, QString url, QString descr, QString handler)
- {
- QString errorMsg;
- ValueList values(5);
- values[s_folder] = "recordings";
- values[s_name] = name;
- values[s_url] = url;
- values[s_descr] = descr;
- values[s_handler] = handler;
- return streamStorage->insertRecord(105, values, errorMsg);
- }
- bool RecorderManager::deleteStreamItem(QString name, QString url, QString descr, QString handler)
- {
- QString errorMsg;
- ValueList values(5);
- values[s_folder] = "recordings";
- values[s_name] = name;
- values[s_url] = url;
- values[s_descr] = descr;
- values[s_handler] = handler;
- return streamStorage->removeRecord(105, values, errorMsg);
- }
- bool RecorderManager::getUTime(QString name, QDateTime& start, QDateTime& stop)
- {
- QRegExp expr;
- int i;
- bool test;
- int year, month, day, sHour, sMin, eHour, eMin;
- expr.setPattern("^REC.*(\\d{4})[/-]?(\\d{2})[/-]?(\\d{2}).*(\\d{2}):?(\\d{2}).*(\\d{2}):?(\\d{2})");
- i = expr.search( name, 0 );
- if ( i > -1 )
- {
- year = expr.cap(1).toInt(&test);
- month = expr.cap(2).toInt(&test);
- day = expr.cap(3).toInt(&test);
- sHour = expr.cap(4).toInt(&test);
- sMin = expr.cap(5).toInt(&test);
- eHour = expr.cap(6).toInt(&test);
- eMin = expr.cap(7).toInt(&test);
- //cout << name << endl;
- //cout << " " << year << month << day << " " << sHour << sMin << " " << eHour << eMin << endl;
- start = QDateTime( QDate(year, month, day), QTime(sHour, sMin) );
- stop = QDateTime( QDate(year, month, day), QTime(eHour, eMin) );
- if ( stop < start ) stop = stop.addDays(1);
- return true;
- }
- else
- return false;
- }
- Recorder* RecorderManager::assignRecorder(QString recName, QString url, QString fileName, QDateTime startDt, QDateTime stopDt)
- {
- Recorder *recorder = new Recorder(this, recName, url, fileName, startDt, stopDt);
- connect ( recorder, SIGNAL( recordingStopped(Recorder*) ), this, SLOT( slotRecorderStopped(Recorder*) ) );
- connect ( recorder, SIGNAL( recordingStarted(Recorder*) ), this, SLOT( slotRecorderStarted(Recorder*) ) );
- recList.insert( recName, recorder );
- return recorder;
- }
- // returns recordName (name of stream item entry in storage)
- // returns empty string on error
- QString RecorderManager::recordNow(QString url, QString name, uint seconds, QString& errorMessage)
- {
- errorMessage = "";
- QDateTime startDt = QDateTime::currentDateTime();
- QDateTime stopDt = startDt.addSecs(seconds);
- QString date = startDt.toString("yyyyMMdd");
- QString sTime = startDt.toString("hhmm");
- QString eTime = stopDt.toString("hhmm");
- QString path = QString(getenv("HOME")) + "/."SUBPATH"/recordings/";
- QString prefix = path + "REC_" + date + "_" + sTime + "_" + eTime;
- QString fileName = "";
- QString recName = "";
- QString handler = "";
- uint index = 0;
- QDir dir(path);
- if (!dir.exists()) dir.mkdir(path);
- bool ready = false;
- while (!ready)
- {
- if ( createRecordFile(fileName, prefix, index) )
- {
- recName = "REC" + QString::number(index) + " " + date + " " + sTime + " " + eTime + " " + name;
- ready = createStreamItem(recName, fileName, url, handler);
- if (!ready) QFile(fileName).remove();
- if (index > 20)
- {
- errorMessage = "more than 20 REC files with prefix " + prefix +
- " OR stream repository problem";
- fileName = "";
- ready = true;
- }
- }
- else
- {
- errorMessage = "cannot create file " + fileName;
- fileName = "";
- ready = true;
- }
- }
- if (fileName != "")
- {
- Recorder *recorder = assignRecorder(recName, url, fileName, startDt, stopDt);
- if ( !recorder->startRecording(errorMessage) )
- {
- recList.remove(recName);
- QFile(fileName).remove();
- deleteStreamItem(recName, url, "", "");
- delete recorder;
- recName = "";
- }
- }
- else recName = "";
- return recName;
- }
- ItemStatus RecorderManager::getItemStatus(QString recName)
- {
- Recorder *recorder = recList.find(recName);
- if (recorder)
- if (recorder->isRecording)
- return recording;
- else
- return scheduled;
- else
- return recorded;
- }
- void RecorderManager::stopRecording(QString recName)
- {
- Recorder *recorder = recList.find(recName);
- if (recorder)
- {
- if ( !recList.remove(recName) )
- cerr << TARGET": recorder instance not found in list";
- recorder->stopRecording();
- }
- }
- void RecorderManager::stopAllRecordings()
- {
- Recorder *recorder;
- Q3DictIterator<Recorder> i(recList);
- for(; i.current(); ++i)
- {
- recorder = i.current();
- if (recorder)
- {
- recorder->stopRecording();
- }
- }
- recList.clear();
- }
- void RecorderManager::slotRecorderStarted(Recorder* recorder)
- {
- emit recordingStarted(recorder->recName);
- emit recorderActive(true);
- }
- void RecorderManager::slotRecorderStopped(Recorder* recorder)
- {
- // delete empty file on fail
- QString fileName = recorder->fileName;
- QFile file(fileName);
- if ( file.size() == 0 && file.remove() )
- {
- deleteStreamItem( recorder->recName, fileName, "", "" );
- emit scheduleEvent(recorder->recName, "Recording removed because it was empty", false);
- }
- recList.remove( recorder->recName ); // if not stopped by stopRecording call
- emit recordingStopped( recorder->recName, recorder->getStopReason() );
- if (!kill) recorder->deleteLater();
- // check recordings and report state
- Recorder *p_rec;
- bool oneActive = false;
- Q3DictIterator<Recorder> i(recList);
- for(; i.current(); ++i)
- {
- p_rec = i.current();
- if (p_rec && p_rec->isRecording)
- oneActive = true;
- }
- if (!oneActive) emit recorderActive(false);
- }
- //-----------------------------------------------------------------
- Recorder::Recorder(QObject *parent, QString recName, QString url, QString fileName,
- QDateTime startDt, QDateTime stopDt)
- {
- myParent = parent;
- this->recName = recName;
- this->url = url;
- this->fileName = fileName;
- this->startDt = startDt;
- this->stopDt = stopDt;
- isRecording = false;
- reason = process;
- sawPlayerOutput = false;
- proc = NULL;
- }
- Recorder::~Recorder()
- {
- if (proc)
- {
- if ( proc->isRunning() ) proc->tryTerminate();
- //QTimer::singleShot( 1000, proc, SLOT( kill() ) );
- }
- }
- bool Recorder::checkSchedule(QString& errorMsg)
- {
- QDateTime now = QDateTime::currentDateTime();
- if ( now >= startDt && now < stopDt && !isRecording )
- return startRecording(errorMsg);
- if ( isRecording && now >= stopDt )
- stopRecording();
- return true;
- }
- bool Recorder::startRecording(QString& errorMsg)
- {
- if (proc != NULL)
- {
- errorMsg = "Already recording. Should not happen (bug).";
- return false;
- }
- this->url = url;
- Q3Url qurl = Q3Url(url);
- if ( !qurl.isValid() || qurl.protocol() == "file" || qurl.isLocalFile() )
- {
- errorMsg = "invalid URL: " + url;
- return false;
- }
- startStream();
- return true;
- }
- void Recorder::stopRecording()
- {
- stopStream();
- }
- void Recorder::parsePlayerOutput(const QString /*msg*/)
- {
- sawPlayerOutput = true;
- // assume player is responsible for unwanted abort
- }
- void Recorder::startStream()
- {
- if ( proc ) return;
- proc = new Q3Process( this );
- proc->setCommunication( Q3Process::Stdin | Q3Process::Stdout| Q3Process::Stderr| Q3Process::DupStderr );
- // proc->addArgument( "sh" );
- // proc->addArgument( "-c" );
- // proc->addArgument( "tail -c 100000000000000 -f /data/linuxhome/files/lessig | mplayer -" );
- proc->addArgument( "mplayer");
- QString file = Q3Url(url).fileName();
- // file == "" matches find below
- if ( file != "" && QString("PLAYLIST").find(Q3Url(url).fileName().right(4), 0, false) != -1 )
- {
- proc->addArgument( "-playlist" );
- }
- proc->addArgument( url );
- proc->addArgument( "-dumpstream");
- proc->addArgument( "-dumpfile");
- proc->addArgument( fileName);
- connect( proc, SIGNAL(readyReadStdout()), this, SLOT(readFromStdout()) );
- connect( proc, SIGNAL(readyReadStderr()), this, SLOT(readFromStderr()) );
- connect( proc, SIGNAL(processExited()), this, SLOT(streamExited()) );
- if ( !proc->start() )
- {
- fprintf( stderr, "error starting player\n" );
- reason = process;
- streamExited();
- }
- else
- {
- isRecording = true;
- recordingStarted(this);
- }
- }
- void Recorder::stopStream()
- {
- if ( proc && proc->isRunning() )
- {
- reason = command;
- proc->tryTerminate();
- }
- }
- void Recorder::readFromStdout()
- {
- QString val = "";
- QString temp = " ";
- while ( temp != "" )
- {
- temp = QString(proc->readStdout());
- val += temp;
- }
- QStringList lines = QStringList::split( QRegExp("[\r\n|\r]"), val );
- for ( QStringList::iterator line = lines.begin();
- line != lines.end(); ++line )
- parsePlayerOutput(*line);
- }
- void Recorder::readFromStderr()
- {
- // is rerouted to stdout
- }
- void Recorder::streamExited()
- {
- delete proc;
- proc = NULL;
- //cout << "recorder exited" << endl;
- // if the player failed blame it on the recorder
- if (sawPlayerOutput && reason == process)
- reason = recorder;
- isRecording = false;
- emit recordingStopped(this);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement