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>
28#include "libmythbase/mythconfig.h"
35#include <AVCVideoServices/StringLogger.h>
36#include <AVCVideoServices/AVSShared.h>
37#include <AVCVideoServices/MPEG2Receiver.h>
40#define IOMainPort IOMasterPort
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 =
59 bool doIRMAllocations =
false);
63#define LOC QString("DFireDev(%1): ").arg(guid_to_string(m_guid))
65#define kAnyAvailableIsochChannel 0xFFFFFFFF
70 UInt32 tsPacketCount, UInt32 **ppBuf,
void *callback_data);
75 UInt32 param2,
void *callback_data);
123 uint64_t guid,
uint subunitid,
uint speed) :
133 LOG(VB_GENERAL, LOG_ERR,
LOC +
"dtor called with open port");
150 mach_port_t master_port;
151 int ret =
IOMainPort(bootstrap_port, &master_port);
152 if (kIOReturnSuccess == ret)
160 kCFRunLoopDefaultMode);
162 ret = IOServiceAddMatchingNotification(
164 IOServiceMatching(
"IOFireWireAVCUnit"),
168 if (kIOReturnSuccess == ret)
173 if (kIOReturnSuccess == ret)
176 QMutexLocker locker(&
m_lock);
232 QMutexLocker locker(&
m_lock);
234 LOG(VB_RECORD, LOG_INFO,
LOC +
"OpenPort()");
246 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unable to start firewire thread.");
252 LOG(VB_GENERAL, LOG_ERR,
LOC +
"No IEEE-1394 device with our GUID");
258 LOG(VB_RECORD, LOG_INFO,
LOC +
"Opening AVC Device");
264 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"No STB at guid: 0x%1")
274 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unable to get handle for port");
284 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Failed to query local node");
290 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Failed to query remote node");
302 QMutexLocker locker(&
m_lock);
304 LOG(VB_RECORD, LOG_INFO,
LOC +
"ClosePort()");
316 LOG(VB_RECORD, LOG_INFO,
LOC +
"Closing AVC Device");
334 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Max Speed: %1, Our speed: %2")
340 LOG(VB_GENERAL, LOG_INFO,
LOC +
341 QString(
"STB is %1already streaming on fwchan: %2")
342 .arg(streaming?
"":
"not ").arg(fwchan));
353 AVS::kCyclesPerReceiveSegment,
354 AVS::kNumReceiveSegments,
357 if (kIOReturnSuccess != ret)
359 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Couldn't create A/V stream object");
371 IOFireWireLibDeviceRef fw_handle =
GetInfoPtr()->fw_handle;
373 if ((*fw_handle)->version < 4)
376 io_object_t dev = (*fw_handle)->GetDevice(fw_handle);
380 int ret = (*fw_handle)->ReadQuadlet(
381 fw_handle, dev, &addr, (UInt32*) &val,
false, 0);
382 val = EndianU32_BtoN(val);
384 return (ret == kIOReturnSuccess) ? (int)((val>>30) & 0x3) : -1;
387 uint32_t generation = 0;
389 int ret = (*fw_handle)->GetBusGeneration(fw_handle, (UInt32*)&generation);
390 if (kIOReturnSuccess == ret)
392 ret = (*fw_handle)->GetSpeedBetweenNodes(
396 return (ret == kIOReturnSuccess) ? (int)speed : -1;
401 IOFireWireLibDeviceRef fw_handle =
GetInfoPtr()->fw_handle;
402 io_object_t dev = (*fw_handle)->GetDevice(fw_handle);
406 int ret = (*fw_handle)->ReadQuadlet(
407 fw_handle, dev, &addr, (UInt32*) &val,
false, 0);
408 val = EndianU32_BtoN(val);
410 if (ret != kIOReturnSuccess)
413 if (val & (kIOFWPCRBroadcast | kIOFWPCRP2PCount))
416 *fw_channel = (val & kIOFWPCRChannel) >> kIOFWPCRChannelPhase;
431 LOG(VB_RECORD, LOG_INFO,
LOC +
"Destroying A/V stream object");
445 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
"ResetBus() -- begin");
450 IOFireWireLibDeviceRef fw_handle =
GetInfoPtr()->fw_handle;
451 bool ok = (*fw_handle)->BusReset(fw_handle) == kIOReturnSuccess;
454 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bus Reset failed" +
ENO);
456 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
"ResetBus() -- end");
466 LOG(VB_RECORD, LOG_INFO,
LOC +
"Starting A/V streaming");
470 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Starting A/V streaming: FAILED");
480 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Starting A/V streaming: %1")
491 LOG(VB_RECORD, LOG_INFO,
LOC +
"Stopping A/V streaming");
498 LOG(VB_RECORD, LOG_ERR,
LOC +
"Failed to stop A/V streaming");
502 LOG(VB_RECORD, LOG_INFO,
LOC +
"Stopped A/V streaming");
507 std::vector<uint8_t> &result,
510 return GetInfoPtr()->SendAVCCommand(cmd, result, retry_cnt);
515 QMutexLocker locker(&
m_lock);
525 QMutexLocker locker(&
m_lock);
535 QMutexLocker locker(&
m_lock);
547 const unsigned char *data,
uint dataSize)
549 QMutexLocker locker(&
m_lock);
564 LOG(VB_GENERAL, LOG_WARNING,
LOC + QString(
"No Input in %1 msecs")
576 uint32_t msg, uint32_t param1, uint32_t param2)
580 if (AVS::kMpeg2ReceiverAllocateIsochPort == msg)
583 int fw_channel = param2;
586 plug_number, fw_channel, speed,
true,
false);
588 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"AllocateIsochPort(%1,%2) %3")
589 .arg(fw_channel).arg(speed).arg(((ok)?
"ok":
"error")));
591 else if (AVS::kMpeg2ReceiverReleaseIsochPort == msg)
595 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"ReleaseIsochPort %1")
596 .arg((kIOReturnSuccess == ret)?
"ok":
"error"));
598 else if (AVS::kMpeg2ReceiverDCLOverrun == msg)
600 LOG(VB_GENERAL, LOG_ERR,
LOC +
"DCL Overrun");
602 else if (AVS::kMpeg2ReceiverReceivedBadPacket == msg)
604 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Received Bad Packet");
608 LOG(VB_GENERAL, LOG_INFO,
LOC +
609 QString(
"Streaming Message: %1").arg(msg));
615 std::vector<AVCInfo> list;
637 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
"GetSTBListPrivate -- begin");
639 QMutexLocker locker(&
m_lock);
641 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
"GetSTBListPrivate -- got lock");
644 std::vector<AVCInfo> list;
651 list.push_back(*dev);
656 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
"GetSTBListPrivate -- end");
663 QMutexLocker locker(&
m_lock);
669 auto *ptr =
new DarwinAVCInfo();
671 LOG(VB_GENERAL, LOG_INFO,
LOC +
672 QString(
"Adding 0x%1").arg(guid, 0, 16));
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));
702 uint plug_number,
int new_fw_chan,
int new_speed,
703 bool add_plug,
bool remove_plug)
708 IOFireWireLibDeviceRef fw_handle =
GetInfoPtr()->fw_handle;
712 io_object_t dev = (*fw_handle)->GetDevice(fw_handle);
715 uint low_addr = kPCRBaseAddress + 4 + (plug_number << 2);
717 uint32_t old_plug_val;
718 if (kIOReturnSuccess != (*fw_handle)->ReadQuadlet(
719 fw_handle, dev, &addr, (UInt32*) &old_plug_val,
false, 0))
723 old_plug_val = EndianU32_BtoN(old_plug_val);
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;
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))
733 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Invalid Plug Count %1")
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))
741 LOG(VB_GENERAL, LOG_WARNING,
LOC +
742 "Ignoring FWChan change request, plug already open");
744 new_fw_chan = old_fw_chan;
747 new_speed = (new_speed >= 0) ? new_speed : old_speed;
748 if (old_plug_cnt && (new_speed != old_speed))
750 LOG(VB_GENERAL, LOG_WARNING,
LOC +
751 "Ignoring speed change request, plug already open");
753 new_speed = old_speed;
756 uint32_t new_plug_val = old_plug_val;
758 new_plug_val &= ~(0x3f<<24);
759 new_plug_val &= (remove_plug) ? ~kIOFWPCRBroadcast : ~0x0;
760 new_plug_val |= (new_plug_cnt & 0x3f) << 24;
762 new_plug_val &= ~(0x3f<<16);
763 new_plug_val |= (new_fw_chan & 0x3F) << 16;
765 new_plug_val &= ~(0x03<<14);
766 new_plug_val |= (new_speed & 0x03) << 14;
768 old_plug_val = EndianU32_NtoB(old_plug_val);
769 new_plug_val = EndianU32_NtoB(new_plug_val);
771 return (kIOReturnSuccess == (*fw_handle)->CompareSwap(
772 fw_handle, dev, &addr, old_plug_val, new_plug_val,
false, 0));
791 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Reset: Failed to reconnect");
793 LOG(VB_RECORD, LOG_INFO,
LOC +
"Reset: Reconnected succesfully");
797 uint plug_number,
int fw_chan,
int speed,
798 bool add_plug,
bool remove_plug,
uint retry_cnt)
805 for (
uint i = 0; (i < retry_cnt) && !ok; i++)
808 plug_number, fw_chan, speed, add_plug, remove_plug);
818 QString loc =
LOC +
"HandleDeviceChange: ";
820 if (kIOMessageServiceIsTerminated == messageType)
822 LOG(VB_RECORD, LOG_INFO, loc +
"Disconnect");
827 if (kIOMessageServiceIsAttemptingOpen == messageType)
829 LOG(VB_RECORD, LOG_INFO, loc +
"Attempting open");
833 if (kIOMessageServiceWasClosed == messageType)
835 LOG(VB_RECORD, LOG_INFO, loc +
"Device Closed");
840 if (kIOMessageServiceIsSuspended == messageType)
842 LOG(VB_RECORD, LOG_INFO, loc +
"kIOMessageServiceIsSuspended");
847 if (kIOMessageServiceIsResumed == messageType)
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");
889 LOG(VB_RECORD, LOG_ERR, loc + QString(
"unknown message 0x%1")
890 .arg(messageType, 0, 16));
913 ProcessNoDataMessage();
915 return kIOReturnSuccess;
919 UInt32 param2,
void *callback_data)
922 ProcessStreamingMessage(msg, param1, param2);
930 return kIOReturnBadArgument;
932 for (uint32_t i = 0; i < tsPacketCount; ++i)
935 return kIOReturnSuccess;
939 UInt32 tsPacketCount, UInt32 **ppBuf,
void *callback_data)
942 tsPacketCount, (uint32_t**)ppBuf, callback_data);
950 while ((it = IOIteratorNext(deviter)))
954 CFMutableDictionaryRef props;
955 int ret = IORegistryEntryCreateCFProperties(
956 it, &props, kCFAllocatorDefault, kNilOptions);
958 if (kIOReturnSuccess == ret)
960 auto GUIDDesc = (CFNumberRef)
961 CFDictionaryGetValue(props, CFSTR(
"GUID"));
962 CFNumberGetValue(GUIDDesc, kCFNumberSInt64Type, &guid);
971 LOG(VB_RECORD, LOG_INFO, QString(
"MPEG2Receiver: %1").arg(msg));
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
pthread_t m_controller_thread
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)
void ProcessNoDataMessage(void)
void HandleBusReset(void)
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 StartStreaming(void)
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)
void StartController(void)
void StopController(void)
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.
static void ThreadSetup(const QString &name)
This is to be called on startup in those few threads that haven't been ported to MThread.
A QElapsedTimer based timer to replace use of QTime as a timer.
std::chrono::milliseconds elapsed(void)
Returns milliseconds elapsed since last start() or restart()
void start(void)
starts measuring elapsed time.
#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 "+".
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
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)