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"))
303 else if (cmd.startsWith(
"StartStreaming"))
307 else if (cmd.startsWith(
"StopStreaming"))
316 send_status(QString(
"ERR:Unknown command '%1'").arg(cmd));
317 LOG(VB_RECORD, LOG_ERR,
LOC + QString(
"Unknown command '%1'")
329 std::array<struct pollfd,2> polls {};
332 polls[0].events = POLLIN | POLLPRI;
333 polls[0].revents = 0;
338 auto *streamThread =
new QThread(
this);
341 connect(streamThread, &QThread::finished,
347 streamThread->start();
350 if (!input.open(stdin, QIODevice::ReadOnly))
352 LOG(VB_RECORD, LOG_ERR,
LOC +
"Opening of stdin failed");
356 QTextStream qtin(&input);
358 LOG(VB_RECORD, LOG_INFO,
LOC +
"Listening for commands");
362 int ret = poll(polls.data(), poll_cnt,
m_timeout);
364 if (polls[0].revents & POLLHUP)
366 LOG(VB_RECORD, LOG_ERR,
LOC +
"poll eof (POLLHUP)");
369 if (polls[0].revents & POLLNVAL)
371 LOG(VB_RECORD, LOG_ERR,
LOC +
"poll error");
375 if (polls[0].revents & POLLIN)
379 cmd = qtin.readLine();
382 streamThread->quit();
383 streamThread->wait();
385 streamThread =
nullptr;
392 if ((EOVERFLOW == errno))
394 LOG(VB_RECORD, LOG_ERR,
LOC +
"command overflow.");
398 if ((EAGAIN == errno) || (EINTR == errno))
400 LOG(VB_RECORD, LOG_ERR,
LOC +
"retry command read.");
404 LOG(VB_RECORD, LOG_ERR,
LOC +
"unknown error reading command.");
413int main(
int argc,
char *argv[])
438 QCoreApplication a(argc, argv);
439 QCoreApplication::setApplicationName(
"mythfilerecorder");
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)