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