12#include <QCoreApplication>
24#include "libmythbase/mythversion.h"
31static constexpr const char*
VERSION {
"1.0.0" };
32#define LOC QString("File(%1): ").arg(m_fileName)
35 int data_rate,
bool loopinput) :
36 m_parent(parent), m_fileName(std::move(fname)),
37 m_loop(loopinput), m_dataRate(data_rate)
39 setObjectName(
"Streamer");
46 LOG(VB_RECORD, LOG_INFO,
LOC +
"Streamer::dtor -- begin");
48 LOG(VB_RECORD, LOG_INFO,
LOC +
"Streamer::dtor -- end");
56 LOG(VB_RECORD, LOG_ERR,
LOC + QString(
"Failed to open '%1' - ")
63 LOG(VB_RECORD, LOG_INFO,
LOC +
"Streamer::Close -- begin");
71 LOG(VB_RECORD, LOG_INFO,
LOC +
"Streamer::Close -- end");
79 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"SendBytes -- start");
83 LOG(VB_GENERAL, LOG_ERR,
LOC +
"SendBytes -- file not open");
103 read_sz = std::min(rate, read_sz);
104#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
112 QByteArray buffer =
m_file->read(read_sz);
114 pkt_size = buffer.size();
121 LOG(VB_RECORD, LOG_WARNING,
LOC +
122 QString(
"SendBytes -- Overflow: %1 > %2, "
123 "dropping first %3 bytes.")
134 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"SendBytes -- Buffer is empty.");
139 LOG(VB_RECORD, LOG_DEBUG,
LOC +
140 QString(
"SendBytes -- Read %1 from file. %2 bytes buffered")
141 .arg(pkt_size).arg(buf_size));
144 write_len = std::min(write_len, buf_size);
145 LOG(VB_RECORD, LOG_DEBUG,
LOC +
146 QString(
"SendBytes -- writing %1 bytes").arg(write_len));
150 LOG(VB_RECORD, LOG_DEBUG,
LOC +
151 QString(
"SendBytes -- wrote %1 bytes").arg(wrote));
153 if (wrote < buf_size)
156 LOG(VB_RECORD, LOG_WARNING,
LOC +
157 QString(
"%1 bytes unwritten").arg(
m_buffer.size()));
164 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"SendBytes -- end");
170 setObjectName(
"Command");
175 QByteArray buf = status.toLatin1() +
'\n';
176 int len =
write(2, buf.constData(), buf.size());
177 if (len != buf.size())
179 LOG(VB_RECORD, LOG_ERR,
LOC +
180 QString(
"Status -- Wrote %1 of %2 bytes of status '%3'")
181 .arg(len).arg(status.size()).arg(status));
184 LOG(VB_RECORD, LOG_DEBUG,
"Status: " + status);
190 LOG(VB_RECORD, LOG_DEBUG,
LOC + cmd);
192 if (cmd.startsWith(
"Version?"))
197 if (cmd.startsWith(
"APIVersion?"))
202 if (cmd.startsWith(
"APIVersion:1"))
204 QString reply = (
API_VERSION == 1) ?
"OK:Yes":
"OK:No";
208 if (cmd.startsWith(
"HasLock?"))
213 if (cmd.startsWith(
"SignalStrengthPercent"))
218 if (cmd.startsWith(
"LockTimeout"))
223 if (cmd.startsWith(
"HasTuner?"))
228 if (cmd.startsWith(
"HasPictureAttributes?"))
237 LOG(VB_RECORD, LOG_ERR,
LOC + QString(
"%1 failed - not initialized!")
242 if (cmd.startsWith(
"SendBytes"))
247 LOG(VB_RECORD, LOG_ERR,
LOC +
"SendBytes - file not open.");
251 if (
m_eof.loadAcquire() != 0)
263 else if (cmd.startsWith(
"XON"))
267 else if (cmd.startsWith(
"XOFF"))
271 else if (cmd.startsWith(
"TuneChannel"))
280 else if (cmd.startsWith(
"IsOpen?"))
288 else if (cmd.startsWith(
"CloseRecorder"))
294 else if (cmd.startsWith(
"FlowControl?"))
298 else if (cmd.startsWith(
"BlockSize"))
300#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
307 else if (cmd.startsWith(
"StartStreaming"))
311 else if (cmd.startsWith(
"StopStreaming"))
320 send_status(QString(
"ERR:Unknown command '%1'").arg(cmd));
321 LOG(VB_RECORD, LOG_ERR,
LOC + QString(
"Unknown command '%1'")
333 std::array<struct pollfd,2> polls {};
336 polls[0].events = POLLIN | POLLPRI;
337 polls[0].revents = 0;
342 auto *streamThread =
new QThread(
this);
345 connect(streamThread, &QThread::finished,
351 streamThread->start();
354 if (!input.open(stdin, QIODevice::ReadOnly))
356 LOG(VB_RECORD, LOG_ERR,
LOC +
"Opening of stdin failed");
360 QTextStream qtin(&input);
362 LOG(VB_RECORD, LOG_INFO,
LOC +
"Listening for commands");
366 int ret = poll(polls.data(), poll_cnt,
m_timeout);
368 if (polls[0].revents & POLLHUP)
370 LOG(VB_RECORD, LOG_ERR,
LOC +
"poll eof (POLLHUP)");
373 if (polls[0].revents & POLLNVAL)
375 LOG(VB_RECORD, LOG_ERR,
LOC +
"poll error");
379 if (polls[0].revents & POLLIN)
383 cmd = qtin.readLine();
386 streamThread->quit();
387 streamThread->wait();
389 streamThread =
nullptr;
396 if ((EOVERFLOW == errno))
398 LOG(VB_RECORD, LOG_ERR,
LOC +
"command overflow.");
402 if ((EAGAIN == errno) || (EINTR == errno))
404 LOG(VB_RECORD, LOG_ERR,
LOC +
"retry command read.");
408 LOG(VB_RECORD, LOG_ERR,
LOC +
"unknown error reading command.");
417int main(
int argc,
char *argv[])
442 QCoreApplication a(argc, argv);
443 QCoreApplication::setApplicationName(
"mythfilerecorder");
461#include "moc_mythfilerecorder.cpp"
bool process_command(QString &cmd)
bool send_status(const QString &status) const
bool toBool(const QString &key) const
Returns stored QVariant as a boolean.
int toInt(const QString &key) const
Returns stored QVariant as an integer, falling to default if not provided.
virtual bool Parse(int argc, const char *const *argv)
Loop through argv and populate arguments with values.
int ConfigureLogging(const QString &mask="general", bool progress=false)
Read in logging options and initialize the logging interface.
QString toString(const QString &key) const
Returns stored QVariant as a QString, falling to default if not provided.
static void PrintVersion(void)
Print application version information.
QStringList GetArgs(void) const
Return list of additional values provided on the command line independent of any keyword.
void PrintHelp(void) const
Print command line option help.
QString ErrorString(void) const
Streamer(Commands *parent, QString fname, int data_rate, bool loopinput)
@ GENERIC_EXIT_OK
Exited with no error.
@ GENERIC_EXIT_INVALID_CMDLINE
Command line parse error.
int main(int argc, char *argv[])
static constexpr int API_VERSION
static constexpr const char * VERSION
#define ENO
This can be appended to the LOG args with "+".
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
MythCommFlagCommandLineParser cmdline
def write(text, progress=True)