7 #include <QRegularExpression>
26 #define LOC QString("SatIPRTSP[%1]: ").arg(m_inputId)
27 #define LOC2 QString("SatIPRTSP[%1](%2): ").arg(m_inputId).arg(m_requestUrl.toString())
49 QTcpSocket ctrl_socket;
52 bool ok = ctrl_socket.waitForConnected(10 * 1000);
55 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Could not connect to server %1:%2")
60 QStringList requestHeaders;
61 requestHeaders.append(QString(
"%1 %2 RTSP/1.0").arg(msg,
m_requestUrl.toString()));
62 requestHeaders.append(QString(
"User-Agent: MythTV Sat>IP client"));
63 requestHeaders.append(QString(
"CSeq: %1").arg(++
m_cseq));
67 requestHeaders.append(QString(
"Session: %1").arg(
m_sessionid));
70 if (additionalheaders !=
nullptr)
72 for (
auto& adhdr : *additionalheaders)
74 requestHeaders.append(adhdr);
78 requestHeaders.append(
"\r\n");
80 for (
const auto& requestLine : requestHeaders)
82 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"sendMessage " +
83 QString(
"write: %1").arg(requestLine.simplified()));
86 QString request = requestHeaders.join(
"\r\n");
87 ctrl_socket.write(request.toLatin1());
91 static const QRegularExpression kFirstLineRE {
"^RTSP/1.0 (\\d+) ([^\r\n]+)" };
92 static const QRegularExpression kHeaderRE { R
"(^([^:]+):\s*([^\r\n]+))" };
93 static const QRegularExpression kBlankLineRE { R
"(^[\r\n]*$)" };
95 bool firstLine =
true;
98 if (!ctrl_socket.canReadLine())
100 bool ready = ctrl_socket.waitForReadyRead(10 * 1000);
103 LOG(VB_RECORD, LOG_ERR,
LOC +
"RTSP server did not respond after 10s");
109 QString line = ctrl_socket.readLine();
110 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"sendMessage " +
111 QString(
"read: %1").arg(line.simplified()));
113 QRegularExpressionMatch match;
116 match = kFirstLineRE.match(line);
117 if (!match.hasMatch())
119 LOG(VB_RECORD, LOG_WARNING,
LOC +
120 QString(
"Could not parse first line of response: '%1'")
121 .arg(line.simplified()));
125 QStringList parts = match.capturedTexts();
126 int responseCode = parts.at(1).toInt();
127 const QString& responseMsg = parts.at(2);
129 LOG(VB_RECORD, LOG_DEBUG,
LOC + QString(
"response code:%1 message:%2")
130 .arg(responseCode).arg(responseMsg));
132 if (responseCode != 200)
134 LOG(VB_RECORD, LOG_WARNING,
LOC +
135 QString(
"Server couldn't process the request: '%1'")
143 match = kBlankLineRE.match(line);
144 if (match.hasMatch())
break;
146 match = kHeaderRE.match(line);
147 if (!match.hasMatch())
149 LOG(VB_RECORD, LOG_WARNING,
LOC +
150 QString(
"Could not parse response header: '%1'")
151 .arg(line.simplified()));
154 QStringList parts = match.capturedTexts();
165 if (cSeq != QString(
"%1").arg(
m_cseq))
167 LOG(VB_RECORD, LOG_WARNING,
LOC +
168 QString(
"Expected CSeq of %1 but got %2").arg(
m_cseq).arg(cSeq));
171 ctrl_socket.disconnectFromHost();
172 if (ctrl_socket.state() != QAbstractSocket::UnconnectedState)
174 ctrl_socket.waitForDisconnected();
183 LOG(VB_RECORD, LOG_DEBUG,
LOC2 + QString(
"SETUP"));
187 LOG(VB_RECORD, LOG_WARNING,
LOC +
188 QString(
"Port %1 is used but SatIP specifies RTSP port 554").arg(
m_requestUrl.port()));
193 LOG(VB_RECORD, LOG_ERR,
LOC +
194 QString(
"Invalid port %1 using 554 instead").arg(
m_requestUrl.port()));
201 QString(
"Transport: RTP/AVP;unicast;client_port=%1-%2")
202 .arg(clientPort1).arg(clientPort2));
206 LOG(VB_RECORD, LOG_ERR,
LOC +
"Failed to send SETUP message");
216 LOG(VB_RECORD, LOG_ERR,
LOC +
"SETUP response did not contain the com.ses.streamID field");
222 static const QRegularExpression sessionTimeoutRegex {
223 "^([^\\r\\n]+);timeout=([0-9]+)?", QRegularExpression::CaseInsensitiveOption };
225 if (!match.hasMatch())
227 LOG(VB_RECORD, LOG_ERR,
LOC +
228 QString(
"Failed to extract session id from session header ('%1')")
234 ? std::chrono::seconds(match.capturedView(2).toInt() / 2)
237 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"Sat>IP protocol timeout:%1 s")
242 LOG(VB_RECORD, LOG_ERR,
LOC +
"SETUP response did not contain the Session field");
246 LOG(VB_RECORD, LOG_DEBUG,
LOC +
247 QString(
"Setup completed, sessionID = %1, streamID = %2, timeout = %3s")
249 .arg(duration_cast<std::chrono::seconds>(
m_timeout).count()));
256 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"Play(pids_str) " + pids_str);
263 LOG(VB_RECORD, LOG_ERR,
LOC +
"Failed to send PLAY message");
274 LOG(VB_RECORD, LOG_DEBUG,
LOC2 +
"TEARDOWN");
284 LOG(VB_RECORD, LOG_ERR,
LOC +
"Teardown failed");
301 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"StartKeepAliveRequested(%1) m_timer:%2")
307 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"StopKeepAliveRequested() m_timer:%1").arg(
m_timer));
317 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"Sending KeepAlive timer %1").arg(
timerEvent->timerId()));