11#include <sys/select.h>
16#include <libraw1394/raw1394.h>
17#include <libraw1394/csr.h>
18#include <libiec61883/iec61883.h>
19#include <libavc1394/avc1394.h>
20#include <libavc1394/rom1394.h>
22#include <netinet/in.h>
42#define LOC QString("LFireDev(%1): ").arg(guid_to_string(m_guid))
56 for (
const auto & device : std::as_const(
m_devices))
116 unsigned char *tspacket,
int len,
uint dropped,
void *callback_data);
118static bool has_data(
int fd, std::chrono::milliseconds msec);
121 raw1394handle_t handle,
uint generation);
124 uint64_t guid,
uint subunitid,
125 uint speed,
bool use_p2p,
uint av_buffer_size_in_bytes) :
127 m_bufsz(av_buffer_size_in_bytes),
128 m_useP2P(use_p2p), m_priv(new
LFDPriv())
142 LOG(VB_GENERAL, LOG_ERR,
LOC +
"ctor called with open port");
156 const QString loc =
LOC + QString(
"SignalReset(%1->%2)")
159 LOG(VB_GENERAL, LOG_INFO, loc);
162 raw1394_update_generation(
GetInfoPtr()->m_fwHandle, generation);
166 LOG(VB_GENERAL, LOG_INFO, loc +
": Updating device list -- begin");
168 LOG(VB_GENERAL, LOG_INFO, loc +
": Updating device list -- end");
176 const QString loc =
LOC +
"HandleBusReset";
183 LOG(VB_GENERAL, LOG_INFO, loc +
": Reconnecting P2P connection");
185 nodeid_t input = raw1394_get_local_id(
GetInfoPtr()->m_fwHandle);
187 int fwchan = iec61883_cmp_reconnect(
195 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bus Reset: Failed to reconnect");
199 LOG(VB_GENERAL, LOG_WARNING,
LOC + QString(
"FWChan changed %1->%2")
204 LOG(VB_GENERAL, LOG_INFO,
205 loc + QString(
": Reconnected fwchan: %1\n\t\t\toutput: 0x%2 "
207 .arg(fwchan).arg(
output,0,16).arg(input,0,16));
214 LOG(VB_RECORD, LOG_INFO, loc +
": Restarting broadcast connection on " +
215 QString(
"node %1, channel %2")
218 int err = iec61883_cmp_create_bcast_output(
225 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bus Reset : Failed to reconnect");
232 LOG(VB_RECORD, LOG_INFO,
LOC +
"Starting Port Handler Thread");
234 LOG(VB_RECORD, LOG_INFO,
LOC +
"Starting Port Handler Thread -- locked");
236 LOG(VB_RECORD, LOG_INFO,
LOC +
"OpenPort()");
238 QMutexLocker mlocker(&
m_lock);
240 LOG(VB_RECORD, LOG_INFO,
LOC +
"OpenPort() -- got lock");
257 raw1394_set_bus_reset_handler(
266 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Not an STB"));
276 LOG(VB_RECORD, LOG_INFO,
LOC +
"Starting port handler thread");
283 LOG(VB_RECORD, LOG_INFO,
LOC +
"Port handler thread started");
292 LOG(VB_RECORD, LOG_INFO,
LOC +
"Stopping Port Handler Thread");
294 LOG(VB_RECORD, LOG_INFO,
LOC +
"Stopping Port Handler Thread -- locked");
296 QMutexLocker mlocker(&
m_lock);
298 LOG(VB_RECORD, LOG_INFO,
LOC +
"ClosePort()");
316 LOG(VB_RECORD, LOG_INFO,
317 LOC +
"Waiting for port handler thread to stop");
328 LOG(VB_RECORD, LOG_INFO,
LOC +
"Joined port handler thread");
341 QMutexLocker locker(&
m_lock);
355 QMutexLocker locker(&
m_lock);
368 const std::vector<uint8_t> &cmd,
369 std::vector<uint8_t> &result,
372 return GetInfoPtr()->SendAVCCommand(cmd, result, retry_cnt);
377 QMutexLocker locker(&
m_lock);
416 LOG(VB_RECORD, LOG_INFO,
LOC +
"Opening P2P connection");
422 nodeid_t input = raw1394_get_local_id(
GetInfoPtr()->m_fwHandle);
430 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to create P2P connection");
446 LOG(VB_RECORD, LOG_INFO,
LOC +
"Closing P2P connection");
452 nodeid_t input = raw1394_get_local_id(
GetInfoPtr()->m_fwHandle);
454 iec61883_cmp_disconnect(
GetInfoPtr()->m_fwHandle,
484 LOG(VB_RECORD, LOG_INFO,
LOC +
"Opening broadcast connection on " +
485 QString(
"node %1, channel %2")
488 int err = iec61883_cmp_create_bcast_output(
495 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to create Broadcast connection");
513 LOG(VB_RECORD, LOG_INFO,
LOC +
"Closing broadcast connection");
525 LOG(VB_RECORD, LOG_INFO,
LOC +
"OpenAVStream");
529 LOG(VB_GENERAL, LOG_ERR,
LOC +
530 "Cannot open AVStream without open IEEE 1394 port");
541 LOG(VB_RECORD, LOG_INFO,
LOC +
"Opening A/V stream object");
548 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unable to open AVStream" +
ENO);
566 LOG(VB_RECORD, LOG_INFO,
LOC +
"Closing A/V stream object");
582 LOG(VB_RECORD, LOG_INFO,
LOC +
"RunPortHandler -- start");
584 LOG(VB_RECORD, LOG_INFO,
LOC +
"RunPortHandler -- got first lock");
589 std::this_thread::sleep_for(2500us);
597 bool handle_reset = reset_timer_on &&
613 int fwfd = raw1394_get_fd(
GetInfoPtr()->m_fwHandle);
636 LOG(VB_GENERAL, LOG_WARNING,
LOC + QString(
"No Input in %1 msec...")
648 int ret = raw1394_loop_iterate(
GetInfoPtr()->m_fwHandle);
651 LOG(VB_GENERAL, LOG_ERR,
LOC +
"raw1394_loop_iterate" +
ENO);
659 LOG(VB_RECORD, LOG_INFO,
LOC +
"RunPortHandler -- end");
672 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Starting A/V streaming, no channel");
676 LOG(VB_RECORD, LOG_INFO,
LOC +
"Starting A/V streaming -- really");
684 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Starting A/V streaming " +
ENO);
687 LOG(VB_RECORD, LOG_INFO,
LOC +
"Starting A/V streaming -- done");
696 LOG(VB_RECORD, LOG_INFO,
LOC +
"Stopping A/V streaming -- really");
702 raw1394_iso_recv_flush(
GetInfoPtr()->m_fwHandle);
705 LOG(VB_RECORD, LOG_INFO,
LOC +
"Stopped A/V streaming");
721 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Buffered packets %1 (%2 KB)")
722 .arg(buffered_packets).arg(buffered_packets * 4));
734 if (curspeed == speed)
740 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"Changing Speed %1 -> %2")
752 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Unable to set firewire speed.");
769 LOG(VB_GENERAL, LOG_INFO,
LOC +
"ResetBus() -- begin");
773 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Bus Reset disabled" +
ENO);
774 LOG(VB_GENERAL, LOG_INFO,
LOC +
"ResetBus() -- end");
778 bool ok = (raw1394_reset_bus_new(
GetInfoPtr()->m_fwHandle,
779 RAW1394_LONG_RESET) == 0);
781 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bus Reset failed" +
ENO);
783 LOG(VB_GENERAL, LOG_INFO,
LOC +
"ResetBus() -- end");
790 if (dropped_packets == 1)
792 LOG(VB_RECORD, LOG_ERR,
LOC +
"Dropped a TS packet");
794 else if (dropped_packets > 1)
796 LOG(VB_RECORD, LOG_ERR,
LOC + QString(
"Dropped %1 TS packets")
797 .arg(dropped_packets));
803 std::vector<AVCInfo> list;
816 LOG(VB_GENERAL, LOG_DEBUG,
"GetSTBListPrivate -- begin");
818 QMutexLocker locker(&
m_lock);
820 LOG(VB_GENERAL, LOG_DEBUG,
"GetSTBListPrivate -- got lock");
823 std::vector<AVCInfo> list;
830 list.push_back(*device);
835 LOG(VB_GENERAL, LOG_DEBUG,
"GetSTBListPrivate -- end");
851 item.
m_handle = raw1394_new_handle();
854 LOG(VB_GENERAL, LOG_ERR, QString(
"LinuxFirewireDevice: ") +
855 "Couldn't get handle" +
ENO);
859 std::array<raw1394_portinfo,16> port_info {};
860 int numcards = raw1394_get_port_info(item.m_handle, port_info.data(),
864 raw1394_destroy_handle(item.m_handle);
868 std::map<uint64_t,bool> guid_online;
869 for (
int port = 0; port < numcards; port++)
871 if (raw1394_set_port(item.m_handle, port) < 0)
873 LOG(VB_GENERAL, LOG_ERR, QString(
"LinuxFirewireDevice: "
874 "Couldn't set port to %1").arg(port));
878 for (
int node = 0; node < raw1394_get_nodecount(item.m_handle); node++)
882 guid = rom1394_get_guid(item.m_handle, node);
886 guid_online[guid] =
true;
889 raw1394_destroy_handle(item.m_handle);
891 item.m_handle = raw1394_new_handle();
894 LOG(VB_GENERAL, LOG_ERR, QString(
"LinuxFirewireDevice: ") +
895 "Couldn't get handle " +
896 QString(
"(after setting port %1").arg(port) +
ENO);
897 item.m_handle =
nullptr;
901 numcards = raw1394_get_port_info(item.m_handle, port_info.data(),
907 raw1394_destroy_handle(item.m_handle);
908 item.m_handle =
nullptr;
915 if (!guid_online[it.key()])
928 auto *ptr =
new LinuxAVCInfo();
930 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"Adding 0x%1").arg(guid,0,16));
939 LOG(VB_RECORD, LOG_INFO,
940 LOC + QString(
"Updating 0x%1 port: %2 node: %3")
966 unsigned char *tspacket,
int len,
uint dropped,
void *callback_data)
976 fw->BroadcastToListeners(tspacket, len);
981static bool has_data(
int fd, std::chrono::milliseconds msec)
987 struct timeval tv {};
988 tv.tv_sec = msec.count() / 1000;
989 tv.tv_usec = (msec.count() % 1000) * 1000;
991 int ready = select(fd + 1, &rfds,
nullptr,
nullptr, &tv);
994 LOG(VB_GENERAL, LOG_ERR,
"LFireDev: Select Error" +
ENO);
1002 return QString(
"Invalid Speed (%1)").arg(speed);
1004 static constexpr std::array<const uint,4> kSpeeds { 100, 200, 400, 800 };
1005 return QString(
"%1Mbps").arg(kSpeeds[speed]);
1009 raw1394handle_t handle,
unsigned int generation)
1016 (*it)->SignalReset(generation);
virtual void AddListener(TSDataListener *listener)
virtual void RemoveListener(TSDataListener *listener)
std::vector< TSDataListener * > m_listeners
MThread * m_portHandlerThread
QWaitCondition m_portHandlerWait
static handle_to_lfd_t s_handle_info
QMutex m_startStopPortHandlerLock
iec61883_mpeg2_t m_avstream
bool m_isPortHandlerRunning
bool IsNodeOpen(void) const
LinuxFirewireDevice(uint64_t guid, uint subunitid, uint speed, bool use_p2p, uint av_buffer_size_in_bytes=0)
bool ResetBus(void) override
void RemoveListener(TSDataListener *listener) override
static const uint kBroadcastChannel
LinuxAVCInfo * GetInfoPtr(void)
bool SetAVStreamSpeed(uint speed)
friend int linux_firewire_device_tspacket_handler(unsigned char *tspacket, int len, uint dropped, void *callback_data)
~LinuxFirewireDevice() override
static const uint kConnectionBroadcast
bool SendAVCCommand(const std::vector< uint8_t > &cmd, std::vector< uint8_t > &result, int retry_cnt) override
bool UpdateDeviceList(void)
bool OpenBroadcastNode(void)
void HandleBusReset(void)
bool ClosePort(void) override
void PrintDropped(uint dropped_packets)
bool OpenPort(void) override
bool IsAVStreamOpen(void) const
void AddListener(TSDataListener *listener) override
void SignalReset(uint generation)
bool IsPortOpen(void) const override
void UpdateDeviceListItem(uint64_t guid, void *pitem)
static const uint kConnectionP2P
static const uint kMaxBufferedPackets
bool SetAVStreamBufferSize(uint size_in_bytes)
static std::vector< AVCInfo > GetSTBList(void)
std::vector< AVCInfo > GetSTBListPrivate(void)
bool CloseBroadcastNode(void)
bool StartStreaming(void)
This is a wrapper around QThread that does several additional things.
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
int GetNumSetting(const QString &key, int defaultval=0)
bool GetBoolSetting(const QString &key, bool defaultval=false)
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.
static constexpr unsigned int kSize
#define LOC
LinuxFirewireDevice Copyright (c) 2005 by Jim Westfall Copyright (c) 2006 by Daniel Kristjansson SA32...
static void remove_handle(raw1394handle_t handle)
static constexpr std::chrono::milliseconds kNoDataTimeout
void * linux_firewire_device_port_handler_thunk(void *param)
static QString speed_to_string(uint speed)
static bool has_data(int fd, std::chrono::milliseconds msec)
int linux_firewire_device_tspacket_handler(unsigned char *tspacket, int len, uint dropped, void *callback_data)
static void add_handle(raw1394handle_t handle, LinuxFirewireDevice *dev)
static int linux_firewire_device_bus_reset_handler(raw1394handle_t handle, uint generation)
static constexpr std::chrono::milliseconds kResetTimeout
QHash< raw1394handle_t, LinuxFirewireDevice * > handle_to_lfd_t
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define ENO
This can be appended to the LOG args with "+".
#define LOG(_MASK_, _LEVEL_, _QSTRING_)