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