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 iterator);
68 static void dfd_streaming_log_message(char *pString);
69 void *dfd_controller_thunk(void *param);
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  foreach (auto dev, 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 {0};
100  CFRunLoopRef m_controller_thread_cf_ref {nullptr};
101  bool m_controller_thread_running {false};
102 
103  IONotificationPortRef m_notify_port {0};
104  CFRunLoopSourceRef m_notify_source {0};
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, 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 vector<AVCInfo> DarwinFirewireDevice::GetSTBList(void)
609 {
610  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 
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  vector<AVCInfo> list;
640 
641  foreach (auto dev, 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  DarwinAVCInfo *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 {
924  reinterpret_cast<DarwinFirewireDevice*>(callback_data);
925 
926  if (!fw)
927  return kIOReturnBadArgument;
928 
929  for (uint32_t i = 0; i < tsPacketCount; ++i)
930  fw->BroadcastToListeners((const unsigned char*) ppBuf[i], 188);
931 
932  return kIOReturnSuccess;
933 }
934 
936  UInt32 tsPacketCount, UInt32 **ppBuf, void *callback_data)
937 {
938  return dfd_tspacket_handler(
939  tsPacketCount, (uint32_t**)ppBuf, callback_data);
940 }
941 
942 static void dfd_update_device_list(void *dfd, io_iterator_t deviter)
943 {
944  DarwinFirewireDevice *dev = reinterpret_cast<DarwinFirewireDevice*>(dfd);
945 
946  io_object_t it = 0;
947  while ((it = IOIteratorNext(deviter)))
948  {
949  uint64_t guid = 0;
950 
951  CFMutableDictionaryRef props;
952  int ret = IORegistryEntryCreateCFProperties(
953  it, &props, kCFAllocatorDefault, kNilOptions);
954 
955  if (kIOReturnSuccess == ret)
956  {
957  CFNumberRef GUIDDesc = (CFNumberRef)
958  CFDictionaryGetValue(props, CFSTR("GUID"));
959  CFNumberGetValue(GUIDDesc, kCFNumberSInt64Type, &guid);
960  CFRelease(props);
961  dfd_update_device_list_item(dev, guid, &it);
962  }
963  }
964 }
965 
966 static void dfd_streaming_log_message(char *msg)
967 {
968  LOG(VB_RECORD, LOG_INFO, QString("MPEG2Receiver: %1").arg(msg));
969 }
void dfd_update_device_list_item(DarwinFirewireDevice *dev, uint64_t guid, void *item)
bool ClosePort(void) override
#define kResetTimeout
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)
static void dfd_update_device_list(void *dfd, io_iterator_t iterator)
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)
friend void * dfd_controller_thunk(void *param)
#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 AddListener(TSDataListener *) override
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
void * dfd_controller_thunk(void *param)
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:99
friend int dfd_no_data_notification(void *cb_data)
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)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
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
static void dfd_streaming_log_message(char *pString)
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
void start(void)
starts measuring elapsed time.
Definition: mythtimer.cpp:47