MythTV  master
darwinfirewiredevice.cpp
Go to the documentation of this file.
1 
9 // POSIX headers
10 #include <pthread.h>
11 
12 // OS X headers
13 #undef always_inline
14 #include <IOKit/IOMessage.h>
15 #include <IOKit/IOKitLib.h>
16 #include <IOKit/firewire/IOFireWireLib.h>
17 #include <IOKit/firewire/IOFireWireLibIsoch.h>
18 #include <IOKit/firewire/IOFireWireFamilyCommon.h>
19 #include <IOKit/avc/IOFireWireAVCLib.h>
20 #include <CoreServices/CoreServices.h> // for EndianU32_BtoN() etc.
21 
22 // Std C++ headers
23 #include <algorithm>
24 #include <vector>
25 using namespace std;
26 
27 // MythTV headers
28 #include "darwinfirewiredevice.h"
29 #include "darwinavcinfo.h"
30 #include "mythlogging.h"
31 #include "mthread.h"
32 #include "mythtimer.h"
33 
34 // Apple Firewire example headers
35 #include <AVCVideoServices/StringLogger.h>
36 #include <AVCVideoServices/AVSShared.h>
37 #include <AVCVideoServices/MPEG2Receiver.h>
38 
39 // header not used because it also requires MPEG2Transmitter.h
40 //#include <AVCVideoServices/FireWireMPEG.h>
41 namespace AVS
42 {
43  IOReturn CreateMPEG2Receiver(
44  MPEG2Receiver **ppReceiver,
45  DataPushProc dataPushProcHandler,
46  void *pDataPushProcRefCon = nil,
47  MPEG2ReceiverMessageProc messageProcHandler = nil,
48  void *pMessageProcRefCon = nil,
49  StringLogger *stringLogger = nil,
50  IOFireWireLibNubRef nubInterface = nil,
51  unsigned int cyclesPerSegment =
52  kCyclesPerReceiveSegment,
53  unsigned int numSegments =
54  kNumReceiveSegments,
55  bool doIRMAllocations = false);
56  IOReturn DestroyMPEG2Receiver(MPEG2Receiver *pReceiver);
57 }
58 
59 #define LOC QString("DFireDev(%1): ").arg(guid_to_string(m_guid))
60 
61 #define kAnyAvailableIsochChannel 0xFFFFFFFF
62 #define kNoDataTimeout 300 /* msec */
63 #define kResetTimeout 1500 /* msec */
64 
65 static IOReturn dfd_tspacket_handler_thunk(
66  UInt32 tsPacketCount, UInt32 **ppBuf, void *callback_data);
67 static void dfd_update_device_list(void *dfd, io_iterator_t deviter);
68 static void dfd_streaming_log_message(char *msg);
69 void *dfd_controller_thunk(void *callback_data);
70 void dfd_stream_msg(UInt32 msg, UInt32 param1,
71  UInt32 param2, void *callback_data);
72 int dfd_no_data_notification(void *callback_data);
73 
74 class DFDPriv
75 {
76 private:
77  DFDPriv(const DFDPriv &) = delete; // not copyable
78  DFDPriv &operator=(const DFDPriv &) = delete; // not copyable
79 
80  public:
82  {
83  m_logger = new AVS::StringLogger(dfd_streaming_log_message);
84  }
85 
87  {
88  for (auto dev : qAsConst(m_devices))
89  delete dev;
90  m_devices.clear();
91 
92  if (m_logger)
93  {
94  delete m_logger;
95  m_logger = nullptr;
96  }
97  }
98 
99  pthread_t m_controller_thread {nullptr};
100  CFRunLoopRef m_controller_thread_cf_ref {nullptr};
101  bool m_controller_thread_running {false};
102 
103  IONotificationPortRef m_notify_port {nullptr};
104  CFRunLoopSourceRef m_notify_source {nullptr};
105  io_iterator_t m_deviter {0};
106 
107  int m_actual_fwchan {-1};
108  bool m_is_streaming {false};
109  AVS::MPEG2Receiver *m_avstream {nullptr};
110  AVS::StringLogger *m_logger {nullptr};
111  uint m_no_data_cnt {0};
112  bool m_no_data_timer_set {false};
114 
116 };
117 
119  uint64_t guid, uint subunitid, uint speed) :
120  FirewireDevice(guid, subunitid, speed),
121  m_priv(new DFDPriv())
122 {
123 }
124 
126 {
127  if (IsPortOpen())
128  {
129  LOG(VB_GENERAL, LOG_ERR, LOC + "dtor called with open port");
130  while (IsPortOpen())
131  ClosePort();
132  }
133 
134  if (m_priv)
135  {
136  delete m_priv;
137  m_priv = nullptr;
138  }
139 }
140 
142 {
143  m_priv->m_controller_thread_cf_ref = CFRunLoopGetCurrent();
144 
145  // Set up IEEE-1394 bus change notification
146  mach_port_t master_port;
147  int ret = IOMasterPort(bootstrap_port, &master_port);
148  if (kIOReturnSuccess == ret)
149  {
150  m_priv->m_notify_port = IONotificationPortCreate(master_port);
151  m_priv->m_notify_source = IONotificationPortGetRunLoopSource(
153 
154  CFRunLoopAddSource(m_priv->m_controller_thread_cf_ref,
156  kCFRunLoopDefaultMode);
157 
158  ret = IOServiceAddMatchingNotification(
159  m_priv->m_notify_port, kIOMatchedNotification,
160  IOServiceMatching("IOFireWireAVCUnit"),
162  }
163 
164  if (kIOReturnSuccess == ret)
166 
168 
169  if (kIOReturnSuccess == ret)
170  CFRunLoopRun();
171 
172  QMutexLocker locker(&m_lock); // ensure that controller_thread_running seen
173 
175 }
176 
178 {
179  m_lock.unlock();
180 
181  pthread_create(&m_priv->m_controller_thread, nullptr,
182  dfd_controller_thunk, this);
183 
184  m_lock.lock();
186  {
187  m_lock.unlock();
188  usleep(5000);
189  m_lock.lock();
190  }
191 }
192 
194 {
196  return;
197 
198  if (m_priv->m_deviter)
199  {
200  IOObjectRelease(m_priv->m_deviter);
201  m_priv->m_deviter = 0;
202  }
203 
204  if (m_priv->m_notify_source)
205  {
206  CFRunLoopSourceInvalidate(m_priv->m_notify_source);
207  m_priv->m_notify_source = nullptr;
208  }
209 
210  if (m_priv->m_notify_port)
211  {
212  IONotificationPortDestroy(m_priv->m_notify_port);
213  m_priv->m_notify_port = nullptr;
214  }
215 
216  CFRunLoopStop(m_priv->m_controller_thread_cf_ref);
217 
219  {
220  m_lock.unlock();
221  usleep(100 * 1000);
222  m_lock.lock();
223  }
224 }
225 
227 {
228  QMutexLocker locker(&m_lock);
229 
230  LOG(VB_RECORD, LOG_INFO, LOC + "OpenPort()");
231 
232  if (GetInfoPtr() && GetInfoPtr()->IsPortOpen())
233  {
234  m_open_port_cnt++;
235  return true;
236  }
237 
238  StartController();
239 
241  {
242  LOG(VB_GENERAL, LOG_ERR, LOC + "Unable to start firewire thread.");
243  return false;
244  }
245 
246  if (!GetInfoPtr())
247  {
248  LOG(VB_GENERAL, LOG_ERR, LOC + "No IEEE-1394 device with our GUID");
249 
250  StopController();
251  return false;
252  }
253 
254  LOG(VB_RECORD, LOG_INFO, LOC + "Opening AVC Device");
255  LOG(VB_RECORD, LOG_INFO, LOC + GetInfoPtr()->GetSubunitInfoString());
256 
257  if (!GetInfoPtr()->IsSubunitType(kAVCSubunitTypeTuner) ||
258  !GetInfoPtr()->IsSubunitType(kAVCSubunitTypePanel))
259  {
260  LOG(VB_GENERAL, LOG_ERR, LOC + QString("No STB at guid: 0x%1")
261  .arg(m_guid,0,16));
262 
263  StopController();
264  return false;
265  }
266 
268  if (!ok)
269  {
270  LOG(VB_GENERAL, LOG_ERR, LOC + "Unable to get handle for port");
271 
272  return false;
273  }
274 
275  // TODO FIXME -- these can change after a reset... (at least local)
276  if (!GetInfoPtr()->GetDeviceNodes(m_local_node, m_remote_node))
277  {
278  if (m_local_node < 0)
279  {
280  LOG(VB_GENERAL, LOG_WARNING, LOC + "Failed to query local node");
281  m_local_node = 0;
282  }
283 
284  if (m_remote_node < 0)
285  {
286  LOG(VB_GENERAL, LOG_WARNING, LOC + "Failed to query remote node");
287  m_remote_node = 0;
288  }
289  }
290 
291  m_open_port_cnt++;
292 
293  return true;
294 }
295 
297 {
298  QMutexLocker locker(&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() && GetInfoPtr()->IsPortOpen())
311  {
312  LOG(VB_RECORD, LOG_INFO, LOC + "Closing AVC Device");
313 
314  GetInfoPtr()->ClosePort();
315  }
316 
317  StopController();
318  m_local_node = -1;
319  m_remote_node = -1;
320 
321  return true;
322 }
323 
325 {
326  if (IsAVStreamOpen())
327  return true;
328 
329  int max_speed = GetMaxSpeed();
330  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Max Speed: %1, Our speed: %2")
331  .arg(max_speed).arg(m_speed));
332  m_speed = min((uint)max_speed, m_speed);
333 
334  uint fwchan = 0;
335  bool streaming = IsSTBStreaming(&fwchan);
336  LOG(VB_GENERAL, LOG_INFO, LOC +
337  QString("STB is %1already streaming on fwchan: %2")
338  .arg(streaming?"":"not ").arg(fwchan));
339 
340  // TODO we should use the stream if it already exists,
341  // this is especially true if it is a broadcast stream...
342 
343  int ret = AVS::CreateMPEG2Receiver(
344  &m_priv->m_avstream,
346  dfd_stream_msg, this,
347  m_priv->m_logger /* StringLogger */,
348  GetInfoPtr()->fw_handle,
349  AVS::kCyclesPerReceiveSegment,
350  AVS::kNumReceiveSegments,
351  true /* p2p */);
352 
353  if (kIOReturnSuccess != ret)
354  {
355  LOG(VB_GENERAL, LOG_ERR, LOC + "Couldn't create A/V stream object");
356  return false;
357  }
358 
359  m_priv->m_avstream->registerNoDataNotificationCallback(
361 
362  return true;
363 }
364 
366 {
367  IOFireWireLibDeviceRef fw_handle = GetInfoPtr()->fw_handle;
368 
369  if ((*fw_handle)->version < 4)
370  {
371  // Just get the STB's info & assume we can handle it
372  io_object_t dev = (*fw_handle)->GetDevice(fw_handle);
373 
374  FWAddress addr(0xffff, 0xf0000900, m_remote_node);
375  uint32_t val;
376  int ret = (*fw_handle)->ReadQuadlet(
377  fw_handle, dev, &addr, (UInt32*) &val, false, 0);
378  val = EndianU32_BtoN(val);
379 
380  return (ret == kIOReturnSuccess) ? (int)((val>>30) & 0x3) : -1;
381  }
382 
383  uint32_t generation = 0;
384  IOFWSpeed speed;
385  int ret = (*fw_handle)->GetBusGeneration(fw_handle, (UInt32*)&generation);
386  if (kIOReturnSuccess == ret)
387  {
388  ret = (*fw_handle)->GetSpeedBetweenNodes(
389  fw_handle, generation, m_remote_node, m_local_node, &speed) ;
390  }
391 
392  return (ret == kIOReturnSuccess) ? (int)speed : -1;
393 }
394 
396 {
397  IOFireWireLibDeviceRef fw_handle = GetInfoPtr()->fw_handle;
398  io_object_t dev = (*fw_handle)->GetDevice(fw_handle);
399 
400  FWAddress addr(0xffff, 0xf0000904, m_remote_node);
401  uint32_t val;
402  int ret = (*fw_handle)->ReadQuadlet(
403  fw_handle, dev, &addr, (UInt32*) &val, false, 0);
404  val = EndianU32_BtoN(val);
405 
406  if (ret != kIOReturnSuccess)
407  return false;
408 
409  if (val & (kIOFWPCRBroadcast | kIOFWPCRP2PCount))
410  {
411  if (fw_channel)
412  *fw_channel = (val & kIOFWPCRChannel) >> kIOFWPCRChannelPhase;
413 
414  return true;
415  }
416 
417  return false;
418 }
419 
421 {
422  if (!m_priv->m_avstream)
423  return true;
424 
425  StopStreaming();
426 
427  LOG(VB_RECORD, LOG_INFO, LOC + "Destroying A/V stream object");
429  m_priv->m_avstream = nullptr;
430 
431  return true;
432 }
433 
435 {
436  return m_priv->m_avstream;
437 }
438 
440 {
441  LOG(VB_GENERAL, LOG_DEBUG, LOC + "ResetBus() -- begin");
442 
443  if (!GetInfoPtr() || !GetInfoPtr()->fw_handle)
444  return false;
445 
446  IOFireWireLibDeviceRef fw_handle = GetInfoPtr()->fw_handle;
447  bool ok = (*fw_handle)->BusReset(fw_handle) == kIOReturnSuccess;
448 
449  if (!ok)
450  LOG(VB_GENERAL, LOG_ERR, LOC + "Bus Reset failed" + ENO);
451 
452  LOG(VB_GENERAL, LOG_DEBUG, LOC + "ResetBus() -- end");
453 
454  return ok;
455 }
456 
458 {
459  if (m_priv->m_is_streaming)
460  return m_priv->m_is_streaming;
461 
462  LOG(VB_RECORD, LOG_INFO, LOC + "Starting A/V streaming");
463 
464  if (!IsAVStreamOpen() && !OpenAVStream())
465  {
466  LOG(VB_GENERAL, LOG_ERR, LOC + "Starting A/V streaming: FAILED");
467  return false;
468  }
469 
470  m_priv->m_avstream->setReceiveIsochChannel(kAnyAvailableIsochChannel);
471  m_priv->m_avstream->setReceiveIsochSpeed((IOFWSpeed) m_speed);
472  int ret = m_priv->m_avstream->startReceive();
473 
474  m_priv->m_is_streaming = (kIOReturnSuccess == ret);
475 
476  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Starting A/V streaming: %1")
477  .arg((m_priv->m_is_streaming)?"success":"failure"));
478 
479  return m_priv->m_is_streaming;
480 }
481 
483 {
484  if (!m_priv->m_is_streaming)
485  return true;
486 
487  LOG(VB_RECORD, LOG_INFO, LOC + "Stopping A/V streaming");
488 
489  bool ok = (kIOReturnSuccess == m_priv->m_avstream->stopReceive());
490  m_priv->m_is_streaming = !ok;
491 
492  if (!ok)
493  {
494  LOG(VB_RECORD, LOG_ERR, LOC + "Failed to stop A/V streaming");
495  return false;
496  }
497 
498  LOG(VB_RECORD, LOG_INFO, LOC + "Stopped A/V streaming");
499  return true;
500 }
501 
502 bool DarwinFirewireDevice::SendAVCCommand(const vector<uint8_t> &cmd,
503  vector<uint8_t> &result,
504  int retry_cnt)
505 {
506  return GetInfoPtr()->SendAVCCommand(cmd, result, retry_cnt);
507 }
508 
510 {
511  QMutexLocker locker(&m_lock);
512 
513  if (!GetInfoPtr())
514  return false;
515 
516  return GetInfoPtr()->IsPortOpen();
517 }
518 
520 {
521  QMutexLocker locker(&m_lock);
522 
523  FirewireDevice::AddListener(listener);
524 
525  if (!m_listeners.empty())
526  StartStreaming();
527 }
528 
530 {
531  QMutexLocker locker(&m_lock);
532 
534 
535  if (m_priv->m_is_streaming && m_listeners.empty())
536  {
537  StopStreaming();
538  CloseAVStream();
539  }
540 }
541 
543  const unsigned char *data, uint dataSize)
544 {
545  QMutexLocker locker(&m_lock);
546  FirewireDevice::BroadcastToListeners(data, dataSize);
547 }
548 
550 {
552  {
553  int short_interval = kNoDataTimeout + (kNoDataTimeout>>1);
554  bool recent = m_priv->m_no_data_timer.elapsed() <= short_interval;
555  m_priv->m_no_data_cnt = (recent) ? m_priv->m_no_data_cnt + 1 : 1;
556  }
557  m_priv->m_no_data_timer_set = true;
559 
560  LOG(VB_GENERAL, LOG_WARNING, LOC + QString("No Input in %1 msecs")
562 
564  {
565  m_priv->m_no_data_timer_set = false;
566  m_priv->m_no_data_cnt = 0;
567  ResetBus();
568  }
569 }
570 
572  uint32_t msg, uint32_t param1, uint32_t param2)
573 {
574  int plug_number = 0;
575 
576  if (AVS::kMpeg2ReceiverAllocateIsochPort == msg)
577  {
578  int speed = param1;
579  int fw_channel = param2;
580 
581  bool ok = UpdatePlugRegister(
582  plug_number, fw_channel, speed, true, false);
583 
584  LOG(VB_GENERAL, LOG_INFO, LOC + QString("AllocateIsochPort(%1,%2) %3")
585  .arg(fw_channel).arg(speed).arg(((ok)?"ok":"error")));
586  }
587  else if (AVS::kMpeg2ReceiverReleaseIsochPort == msg)
588  {
589  int ret = UpdatePlugRegister(plug_number, -1, -1, false, true);
590 
591  LOG(VB_GENERAL, LOG_INFO, LOC + QString("ReleaseIsochPort %1")
592  .arg((kIOReturnSuccess == ret)?"ok":"error"));
593  }
594  else if (AVS::kMpeg2ReceiverDCLOverrun == msg)
595  {
596  LOG(VB_GENERAL, LOG_ERR, LOC + "DCL Overrun");
597  }
598  else if (AVS::kMpeg2ReceiverReceivedBadPacket == msg)
599  {
600  LOG(VB_GENERAL, LOG_ERR, LOC + "Received Bad Packet");
601  }
602  else
603  {
604  LOG(VB_GENERAL, LOG_INFO, LOC +
605  QString("Streaming Message: %1").arg(msg));
606  }
607 }
608 
609 vector<AVCInfo> DarwinFirewireDevice::GetSTBList(void)
610 {
611  vector<AVCInfo> list;
612 
613  {
614  DarwinFirewireDevice dev(0,0,0);
615 
616  dev.m_lock.lock();
617  dev.StartController();
618  dev.m_lock.unlock();
619 
620  list = dev.GetSTBListPrivate();
621 
622  dev.m_lock.lock();
623  dev.StopController();
624  dev.m_lock.unlock();
625  }
626 
627  return list;
628 }
629 
631 {
632 #if 0
633  LOG(VB_GENERAL, LOG_DEBUG, LOC + "GetSTBListPrivate -- begin");
634 #endif
635  QMutexLocker locker(&m_lock);
636 #if 0
637  LOG(VB_GENERAL, LOG_DEBUG, LOC + "GetSTBListPrivate -- got lock");
638 #endif
639 
640  vector<AVCInfo> list;
641 
642  for (auto dev : qAsConst(m_priv->m_devices))
643  {
644  if (dev->IsSubunitType(kAVCSubunitTypeTuner) &&
645  dev->IsSubunitType(kAVCSubunitTypePanel))
646  {
647  list.push_back(*dev);
648  }
649  }
650 
651 #if 0
652  LOG(VB_GENERAL, LOG_DEBUG, LOC + "GetSTBListPrivate -- end");
653 #endif
654  return list;
655 }
656 
657 void DarwinFirewireDevice::UpdateDeviceListItem(uint64_t guid, void *pitem)
658 {
659  QMutexLocker locker(&m_lock);
660 
661  avcinfo_list_t::iterator it = m_priv->m_devices.find(guid);
662 
663  if (it == m_priv->m_devices.end())
664  {
665  auto *ptr = new DarwinAVCInfo();
666 
667  LOG(VB_GENERAL, LOG_INFO, LOC +
668  QString("Adding 0x%1").arg(guid, 0, 16));
669 
670  m_priv->m_devices[guid] = ptr;
671  it = m_priv->m_devices.find(guid);
672  }
673 
674  if (it != m_priv->m_devices.end())
675  {
676  io_object_t &item = *((io_object_t*) pitem);
677  LOG(VB_GENERAL, LOG_INFO, LOC +
678  QString("Updating 0x%1").arg(guid, 0, 16));
679  (*it)->Update(guid, this, m_priv->m_notify_port,
681  }
682 }
683 
685 {
686  avcinfo_list_t::iterator it = m_priv->m_devices.find(m_guid);
687  return (it == m_priv->m_devices.end()) ? nullptr : *it;
688 }
689 
691 {
692  avcinfo_list_t::iterator it = m_priv->m_devices.find(m_guid);
693  return (it == m_priv->m_devices.end()) ? nullptr : *it;
694 }
695 
696 
698  uint plug_number, int new_fw_chan, int new_speed,
699  bool add_plug, bool remove_plug)
700 {
701  if (!GetInfoPtr())
702  return false;
703 
704  IOFireWireLibDeviceRef fw_handle = GetInfoPtr()->fw_handle;
705  if (!fw_handle)
706  return false;
707 
708  io_object_t dev = (*fw_handle)->GetDevice(fw_handle);
709 
710  // Read the register
711  uint low_addr = kPCRBaseAddress + 4 + (plug_number << 2);
712  FWAddress addr(0xffff, low_addr, m_remote_node);
713  uint32_t old_plug_val;
714  if (kIOReturnSuccess != (*fw_handle)->ReadQuadlet(
715  fw_handle, dev, &addr, (UInt32*) &old_plug_val, false, 0))
716  {
717  return false;
718  }
719  old_plug_val = EndianU32_BtoN(old_plug_val);
720 
721  int old_plug_cnt = (old_plug_val >> 24) & 0x3f;
722  int old_fw_chan = (old_plug_val >> 16) & 0x3f;
723  int old_speed = (old_plug_val >> 14) & 0x03;
724 
725  int new_plug_cnt = (int) old_plug_cnt;
726  new_plug_cnt += ((add_plug) ? 1 : 0) - ((remove_plug) ? 1 : 0);
727  if ((new_plug_cnt > 0x3f) || (new_plug_cnt < 0))
728  {
729  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Invalid Plug Count %1")
730  .arg(new_plug_cnt));
731  return false;
732  }
733 
734  new_fw_chan = (new_fw_chan >= 0) ? new_fw_chan : old_fw_chan;
735  if (old_plug_cnt && (new_fw_chan != old_fw_chan))
736  {
737  LOG(VB_GENERAL, LOG_WARNING, LOC +
738  "Ignoring FWChan change request, plug already open");
739 
740  new_fw_chan = old_fw_chan;
741  }
742 
743  new_speed = (new_speed >= 0) ? new_speed : old_speed;
744  if (old_plug_cnt && (new_speed != old_speed))
745  {
746  LOG(VB_GENERAL, LOG_WARNING, LOC +
747  "Ignoring speed change request, plug already open");
748 
749  new_speed = old_speed;
750  }
751 
752  uint32_t new_plug_val = old_plug_val;
753 
754  new_plug_val &= ~(0x3f<<24);
755  new_plug_val &= (remove_plug) ? ~kIOFWPCRBroadcast : ~0x0;
756  new_plug_val |= (new_plug_cnt & 0x3f) << 24;
757 
758  new_plug_val &= ~(0x3f<<16);
759  new_plug_val |= (new_fw_chan & 0x3F) << 16;
760 
761  new_plug_val &= ~(0x03<<14);
762  new_plug_val |= (new_speed & 0x03) << 14;
763 
764  old_plug_val = EndianU32_NtoB(old_plug_val);
765  new_plug_val = EndianU32_NtoB(new_plug_val);
766 
767  return (kIOReturnSuccess == (*fw_handle)->CompareSwap(
768  fw_handle, dev, &addr, old_plug_val, new_plug_val, false, 0));
769 }
770 
772 {
773  int plug_number = 0;
774  if (!GetInfoPtr())
775  return;
776 
777  int fw_channel = m_priv->m_actual_fwchan;
778  bool ok = UpdatePlugRegister(plug_number, fw_channel,
779  m_speed, true, false);
780  if (!ok)
781  {
783  m_speed, true, false);
784  }
785 
786  if (!ok)
787  LOG(VB_GENERAL, LOG_ERR, LOC + "Reset: Failed to reconnect");
788  else
789  LOG(VB_RECORD, LOG_INFO, LOC + "Reset: Reconnected succesfully");
790 }
791 
793  uint plug_number, int fw_chan, int speed,
794  bool add_plug, bool remove_plug, uint retry_cnt)
795 {
796  if (!GetInfoPtr() || !GetInfoPtr()->fw_handle)
797  return false;
798 
799  bool ok = false;
800 
801  for (uint i = 0; (i < retry_cnt) && !ok; i++)
802  {
804  plug_number, fw_chan, speed, add_plug, remove_plug);
805  }
806 
808 
809  return ok;
810 }
811 
813 {
814  QString loc = LOC + "HandleDeviceChange: ";
815 
816  if (kIOMessageServiceIsTerminated == messageType)
817  {
818  LOG(VB_RECORD, LOG_INFO, loc + "Disconnect");
819  // stop printing no data messages.. don't try to open
820  return;
821  }
822 
823  if (kIOMessageServiceIsAttemptingOpen == messageType)
824  {
825  LOG(VB_RECORD, LOG_INFO, loc + "Attempting open");
826  return;
827  }
828 
829  if (kIOMessageServiceWasClosed == messageType)
830  {
831  LOG(VB_RECORD, LOG_INFO, loc + "Device Closed");
832  // fill unit_table
833  return;
834  }
835 
836  if (kIOMessageServiceIsSuspended == messageType)
837  {
838  LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageServiceIsSuspended");
839  // start of reset
840  return;
841  }
842 
843  if (kIOMessageServiceIsResumed == messageType)
844  {
845  // end of reset
846  HandleBusReset();
847  }
848 
849  if (kIOMessageServiceIsTerminated == messageType)
850  LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageServiceIsTerminated");
851  else if (kIOMessageServiceIsRequestingClose == messageType)
852  LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageServiceIsRequestingClose");
853  else if (kIOMessageServiceIsAttemptingOpen == messageType)
854  LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageServiceIsAttemptingOpen");
855  else if (kIOMessageServiceWasClosed == messageType)
856  LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageServiceWasClosed");
857  else if (kIOMessageServiceBusyStateChange == messageType)
858  LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageServiceBusyStateChange");
859  else if (kIOMessageCanDevicePowerOff == messageType)
860  LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageCanDevicePowerOff");
861  else if (kIOMessageDeviceWillPowerOff == messageType)
862  LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageDeviceWillPowerOff");
863  else if (kIOMessageDeviceWillNotPowerOff == messageType)
864  LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageDeviceWillNotPowerOff");
865  else if (kIOMessageDeviceHasPoweredOn == messageType)
866  LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageDeviceHasPoweredOn");
867  else if (kIOMessageCanSystemPowerOff == messageType)
868  LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageCanSystemPowerOff");
869  else if (kIOMessageSystemWillPowerOff == messageType)
870  LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageSystemWillPowerOff");
871  else if (kIOMessageSystemWillNotPowerOff == messageType)
872  LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageSystemWillNotPowerOff");
873  else if (kIOMessageCanSystemSleep == messageType)
874  LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageCanSystemSleep");
875  else if (kIOMessageSystemWillSleep == messageType)
876  LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageSystemWillSleep");
877  else if (kIOMessageSystemWillNotSleep == messageType)
878  LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageSystemWillNotSleep");
879  else if (kIOMessageSystemHasPoweredOn == messageType)
880  LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageSystemHasPoweredOn");
881  else if (kIOMessageSystemWillRestart == messageType)
882  LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageSystemWillRestart");
883  else
884  {
885  LOG(VB_RECORD, LOG_ERR, loc + QString("unknown message 0x%1")
886  .arg(messageType, 0, 16));
887  }
888 }
889 
890 // Various message callbacks.
891 
892 void *dfd_controller_thunk(void *callback_data)
893 {
894  MThread::ThreadSetup("DarwinController");
895  reinterpret_cast<DarwinFirewireDevice*>(callback_data)->RunController();
897  return nullptr;
898 }
899 
901  DarwinFirewireDevice *dev, uint64_t guid, void *item)
902 {
903  dev->UpdateDeviceListItem(guid, item);
904 }
905 
906 int dfd_no_data_notification(void *callback_data)
907 {
908  reinterpret_cast<DarwinFirewireDevice*>(callback_data)->
909  ProcessNoDataMessage();
910 
911  return kIOReturnSuccess;
912 }
913 
914 void dfd_stream_msg(UInt32 msg, UInt32 param1,
915  UInt32 param2, void *callback_data)
916 {
917  reinterpret_cast<DarwinFirewireDevice*>(callback_data)->
918  ProcessStreamingMessage(msg, param1, param2);
919 }
920 
921 int dfd_tspacket_handler(uint tsPacketCount, uint32_t **ppBuf,
922  void *callback_data)
923 {
924  auto *fw = reinterpret_cast<DarwinFirewireDevice*>(callback_data);
925  if (!fw)
926  return kIOReturnBadArgument;
927 
928  for (uint32_t i = 0; i < tsPacketCount; ++i)
929  fw->BroadcastToListeners((const unsigned char*) ppBuf[i], 188);
930 
931  return kIOReturnSuccess;
932 }
933 
935  UInt32 tsPacketCount, UInt32 **ppBuf, void *callback_data)
936 {
937  return dfd_tspacket_handler(
938  tsPacketCount, (uint32_t**)ppBuf, callback_data);
939 }
940 
941 static void dfd_update_device_list(void *dfd, io_iterator_t deviter)
942 {
943  auto *dev = reinterpret_cast<DarwinFirewireDevice*>(dfd);
944 
945  io_object_t it = 0;
946  while ((it = IOIteratorNext(deviter)))
947  {
948  uint64_t guid = 0;
949 
950  CFMutableDictionaryRef props;
951  int ret = IORegistryEntryCreateCFProperties(
952  it, &props, kCFAllocatorDefault, kNilOptions);
953 
954  if (kIOReturnSuccess == ret)
955  {
956  auto GUIDDesc = (CFNumberRef)
957  CFDictionaryGetValue(props, CFSTR("GUID"));
958  CFNumberGetValue(GUIDDesc, kCFNumberSInt64Type, &guid);
959  CFRelease(props);
960  dfd_update_device_list_item(dev, guid, &it);
961  }
962  }
963 }
964 
965 static void dfd_streaming_log_message(char *msg)
966 {
967  LOG(VB_RECORD, LOG_INFO, QString("MPEG2Receiver: %1").arg(msg));
968 }
void dfd_update_device_list_item(DarwinFirewireDevice *dev, uint64_t guid, void *item)
bool ClosePort(void) override
#define kResetTimeout
static void dfd_streaming_log_message(char *msg)
A QElapsedTimer based timer to replace use of QTime as a timer.
Definition: mythtimer.h:13
bool IsAVStreamOpen(void) const
bool UpdatePlugRegisterPrivate(uint plug_number, int fw_chan, int new_speed, bool add_plug, bool remove_plug)
virtual void RemoveListener(TSDataListener *listener)
bool IsPortOpen(void) const
Definition: darwinavcinfo.h:52
vector< AVCInfo > GetSTBListPrivate(void)
static void ThreadSetup(const QString &name)
This is to be called on startup in those few threads that haven't been ported to MThread.
Definition: mthread.cpp:227
void dfd_stream_msg(UInt32 msg, UInt32 param1, UInt32 param2, void *callback_data)
int dfd_no_data_notification(void *callback_data)
IOFireWireLibDeviceRef fw_handle
Definition: darwinavcinfo.h:63
IOReturn CreateMPEG2Receiver(MPEG2Receiver **ppReceiver, DataPushProc dataPushProcHandler, void *pDataPushProcRefCon=nil, MPEG2ReceiverMessageProc messageProcHandler=nil, void *pMessageProcRefCon=nil, StringLogger *stringLogger=nil, IOFireWireLibNubRef nubInterface=nil, unsigned int cyclesPerSegment=kCyclesPerReceiveSegment, unsigned int numSegments=kNumReceiveSegments, bool doIRMAllocations=false)
static void dfd_update_device_list(void *dfd, io_iterator_t deviter)
#define LOC
friend void dfd_stream_msg(UInt32 msg, UInt32 param1, UInt32 param2, void *callback_data)
avcinfo_list_t m_devices
IONotificationPortRef m_notify_port
void HandleDeviceChange(uint messageType)
io_iterator_t m_deviter
virtual void AddListener(TSDataListener *listener)
void * dfd_controller_thunk(void *callback_data)
void AddListener(TSDataListener *) override
friend int dfd_no_data_notification(void *callback_data)
bool IsSTBStreaming(uint *fw_channel=nullptr)
CFRunLoopSourceRef m_notify_source
bool OpenPort(CFRunLoopRef &thread_cf_ref)
vector< TSDataListener * > m_listeners
pthread_t m_controller_thread
bool m_controller_thread_running
AVS::MPEG2Receiver * m_avstream
int dfd_tspacket_handler(uint tsPacketCount, uint32_t **ppBuf, void *callback_data)
unsigned int uint
Definition: compat.h:140
static void ThreadCleanup(void)
This is to be called on exit in those few threads that haven't been ported to MThread.
Definition: mthread.cpp:237
bool ResetBus(void) override
DarwinAVCInfo * GetInfoPtr(void)
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:72
CFRunLoopRef m_controller_thread_cf_ref
bool UpdatePlugRegister(uint plug_number, int fw_chan, int speed, bool add_plug, bool remove_plug, uint retry_cnt=4)
static IOReturn dfd_tspacket_handler_thunk(UInt32 tsPacketCount, UInt32 **ppBuf, void *callback_data)
QMap< uint64_t, DarwinAVCInfo * > avcinfo_list_t
Definition: darwinavcinfo.h:65
bool SendAVCCommand(const vector< uint8_t > &cmd, vector< uint8_t > &result, int) override
bool OpenPort(void) override
void ProcessStreamingMessage(uint32_t msg, uint32_t param1, uint32_t param2)
bool ClosePort(void)
MythTimer m_no_data_timer
static int x0
Definition: mythsocket.cpp:59
void UpdateDeviceListItem(uint64_t guid, void *item)
static vector< AVCInfo > GetSTBList(void)
int elapsed(void)
Returns milliseconds elapsed since last start() or restart()
Definition: mythtimer.cpp:90
void RemoveListener(TSDataListener *) override
virtual void BroadcastToListeners(const unsigned char *data, uint dataSize)
bool SendAVCCommand(const vector< uint8_t > &cmd, vector< uint8_t > &result, int retry_cnt) override
bool IsPortOpen(void) const override
void BroadcastToListeners(const unsigned char *data, uint dataSize) override
IOReturn DestroyMPEG2Receiver(MPEG2Receiver *pReceiver)
#define kNoDataTimeout
DarwinFirewireDevice(uint64_t guid, uint subunitid, uint speed)
AVS::StringLogger * m_logger
#define kAnyAvailableIsochChannel
friend void * dfd_controller_thunk(void *callback_data)
void start(void)
starts measuring elapsed time.
Definition: mythtimer.cpp:47
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23