Advertisement
Guest User

Untitled

a guest
Apr 23rd, 2012
38
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 20.19 KB | None | 0 0
  1. diff --git a/mythtv/libs/libmythtv/mythraopconnection.cpp b/mythtv/libs/libmythtv/mythraopconnection.cpp
  2. index 962c142..8b71dfb 100644
  3. --- a/mythtv/libs/libmythtv/mythraopconnection.cpp
  4. +++ b/mythtv/libs/libmythtv/mythraopconnection.cpp
  5. @@ -2,9 +2,8 @@
  6. // remove hardcoded frames per packet
  7.  
  8. #include <QTimer>
  9. -#include <QTcpSocket>
  10. -#include <QUdpSocket>
  11. #include <QtEndian>
  12. +#include <QNetworkInterface>
  13.  
  14. #include "mythlogging.h"
  15. #include "mythcorecontext.h"
  16. @@ -23,6 +22,22 @@
  17.  
  18. RSA* MythRAOPConnection::g_rsa = NULL;
  19.  
  20. +class NetStream : public QTextStream
  21. +{
  22. +public:
  23. + NetStream(QIODevice *device) : QTextStream(device)
  24. + {
  25. + };
  26. + NetStream &operator<<(const QString &str)
  27. + {
  28. + LOG(VB_GENERAL, LOG_DEBUG,
  29. + LOC + QString("Sending(%1): ").arg(str.length()) + str);
  30. + QTextStream *q = this;
  31. + *q << str;
  32. + return *this;
  33. + };
  34. +};
  35. +
  36. MythRAOPConnection::MythRAOPConnection(QObject *parent, QTcpSocket *socket,
  37. QByteArray id, int port)
  38. : QObject(parent), m_watchdogTimer(NULL), m_socket(socket),
  39. @@ -82,12 +97,18 @@ MythRAOPConnection::~MythRAOPConnection()
  40.  
  41. // free decoded audio buffer
  42. ExpireAudio(UINT64_MAX);
  43. +
  44. + if (g_rsa)
  45. + {
  46. + RSA_free(g_rsa);
  47. + g_rsa = NULL;
  48. + }
  49. }
  50.  
  51. bool MythRAOPConnection::Init(void)
  52. {
  53. // connect up the request socket
  54. - m_textStream = new QTextStream(m_socket);
  55. + m_textStream = new NetStream(m_socket);
  56. m_textStream->setCodec("UTF-8");
  57. if (!connect(m_socket, SIGNAL(readyRead()), this, SLOT(readClient())))
  58. {
  59. @@ -138,6 +159,24 @@ bool MythRAOPConnection::Init(void)
  60. return true;
  61. }
  62.  
  63. +void MythRAOPConnection::udpDataReady(void)
  64. +{
  65. + QUdpSocket *socket = dynamic_cast<QUdpSocket*>(sender());
  66. +
  67. + while (socket->state() == QAbstractSocket::BoundState &&
  68. + socket->hasPendingDatagrams())
  69. + {
  70. + QByteArray buffer;
  71. + buffer.resize(socket->pendingDatagramSize());
  72. + QHostAddress sender;
  73. + quint16 senderPort;
  74. +
  75. + socket->readDatagram(buffer.data(), buffer.size(),
  76. + &sender, &senderPort);
  77. + udpDataReady(buffer, sender, senderPort);
  78. + }
  79. +}
  80. +
  81. void MythRAOPConnection::udpDataReady(QByteArray buf, QHostAddress peer,
  82. quint16 port)
  83. {
  84. @@ -191,7 +230,8 @@ void MythRAOPConnection::udpDataReady(QByteArray buf, QHostAddress peer,
  85. m_resends.remove(this_sequence);
  86. }
  87. else
  88. - LOG(VB_GENERAL, LOG_WARNING, LOC + "Received unexpected resent packet.");
  89. + LOG(VB_GENERAL, LOG_WARNING, LOC + QString("Received unexpected resent packet %1")
  90. + .arg(this_sequence));
  91. }
  92.  
  93. ExpireResendRequests(timenow);
  94. @@ -332,12 +372,13 @@ void MythRAOPConnection::ProcessSyncPacket(const QByteArray &buf, uint64_t timen
  95.  
  96. if (m_audio)
  97. {
  98. + uint64_t total = averageaudio + averagequeue;
  99. LOG(VB_GENERAL, LOG_DEBUG, LOC +
  100. QString("Sync packet: Timestamp: %1 Current Audio ts: %2 (avsync %3ms) "
  101. "Latency: audio %4 queue %5 total %6ms <-> target %7ms")
  102. .arg(m_lastSyncTimestamp).arg(m_audio->GetAudiotime()).arg(averageav, 0)
  103. .arg(averageaudio).arg(averagequeue)
  104. - .arg(averageaudio + averagequeue).arg(m_lastLatency));
  105. + .arg(total).arg(m_lastLatency));
  106. }
  107. m_latencyAudio = m_latencyQueued = m_latencyCounter = m_avSync = 0;
  108. }
  109. @@ -463,78 +504,82 @@ void MythRAOPConnection::ProcessRequest(const QList<QByteArray> &lines)
  110. return;
  111. }
  112.  
  113. - QByteArray option = lines[0].left(lines[0].indexOf(" "));
  114. + *m_textStream << "RTSP/1.0 200 OK\r\n";
  115.  
  116. - if (option == "OPTIONS")
  117. + if (tags.contains("Apple-Challenge"))
  118. {
  119. - StartResponse(m_textStream);
  120. - if (tags.contains("Apple-Challenge"))
  121. - {
  122. - *m_textStream << "Apple-Response: ";
  123. - if (!LoadKey())
  124. - return;
  125. - int tosize = RSA_size(LoadKey());
  126. - unsigned char to[tosize];
  127. -
  128. - QByteArray challenge = QByteArray::fromBase64(tags["Apple-Challenge"].data());
  129. - int challenge_size = challenge.size();
  130. - if (challenge_size != 16)
  131. - {
  132. - LOG(VB_GENERAL, LOG_ERR, LOC +
  133. - QString("Decoded challenge size %1, expected 16").arg(challenge_size));
  134. - if (challenge_size > 16)
  135. - challenge_size = 16;
  136. - }
  137. + LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("Received Apple-Challenge"));
  138.  
  139. - int i = 0;
  140. - unsigned char from[38];
  141. - memcpy(from, challenge.data(), challenge_size);
  142. - i += challenge_size;
  143. - if (m_socket->localAddress().protocol() == QAbstractSocket::IPv4Protocol)
  144. - {
  145. - uint32_t ip = m_socket->localAddress().toIPv4Address();
  146. - ip = qToBigEndian(ip);
  147. - memcpy(from + i, &ip, 4);
  148. - i += 4;
  149. - }
  150. - else if (m_socket->localAddress().protocol() == QAbstractSocket::IPv6Protocol)
  151. - {
  152. - // NB IPv6 untested
  153. - Q_IPV6ADDR ip = m_socket->localAddress().toIPv6Address();
  154. - //ip = qToBigEndian(ip);
  155. - memcpy(from + i, &ip, 16);
  156. - i += 16;
  157. - }
  158. - memcpy(from + i, m_hardwareId.data(), RAOP_HARDWARE_ID_SIZE);
  159. - i += RAOP_HARDWARE_ID_SIZE;
  160. + *m_textStream << "Apple-Response: ";
  161. + if (!LoadKey())
  162. + return;
  163. + int tosize = RSA_size(LoadKey());
  164. + unsigned char to[tosize];
  165.  
  166. - int pad = 32 - i;
  167. - if (pad > 0)
  168. - {
  169. - memset(from + i, 0, pad);
  170. - i += pad;
  171. - }
  172. + QByteArray challenge = QByteArray::fromBase64(tags["Apple-Challenge"].data());
  173. + int challenge_size = challenge.size();
  174. + if (challenge_size != 16)
  175. + {
  176. + LOG(VB_GENERAL, LOG_ERR, LOC +
  177. + QString("Decoded challenge size %1, expected 16").arg(challenge_size));
  178. + if (challenge_size > 16)
  179. + challenge_size = 16;
  180. + }
  181.  
  182. - LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("Full base64 response: '%1' size %2")
  183. - .arg(QByteArray((const char*)from, i).toBase64().data()).arg(i));
  184. + int i = 0;
  185. + unsigned char from[38];
  186. + memcpy(from, challenge.data(), challenge_size);
  187. + i += challenge_size;
  188. + if (m_socket->localAddress().protocol() == QAbstractSocket::IPv4Protocol)
  189. + {
  190. + uint32_t ip = m_socket->localAddress().toIPv4Address();
  191. + ip = qToBigEndian(ip);
  192. + memcpy(from + i, &ip, 4);
  193. + i += 4;
  194. + }
  195. + else if (m_socket->localAddress().protocol() == QAbstractSocket::IPv6Protocol)
  196. + {
  197. + // NB IPv6 untested
  198. + Q_IPV6ADDR ip = m_socket->localAddress().toIPv6Address();
  199. + //ip = qToBigEndian(ip);
  200. + memcpy(from + i, &ip, 16);
  201. + i += 16;
  202. + }
  203. + memcpy(from + i, m_hardwareId.data(), RAOP_HARDWARE_ID_SIZE);
  204. + i += RAOP_HARDWARE_ID_SIZE;
  205. +
  206. + int pad = 32 - i;
  207. + if (pad > 0)
  208. + {
  209. + memset(from + i, 0, pad);
  210. + i += pad;
  211. + }
  212.  
  213. - RSA_private_encrypt(i, from, to, LoadKey(), RSA_PKCS1_PADDING);
  214. + LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("Full base64 response: '%1' size %2")
  215. + .arg(QByteArray((const char*)from, i).toBase64().data()).arg(i));
  216.  
  217. - QByteArray base64 = QByteArray((const char*)to, tosize).toBase64();
  218. + RSA_private_encrypt(i, from, to, LoadKey(), RSA_PKCS1_PADDING);
  219.  
  220. - for (int pos = base64.size() - 1; pos > 0; pos--)
  221. - {
  222. - if (base64[pos] == '=')
  223. - base64[pos] = ' ';
  224. - else
  225. - break;
  226. - }
  227. + QByteArray base64 = QByteArray((const char*)to, tosize).toBase64();
  228.  
  229. - *m_textStream << base64.trimmed() << "\r\n";
  230. + for (int pos = base64.size() - 1; pos > 0; pos--)
  231. + {
  232. + if (base64[pos] == '=')
  233. + base64[pos] = ' ';
  234. + else
  235. + break;
  236. }
  237. + LOG(VB_GENERAL, LOG_DEBUG, QString("tSize=%1 tLen=%2 tResponse=%3")
  238. + .arg(tosize).arg(base64.size()).arg(base64.data()));
  239. + *m_textStream << base64.trimmed() << "\r\n";
  240. + }
  241. +
  242. + QByteArray option = lines[0].left(lines[0].indexOf(" "));
  243.  
  244. + if (option == "OPTIONS")
  245. + {
  246. + StartResponse(m_textStream, option, tags["CSeq"]);
  247. *m_textStream << "Public: ANNOUNCE, SETUP, RECORD, PAUSE, FLUSH, TEARDOWN, OPTIONS, GET_PARAMETER, SET_PARAMETER\r\n";
  248. - FinishResponse(m_textStream, m_socket, option, tags["Cseq"]);
  249. }
  250. else if (option == "ANNOUNCE")
  251. {
  252. @@ -589,9 +634,7 @@ void MythRAOPConnection::ProcessRequest(const QList<QByteArray> &lines)
  253. LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("Audio parameter: %1").arg(fmt));
  254. }
  255. }
  256. -
  257. - StartResponse(m_textStream);
  258. - FinishResponse(m_textStream, m_socket, option, tags["Cseq"]);
  259. + StartResponse(m_textStream, option, tags["CSeq"]);
  260. }
  261. else if (option == "SETUP")
  262. {
  263. @@ -617,14 +660,6 @@ void MythRAOPConnection::ProcessRequest(const QList<QByteArray> &lines)
  264. QString("control port: %1 timing port: %2")
  265. .arg(control_port).arg(timing_port));
  266.  
  267. - StartResponse(m_textStream);
  268. - *m_textStream << "Transport: " << tags["Transport"];
  269. - *m_textStream << ";server_port=" << QString::number(m_dataPort) << "\r\n";
  270. - FinishResponse(m_textStream, m_socket, option, tags["Cseq"]);
  271. -
  272. - if (OpenAudioDevice())
  273. - CreateDecoder();
  274. -
  275. if (m_clientControlSocket)
  276. {
  277. m_clientControlSocket->disconnect();
  278. @@ -632,21 +667,31 @@ void MythRAOPConnection::ProcessRequest(const QList<QByteArray> &lines)
  279. delete m_clientControlSocket;
  280. }
  281.  
  282. - m_clientControlSocket = new ServerPool(this);
  283. + m_clientControlSocket = new QUdpSocket(this);
  284. if (!m_clientControlSocket->bind(control_port))
  285. {
  286. LOG(VB_GENERAL, LOG_ERR, LOC +
  287. - QString("Failed to bind to client control port %1").arg(control_port));
  288. + QString("Failed to bind to client control port %1. "
  289. + "Control of audio stream may fail")
  290. + .arg(control_port));
  291. }
  292. else
  293. {
  294. LOG(VB_GENERAL, LOG_INFO, LOC +
  295. QString("Bound to client control port %1").arg(control_port));
  296. - m_peerAddress = m_socket->peerAddress();
  297. - m_clientControlPort = control_port;
  298. - connect(m_clientControlSocket, SIGNAL(newDatagram(QByteArray, QHostAddress, quint16)),
  299. - this, SLOT(udpDataReady(QByteArray, QHostAddress, quint16)));
  300. }
  301. +
  302. + if (OpenAudioDevice())
  303. + CreateDecoder();
  304. +
  305. + m_peerAddress = m_socket->peerAddress();
  306. + m_clientControlPort = control_port;
  307. + connect(m_clientControlSocket, SIGNAL(readyRead()), this, SLOT(udpDataReady()));
  308. +
  309. + StartResponse(m_textStream, option, tags["CSeq"]);
  310. + *m_textStream << "Transport: " << tags["Transport"].data();
  311. + *m_textStream << ";server_port=" << QString::number(m_dataPort);
  312. + *m_textStream << "\r\nSession: DEADBEEF\r\n";
  313. }
  314. else
  315. {
  316. @@ -656,13 +701,24 @@ void MythRAOPConnection::ProcessRequest(const QList<QByteArray> &lines)
  317. }
  318. else if (option == "RECORD")
  319. {
  320. - StartResponse(m_textStream);
  321. - FinishResponse(m_textStream, m_socket, option, tags["Cseq"]);
  322. + StartResponse(m_textStream, option, tags["CSeq"]);
  323. + }
  324. + else if (option == "TEARDOWN")
  325. + {
  326. + *m_textStream << "Connection: close\r\n";
  327. + StartResponse(m_textStream, option, tags["CSeq"]);
  328. + }
  329. + else if (option == "FLUSH")
  330. + {
  331. + ResetAudio();
  332. + *m_textStream << "flush\r\n";
  333. + StartResponse(m_textStream, option, tags["CSeq"]);
  334. }
  335. else if (option == "SET_PARAMETER")
  336. {
  337. foreach (QByteArray line, lines)
  338. {
  339. + StartResponse(m_textStream, option, tags["CSeq"]);
  340. if (line.startsWith("volume:") && m_allowVolumeControl && m_audio)
  341. {
  342. QByteArray rawvol = line.mid(7).trimmed();
  343. @@ -674,43 +730,34 @@ void MythRAOPConnection::ProcessRequest(const QList<QByteArray> &lines)
  344. m_audio->SetCurrentVolume((int)volume);
  345. }
  346. }
  347. -
  348. - StartResponse(m_textStream);
  349. - FinishResponse(m_textStream, m_socket, option, tags["Cseq"]);
  350. - }
  351. - else if (option == "FLUSH")
  352. - {
  353. - ResetAudio();
  354. - StartResponse(m_textStream);
  355. - FinishResponse(m_textStream, m_socket, option, tags["Cseq"]);
  356. }
  357. - else if (option == "TEARDOWN")
  358. + else
  359. {
  360. - StartResponse(m_textStream);
  361. - *m_textStream << "Connection: close\r\n";
  362. - FinishResponse(m_textStream, m_socket, option, tags["Cseq"]);
  363. + LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("Command not handled: %1")
  364. + .arg(option.data()));
  365. + StartResponse(m_textStream, option, tags["CSeq"]);
  366. }
  367. -
  368. + FinishResponse(m_textStream, m_socket, option, tags["CSeq"]);
  369. }
  370.  
  371. -void MythRAOPConnection::StartResponse(QTextStream *stream)
  372. +void MythRAOPConnection::StartResponse(NetStream *stream,
  373. + QByteArray &option, QByteArray &cseq)
  374. {
  375. if (!stream)
  376. return;
  377. - *stream << "RTSP/1.0 200 OK\r\n";
  378. -}
  379. -
  380. -void MythRAOPConnection::FinishResponse(QTextStream *stream, QTcpSocket *socket,
  381. - QByteArray &option, QByteArray &cseq)
  382. -{
  383. LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("%1 sequence %2")
  384. .arg(option.data()).arg(cseq.data()));
  385. *stream << "Audio-Jack-Status: connected; type=analog\r\n";
  386. *stream << "CSeq: " << cseq << "\r\n";
  387. +}
  388. +
  389. +void MythRAOPConnection::FinishResponse(NetStream *stream, QTcpSocket *socket,
  390. + QByteArray &option, QByteArray &cseq)
  391. +{
  392. *stream << "\r\n";
  393. stream->flush();
  394. - LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("Send: %1")
  395. - .arg(socket->flush()));
  396. + LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("Finished %1 , Send: %2")
  397. + .arg(cseq.data()).arg(socket->flush()));
  398. }
  399.  
  400. RSA* MythRAOPConnection::LoadKey(void)
  401. @@ -797,7 +844,7 @@ bool MythRAOPConnection::CreateDecoder(void)
  402. extradata[13] = (fs >> 16) & 0xff;
  403. extradata[14] = (fs >> 8) & 0xff;
  404. extradata[15] = fs & 0xff;
  405. - extradata[16] = 2; // channels
  406. + extradata[16] = m_channels; // channels
  407. extradata[17] = m_audioFormat[3]; // sample size
  408. extradata[18] = m_audioFormat[4]; // rice_historymult
  409. extradata[19] = m_audioFormat[5]; // rice_initialhistory
  410. @@ -805,7 +852,7 @@ bool MythRAOPConnection::CreateDecoder(void)
  411. }
  412. m_codeccontext->extradata = extradata;
  413. m_codeccontext->extradata_size = 36;
  414. - m_codeccontext->channels = 2;
  415. + m_codeccontext->channels = m_channels;
  416. if (avcodec_open(m_codeccontext, m_codec) < 0)
  417. {
  418. LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to open ALAC decoder - going silent...");
  419. @@ -834,6 +881,7 @@ bool MythRAOPConnection::OpenAudioDevice(void)
  420. CloseAudioDevice();
  421.  
  422. m_sampleRate = m_audioFormat.size() >= 12 ? m_audioFormat[11] : DEFAULT_SAMPLE_RATE;
  423. + m_channels = m_audioFormat[7] > 0 ? m_audioFormat[7] : 2;
  424. if (m_sampleRate < 1)
  425. m_sampleRate = DEFAULT_SAMPLE_RATE;
  426.  
  427. @@ -841,7 +889,7 @@ bool MythRAOPConnection::OpenAudioDevice(void)
  428. ? gCoreContext->GetSetting("PassThruOutputDevice") : QString::null;
  429. QString device = gCoreContext->GetSetting("AudioOutputDevice");
  430.  
  431. - m_audio = AudioOutput::OpenAudio(device, passthru, FORMAT_S16, 2,
  432. + m_audio = AudioOutput::OpenAudio(device, passthru, FORMAT_S16, m_channels,
  433. 0, m_sampleRate, AUDIOOUTPUT_MUSIC,
  434. m_allowVolumeControl, false);
  435. if (!m_audio)
  436. diff --git a/mythtv/libs/libmythtv/mythraopconnection.h b/mythtv/libs/libmythtv/mythraopconnection.h
  437. index 9d56d4e..4200979 100644
  438. --- a/mythtv/libs/libmythtv/mythraopconnection.h
  439. +++ b/mythtv/libs/libmythtv/mythraopconnection.h
  440. @@ -15,15 +15,16 @@ extern "C" {
  441. #include "libavformat/avformat.h"
  442. }
  443.  
  444. -class QTextStream;
  445. class QTcpSocket;
  446. class QUdpSocket;
  447. class QTimer;
  448. class AudioOutput;
  449. class ServerPool;
  450. +class NetStream;
  451.  
  452. typedef QHash<QByteArray,QByteArray> RawHash;
  453.  
  454. +
  455. class MythRAOPConnection : public QObject
  456. {
  457. Q_OBJECT
  458. @@ -42,6 +43,7 @@ class MythRAOPConnection : public QObject
  459. public slots:
  460. void readClient(void);
  461. void udpDataReady(QByteArray buf, QHostAddress peer, quint16 port);
  462. + void udpDataReady(void);
  463. void timeout(void);
  464. void audioRetry(void);
  465.  
  466. @@ -58,8 +60,9 @@ class MythRAOPConnection : public QObject
  467. void ProcessAudio(uint64_t timenow);
  468. void ResetAudio(void);
  469. void ProcessRequest(const QList<QByteArray> &lines);
  470. - void StartResponse(QTextStream *stream);
  471. - void FinishResponse(QTextStream *stream, QTcpSocket *socket,
  472. + void StartResponse(NetStream *stream,
  473. + QByteArray &option, QByteArray &cseq);
  474. + void FinishResponse(NetStream *stream, QTcpSocket *socket,
  475. QByteArray &option, QByteArray &cseq);
  476. RawHash FindTags(const QList<QByteArray> &lines);
  477. bool CreateDecoder(void);
  478. @@ -72,13 +75,13 @@ class MythRAOPConnection : public QObject
  479. QTimer *m_watchdogTimer;
  480. // comms socket
  481. QTcpSocket *m_socket;
  482. - QTextStream *m_textStream;
  483. + NetStream *m_textStream;
  484. QByteArray m_hardwareId;
  485. // incoming audio
  486. QHostAddress m_peerAddress;
  487. int m_dataPort;
  488. ServerPool *m_dataSocket;
  489. - ServerPool *m_clientControlSocket;
  490. + QUdpSocket *m_clientControlSocket;
  491. int m_clientControlPort;
  492. QMap<uint16_t,uint64_t> m_resends;
  493. // crypto
  494. @@ -91,6 +94,7 @@ class MythRAOPConnection : public QObject
  495. AVCodecContext *m_codeccontext;
  496. QList<int> m_audioFormat;
  497. int m_sampleRate;
  498. + int m_channels;
  499. typedef struct
  500. {
  501. int16_t *samples;
  502. diff --git a/mythtv/libs/libmythtv/mythraopdevice.cpp b/mythtv/libs/libmythtv/mythraopdevice.cpp
  503. index f27f166..bad4932 100644
  504. --- a/mythtv/libs/libmythtv/mythraopdevice.cpp
  505. +++ b/mythtv/libs/libmythtv/mythraopdevice.cpp
  506. @@ -1,6 +1,5 @@
  507. #include <QTimer>
  508. #include <QtEndian>
  509. -#include <QTcpSocket>
  510. #include <QNetworkInterface>
  511.  
  512. #include "mthread.h"
  513. @@ -146,11 +145,6 @@ void MythRAOPDevice::Start(void)
  514.  
  515. // announce service
  516. m_bonjour = new BonjourRegister(this);
  517. - if (!m_bonjour)
  518. - {
  519. - LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create Bonjour object.");
  520. - return;
  521. - }
  522.  
  523. // give each frontend a unique name
  524. int multiple = m_setupPort - baseport;
  525. @@ -177,6 +171,8 @@ void MythRAOPDevice::Start(void)
  526. txt.append(4); txt.append("vn=3");
  527. txt.append(9); txt.append("txtvers=1");
  528.  
  529. + LOG(VB_GENERAL, LOG_INFO, QString("Registering service %1.%2 port %3 TXT %4")
  530. + .arg(QString(name)).arg(QString(type)).arg(m_setupPort).arg(QString(txt)));
  531. if (!m_bonjour->Register(m_setupPort, type, name, txt))
  532. {
  533. LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to register service.");
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement