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