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