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