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