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>
41#define LOC QString("LFireDev(%1): ").arg(guid_to_string(m_guid))
55 for (
const auto & device : std::as_const(
m_devices))
115 unsigned char *tspacket,
int len,
uint dropped,
void *callback_data);
117static bool has_data(
int fd, std::chrono::milliseconds msec);
120 raw1394handle_t handle,
uint generation);
123 uint64_t guid,
uint subunitid,
124 uint speed,
bool use_p2p,
uint av_buffer_size_in_bytes) :
126 m_bufsz(av_buffer_size_in_bytes),
127 m_useP2P(use_p2p), m_priv(new
LFDPriv())
141 LOG(VB_GENERAL, LOG_ERR,
LOC +
"ctor called with open port");
155 const QString loc =
LOC + QString(
"SignalReset(%1->%2)")
158 LOG(VB_GENERAL, LOG_INFO, loc);
161 raw1394_update_generation(
GetInfoPtr()->m_fwHandle, generation);
165 LOG(VB_GENERAL, LOG_INFO, loc +
": Updating device list -- begin");
167 LOG(VB_GENERAL, LOG_INFO, loc +
": Updating device list -- end");
175 const QString loc =
LOC +
"HandleBusReset";
182 LOG(VB_GENERAL, LOG_INFO, loc +
": Reconnecting P2P connection");
184 nodeid_t input = raw1394_get_local_id(
GetInfoPtr()->m_fwHandle);
186 int fwchan = iec61883_cmp_reconnect(
194 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bus Reset: Failed to reconnect");
198 LOG(VB_GENERAL, LOG_WARNING,
LOC + QString(
"FWChan changed %1->%2")
203 LOG(VB_GENERAL, LOG_INFO,
204 loc + QString(
": Reconnected fwchan: %1\n\t\t\toutput: 0x%2 "
206 .arg(fwchan).arg(
output,0,16).arg(input,0,16));
213 LOG(VB_RECORD, LOG_INFO, loc +
": Restarting broadcast connection on " +
214 QString(
"node %1, channel %2")
217 int err = iec61883_cmp_create_bcast_output(
224 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bus Reset : Failed to reconnect");
231 LOG(VB_RECORD, LOG_INFO,
LOC +
"Starting Port Handler Thread");
233 LOG(VB_RECORD, LOG_INFO,
LOC +
"Starting Port Handler Thread -- locked");
235 LOG(VB_RECORD, LOG_INFO,
LOC +
"OpenPort()");
237 QMutexLocker mlocker(&
m_lock);
239 LOG(VB_RECORD, LOG_INFO,
LOC +
"OpenPort() -- got lock");
256 raw1394_set_bus_reset_handler(
265 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Not an STB"));
275 LOG(VB_RECORD, LOG_INFO,
LOC +
"Starting port handler thread");
282 LOG(VB_RECORD, LOG_INFO,
LOC +
"Port handler thread started");
291 LOG(VB_RECORD, LOG_INFO,
LOC +
"Stopping Port Handler Thread");
293 LOG(VB_RECORD, LOG_INFO,
LOC +
"Stopping Port Handler Thread -- locked");
295 QMutexLocker mlocker(&
m_lock);
297 LOG(VB_RECORD, LOG_INFO,
LOC +
"ClosePort()");
315 LOG(VB_RECORD, LOG_INFO,
316 LOC +
"Waiting for port handler thread to stop");
327 LOG(VB_RECORD, LOG_INFO,
LOC +
"Joined port handler thread");
340 QMutexLocker locker(&
m_lock);
354 QMutexLocker locker(&
m_lock);
367 const std::vector<uint8_t> &cmd,
368 std::vector<uint8_t> &result,
371 return GetInfoPtr()->SendAVCCommand(cmd, result, retry_cnt);
376 QMutexLocker locker(&
m_lock);
415 LOG(VB_RECORD, LOG_INFO,
LOC +
"Opening P2P connection");
421 nodeid_t input = raw1394_get_local_id(
GetInfoPtr()->m_fwHandle);
429 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to create P2P connection");
445 LOG(VB_RECORD, LOG_INFO,
LOC +
"Closing P2P connection");
451 nodeid_t input = raw1394_get_local_id(
GetInfoPtr()->m_fwHandle);
453 iec61883_cmp_disconnect(
GetInfoPtr()->m_fwHandle,
483 LOG(VB_RECORD, LOG_INFO,
LOC +
"Opening broadcast connection on " +
484 QString(
"node %1, channel %2")
487 int err = iec61883_cmp_create_bcast_output(
494 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to create Broadcast connection");
512 LOG(VB_RECORD, LOG_INFO,
LOC +
"Closing broadcast connection");
524 LOG(VB_RECORD, LOG_INFO,
LOC +
"OpenAVStream");
528 LOG(VB_GENERAL, LOG_ERR,
LOC +
529 "Cannot open AVStream without open IEEE 1394 port");
540 LOG(VB_RECORD, LOG_INFO,
LOC +
"Opening A/V stream object");
547 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unable to open AVStream" +
ENO);
565 LOG(VB_RECORD, LOG_INFO,
LOC +
"Closing A/V stream object");
581 LOG(VB_RECORD, LOG_INFO,
LOC +
"RunPortHandler -- start");
583 LOG(VB_RECORD, LOG_INFO,
LOC +
"RunPortHandler -- got first lock");
588 std::this_thread::sleep_for(2500us);
596 bool handle_reset = reset_timer_on &&
612 int fwfd = raw1394_get_fd(
GetInfoPtr()->m_fwHandle);
635 LOG(VB_GENERAL, LOG_WARNING,
LOC + QString(
"No Input in %1 msec...")
647 int ret = raw1394_loop_iterate(
GetInfoPtr()->m_fwHandle);
650 LOG(VB_GENERAL, LOG_ERR,
LOC +
"raw1394_loop_iterate" +
ENO);
658 LOG(VB_RECORD, LOG_INFO,
LOC +
"RunPortHandler -- end");
671 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Starting A/V streaming, no channel");
675 LOG(VB_RECORD, LOG_INFO,
LOC +
"Starting A/V streaming -- really");
683 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Starting A/V streaming " +
ENO);
686 LOG(VB_RECORD, LOG_INFO,
LOC +
"Starting A/V streaming -- done");
695 LOG(VB_RECORD, LOG_INFO,
LOC +
"Stopping A/V streaming -- really");
701 raw1394_iso_recv_flush(
GetInfoPtr()->m_fwHandle);
704 LOG(VB_RECORD, LOG_INFO,
LOC +
"Stopped A/V streaming");
720 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Buffered packets %1 (%2 KB)")
721 .arg(buffered_packets).arg(buffered_packets * 4));
733 if (curspeed == speed)
739 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"Changing Speed %1 -> %2")
751 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Unable to set firewire speed.");
768 LOG(VB_GENERAL, LOG_INFO,
LOC +
"ResetBus() -- begin");
772 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Bus Reset disabled" +
ENO);
773 LOG(VB_GENERAL, LOG_INFO,
LOC +
"ResetBus() -- end");
777 bool ok = (raw1394_reset_bus_new(
GetInfoPtr()->m_fwHandle,
778 RAW1394_LONG_RESET) == 0);
780 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bus Reset failed" +
ENO);
782 LOG(VB_GENERAL, LOG_INFO,
LOC +
"ResetBus() -- end");
789 if (dropped_packets == 1)
791 LOG(VB_RECORD, LOG_ERR,
LOC +
"Dropped a TS packet");
793 else if (dropped_packets > 1)
795 LOG(VB_RECORD, LOG_ERR,
LOC + QString(
"Dropped %1 TS packets")
796 .arg(dropped_packets));
802 std::vector<AVCInfo> list;
815 LOG(VB_GENERAL, LOG_DEBUG,
"GetSTBListPrivate -- begin");
817 QMutexLocker locker(&
m_lock);
819 LOG(VB_GENERAL, LOG_DEBUG,
"GetSTBListPrivate -- got lock");
822 std::vector<AVCInfo> list;
829 list.push_back(*device);
834 LOG(VB_GENERAL, LOG_DEBUG,
"GetSTBListPrivate -- end");
850 item.
m_handle = raw1394_new_handle();
853 LOG(VB_GENERAL, LOG_ERR, QString(
"LinuxFirewireDevice: ") +
854 "Couldn't get handle" +
ENO);
858 std::array<raw1394_portinfo,16> port_info {};
859 int numcards = raw1394_get_port_info(item.m_handle, port_info.data(),
863 raw1394_destroy_handle(item.m_handle);
867 std::map<uint64_t,bool> guid_online;
868 for (
int port = 0; port < numcards; port++)
870 if (raw1394_set_port(item.m_handle, port) < 0)
872 LOG(VB_GENERAL, LOG_ERR, QString(
"LinuxFirewireDevice: "
873 "Couldn't set port to %1").arg(port));
877 for (
int node = 0; node < raw1394_get_nodecount(item.m_handle); node++)
881 guid = rom1394_get_guid(item.m_handle, node);
885 guid_online[guid] =
true;
888 raw1394_destroy_handle(item.m_handle);
890 item.m_handle = raw1394_new_handle();
893 LOG(VB_GENERAL, LOG_ERR, QString(
"LinuxFirewireDevice: ") +
894 "Couldn't get handle " +
895 QString(
"(after setting port %1").arg(port) +
ENO);
896 item.m_handle =
nullptr;
900 numcards = raw1394_get_port_info(item.m_handle, port_info.data(),
906 raw1394_destroy_handle(item.m_handle);
907 item.m_handle =
nullptr;
914 if (!guid_online[it.key()])
927 auto *ptr =
new LinuxAVCInfo();
929 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"Adding 0x%1").arg(guid,0,16));
938 LOG(VB_RECORD, LOG_INFO,
939 LOC + QString(
"Updating 0x%1 port: %2 node: %3")
965 unsigned char *tspacket,
int len,
uint dropped,
void *callback_data)
975 fw->BroadcastToListeners(tspacket, len);
980static bool has_data(
int fd, std::chrono::milliseconds msec)
986 struct timeval tv {};
987 tv.tv_sec = msec.count() / 1000;
988 tv.tv_usec = (msec.count() % 1000) * 1000;
990 int ready = select(fd + 1, &rfds,
nullptr,
nullptr, &tv);
993 LOG(VB_GENERAL, LOG_ERR,
"LFireDev: Select Error" +
ENO);
1001 return QString(
"Invalid Speed (%1)").arg(speed);
1003 static constexpr std::array<const uint,4> kSpeeds { 100, 200, 400, 800 };
1004 return QString(
"%1Mbps").arg(kSpeeds[speed]);
1008 raw1394handle_t handle,
unsigned int generation)
1015 (*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_)