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  public:
78  {
79  logger = new AVS::StringLogger(dfd_streaming_log_message);
80  }
81 
83  {
84  avcinfo_list_t::iterator it = devices.begin();
85  for (; it != devices.end(); ++it)
86  delete (*it);
87  devices.clear();
88 
89  if (logger)
90  {
91  delete logger;
92  logger = nullptr;
93  }
94  }
95 
96  pthread_t controller_thread{0};
97  CFRunLoopRef controller_thread_cf_ref {nullptr};
98  bool controller_thread_running {false};
99 
100  IONotificationPortRef notify_port {0};
101  CFRunLoopSourceRef notify_source {0};
102  io_iterator_t deviter {0};
103 
104  int actual_fwchan {-1};
105  bool is_streaming {false};
106  AVS::MPEG2Receiver *avstream {nullptr};
107  AVS::StringLogger *logger {nullptr};
108  uint no_data_cnt {0};
109  bool no_data_timer_set {false};
111 
113 };
114 
116  uint64_t guid, uint subunitid, uint speed) :
117  FirewireDevice(guid, subunitid, speed),
118  m_local_node(-1), m_remote_node(-1), m_priv(new DFDPriv())
119 {
120 
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->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->notify_port = IONotificationPortCreate(master_port);
150  m_priv->notify_source = IONotificationPortGetRunLoopSource(
152 
153  CFRunLoopAddSource(m_priv->controller_thread_cf_ref,
155  kCFRunLoopDefaultMode);
156 
157  ret = IOServiceAddMatchingNotification(
158  m_priv->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->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->deviter)
198  {
199  IOObjectRelease(m_priv->deviter);
200  m_priv->deviter = 0;
201  }
202 
203  if (m_priv->notify_source)
204  {
205  CFRunLoopSourceInvalidate(m_priv->notify_source);
206  m_priv->notify_source = nullptr;
207  }
208 
209  if (m_priv->notify_port)
210  {
211  IONotificationPortDestroy(m_priv->notify_port);
212  m_priv->notify_port = nullptr;
213  }
214 
215  CFRunLoopStop(m_priv->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_open_port_cnt++;
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_open_port_cnt++;
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_open_port_cnt < 1)
302  return false;
303 
304  m_open_port_cnt--;
305 
306  if (m_open_port_cnt != 0)
307  return true;
308 
309  if (GetInfoPtr() && 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 = 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->avstream,
345  dfd_stream_msg, this,
346  m_priv->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->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->avstream)
422  return true;
423 
424  StopStreaming();
425 
426  LOG(VB_RECORD, LOG_INFO, LOC + "Destroying A/V stream object");
428  m_priv->avstream = nullptr;
429 
430  return true;
431 }
432 
434 {
435  return m_priv->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->is_streaming)
459  return m_priv->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->avstream->setReceiveIsochChannel(kAnyAvailableIsochChannel);
470  m_priv->avstream->setReceiveIsochSpeed((IOFWSpeed) m_speed);
471  int ret = m_priv->avstream->startReceive();
472 
473  m_priv->is_streaming = (kIOReturnSuccess == ret);
474 
475  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Starting A/V streaming: %1")
476  .arg((m_priv->is_streaming)?"success":"failure"));
477 
478  return m_priv->is_streaming;
479 }
480 
482 {
483  if (!m_priv->is_streaming)
484  return true;
485 
486  LOG(VB_RECORD, LOG_INFO, LOC + "Stopping A/V streaming");
487 
488  bool ok = (kIOReturnSuccess == m_priv->avstream->stopReceive());
489  m_priv->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 vector<uint8_t> &cmd,
502  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->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  int short_interval = kNoDataTimeout + (kNoDataTimeout>>1);
553  bool recent = m_priv->no_data_timer.elapsed() <= short_interval;
554  m_priv->no_data_cnt = (recent) ? m_priv->no_data_cnt + 1 : 1;
555  }
556  m_priv->no_data_timer_set = true;
558 
559  LOG(VB_GENERAL, LOG_WARNING, LOC + QString("No Input in %1 msecs")
561 
563  {
564  m_priv->no_data_timer_set = false;
565  m_priv->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, fw_channel = param2;
578 
579  bool ok = UpdatePlugRegister(
580  plug_number, fw_channel, speed, true, false);
581 
582  LOG(VB_GENERAL, LOG_INFO, LOC + QString("AllocateIsochPort(%1,%2) %3")
583  .arg(fw_channel).arg(speed).arg(((ok)?"ok":"error")));
584  }
585  else if (AVS::kMpeg2ReceiverReleaseIsochPort == msg)
586  {
587  int ret = UpdatePlugRegister(plug_number, -1, -1, false, true);
588 
589  LOG(VB_GENERAL, LOG_INFO, LOC + QString("ReleaseIsochPort %1")
590  .arg((kIOReturnSuccess == ret)?"ok":"error"));
591  }
592  else if (AVS::kMpeg2ReceiverDCLOverrun == msg)
593  {
594  LOG(VB_GENERAL, LOG_ERR, LOC + "DCL Overrun");
595  }
596  else if (AVS::kMpeg2ReceiverReceivedBadPacket == msg)
597  {
598  LOG(VB_GENERAL, LOG_ERR, LOC + "Received Bad Packet");
599  }
600  else
601  {
602  LOG(VB_GENERAL, LOG_INFO, LOC +
603  QString("Streaming Message: %1").arg(msg));
604  }
605 }
606 
607 vector<AVCInfo> DarwinFirewireDevice::GetSTBList(void)
608 {
609  vector<AVCInfo> list;
610 
611  {
612  DarwinFirewireDevice dev(0,0,0);
613 
614  dev.m_lock.lock();
615  dev.StartController();
616  dev.m_lock.unlock();
617 
618  list = dev.GetSTBListPrivate();
619 
620  dev.m_lock.lock();
621  dev.StopController();
622  dev.m_lock.unlock();
623  }
624 
625  return list;
626 }
627 
629 {
630 #if 0
631  LOG(VB_GENERAL, LOG_DEBUG, LOC + "GetSTBListPrivate -- begin");
632 #endif
633  QMutexLocker locker(&m_lock);
634 #if 0
635  LOG(VB_GENERAL, LOG_DEBUG, LOC + "GetSTBListPrivate -- got lock");
636 #endif
637 
638  vector<AVCInfo> list;
639 
640  avcinfo_list_t::iterator it = m_priv->devices.begin();
641  for (; it != m_priv->devices.end(); ++it)
642  {
643  if ((*it)->IsSubunitType(kAVCSubunitTypeTuner) &&
644  (*it)->IsSubunitType(kAVCSubunitTypePanel))
645  {
646  list.push_back(*(*it));
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->devices.find(guid);
661 
662  if (it == m_priv->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->devices[guid] = ptr;
670  it = m_priv->devices.find(guid);
671  }
672 
673  io_object_t &item = *((io_object_t*) pitem);
674  if (it != m_priv->devices.end())
675  {
676  LOG(VB_GENERAL, LOG_INFO, LOC +
677  QString("Updating 0x%1").arg(guid, 0, 16));
678  (*it)->Update(guid, this, m_priv->notify_port,
680  }
681 }
682 
684 {
685  avcinfo_list_t::iterator it = m_priv->devices.find(m_guid);
686  return (it == m_priv->devices.end()) ? nullptr : *it;
687 }
688 
690 {
691  avcinfo_list_t::iterator it = m_priv->devices.find(m_guid);
692  return (it == m_priv->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->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 
806  m_priv->actual_fwchan = (ok) ? fw_chan : kAnyAvailableIsochChannel;
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 }
MythTimer no_data_timer
void dfd_update_device_list_item(DarwinFirewireDevice *dev, uint64_t guid, void *item)
bool ClosePort(void) override
QMap< uint64_t, DarwinAVCInfo * > avcinfo_list_t
Definition: darwinavcinfo.h:69
#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)
bool IsPortOpen(void) const
Definition: darwinavcinfo.h:56
vector< AVCInfo > GetSTBListPrivate(void)
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:67
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)
unsigned int uint
Definition: compat.h:140
IONotificationPortRef notify_port
CFRunLoopSourceRef notify_source
AVS::StringLogger * logger
CFRunLoopRef controller_thread_cf_ref
void HandleDeviceChange(uint messageType)
avcinfo_list_t devices
void AddListener(TSDataListener *) override
bool IsSTBStreaming(uint *fw_channel=nullptr)
bool OpenPort(CFRunLoopRef &thread_cf_ref)
vector< TSDataListener * > m_listeners
void * dfd_controller_thunk(void *param)
int dfd_tspacket_handler(uint tsPacketCount, uint32_t **ppBuf, void *callback_data)
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:238
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)
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)
int elapsed(void) const
Returns milliseconds elapsed since last start() or restart()
Definition: mythtimer.cpp:90
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)
static int x0
Definition: mythsocket.cpp:59
void UpdateDeviceListItem(uint64_t guid, void *item)
virtual void RemoveListener(TSDataListener *)
static vector< AVCInfo > GetSTBList(void)
AVS::MPEG2Receiver * avstream
static void dfd_streaming_log_message(char *pString)
void RemoveListener(TSDataListener *) override
virtual void BroadcastToListeners(const unsigned char *data, uint dataSize)
io_iterator_t deviter
bool SendAVCCommand(const vector< uint8_t > &cmd, vector< uint8_t > &result, int retry_cnt) override
static void ThreadSetup(const QString &)
This is to be called on startup in those few threads that haven't been ported to MThread.
Definition: mthread.cpp:228
bool IsPortOpen(void) const override
void BroadcastToListeners(const unsigned char *data, uint dataSize)
static void logger(cdio_log_level_t level, const char message[])
Definition: cddecoder.cpp:37
IOReturn DestroyMPEG2Receiver(MPEG2Receiver *pReceiver)
bool controller_thread_running
#define kNoDataTimeout
DarwinFirewireDevice(uint64_t guid, uint subunitid, uint speed)
virtual void AddListener(TSDataListener *)
#define kAnyAvailableIsochChannel
pthread_t controller_thread
void start(void)
starts measuring elapsed time.
Definition: mythtimer.cpp:47