Ticket #1648: firewire-sm-v18.patch
File firewire-sm-v18.patch, 87.6 KB (added by , 17 years ago) |
---|
-
libs/libmythtv/firewirechannel.cpp
1 1 /** 2 2 * FirewireChannel 3 3 * Copyright (c) 2005 by Jim Westfall 4 * SA3250HD support Copyright (c) 2005 by Matt Porter5 * SA4200HD/Alternate 3250 support Copyright (c) 2006 by Chris Ingrassia6 4 * Distributed as part of MythTV under GPL v2 and later. 7 5 */ 8 6 9 10 #include <iostream> 7 // MythTV headers 11 8 #include "mythcontext.h" 12 9 #include "firewirechannel.h" 10 #include "linuxfirewiredevice.h" 13 11 14 12 class TVRec; 15 13 16 #define LOC QString("FireChan: ") 17 #define LOC_ERR QString("FireChan, Error: ") 14 #define LOC QString("FireChan(%1): ").arg(GetDevice()) 15 #define LOC_WARN QString("FireChan(%1), Warning: ").arg(GetDevice()) 16 #define LOC_ERR QString("FireChan(%1), Error: ").arg(GetDevice()) 18 17 19 #ifndef AVC1394_PANEL_COMMAND_PASS_THROUGH 20 #define AVC1394_PANEL_COMMAND_PASS_THROUGH 0x000007C00 21 #endif 22 23 #ifndef AVC1394_PANEL_OPERATION_0 24 #define AVC1394_PANEL_OPERATION_0 0x000000020 25 #endif 26 27 #define DCT6200_CMD0 (AVC1394_CTYPE_CONTROL | \ 28 AVC1394_SUBUNIT_TYPE_PANEL | \ 29 AVC1394_SUBUNIT_ID_0 | \ 30 AVC1394_PANEL_COMMAND_PASS_THROUGH | \ 31 AVC1394_PANEL_OPERATION_0) 32 33 // SA3250HD defines 34 #define AVC1394_SA3250_OPERAND_KEY_PRESS 0xE7 35 #define AVC1394_SA3250_OPERAND_KEY_RELEASE 0x67 36 37 #define SA3250_CMD0 (AVC1394_CTYPE_CONTROL | \ 38 AVC1394_SUBUNIT_TYPE_PANEL | \ 39 AVC1394_SUBUNIT_ID_0 | \ 40 AVC1394_PANEL_COMMAND_PASS_THROUGH) 41 #define SA3250_CMD1 (0x04 << 24) 42 #define SA3250_CMD2 0xff000000 43 44 // power defines 45 #define AVC1394_CMD_OPERAND_POWER_STATE 0x7F 46 #define STB_POWER_STATE (AVC1394_CTYPE_STATUS | \ 47 AVC1394_SUBUNIT_TYPE_UNIT | \ 48 AVC1394_SUBUNIT_ID_IGNORE | \ 49 AVC1394_COMMAND_POWER | \ 50 AVC1394_CMD_OPERAND_POWER_STATE) 51 52 #define STB_POWER_ON (AVC1394_CTYPE_CONTROL | \ 53 AVC1394_SUBUNIT_TYPE_UNIT | \ 54 AVC1394_SUBUNIT_ID_IGNORE | \ 55 AVC1394_COMMAND_POWER | \ 56 AVC1394_CMD_OPERAND_POWER_ON) 57 58 static bool is_supported(const QString &model) 18 LinuxFirewireChannel::LinuxFirewireChannel( 19 FireWireDBOptions firewire_opts, TVRec *parent) : 20 FirewireChannelBase(parent), 21 fw_opts(firewire_opts), 22 device(new LinuxFirewireDevice( 23 fw_opts.port, fw_opts.node, fw_opts.speed, 24 LinuxFirewireDevice::kConnectionP2P == 25 (uint) fw_opts.connection)), 26 current_channel(0), 27 is_port_open(false) 59 28 { 60 return ((model == "DCT-6200") ||61 (model == "SA3250HD") ||62 (model == "SA4200HD"));63 29 } 64 30 65 FirewireChannel::FirewireChannel(FireWireDBOptions firewire_opts, 66 TVRec *parent) 67 : FirewireChannelBase(parent), fw_opts(firewire_opts), fwhandle(NULL) 31 LinuxFirewireChannel::~LinuxFirewireChannel(void) 68 32 { 69 }70 71 FirewireChannel::~FirewireChannel(void)72 {73 33 Close(); 74 34 } 75 35 76 bool FirewireChannel::SetChannelByNumber(int channel)36 bool LinuxFirewireChannel::Retune(void) 77 37 { 78 // Change channel using internal changer38 VERBOSE(VB_CHANNEL, LOC + "Retune()"); 79 39 80 if ( !is_supported(fw_opts.model))40 if (FirewireDevice::kAVCPowerOff == GetPowerState()) 81 41 { 82 42 VERBOSE(VB_IMPORTANT, LOC_ERR + 83 QString("Model: '%1' ").arg(fw_opts.model) +84 "is not supported by internal channel changer."); 43 "STB is turned off, must be on to retune."); 44 85 45 return false; 86 46 } 87 47 88 int dig[3]; 89 dig[0] = (channel % 1000) / 100; 90 dig[1] = (channel % 100) / 10; 91 dig[2] = (channel % 10); 48 if (current_channel) 49 return SetChannelByNumber(current_channel); 92 50 93 if (fw_opts.model == "DCT-6200") 94 { 95 VERBOSE(VB_CHANNEL, LOC + 96 QString("Channel1: %1%2%3 cmds: 0x%4, 0x%5, 0x%6") 97 .arg(dig[0]).arg(dig[1]) 98 .arg(dig[2]).arg(DCT6200_CMD0 | dig[0], 0, 16) 99 .arg(DCT6200_CMD0 | dig[1], 0, 16) 100 .arg(DCT6200_CMD0 | dig[2], 0, 16)); 51 return false; 52 } 101 53 102 for (uint i = 0; i < 3 ;i++) 103 { 104 quadlet_t cmd[2] = { DCT6200_CMD0 | dig[i], 0x0, }; 105 if (!avc1394_transaction_block(fwhandle, fw_opts.node, cmd, 2, 1)) 106 { 107 VERBOSE(VB_IMPORTANT, "AVC transaction failed."); 108 return false; 109 } 110 usleep(500000); 111 } 112 } 113 else if (fw_opts.model == "SA3250HD") 54 bool LinuxFirewireChannel::SetChannelByNumber(int channel) 55 { 56 current_channel = channel; 57 58 if (FirewireDevice::kAVCPowerOff == GetPowerState()) 114 59 { 115 dig[0] |= 0x30; 116 dig[1] |= 0x30; 117 dig[2] |= 0x30; 60 VERBOSE(VB_IMPORTANT, LOC_WARN + 61 "STB is turned off, must be on to set channel."); 118 62 119 quadlet_t cmd[3] = 120 { 121 SA3250_CMD0 | AVC1394_SA3250_OPERAND_KEY_PRESS, 122 SA3250_CMD1 | (dig[2] << 16) | (dig[1] << 8) | dig[0], 123 SA3250_CMD2, 124 }; 63 SetSIStandard("mpeg"); 64 SetCachedATSCInfo(QString("%1-1").arg(channel)); 125 65 126 VERBOSE(VB_CHANNEL, LOC + 127 QString("Channel2: %1%2%3 cmds: 0x%4, 0x%5, 0x%6") 128 .arg(dig[0] & 0xf).arg(dig[1] & 0xf) 129 .arg(dig[2] & 0xf) 130 .arg(cmd[0], 0, 16).arg(cmd[1], 0, 16) 131 .arg(cmd[2], 0, 16)); 132 133 if(!avc1394_transaction_block(fwhandle, fw_opts.node, cmd, 3, 1)) 134 { 135 VERBOSE(VB_IMPORTANT, "AVC transaction failed."); 136 return false; 137 } 138 139 cmd[0] = SA3250_CMD0 | AVC1394_SA3250_OPERAND_KEY_RELEASE; 140 cmd[1] = SA3250_CMD1 | (dig[0] << 16) | (dig[1] << 8) | dig[2]; 141 cmd[2] = SA3250_CMD2; 142 143 VERBOSE(VB_CHANNEL, LOC + 144 QString("Channel3: %1%2%3 cmds: 0x%4, 0x%5, 0x%6") 145 .arg(dig[0] & 0xf).arg(dig[1] & 0xf) 146 .arg(dig[2] & 0xf) 147 .arg(cmd[0], 0, 16).arg(cmd[1], 0, 16) 148 .arg(cmd[2], 0, 16)); 149 150 if (!avc1394_transaction_block(fwhandle, fw_opts.node, cmd, 3, 1)) 151 { 152 VERBOSE(VB_IMPORTANT, "AVC transaction failed."); 153 return false; 154 } 66 return true; // signal monitor will call retune later... 155 67 } 156 else if (fw_opts.model == "SA4200HD")157 {158 quadlet_t cmd[3] =159 {160 SA3250_CMD0 | AVC1394_SA3250_OPERAND_KEY_PRESS,161 SA3250_CMD1 | (channel << 8),162 SA3250_CMD2,163 };164 68 165 VERBOSE(VB_CHANNEL, LOC + 166 QString("SA4200Channel: %1 cmds: 0x%2 0x%3 0x%4") 167 .arg(channel).arg(cmd[0], 0, 16) 168 .arg(cmd[1], 0, 16) 169 .arg(cmd[2], 0, 16)); 69 if (!device->SetChannel(fw_opts.model, channel)) 70 return false; 170 71 171 if (!avc1394_transaction_block(fwhandle, fw_opts.node, cmd, 3, 1)) 172 { 173 VERBOSE(VB_IMPORTANT, "AVC transaction failed."); 174 return false; 175 } 176 } 72 SetSIStandard("mpeg"); 73 SetCachedATSCInfo(QString("%1-1").arg(channel)); 177 74 178 75 return true; 179 76 } 180 77 181 bool FirewireChannel::OpenFirewire(void)78 bool LinuxFirewireChannel::OpenFirewire(void) 182 79 { 183 if (!is_supported(fw_opts.model)) 80 VERBOSE(VB_IMPORTANT, LOC + "OpenFirewire()"); 81 82 if (is_port_open) 83 return true; 84 85 if (!LinuxFirewireDevice::IsSTBSupported(fw_opts.model)) 184 86 { 185 87 VERBOSE(VB_IMPORTANT, LOC_ERR + 186 88 QString("Model: '%1' ").arg(fw_opts.model) + 187 89 "is not supported by internal channel changer."); 188 return false;189 }190 90 191 // Open channel192 fwhandle = raw1394_new_handle_on_port(fw_opts.port);193 if (!fwhandle)194 {195 VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to get handle " +196 QString("for port: %1").arg(fw_opts.port));197 91 return false; 198 92 } 199 93 200 VERBOSE(VB_CHANNEL, LOC + "Allocated raw1394 handle " + 201 QString("for port %1").arg(fw_opts.port)); 202 203 // verify node looks like a stb 204 if (!avc1394_check_subunit_type(fwhandle, fw_opts.node, 205 AVC1394_SUBUNIT_TYPE_TUNER)) 206 { 207 VERBOSE(VB_IMPORTANT, LOC_ERR + QString("node %1 is not subunit " 208 "type tuner.").arg(fw_opts.node)); 209 CloseFirewire(); 94 if (!device->OpenPort()) 210 95 return false; 211 }212 96 213 if (!avc1394_check_subunit_type(fwhandle, fw_opts.node, 214 AVC1394_SUBUNIT_TYPE_PANEL)) 97 if (!device->IsSTB()) 215 98 { 216 VERBOSE(VB_IMPORTANT, LOC_ERR + QString("node %1 is not subunit " 217 "type panel.").arg(fw_opts.node)); 218 CloseFirewire(); 99 device->ClosePort(); 219 100 return false; 220 101 } 221 102 222 // check power, power on if off 223 if (GetPowerState() == Off) 224 { 225 quadlet_t *rval, response, cmd = STB_POWER_ON; 226 VERBOSE(VB_IMPORTANT, LOC + QString("Powering on (cmd: 0x%1)") 227 .arg(cmd, 0, 16)); 228 rval = avc1394_transaction_block(fwhandle, fw_opts.node, &cmd, 1, 1); 229 if (rval) 230 { 231 response = rval[0]; 103 is_port_open = true; 232 104 233 if (AVC1394_MASK_RESPONSE(response) == AVC1394_RESPONSE_ACCEPTED)234 {235 VERBOSE(VB_IMPORTANT, LOC + QString("Power on cmd successful "236 "(0x%1)")237 .arg(response, 0, 16));238 // allow some time for the stb to power on239 sleep(3);240 if (GetPowerState() == Off)241 {242 VERBOSE(VB_IMPORTANT, LOC + "STB is still off!?");243 return false;244 }245 return true;246 }247 else248 {249 VERBOSE(VB_IMPORTANT, LOC + QString("Power on cmd failed "250 "(0x%1)")251 .arg(response, 0, 16));252 return false;253 }254 }255 else256 {257 VERBOSE(VB_IMPORTANT, LOC + "Power on cmd failed (no response)");258 return false;259 }260 }261 105 return true; 262 106 } 263 107 264 void FirewireChannel::CloseFirewire(void)108 void LinuxFirewireChannel::CloseFirewire(void) 265 109 { 266 VERBOSE(VB_CHANNEL, LOC + "Releasing raw1394 handle"); 267 raw1394_destroy_handle(fwhandle); 110 VERBOSE(VB_IMPORTANT, LOC + "CloseFirewire()"); 111 112 if (!is_port_open) 113 return; 114 115 device->ClosePort(); 116 is_port_open = false; 268 117 } 269 118 270 FirewireChannel::PowerState FirewireChannel::GetPowerState(void)119 bool LinuxFirewireChannel::SetPowerState(bool on) 271 120 { 272 quadlet_t *rval, response, cmd = STB_POWER_STATE; 121 return device->SetPowerState(on); 122 } 273 123 274 VERBOSE(VB_CHANNEL, LOC + QString("Requesting STB Power State (cmd: 0x%1)") 275 .arg(STB_POWER_STATE, 0, 16)); 276 rval = avc1394_transaction_block(fwhandle, fw_opts.node, &cmd, 1, 1); 277 278 if (rval) 279 { 280 response = rval[0]; 281 282 if (AVC1394_MASK_RESPONSE(response) == AVC1394_RESPONSE_IMPLEMENTED) 283 { 284 if ((response & 0xFF) == AVC1394_CMD_OPERAND_POWER_ON) 285 { 286 VERBOSE(VB_CHANNEL, LOC + QString("STB Power State: ON (0x%1)") 287 .arg(response, 0, 16)); 288 return On; 289 } 290 else if ((response & 0xFF) == AVC1394_CMD_OPERAND_POWER_OFF) 291 { 292 VERBOSE(VB_IMPORTANT, LOC + QString("STB Power State: OFF " 293 "(0x%1)") 294 .arg(response, 0, 16)); 295 return Off; 296 } 297 else 298 { 299 VERBOSE(VB_CHANNEL, LOC + QString("STB Power State: " 300 "Unknown Response (0x%1)") 301 .arg(response, 0, 16)); 302 return Failed; 303 } 304 } 305 else 306 { 307 VERBOSE(VB_CHANNEL, LOC + QString("STB Power State: Failed (0x%1)") 308 .arg(response, 0, 16)); 309 return Failed; 310 } 311 } 312 VERBOSE(VB_CHANNEL, LOC + "Failed to get STB Power State"); 313 return Failed; 124 FirewireDevice::PowerState LinuxFirewireChannel::GetPowerState(void) const 125 { 126 return device->GetPowerState(); 314 127 } -
libs/libmythtv/firewirerecorderbase.h
12 12 #include "tspacket.h" 13 13 #include "streamlisteners.h" 14 14 15 class TVRec; 16 class FirewireChannelBase; 17 15 18 /** \class FirewireRecorderBase 16 19 * \brief This is a specialization of DTVRecorder used to 17 20 * handle DVB and ATSC streams from a firewire input. … … 25 28 friend class TSPacketProcessor; 26 29 27 30 public: 28 FirewireRecorderBase(TVRec *rec); 29 ~FirewireRecorderBase(); 31 virtual ~FirewireRecorderBase(); 30 32 31 33 // Commands 32 34 void StartRecording(void); … … 41 43 void SetStreamData(MPEGStreamData*); 42 44 43 45 // Gets 44 MPEGStreamData *StreamData(void) { return _mpeg_stream_data; }46 MPEGStreamData *GetStreamData(void) { return _mpeg_stream_data; } 45 47 46 48 // MPEG Single Program 47 49 void HandleSingleProgramPAT(ProgramAssociationTable*); 48 50 void HandleSingleProgramPMT(ProgramMapTable*); 49 51 52 // Factory 53 static FirewireRecorderBase *Init( 54 TVRec *rec, FirewireChannelBase *channel); 55 56 protected: 57 FirewireRecorderBase(TVRec *rec); 58 50 59 private: 51 60 virtual void Close() = 0; 52 virtual void start() = 0; 53 virtual void stop() = 0; 54 virtual bool grab_frames() = 0; 61 virtual void StartStreaming(void) = 0; 62 virtual void StopStreaming(void) = 0; 55 63 56 64 MPEGStreamData *_mpeg_stream_data; 57 65 TSStats _ts_stats; -
libs/libmythtv/firewirechannelbase.h
8 8 #ifndef LIBMYTHTV_FIREWIRECHANNELBASE_H 9 9 #define LIBMYTHTV_FIREWIRECHANNELBASE_H 10 10 11 #include <qstring.h> 12 #include "tv_rec.h" 13 #include "channelbase.h" 11 #include "dtvchannel.h" 12 #include "firewiredevice.h" 14 13 15 #include "mythconfig.h" 14 class TVRec; 15 class FireWireDBOptions; 16 16 17 namespace AVS 17 class FirewireChannelBase : public DTVChannel 18 18 { 19 class AVCDeviceController;20 class AVCDevice;21 }22 23 class FirewireChannelBase : public ChannelBase24 {25 19 public: 26 FirewireChannelBase(TVRec *parent) 27 : ChannelBase(parent), isopen(false) { } 28 ~FirewireChannelBase() { Close(); } 20 // Commands 21 virtual bool Open(void); 22 virtual void Close(void); 23 virtual bool SwitchToInput(const QString &inputname, const QString &chan); 24 virtual bool SwitchToInput(int newcapchannel, bool setstarting) 25 { (void)newcapchannel; (void)setstarting; return false; } 29 26 30 bool Open(void); 31 void Close(void); 27 virtual bool TuneMultiplex(uint /*mplexid*/, QString /*inputname*/) 28 { return false; } 29 virtual bool Tune(const DTVMultiplex &/*tuning*/, QString /*inputname*/) 30 { return false; } 31 virtual bool Retune(void) 32 { return false; } 32 33 33 34 // Sets 34 bool SetChannelByString(const QString &chan);35 virtual bool SetChannelByString(const QString &chan); 35 36 virtual bool SetChannelByNumber(int channel) = 0; 37 virtual bool SetPowerState(bool /*on*/) = 0; 36 38 37 39 // Gets 38 bool IsOpen(void) const { return isopen; } 40 virtual bool IsOpen(void) const { return isopen; } 41 virtual FirewireDevice::PowerState GetPowerState(void) const = 0; 39 42 40 // Commands 41 bool SwitchToInput(const QString &inputname, const QString &chan); 42 bool SwitchToInput(int newcapchannel, bool setstarting) 43 { (void)newcapchannel; (void)setstarting; return false; } 43 // Factory method 44 static FirewireChannelBase *Init( 45 const FireWireDBOptions &firewire_opts, TVRec *parent); 44 46 47 protected: 48 FirewireChannelBase(TVRec *parent) : 49 DTVChannel(parent), isopen(false) { } 50 ~FirewireChannelBase() { Close(); } 51 45 52 private: 46 virtual bool OpenFirewire( ) = 0;47 virtual void CloseFirewire( ) = 0;53 virtual bool OpenFirewire(void) = 0; 54 virtual void CloseFirewire(void) = 0; 48 55 49 56 protected: 50 57 bool isopen; -
libs/libmythtv/libmythtv.pro
380 380 using_firewire { 381 381 HEADERS += firewirechannelbase.h firewirerecorderbase.h 382 382 SOURCES += firewirechannelbase.cpp firewirerecorderbase.cpp 383 HEADERS += firewiresignalmonitor.h firewiredevice.h 384 SOURCES += firewiresignalmonitor.cpp 383 385 384 386 macx { 385 387 HEADERS += darwinfirewirechannel.h darwinfirewirerecorder.h … … 391 393 !macx { 392 394 HEADERS += firewirechannel.h firewirerecorder.h 393 395 SOURCES += firewirechannel.cpp firewirerecorder.cpp 396 HEADERS += linuxfirewiredevice.h 397 SOURCES += linuxfirewiredevice.cpp 394 398 } 395 399 396 400 DEFINES += USING_FIREWIRE -
libs/libmythtv/darwinfirewirerecorder.cpp
11 11 #undef always_inline 12 12 #include <AVCVideoServices/AVCVideoServices.h> 13 13 14 DarwinFirewireRecorder::DarwinFirewireRecorder(TVRec *rec, ChannelBase* tuner) 15 : FirewireRecorderBase(rec), 16 capture_device( 17 dynamic_cast<DarwinFirewireChannel*>(tuner)->GetAVCDevice() 18 ), 19 message_log(NULL), 20 video_stream(NULL), 21 isopen(false) 22 {;} 14 DarwinFirewireRecorder::DarwinFirewireRecorder( 15 TVRec *rec, DarwinFirewireChannel *channel) : 16 FirewireRecorderBase(rec), 17 capture_device(channel->GetAVCDevice()), 18 message_log(NULL), 19 video_stream(NULL), 20 isopen(false) 21 { 22 SetStreamData(new MPEGStreamData(1, true)); 23 } 23 24 24 25 DarwinFirewireRecorder::~DarwinFirewireRecorder() 25 26 { … … 196 197 this->message_log = 0; 197 198 } 198 199 199 void DarwinFirewireRecorder:: start()200 void DarwinFirewireRecorder::StartStreaming(void) 200 201 { 201 202 VERBOSE(VB_RECORD, "Firewire: Starting video stream"); 202 203 this->capture_device->StartAVCDeviceStream(this->video_stream); 203 204 } 204 205 205 void DarwinFirewireRecorder:: stop()206 void DarwinFirewireRecorder::StopStreaming(void) 206 207 { 207 208 VERBOSE(VB_RECORD, "Firewire: Stopping video stream"); 208 209 this->capture_device->StopAVCDeviceStream(this->video_stream); 209 210 } 210 211 bool DarwinFirewireRecorder::grab_frames()212 {213 usleep(1000000 / 2); // 2 times a second214 return true;215 }216 217 void DarwinFirewireRecorder::SetOption(const QString &name, const QString &value)218 {219 (void)name;220 (void)value;221 }222 223 void DarwinFirewireRecorder::SetOption(const QString &name, int value)224 {225 (void)name;226 (void)value;227 } -
libs/libmythtv/signalmonitor.h
285 285 return (CardUtil::IsDVBCardType(cardtype) || 286 286 (cardtype.upper() == "HDTV") || 287 287 (cardtype.upper() == "HDHOMERUN") || 288 (cardtype.upper() == "FIREWIRE") || 288 289 (cardtype.upper() == "FREEBOX")); 289 290 } 290 291 -
libs/libmythtv/firewirerecorderbase.cpp
5 5 */ 6 6 7 7 // MythTV includes 8 #include "mythconfig.h" // for CONFIG_DARWIN 8 9 #include "firewirerecorderbase.h" 9 10 #include "mythcontext.h" 10 11 #include "mpegtables.h" 11 12 #include "mpegstreamdata.h" 12 13 #include "tv_rec.h" 13 14 15 #ifdef CONFIG_DARWIN 16 # include "darwinfirewirechannel.h" 17 # include "darwinfirewirerecorder.h" 18 #else 19 # include "firewirechannel.h" 20 # include "firewirerecorder.h" 21 # include "linuxfirewiredevice.h" 22 #endif 23 14 24 #define LOC QString("FireRecBase: ") 15 25 #define LOC_ERR QString("FireRecBase, Error: ") 16 26 17 27 const int FirewireRecorderBase::kTimeoutInSeconds = 15; 18 28 29 FirewireRecorderBase *FirewireRecorderBase::Init( 30 TVRec *rec, FirewireChannelBase *channel) 31 { 32 #ifdef CONFIG_DARWIN 33 DarwinFirewireChannel *dfch = 34 dynamic_cast<DarwinFirewireChannel*>(channel); 35 if (dfch) 36 return new DarwinFirewireRecorder(rec, channel); 37 #else 38 LinuxFirewireChannel *lfch = 39 dynamic_cast<LinuxFirewireChannel*>(channel); 40 if (lfch) 41 return new LinuxFirewireRecorder(rec, lfch); 42 #endif 43 44 return NULL; 45 } 46 19 47 FirewireRecorderBase::FirewireRecorderBase(TVRec *rec) 20 48 : DTVRecorder(rec), _mpeg_stream_data(NULL) 21 49 { 22 SetStreamData(new MPEGStreamData(1, true));23 50 } 24 51 25 52 FirewireRecorderBase::~FirewireRecorderBase() … … 39 66 _request_recording = true; 40 67 _recording = true; 41 68 42 start();69 StartStreaming(); 43 70 44 while(_request_recording) { 45 if (PauseAndWait()) 46 continue; 47 48 if (!grab_frames()) 49 { 50 _error = true; 51 return; 52 } 71 while (_request_recording) 72 { 73 if (!PauseAndWait()) 74 usleep(250 * 1000); 53 75 } 54 76 55 stop();77 StopStreaming(); 56 78 FinishRecording(); 57 79 58 80 _recording = false; … … 67 89 return; 68 90 69 91 if (tspacket.HasAdaptationField()) 70 StreamData()->HandleAdaptationFieldControl(&tspacket);92 GetStreamData()->HandleAdaptationFieldControl(&tspacket); 71 93 72 94 if (tspacket.HasPayload()) 73 95 { 74 96 const unsigned int lpid = tspacket.PID(); 75 97 76 98 // Pass or reject packets based on PID, and parse info from them 77 if (lpid == StreamData()->VideoPIDSingleProgram())99 if (lpid == GetStreamData()->VideoPIDSingleProgram()) 78 100 { 79 101 _buffer_packets = !FindMPEG2Keyframes(&tspacket); 80 102 BufferedWrite(tspacket); 81 103 } 82 else if ( StreamData()->IsAudioPID(lpid))104 else if (GetStreamData()->IsAudioPID(lpid)) 83 105 BufferedWrite(tspacket); 84 else if ( StreamData()->IsListeningPID(lpid))85 StreamData()->HandleTSTables(&tspacket);86 else if ( StreamData()->IsWritingPID(lpid))106 else if (GetStreamData()->IsListeningPID(lpid)) 107 GetStreamData()->HandleTSTables(&tspacket); 108 else if (GetStreamData()->IsWritingPID(lpid)) 87 109 BufferedWrite(tspacket); 88 110 } 89 111 … … 108 130 { 109 131 if (request_pause) 110 132 { 133 VERBOSE(VB_RECORD, LOC + "PauseAndWait("<<timeout<<") -- pause"); 111 134 if (!paused) 112 135 { 113 stop();136 StopStreaming(); 114 137 paused = true; 115 138 pauseWait.wakeAll(); 116 139 if (tvrec) … … 120 143 } 121 144 if (!request_pause && paused) 122 145 { 123 start(); 146 VERBOSE(VB_RECORD, LOC + "PauseAndWait("<<timeout<<") -- unpause"); 147 StartStreaming(); 124 148 paused = false; 125 149 } 126 150 return paused; -
libs/libmythtv/firewirerecorder.cpp
8 8 #include <pthread.h> 9 9 #include <sys/select.h> 10 10 11 // C++ includes 12 #include <iostream> 13 using namespace std; 11 // Linux C includes 12 #include <libraw1394/raw1394.h> 14 13 15 14 // MythTV includes 16 15 #include "firewirerecorder.h" 16 #include "firewirechannel.h" 17 #include "linuxfirewiredevice.h" 17 18 #include "mythcontext.h" 18 19 #include "mpegtables.h" 19 20 #include "mpegstreamdata.h" 20 21 #include "tv_rec.h" 21 22 22 #define LOC QString("FireRec : ")23 #define LOC_ERR QString("FireRec , Error: ")23 #define LOC QString("FireRec(%1): ").arg(channel->GetDevice()) 24 #define LOC_ERR QString("FireRec(%1), Error: ").arg(tvrec->GetDevice()) 24 25 25 const int FirewireRecorder::kBroadcastChannel = 63; 26 const int FirewireRecorder::kConnectionP2P = 0; 27 const int FirewireRecorder::kConnectionBroadcast = 1; 28 const uint FirewireRecorder::kMaxBufferedPackets = 2000; 29 30 // callback function for libiec61883 31 int fw_tspacket_handler(unsigned char *tspacket, int /*len*/, 32 uint dropped, void *callback_data) 26 LinuxFirewireRecorder::LinuxFirewireRecorder( 27 TVRec *rec, 28 LinuxFirewireChannel *chan) : 29 FirewireRecorderBase(rec), channel(chan), isopen(false) 33 30 { 34 if (dropped)35 {36 VERBOSE(VB_RECORD, LOC_ERR +37 QString("Dropped %1 packet(s).").arg(dropped));38 }39 40 if (SYNC_BYTE != tspacket[0])41 {42 VERBOSE(VB_IMPORTANT, LOC_ERR + "TS packet out of sync.");43 return 1;44 }45 46 FirewireRecorder *fw = (FirewireRecorder*) callback_data;47 if (fw)48 fw->ProcessTSPacket(*(reinterpret_cast<TSPacket*>(tspacket)));49 50 return (fw) ? 1 : 0;51 31 } 52 32 53 static QString speed_to_string(uint speed)33 LinuxFirewireRecorder::~LinuxFirewireRecorder() 54 34 { 55 if (speed > RAW1394_ISO_SPEED_400) 56 return QString("Invalid Speed (%1)").arg(speed); 57 58 static const uint speeds[] = { 100, 200, 400, }; 59 return QString("%1Mbps").arg(speeds[speed]); 35 Close(); 60 36 } 61 37 62 bool FirewireRecorder::Open(void)38 bool LinuxFirewireRecorder::Open(void) 63 39 { 64 if ( isopen)65 return true;40 if (!isopen) 41 isopen = channel->GetFirewireDevice()->OpenPort(); 66 42 67 VERBOSE(VB_RECORD, LOC + 68 QString("Initializing Port: %1, Node: %2, Speed: %3") 69 .arg(fwport).arg(fwnode).arg(speed_to_string(fwspeed))); 70 71 fwhandle = raw1394_new_handle_on_port(fwport); 72 if (!fwhandle) 73 { 74 VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to get handle for " + 75 QString("port: %1, bailing").arg(fwport) + ENO); 76 return false; 77 } 78 79 if (kConnectionP2P == fwconnection) 80 { 81 VERBOSE(VB_RECORD, LOC + "Creating P2P Connection " + 82 QString("with Node: %1").arg(fwnode)); 83 fwchannel = iec61883_cmp_connect(fwhandle, 84 fwnode | 0xffc0, &fwoplug, 85 raw1394_get_local_id(fwhandle), 86 &fwiplug, &fwbandwidth); 87 if (fwchannel > -1) 88 { 89 VERBOSE(VB_RECORD, LOC + 90 QString("Created Channel: %1, " 91 "Bandwidth Allocation: %2") 92 .arg(fwchannel).arg(fwbandwidth)); 93 } 94 } 95 else 96 { 97 fwchannel = kBroadcastChannel - fwnode; 98 99 VERBOSE(VB_RECORD, LOC + "Creating Broadcast Connection " + 100 QString("with Node: %1, Channel: %2").arg(fwnode) 101 .arg(fwchannel)); 102 if (iec61883_cmp_create_bcast_output(fwhandle, 103 fwnode | 0xffc0, 0, 104 fwchannel, 105 fwspeed) != 0) 106 { 107 VERBOSE(VB_IMPORTANT, LOC + "Failed to create connection"); 108 // release raw1394 object; 109 raw1394_destroy_handle(fwhandle); 110 return false; 111 } 112 fwbandwidth = 0; 113 } 114 115 fwmpeg = iec61883_mpeg2_recv_init(fwhandle, fw_tspacket_handler, this); 116 if (!fwmpeg) 117 { 118 VERBOSE(VB_IMPORTANT, LOC + 119 "Unable to init iec61883_mpeg2 object, bailing" + ENO); 120 121 // release raw1394 object; 122 raw1394_destroy_handle(fwhandle); 123 return false; 124 } 125 126 // Set buffered packets size 127 size_t buffer_size = gContext->GetNumSetting("HDRingbufferSize", 128 50 * TSPacket::SIZE); 129 size_t buffered_packets = min(buffer_size / 4, 130 (size_t) kMaxBufferedPackets); 131 iec61883_mpeg2_set_buffers(fwmpeg, buffered_packets); 132 VERBOSE(VB_IMPORTANT, LOC + 133 QString("Buffered packets %1 (%2 KB)") 134 .arg(buffered_packets).arg(buffered_packets * 4)); 135 136 // Set speed if needed. 137 // Probably shouldn't even allow user to set, 138 // 100Mbps should be more the enough. 139 int curspeed = iec61883_mpeg2_get_speed(fwmpeg); 140 if (curspeed != fwspeed) 141 { 142 VERBOSE(VB_RECORD, LOC + 143 QString("Changing Speed %1 -> %2") 144 .arg(speed_to_string(curspeed)) 145 .arg(speed_to_string(fwspeed))); 146 147 iec61883_mpeg2_set_speed(fwmpeg, fwspeed); 148 if (fwspeed != iec61883_mpeg2_get_speed(fwmpeg)) 149 { 150 VERBOSE(VB_IMPORTANT, LOC + 151 "Unable to set firewire speed, continuing"); 152 } 153 } 154 155 fwfd = raw1394_get_fd(fwhandle); 156 157 return isopen = true; 43 return isopen; 158 44 } 159 45 160 void FirewireRecorder::Close(void)46 void LinuxFirewireRecorder::Close(void) 161 47 { 162 if (!isopen) 163 return; 164 165 isopen = false; 166 167 VERBOSE(VB_RECORD, LOC + "Releasing iec61883_mpeg2 object"); 168 iec61883_mpeg2_close(fwmpeg); 169 170 if (fwconnection == kConnectionP2P && fwchannel > -1) 48 if (isopen) 171 49 { 172 VERBOSE(VB_RECORD, LOC + 173 QString("Disconnecting channel %1").arg(fwchannel)); 174 175 iec61883_cmp_disconnect(fwhandle, fwnode | 0xffc0, fwoplug, 176 raw1394_get_local_id (fwhandle), 177 fwiplug, fwchannel, fwbandwidth); 50 channel->GetFirewireDevice()->ClosePort(); 51 isopen = false; 178 52 } 53 } 179 54 180 VERBOSE(VB_RECORD, LOC + "Releasing raw1394 handle"); 181 raw1394_destroy_handle(fwhandle); 55 void LinuxFirewireRecorder::StartStreaming(void) 56 { 57 channel->GetFirewireDevice()->AddListener(this); 182 58 } 183 59 184 bool FirewireRecorder::grab_frames()60 void LinuxFirewireRecorder::StopStreaming(void) 185 61 { 186 struct timeval tv;187 fd_set rfds; 62 channel->GetFirewireDevice()->RemoveListener(this); 63 } 188 64 189 FD_ZERO(&rfds); 190 FD_SET(fwfd, &rfds); 191 tv.tv_sec = kTimeoutInSeconds; 192 tv.tv_usec = 0; 65 void LinuxFirewireRecorder::AddData(const unsigned char *data, uint len) 66 { 67 //cout<<":"; 193 68 194 if (select(fwfd + 1, &rfds, NULL, NULL, &tv) <= 0) 195 { 196 VERBOSE(VB_IMPORTANT, LOC + 197 QString("No Input in %1 seconds [P:%2 N:%3] (select)") 198 .arg(kTimeoutInSeconds).arg(fwport).arg(fwnode)); 199 return false; 69 uint bufsz = buffer.size(); 70 if ((SYNC_BYTE == data[0]) && (TSPacket::SIZE == len) && 71 (TSPacket::SIZE > bufsz)) 72 { 73 if (bufsz) 74 buffer.clear(); 75 76 ProcessTSPacket(*(reinterpret_cast<const TSPacket*>(data))); 77 return; 200 78 } 201 79 202 int ret = raw1394_loop_iterate(fwhandle); 203 if (ret) 80 buffer.insert(buffer.end(), data, data + len); 81 bufsz += len; 82 83 int sync_at = -1; 84 for (uint i = 0; (i < bufsz) && (sync_at < 0); i++) 204 85 { 205 VERBOSE(VB_IMPORTANT, LOC_ERR + "libraw1394_loop_iterate() " + 206 QString("returned %1").arg(ret)); 207 return false; 86 if (buffer[i] == SYNC_BYTE) 87 sync_at = i; 208 88 } 209 89 210 return true;211 } 90 if (sync_at < 0) 91 return; 212 92 213 void FirewireRecorder::SetOption(const QString &name, const QString &value) 214 { 215 if (name == "model") 216 fwmodel = value; 217 } 93 if (bufsz < 30 * TSPacket::SIZE) 94 return; // build up a little buffer 218 95 219 void FirewireRecorder::SetOption(const QString &name, int value) 220 { 221 if (name == "port") 222 fwport = value; 223 else if (name == "node") 224 fwnode = value; 225 else if (name == "speed") 96 while (sync_at + TSPacket::SIZE < bufsz) 226 97 { 227 if (RAW1394_ISO_SPEED_100 != value && 228 RAW1394_ISO_SPEED_200 != value && 229 RAW1394_ISO_SPEED_400 != value) 230 { 231 VERBOSE(VB_IMPORTANT, LOC_ERR + 232 QString("Unknown speed '%1', will use 100Mbps") 233 .arg(value)); 98 ProcessTSPacket(*(reinterpret_cast<const TSPacket*>( 99 &buffer[0] + sync_at))); 234 100 235 value = RAW1394_ISO_SPEED_100; 236 } 237 fwspeed = value; 101 sync_at += TSPacket::SIZE; 238 102 } 239 else if (name == "connection")240 {241 if (kConnectionP2P != value &&242 kConnectionBroadcast != value)243 {244 VERBOSE(VB_IMPORTANT, LOC_ERR +245 QString("Unknown connection type '%1', will use P2P")246 .arg(fwconnection));247 103 248 fwconnection = kConnectionP2P; 249 } 250 fwconnection = value; 251 } 104 buffer.erase(buffer.begin(), buffer.begin() + sync_at); 105 106 return; 252 107 } -
libs/libmythtv/firewirerecorder.h
4 4 * Distributed as part of MythTV under GPL v2 and later. 5 5 */ 6 6 7 #ifndef FIREWIRERECORDER_H_8 #define FIREWIRERECORDER_H_7 #ifndef _LINUX_FIREWIRE_RECORDER_H_ 8 #define _LINUX_FIREWIRE_RECORDER_H_ 9 9 10 10 #include "firewirerecorderbase.h" 11 #include "tsstats.h" 12 #include <libraw1394/raw1394.h> 13 #include <libiec61883/iec61883.h> 11 #include "linuxfirewiredevice.h" 14 12 15 /** \class FirewireRecorder 16 * \brief Linux FirewireRFecorder 13 class LinuxFirewireChannel; 14 15 /** \class LinuxFirewireRecorder 16 * \brief Linux Firewire Recorder 17 17 * 18 18 * \sa FirewireRecorderBase 19 19 */ 20 class FirewireRecorder : public FirewireRecorderBase 20 class LinuxFirewireRecorder : 21 public FirewireRecorderBase, public TSDataListener 21 22 { 22 friend int fw_tspacket_handler(unsigned char*,int,uint,void*);23 24 23 public: 25 FirewireRecorder(TVRec *rec) 26 : FirewireRecorderBase(rec), 27 fwport(-1), fwchannel(-1), fwspeed(-1), fwbandwidth(-1), 28 fwfd(-1), fwconnection(kConnectionP2P), 29 fwoplug(-1), fwiplug(-1), fwmodel(""), fwnode(0), 30 fwhandle(NULL), fwmpeg(NULL), isopen(false) { } 31 ~FirewireRecorder() { Close(); } 24 LinuxFirewireRecorder(TVRec *rec, LinuxFirewireChannel *chan); 25 ~LinuxFirewireRecorder(); 32 26 33 27 // Commands 34 bool Open(void); 35 36 // Sets 37 void SetOption(const QString &name, const QString &value); 38 void SetOption(const QString &name, int value); 39 40 private: 28 bool Open(void); 29 void StartStreaming(void); 30 void StopStreaming(void); 41 31 void Close(void); 42 void start() { iec61883_mpeg2_recv_start(fwmpeg, fwchannel); }43 void stop() { iec61883_mpeg2_recv_stop(fwmpeg); }44 bool grab_frames();45 32 46 33 private: 47 int fwport; 48 int fwchannel; 49 int fwspeed; 50 int fwbandwidth; 51 int fwfd; 52 int fwconnection; 53 int fwoplug; 54 int fwiplug; 55 QString fwmodel; 56 nodeid_t fwnode; 57 raw1394handle_t fwhandle; 58 iec61883_mpeg2_t fwmpeg; 59 bool isopen; 34 void AddData(const unsigned char *data, uint dataSize); 60 35 61 static const int kBroadcastChannel;62 static const int kConnectionP2P;63 static const int kConnectionBroadcast;64 static const uint kMaxBufferedPackets;36 private: 37 LinuxFirewireChannel *channel; 38 bool isopen; 39 vector<unsigned char> buffer; 65 40 }; 66 41 67 #endif 42 #endif // _LINUX_FIREWIRE_RECORDER_H_ -
libs/libmythtv/darwinfirewirechannel.cpp
15 15 #undef always_inline 16 16 #include <AVCVideoServices/AVCVideoServices.h> 17 17 18 #define LOC QString("DarwinFirewireChannel: ") 19 #define LOC_ERR QString("DarwinFirewireChannel, Error: ") 18 20 19 21 namespace 20 22 { … … 84 86 return this->device; 85 87 } 86 88 89 FirewireDevice::PowerState DarwinFirewireChannel::GetPowerState(void) const 90 { 91 UInt8 power_state; 92 IOReturn err = device->GetPowerState(&power_state); 93 94 if (err != kIOReturnSuccess) 95 return FirewireDevice::kAVCPowerQueryFailed; 96 else if (kAVCPowerStateOff == power_state) 97 return FirewireDevice::kAVCPowerOff; 98 else if (kAVCPowerStateOn == power_state) 99 return FirewireDevice::kAVCPowerOn; 100 else 101 return FirewireDevice::kAVCPowerUnknown; 102 } 103 104 bool DarwinFirewireChannel::SetPowerState(bool on) 105 { 106 if (on) 107 SetPowerState(kAVCPowerStateOn); 108 else 109 SetPowerState(kAVCPowerStateOff); 110 111 return true; 112 } 113 87 114 bool DarwinFirewireChannel::SetChannelByNumber(int channel) 88 115 { 89 116 // If the tuner is off, try to turn it on. 90 UInt8 power_state; 91 IOReturn err = this->device->GetPowerState(&power_state); 92 if (err == kIOReturnSuccess && power_state == kAVCPowerStateOff) 117 if (FirewireDevice::kAVCPowerOff == GetPowerState()) 93 118 { 94 this->device->SetPowerState(kAVCPowerStateOn);119 SetPowerState(true); 95 120 96 121 // Give it time to power up. 97 122 usleep(2000000); // Sleep for two seconds … … 101 126 err = panel.Tune(channel); 102 127 if (err != kIOReturnSuccess) 103 128 { 104 VERBOSE(VB_GENERAL, QString("DarwinFirewireChannel: Tuning failed: %1").arg(err,0,16)); 105 VERBOSE(VB_GENERAL, QString("Ignoring error per apple example")); 129 VERBOSE(VB_GENERAL, LOC_ERR + 130 QString("Tuning failed: %1").arg(err,0,16) + 131 QString("Ignoring error per apple example")); 106 132 } 133 107 134 // Give it time to transition. 108 135 usleep(1000000); // Sleep for one second 136 109 137 return true; 110 138 } -
libs/libmythtv/firewiresignalmonitor.cpp
1 // -*- Mode: c++ -*- 2 // Copyright (c) 2006, Daniel Thor Kristjansson 3 4 #include <pthread.h> 5 #include <fcntl.h> 6 #include <unistd.h> 7 #include <sys/select.h> 8 9 #include "mythcontext.h" 10 #include "mythdbcon.h" 11 #include "firewiresignalmonitor.h" 12 #include "atscstreamdata.h" 13 #include "mpegtables.h" 14 #include "atsctables.h" 15 16 #include "firewirechannelbase.h" 17 18 #include "firewirechannel.h" 19 20 #define LOC QString("FireSM(%1): ").arg(channel->GetDevice()) 21 #define LOC_WARN QString("FireSM(%1), Warning: ").arg(channel->GetDevice()) 22 #define LOC_ERR QString("FireSM(%1), Error: ").arg(channel->GetDevice()) 23 24 const uint FirewireSignalMonitor::kPowerTimeout = 3000; /* ms */ 25 const uint FirewireSignalMonitor::kBufferTimeout = 5000; /* ms */ 26 27 QMap<void*,uint> FirewireSignalMonitor::pat_keys; 28 QMutex FirewireSignalMonitor::pat_keys_lock; 29 30 /** \fn FirewireSignalMonitor::FirewireSignalMonitor(int,FirewireChannel*,uint,const char*) 31 * \brief Initializes signal lock and signal values. 32 * 33 * Start() must be called to actually begin continuous 34 * signal monitoring. The timeout is set to 3 seconds, 35 * and the signal threshold is initialized to 0%. 36 * 37 * \param db_cardnum Recorder number to monitor, 38 * if this is less than 0, SIGNAL events will not be 39 * sent to the frontend even if SetNotifyFrontend(true) 40 * is called. 41 * \param _channel FirewireChannel for card 42 * \param _flags Flags to start with 43 * \param _name Name for Qt signal debugging 44 */ 45 FirewireSignalMonitor::FirewireSignalMonitor( 46 int db_cardnum, 47 FirewireChannelBase *_channel, 48 uint _flags, const char *_name) : 49 DTVSignalMonitor(db_cardnum, _channel, _flags, _name), 50 dtvMonitorRunning(false), 51 stb_needs_retune(true), 52 stb_needs_to_wait_for_pat(false), 53 stb_needs_to_wait_for_power(false) 54 { 55 VERBOSE(VB_CHANNEL, LOC + "ctor"); 56 57 signalStrength.SetThreshold(65); 58 59 AddFlags(kDTVSigMon_WaitForSig); 60 61 stb_needs_retune = 62 (FirewireDevice::kAVCPowerOff == _channel->GetPowerState()); 63 } 64 65 /** \fn FirewireSignalMonitor::~FirewireSignalMonitor() 66 * \brief Stops signal monitoring and table monitoring threads. 67 */ 68 FirewireSignalMonitor::~FirewireSignalMonitor() 69 { 70 VERBOSE(VB_CHANNEL, LOC + "dtor"); 71 Stop(); 72 } 73 74 void FirewireSignalMonitor::deleteLater(void) 75 { 76 disconnect(); // disconnect signals we may be sending... 77 Stop(); 78 DTVSignalMonitor::deleteLater(); 79 } 80 81 /** \fn FirewireSignalMonitor::Stop(void) 82 * \brief Stop signal monitoring and table monitoring threads. 83 */ 84 void FirewireSignalMonitor::Stop(void) 85 { 86 VERBOSE(VB_CHANNEL, LOC + "Stop() -- begin"); 87 SignalMonitor::Stop(); 88 if (dtvMonitorRunning) 89 { 90 dtvMonitorRunning = false; 91 pthread_join(table_monitor_thread, NULL); 92 } 93 VERBOSE(VB_CHANNEL, LOC + "Stop() -- end"); 94 } 95 96 void FirewireSignalMonitor::HandlePAT(const ProgramAssociationTable *pat) 97 { 98 AddFlags(kDTVSigMon_PATSeen); 99 100 { 101 QMutexLocker locker(&pat_keys_lock); 102 const uint crc = pat_keys[channel]; 103 104 VERBOSE(VB_CHANNEL, LOC + "HandlePAT() CRC: 0x" 105 <<hex<<pat->CalcCRC()<<"|0x"<<crc<<dec); 106 107 bool crc_bogus = (pat->CalcCRC() == crc); 108 if (crc_bogus && stb_needs_to_wait_for_pat && 109 (stb_wait_for_pat_timer.elapsed() < kBufferTimeout)) 110 { 111 VERBOSE(VB_CHANNEL, LOC + "HandlePAT() ignoring PAT"); 112 uint tsid = pat->TransportStreamID(); 113 GetStreamData()->SetVersionPAT(tsid, -1,0); 114 return; 115 } 116 117 if (crc_bogus && stb_needs_to_wait_for_pat) 118 { 119 VERBOSE(VB_IMPORTANT, LOC_WARN + "Wait for valid PAT timed out"); 120 stb_needs_to_wait_for_pat = false; 121 } 122 123 pat_keys[channel] = pat->CalcCRC(); 124 } 125 126 DTVSignalMonitor::HandlePAT(pat); 127 } 128 129 void FirewireSignalMonitor::HandlePMT(uint pnum, const ProgramMapTable *pmt) 130 { 131 VERBOSE(VB_CHANNEL, LOC + "HandlePMT()"); 132 133 AddFlags(kDTVSigMon_PMTSeen); 134 135 if (!HasFlags(kDTVSigMon_PATMatch)) 136 { 137 GetStreamData()->SetVersionPMT(pnum, -1,0); 138 VERBOSE(VB_CHANNEL, LOC + "HandlePMT() ignoring PMT"); 139 return; 140 } 141 142 DTVSignalMonitor::HandlePMT(pnum, pmt); 143 } 144 145 void *FirewireSignalMonitor::TableMonitorThread(void *param) 146 { 147 FirewireSignalMonitor *mon = (FirewireSignalMonitor*) param; 148 mon->RunTableMonitor(); 149 return NULL; 150 } 151 152 void FirewireSignalMonitor::RunTableMonitor(void) 153 { 154 stb_needs_to_wait_for_pat = true; 155 stb_wait_for_pat_timer.start(); 156 dtvMonitorRunning = true; 157 158 VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- begin"); 159 160 LinuxFirewireChannel *lchan = dynamic_cast<LinuxFirewireChannel*>(channel); 161 if (!lchan) 162 { 163 VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- err end"); 164 dtvMonitorRunning = false; 165 return; 166 } 167 168 LinuxFirewireDevice *dev = lchan->GetFirewireDevice(); 169 170 dev->OpenPort(); 171 dev->AddListener(this); 172 173 while (dtvMonitorRunning && GetStreamData()) 174 usleep(100000); 175 176 VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- shutdown "); 177 178 dev->RemoveListener(this); 179 dev->ClosePort(); 180 181 dtvMonitorRunning = false; 182 183 VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- end"); 184 } 185 186 void FirewireSignalMonitor::AddData(const unsigned char *data, uint len) 187 { 188 if (!dtvMonitorRunning) 189 return; 190 191 if (GetStreamData()) 192 GetStreamData()->ProcessData((unsigned char *)data, len); 193 } 194 195 /** \fn FirewireSignalMonitor::UpdateValues(void) 196 * \brief Fills in frontend stats and emits status Qt signals. 197 * 198 * This function uses five ioctl's FE_READ_SNR, FE_READ_SIGNAL_STRENGTH 199 * FE_READ_BER, FE_READ_UNCORRECTED_BLOCKS, and FE_READ_STATUS to obtain 200 * statistics from the frontend. 201 * 202 * This is automatically called by MonitorLoop(), after Start() 203 * has been used to start the signal monitoring thread. 204 */ 205 void FirewireSignalMonitor::UpdateValues(void) 206 { 207 if (!running || exit) 208 return; 209 210 if (dtvMonitorRunning) 211 { 212 EmitFirewireSignals(); 213 if (IsAllGood()) 214 emit AllGood(); 215 // TODO dtv signals... 216 217 update_done = true; 218 return; 219 } 220 221 if (stb_needs_to_wait_for_power && 222 (stb_wait_for_power_timer.elapsed() < (int)kPowerTimeout)) 223 { 224 return; 225 } 226 stb_needs_to_wait_for_power = false; 227 228 FirewireChannelBase *fwchan = dynamic_cast<FirewireChannelBase*>(channel); 229 230 if (HasFlags(kFWSigMon_WaitForPower) && !HasFlags(kFWSigMon_PowerMatch)) 231 { 232 FirewireDevice::PowerState power = fwchan->GetPowerState(); 233 if (FirewireDevice::kAVCPowerOn == power) 234 { 235 AddFlags(kFWSigMon_PowerSeen | kFWSigMon_PowerMatch); 236 } 237 else if (FirewireDevice::kAVCPowerOff == power) 238 { 239 AddFlags(kFWSigMon_PowerSeen); 240 fwchan->SetPowerState(true); 241 stb_wait_for_power_timer.start(); 242 stb_needs_to_wait_for_power = true; 243 } 244 } 245 246 bool isLocked = !HasFlags(kFWSigMon_WaitForPower) || 247 HasFlags(kFWSigMon_WaitForPower | kFWSigMon_PowerMatch); 248 249 if (isLocked && stb_needs_retune) 250 { 251 fwchan->Retune(); 252 isLocked = stb_needs_retune = false; 253 } 254 255 // Set SignalMonitorValues from info from card. 256 { 257 QMutexLocker locker(&statusLock); 258 signalStrength.SetValue(isLocked ? 100 : 0); 259 signalLock.SetValue(isLocked ? 1 : 0); 260 } 261 262 EmitFirewireSignals(); 263 if (IsAllGood()) 264 emit AllGood(); 265 266 // Start table monitoring if we are waiting on any table 267 // and we have a lock. 268 if (isLocked && GetStreamData() && 269 HasAnyFlag(kDTVSigMon_WaitForPAT | kDTVSigMon_WaitForPMT | 270 kDTVSigMon_WaitForMGT | kDTVSigMon_WaitForVCT | 271 kDTVSigMon_WaitForNIT | kDTVSigMon_WaitForSDT)) 272 { 273 pthread_create(&table_monitor_thread, NULL, 274 TableMonitorThread, this); 275 276 VERBOSE(VB_CHANNEL, LOC + "UpdateValues() -- " 277 "Waiting for table monitor to start"); 278 279 while (!dtvMonitorRunning) 280 usleep(50); 281 282 VERBOSE(VB_CHANNEL, LOC + "UpdateValues() -- " 283 "Table monitor started"); 284 } 285 286 update_done = true; 287 } 288 289 #define EMIT(SIGNAL_FUNC, SIGNAL_VAL) \ 290 do { statusLock.lock(); \ 291 SignalMonitorValue val = SIGNAL_VAL; \ 292 statusLock.unlock(); \ 293 emit SIGNAL_FUNC(val); } while (false) 294 295 /** \fn FirewireSignalMonitor::EmitFirewireSignals(void) 296 * \brief Emits signals for lock, signal strength, etc. 297 */ 298 void FirewireSignalMonitor::EmitFirewireSignals(void) 299 { 300 // Emit signals.. 301 EMIT(StatusSignalLock, signalLock); 302 if (HasFlags(kDTVSigMon_WaitForSig)) 303 EMIT(StatusSignalStrength, signalStrength); 304 } 305 306 #undef EMIT -
libs/libmythtv/darwinfirewirechannel.h
24 24 public: 25 25 DarwinFirewireChannel(FireWireDBOptions const&, TVRec *parent); 26 26 27 // Sets 28 virtual bool SetChannelByNumber(int channel); 29 virtual bool SetPowerState(bool on); 30 27 31 // Gets 28 AVS::AVCDevice* GetAVCDevice() const; 32 AVS::AVCDevice* GetAVCDevice(void) const; 33 virtual FirewireDevice::PowerState GetPowerState(void) const; 29 34 30 // Sets31 bool SetChannelByNumber(int channel);32 33 35 private: 34 bool OpenFirewire();35 v oid CloseFirewire();36 virtual bool OpenFirewire(void); 37 virtual void CloseFirewire(void); 36 38 37 39 private: 38 40 AVS::AVCDeviceController* device_controller; -
libs/libmythtv/signalmonitor.cpp
34 34 # include "iptvchannel.h" 35 35 #endif 36 36 37 #ifdef USING_FIREWIRE 38 # include "firewiresignalmonitor.h" 39 # include "firewirechannelbase.h" 40 #endif 41 37 42 #undef DBG_SM 38 43 #define DBG_SM(FUNC, MSG) VERBOSE(VB_CHANNEL, \ 39 44 "SM("<<channel->GetDevice()<<")::"<<FUNC<<": "<<MSG); … … 117 122 } 118 123 #endif 119 124 125 #ifdef USING_FIREWIRE 126 if (cardtype.upper() == "FIREWIRE") 127 { 128 FirewireChannelBase *fc = dynamic_cast<FirewireChannelBase*>(channel); 129 if (fc) 130 signalMonitor = new FirewireSignalMonitor(db_cardnum, fc); 131 } 132 #endif 133 120 134 if (!signalMonitor) 121 135 { 122 136 VERBOSE(VB_IMPORTANT, -
libs/libmythtv/firewiresignalmonitor.h
1 // -*- Mode: c++ -*- 2 3 #ifndef _FIREWIRESIGNALMONITOR_H_ 4 #define _FIREWIRESIGNALMONITOR_H_ 5 6 #include <qmap.h> 7 #include <qmutex.h> 8 #include <qdatetime.h> 9 10 #include "dtvsignalmonitor.h" 11 #include "linuxfirewiredevice.h" 12 #include "util.h" 13 14 class FirewireChannelBase; 15 16 class FirewireSignalMonitor : public DTVSignalMonitor, public TSDataListener 17 { 18 Q_OBJECT 19 20 public: 21 FirewireSignalMonitor(int db_cardnum, FirewireChannelBase* _channel, 22 uint _flags = kFWSigMon_WaitForPower, 23 const char *_name = "FirewireSignalMonitor"); 24 25 virtual void HandlePAT(const ProgramAssociationTable*); 26 virtual void HandlePMT(uint, const ProgramMapTable*); 27 28 void Stop(void); 29 30 public slots: 31 void deleteLater(void); 32 33 protected: 34 FirewireSignalMonitor(void); 35 FirewireSignalMonitor(const FirewireSignalMonitor&); 36 virtual ~FirewireSignalMonitor(); 37 38 virtual void UpdateValues(void); 39 void EmitFirewireSignals(void); 40 41 static void *TableMonitorThread(void *param); 42 void RunTableMonitor(void); 43 44 bool SupportsTSMonitoring(void); 45 46 void AddData(const unsigned char *data, uint dataSize); 47 48 public: 49 static const uint kPowerTimeout; 50 static const uint kBufferTimeout; 51 52 protected: 53 bool dtvMonitorRunning; 54 pthread_t table_monitor_thread; 55 bool stb_needs_retune; 56 bool stb_needs_to_wait_for_pat; 57 bool stb_needs_to_wait_for_power; 58 MythTimer stb_wait_for_pat_timer; 59 MythTimer stb_wait_for_power_timer; 60 61 vector<unsigned char> buffer; 62 63 static QMap<void*,uint> pat_keys; 64 static QMutex pat_keys_lock; 65 }; 66 67 #endif // _FIREWIRESIGNALMONITOR_H_ -
libs/libmythtv/darwinfirewirerecorder.h
33 33 class DarwinFirewireRecorder : public FirewireRecorderBase 34 34 { 35 35 public: 36 DarwinFirewireRecorder(TVRec *rec, ChannelBase* tuner);36 DarwinFirewireRecorder(TVRec *rec, DarwinFirewireChannel *channel); 37 37 ~DarwinFirewireRecorder(); 38 38 39 39 bool Open(void); 40 40 41 void SetOption(const QString &name, const QString &value);42 void SetOption(const QString &name, int value);43 44 41 private: 45 42 void Close(); 46 43 47 44 void start(); 48 45 void stop(); 49 46 void no_data(); 50 bool grab_frames();51 47 52 48 static IOReturn MPEGNoData(void* pRefCon); 53 49 static IOReturn tspacket_callback(UInt32 tsPacketCount, UInt32 **ppBuf, void *pRefCon); -
libs/libmythtv/firewirechannel.h
5 5 * Distributed as part of MythTV under GPL v2 and later. 6 6 */ 7 7 8 #ifndef _LINUX_FIREWIRE_CHANNEL_H_ 9 #define _LINUX_FIREWIRE_CHANNEL_H_ 8 10 9 #ifndef FIREWIRECHANNEL_H10 #define FIREWIRECHANNEL_H11 12 11 #include <qstring.h> 13 12 #include "tv_rec.h" 14 13 #include "firewirechannelbase.h" 15 #include <libavc1394/avc1394.h>16 14 17 15 using namespace std; 18 16 19 class FirewireChannel : public FirewireChannelBase 17 class LinuxFirewireDevice; 18 19 class LinuxFirewireChannel : public FirewireChannelBase 20 20 { 21 21 public: 22 enum PowerState { 23 On, 24 Off, 25 Failed 26 }; 22 LinuxFirewireChannel(FireWireDBOptions firewire_opts, TVRec *parent); 23 ~LinuxFirewireChannel(void); 27 24 28 FirewireChannel(FireWireDBOptions firewire_opts, TVRec *parent);29 ~FirewireChannel(void);25 // Commands 26 virtual bool Retune(void); 30 27 31 bool OpenFirewire(void);32 void CloseFirewire(void);33 34 28 // Sets 35 v oid SetExternalChanger(void);36 bool SetChannelByNumber(int channel);29 virtual bool SetChannelByNumber(int channel); 30 virtual bool SetPowerState(bool on); 37 31 38 32 // Gets 39 bool IsOpen(void) const { return isopen; } 40 QString GetDevice(void) const 33 virtual QString GetDevice(void) const 41 34 { return QString("%1:%2").arg(fw_opts.port).arg(fw_opts.node); } 42 PowerState GetPowerState(void); 35 virtual LinuxFirewireDevice *GetFirewireDevice(void) 36 { return device; } 37 virtual FirewireDevice::PowerState GetPowerState(void) const; 43 38 44 39 private: 45 FireWireDBOptions fw_opts; 46 nodeid_t fwnode; 47 raw1394handle_t fwhandle; 40 virtual bool OpenFirewire(void); 41 virtual void CloseFirewire(void); 42 43 private: 44 FireWireDBOptions fw_opts; 45 LinuxFirewireDevice *device; 46 uint current_channel; 47 bool is_port_open; 48 48 }; 49 49 50 #endif 50 #endif // _LINUX_FIREWIRE_CHANNEL_H_ -
libs/libmythtv/firewirechannelbase.cpp
5 5 */ 6 6 7 7 8 #include <iostream>8 #include "mythconfig.h" // for CONFIG_DARWIN 9 9 #include "mythcontext.h" 10 10 #include "firewirechannelbase.h" 11 #include "tv_rec.h" 11 12 13 #ifdef CONFIG_DARWIN 14 # include "darwinfirewirechannel.h" 15 #else 16 # include "firewirechannel.h" 17 #endif 18 19 FirewireChannelBase *FirewireChannelBase::Init( 20 const FireWireDBOptions &firewire_opts, TVRec *parent) 21 { 22 #ifdef CONFIG_DARWIN 23 return new DarwinFirewireChannel(firewire_opts, parent); 24 #else 25 return new LinuxFirewireChannel(firewire_opts, parent); 26 #endif 27 } 28 12 29 bool FirewireChannelBase::SetChannelByString(const QString &chan) 13 30 { 14 31 inputs[currentInputID]->startChanNum = chan; … … 22 39 return isopen && SetChannelByNumber(chan.toInt()); 23 40 } 24 41 25 bool FirewireChannelBase::Open( )42 bool FirewireChannelBase::Open(void) 26 43 { 27 44 if (!InitializeInputs()) 28 45 return false; … … 39 56 return true; 40 57 } 41 58 42 void FirewireChannelBase::Close( )59 void FirewireChannelBase::Close(void) 43 60 { 44 61 if (isopen) 45 62 CloseFirewire(); -
libs/libmythtv/linuxfirewiredevice.h
1 /** 2 * LinuxFirewireDevice 3 * Copyright (c) 2005 by Jim Westfall 4 * Distributed as part of MythTV under GPL v2 and later. 5 */ 6 7 #ifndef _LINUX_FIREWIRE_DEVICE_H_ 8 #define _LINUX_FIREWIRE_DEVICE_H_ 9 10 #include "firewiredevice.h" 11 12 class FWPriv; 13 14 class LinuxFirewireDevice : public FirewireDevice 15 { 16 public: 17 18 LinuxFirewireDevice(uint port, uint node, uint speed, bool use_p2p, 19 uint av_buffer_size_in_bytes = 0); 20 ~LinuxFirewireDevice(); 21 22 bool OpenPort(void); 23 bool ClosePort(void); 24 25 void AddListener(TSDataListener*); 26 void RemoveListener(TSDataListener*); 27 28 // Sets 29 bool SetPowerState(bool on); 30 bool SetChannel(const QString &panel_model, uint channel); 31 32 // Gets 33 bool IsPortOpen(void) const; 34 bool IsNodeOpen(void) const; 35 bool IsAVStreamOpen(void) const; 36 bool IsTuner(void) const; 37 bool IsPanel(void) const; 38 bool IsSTB(void) const { return IsTuner() && IsPanel(); } 39 40 // non-const Gets 41 PowerState GetPowerState(void); 42 43 // Commands 44 bool ResetBus(void); 45 46 void RunStreaming(void); 47 bool LoopIteration(uint timeout_in_msec); 48 49 void PrintDropped(uint dropped_packets); 50 void BroadcastToListeners(const unsigned char *data, uint dataSize); 51 52 // Statics 53 static inline bool IsSTBSupported(const QString &model); 54 55 // Constants 56 static const uint kBroadcastChannel; 57 static const uint kConnectionP2P; 58 static const uint kConnectionBroadcast; 59 static const uint kMaxBufferedPackets; 60 61 private: 62 bool OpenNode(void); 63 bool CloseNode(void); 64 65 bool OpenAVStream(void); 66 bool CloseAVStream(void); 67 68 bool OpenP2PNode(void); 69 bool CloseP2PNode(void); 70 71 bool OpenBroadcastNode(void); 72 bool CloseBroadcastNode(void); 73 74 bool StartStreaming(void); 75 bool StopStreaming(void); 76 bool StopStreamingLater(void); 77 78 bool SetAVStreamBufferSize(uint size_in_bytes); 79 bool SetAVStreamSpeed(uint speed); 80 81 bool IsSubunitType(uint subunit_type) const; 82 83 private: 84 uint m_port; 85 uint m_node; 86 uint m_speed; 87 uint m_bufsz; 88 bool m_use_p2p; 89 uint m_open_port_cnt; 90 FWPriv *m_priv; 91 vector<TSDataListener*> m_listeners; 92 }; 93 94 inline bool LinuxFirewireDevice::IsSTBSupported(const QString &panel_model) 95 { 96 QString model = panel_model.upper(); 97 return ((model == "DCT-6200") || 98 (model == "SA3250HD") || 99 (model == "SA4200HD")); 100 } 101 102 #endif // _LINUX_FIREWIRE_DEVICE_H_ -
libs/libmythtv/dtvsignalmonitor.h
83 83 bool WaitForLock(int timeout=-1); 84 84 85 85 // MPEG 86 v oid HandlePAT(const ProgramAssociationTable*);87 v oid HandleCAT(const ConditionalAccessTable*) {}88 v oid HandlePMT(uint, const ProgramMapTable*);86 virtual void HandlePAT(const ProgramAssociationTable*); 87 virtual void HandleCAT(const ConditionalAccessTable*) {} 88 virtual void HandlePMT(uint, const ProgramMapTable*); 89 89 90 90 // ATSC Main 91 91 void HandleSTT(const SystemTimeTable*) {} -
libs/libmythtv/tv_rec.cpp
48 48 #include "dbox2channel.h" 49 49 #include "hdhrchannel.h" 50 50 #include "iptvchannel.h" 51 #include "firewirechannelbase.h" 51 52 52 53 #include "recorderbase.h" 53 54 #include "NuppelVideoRecorder.h" … … 57 58 #include "dbox2recorder.h" 58 59 #include "hdhrrecorder.h" 59 60 #include "iptvrecorder.h" 61 #include "firewirerecorderbase.h" 60 62 61 63 #ifdef USING_V4L 62 64 #include "channel.h" 63 65 #endif 64 66 65 #ifdef USING_FIREWIRE66 #ifdef CONFIG_DARWIN67 #include "darwinfirewirerecorder.h"68 #include "darwinfirewirechannel.h"69 #else70 #include "firewirerecorder.h"71 #include "firewirechannel.h"72 #endif73 #endif74 75 67 #define DEBUG_CHANNEL_PREFIX 0 /**< set to 1 to channel prefixing */ 76 68 77 69 #define LOC QString("TVRec(%1): ").arg(cardid) … … 158 150 else if (genOpt.cardtype == "FIREWIRE") 159 151 { 160 152 #ifdef USING_FIREWIRE 161 # ifdef CONFIG_DARWIN 162 channel = new DarwinFirewireChannel(fwOpt, this); 163 # else 164 channel = new FirewireChannel(fwOpt, this); 165 # endif 166 if (!channel->Open()) 153 channel = FirewireChannelBase::Init(fwOpt, this); 154 if (!channel || !channel->Open()) 167 155 return false; 168 156 InitChannel(genOpt.defaultinput, startchannel); 169 157 init_run = true; … … 831 819 else if (genOpt.cardtype == "FIREWIRE") 832 820 { 833 821 #ifdef USING_FIREWIRE 834 # ifdef CONFIG_DARWIN 835 recorder = new DarwinFirewireRecorder(this, this->channel); 836 # else 837 recorder = new FirewireRecorder(this); 838 recorder->SetOption("port", fwOpt.port); 839 recorder->SetOption("node", fwOpt.node); 840 recorder->SetOption("speed", fwOpt.speed); 841 recorder->SetOption("model", fwOpt.model); 842 recorder->SetOption("connection", fwOpt.connection); 843 # endif // !CONFIG_DARWIN 822 recorder = FirewireRecorderBase::Init(this, GetFirewireChannel()); 823 if (recorder) 824 { 825 recorder->SetOption("port", fwOpt.port); 826 recorder->SetOption("node", fwOpt.node); 827 recorder->SetOption("speed", fwOpt.speed); 828 recorder->SetOption("model", fwOpt.model); 829 recorder->SetOption("connection", fwOpt.connection); 830 } 844 831 #endif // USING_FIREWIRE 845 832 } 846 833 else if (genOpt.cardtype == "DBOX2") … … 1114 1101 #endif // USING_DVB 1115 1102 } 1116 1103 1104 FirewireChannelBase *TVRec::GetFirewireChannel(void) 1105 { 1106 #ifdef USING_FIREWIRE 1107 return dynamic_cast<FirewireChannelBase*>(channel); 1108 #else 1109 return NULL; 1110 #endif // USING_FIREWIRE 1111 } 1112 1117 1113 Channel *TVRec::GetV4LChannel(void) 1118 1114 { 1119 1115 #ifdef USING_V4L -
libs/libmythtv/tv_rec.h
35 35 class DBox2Channel; 36 36 class DTVChannel; 37 37 class DVBChannel; 38 class FirewireChannelBase; 38 39 class Channel; 39 40 class HDHRChannel; 40 41 … … 261 262 DTVChannel *GetDTVChannel(void); 262 263 HDHRChannel *GetHDHRChannel(void); 263 264 DVBChannel *GetDVBChannel(void); 265 FirewireChannelBase *GetFirewireChannel(void); 264 266 Channel *GetV4LChannel(void); 265 267 266 268 bool SetupSignalMonitor(bool enable_table_monitoring, bool notify); -
libs/libmythtv/firewiredevice.h
1 /** 2 * FirewireDevice 3 * Copyright (c) 2005 by Jim Westfall 4 * Distributed as part of MythTV under GPL v2 and later. 5 */ 6 7 #ifndef _FIREWIRE_DEVICE_H_ 8 #define _FIREWIRE_DEVICE_H_ 9 10 // C++ headers 11 #include <vector> 12 using namespace std; 13 14 #include <qstring.h> 15 16 class TSDataListener 17 { 18 public: 19 /// Callback function to add MPEG2 TS data 20 virtual void AddData(const unsigned char *data, uint dataSize) = 0; 21 22 protected: 23 virtual ~TSDataListener() { } 24 }; 25 26 class FirewireDevice 27 { 28 public: 29 // Public enums 30 typedef enum 31 { 32 kAVCPowerOn, 33 kAVCPowerOff, 34 kAVCPowerUnknown, 35 kAVCPowerQueryFailed, 36 } PowerState; 37 }; 38 39 #endif // _FIREWIRE_DEVICE_H_ -
libs/libmythtv/linuxfirewiredevice.cpp
1 /** 2 * LinuxFirewireDevice 3 * Copyright (c) 2005 by Jim Westfall 4 * Copyright (c) 2006 by Daniel Kristjansson 5 * SA3250HD support Copyright (c) 2005 by Matt Porter 6 * SA4200HD/Alternate 3250 support Copyright (c) 2006 by Chris Ingrassia 7 * Distributed as part of MythTV under GPL v2 and later. 8 */ 9 10 // POSIX headers 11 #include <pthread.h> 12 #include <sys/select.h> 13 14 // Linux headers 15 #include <libraw1394/raw1394.h> 16 #include <libiec61883/iec61883.h> 17 #include <libavc1394/avc1394.h> 18 19 // C++ headers 20 #include <algorithm> 21 using namespace std; 22 23 // Qt headers 24 #include <qdatetime.h> 25 26 // MythTV headers 27 #include "linuxfirewiredevice.h" 28 #include "firewirerecorder.h" 29 #include "mythcontext.h" 30 31 #define LOC QString("FireDev(%1:%2): ").arg(m_port).arg(m_node) 32 #define LOC_WARN QString("FireDev(%1:%2), Warning: ").arg(m_port).arg(m_node) 33 #define LOC_ERR QString("FireDev(%1:%2), Error: ").arg(m_port).arg(m_node) 34 35 36 #ifndef AVC1394_PANEL_COMMAND_PASS_THROUGH 37 #define AVC1394_PANEL_COMMAND_PASS_THROUGH 0x000007C00 38 #endif 39 40 #ifndef AVC1394_PANEL_OPERATION_0 41 #define AVC1394_PANEL_OPERATION_0 0x000000020 42 #endif 43 44 #define AVC1394_CMD_OPERAND_POWER_STATE 0x7F 45 46 // Basic Panel commands 47 #define PANEL_CMD0 (AVC1394_CTYPE_CONTROL | \ 48 AVC1394_SUBUNIT_TYPE_PANEL | \ 49 AVC1394_SUBUNIT_ID_0 | \ 50 AVC1394_PANEL_COMMAND_PASS_THROUGH) 51 52 // Scientific Atlanta defines 53 #define AVC1394_SA3250_OPERAND_KEY_PRESS 0xE7 54 #define AVC1394_SA3250_OPERAND_KEY_RELEASE 0x67 55 #define SA_CMD0 PANEL_CMD0 56 #define SA_CMD1 AVC1394_CTYPE_GENERAL_INQUIRY 57 #define SA_CMD2 0xff000000 58 59 // Motorola defines 60 #define MOT_CMD0 (PANEL_CMD0 | AVC1394_PANEL_OPERATION_0) 61 62 class FWPriv 63 { 64 public: 65 FWPriv() : 66 handle(0), avstream(0), 67 channel(-1), 68 is_p2p_node_open(false), is_bcast_node_open(false), 69 is_streaming(false), stop_streaming_timer_on(false) 70 { 71 bzero(unit_table, sizeof(unit_table)); 72 } 73 74 raw1394handle_t handle; 75 iec61883_mpeg2_t avstream; 76 quadlet_t unit_table[8]; 77 int channel; 78 int open_node; 79 bool is_p2p_node_open; 80 bool is_bcast_node_open; 81 bool is_streaming; 82 bool is_streaming_running; 83 bool stop_streaming_timer_on; 84 QDateTime stop_streaming_timer; 85 pthread_t streaming_thread; 86 }; 87 88 const uint LinuxFirewireDevice::kBroadcastChannel = 63; 89 const uint LinuxFirewireDevice::kConnectionP2P = 0; 90 const uint LinuxFirewireDevice::kConnectionBroadcast = 1; 91 const uint LinuxFirewireDevice::kMaxBufferedPackets = 2000; 92 93 // callback function for libiec61883 94 static int fw_tspacket_handler(unsigned char *tspacket, int len, 95 uint dropped, void *callback_data); 96 static QString speed_to_string(uint speed); 97 static quadlet_t *send_avc_command(raw1394handle_t handle, 98 uint node, 99 quadlet_t *cmd, 100 uint cmd_len, 101 uint retry_cnt = 1); 102 static void close_avc_command(raw1394handle_t handle); 103 104 105 LinuxFirewireDevice::LinuxFirewireDevice( 106 uint port, uint node, uint speed, bool use_p2p, 107 uint av_buffer_size_in_bytes) : 108 m_port(port), m_node(node), 109 m_speed(speed), m_bufsz(av_buffer_size_in_bytes), 110 m_use_p2p(use_p2p), 111 m_open_port_cnt(0), m_priv(new FWPriv()) 112 { 113 if (!m_bufsz) 114 m_bufsz = gContext->GetNumSetting("HDRingbufferSize"); 115 } 116 117 LinuxFirewireDevice::~LinuxFirewireDevice() 118 { 119 if (IsPortOpen()) 120 { 121 VERBOSE(VB_IMPORTANT, LOC_ERR + "ctor called with open port"); 122 while (IsPortOpen()) 123 ClosePort(); 124 } 125 126 if (m_priv) 127 { 128 delete m_priv; 129 m_priv = NULL; 130 } 131 } 132 133 bool LinuxFirewireDevice::OpenPort(void) 134 { 135 VERBOSE(VB_RECORD, LOC + "OpenPort()"); 136 137 m_open_port_cnt++; 138 139 if (m_priv->handle) 140 return true; 141 142 VERBOSE(VB_RECORD, LOC + "Getting raw1394 handle "<<(m_open_port_cnt-1)); 143 m_priv->handle = raw1394_new_handle_on_port(m_port); 144 145 if (!m_priv->handle) 146 { 147 VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to get handle for " + 148 QString("port: %1").arg(m_port) + ENO); 149 150 return false; 151 } 152 153 if (avc1394_subunit_info(m_priv->handle, m_node, m_priv->unit_table) < 0) 154 bzero(m_priv->unit_table, sizeof(m_priv->unit_table)); 155 156 QString str = "Subunit Types: "; 157 158 if (IsSubunitType(AVC1394_SUBUNIT_TYPE_VIDEO_MONITOR)) 159 str += "Video Monitor, "; 160 if (IsSubunitType(AVC1394_SUBUNIT_TYPE_AUDIO)) 161 str += "Audio, "; 162 if (IsSubunitType(AVC1394_SUBUNIT_TYPE_PRINTER)) 163 str += "Printer, "; 164 if (IsSubunitType(AVC1394_SUBUNIT_TYPE_DISC_RECORDER)) 165 str += "Disk Recorder, "; 166 if (IsSubunitType(AVC1394_SUBUNIT_TYPE_TAPE_RECORDER)) 167 str += "Tape Recorder, "; 168 if (IsSubunitType(AVC1394_SUBUNIT_TYPE_VCR)) 169 str += "VCR, "; 170 if (IsSubunitType(AVC1394_SUBUNIT_TYPE_TUNER)) 171 str += "Tuner, "; 172 if (IsSubunitType(AVC1394_SUBUNIT_TYPE_CA)) 173 str += "CA, "; 174 if (IsSubunitType(AVC1394_SUBUNIT_TYPE_VIDEO_CAMERA)) 175 str += "Camera, "; 176 if (IsSubunitType(AVC1394_SUBUNIT_TYPE_PANEL)) 177 str += "Panel, "; 178 if (IsSubunitType(AVC1394_SUBUNIT_TYPE_BULLETIN_BOARD)) 179 str += "Bulletin Board, "; 180 if (IsSubunitType(AVC1394_SUBUNIT_TYPE_CAMERA_STORAGE)) 181 str += "Camera Storage, "; 182 if (IsSubunitType(AVC1394_SUBUNIT_TYPE_MUSIC)) 183 str += "Music, "; 184 if (IsSubunitType(AVC1394_SUBUNIT_TYPE_VENDOR_UNIQUE)) 185 str += "Vendor Unique, "; 186 187 VERBOSE(VB_RECORD, LOC + str); 188 189 return true; 190 } 191 192 bool LinuxFirewireDevice::ClosePort(void) 193 { 194 VERBOSE(VB_RECORD, LOC + "ClosePort()"); 195 196 if (m_open_port_cnt < 1) 197 return false; 198 199 m_open_port_cnt--; 200 201 if (m_open_port_cnt != 0) 202 return true; 203 204 if (m_priv->handle) 205 { 206 if (IsNodeOpen()) 207 CloseNode(); 208 209 VERBOSE(VB_RECORD, LOC + "Releasing raw1394 handle "<<m_open_port_cnt); 210 raw1394_destroy_handle(m_priv->handle); 211 m_priv->handle = NULL; 212 } 213 214 return true; 215 } 216 217 bool LinuxFirewireDevice::OpenNode(void) 218 { 219 if (m_use_p2p) 220 return OpenP2PNode(); 221 else 222 return OpenBroadcastNode(); 223 } 224 225 bool LinuxFirewireDevice::CloseNode(void) 226 { 227 if (m_priv->is_p2p_node_open) 228 return CloseP2PNode(); 229 230 if (m_priv->is_bcast_node_open) 231 return CloseBroadcastNode(); 232 233 return true; 234 } 235 236 bool LinuxFirewireDevice::OpenP2PNode(void) 237 { 238 if (m_priv->is_bcast_node_open) 239 return false; 240 241 if (m_priv->is_p2p_node_open) 242 return true; 243 244 VERBOSE(VB_RECORD, LOC + "Opening P2P connection"); 245 246 m_priv->channel = m_node; 247 if (iec61883_cmp_create_p2p_output(m_priv->handle, m_node | 0xffc0, 0, 248 m_priv->channel, m_speed) != 0) 249 { 250 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to create P2P connection"); 251 252 m_priv->channel = -1; 253 return false; 254 } 255 256 m_priv->is_p2p_node_open = true; 257 258 return true; 259 } 260 261 bool LinuxFirewireDevice::CloseP2PNode(void) 262 { 263 if (m_priv->is_p2p_node_open && (m_priv->channel >= 0)) 264 { 265 VERBOSE(VB_RECORD, LOC + "Closing P2P connection"); 266 267 if (m_priv->avstream) 268 CloseAVStream(); 269 270 iec61883_cmp_disconnect(m_priv->handle, m_node | 0xffc0, 0, 271 raw1394_get_local_id(m_priv->handle), 272 -1, m_priv->channel, 0); 273 274 m_priv->channel = -1; 275 m_priv->is_p2p_node_open = false; 276 } 277 278 return true; 279 } 280 281 bool LinuxFirewireDevice::OpenBroadcastNode(void) 282 { 283 if (m_priv->is_p2p_node_open) 284 return false; 285 286 if (m_priv->is_bcast_node_open) 287 return true; 288 289 m_priv->channel = kBroadcastChannel - m_node; 290 291 VERBOSE(VB_RECORD, LOC + "Opening broadcast connection on " + 292 QString("node %1, channel %2") 293 .arg(m_node).arg(m_priv->channel)); 294 295 if (m_priv->avstream) 296 CloseAVStream(); 297 298 int err = iec61883_cmp_create_bcast_output( 299 m_priv->handle, m_node | 0xffc0, 0, m_priv->channel, m_speed); 300 301 if (err != 0) 302 { 303 VERBOSE(VB_IMPORTANT, LOC_ERR + 304 "Failed to create Broadcast connection"); 305 306 m_priv->channel = -1; 307 return false; 308 } 309 310 m_priv->is_bcast_node_open = true; 311 312 return true; 313 } 314 315 bool LinuxFirewireDevice::CloseBroadcastNode(void) 316 { 317 if (m_priv->is_bcast_node_open) 318 { 319 VERBOSE(VB_RECORD, LOC + "Closing broadcast connection"); 320 321 m_priv->channel = -1; 322 m_priv->is_bcast_node_open = false; 323 } 324 return true; 325 } 326 327 bool LinuxFirewireDevice::OpenAVStream(void) 328 { 329 VERBOSE(VB_RECORD, LOC + "OpenAVStream"); 330 331 if (!IsNodeOpen() && !OpenNode()) 332 return false; 333 334 if (m_priv->avstream) 335 return true; 336 337 VERBOSE(VB_RECORD, LOC + "Opening A/V stream object"); 338 339 if (!m_priv->handle) 340 { 341 VERBOSE(VB_IMPORTANT, LOC + 342 "Can not open AVStream without IEEE 1394 Port"); 343 344 return false; 345 } 346 347 m_priv->avstream = iec61883_mpeg2_recv_init( 348 m_priv->handle, fw_tspacket_handler, this); 349 350 if (!m_priv->avstream) 351 { 352 VERBOSE(VB_IMPORTANT, LOC + "Unable to open AVStream" + ENO); 353 354 return false; 355 } 356 357 iec61883_mpeg2_set_synch(m_priv->avstream, 1 /* sync on close */); 358 359 if (m_bufsz) 360 SetAVStreamBufferSize(m_bufsz); 361 362 return true; 363 } 364 365 bool LinuxFirewireDevice::CloseAVStream(void) 366 { 367 if (!m_priv->avstream) 368 return true; 369 370 VERBOSE(VB_RECORD, LOC + "Closing A/V stream object"); 371 372 while (m_listeners.size()) 373 RemoveListener(m_listeners[m_listeners.size() - 1]); 374 375 if (m_priv->is_streaming) 376 StopStreaming(); 377 378 iec61883_mpeg2_close(m_priv->avstream); 379 m_priv->avstream = NULL; 380 381 return true; 382 } 383 384 static void *streaming_thunk(void *param) 385 { 386 LinuxFirewireDevice *mon = (LinuxFirewireDevice*) param; 387 mon->RunStreaming(); 388 return NULL; 389 } 390 391 void LinuxFirewireDevice::RunStreaming(void) 392 { 393 m_priv->is_streaming_running = true; 394 395 uint no_data_cnt = 0; 396 while (m_priv->is_streaming) 397 { 398 if (m_priv->stop_streaming_timer_on) 399 { 400 if (m_priv->stop_streaming_timer < QDateTime::currentDateTime()) 401 break; 402 403 usleep(50000); 404 continue; 405 } 406 407 no_data_cnt = (LoopIteration(250)) ? 0 : no_data_cnt + 1; 408 if (no_data_cnt > 6) 409 { 410 ResetBus(); 411 no_data_cnt = 0; 412 } 413 } 414 415 m_priv->is_streaming_running = false; 416 if (m_priv->stop_streaming_timer_on) 417 { 418 CloseAVStream(); 419 CloseNode(); 420 m_priv->stop_streaming_timer_on = false; 421 } 422 } 423 424 bool LinuxFirewireDevice::StartStreaming(void) 425 { 426 m_priv->stop_streaming_timer_on = false; 427 428 if (m_priv->is_streaming) 429 return m_priv->is_streaming; 430 431 if (!IsAVStreamOpen() && !OpenAVStream()) 432 return false; 433 434 VERBOSE(VB_RECORD, LOC + "Starting A/V streaming"); 435 436 if (!m_priv->avstream) 437 { 438 VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting A/V streaming, no A/V obj"); 439 return false; 440 } 441 442 if (m_priv->channel < 0) 443 { 444 VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting A/V streaming, no channel"); 445 return false; 446 } 447 448 if (iec61883_mpeg2_recv_start(m_priv->avstream, m_priv->channel) == 0) 449 { 450 m_priv->is_streaming = true; 451 452 pthread_create(&m_priv->streaming_thread, NULL, 453 streaming_thunk, this); 454 455 while (!m_priv->is_streaming_running) 456 usleep(50); 457 } 458 else 459 { 460 VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting A/V streaming " + ENO); 461 } 462 463 return m_priv->is_streaming; 464 } 465 466 bool LinuxFirewireDevice::StopStreaming(void) 467 { 468 VERBOSE(VB_RECORD, LOC + "Stopping A/V streaming"); 469 470 if (m_priv->is_streaming) 471 { 472 m_priv->stop_streaming_timer_on = false; 473 m_priv->is_streaming = false; 474 475 pthread_join(m_priv->streaming_thread, NULL); 476 477 iec61883_mpeg2_recv_stop(m_priv->avstream); 478 479 raw1394_iso_recv_flush(m_priv->handle); 480 } 481 482 return true; 483 } 484 485 bool LinuxFirewireDevice::StopStreamingLater(void) 486 { 487 if (m_priv->is_streaming && !m_priv->stop_streaming_timer_on) 488 { 489 m_priv->stop_streaming_timer = 490 QDateTime::currentDateTime().addSecs(2); 491 m_priv->stop_streaming_timer_on = true; 492 } 493 494 return true; 495 } 496 497 bool LinuxFirewireDevice::SetAVStreamBufferSize(uint size_in_bytes) 498 { 499 if (!m_priv->avstream) 500 return false; 501 502 // Set buffered packets size 503 uint buffer_size = max(size_in_bytes, 50 * TSPacket::SIZE); 504 size_t buffered_packets = min(buffer_size / 4, kMaxBufferedPackets); 505 506 iec61883_mpeg2_set_buffers(m_priv->avstream, buffered_packets); 507 508 VERBOSE(VB_IMPORTANT, LOC + 509 QString("Buffered packets %1 (%2 KB)") 510 .arg(buffered_packets).arg(buffered_packets * 4)); 511 512 return true; 513 } 514 515 bool LinuxFirewireDevice::SetAVStreamSpeed(uint speed) 516 { 517 if (!m_priv->avstream) 518 return false; 519 520 uint curspeed = iec61883_mpeg2_get_speed(m_priv->avstream); 521 522 if (curspeed == speed) 523 { 524 m_speed = speed; 525 return true; 526 } 527 528 VERBOSE(VB_RECORD, LOC + 529 QString("Changing Speed %1 -> %2") 530 .arg(speed_to_string(curspeed)) 531 .arg(speed_to_string(m_speed))); 532 533 iec61883_mpeg2_set_speed(m_priv->avstream, speed); 534 535 if (speed == (uint)iec61883_mpeg2_get_speed(m_priv->avstream)) 536 { 537 m_speed = speed; 538 return true; 539 } 540 541 VERBOSE(VB_IMPORTANT, LOC_WARN + "Unable to set firewire speed."); 542 543 return false; 544 } 545 546 bool LinuxFirewireDevice::IsSubunitType(uint subunit_type) const 547 { 548 for (uint i = 0; i < 8; i++) 549 { 550 for (uint j = 0; j < 32; j += 8) 551 { 552 uint subunit = (m_priv->unit_table[i] >> j) & 0xff; 553 if ((subunit != 0xff) && 554 (subunit >> 3) == AVC1394_GET_SUBUNIT_TYPE(subunit_type)) 555 { 556 return true; 557 } 558 } 559 } 560 return false; 561 } 562 563 bool LinuxFirewireDevice::IsTuner(void) const 564 { 565 return IsSubunitType(AVC1394_SUBUNIT_TYPE_TUNER); 566 } 567 568 bool LinuxFirewireDevice::IsPanel(void) const 569 { 570 return IsSubunitType(AVC1394_SUBUNIT_TYPE_PANEL); 571 } 572 573 bool LinuxFirewireDevice::IsPortOpen(void) const 574 { 575 return m_priv->handle; 576 } 577 578 bool LinuxFirewireDevice::IsNodeOpen(void) const 579 { 580 return m_priv->is_p2p_node_open || m_priv->is_bcast_node_open; 581 } 582 583 bool LinuxFirewireDevice::IsAVStreamOpen(void) const 584 { 585 return m_priv->avstream; 586 } 587 588 bool LinuxFirewireDevice::ResetBus(void) 589 { 590 /* 591 VERBOSE(VB_IMPORTANT, LOC + "ResetBus()"); 592 593 bool open_node = IsNodeOpen(); 594 bool open_avstream = IsAVStreamOpen(); 595 bool restart_streaming = m_priv->is_streaming; 596 597 StopStreaming(); 598 CloseAVStream(); 599 CloseNode(); 600 601 bool ok = (raw1394_reset_bus_new(m_priv->handle, RAW1394_LONG_RESET) != 0); 602 if (!ok) 603 VERBOSE(VB_IMPORTANT, LOC_ERR + "Bus Reset failed"); 604 605 if (open_node) 606 ok &= OpenNode(); 607 608 if (open_avstream) 609 ok &= OpenAVStream(); 610 611 if (restart_streaming) 612 ok &= StartStreaming(); 613 614 return ok; 615 */ 616 return true; 617 } 618 619 bool LinuxFirewireDevice::LoopIteration(uint timeout_in_msec) 620 { 621 int fwfd = raw1394_get_fd(m_priv->handle); 622 if (fwfd < 0) 623 return false; 624 625 struct timeval tv; 626 fd_set rfds; 627 628 FD_ZERO(&rfds); 629 FD_SET(fwfd, &rfds); 630 631 tv.tv_sec = timeout_in_msec / 1000; 632 tv.tv_usec = (timeout_in_msec % 1000) * 1000; 633 634 if (select(fwfd + 1, &rfds, NULL, NULL, &tv) <= 0) 635 { 636 VERBOSE(VB_IMPORTANT, LOC + QString("No Input in %1 msec...") 637 .arg(timeout_in_msec)); 638 639 return false; 640 } 641 642 int ret = raw1394_loop_iterate(m_priv->handle); 643 if (ret) 644 { 645 VERBOSE(VB_IMPORTANT, LOC_ERR + "libraw1394_loop_iterate() " + 646 QString("returned %1").arg(ret)); 647 648 return false; 649 } 650 651 return true; 652 } 653 654 void LinuxFirewireDevice::AddListener(TSDataListener *listener) 655 { 656 if (listener) 657 { 658 RemoveListener(listener); 659 m_listeners.push_back(listener); 660 } 661 662 VERBOSE(VB_RECORD, LOC + "AddListener() "<<m_listeners.size()); 663 664 if (!m_listeners.empty()) 665 StartStreaming(); 666 } 667 668 void LinuxFirewireDevice::RemoveListener(TSDataListener *listener) 669 { 670 vector<TSDataListener*>::iterator it = m_listeners.end(); 671 672 uint cnt = 0; 673 674 do 675 { 676 it = find(m_listeners.begin(), m_listeners.end(), listener); 677 if (it != m_listeners.end()) 678 { 679 m_listeners.erase(it); 680 cnt++; 681 } 682 } 683 while (it != m_listeners.end()); 684 685 if (cnt) 686 { 687 VERBOSE(VB_RECORD, LOC + "RemoveListener() "<<m_listeners.size()); 688 689 // if (m_priv->is_streaming && m_listeners.empty()) 690 // StopStreamingLater(); 691 692 if (m_priv->is_streaming && m_listeners.empty()) 693 StopStreaming(); 694 695 CloseAVStream(); 696 CloseNode(); 697 } 698 } 699 700 void LinuxFirewireDevice::BroadcastToListeners( 701 const unsigned char *data, uint dataSize) 702 { 703 vector<TSDataListener*>::iterator it = m_listeners.begin(); 704 for (; it != m_listeners.end(); ++it) 705 (*it)->AddData(data, dataSize); 706 } 707 708 bool LinuxFirewireDevice::SetChannel(const QString &panel_model, uint channel) 709 { 710 if (!IsSTBSupported(panel_model)) 711 { 712 VERBOSE(VB_IMPORTANT, LOC_ERR + 713 QString("Model: '%1' ").arg(panel_model) + 714 "is not supported by internal channel changer."); 715 return false; 716 } 717 718 int digit[3]; 719 digit[0] = (channel % 1000) / 100; 720 digit[1] = (channel % 100) / 10; 721 digit[2] = (channel % 10); 722 723 if (panel_model.upper() == "DCT-6200") 724 { 725 for (uint i = 0; i < 3 ;i++) 726 { 727 quadlet_t cmd[2] = 728 { 729 MOT_CMD0 | AVC1394_PANEL_OPERATION_0 | digit[i], 730 0x0, 731 }; 732 733 if (!send_avc_command(m_priv->handle, m_node, cmd, 2)) 734 return false; 735 736 usleep(500000); 737 } 738 739 return true; 740 } 741 742 if (panel_model.upper() == "SA4200HD") 743 { 744 quadlet_t cmd[3] = 745 { 746 SA_CMD0 | AVC1394_SA3250_OPERAND_KEY_PRESS, 747 SA_CMD1 | (channel << 8), 748 SA_CMD2, 749 }; 750 751 if (!send_avc_command(m_priv->handle, m_node, cmd, 3)) 752 return false; 753 754 return true; 755 } 756 757 if (panel_model == "SA3250HD") 758 { 759 digit[0] |= 0x30; 760 digit[1] |= 0x30; 761 digit[2] |= 0x30; 762 763 quadlet_t cmd[3] = 764 { 765 SA_CMD0 | AVC1394_SA3250_OPERAND_KEY_PRESS, 766 SA_CMD1 | (digit[2] << 16) | (digit[1] << 8) | digit[0], 767 SA_CMD2, 768 }; 769 770 VERBOSE(VB_CHANNEL, LOC + 771 QString("Channel2: %1%2%3 cmds: 0x%4, 0x%5, 0x%6") 772 .arg(digit[0] & 0xf).arg(digit[1] & 0xf) 773 .arg(digit[2] & 0xf) 774 .arg(cmd[0], 0, 16).arg(cmd[1], 0, 16) 775 .arg(cmd[2], 0, 16)); 776 777 if (!send_avc_command(m_priv->handle, m_node, cmd, 3)) 778 return false; 779 780 cmd[0] = SA_CMD0 | AVC1394_SA3250_OPERAND_KEY_RELEASE; 781 cmd[1] = SA_CMD1 | (digit[0] << 16) | (digit[1] << 8) | digit[2]; 782 cmd[2] = SA_CMD2; 783 784 VERBOSE(VB_CHANNEL, LOC + 785 QString("Channel3: %1%2%3 cmds: 0x%4, 0x%5, 0x%6") 786 .arg(digit[0] & 0xf).arg(digit[1] & 0xf) 787 .arg(digit[2] & 0xf) 788 .arg(cmd[0], 0, 16).arg(cmd[1], 0, 16) 789 .arg(cmd[2], 0, 16)); 790 791 if (!send_avc_command(m_priv->handle, m_node, cmd, 3)) 792 return false; 793 794 return true; 795 } 796 797 return false; 798 } 799 800 bool LinuxFirewireDevice::SetPowerState(bool on) 801 { 802 quadlet_t cmd = 803 AVC1394_CTYPE_CONTROL | AVC1394_SUBUNIT_TYPE_UNIT | 804 AVC1394_SUBUNIT_ID_IGNORE | AVC1394_COMMAND_POWER; 805 806 cmd |= (on) ? AVC1394_CMD_OPERAND_POWER_ON : AVC1394_CMD_OPERAND_POWER_OFF; 807 808 QString cmdStr = (on) ? "on" : "off"; 809 VERBOSE(VB_RECORD, LOC + QString("Powering %1 (cmd: 0x%2)") 810 .arg(cmdStr).arg(cmd, 0, 16)); 811 812 quadlet_t *rval = send_avc_command(m_priv->handle, m_node, &cmd, 1); 813 814 if (!rval) 815 { 816 close_avc_command(m_priv->handle); 817 VERBOSE(VB_IMPORTANT, LOC + "Power on cmd failed (no response)"); 818 return false; 819 } 820 821 quadlet_t response = rval[0]; 822 close_avc_command(m_priv->handle); 823 824 if (AVC1394_MASK_RESPONSE(response) != AVC1394_RESPONSE_ACCEPTED) 825 { 826 VERBOSE(VB_IMPORTANT, LOC_ERR + 827 QString("Power %1 cmd failed (0x%2)") 828 .arg(cmdStr).arg(response, 0, 16)); 829 830 return false; 831 } 832 833 VERBOSE(VB_RECORD, LOC + 834 QString("Power %1 cmd sent successfully (0x%2)") 835 .arg(cmdStr).arg(response, 0, 16)); 836 837 return true; 838 } 839 840 FirewireDevice::PowerState LinuxFirewireDevice::GetPowerState(void) 841 { 842 quadlet_t cmd = 843 AVC1394_CTYPE_STATUS | AVC1394_SUBUNIT_TYPE_UNIT | 844 AVC1394_SUBUNIT_ID_IGNORE | AVC1394_COMMAND_POWER | 845 AVC1394_CMD_OPERAND_POWER_STATE; 846 847 VERBOSE(VB_CHANNEL, LOC + QString("Requesting STB Power State (cmd: 0x%1)") 848 .arg(cmd, 0, 16)); 849 850 quadlet_t *rval = send_avc_command(m_priv->handle, m_node, &cmd, 1); 851 852 if (!rval) 853 { 854 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to get STB Power State"); 855 return kAVCPowerQueryFailed; 856 } 857 858 quadlet_t response = rval[0]; 859 // TODO we probably need to call close_avc_command(m_priv->handle)... 860 861 QString loc = LOC + "STB Power State: "; 862 QString rs = QString(" (0x%1)").arg(response, 0, 16); 863 864 if (AVC1394_MASK_RESPONSE(response) != AVC1394_RESPONSE_IMPLEMENTED) 865 { 866 VERBOSE(VB_CHANNEL, loc + "Query not implemented" + rs); 867 return kAVCPowerUnknown; 868 } 869 870 if (AVC1394_MASK_OPERAND0(response) == AVC1394_CMD_OPERAND_POWER_ON) 871 { 872 VERBOSE(VB_CHANNEL, loc + "On" + rs); 873 return kAVCPowerOn; 874 } 875 876 if (AVC1394_MASK_OPERAND0(response) == AVC1394_CMD_OPERAND_POWER_OFF) 877 { 878 VERBOSE(VB_CHANNEL, loc + "Off" + rs); 879 return kAVCPowerOff; 880 } 881 882 VERBOSE(VB_IMPORTANT, LOC_ERR + "STB Power State: Unknown Response" + rs); 883 884 return kAVCPowerUnknown; 885 } 886 887 void LinuxFirewireDevice::PrintDropped(uint dropped_packets) 888 { 889 if (dropped_packets == 1) 890 { 891 VERBOSE(VB_RECORD, LOC_ERR + "Dropped a TS packet"); 892 } 893 else if (dropped_packets > 1) 894 { 895 VERBOSE(VB_RECORD, LOC_ERR + 896 QString("Dropped %1 TS packets").arg(dropped_packets)); 897 } 898 } 899 900 static int fw_tspacket_handler(unsigned char *tspacket, int len, 901 uint dropped, void *callback_data) 902 { 903 LinuxFirewireDevice *fw = (LinuxFirewireDevice*) callback_data; 904 if (!fw) 905 return 0; 906 907 if (dropped) 908 fw->PrintDropped(dropped); 909 910 if (len > 0) 911 fw->BroadcastToListeners(tspacket, len); 912 913 return 1; 914 } 915 916 static QString speed_to_string(uint speed) 917 { 918 if (speed > RAW1394_ISO_SPEED_400) 919 return QString("Invalid Speed (%1)").arg(speed); 920 921 static const uint speeds[] = { 100, 200, 400, }; 922 return QString("%1Mbps").arg(speeds[speed]); 923 } 924 925 static quadlet_t *send_avc_command(raw1394handle_t handle, 926 uint node, 927 quadlet_t *cmd, 928 uint cmd_len, 929 uint retry_cnt) 930 { 931 if (!handle) 932 return NULL; 933 934 quadlet_t *ret = avc1394_transaction_block( 935 handle, node, cmd, cmd_len, retry_cnt); 936 937 if (!ret) 938 VERBOSE(VB_IMPORTANT, "AVC transaction failed."); 939 940 return ret; 941 } 942 943 static void close_avc_command(raw1394handle_t handle) 944 { 945 if (handle) 946 avc1394_transaction_block_close(handle); 947 } 948