MythTV  master
linuxfirewiredevice.cpp
Go to the documentation of this file.
1 
10 // POSIX headers
11 #include <sys/select.h>
12 #include <unistd.h>
13 #include <fcntl.h>
14 
15 // Linux headers
16 #include <libraw1394/raw1394.h>
17 #include <libraw1394/csr.h>
18 #include <libiec61883/iec61883.h>
19 #include <libavc1394/avc1394.h>
20 #include <libavc1394/rom1394.h>
21 
22 #include <netinet/in.h>
23 
24 // C++ headers
25 #include <algorithm>
26 #include <chrono> // for milliseconds
27 #include <map>
28 #include <thread> // for sleep_for
29 using namespace std;
30 
31 // Qt headers
32 #include <QDateTime>
33 
34 // MythTV headers
35 #include "linuxfirewiredevice.h"
36 #include "firewirerecorder.h"
37 #include "mythcorecontext.h"
38 #include "linuxavcinfo.h"
39 #include "mythlogging.h"
40 
41 #define LOC QString("LFireDev(%1): ").arg(guid_to_string(m_guid))
42 
43 #define kNoDataTimeout 50 /* msec */
44 #define kResetTimeout 1000 /* msec */
45 
46 using handle_to_lfd_t = QHash<raw1394handle_t,LinuxFirewireDevice*>;
47 
48 class LFDPriv
49 {
50  public:
51  LFDPriv() = default;
52 
54  {
55  for (const auto & device : qAsConst(m_devices))
56  delete device;
57  m_devices.clear();
58 
59  if (m_portHandlerThread)
60  {
61  m_portHandlerThread->wait();
62  delete m_portHandlerThread;
63  }
64  }
65 
66  uint m_generation {0};
67  bool m_resetTimerOn {false};
69 
70  bool m_runPortHandler {false};
71  bool m_isPortHandlerRunning {false};
72  QWaitCondition m_portHandlerWait;
74 
75  iec61883_mpeg2_t m_avstream {nullptr};
76  int m_channel {-1};
77  int m_outputPlug {-1};
78  int m_inputPlug {-1};
79  int m_bandwidth {0};
80  uint m_noDataCnt {0};
81 
82  bool m_isP2pNodeOpen {false};
83  bool m_isBcastNodeOpen {false};
84  bool m_isStreaming {false};
85 
86  MThread *m_portHandlerThread {nullptr};
87 
89 
90  static QMutex s_lock;
92 };
93 QMutex LFDPriv::s_lock;
95 
96 static void add_handle(raw1394handle_t handle, LinuxFirewireDevice *dev)
97 {
98  QMutexLocker slocker(&LFDPriv::s_lock);
99  LFDPriv::s_handle_info[handle] = dev;
100 }
101 
102 static void remove_handle(raw1394handle_t handle)
103 {
104  QMutexLocker slocker(&LFDPriv::s_lock);
105  LFDPriv::s_handle_info.remove(handle);
106 }
107 
111 const uint LinuxFirewireDevice::kMaxBufferedPackets = 4 * 1024 * 1024 / 188;
112 
113 // callback function for libiec61883
115  unsigned char *tspacket, int len, uint dropped, void *callback_data);
117 static bool has_data(int fd, int msec);
118 static QString speed_to_string(uint speed);
120  raw1394handle_t handle, uint generation);
121 
123  uint64_t guid, uint subunitid,
124  uint speed, bool use_p2p, uint av_buffer_size_in_bytes) :
125  FirewireDevice(guid, subunitid, speed),
126  m_bufsz(av_buffer_size_in_bytes),
127  m_useP2P(use_p2p), m_priv(new LFDPriv())
128 {
129  if (!m_bufsz)
130  m_bufsz = gCoreContext->GetNumSetting("HDRingbufferSize");
131 
132  m_dbResetDisabled = gCoreContext->GetBoolSetting("DisableFirewireReset", false);
133 
135 }
136 
138 {
140  {
141  LOG(VB_GENERAL, LOG_ERR, LOC + "ctor called with open port");
144  }
145 
146  if (m_priv)
147  {
148  delete m_priv;
149  m_priv = nullptr;
150  }
151 }
152 
154 {
155  const QString loc = LOC + QString("SignalReset(%1->%2)")
156  .arg(m_priv->m_generation).arg(generation);
157 
158  LOG(VB_GENERAL, LOG_INFO, loc);
159 
160  if (GetInfoPtr())
161  raw1394_update_generation(GetInfoPtr()->m_fwHandle, generation);
162 
163  m_priv->m_generation = generation;
164 
165  LOG(VB_GENERAL, LOG_INFO, loc + ": Updating device list -- begin");
167  LOG(VB_GENERAL, LOG_INFO, loc + ": Updating device list -- end");
168 
169  m_priv->m_resetTimerOn = true;
171 }
172 
174 {
175  const QString loc = LOC + "HandleBusReset";
176 
177  if (!GetInfoPtr() || !GetInfoPtr()->m_fwHandle)
178  return;
179 
180  if (m_priv->m_isP2pNodeOpen)
181  {
182  LOG(VB_GENERAL, LOG_INFO, loc + ": Reconnecting P2P connection");
183  nodeid_t output = GetInfoPtr()->GetNode() | 0xffc0;
184  nodeid_t input = raw1394_get_local_id(GetInfoPtr()->m_fwHandle);
185 
186  int fwchan = iec61883_cmp_reconnect(
187  GetInfoPtr()->m_fwHandle,
189  input, &m_priv->m_inputPlug,
191 
192  if (fwchan < 0)
193  {
194  LOG(VB_GENERAL, LOG_ERR, LOC + "Bus Reset: Failed to reconnect");
195  }
196  else if (fwchan != m_priv->m_channel)
197  {
198  LOG(VB_GENERAL, LOG_WARNING, LOC + QString("FWChan changed %1->%2")
199  .arg(m_priv->m_channel).arg(fwchan));
200  }
201  m_priv->m_channel = fwchan;
202 
203  LOG(VB_GENERAL, LOG_INFO,
204  loc + QString(": Reconnected fwchan: %1\n\t\t\toutput: 0x%2 "
205  "input: 0x%3")
206  .arg(fwchan).arg(output,0,16).arg(input,0,16));
207  }
208 
210  {
211  nodeid_t output = GetInfoPtr()->GetNode() | 0xffc0;
212 
213  LOG(VB_RECORD, LOG_INFO, loc + ": Restarting broadcast connection on " +
214  QString("node %1, channel %2")
215  .arg(GetInfoPtr()->GetNode()).arg(m_priv->m_channel));
216 
217  int err = iec61883_cmp_create_bcast_output(
218  GetInfoPtr()->m_fwHandle,
221 
222  if (err < 0)
223  {
224  LOG(VB_GENERAL, LOG_ERR, LOC + "Bus Reset : Failed to reconnect");
225  }
226  }
227 }
228 
230 {
231  LOG(VB_RECORD, LOG_INFO, LOC + "Starting Port Handler Thread");
232  QMutexLocker locker(&m_priv->m_startStopPortHandlerLock);
233  LOG(VB_RECORD, LOG_INFO, LOC + "Starting Port Handler Thread -- locked");
234 
235  LOG(VB_RECORD, LOG_INFO, LOC + "OpenPort()");
236 
237  QMutexLocker mlocker(&m_lock);
238 
239  LOG(VB_RECORD, LOG_INFO, LOC + "OpenPort() -- got lock");
240 
241  if (!GetInfoPtr())
242  return false;
243 
244  if (GetInfoPtr()->IsPortOpen())
245  {
246  m_openPortCnt++;
247  return true;
248  }
249 
250  if (!GetInfoPtr()->OpenPort())
251  return false;
252 
253  add_handle(GetInfoPtr()->m_fwHandle, this);
254 
255  m_priv->m_generation = raw1394_get_generation(GetInfoPtr()->m_fwHandle);
256  raw1394_set_bus_reset_handler(
258 
260  LOG(VB_RECORD, LOG_INFO, LOC + GetInfoPtr()->GetSubunitInfoString());
261 
262  if (!GetInfoPtr()->IsSubunitType(kAVCSubunitTypeTuner) ||
263  !GetInfoPtr()->IsSubunitType(kAVCSubunitTypePanel))
264  {
265  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Not an STB"));
266 
267  mlocker.unlock();
268  ClosePort();
269 
270  return false;
271  }
272 
273  m_priv->m_runPortHandler = true;
274 
275  LOG(VB_RECORD, LOG_INFO, LOC + "Starting port handler thread");
276  m_priv->m_portHandlerThread = new MThread("LinuxController", this);
278 
280  m_priv->m_portHandlerWait.wait(mlocker.mutex(), 100);
281 
282  LOG(VB_RECORD, LOG_INFO, LOC + "Port handler thread started");
283 
284  m_openPortCnt++;
285 
286  return true;
287 }
288 
290 {
291  LOG(VB_RECORD, LOG_INFO, LOC + "Stopping Port Handler Thread");
292  QMutexLocker locker(&m_priv->m_startStopPortHandlerLock);
293  LOG(VB_RECORD, LOG_INFO, LOC + "Stopping Port Handler Thread -- locked");
294 
295  QMutexLocker mlocker(&m_lock);
296 
297  LOG(VB_RECORD, LOG_INFO, LOC + "ClosePort()");
298 
299  if (m_openPortCnt < 1)
300  return false;
301 
302  m_openPortCnt--;
303 
304  if (m_openPortCnt != 0)
305  return true;
306 
307  if (!GetInfoPtr())
308  return false;
309 
310  if (GetInfoPtr()->IsPortOpen())
311  {
312  if (IsNodeOpen())
313  CloseNode();
314 
315  LOG(VB_RECORD, LOG_INFO,
316  LOC + "Waiting for port handler thread to stop");
317  m_priv->m_runPortHandler = false;
318  m_priv->m_portHandlerWait.wakeAll();
319 
320  mlocker.unlock();
322  mlocker.relock();
323 
324  delete m_priv->m_portHandlerThread;
325  m_priv->m_portHandlerThread = nullptr;
326 
327  LOG(VB_RECORD, LOG_INFO, LOC + "Joined port handler thread");
328 
329  remove_handle(GetInfoPtr()->m_fwHandle);
330 
331  if (!GetInfoPtr()->ClosePort())
332  return false;
333  }
334 
335  return true;
336 }
337 
339 {
340  QMutexLocker locker(&m_lock);
341 
342  FirewireDevice::AddListener(listener);
343 
344  if (!m_listeners.empty())
345  {
346  OpenNode();
347  OpenAVStream();
348  StartStreaming();
349  }
350 }
351 
353 {
354  QMutexLocker locker(&m_lock);
355 
357 
358  if (m_listeners.empty())
359  {
360  StopStreaming();
361  CloseAVStream();
362  CloseNode();
363  }
364 }
365 
367  const vector<uint8_t> &cmd,
368  vector<uint8_t> &result,
369  int retry_cnt)
370 {
371  return GetInfoPtr()->SendAVCCommand(cmd, result, retry_cnt);
372 }
373 
375 {
376  QMutexLocker locker(&m_lock);
377 
378  if (!GetInfoPtr())
379  return false;
380 
381  return GetInfoPtr()->IsPortOpen();
382 }
383 
385 // Private methods
386 
388 {
389  if (m_useP2P)
390  return OpenP2PNode();
391  return OpenBroadcastNode();
392 }
393 
395 {
396  if (m_priv->m_isP2pNodeOpen)
397  return CloseP2PNode();
398 
400  return CloseBroadcastNode();
401 
402  return true;
403 }
404 
405 // This may in fact open a broadcast connection, but it tries to open
406 // a P2P connection first.
408 {
410  return false;
411 
412  if (m_priv->m_isP2pNodeOpen)
413  return true;
414 
415  LOG(VB_RECORD, LOG_INFO, LOC + "Opening P2P connection");
416 
417  m_priv->m_bandwidth = +1; // +1 == allocate bandwidth
418  m_priv->m_outputPlug = -1; // -1 == find first online plug
419  m_priv->m_inputPlug = -1; // -1 == find first online plug
420  nodeid_t output = GetInfoPtr()->GetNode() | 0xffc0;
421  nodeid_t input = raw1394_get_local_id(GetInfoPtr()->m_fwHandle);
422  m_priv->m_channel = iec61883_cmp_connect(GetInfoPtr()->m_fwHandle,
424  input, &m_priv->m_inputPlug,
425  &m_priv->m_bandwidth);
426 
427  if (m_priv->m_channel < 0)
428  {
429  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create P2P connection");
430 
431  m_priv->m_bandwidth = 0;
432 
433  return false;
434  }
435 
436  m_priv->m_isP2pNodeOpen = true;
437 
438  return true;
439 }
440 
442 {
443  if (m_priv->m_isP2pNodeOpen && (m_priv->m_channel >= 0))
444  {
445  LOG(VB_RECORD, LOG_INFO, LOC + "Closing P2P connection");
446 
447  if (m_priv->m_avstream)
448  CloseAVStream();
449 
450  nodeid_t output = GetInfoPtr()->GetNode() | 0xffc0;
451  nodeid_t input = raw1394_get_local_id(GetInfoPtr()->m_fwHandle);
452 
453  iec61883_cmp_disconnect(GetInfoPtr()->m_fwHandle,
455  input, m_priv->m_inputPlug,
457 
458  m_priv->m_channel = -1;
459  m_priv->m_outputPlug = -1;
460  m_priv->m_inputPlug = -1;
461  m_priv->m_isP2pNodeOpen = false;
462  }
463 
464  return true;
465 }
466 
468 {
469  if (m_priv->m_isP2pNodeOpen)
470  return false;
471 
473  return true;
474 
475  if (m_priv->m_avstream)
476  CloseAVStream();
477 
479  m_priv->m_outputPlug = 0;
480  m_priv->m_inputPlug = 0;
481  nodeid_t output = GetInfoPtr()->GetNode() | 0xffc0;
482 
483  LOG(VB_RECORD, LOG_INFO, LOC + "Opening broadcast connection on " +
484  QString("node %1, channel %2")
485  .arg(GetInfoPtr()->GetNode()).arg(m_priv->m_channel));
486 
487  int err = iec61883_cmp_create_bcast_output(
488  GetInfoPtr()->m_fwHandle,
491 
492  if (err != 0)
493  {
494  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create Broadcast connection");
495 
496  m_priv->m_channel = -1;
497  m_priv->m_outputPlug = -1;
498  m_priv->m_inputPlug = -1;
499 
500  return false;
501  }
502 
503  m_priv->m_isBcastNodeOpen = true;
504 
505  return true;
506 }
507 
509 {
511  {
512  LOG(VB_RECORD, LOG_INFO, LOC + "Closing broadcast connection");
513 
514  m_priv->m_channel = -1;
515  m_priv->m_outputPlug = -1;
516  m_priv->m_inputPlug = -1;
517  m_priv->m_isBcastNodeOpen = false;
518  }
519  return true;
520 }
521 
523 {
524  LOG(VB_RECORD, LOG_INFO, LOC + "OpenAVStream");
525 
526  if (!GetInfoPtr() || !GetInfoPtr()->IsPortOpen())
527  {
528  LOG(VB_GENERAL, LOG_ERR, LOC +
529  "Cannot open AVStream without open IEEE 1394 port");
530 
531  return false;
532  }
533 
534  if (!IsNodeOpen() && !OpenNode())
535  return false;
536 
537  if (m_priv->m_avstream)
538  return true;
539 
540  LOG(VB_RECORD, LOG_INFO, LOC + "Opening A/V stream object");
541 
542  m_priv->m_avstream = iec61883_mpeg2_recv_init(
544 
545  if (!m_priv->m_avstream)
546  {
547  LOG(VB_GENERAL, LOG_ERR, LOC + "Unable to open AVStream" + ENO);
548 
549  return false;
550  }
551 
552  iec61883_mpeg2_set_synch(m_priv->m_avstream, 1 /* sync on close */);
553 
554  if (m_bufsz)
556 
557  return true;
558 }
559 
561 {
562  if (!m_priv->m_avstream)
563  return true;
564 
565  LOG(VB_RECORD, LOG_INFO, LOC + "Closing A/V stream object");
566 
567  while (!m_listeners.empty())
569 
570  if (m_priv->m_isStreaming)
571  StopStreaming();
572 
573  iec61883_mpeg2_close(m_priv->m_avstream);
574  m_priv->m_avstream = nullptr;
575 
576  return true;
577 }
578 
580 {
581  LOG(VB_RECORD, LOG_INFO, LOC + "RunPortHandler -- start");
582  m_lock.lock();
583  LOG(VB_RECORD, LOG_INFO, LOC + "RunPortHandler -- got first lock");
585  m_priv->m_portHandlerWait.wakeAll();
586  // we need to unlock & sleep to allow wakeAll to wake other threads.
587  m_lock.unlock();
588  std::this_thread::sleep_for(std::chrono::microseconds(2500));
589  m_lock.lock();
590 
591  m_priv->m_noDataCnt = 0;
592  while (m_priv->m_runPortHandler)
593  {
594  LFDPriv::s_lock.lock();
595  bool reset_timer_on = m_priv->m_resetTimerOn;
596  bool handle_reset = reset_timer_on &&
597  (m_priv->m_resetTimer.elapsed() > 100);
598  if (handle_reset)
599  m_priv->m_resetTimerOn = false;
600  LFDPriv::s_lock.unlock();
601 
602  if (handle_reset)
603  HandleBusReset();
604 
605  if (!reset_timer_on && m_priv->m_isStreaming &&
607  {
608  m_priv->m_noDataCnt = 0;
609  ResetBus();
610  }
611 
612  int fwfd = raw1394_get_fd(GetInfoPtr()->m_fwHandle);
613  if (fwfd < 0)
614  {
615  // We unlock here because this can take a long time
616  // and we don't want to block other actions.
618 
619  m_priv->m_noDataCnt += (m_priv->m_isStreaming) ? 1 : 0;
620  continue;
621  }
622 
623  // We unlock here because this can take a long time and we
624  // don't want to block other actions. All reads and writes
625  // are done with the lock, so this is safe so long as we
626  // check that we really have data once we get the lock.
627  m_lock.unlock();
628  bool ready = has_data(fwfd, kNoDataTimeout);
629  m_lock.lock();
630 
631  if (!ready && m_priv->m_isStreaming)
632  {
633  m_priv->m_noDataCnt++;
634 
635  LOG(VB_GENERAL, LOG_WARNING, LOC + QString("No Input in %1 msec...")
637  }
638 
639  // Confirm that we won't block, now that we have the lock...
640  if (ready && has_data(fwfd, 1 /* msec */))
641  {
642  // Performs blocking read of next 4 bytes off bus and handles
643  // them. Most firewire commands do their own loop_iterate
644  // internally to check for results, but some things like
645  // streaming data and FireWire bus resets must be handled
646  // as well, which we do here...
647  int ret = raw1394_loop_iterate(GetInfoPtr()->m_fwHandle);
648  if (-1 == ret)
649  {
650  LOG(VB_GENERAL, LOG_ERR, LOC + "raw1394_loop_iterate" + ENO);
651  }
652  }
653  }
654 
656  m_priv->m_portHandlerWait.wakeAll();
657  m_lock.unlock();
658  LOG(VB_RECORD, LOG_INFO, LOC + "RunPortHandler -- end");
659 }
660 
662 {
663  if (m_priv->m_isStreaming)
664  return m_priv->m_isStreaming;
665 
666  if (!IsAVStreamOpen() && !OpenAVStream())
667  return false;
668 
669  if (m_priv->m_channel < 0)
670  {
671  LOG(VB_GENERAL, LOG_ERR, LOC + "Starting A/V streaming, no channel");
672  return false;
673  }
674 
675  LOG(VB_RECORD, LOG_INFO, LOC + "Starting A/V streaming -- really");
676 
677  if (iec61883_mpeg2_recv_start(m_priv->m_avstream, m_priv->m_channel) == 0)
678  {
679  m_priv->m_isStreaming = true;
680  }
681  else
682  {
683  LOG(VB_GENERAL, LOG_ERR, LOC + "Starting A/V streaming " + ENO);
684  }
685 
686  LOG(VB_RECORD, LOG_INFO, LOC + "Starting A/V streaming -- done");
687 
688  return m_priv->m_isStreaming;
689 }
690 
692 {
693  if (m_priv->m_isStreaming)
694  {
695  LOG(VB_RECORD, LOG_INFO, LOC + "Stopping A/V streaming -- really");
696 
697  m_priv->m_isStreaming = false;
698 
699  iec61883_mpeg2_recv_stop(m_priv->m_avstream);
700 
701  raw1394_iso_recv_flush(GetInfoPtr()->m_fwHandle);
702  }
703 
704  LOG(VB_RECORD, LOG_INFO, LOC + "Stopped A/V streaming");
705 
706  return true;
707 }
708 
710 {
711  if (!m_priv->m_avstream)
712  return false;
713 
714  // Set buffered packets size
715  uint buffer_size = max(size_in_bytes, 50 * TSPacket::kSize);
716  size_t buffered_packets = min(buffer_size / 4, kMaxBufferedPackets);
717 
718  iec61883_mpeg2_set_buffers(m_priv->m_avstream, buffered_packets);
719 
720  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Buffered packets %1 (%2 KB)")
721  .arg(buffered_packets).arg(buffered_packets * 4));
722 
723  return true;
724 }
725 
727 {
728  if (!m_priv->m_avstream)
729  return false;
730 
731  uint curspeed = iec61883_mpeg2_get_speed(m_priv->m_avstream);
732 
733  if (curspeed == speed)
734  {
735  m_speed = speed;
736  return true;
737  }
738 
739  LOG(VB_RECORD, LOG_INFO, LOC + QString("Changing Speed %1 -> %2")
740  .arg(speed_to_string(curspeed))
742 
743  iec61883_mpeg2_set_speed(m_priv->m_avstream, speed);
744 
745  if (speed == (uint)iec61883_mpeg2_get_speed(m_priv->m_avstream))
746  {
747  m_speed = speed;
748  return true;
749  }
750 
751  LOG(VB_GENERAL, LOG_WARNING, LOC + "Unable to set firewire speed.");
752 
753  return false;
754 }
755 
757 {
759 }
760 
762 {
763  return m_priv->m_avstream;
764 }
765 
767 {
768  LOG(VB_GENERAL, LOG_INFO, LOC + "ResetBus() -- begin");
769 
770  if (m_dbResetDisabled)
771  {
772  LOG(VB_GENERAL, LOG_WARNING, LOC + "Bus Reset disabled" + ENO);
773  LOG(VB_GENERAL, LOG_INFO, LOC + "ResetBus() -- end");
774  return true;
775  }
776 
777  bool ok = (raw1394_reset_bus_new(GetInfoPtr()->m_fwHandle,
778  RAW1394_LONG_RESET) == 0);
779  if (!ok)
780  LOG(VB_GENERAL, LOG_ERR, LOC + "Bus Reset failed" + ENO);
781 
782  LOG(VB_GENERAL, LOG_INFO, LOC + "ResetBus() -- end");
783 
784  return ok;
785 }
786 
788 {
789  if (dropped_packets == 1)
790  {
791  LOG(VB_RECORD, LOG_ERR, LOC + "Dropped a TS packet");
792  }
793  else if (dropped_packets > 1)
794  {
795  LOG(VB_RECORD, LOG_ERR, LOC + QString("Dropped %1 TS packets")
796  .arg(dropped_packets));
797  }
798 }
799 
800 vector<AVCInfo> LinuxFirewireDevice::GetSTBList(void)
801 {
802  vector<AVCInfo> list;
803 
804  {
805  LinuxFirewireDevice dev(0,0,0,false);
806  list = dev.GetSTBListPrivate();
807  }
808 
809  return list;
810 }
811 
813 {
814 #if 0
815  LOG(VB_GENERAL, LOG_DEBUG, "GetSTBListPrivate -- begin");
816 #endif
817  QMutexLocker locker(&m_lock);
818 #if 0
819  LOG(VB_GENERAL, LOG_DEBUG, "GetSTBListPrivate -- got lock");
820 #endif
821 
822  vector<AVCInfo> list;
823 
824  for (const auto & device : qAsConst(m_priv->m_devices))
825  {
826  if (device->IsSubunitType(kAVCSubunitTypeTuner) &&
827  device->IsSubunitType(kAVCSubunitTypePanel))
828  {
829  list.push_back(*device);
830  }
831  }
832 
833 #if 0
834  LOG(VB_GENERAL, LOG_DEBUG, "GetSTBListPrivate -- end");
835 #endif
836  return list;
837 }
838 
839 struct dev_item
840 {
841  raw1394handle_t m_handle;
842  int m_port;
843  int m_node;
844 };
845 
847 {
848  dev_item item {};
849 
850  item.m_handle = raw1394_new_handle();
851  if (!item.m_handle)
852  {
853  LOG(VB_GENERAL, LOG_ERR, QString("LinuxFirewireDevice: ") +
854  "Couldn't get handle" + ENO);
855  return false;
856  }
857 
858  std::array<raw1394_portinfo,16> port_info {};
859  int numcards = raw1394_get_port_info(item.m_handle, port_info.data(),
860  port_info.size());
861  if (numcards < 1)
862  {
863  raw1394_destroy_handle(item.m_handle);
864  return true;
865  }
866 
867  map<uint64_t,bool> guid_online;
868  for (int port = 0; port < numcards; port++)
869  {
870  if (raw1394_set_port(item.m_handle, port) < 0)
871  {
872  LOG(VB_GENERAL, LOG_ERR, QString("LinuxFirewireDevice: "
873  "Couldn't set port to %1").arg(port));
874  continue;
875  }
876 
877  for (int node = 0; node < raw1394_get_nodecount(item.m_handle); node++)
878  {
879  uint64_t guid = 0;
880 
881  guid = rom1394_get_guid(item.m_handle, node);
882  item.m_port = port;
883  item.m_node = node;
884  UpdateDeviceListItem(guid, &item);
885  guid_online[guid] = true;
886  }
887 
888  raw1394_destroy_handle(item.m_handle);
889 
890  item.m_handle = raw1394_new_handle();
891  if (!item.m_handle)
892  {
893  LOG(VB_GENERAL, LOG_ERR, QString("LinuxFirewireDevice: ") +
894  "Couldn't get handle " +
895  QString("(after setting port %1").arg(port) + ENO);
896  item.m_handle = nullptr;
897  break;
898  }
899 
900  numcards = raw1394_get_port_info(item.m_handle, port_info.data(),
901  port_info.size());
902  }
903 
904  if (item.m_handle)
905  {
906  raw1394_destroy_handle(item.m_handle);
907  item.m_handle = nullptr;
908  }
909 
910  item.m_port = -1;
911  item.m_node = -1;
912  for (auto it = m_priv->m_devices.begin(); it != m_priv->m_devices.end(); ++it)
913  {
914  if (!guid_online[it.key()])
915  UpdateDeviceListItem(it.key(), &item);
916  }
917 
918  return true;
919 }
920 
921 void LinuxFirewireDevice::UpdateDeviceListItem(uint64_t guid, void *pitem)
922 {
923  avcinfo_list_t::iterator it = m_priv->m_devices.find(guid);
924 
925  if (it == m_priv->m_devices.end())
926  {
927  auto *ptr = new LinuxAVCInfo();
928 
929  LOG(VB_RECORD, LOG_INFO, LOC + QString("Adding 0x%1").arg(guid,0,16));
930 
931  m_priv->m_devices[guid] = ptr;
932  it = m_priv->m_devices.find(guid);
933  }
934 
935  if (it != m_priv->m_devices.end())
936  {
937  dev_item &item = *((dev_item*) pitem);
938  LOG(VB_RECORD, LOG_INFO,
939  LOC + QString("Updating 0x%1 port: %2 node: %3")
940  .arg(guid,0,16).arg(item.m_port).arg(item.m_node));
941 
942  (*it)->Update(guid, item.m_handle, item.m_port, item.m_node);
943  }
944 }
945 
947 {
948  if (!m_priv)
949  return nullptr;
950 
951  avcinfo_list_t::iterator it = m_priv->m_devices.find(m_guid);
952  return (it == m_priv->m_devices.end()) ? nullptr : *it;
953 }
954 
956 {
957  if (!m_priv)
958  return nullptr;
959 
960  avcinfo_list_t::iterator it = m_priv->m_devices.find(m_guid);
961  return (it == m_priv->m_devices.end()) ? nullptr : *it;
962 }
963 
965  unsigned char *tspacket, int len, uint dropped, void *callback_data)
966 {
967  auto *fw = reinterpret_cast<LinuxFirewireDevice*>(callback_data);
968  if (!fw)
969  return 0;
970 
971  if (dropped)
972  fw->PrintDropped(dropped);
973 
974  if (len > 0)
975  fw->BroadcastToListeners(tspacket, len);
976 
977  return 1;
978 }
979 
980 static bool has_data(int fd, int msec)
981 {
982  fd_set rfds;
983  FD_ZERO(&rfds); // NOLINT(readability-isolate-declaration)
984  FD_SET(fd, &rfds);
985 
986  struct timeval tv {};
987  tv.tv_sec = msec / 1000;
988  tv.tv_usec = (msec % 1000) * 1000;
989 
990  int ready = select(fd + 1, &rfds, nullptr, nullptr, &tv);
991 
992  if (ready < 0)
993  LOG(VB_GENERAL, LOG_ERR, "LFireDev: Select Error" + ENO);
994 
995  return ready > 0;
996 }
997 
998 static QString speed_to_string(uint speed)
999 {
1000  if (speed > 3)
1001  return QString("Invalid Speed (%1)").arg(speed);
1002 
1003  static constexpr std::array<const uint,4> kSpeeds { 100, 200, 400, 800 };
1004  return QString("%1Mbps").arg(kSpeeds[speed]);
1005 }
1006 
1008  raw1394handle_t handle, unsigned int generation)
1009 {
1010  QMutexLocker locker(&LFDPriv::s_lock);
1011 
1012  handle_to_lfd_t::iterator it = LFDPriv::s_handle_info.find(handle);
1013 
1014  if (it != LFDPriv::s_handle_info.end())
1015  (*it)->SignalReset(generation);
1016 
1017  return 0;
1018 }
LFDPriv::~LFDPriv
~LFDPriv()
Definition: linuxfirewiredevice.cpp:53
linuxfirewiredevice.h
LinuxAVCInfo::SendAVCCommand
bool SendAVCCommand(const vector< uint8_t > &cmd, vector< uint8_t > &result, int retry_cnt) override
Definition: linuxavcinfo.cpp:66
LFDPriv::m_runPortHandler
bool m_runPortHandler
Definition: linuxfirewiredevice.cpp:70
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:289
ENO
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:72
FirewireDevice::RemoveListener
virtual void RemoveListener(TSDataListener *listener)
Definition: firewiredevice.cpp:49
LFDPriv::m_isPortHandlerRunning
bool m_isPortHandlerRunning
Definition: linuxfirewiredevice.cpp:71
LinuxFirewireDevice::m_useP2P
bool m_useP2P
Definition: linuxfirewiredevice.h:94
LinuxFirewireDevice::CloseP2PNode
bool CloseP2PNode(void)
Definition: linuxfirewiredevice.cpp:441
LinuxFirewireDevice::SignalReset
void SignalReset(uint generation)
Definition: linuxfirewiredevice.cpp:153
LinuxFirewireDevice::GetSTBListPrivate
vector< AVCInfo > GetSTBListPrivate(void)
Definition: linuxfirewiredevice.cpp:812
LinuxFirewireDevice::AddListener
void AddListener(TSDataListener *listener) override
Definition: linuxfirewiredevice.cpp:338
MythTimer
A QElapsedTimer based timer to replace use of QTime as a timer.
Definition: mythtimer.h:14
LinuxFirewireDevice::LinuxFirewireDevice
LinuxFirewireDevice(uint64_t guid, uint subunitid, uint speed, bool use_p2p, uint av_buffer_size_in_bytes=0)
Definition: linuxfirewiredevice.cpp:122
FirewireDevice::m_guid
uint64_t m_guid
Definition: firewiredevice.h:231
LinuxAVCInfo
Definition: linuxavcinfo.h:24
LinuxFirewireDevice::IsAVStreamOpen
bool IsAVStreamOpen(void) const
Definition: linuxfirewiredevice.cpp:761
LinuxFirewireDevice::OpenAVStream
bool OpenAVStream(void)
Definition: linuxfirewiredevice.cpp:522
speed_to_string
static QString speed_to_string(uint speed)
Definition: linuxfirewiredevice.cpp:998
has_data
static bool has_data(int fd, int msec)
Definition: linuxfirewiredevice.cpp:980
LinuxFirewireDevice::OpenP2PNode
bool OpenP2PNode(void)
Definition: linuxfirewiredevice.cpp:407
LinuxFirewireDevice::OpenPort
bool OpenPort(void) override
Definition: linuxfirewiredevice.cpp:229
linux_firewire_device_tspacket_handler
int linux_firewire_device_tspacket_handler(unsigned char *tspacket, int len, uint dropped, void *callback_data)
Definition: linuxfirewiredevice.cpp:964
firewirerecorder.h
arg
arg(title).arg(filename).arg(doDelete))
LinuxFirewireDevice::m_priv
LFDPriv * m_priv
Definition: linuxfirewiredevice.h:95
FirewireDevice::AddListener
virtual void AddListener(TSDataListener *listener)
Definition: firewiredevice.cpp:36
MythTimer::start
void start(void)
starts measuring elapsed time.
Definition: mythtimer.cpp:47
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
LFDPriv::m_bandwidth
int m_bandwidth
Definition: linuxfirewiredevice.cpp:79
LinuxFirewireDevice::GetInfoPtr
LinuxAVCInfo * GetInfoPtr(void)
Definition: linuxfirewiredevice.cpp:946
LinuxFirewireDevice::CloseBroadcastNode
bool CloseBroadcastNode(void)
Definition: linuxfirewiredevice.cpp:508
TSDataListener
Definition: streamlisteners.h:53
LFDPriv::s_handle_info
static handle_to_lfd_t s_handle_info
Definition: linuxfirewiredevice.cpp:91
LinuxFirewireDevice::IsNodeOpen
bool IsNodeOpen(void) const
Definition: linuxfirewiredevice.cpp:756
LOC
#define LOC
Definition: linuxfirewiredevice.cpp:41
LFDPriv::m_channel
int m_channel
Definition: linuxfirewiredevice.cpp:76
LFDPriv::m_isBcastNodeOpen
bool m_isBcastNodeOpen
Definition: linuxfirewiredevice.cpp:83
LinuxFirewireDevice::UpdateDeviceListItem
void UpdateDeviceListItem(uint64_t guid, void *pitem)
Definition: linuxfirewiredevice.cpp:921
LinuxFirewireDevice
Definition: linuxfirewiredevice.h:20
kResetTimeout
#define kResetTimeout
Definition: linuxfirewiredevice.cpp:44
LinuxFirewireDevice::kBroadcastChannel
static const uint kBroadcastChannel
Definition: linuxfirewiredevice.h:48
LFDPriv::s_lock
static QMutex s_lock
Definition: linuxfirewiredevice.cpp:90
FirewireDevice::kAVCSubunitTypeTuner
@ kAVCSubunitTypeTuner
Definition: firewiredevice.h:73
add_handle
static void add_handle(raw1394handle_t handle, LinuxFirewireDevice *dev)
Definition: linuxfirewiredevice.cpp:96
remove_handle
static void remove_handle(raw1394handle_t handle)
Definition: linuxfirewiredevice.cpp:102
LFDPriv::m_portHandlerWait
QWaitCondition m_portHandlerWait
Definition: linuxfirewiredevice.cpp:72
dev_item::m_handle
raw1394handle_t m_handle
Definition: linuxfirewiredevice.cpp:841
mythlogging.h
AVCInfo::GetSubunitInfo
bool GetSubunitInfo(void)
Definition: avcinfo.cpp:42
LinuxFirewireDevice::ClosePort
bool ClosePort(void) override
Definition: linuxfirewiredevice.cpp:289
LinuxFirewireDevice::m_bufsz
uint m_bufsz
Definition: linuxfirewiredevice.h:92
LinuxFirewireDevice::~LinuxFirewireDevice
~LinuxFirewireDevice() override
Definition: linuxfirewiredevice.cpp:137
LinuxFirewireDevice::linux_firewire_device_tspacket_handler
friend int linux_firewire_device_tspacket_handler(unsigned char *tspacket, int len, uint dropped, void *callback_data)
Definition: linuxfirewiredevice.cpp:964
LinuxFirewireDevice::CloseNode
bool CloseNode(void)
Definition: linuxfirewiredevice.cpp:394
LinuxFirewireDevice::m_dbResetDisabled
bool m_dbResetDisabled
Definition: linuxfirewiredevice.h:93
LinuxFirewireDevice::HandleBusReset
void HandleBusReset(void)
Definition: linuxfirewiredevice.cpp:173
LFDPriv::m_devices
avcinfo_list_t m_devices
Definition: linuxfirewiredevice.cpp:88
LinuxFirewireDevice::OpenBroadcastNode
bool OpenBroadcastNode(void)
Definition: linuxfirewiredevice.cpp:467
FirewireDevice::m_listeners
vector< TSDataListener * > m_listeners
Definition: firewiredevice.h:239
LinuxFirewireDevice::SetAVStreamBufferSize
bool SetAVStreamBufferSize(uint size_in_bytes)
Definition: linuxfirewiredevice.cpp:709
LinuxFirewireDevice::StartStreaming
bool StartStreaming(void)
Definition: linuxfirewiredevice.cpp:661
avcinfo_list_t
QMap< uint64_t, DarwinAVCInfo * > avcinfo_list_t
Definition: darwinavcinfo.h:65
LFDPriv::m_startStopPortHandlerLock
QMutex m_startStopPortHandlerLock
Definition: linuxfirewiredevice.cpp:73
linux_firewire_device_port_handler_thunk
void * linux_firewire_device_port_handler_thunk(void *param)
LinuxFirewireDevice::kConnectionP2P
static const uint kConnectionP2P
Definition: linuxfirewiredevice.h:49
LinuxAVCInfo::IsPortOpen
bool IsPortOpen(void) const
Definition: linuxavcinfo.h:39
LinuxFirewireDevice::kMaxBufferedPackets
static const uint kMaxBufferedPackets
Definition: linuxfirewiredevice.h:51
uint
unsigned int uint
Definition: compat.h:140
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:57
LinuxFirewireDevice::StopStreaming
bool StopStreaming(void)
Definition: linuxfirewiredevice.cpp:691
LFDPriv::m_resetTimerOn
bool m_resetTimerOn
Definition: linuxfirewiredevice.cpp:67
LinuxFirewireDevice::run
void run(void) override
Definition: linuxfirewiredevice.cpp:579
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:930
linux_firewire_device_bus_reset_handler
static int linux_firewire_device_bus_reset_handler(raw1394handle_t handle, uint generation)
Definition: linuxfirewiredevice.cpp:1007
LinuxFirewireDevice::CloseAVStream
bool CloseAVStream(void)
Definition: linuxfirewiredevice.cpp:560
LFDPriv::m_noDataCnt
uint m_noDataCnt
Definition: linuxfirewiredevice.cpp:80
LFDPriv::m_avstream
iec61883_mpeg2_t m_avstream
Definition: linuxfirewiredevice.cpp:75
LinuxFirewireDevice::SetAVStreamSpeed
bool SetAVStreamSpeed(uint speed)
Definition: linuxfirewiredevice.cpp:726
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:924
dev_item
Definition: linuxfirewiredevice.cpp:840
dev_item::m_port
int m_port
Definition: linuxfirewiredevice.cpp:842
MythTimer::elapsed
int elapsed(void)
Returns milliseconds elapsed since last start() or restart()
Definition: mythtimer.cpp:90
LinuxAVCInfo::GetNode
int GetNode(void) const
Returns remote node.
Definition: linuxavcinfo.h:42
dev_item::m_node
int m_node
Definition: linuxfirewiredevice.cpp:843
LinuxFirewireDevice::PrintDropped
void PrintDropped(uint dropped_packets)
Definition: linuxfirewiredevice.cpp:787
LinuxFirewireDevice::SendAVCCommand
bool SendAVCCommand(const vector< uint8_t > &cmd, vector< uint8_t > &result, int retry_cnt) override
Definition: linuxfirewiredevice.cpp:366
mythcorecontext.h
LFDPriv::m_isStreaming
bool m_isStreaming
Definition: linuxfirewiredevice.cpp:84
LinuxFirewireDevice::IsPortOpen
bool IsPortOpen(void) const override
Definition: linuxfirewiredevice.cpp:374
LinuxFirewireDevice::kConnectionBroadcast
static const uint kConnectionBroadcast
Definition: linuxfirewiredevice.h:50
LFDPriv::m_generation
uint m_generation
Definition: linuxfirewiredevice.cpp:66
LFDPriv::m_isP2pNodeOpen
bool m_isP2pNodeOpen
Definition: linuxfirewiredevice.cpp:82
FirewireDevice::m_speed
uint m_speed
Definition: firewiredevice.h:233
FirewireDevice::kAVCSubunitTypePanel
@ kAVCSubunitTypePanel
Definition: firewiredevice.h:76
MThread
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:49
handle_to_lfd_t
QHash< raw1394handle_t, LinuxFirewireDevice * > handle_to_lfd_t
Definition: linuxfirewiredevice.cpp:46
LinuxFirewireDevice::ResetBus
bool ResetBus(void) override
Definition: linuxfirewiredevice.cpp:766
kNoDataTimeout
#define kNoDataTimeout
Definition: linuxfirewiredevice.cpp:43
LinuxFirewireDevice::RemoveListener
void RemoveListener(TSDataListener *listener) override
Definition: linuxfirewiredevice.cpp:352
LinuxFirewireDevice::UpdateDeviceList
bool UpdateDeviceList(void)
Definition: linuxfirewiredevice.cpp:846
LFDPriv
Definition: linuxfirewiredevice.cpp:49
LinuxFirewireDevice::GetSTBList
static vector< AVCInfo > GetSTBList(void)
Definition: linuxfirewiredevice.cpp:800
LFDPriv::LFDPriv
LFDPriv()=default
LFDPriv::m_resetTimer
MythTimer m_resetTimer
Definition: linuxfirewiredevice.cpp:68
LFDPriv::m_outputPlug
int m_outputPlug
Definition: linuxfirewiredevice.cpp:77
MThread::wait
bool wait(unsigned long time=ULONG_MAX)
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:306
LinuxFirewireDevice::OpenNode
bool OpenNode(void)
Definition: linuxfirewiredevice.cpp:387
FirewireDevice::m_lock
QMutex m_lock
Definition: firewiredevice.h:240
LFDPriv::m_inputPlug
int m_inputPlug
Definition: linuxfirewiredevice.cpp:78
output
#define output
Definition: synaesthesia.cpp:221
FirewireDevice::m_openPortCnt
uint m_openPortCnt
Definition: firewiredevice.h:238
LFDPriv::m_portHandlerThread
MThread * m_portHandlerThread
Definition: linuxfirewiredevice.cpp:86
FirewireDevice
Definition: firewiredevice.h:25
TSPacket::kSize
static constexpr unsigned int kSize
Definition: tspacket.h:223
linuxavcinfo.h