Ticket #1648: firewire-sm-v28.patch
| File firewire-sm-v28.patch, 124.5 KB (added by , 20 years ago) |
|---|
-
libs/libmythtv/firewirechannel.cpp
1 1 /** 2 2 * FirewireChannel 3 * Copyright (c) 2005 by Jim Westfall 4 * SA3250HD support Copyright (c) 2005 by Matt Porter 5 * SA4200HD/Alternate 3250 support Copyright (c) 2006 by Chris Ingrassia 3 * Copyright (c) 2005 by Jim Westfall, Dave Abrahams 4 * Copyright (c) 2006 by Daniel Kristjansson 6 5 * Distributed as part of MythTV under GPL v2 and later. 7 6 */ 8 7 9 10 #include <iostream>11 8 #include "mythcontext.h" 9 #include "tv_rec.h" 10 #include "linuxfirewiredevice.h" 11 #include "darwinfirewiredevice.h" 12 12 #include "firewirechannel.h" 13 13 14 class TVRec; 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()) 15 17 16 #define LOC QString("FireChan: ") 17 #define LOC_ERR QString("FireChan, Error: ") 18 19 #ifndef AVC1394_PANEL_COMMAND_PASS_THROUGH 20 #define AVC1394_PANEL_COMMAND_PASS_THROUGH 0x000007C00 18 FirewireChannel::FirewireChannel( 19 const FireWireDBOptions &firewire_opts, TVRec *parent) : 20 DTVChannel(parent), 21 fw_opts(firewire_opts), 22 device(NULL), 23 current_channel(0), 24 is_port_open(false) 25 { 26 #ifdef USING_LINUX_FIREWIRE 27 device = new LinuxFirewireDevice( 28 fw_opts.port, fw_opts.node, fw_opts.speed, 29 LinuxFirewireDevice::kConnectionP2P == 30 (uint) fw_opts.connection); 31 #elif USING_OSX_FIREWIRE 32 device = new DarwinFirewireDevice(); 21 33 #endif 34 } 22 35 23 #ifndef AVC1394_PANEL_OPERATION_0 24 #define AVC1394_PANEL_OPERATION_0 0x000000020 25 #endif 36 bool FirewireChannel::SetChannelByString(const QString &chan) 37 { 38 inputs[currentInputID]->startChanNum = chan; 39 curchannelname = chan; 26 40 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) 41 InputMap::const_iterator it = inputs.find(currentInputID); 32 42 33 // SA3250HD defines 34 #define AVC1394_SA3250_OPERAND_KEY_PRESS 0xE7 35 #define AVC1394_SA3250_OPERAND_KEY_RELEASE 0x67 43 if (!(*it)->externalChanger.isEmpty()) 44 return ChangeExternalChannel(chan); 36 45 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 46 return isopen && SetChannelByNumber(chan.toInt()); 47 } 43 48 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) 49 bool FirewireChannel::Open(void) 50 { 51 if (!InitializeInputs()) 52 return false; 51 53 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) 54 InputMap::const_iterator it = inputs.find(currentInputID); 55 if (!(*it)->externalChanger.isEmpty()) 56 return true; 57 57 58 static bool is_supported(const QString &model) 59 { 60 return ((model == "DCT-6200") || 61 (model == "SA3250HD") || 62 (model == "SA4200HD")); 63 } 58 if (!isopen) 59 isopen = OpenFirewire(); 64 60 65 FirewireChannel::FirewireChannel(FireWireDBOptions firewire_opts, 66 TVRec *parent) 67 : FirewireChannelBase(parent), fw_opts(firewire_opts), fwhandle(NULL) 68 { 61 return isopen; 69 62 } 70 63 71 FirewireChannel::~FirewireChannel(void)64 void FirewireChannel::Close(void) 72 65 { 73 Close(); 66 if (isopen) 67 { 68 CloseFirewire(); 69 isopen = false; 70 } 74 71 } 75 76 bool FirewireChannel:: SetChannelByNumber(int channel)72 73 bool FirewireChannel::OpenFirewire(void) 77 74 { 78 // Change channel using internal changer 75 if (is_port_open) 76 return true; 79 77 80 if (! is_supported(fw_opts.model))78 if (!FirewireDevice::IsSTBSupported(fw_opts.model)) 81 79 { 82 80 VERBOSE(VB_IMPORTANT, LOC_ERR + 83 81 QString("Model: '%1' ").arg(fw_opts.model) + 84 82 "is not supported by internal channel changer."); 83 85 84 return false; 86 85 } 87 86 88 int dig[3]; 89 dig[0] = (channel % 1000) / 100; 90 dig[1] = (channel % 100) / 10; 91 dig[2] = (channel % 10); 87 if (!device) 88 return false; 92 89 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)); 90 if (!device->OpenPort()) 91 return false; 101 92 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") 93 if (!device->IsSTB()) 114 94 { 115 d ig[0] |= 0x30;116 dig[1] |= 0x30;117 dig[2] |= 0x30;95 device->ClosePort(); 96 return false; 97 } 118 98 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 }; 99 is_port_open = true; 125 100 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)); 101 return true; 102 } 132 103 133 if(!avc1394_transaction_block(fwhandle, fw_opts.node, cmd, 3, 1)) 134 { 135 VERBOSE(VB_IMPORTANT, "AVC transaction failed."); 136 return false; 137 } 104 void FirewireChannel::CloseFirewire(void) 105 { 106 if (!is_port_open) 107 return; 138 108 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; 109 device->ClosePort(); 110 is_port_open = false; 111 } 142 112 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));113 bool FirewireChannel::SwitchToInput(const QString &input, 114 const QString &chan) 115 { 116 int inputNum = GetInputByName(input); 117 if (inputNum < 0) 118 return false; 149 119 150 if (!avc1394_transaction_block(fwhandle, fw_opts.node, cmd, 3, 1)) 151 { 152 VERBOSE(VB_IMPORTANT, "AVC transaction failed."); 153 return false; 154 } 155 } 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 }; 120 return SetChannelByString(chan); 121 } 164 122 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)); 123 QString FirewireChannel::GetDevice(void) const 124 { 125 return QString("%1:%2").arg(fw_opts.port).arg(fw_opts.node); 126 } 170 127 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 } 128 bool FirewireChannel::SetPowerState(bool on) 129 { 130 return device->SetPowerState(on); 131 } 177 132 178 return true; 133 FirewireDevice::PowerState FirewireChannel::GetPowerState(void) const 134 { 135 return device->GetPowerState(); 179 136 } 180 137 181 bool FirewireChannel:: OpenFirewire(void)138 bool FirewireChannel::Retune(void) 182 139 { 183 if (!is_supported(fw_opts.model)) 140 VERBOSE(VB_CHANNEL, LOC + "Retune()"); 141 142 if (FirewireDevice::kAVCPowerOff == GetPowerState()) 184 143 { 185 144 VERBOSE(VB_IMPORTANT, LOC_ERR + 186 QString("Model: '%1' ").arg(fw_opts.model) + 187 "is not supported by internal channel changer."); 188 return false; 189 } 145 "STB is turned off, must be on to retune."); 190 146 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 147 return false; 198 148 } 199 149 200 VERBOSE(VB_CHANNEL, LOC + "Allocated raw1394 handle " +201 QString("for port %1").arg(fw_opts.port));150 if (current_channel) 151 return SetChannelByNumber(current_channel); 202 152 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(); 210 return false; 211 } 153 return false; 154 } 212 155 213 if (!avc1394_check_subunit_type(fwhandle, fw_opts.node, 214 AVC1394_SUBUNIT_TYPE_PANEL)) 215 { 216 VERBOSE(VB_IMPORTANT, LOC_ERR + QString("node %1 is not subunit " 217 "type panel.").arg(fw_opts.node)); 218 CloseFirewire(); 219 return false; 220 } 156 bool FirewireChannel::SetChannelByNumber(int channel) 157 { 158 current_channel = channel; 221 159 222 // check power, power on if off 223 if (GetPowerState() == Off) 160 if (FirewireDevice::kAVCPowerOff == GetPowerState()) 224 161 { 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]; 162 VERBOSE(VB_IMPORTANT, LOC_WARN + 163 "STB is turned off, must be on to set channel."); 232 164 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 on 239 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 else 248 { 249 VERBOSE(VB_IMPORTANT, LOC + QString("Power on cmd failed " 250 "(0x%1)") 251 .arg(response, 0, 16)); 252 return false; 253 } 254 } 255 else 256 { 257 VERBOSE(VB_IMPORTANT, LOC + "Power on cmd failed (no response)"); 258 return false; 259 } 165 SetSIStandard("mpeg"); 166 SetCachedATSCInfo(QString("%1-1").arg(channel)); 167 168 return true; // signal monitor will call retune later... 260 169 } 261 return true;262 }263 170 264 void FirewireChannel::CloseFirewire(void) 265 { 266 VERBOSE(VB_CHANNEL, LOC + "Releasing raw1394 handle"); 267 raw1394_destroy_handle(fwhandle); 268 } 171 if (!device->SetChannel(fw_opts.model, channel)) 172 return false; 269 173 270 FirewireChannel::PowerState FirewireChannel::GetPowerState(void) 271 { 272 quadlet_t *rval, response, cmd = STB_POWER_STATE; 174 SetSIStandard("mpeg"); 175 SetCachedATSCInfo(QString("%1-1").arg(channel)); 273 176 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; 177 return true; 314 178 } -
libs/libmythtv/firewirerecorderbase.h
1 /**2 * FirewireRecorderBase3 * Copyright (c) 2005 by Jim Westfall4 * Distributed as part of MythTV under GPL v2 and later.5 */6 7 #ifndef FIREWIRERECORDERBASE_H_8 #define FIREWIRERECORDERBASE_H_9 10 #include "dtvrecorder.h"11 #include "tsstats.h"12 #include "tspacket.h"13 #include "streamlisteners.h"14 15 /** \class FirewireRecorderBase16 * \brief This is a specialization of DTVRecorder used to17 * handle DVB and ATSC streams from a firewire input.18 *19 * \sa DTVRecorder20 */21 class FirewireRecorderBase : public DTVRecorder,22 public MPEGSingleProgramStreamListener23 {24 friend class MPEGStreamData;25 friend class TSPacketProcessor;26 27 public:28 FirewireRecorderBase(TVRec *rec);29 ~FirewireRecorderBase();30 31 // Commands32 void StartRecording(void);33 void ProcessTSPacket(const TSPacket &tspacket);34 bool PauseAndWait(int timeout = 100);35 36 // Sets37 void SetOptionsFromProfile(RecordingProfile *profile,38 const QString &videodev,39 const QString &audiodev,40 const QString &vbidev);41 void SetStreamData(MPEGStreamData*);42 43 // Gets44 MPEGStreamData* StreamData(void) { return _mpeg_stream_data; }45 46 // MPEG Single Program47 void HandleSingleProgramPAT(ProgramAssociationTable*);48 void HandleSingleProgramPMT(ProgramMapTable*);49 50 private:51 virtual void Close() = 0;52 virtual void start() = 0;53 virtual void stop() = 0;54 virtual bool grab_frames() = 0;55 56 MPEGStreamData *_mpeg_stream_data;57 TSStats _ts_stats;58 59 protected:60 static const int kTimeoutInSeconds;61 };62 63 #endif -
libs/libmythtv/firewirechannelbase.h
1 /**2 * FirewireChannelBase3 * Copyright (c) 2005 by Jim Westfall and Dave Abrahams4 * Distributed as part of MythTV under GPL v2 and later.5 */6 7 8 #ifndef LIBMYTHTV_FIREWIRECHANNELBASE_H9 #define LIBMYTHTV_FIREWIRECHANNELBASE_H10 11 #include <qstring.h>12 #include "tv_rec.h"13 #include "channelbase.h"14 15 #include "mythconfig.h"16 17 namespace AVS18 {19 class AVCDeviceController;20 class AVCDevice;21 }22 23 class FirewireChannelBase : public ChannelBase24 {25 public:26 FirewireChannelBase(TVRec *parent)27 : ChannelBase(parent), isopen(false) { }28 ~FirewireChannelBase() { Close(); }29 30 bool Open(void);31 void Close(void);32 33 // Sets34 bool SetChannelByString(const QString &chan);35 virtual bool SetChannelByNumber(int channel) = 0;36 37 // Gets38 bool IsOpen(void) const { return isopen; }39 40 // Commands41 bool SwitchToInput(const QString &inputname, const QString &chan);42 bool SwitchToInput(int newcapchannel, bool setstarting)43 { (void)newcapchannel; (void)setstarting; return false; }44 45 private:46 virtual bool OpenFirewire() = 0;47 virtual void CloseFirewire() = 0;48 49 protected:50 bool isopen;51 };52 53 #endif -
libs/libmythtv/firewiredevice.cpp
1 /** 2 * FirewireDevice 3 * Copyright (c) 2005 by Jim Westfall 4 * Distributed as part of MythTV under GPL v2 and later. 5 */ 6 7 // MythTV headers 8 #include "firewiredevice.h" 9 #include "mythcontext.h" 10 #include "pespacket.h" 11 12 #define LOC QString("FireDev(): ") 13 #define LOC_WARN QString("FireDev(), Warning: ") 14 #define LOC_ERR QString("FireDev(), Error: ") 15 16 FirewireDevice::FirewireDevice() : 17 m_last_channel(0), m_last_crc(0), 18 m_buffer_cleared(true), m_open_port_cnt(0), 19 m_lock(false) 20 { 21 } 22 23 void FirewireDevice::AddListener(TSDataListener *listener) 24 { 25 QMutexLocker locker(&m_lock); 26 27 if (listener) 28 { 29 vector<TSDataListener*>::iterator it = 30 find(m_listeners.begin(), m_listeners.end(), listener); 31 32 if (it == m_listeners.end()) 33 m_listeners.push_back(listener); 34 } 35 36 VERBOSE(VB_RECORD, LOC + "AddListener() "<<m_listeners.size()); 37 } 38 39 void FirewireDevice::RemoveListener(TSDataListener *listener) 40 { 41 QMutexLocker locker(&m_lock); 42 43 vector<TSDataListener*>::iterator it = m_listeners.end(); 44 45 do 46 { 47 it = find(m_listeners.begin(), m_listeners.end(), listener); 48 if (it != m_listeners.end()) 49 m_listeners.erase(it); 50 } 51 while (it != m_listeners.end()); 52 53 VERBOSE(VB_RECORD, LOC + "RemoveListener() "<<m_listeners.size()); 54 } 55 56 void FirewireDevice::SetLastChannel(const uint channel) 57 { 58 m_buffer_cleared = (channel == m_last_channel); 59 m_last_channel = channel; 60 61 VERBOSE(VB_IMPORTANT, QString("SetLastChannel(%1): cleared: %2") 62 .arg(channel).arg(m_buffer_cleared ? "yes" : "no")); 63 } 64 65 void FirewireDevice::ProcessPATPacket(const TSPacket &tspacket) 66 { 67 if (!tspacket.TransportError() && !tspacket.ScramplingControl() && 68 tspacket.HasPayload() && tspacket.PayloadStart() && !tspacket.PID()) 69 { 70 PESPacket pes = PESPacket::View(tspacket); 71 uint crc = pes.CalcCRC(); 72 m_buffer_cleared |= (crc != m_last_crc); 73 m_last_crc = crc; 74 VERBOSE(VB_RECORD, LOC + 75 QString("ProcessPATPacket: CRC 0x%1 cleared: %2") 76 .arg(crc,0,16).arg(m_buffer_cleared ? "yes" : "no")); 77 } 78 else 79 { 80 VERBOSE(VB_IMPORTANT, LOC_ERR + "Can't handle large PAT's"); 81 } 82 } -
libs/libmythtv/libmythtv.pro
377 377 } 378 378 379 379 # Support for cable boxes that provide Firewire out 380 using_firewire { 381 HEADERS += firewirechannelbase.h firewirerecorderbase.h 382 SOURCES += firewirechannelbase.cpp firewirerecorderbase.cpp 380 using_firewire { 381 HEADERS += firewirechannel.h firewirerecorder.h 382 HEADERS += firewiresignalmonitor.h firewiredevice.h 383 SOURCES += firewirechannel.cpp firewirerecorder.cpp 384 SOURCES += firewiresignalmonitor.cpp firewiredevice.cpp 383 385 384 386 macx { 385 HEADERS += darwinfirewirechannel.h darwinfirewirerecorder.h 386 SOURCES += darwinfirewirechannel.cpp darwinfirewirerecorder.cpp 387 HEADERS += selectavcdevice.h 388 SOURCES += selectavcdevice.cpp 387 HEADERS += darwinfirewiredevice.h 388 SOURCES += darwinfirewiredevice.cpp 389 DEFINES += USING_OSX_FIREWIRE 389 390 } 390 391 391 392 !macx { 392 HEADERS += firewirechannel.h firewirerecorder.h 393 SOURCES += firewirechannel.cpp firewirerecorder.cpp 393 HEADERS += linuxfirewiredevice.h 394 SOURCES += linuxfirewiredevice.cpp 395 DEFINES += USING_LINUX_FIREWIRE 394 396 } 395 397 396 398 DEFINES += USING_FIREWIRE -
libs/libmythtv/darwinfirewirerecorder.cpp
1 /**2 * DarwinDarwinFirewireRecorder3 * Copyright (c) 2005 by Jim Westfall and Dave Abrahams4 * Distributed as part of MythTV under GPL v2 and later.5 */6 7 // MythTV includes8 #include "darwinfirewirerecorder.h"9 #include "tspacket.h"10 11 #undef always_inline12 #include <AVCVideoServices/AVCVideoServices.h>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 {;}23 24 DarwinFirewireRecorder::~DarwinFirewireRecorder()25 {26 this->Close();27 }28 29 // Various message callbacks.30 IOReturn DarwinFirewireRecorder::MPEGNoData(void *pRefCon)31 {32 33 DarwinFirewireRecorder* self = static_cast<DarwinFirewireRecorder*>(pRefCon);34 self->no_data();35 return 0;36 }37 38 void DarwinFirewireRecorder::no_data()39 {40 VERBOSE(41 VB_IMPORTANT,42 QString("Firewire: No Input in %1 seconds").arg(kTimeoutInSeconds));43 }44 45 namespace46 {47 void avs_log_message(char *pString)48 {49 // I don't know what QString does with plain char*, but surely it50 // treats char const* as an NTBS.51 char const* s = pString;52 53 VERBOSE(VB_GENERAL,QString("Firewire MPEG2Receiver log: %1")54 .arg(s));55 }56 57 void avs_message_received(58 UInt32 msg, UInt32 param1, UInt32 param2, void *pRefCon)59 {60 (void)pRefCon;61 62 VERBOSE(VB_RECORD,QString("Firewire MPEG2Receiver message: %1")63 .arg(msg));64 65 switch (msg)66 {67 case AVS::kMpeg2ReceiverAllocateIsochPort:68 VERBOSE(69 VB_RECORD,70 QString("Firewire MPEG2Receiver allocated channel: %1, speed %2")71 .arg(param2).arg(param1)72 );73 break;74 75 case AVS::kMpeg2ReceiverDCLOverrun:76 VERBOSE(77 VB_IMPORTANT,78 QString("Firewire MPEG2Receiver DCL Overrun")79 );80 break;81 82 case AVS::kMpeg2ReceiverReceivedBadPacket:83 VERBOSE(84 VB_IMPORTANT,85 QString("Firewire MPEG2Receiver Received Bad Packet ")86 );87 break;88 89 default:90 break;91 }92 }93 94 bool find_capture_device(AVS::AVCDevice* d)95 {96 // We'd check isMPEGDevice, but it turns out that for the97 // DCT-6200, Apple doesn't set that flag. So instead we rule98 // out DV devices.99 // A more general OSX AVCRecorder class that also handles DV100 // devices might not check either flag.101 return d->isAttached && !d->isDVDevice102 // && (d->hasTapeSubunit || d->hasMonitorOrTunerSubunit)103 ;104 }105 106 IOReturn device_controller_notification(AVS::AVCDeviceController *, void *, AVS::AVCDevice*)107 {108 return 0;109 }110 }111 112 IOReturn DarwinFirewireRecorder::tspacket_callback(UInt32 tsPacketCount, UInt32 **ppBuf,void *pRefCon)113 {114 DarwinFirewireRecorder* self = static_cast<DarwinFirewireRecorder*>(pRefCon);115 if (!self)116 return kIOReturnBadArgument;117 118 for (UInt32 i = 0; i < tsPacketCount; ++i)119 self->ProcessTSPacket(*(reinterpret_cast<TSPacket*>(ppBuf[i])));120 121 return 0;122 }123 124 125 bool DarwinFirewireRecorder::Open()126 {127 if (isopen)128 return true;129 130 VERBOSE(VB_GENERAL,QString("Firewire: Creating logger object"));131 132 this->message_log = new AVS::StringLogger(avs_log_message);133 if (!this->message_log)134 {135 VERBOSE(VB_IMPORTANT, QString("Firewire: Couldn't create logger") );136 return false;137 }138 139 // If we don't set this immediately, Close() will refuse to clean140 // up after whatever mess we make here141 this->isopen = true;142 143 VERBOSE(VB_GENERAL,QString("Firewire: Creating MPEG-2 device stream"));144 145 // This not only builds an MPEG2Receiver object but also starts dedicated real-time threads.146 this->video_stream = capture_device->CreateMPEGReceiverForDevicePlug(147 0, // Plug number. Why is zero always OK? I148 // don't know, but that's what Apple's149 // examples do.150 tspacket_callback,151 this,152 avs_message_received,153 this,154 this->message_log,155 AVS::kCyclesPerReceiveSegment,156 // Why multiply by 2 instead of using the default,157 // kNumReceiveSegments? Because it's what Apple's only158 // example of the use of this function does.159 AVS::kNumReceiveSegments*2);160 161 if (!this->video_stream)162 {163 VERBOSE(VB_IMPORTANT, QString("Firewire: Couldn't create MPEG-2 device stream") );164 this->Close();165 return false;166 }167 168 // We could set the channel to receive on, but it doesn't seem169 // like we need to, and if the device is already transmitting it170 // could lead to inefficiency because the device stream is smart171 // enough to avoid allocating new bandwidth.172 173 // Register a no-data notification callback174 video_stream->pMPEGReceiver->registerNoDataNotificationCallback(175 MPEGNoData, this, kTimeoutInSeconds * 1000);176 177 return true;178 }179 180 void DarwinFirewireRecorder::Close()181 {182 if (!isopen)183 return;184 185 isopen = false;186 187 if (this->video_stream)188 {189 this->stop();190 VERBOSE(VB_RECORD, "Firewire: Destroying device stream");191 this->capture_device->DestroyAVCDeviceStream(this->video_stream);192 this->video_stream = 0;193 }194 195 delete this->message_log;196 this->message_log = 0;197 }198 199 void DarwinFirewireRecorder::start()200 {201 VERBOSE(VB_RECORD, "Firewire: Starting video stream");202 this->capture_device->StartAVCDeviceStream(this->video_stream);203 }204 205 void DarwinFirewireRecorder::stop()206 {207 VERBOSE(VB_RECORD, "Firewire: Stopping video stream");208 this->capture_device->StopAVCDeviceStream(this->video_stream);209 }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/dbcheck.cpp
10 10 #include "mythdbcon.h" 11 11 12 12 /// This is the DB schema version expected by the running MythTV instance. 13 const QString currentDatabaseVersion = "117 2";13 const QString currentDatabaseVersion = "1173"; 14 14 15 15 static bool UpdateDBVersionNumber(const QString &newnumber); 16 16 static bool performActualUpdate(const QString updates[], QString version, … … 2772 2772 return false; 2773 2773 } 2774 2774 2775 if (dbver == "1172") 2776 { 2777 // Add Firewire and DBox2 default recording profiles.. 2778 const QString updates[] = { 2779 "UPDATE capturecard SET channel_timeout = 9000 WHERE cardtype = 'FIREWIRE';", 2780 "" 2781 }; 2782 if (!performActualUpdate(updates, "1173", dbver)) 2783 return false; 2784 } 2785 2775 2786 //"ALTER TABLE cardinput DROP COLUMN preference;" in 0.22 2776 2787 //"ALTER TABLE channel DROP COLUMN atscsrcid;" in 0.22 2777 2788 //"ALTER TABLE recordedmarkup DROP COLUMN offset;" in 0.22 -
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/darwinfirewiredevice.cpp
1 /** 2 * DarwinFirewireChannel 3 * Copyright (c) 2005 by Jim Westfall 4 * SA3250HD support Copyright (c) 2005 by Matt Porter 5 * Copyright (c) 2006 by Dave Abrahams 6 * Distributed as part of MythTV under GPL v2 and later. 7 */ 8 9 #undef always_inline 10 #include <AVCVideoServices/AVCVideoServices.h> 11 12 #include "darwinfirewiredevice.h" 13 #include "mythcontext.h" 14 15 #define LOC QString("DFireDev(): ") 16 #define LOC_WARN QString("DFireDev(), Warning: ") 17 #define LOC_ERR QString("DFireDev(), Error: ") 18 19 namespace AVS 20 { 21 class AVCDeviceController; 22 class AVCDevice; 23 class AVCDeviceStream; 24 class StringLogger; 25 } 26 27 static bool dfd_find_panel_device(AVS::AVCDevice *d); 28 static bool dfd_find_capture_device(AVS::AVCDevice *d); 29 static AVS::AVCDevice *dfd_select_device(AVS::AVCDeviceController*, 30 bool (*)(AVS::AVCDevice*)); 31 32 static void dfd_log_message(char *pString); 33 static void dfd_err_message(uint32_t msg, uint32_t param1, 34 uint32_t param2, void *callback_data); 35 36 class DFDPriv 37 { 38 public: 39 DFDPriv() : 40 avc_device_controller(NULL), avc_device(NULL), 41 avstream(NULL), message_log(NULL), is_streaming(false) { } 42 43 AVS::AVCDeviceController *avc_device_controller; 44 AVS::AVCDevice *avc_device; 45 AVS::AVCDeviceStream *avstream; 46 AVS::StringLogger *message_log; 47 bool is_streaming; 48 }; 49 50 DarwinFirewireDevice::DarwinFirewireDevice() : m_priv(new DFDPriv()) 51 { 52 } 53 54 DarwinFirewireDevice::~DarwinFirewireDevice() 55 { 56 if (IsPortOpen()) 57 { 58 VERBOSE(VB_IMPORTANT, LOC_ERR + "ctor called with open port"); 59 while (IsPortOpen()) 60 ClosePort(); 61 } 62 63 if (m_priv) 64 { 65 delete m_priv; 66 m_priv = NULL; 67 } 68 } 69 70 bool DarwinFirewireDevice::OpenPort(void) 71 { 72 QMutexLocker locker(&m_lock); 73 74 VERBOSE(VB_RECORD, LOC + "OpenPort()"); 75 76 m_open_port_cnt++; 77 78 if (m_priv->avc_device) 79 return true; 80 81 int err = AVS::CreateAVCDeviceController(&m_priv->avc_device_controller); 82 if (err) 83 { 84 VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to open device controller: " + 85 QString("%1").arg(err,0,16)); 86 87 return false; 88 } 89 90 VERBOSE(VB_RECORD, LOC + "Opening AVC Device"); 91 92 m_priv->avc_device = dfd_select_device( 93 m_priv->avc_device_controller, dfd_find_panel_device); 94 95 if (!m_priv->avc_device) 96 { 97 VERBOSE(VB_IMPORTANT, LOC_ERR + 98 "Unable to find an attached " 99 "MPEG2 device that supports channel changes"); 100 101 AVS::DestroyAVCDeviceController(m_priv->avc_device_controller); 102 m_priv->avc_device_controller = NULL; 103 104 return false; 105 } 106 107 err = m_priv->avc_device->openDevice(); 108 109 if (err) 110 { 111 VERBOSE(VB_IMPORTANT, LOC_ERR + 112 QString("Couldn't open tuner device: %1").arg(err,0,16)); 113 114 AVS::DestroyAVCDeviceController(m_priv->avc_device_controller); 115 m_priv->avc_device_controller = NULL; 116 117 return false; 118 } 119 120 return true; 121 } 122 123 bool DarwinFirewireDevice::ClosePort(void) 124 { 125 QMutexLocker locker(&m_lock); 126 127 VERBOSE(VB_RECORD, LOC + "ClosePort()"); 128 129 if (m_open_port_cnt < 1) 130 return false; 131 132 m_open_port_cnt--; 133 134 if (m_open_port_cnt != 0) 135 return true; 136 137 if (m_priv->avc_device) 138 { 139 VERBOSE(VB_RECORD, LOC + "Closing AVC Device"); 140 141 m_priv->avc_device->closeDevice(); 142 143 //AVS::DestroyAVCDevice(m_priv->avc_device); 144 m_priv->avc_device = NULL; 145 } 146 147 return true; 148 } 149 150 bool DarwinFirewireDevice::OpenAVStream(void) 151 { 152 VERBOSE(VB_RECORD, LOC + "Creating logger object"); 153 154 m_priv->message_log = new AVS::StringLogger(dfd_log_message); 155 if (!m_priv->message_log) 156 { 157 VERBOSE(VB_IMPORTANT, LOC_ERR + "Couldn't create logger"); 158 return false; 159 } 160 161 // Plug number. Why is zero always OK? I don't know, but that's 162 // what Apple's examples do. 163 uint plug_num = 0; 164 165 // Why multiply by 2 instead of using the default, 166 // kNumReceiveSegments? Because it's what Apple's only 167 // example of the use of this function does. 168 uint recv_segments = 2 * AVS::kNumReceiveSegments; 169 170 // This not only builds an MPEG2Receiver object 171 // but also starts dedicated real-time threads. 172 m_priv->avstream = m_priv->avc_device->CreateMPEGReceiverForDevicePlug( 173 plug_num, dfd_tspacket_handler, this, dfd_err_message, this, 174 m_priv->message_log, AVS::kCyclesPerReceiveSegment, recv_segments); 175 176 if (!m_priv->avstream) 177 { 178 VERBOSE(VB_IMPORTANT, LOC_ERR + 179 "Couldn't create MPEG-2 device stream"); 180 181 CloseAVStream(); 182 183 return false; 184 } 185 186 // We could set the channel to receive on, but it doesn't seem 187 // like we need to, and if the device is already transmitting it 188 // could lead to inefficiency because the device stream is smart 189 // enough to avoid allocating new bandwidth. 190 191 // Register a no-data notification callback 192 m_priv->avstream->pMPEGReceiver->registerNoDataNotificationCallback( 193 dfd_no_data_notification, this, 50 /* msec */); 194 195 return true; 196 } 197 198 bool DarwinFirewireDevice::CloseAVStream(void) 199 { 200 if (m_priv->avstream) 201 { 202 StopStreaming(); 203 VERBOSE(VB_RECORD, LOC + "Destroying device stream"); 204 m_priv->avc_device->DestroyAVCDeviceStream(m_priv->avstream); 205 m_priv->avstream = NULL; 206 } 207 208 if (m_priv->message_log) 209 { 210 delete m_priv->message_log; 211 m_priv->message_log = NULL; 212 } 213 214 return true; 215 } 216 217 bool DarwinFirewireDevice::StartStreaming(void) 218 { 219 if (m_priv->is_streaming) 220 return m_priv->is_streaming; 221 222 VERBOSE(VB_RECORD, LOC + "Starting A/V streaming"); 223 224 if (!m_priv->avstream) 225 { 226 VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting A/V streaming, no A/V obj"); 227 return false; 228 } 229 230 m_priv->avc_device->StartAVCDeviceStream(m_priv->avstream); 231 m_priv->is_streaming = true; 232 233 return m_priv->is_streaming; 234 } 235 236 bool DarwinFirewireDevice::StopStreaming(void) 237 { 238 VERBOSE(VB_RECORD, LOC + "Stopping A/V streaming"); 239 240 if (m_priv->is_streaming) 241 { 242 m_priv->is_streaming = false; 243 m_priv->avc_device->StopAVCDeviceStream(m_priv->avstream); 244 } 245 246 VERBOSE(VB_RECORD, LOC + "Stopped A/V streaming"); 247 248 return true; 249 } 250 251 bool DarwinFirewireDevice::SetChannel(const QString &panel_model, uint channel) 252 { 253 QMutexLocker locker(&m_lock); 254 255 (void) panel_model; 256 257 AVS::PanelSubunitController panel(m_priv->avc_device); 258 259 int err = panel.Tune(channel); 260 if (err != kIOReturnSuccess) 261 { 262 VERBOSE(VB_GENERAL, LOC_ERR + "Tuning failed: " + 263 QString("0x%1").arg(err,0,16)); 264 265 return false; 266 } 267 268 return true; 269 } 270 271 bool DarwinFirewireDevice::SetPowerState(bool on) 272 { 273 QMutexLocker locker(&m_lock); 274 275 if (on) 276 m_priv->avc_device->SetPowerState(kAVCPowerStateOn); 277 else 278 m_priv->avc_device->SetPowerState(kAVCPowerStateOff); 279 280 return true; 281 } 282 283 FirewireDevice::PowerState DarwinFirewireDevice::GetPowerState(void) 284 { 285 QMutexLocker locker(&m_lock); 286 287 uint8_t power_state; 288 289 int err = m_priv->avc_device->GetPowerState(&power_state); 290 291 if (err != kIOReturnSuccess) 292 return FirewireDevice::kAVCPowerQueryFailed; 293 else if (kAVCPowerStateOff == power_state) 294 return FirewireDevice::kAVCPowerOff; 295 else if (kAVCPowerStateOn == power_state) 296 return FirewireDevice::kAVCPowerOn; 297 else 298 return FirewireDevice::kAVCPowerUnknown; 299 } 300 301 bool DarwinFirewireDevice::IsPortOpen(void) const 302 { 303 QMutexLocker locker(&m_lock); 304 305 return m_priv->avc_device; 306 } 307 308 bool DarwinFirewireDevice::IsTuner(void) const 309 { 310 return IsPortOpen(); 311 } 312 313 bool DarwinFirewireDevice::IsPanel(void) const 314 { 315 return IsPortOpen(); 316 } 317 318 bool DarwinFirewireDevice::IsSTB(void) const 319 { 320 return IsPortOpen(); 321 } 322 323 void DarwinFirewireDevice::AddListener(TSDataListener *listener) 324 { 325 FirewireDevice::AddListener(listener); 326 327 QMutexLocker locker(&m_lock); 328 if (!m_listeners.empty()) 329 StartStreaming(); 330 } 331 332 void DarwinFirewireDevice::RemoveListener(TSDataListener *listener) 333 { 334 FirewireDevice::RemoveListener(listener); 335 336 QMutexLocker locker(&m_lock); 337 if (m_priv->is_streaming && m_listeners.empty()) 338 { 339 StopStreaming(); 340 CloseAVStream(); 341 } 342 } 343 344 void DarwinFirewireDevice::BroadcastToListeners( 345 const unsigned char *data, uint dataSize) 346 { 347 QMutexLocker locker(&m_lock); 348 349 if ((dataSize >= TSPacket::SIZE) && (data[0] == SYNC_BYTE) && 350 ((data[1] & 0x1f) == 0) && (data[2] == 0)) 351 { 352 ProcessPATPacket(*((const TSPacket*)data)); 353 } 354 355 vector<TSDataListener*>::iterator it = m_listeners.begin(); 356 for (; it != m_listeners.end(); ++it) 357 (*it)->AddData(data, dataSize); 358 } 359 360 void DarwinFirewireDevice::no_data(void) 361 { 362 VERBOSE(VB_IMPORTANT, LOC_WARN + "No Input in 50 msecs"); 363 } 364 365 // Various message callbacks. 366 int dfd_no_data_notification(void *callback_data) 367 { 368 DarwinFirewireDevice *fw = 369 static_cast<DarwinFirewireDevice*>(callback_data); 370 371 fw->no_data(); 372 373 return 0; 374 } 375 376 int dfd_tspacket_handler(uint32_t tsPacketCount, uint32_t **ppBuf, 377 void *callback_data) 378 { 379 DarwinFirewireDevice *fw = (DarwinFirewireDevice*) callback_data; 380 if (!fw) 381 return kIOReturnBadArgument; 382 383 for (uint32_t i = 0; i < tsPacketCount; ++i) 384 fw->BroadcastToListeners((const unsigned char*) ppBuf[i], 1); 385 386 return 0; 387 } 388 389 // For the time being, the DarwinFireWireRecorder doesn't 390 // handle DV devices, so there's no point in finding one we 391 // can tune to here. That saves us from having to search 392 // twice for an eligible device. 393 static bool dfd_find_panel_device(AVS::AVCDevice *d) 394 { 395 return d->isAttached && d->hasMonitorOrTunerSubunit && !d->isDVDevice; 396 } 397 398 // We'd check isMPEGDevice, but it turns out that for the 399 // DCT-6200, Apple doesn't set that flag. So instead we rule 400 // out DV devices. 401 // A more general OSX AVCRecorder class that also handles DV 402 // devices might not check either flag. 403 static bool dfd_find_capture_device(AVS::AVCDevice *d) 404 { 405 return d->isAttached && !d->isDVDevice; 406 } 407 408 // TODO This needs to be worked on so that we can handle multiple STBs. 409 static AVS::AVCDevice *dfd_select_device(AVS::AVCDeviceController *controller, 410 bool (*filter)(AVS::AVCDevice*)) 411 { 412 VERBOSE(VB_RECORD, "dfd_select_device()"); 413 414 uint cnt = CFArrayGetCount(controller->avcDeviceArray); 415 for (uint i = 0; i < cnt; i++) 416 { 417 AVS::AVCDevice *dev = (AVS::AVCDevice*) 418 CFArrayGetValueAtIndex(controller->avcDeviceArray, i); 419 420 VERBOSE(VB_RECORD, 421 QString("dfd_select_device: " 422 "%1, format: %2, attached: %3, type: %4") 423 .arg(dev->deviceName) 424 .arg(dev->isDVDevice ? "DV" : 425 dev->isMPEGDevice ? "MPEG2-TS" : "unknown") 426 .arg(dev->isAttached ? "yes" : "no") 427 .arg(dev->hasTapeSubunit ? "tape" : 428 dev->hasMonitorOrTunerSubunit ? "tuner" : "unknown")); 429 430 if (filter(dev)) 431 { 432 VERBOSE(VB_RECORD, "dfd_select_device: FOUND"); 433 return dev; 434 } 435 } 436 437 VERBOSE(VB_RECORD, "dfd_select_device: NOT FOUND"); 438 439 return 0; 440 } 441 442 #define AVC_MSG_LOC QString("Firewire MPEG2Receiver: ") 443 #define AVC_MSG_LOC_ERR QString("Firewire MPEG2Receiver, Error: ") 444 static void dfd_log_message(char *pString) 445 { 446 VERBOSE(VB_RECORD, AVC_MSG_LOC + QString("Log: %1").arg(pString)); 447 } 448 449 static void dfd_err_message( 450 uint32_t msg, uint32_t param1, uint32_t param2, void *callback_data) 451 { 452 (void) callback_data; 453 454 if (AVS::kMpeg2ReceiverAllocateIsochPort == msg) 455 { 456 VERBOSE(VB_RECORD, AVC_MSG_LOC + 457 QString("Allocated channel: %1, speed %2") 458 .arg(param2).arg(param1)); 459 } 460 else if (AVS::kMpeg2ReceiverDCLOverrun == msg) 461 VERBOSE(VB_IMPORTANT, AVC_MSG_LOC_ERR + "DCL Overrun"); 462 else if (AVS::kMpeg2ReceiverReceivedBadPacket == msg) 463 VERBOSE(VB_IMPORTANT, AVC_MSG_LOC_ERR + "Received Bad Packet"); 464 else 465 VERBOSE(VB_RECORD, AVC_MSG_LOC + QString("Message: %1").arg(msg)); 466 } 467 #undef AVC_MSG_LOC 468 #undef AVC_MSG_LOC_ERR -
libs/libmythtv/firewirerecorderbase.cpp
1 /**2 * FirewireRecorder3 * Copyright (c) 2005 by Jim Westfall and Dave Abrahams4 * Distributed as part of MythTV under GPL v2 and later.5 */6 7 // MythTV includes8 #include "firewirerecorderbase.h"9 #include "mythcontext.h"10 #include "mpegtables.h"11 #include "mpegstreamdata.h"12 #include "tv_rec.h"13 14 #define LOC QString("FireRecBase: ")15 #define LOC_ERR QString("FireRecBase, Error: ")16 17 const int FirewireRecorderBase::kTimeoutInSeconds = 15;18 19 FirewireRecorderBase::FirewireRecorderBase(TVRec *rec)20 : DTVRecorder(rec), _mpeg_stream_data(NULL)21 {22 SetStreamData(new MPEGStreamData(1, true));23 }24 25 FirewireRecorderBase::~FirewireRecorderBase()26 {27 SetStreamData(NULL);28 }29 30 void FirewireRecorderBase::StartRecording(void) {31 32 VERBOSE(VB_RECORD, LOC + "StartRecording");33 34 if (!Open()) {35 _error = true;36 return;37 }38 39 _request_recording = true;40 _recording = true;41 42 start();43 44 while(_request_recording) {45 if (PauseAndWait())46 continue;47 48 if (!grab_frames())49 {50 _error = true;51 return;52 }53 }54 55 stop();56 FinishRecording();57 58 _recording = false;59 }60 61 void FirewireRecorderBase::ProcessTSPacket(const TSPacket &tspacket)62 {63 if (tspacket.TransportError())64 return;65 66 if (tspacket.ScramplingControl())67 return;68 69 if (tspacket.HasAdaptationField())70 StreamData()->HandleAdaptationFieldControl(&tspacket);71 72 if (tspacket.HasPayload())73 {74 const unsigned int lpid = tspacket.PID();75 76 // Pass or reject packets based on PID, and parse info from them77 if (lpid == StreamData()->VideoPIDSingleProgram())78 {79 _buffer_packets = !FindMPEG2Keyframes(&tspacket);80 BufferedWrite(tspacket);81 }82 else if (StreamData()->IsAudioPID(lpid))83 BufferedWrite(tspacket);84 else if (StreamData()->IsListeningPID(lpid))85 StreamData()->HandleTSTables(&tspacket);86 else if (StreamData()->IsWritingPID(lpid))87 BufferedWrite(tspacket);88 }89 90 _ts_stats.IncrTSPacketCount();91 if (0 == _ts_stats.TSPacketCount()%1000000)92 VERBOSE(VB_RECORD, _ts_stats.toString());93 }94 95 void FirewireRecorderBase::SetOptionsFromProfile(RecordingProfile *profile,96 const QString &videodev,97 const QString &audiodev,98 const QString &vbidev)99 {100 (void)videodev;101 (void)audiodev;102 (void)vbidev;103 (void)profile;104 }105 106 // documented in recorderbase.cpp107 bool FirewireRecorderBase::PauseAndWait(int timeout)108 {109 if (request_pause)110 {111 if (!paused)112 {113 stop();114 paused = true;115 pauseWait.wakeAll();116 if (tvrec)117 tvrec->RecorderPaused();118 }119 unpauseWait.wait(timeout);120 }121 if (!request_pause && paused)122 {123 start();124 paused = false;125 }126 return paused;127 }128 129 void FirewireRecorderBase::SetStreamData(MPEGStreamData *data)130 {131 if (data == _mpeg_stream_data)132 return;133 134 MPEGStreamData *old_data = _mpeg_stream_data;135 _mpeg_stream_data = data;136 137 if (data)138 data->AddMPEGSPListener(this);139 140 if (old_data)141 delete old_data;142 }143 144 void FirewireRecorderBase::HandleSingleProgramPAT(145 ProgramAssociationTable *pat)146 {147 if (!pat)148 return;149 150 int next = (pat->tsheader()->ContinuityCounter()+1)&0xf;151 pat->tsheader()->SetContinuityCounter(next);152 BufferedWrite(*(reinterpret_cast<const TSPacket*>(pat->tsheader())));153 }154 155 void FirewireRecorderBase::HandleSingleProgramPMT(ProgramMapTable *pmt)156 {157 if (!pmt)158 return;159 160 int next = (pmt->tsheader()->ContinuityCounter()+1)&0xf;161 pmt->tsheader()->SetContinuityCounter(next);162 BufferedWrite(*(reinterpret_cast<const TSPacket*>(pmt->tsheader())));163 } -
libs/libmythtv/firewirerecorder.cpp
1 1 /** 2 2 * FirewireRecorder 3 * Copyright (c) 2005 by Jim Westfall 3 * Copyright (c) 2005 by Jim Westfall and Dave Abrahams 4 4 * Distributed as part of MythTV under GPL v2 and later. 5 5 */ 6 6 7 // C includes8 #include <pthread.h>9 #include <sys/select.h>10 11 // C++ includes12 #include <iostream>13 using namespace std;14 15 7 // MythTV includes 16 8 #include "firewirerecorder.h" 9 #include "firewirechannel.h" 17 10 #include "mythcontext.h" 18 11 #include "mpegtables.h" 19 12 #include "mpegstreamdata.h" 20 13 #include "tv_rec.h" 21 14 22 #define LOC QString("FireRec : ")23 #define LOC_ERR QString("FireRec , Error: ")15 #define LOC QString("FireRecBase: ") 16 #define LOC_ERR QString("FireRecBase, Error: ") 24 17 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) 18 FirewireRecorder::FirewireRecorder(TVRec *rec, FirewireChannel *chan) : 19 DTVRecorder(rec), _mpeg_stream_data(NULL), 20 channel(chan), isopen(false) 33 21 { 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 22 } 52 23 53 static QString speed_to_string(uint speed)24 FirewireRecorder::~FirewireRecorder() 54 25 { 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]); 26 SetStreamData(NULL); 27 Close(); 60 28 } 61 29 62 30 bool FirewireRecorder::Open(void) 63 31 { 64 if (isopen)65 return true;32 if (!isopen) 33 isopen = channel->GetFirewireDevice()->OpenPort(); 66 34 67 VERBOSE(VB_RECORD, LOC + 68 QString("Initializing Port: %1, Node: %2, Speed: %3") 69 .arg(fwport).arg(fwnode).arg(speed_to_string(fwspeed))); 35 return isopen; 36 } 70 37 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 } 38 void FirewireRecorder::Close(void) 39 { 40 if (isopen) 41 { 42 channel->GetFirewireDevice()->ClosePort(); 43 isopen = false; 44 } 45 } 78 46 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; 47 void FirewireRecorder::StartStreaming(void) 48 { 49 channel->GetFirewireDevice()->AddListener(this); 50 } 98 51 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 } 52 void FirewireRecorder::StopStreaming(void) 53 { 54 channel->GetFirewireDevice()->RemoveListener(this); 55 } 114 56 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); 57 void FirewireRecorder::StartRecording(void) 58 { 59 VERBOSE(VB_RECORD, LOC + "StartRecording"); 120 60 121 // release raw1394 object; 122 raw1394_destroy_handle(fwhandle); 123 return false; 124 } 61 if (!Open()) 62 { 63 _error = true; 64 return; 65 } 125 66 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)); 67 _request_recording = true; 68 _recording = true; 135 69 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))); 70 StartStreaming(); 146 71 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 } 72 while (_request_recording) 73 { 74 if (!PauseAndWait()) 75 usleep(50 * 1000); 76 } 154 77 155 fwfd = raw1394_get_fd(fwhandle); 78 StopStreaming(); 79 FinishRecording(); 156 80 157 return isopen = true;81 _recording = false; 158 82 } 159 83 160 void FirewireRecorder:: Close(void)84 void FirewireRecorder::AddData(const unsigned char *data, uint len) 161 85 { 162 if (!isopen) 86 uint bufsz = buffer.size(); 87 if ((SYNC_BYTE == data[0]) && (TSPacket::SIZE == len) && 88 (TSPacket::SIZE > bufsz)) 89 { 90 if (bufsz) 91 buffer.clear(); 92 93 ProcessTSPacket(*(reinterpret_cast<const TSPacket*>(data))); 163 94 return; 95 } 164 96 165 isopen = false; 97 buffer.insert(buffer.end(), data, data + len); 98 bufsz += len; 166 99 167 VERBOSE(VB_RECORD, LOC + "Releasing iec61883_mpeg2 object"); 168 iec61883_mpeg2_close(fwmpeg); 100 int sync_at = -1; 101 for (uint i = 0; (i < bufsz) && (sync_at < 0); i++) 102 { 103 if (buffer[i] == SYNC_BYTE) 104 sync_at = i; 105 } 169 106 170 if (fwconnection == kConnectionP2P && fwchannel > -1) 107 if (sync_at < 0) 108 return; 109 110 if (bufsz < 30 * TSPacket::SIZE) 111 return; // build up a little buffer 112 113 while (sync_at + TSPacket::SIZE < bufsz) 171 114 { 172 VERBOSE(VB_RECORD, LOC +173 QString("Disconnecting channel %1").arg(fwchannel));115 ProcessTSPacket(*(reinterpret_cast<const TSPacket*>( 116 &buffer[0] + sync_at))); 174 117 175 iec61883_cmp_disconnect(fwhandle, fwnode | 0xffc0, fwoplug, 176 raw1394_get_local_id (fwhandle), 177 fwiplug, fwchannel, fwbandwidth); 118 sync_at += TSPacket::SIZE; 178 119 } 179 120 180 VERBOSE(VB_RECORD, LOC + "Releasing raw1394 handle"); 181 raw1394_destroy_handle(fwhandle); 121 buffer.erase(buffer.begin(), buffer.begin() + sync_at); 122 123 return; 182 124 } 183 125 184 bool FirewireRecorder::grab_frames()126 void FirewireRecorder::ProcessTSPacket(const TSPacket &tspacket) 185 127 { 186 struct timeval tv;187 fd_set rfds;128 if (tspacket.TransportError()) 129 return; 188 130 189 FD_ZERO(&rfds); 190 FD_SET(fwfd, &rfds); 191 tv.tv_sec = kTimeoutInSeconds; 192 tv.tv_usec = 0; 131 if (tspacket.ScramplingControl()) 132 return; 193 133 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; 200 } 134 if (tspacket.HasAdaptationField()) 135 GetStreamData()->HandleAdaptationFieldControl(&tspacket); 201 136 202 int ret = raw1394_loop_iterate(fwhandle); 203 if (ret) 137 if (tspacket.HasPayload()) 204 138 { 205 VERBOSE(VB_IMPORTANT, LOC_ERR + "libraw1394_loop_iterate() " + 206 QString("returned %1").arg(ret)); 207 return false; 208 } 139 const unsigned int lpid = tspacket.PID(); 209 140 210 return true; 141 // Pass or reject packets based on PID, and parse info from them 142 if (lpid == GetStreamData()->VideoPIDSingleProgram()) 143 { 144 _buffer_packets = !FindMPEG2Keyframes(&tspacket); 145 BufferedWrite(tspacket); 146 } 147 else if (GetStreamData()->IsAudioPID(lpid)) 148 BufferedWrite(tspacket); 149 else if (GetStreamData()->IsListeningPID(lpid)) 150 GetStreamData()->HandleTSTables(&tspacket); 151 else if (GetStreamData()->IsWritingPID(lpid)) 152 BufferedWrite(tspacket); 153 } 211 154 } 212 155 213 void FirewireRecorder::SetOption(const QString &name, const QString &value) 156 void FirewireRecorder::SetOptionsFromProfile(RecordingProfile *profile, 157 const QString &videodev, 158 const QString &audiodev, 159 const QString &vbidev) 214 160 { 215 if (name == "model") 216 fwmodel = value; 161 (void)videodev; 162 (void)audiodev; 163 (void)vbidev; 164 (void)profile; 217 165 } 218 166 219 void FirewireRecorder::SetOption(const QString &name, int value) 167 // documented in recorderbase.cpp 168 bool FirewireRecorder::PauseAndWait(int timeout) 220 169 { 221 if (name == "port") 222 fwport = value; 223 else if (name == "node") 224 fwnode = value; 225 else if (name == "speed") 170 if (request_pause) 226 171 { 227 if (RAW1394_ISO_SPEED_100 != value && 228 RAW1394_ISO_SPEED_200 != value && 229 RAW1394_ISO_SPEED_400 != value) 172 VERBOSE(VB_RECORD, LOC + "PauseAndWait("<<timeout<<") -- pause"); 173 if (!paused) 230 174 { 231 VERBOSE(VB_IMPORTANT, LOC_ERR +232 QString("Unknown speed '%1', will use 100Mbps")233 .arg(value));234 235 value = RAW1394_ISO_SPEED_100;175 StopStreaming(); 176 paused = true; 177 pauseWait.wakeAll(); 178 if (tvrec) 179 tvrec->RecorderPaused(); 236 180 } 237 fwspeed = value;181 unpauseWait.wait(timeout); 238 182 } 239 else if (name == "connection")183 if (!request_pause && paused) 240 184 { 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)); 185 VERBOSE(VB_RECORD, LOC + "PauseAndWait("<<timeout<<") -- unpause"); 186 StartStreaming(); 187 paused = false; 188 } 189 return paused; 190 } 247 191 248 fwconnection = kConnectionP2P; 249 } 250 fwconnection = value; 192 void FirewireRecorder::SetStreamData(MPEGStreamData *data) 193 { 194 if (data == _mpeg_stream_data) 195 return; 196 197 MPEGStreamData *old_data = _mpeg_stream_data; 198 _mpeg_stream_data = data; 199 if (old_data) 200 delete old_data; 201 202 if (data) 203 { 204 data->AddMPEGSPListener(this); 205 206 if (data->DesiredProgram() >= 0) 207 data->SetDesiredProgram(data->DesiredProgram()); 251 208 } 252 209 } 210 211 void FirewireRecorder::HandleSingleProgramPAT(ProgramAssociationTable *pat) 212 { 213 if (!pat) 214 return; 215 216 int next = (pat->tsheader()->ContinuityCounter()+1)&0xf; 217 pat->tsheader()->SetContinuityCounter(next); 218 BufferedWrite(*(reinterpret_cast<const TSPacket*>(pat->tsheader()))); 219 } 220 221 void FirewireRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt) 222 { 223 if (!pmt) 224 return; 225 226 int next = (pmt->tsheader()->ContinuityCounter()+1)&0xf; 227 pmt->tsheader()->SetContinuityCounter(next); 228 BufferedWrite(*(reinterpret_cast<const TSPacket*>(pmt->tsheader()))); 229 } -
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 _FIREWIRERECORDER_H_ 8 #define _FIREWIRERECORDER_H_ 9 9 10 #include "firewirerecorderbase.h" 11 #include " tsstats.h"12 #include <libraw1394/raw1394.h>13 #include <libiec61883/iec61883.h>10 // MythTV headers 11 #include "dtvrecorder.h" 12 #include "tspacket.h" 13 #include "streamlisteners.h" 14 14 15 class TVRec; 16 class FirewireChannel; 17 15 18 /** \class FirewireRecorder 16 * \brief Linux FirewireRFecorder 19 * \brief This is a specialization of DTVRecorder used to 20 * handle DVB and ATSC streams from a firewire input. 17 21 * 18 * \sa FirewireRecorderBase22 * \sa DTVRecorder 19 23 */ 20 class FirewireRecorder : public FirewireRecorderBase 24 class FirewireRecorder : public DTVRecorder, 25 public MPEGSingleProgramStreamListener, 26 public TSDataListener 21 27 { 22 friend int fw_tspacket_handler(unsigned char*,int,uint,void*); 28 friend class MPEGStreamData; 29 friend class TSPacketProcessor; 23 30 24 31 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(); } 32 FirewireRecorder(TVRec *rec, FirewireChannel *chan); 33 virtual ~FirewireRecorder(); 32 34 33 35 // Commands 34 bool Open(void); 36 bool Open(void); 37 void Close(void); 35 38 39 void StartStreaming(void); 40 void StopStreaming(void); 41 42 void StartRecording(void); 43 bool PauseAndWait(int timeout = 100); 44 45 void AddData(const unsigned char *data, uint dataSize); 46 void ProcessTSPacket(const TSPacket &tspacket); 47 36 48 // Sets 37 void SetOption(const QString &name, const QString &value); 38 void SetOption(const QString &name, int value); 49 void SetOptionsFromProfile(RecordingProfile *profile, 50 const QString &videodev, 51 const QString &audiodev, 52 const QString &vbidev); 53 void SetStreamData(MPEGStreamData*); 39 54 40 private: 41 void Close(void); 42 void start() { iec61883_mpeg2_recv_start(fwmpeg, fwchannel); } 43 void stop() { iec61883_mpeg2_recv_stop(fwmpeg); } 44 bool grab_frames(); 55 // Gets 56 MPEGStreamData *GetStreamData(void) { return _mpeg_stream_data; } 45 57 58 // MPEG Single Program 59 void HandleSingleProgramPAT(ProgramAssociationTable*); 60 void HandleSingleProgramPMT(ProgramMapTable*); 61 62 protected: 63 FirewireRecorder(TVRec *rec); 64 46 65 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; 60 61 static const int kBroadcastChannel; 62 static const int kConnectionP2P; 63 static const int kConnectionBroadcast; 64 static const uint kMaxBufferedPackets; 66 MPEGStreamData *_mpeg_stream_data; 67 FirewireChannel *channel; 68 bool isopen; 69 vector<unsigned char> buffer; 65 70 }; 66 71 67 #endif 72 #endif // _FIREWIRERECORDER_H_ -
libs/libmythtv/darwinfirewiredevice.h
1 #ifndef _DARWIN_FIREWIRE_DEVICE_H_ 2 #define _DARWIN_FIREWIRE_DEVICE_H_ 3 4 #include "firewiredevice.h" 5 6 class DFDPriv; 7 8 class DarwinFirewireDevice : public FirewireDevice 9 { 10 friend int dfd_no_data_notification(void *cb_data); 11 friend int dfd_tspacket_handler( 12 uint32_t tsPacketCount, uint32_t **ppBuf, void *callback_data); 13 14 public: 15 DarwinFirewireDevice(); 16 ~DarwinFirewireDevice(); 17 18 virtual bool OpenPort(void); 19 virtual bool ClosePort(void); 20 21 virtual void AddListener(TSDataListener*); 22 virtual void RemoveListener(TSDataListener*); 23 24 // Sets 25 virtual bool SetPowerState(bool on); 26 virtual bool SetChannel(const QString &panel_model, uint channel); 27 28 // Gets 29 virtual bool IsPortOpen(void) const; 30 virtual bool IsTuner(void) const; 31 virtual bool IsPanel(void) const; 32 virtual bool IsSTB(void) const; 33 34 // non-const Gets 35 virtual PowerState GetPowerState(void); 36 37 void no_data(void); 38 39 private: 40 bool OpenAVStream(void); 41 bool CloseAVStream(void); 42 43 bool StartStreaming(void); 44 bool StopStreaming(void); 45 46 void BroadcastToListeners(const unsigned char *data, uint dataSize); 47 48 private: 49 DFDPriv *m_priv; 50 }; 51 52 #endif // _DARWIN_FIREWIRE_DEVICE_H_ -
libs/libmythtv/darwinfirewirechannel.cpp
1 /**2 * DarwinFirewireChannel3 * Copyright (c) 2005 by Jim Westfall4 * SA3250HD support Copyright (c) 2005 by Matt Porter5 * Distributed as part of MythTV under GPL v2 and later.6 */7 8 9 #include <iostream>10 #include "mythcontext.h"11 #include "darwinfirewirechannel.h"12 13 #include "selectavcdevice.h"14 15 #undef always_inline16 #include <AVCVideoServices/AVCVideoServices.h>17 18 19 namespace20 {21 bool find_device(AVS::AVCDevice* d)22 {23 return d->isAttached && d->hasMonitorOrTunerSubunit24 // For the time being, the DarwinFireWireRecorder doesn't25 // handle DVB devices, so there's no point in finding one we26 // can tune to, here. That saves us from having to search27 // twice for an eligible device.28 && !d->isDVDevice29 ;30 }31 }32 33 DarwinFirewireChannel::DarwinFirewireChannel(FireWireDBOptions const& firewire_opts,TVRec *parent)34 : FirewireChannelBase(parent)35 , device_controller(0)36 , device(0)37 {38 (void)firewire_opts;39 }40 41 bool DarwinFirewireChannel::OpenFirewire()42 {43 IOReturn err = AVS::CreateAVCDeviceController(&this->device_controller);44 if (err)45 {46 VERBOSE(47 VB_IMPORTANT,48 QString("unable to open device controller: %1").arg(err,0,16));49 return false;50 }51 52 if ((this->device = SelectAVCDevice(device_controller, find_device)))53 {54 VERBOSE(VB_RECORD, QString("DarwinFirewireChannel: opening device") );55 err = this->device->openDevice();56 if (!err)57 return true;58 59 VERBOSE(60 VB_IMPORTANT,61 QString("FireWireChannel: couldn't open tuner device: %1").arg(err,0,16));62 }63 else64 {65 VERBOSE(66 VB_IMPORTANT,67 QString(68 "DarwinFireWireChannel: unable to find an attached"69 " MPEG2 device that supports channel changes"));70 }71 AVS::DestroyAVCDeviceController(this->device_controller);72 return false;73 }74 75 void DarwinFirewireChannel::CloseFirewire()76 {77 this->device->closeDevice();78 AVS::DestroyAVCDeviceController(this->device_controller);79 // Leave the device controller for the destructor80 }81 82 AVS::AVCDevice* DarwinFirewireChannel::GetAVCDevice() const83 {84 return this->device;85 }86 87 bool DarwinFirewireChannel::SetChannelByNumber(int channel)88 {89 // 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)93 {94 this->device->SetPowerState(kAVCPowerStateOn);95 96 // Give it time to power up.97 usleep(2000000); // Sleep for two seconds98 }99 100 AVS::PanelSubunitController panel(this->device);101 err = panel.Tune(channel);102 if (err != kIOReturnSuccess)103 {104 VERBOSE(VB_GENERAL, QString("DarwinFirewireChannel: Tuning failed: %1").arg(err,0,16));105 VERBOSE(VB_GENERAL, QString("Ignoring error per apple example"));106 }107 // Give it time to transition.108 usleep(1000000); // Sleep for one second109 return true;110 } -
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 "atscstreamdata.h" 12 #include "mpegtables.h" 13 #include "atsctables.h" 14 #include "firewirechannel.h" 15 #include "firewiresignalmonitor.h" 16 17 #define LOC QString("FireSM(%1): ").arg(channel->GetDevice()) 18 #define LOC_WARN QString("FireSM(%1), Warning: ").arg(channel->GetDevice()) 19 #define LOC_ERR QString("FireSM(%1), Error: ").arg(channel->GetDevice()) 20 21 const uint FirewireSignalMonitor::kPowerTimeout = 3000; /* ms */ 22 const uint FirewireSignalMonitor::kBufferTimeout = 5000; /* ms */ 23 24 QMap<void*,uint> FirewireSignalMonitor::pat_keys; 25 QMutex FirewireSignalMonitor::pat_keys_lock; 26 27 /** \fn FirewireSignalMonitor::FirewireSignalMonitor(int,FirewireChannel*,uint,const char*) 28 * \brief Initializes signal lock and signal values. 29 * 30 * Start() must be called to actually begin continuous 31 * signal monitoring. The timeout is set to 3 seconds, 32 * and the signal threshold is initialized to 0%. 33 * 34 * \param db_cardnum Recorder number to monitor, 35 * if this is less than 0, SIGNAL events will not be 36 * sent to the frontend even if SetNotifyFrontend(true) 37 * is called. 38 * \param _channel FirewireChannel for card 39 * \param _flags Flags to start with 40 * \param _name Name for Qt signal debugging 41 */ 42 FirewireSignalMonitor::FirewireSignalMonitor( 43 int db_cardnum, 44 FirewireChannel *_channel, 45 uint _flags, const char *_name) : 46 DTVSignalMonitor(db_cardnum, _channel, _flags, _name), 47 dtvMonitorRunning(false), 48 stb_needs_retune(true), 49 stb_needs_to_wait_for_pat(false), 50 stb_needs_to_wait_for_power(false) 51 { 52 VERBOSE(VB_CHANNEL, LOC + "ctor"); 53 54 signalStrength.SetThreshold(65); 55 56 AddFlags(kDTVSigMon_WaitForSig); 57 58 stb_needs_retune = 59 (FirewireDevice::kAVCPowerOff == _channel->GetPowerState()); 60 } 61 62 /** \fn FirewireSignalMonitor::~FirewireSignalMonitor() 63 * \brief Stops signal monitoring and table monitoring threads. 64 */ 65 FirewireSignalMonitor::~FirewireSignalMonitor() 66 { 67 VERBOSE(VB_CHANNEL, LOC + "dtor"); 68 Stop(); 69 } 70 71 void FirewireSignalMonitor::deleteLater(void) 72 { 73 disconnect(); // disconnect signals we may be sending... 74 Stop(); 75 DTVSignalMonitor::deleteLater(); 76 } 77 78 /** \fn FirewireSignalMonitor::Stop(void) 79 * \brief Stop signal monitoring and table monitoring threads. 80 */ 81 void FirewireSignalMonitor::Stop(void) 82 { 83 VERBOSE(VB_CHANNEL, LOC + "Stop() -- begin"); 84 SignalMonitor::Stop(); 85 if (dtvMonitorRunning) 86 { 87 dtvMonitorRunning = false; 88 pthread_join(table_monitor_thread, NULL); 89 } 90 VERBOSE(VB_CHANNEL, LOC + "Stop() -- end"); 91 } 92 93 void FirewireSignalMonitor::HandlePAT(const ProgramAssociationTable *pat) 94 { 95 AddFlags(kDTVSigMon_PATSeen); 96 97 FirewireChannel *fwchan = dynamic_cast<FirewireChannel*>(channel); 98 bool crc_bogus = !fwchan->GetFirewireDevice()->IsSTBBufferCleared(); 99 if (crc_bogus && stb_needs_to_wait_for_pat && 100 (stb_wait_for_pat_timer.elapsed() < (int)kBufferTimeout)) 101 { 102 VERBOSE(VB_CHANNEL, LOC + "HandlePAT() ignoring PAT"); 103 uint tsid = pat->TransportStreamID(); 104 GetStreamData()->SetVersionPAT(tsid, -1,0); 105 return; 106 } 107 108 if (crc_bogus && stb_needs_to_wait_for_pat) 109 { 110 VERBOSE(VB_IMPORTANT, LOC_WARN + "Wait for valid PAT timed out"); 111 stb_needs_to_wait_for_pat = false; 112 } 113 114 DTVSignalMonitor::HandlePAT(pat); 115 } 116 117 void FirewireSignalMonitor::HandlePMT(uint pnum, const ProgramMapTable *pmt) 118 { 119 VERBOSE(VB_CHANNEL, LOC + "HandlePMT()"); 120 121 AddFlags(kDTVSigMon_PMTSeen); 122 123 if (!HasFlags(kDTVSigMon_PATMatch)) 124 { 125 GetStreamData()->SetVersionPMT(pnum, -1,0); 126 VERBOSE(VB_CHANNEL, LOC + "HandlePMT() ignoring PMT"); 127 return; 128 } 129 130 DTVSignalMonitor::HandlePMT(pnum, pmt); 131 } 132 133 void *FirewireSignalMonitor::TableMonitorThread(void *param) 134 { 135 FirewireSignalMonitor *mon = (FirewireSignalMonitor*) param; 136 mon->RunTableMonitor(); 137 return NULL; 138 } 139 140 void FirewireSignalMonitor::RunTableMonitor(void) 141 { 142 stb_needs_to_wait_for_pat = true; 143 stb_wait_for_pat_timer.start(); 144 dtvMonitorRunning = true; 145 146 VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- begin"); 147 148 FirewireChannel *lchan = dynamic_cast<FirewireChannel*>(channel); 149 if (!lchan) 150 { 151 VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- err end"); 152 dtvMonitorRunning = false; 153 return; 154 } 155 156 FirewireDevice *dev = lchan->GetFirewireDevice(); 157 158 dev->OpenPort(); 159 dev->AddListener(this); 160 161 while (dtvMonitorRunning && GetStreamData()) 162 usleep(100000); 163 164 VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- shutdown "); 165 166 dev->RemoveListener(this); 167 dev->ClosePort(); 168 169 dtvMonitorRunning = false; 170 171 VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- end"); 172 } 173 174 void FirewireSignalMonitor::AddData(const unsigned char *data, uint len) 175 { 176 if (!dtvMonitorRunning) 177 return; 178 179 if (GetStreamData()) 180 GetStreamData()->ProcessData((unsigned char *)data, len); 181 } 182 183 /** \fn FirewireSignalMonitor::UpdateValues(void) 184 * \brief Fills in frontend stats and emits status Qt signals. 185 * 186 * This function uses five ioctl's FE_READ_SNR, FE_READ_SIGNAL_STRENGTH 187 * FE_READ_BER, FE_READ_UNCORRECTED_BLOCKS, and FE_READ_STATUS to obtain 188 * statistics from the frontend. 189 * 190 * This is automatically called by MonitorLoop(), after Start() 191 * has been used to start the signal monitoring thread. 192 */ 193 void FirewireSignalMonitor::UpdateValues(void) 194 { 195 if (!running || exit) 196 return; 197 198 if (dtvMonitorRunning) 199 { 200 EmitFirewireSignals(); 201 if (IsAllGood()) 202 emit AllGood(); 203 // TODO dtv signals... 204 205 update_done = true; 206 return; 207 } 208 209 if (stb_needs_to_wait_for_power && 210 (stb_wait_for_power_timer.elapsed() < (int)kPowerTimeout)) 211 { 212 return; 213 } 214 stb_needs_to_wait_for_power = false; 215 216 FirewireChannel *fwchan = dynamic_cast<FirewireChannel*>(channel); 217 218 if (HasFlags(kFWSigMon_WaitForPower) && !HasFlags(kFWSigMon_PowerMatch)) 219 { 220 FirewireDevice::PowerState power = fwchan->GetPowerState(); 221 if (FirewireDevice::kAVCPowerOn == power) 222 { 223 AddFlags(kFWSigMon_PowerSeen | kFWSigMon_PowerMatch); 224 } 225 else if (FirewireDevice::kAVCPowerOff == power) 226 { 227 AddFlags(kFWSigMon_PowerSeen); 228 fwchan->SetPowerState(true); 229 stb_wait_for_power_timer.start(); 230 stb_needs_to_wait_for_power = true; 231 } 232 } 233 234 bool isLocked = !HasFlags(kFWSigMon_WaitForPower) || 235 HasFlags(kFWSigMon_WaitForPower | kFWSigMon_PowerMatch); 236 237 if (isLocked && stb_needs_retune) 238 { 239 fwchan->Retune(); 240 isLocked = stb_needs_retune = false; 241 } 242 243 // Set SignalMonitorValues from info from card. 244 { 245 QMutexLocker locker(&statusLock); 246 signalStrength.SetValue(isLocked ? 100 : 0); 247 signalLock.SetValue(isLocked ? 1 : 0); 248 } 249 250 EmitFirewireSignals(); 251 if (IsAllGood()) 252 emit AllGood(); 253 254 // Start table monitoring if we are waiting on any table 255 // and we have a lock. 256 if (isLocked && GetStreamData() && 257 HasAnyFlag(kDTVSigMon_WaitForPAT | kDTVSigMon_WaitForPMT | 258 kDTVSigMon_WaitForMGT | kDTVSigMon_WaitForVCT | 259 kDTVSigMon_WaitForNIT | kDTVSigMon_WaitForSDT)) 260 { 261 pthread_create(&table_monitor_thread, NULL, 262 TableMonitorThread, this); 263 264 VERBOSE(VB_CHANNEL, LOC + "UpdateValues() -- " 265 "Waiting for table monitor to start"); 266 267 while (!dtvMonitorRunning) 268 usleep(50); 269 270 VERBOSE(VB_CHANNEL, LOC + "UpdateValues() -- " 271 "Table monitor started"); 272 } 273 274 update_done = true; 275 } 276 277 #define EMIT(SIGNAL_FUNC, SIGNAL_VAL) \ 278 do { statusLock.lock(); \ 279 SignalMonitorValue val = SIGNAL_VAL; \ 280 statusLock.unlock(); \ 281 emit SIGNAL_FUNC(val); } while (false) 282 283 /** \fn FirewireSignalMonitor::EmitFirewireSignals(void) 284 * \brief Emits signals for lock, signal strength, etc. 285 */ 286 void FirewireSignalMonitor::EmitFirewireSignals(void) 287 { 288 // Emit signals.. 289 EMIT(StatusSignalLock, signalLock); 290 if (HasFlags(kDTVSigMon_WaitForSig)) 291 EMIT(StatusSignalStrength, signalStrength); 292 } 293 294 #undef EMIT -
libs/libmythtv/mpeg/streamlisteners.h
33 33 class ServiceDescriptionTable; 34 34 class DVBEventInformationTable; 35 35 36 class TSDataListener 37 { 38 public: 39 /// Callback function to add MPEG2 TS data 40 virtual void AddData(const unsigned char *data, uint dataSize) = 0; 41 42 protected: 43 virtual ~TSDataListener() { } 44 }; 45 36 46 class MPEGStreamListener 37 47 { 38 48 protected: -
libs/libmythtv/darwinfirewirechannel.h
1 /**2 * DarwinFirewireChannel3 * Copyright (c) 2005 by Dave Abrahams4 * Distributed as part of MythTV under GPL v2 and later.5 */6 7 8 #ifndef LIBMYTHTV_DARWINFIREWIRECHANNEL_H9 #define LIBMYTHTV_DARWINFIREWIRECHANNEL_H10 11 #include <qstring.h>12 #include "tv_rec.h"13 #include "firewirechannelbase.h"14 15 16 namespace AVS17 {18 class AVCDeviceController;19 class AVCDevice;20 }21 22 class DarwinFirewireChannel : public FirewireChannelBase23 {24 public:25 DarwinFirewireChannel(FireWireDBOptions const&, TVRec *parent);26 27 // Gets28 AVS::AVCDevice* GetAVCDevice() const;29 30 // Sets31 bool SetChannelByNumber(int channel);32 33 private:34 bool OpenFirewire();35 void CloseFirewire();36 37 private:38 AVS::AVCDeviceController* device_controller;39 AVS::AVCDevice* device;40 };41 42 #endif -
libs/libmythtv/signalmonitor.cpp
34 34 # include "iptvchannel.h" 35 35 #endif 36 36 37 #ifdef USING_FIREWIRE 38 # include "firewiresignalmonitor.h" 39 # include "firewirechannel.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 FirewireChannel *fc = dynamic_cast<FirewireChannel*>(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 "firewiredevice.h" 12 #include "util.h" 13 14 class FirewireChannel; 15 16 class FirewireSignalMonitor : public DTVSignalMonitor, public TSDataListener 17 { 18 Q_OBJECT 19 20 public: 21 FirewireSignalMonitor(int db_cardnum, FirewireChannel *_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
1 /**2 * FirewireRecorder3 * Copyright (c) 2005 by Jim Westfall and Dave Abrahams4 * Distributed as part of MythTV under GPL v2 and later.5 */6 7 #ifndef LIBMYTHTV_DARWINFIREWIRERECORDER_H_8 #define LIBMYTHTV_DARWINFIREWIRERECORDER_H_9 10 #include "firewirerecorderbase.h"11 #include "darwinfirewirechannel.h"12 13 //#include <IOKit/IOReturn.h>14 //#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacTypes.h>15 16 typedef unsigned long UInt32;17 typedef int IOReturn;18 19 namespace AVS20 {21 class AVCDeviceController;22 class AVCDevice;23 class StringLogger;24 class AVCDeviceStream;25 }26 27 /** \class DarwinFirewireRecorder28 * \brief This is a specialization of DTVRecorder used to29 * handle DVB and ATSC streams from a firewire input.30 *31 * \sa DTVRecorder32 */33 class DarwinFirewireRecorder : public FirewireRecorderBase34 {35 public:36 DarwinFirewireRecorder(TVRec *rec, ChannelBase* tuner);37 ~DarwinFirewireRecorder();38 39 bool Open(void);40 41 void SetOption(const QString &name, const QString &value);42 void SetOption(const QString &name, int value);43 44 private:45 void Close();46 47 void start();48 void stop();49 void no_data();50 bool grab_frames();51 52 static IOReturn MPEGNoData(void* pRefCon);53 static IOReturn tspacket_callback(UInt32 tsPacketCount, UInt32 **ppBuf, void *pRefCon);54 55 AVS::AVCDevice* capture_device;56 AVS::StringLogger* message_log;57 AVS::AVCDeviceStream* video_stream;58 59 bool isopen;60 };61 62 #endif -
libs/libmythtv/firewirechannel.h
1 1 /** 2 2 * FirewireChannel 3 * Copyright (c) 2005 by Jim Westfall 4 * SA3250HD support Copyright (c) 2005 by Matt Porter 3 * Copyright (c) 2005 by Jim Westfall and Dave Abrahams 5 4 * Distributed as part of MythTV under GPL v2 and later. 6 5 */ 7 6 7 #ifndef _FIREWIRECHANNEL_H_ 8 #define _FIREWIRECHANNEL_H_ 8 9 9 #ifndef FIREWIRECHANNEL_H10 #define FIREWIRECHANNEL_H11 12 #include <qstring.h>13 10 #include "tv_rec.h" 14 #include " firewirechannelbase.h"15 #include <libavc1394/avc1394.h>11 #include "dtvchannel.h" 12 #include "firewiredevice.h" 16 13 17 using namespace std; 18 19 class FirewireChannel : public FirewireChannelBase 14 class FirewireChannel : public DTVChannel 20 15 { 21 16 public: 22 enum PowerState { 23 On, 24 Off, 25 Failed 26 }; 17 FirewireChannel(const FireWireDBOptions &firewire_opts, TVRec *parent); 27 18 28 FirewireChannel(FireWireDBOptions firewire_opts, TVRec *parent); 29 ~FirewireChannel(void); 19 // Commands 20 virtual bool Open(void); 21 virtual void Close(void); 22 virtual bool SwitchToInput(const QString &inputname, const QString &chan); 23 virtual bool SwitchToInput(int newcapchannel, bool setstarting) 24 { (void)newcapchannel; (void)setstarting; return false; } 30 25 31 bool OpenFirewire(void); 32 void CloseFirewire(void); 26 virtual bool TuneMultiplex(uint /*mplexid*/, QString /*inputname*/) 27 { return false; } 28 virtual bool Tune(const DTVMultiplex &/*tuning*/, QString /*inputname*/) 29 { return false; } 30 virtual bool Retune(void); 33 31 34 32 // Sets 35 void SetExternalChanger(void); 36 bool SetChannelByNumber(int channel); 33 virtual bool SetChannelByString(const QString &chan); 34 virtual bool SetChannelByNumber(int channel); 35 virtual bool SetPowerState(bool on); 37 36 38 37 // Gets 39 bool IsOpen(void) const { return isopen; }40 QString GetDevice(void) const41 { return QString("%1:%2").arg(fw_opts.port).arg(fw_opts.node); }42 PowerState GetPowerState(void);38 virtual bool IsOpen(void) const { return isopen; } 39 virtual FirewireDevice::PowerState GetPowerState(void) const; 40 virtual QString GetDevice(void) const; 41 virtual FirewireDevice *GetFirewireDevice(void) { return device; } 43 42 43 protected: 44 FirewireChannel(TVRec *parent) : 45 DTVChannel(parent), isopen(false) { } 46 ~FirewireChannel() { Close(); } 47 44 48 private: 49 virtual bool OpenFirewire(void); 50 virtual void CloseFirewire(void); 51 52 protected: 53 bool isopen; 45 54 FireWireDBOptions fw_opts; 46 nodeid_t fwnode; 47 raw1394handle_t fwhandle; 55 FirewireDevice *device; 56 uint current_channel; 57 bool is_port_open; 48 58 }; 49 59 50 #endif 60 #endif // _FIREWIRECHANNEL_H_ -
libs/libmythtv/videosource.cpp
1031 1031 hg1->addChild(new FirewireNode(parent)); 1032 1032 hg1->addChild(new FirewireSpeed(parent)); 1033 1033 addChild(hg1); 1034 addChild(new FirewireInput(parent)); 1034 1035 FirewireInput *defaultinput = new FirewireInput(parent); 1036 addChild(defaultinput); 1037 defaultinput->setVisible(false); 1038 1039 addChild(new ChannelTimeout(parent, 9000)); 1035 1040 }; 1041 1036 1042 private: 1037 1043 CaptureCard &parent; 1038 1044 }; … … 1186 1192 HDHRCardInput *defaultinput = new HDHRCardInput(parent); 1187 1193 addChild(defaultinput); 1188 1194 defaultinput->setVisible(false); 1195 1196 addChild(new SignalTimeout(parent, 1000)); 1197 addChild(new ChannelTimeout(parent, 3000)); 1189 1198 }; 1190 1199 1191 1200 private: -
libs/libmythtv/selectavcdevice.cpp
1 /**2 * SelectAVCDevice3 * Copyright (c) 2006 by Dave Abrahams4 * Distributed as part of MythTV under GPL v2 and later.5 */6 7 #include "mythconfig.h"8 9 #ifdef CONFIG_DARWIN10 # include "mythcontext.h"11 # include "selectavcdevice.h"12 # undef always_inline13 # include <AVCVideoServices/AVCVideoServices.h>14 15 AVS::AVCDevice* SelectAVCDevice(16 AVS::AVCDeviceController* controller,17 bool (*filter)(AVS::AVCDevice*)18 )19 {20 VERBOSE(VB_GENERAL, QString("SelectAVCDevice:"));21 22 for (unsigned n = CFArrayGetCount(controller->avcDeviceArray),23 i = 0; i < n; ++i)24 {25 AVS::AVCDevice& d = *(AVS::AVCDevice*)CFArrayGetValueAtIndex(controller->avcDeviceArray, i);26 27 VERBOSE(28 VB_GENERAL,29 QString("SelectAVCDevice: %1, format: %2, attached: %3, type: %4")30 .arg(d.deviceName)31 .arg(d.isDVDevice ? "DV" : d.isMPEGDevice ? "MPEG2-TS" : "unknown")32 .arg(d.isAttached ? "yes" : "no")33 .arg(d.hasTapeSubunit ? "tape" : d.hasMonitorOrTunerSubunit ? "tuner" : "unknown")34 );35 36 if (filter(&d))37 {38 VERBOSE(VB_GENERAL, QString("SelectAVCDevice: FOUND"));39 return &d;40 }41 }42 VERBOSE(VB_GENERAL, QString("SelectAVCDevice: NOT FOUND"));43 return 0;44 }45 46 #endif // CONFIG_DARWIN47 -
libs/libmythtv/firewirechannelbase.cpp
1 /**2 * FirewireChannelBase3 * Copyright (c) 2005 by Jim Westfall Dave Abrahams4 * Distributed as part of MythTV under GPL v2 and later.5 */6 7 8 #include <iostream>9 #include "mythcontext.h"10 #include "firewirechannelbase.h"11 12 bool FirewireChannelBase::SetChannelByString(const QString &chan)13 {14 inputs[currentInputID]->startChanNum = chan;15 curchannelname = chan;16 17 InputMap::const_iterator it = inputs.find(currentInputID);18 19 if (!(*it)->externalChanger.isEmpty())20 return ChangeExternalChannel(chan);21 22 return isopen && SetChannelByNumber(chan.toInt());23 }24 25 bool FirewireChannelBase::Open()26 {27 if (!InitializeInputs())28 return false;29 30 InputMap::const_iterator it = inputs.find(currentInputID);31 if (!(*it)->externalChanger.isEmpty())32 return true;33 34 if (!isopen)35 {36 isopen = OpenFirewire();37 return isopen;38 }39 return true;40 }41 42 void FirewireChannelBase::Close()43 {44 if (isopen)45 CloseFirewire();46 isopen = false;47 }48 49 bool FirewireChannelBase::SwitchToInput(const QString &input,50 const QString &chan)51 {52 int inputNum = GetInputByName(input);53 if (inputNum < 0)54 return false;55 56 return SetChannelByString(chan);57 } -
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 LFDPriv; 13 14 class LinuxFirewireDevice : public FirewireDevice 15 { 16 friend void *linux_firewire_device_streaming_thunk(void *param); 17 friend int linux_firewire_device_tspacket_handler( 18 unsigned char *tspacket, int len, uint dropped, void *callback_data); 19 20 public: 21 22 LinuxFirewireDevice(uint port, uint node, uint speed, bool use_p2p, 23 uint av_buffer_size_in_bytes = 0); 24 ~LinuxFirewireDevice(); 25 26 virtual bool OpenPort(void); 27 virtual bool ClosePort(void); 28 29 virtual void AddListener(TSDataListener*); 30 virtual void RemoveListener(TSDataListener*); 31 32 // Sets 33 virtual bool SetPowerState(bool on); 34 virtual bool SetChannel(const QString &panel_model, uint channel); 35 36 // Gets 37 virtual bool IsPortOpen(void) const; 38 virtual bool IsTuner(void) const; 39 virtual bool IsPanel(void) const; 40 virtual bool IsSTB(void) const; 41 42 // non-const Gets 43 virtual PowerState GetPowerState(void); 44 45 // Constants 46 static const uint kBroadcastChannel; 47 static const uint kConnectionP2P; 48 static const uint kConnectionBroadcast; 49 static const uint kMaxBufferedPackets; 50 51 private: 52 bool OpenNode(void); 53 bool CloseNode(void); 54 55 bool OpenAVStream(void); 56 bool CloseAVStream(void); 57 58 bool OpenP2PNode(void); 59 bool CloseP2PNode(void); 60 61 bool OpenBroadcastNode(void); 62 bool CloseBroadcastNode(void); 63 64 bool StartStreaming(void); 65 bool StopStreaming(void); 66 bool StopStreamingLater(void); 67 68 bool ResetBus(void); 69 70 void RunStreaming(void); 71 bool LoopIteration(uint timeout_in_msec); 72 void PrintDropped(uint dropped_packets); 73 void BroadcastToListeners(const unsigned char *data, uint dataSize); 74 75 bool SetAVStreamBufferSize(uint size_in_bytes); 76 bool SetAVStreamSpeed(uint speed); 77 78 bool IsNodeOpen(void) const; 79 bool IsAVStreamOpen(void) const; 80 bool IsSubunitType(uint subunit_type) const; 81 82 private: 83 uint m_port; 84 uint m_node; 85 uint m_speed; 86 uint m_bufsz; 87 bool m_use_p2p; 88 bool m_resetting; 89 LFDPriv *m_priv; 90 }; 91 92 #endif // _LINUX_FIREWIRE_DEVICE_H_ -
libs/libmythtv/tv_rec.cpp
48 48 #include "dbox2channel.h" 49 49 #include "hdhrchannel.h" 50 50 #include "iptvchannel.h" 51 #include "firewirechannel.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 "firewirerecorder.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_DARWIN162 channel = new DarwinFirewireChannel(fwOpt, this);163 # else164 153 channel = new FirewireChannel(fwOpt, this); 165 # endif166 154 if (!channel->Open()) 167 155 return false; 168 156 InitChannel(genOpt.defaultinput, startchannel); … … 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 = new FirewireRecorder(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 FirewireChannel *TVRec::GetFirewireChannel(void) 1105 { 1106 #ifdef USING_FIREWIRE 1107 return dynamic_cast<FirewireChannel*>(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 FirewireChannel; 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 FirewireChannel *GetFirewireChannel(void); 264 266 Channel *GetV4LChannel(void); 265 267 266 268 bool SetupSignalMonitor(bool enable_table_monitoring, bool notify); -
libs/libmythtv/selectavcdevice.h
1 /**2 * SelectAVCDevice3 * Copyright (c) 2006 by Dave Abrahams4 * Distributed as part of MythTV under GPL v2 and later.5 */6 7 #ifndef LIBMYTHTV_SELECTAVCDEVICE_H_8 # define LIBMYTHTV_SELECTAVCDEVICE_H_9 10 # include "mythconfig.h"11 12 # ifdef CONFIG_DARWIN13 # undef always_inline14 # include <AVCVideoServices/AVCVideoServices.h>15 16 AVS::AVCDevice* SelectAVCDevice(17 AVS::AVCDeviceController*,18 bool (*)(AVS::AVCDevice*)19 );20 21 # endif // CONFIG_DARWIN22 23 #endif LIBMYTHTV_SELECTAVCDEVICE_H_24 -
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 // Qt headers 15 #include <qstring.h> 16 #include <qmutex.h> 17 18 // MythTV headers 19 #include "streamlisteners.h" 20 21 class TSPacket; 22 23 class FirewireDevice 24 { 25 public: 26 // Public enums 27 typedef enum 28 { 29 kAVCPowerOn, 30 kAVCPowerOff, 31 kAVCPowerUnknown, 32 kAVCPowerQueryFailed, 33 } PowerState; 34 35 FirewireDevice(); 36 virtual ~FirewireDevice() { } 37 38 virtual bool OpenPort(void) = 0; 39 virtual bool ClosePort(void) = 0; 40 41 virtual void AddListener(TSDataListener*); 42 virtual void RemoveListener(TSDataListener*); 43 44 // Sets 45 virtual bool SetPowerState(bool on) = 0; 46 virtual bool SetChannel(const QString &panel_model, uint channel) = 0; 47 48 // Gets 49 virtual bool IsPortOpen(void) const = 0; 50 virtual bool IsTuner(void) const = 0; 51 virtual bool IsPanel(void) const = 0; 52 virtual bool IsSTB(void) const = 0; 53 bool IsSTBBufferCleared(void) const { return m_buffer_cleared; } 54 55 // non-const Gets 56 virtual PowerState GetPowerState(void) = 0; 57 58 // Statics 59 static inline bool IsSTBSupported(const QString &model); 60 61 protected: 62 void SetLastChannel(uint channel); 63 void ProcessPATPacket(const TSPacket&); 64 65 uint m_last_channel; 66 uint m_last_crc; 67 bool m_buffer_cleared; 68 69 uint m_open_port_cnt; 70 vector<TSDataListener*> m_listeners; 71 mutable QMutex m_lock; 72 }; 73 74 inline bool FirewireDevice::IsSTBSupported(const QString &panel_model) 75 { 76 #ifdef USING_LINUX_FIREWIRE 77 QString model = panel_model.upper(); 78 return ((model == "DCT-6200") || 79 (model == "SA3250HD") || 80 (model == "SA4200HD")); 81 #elif USING_OSX_FIREWIRE 82 return true; 83 #else 84 return false; 85 #endif 86 } 87 88 #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 #include <cassert> 15 16 // Linux headers 17 #include <libraw1394/raw1394.h> 18 #include <libiec61883/iec61883.h> 19 #include <libavc1394/avc1394.h> 20 21 // C++ headers 22 #include <algorithm> 23 using namespace std; 24 25 // Qt headers 26 #include <qdatetime.h> 27 28 // MythTV headers 29 #include "linuxfirewiredevice.h" 30 #include "firewirerecorder.h" 31 #include "mythcontext.h" 32 33 #define LOC QString("LFireDev(%1:%2): ").arg(m_port).arg(m_node) 34 #define LOC_WARN QString("LFireDev(%1:%2), Warning: ").arg(m_port).arg(m_node) 35 #define LOC_ERR QString("LFireDev(%1:%2), Error: ").arg(m_port).arg(m_node) 36 37 38 #ifndef AVC1394_PANEL_COMMAND_PASS_THROUGH 39 #define AVC1394_PANEL_COMMAND_PASS_THROUGH 0x000007C00 40 #endif 41 42 #ifndef AVC1394_PANEL_OPERATION_0 43 #define AVC1394_PANEL_OPERATION_0 0x000000020 44 #endif 45 46 #define AVC1394_CMD_OPERAND_POWER_STATE 0x7F 47 48 // Basic Panel commands 49 #define PANEL_CMD0 (AVC1394_CTYPE_CONTROL | \ 50 AVC1394_SUBUNIT_TYPE_PANEL | \ 51 AVC1394_SUBUNIT_ID_0 | \ 52 AVC1394_PANEL_COMMAND_PASS_THROUGH) 53 54 // Scientific Atlanta defines 55 #define AVC1394_SA3250_OPERAND_KEY_PRESS 0xE7 56 #define AVC1394_SA3250_OPERAND_KEY_RELEASE 0x67 57 #define SA_CMD0 PANEL_CMD0 58 #define SA_CMD1 AVC1394_CTYPE_GENERAL_INQUIRY 59 #define SA_CMD2 0xff000000 60 61 // Motorola defines 62 #define MOT_CMD0 (PANEL_CMD0 | AVC1394_PANEL_OPERATION_0) 63 64 class LFDPriv 65 { 66 public: 67 LFDPriv() : 68 handle(0), avstream(0), 69 channel(-1), 70 is_p2p_node_open(false), is_bcast_node_open(false), 71 is_streaming(false) 72 { 73 bzero(unit_table, sizeof(unit_table)); 74 } 75 76 raw1394handle_t handle; 77 iec61883_mpeg2_t avstream; 78 quadlet_t unit_table[8]; 79 int channel; 80 int open_node; 81 bool is_p2p_node_open; 82 bool is_bcast_node_open; 83 bool is_streaming; 84 bool is_streaming_running; 85 QDateTime stop_streaming_timer; 86 pthread_t streaming_thread; 87 QMutex start_stop_streaming_lock; 88 }; 89 90 const uint LinuxFirewireDevice::kBroadcastChannel = 63; 91 const uint LinuxFirewireDevice::kConnectionP2P = 0; 92 const uint LinuxFirewireDevice::kConnectionBroadcast = 1; 93 const uint LinuxFirewireDevice::kMaxBufferedPackets = 2000; 94 95 // callback function for libiec61883 96 int linux_firewire_device_tspacket_handler( 97 unsigned char *tspacket, int len, uint dropped, void *callback_data); 98 static QString speed_to_string(uint speed); 99 static quadlet_t *send_avc_command(raw1394handle_t handle, 100 uint node, 101 quadlet_t *cmd, 102 uint cmd_len, 103 uint retry_cnt = 1); 104 static void close_avc_command(raw1394handle_t handle); 105 106 107 LinuxFirewireDevice::LinuxFirewireDevice( 108 uint port, uint node, uint speed, bool use_p2p, 109 uint av_buffer_size_in_bytes) : 110 m_port(port), m_node(node), 111 m_speed(speed), m_bufsz(av_buffer_size_in_bytes), 112 m_use_p2p(use_p2p), m_resetting(false), 113 m_priv(new LFDPriv()) 114 { 115 if (!m_bufsz) 116 m_bufsz = gContext->GetNumSetting("HDRingbufferSize"); 117 } 118 119 LinuxFirewireDevice::~LinuxFirewireDevice() 120 { 121 if (IsPortOpen()) 122 { 123 VERBOSE(VB_IMPORTANT, LOC_ERR + "ctor called with open port"); 124 while (IsPortOpen()) 125 ClosePort(); 126 } 127 128 if (m_priv) 129 { 130 delete m_priv; 131 m_priv = NULL; 132 } 133 } 134 135 bool LinuxFirewireDevice::OpenPort(void) 136 { 137 QMutexLocker locker(&m_lock); 138 139 VERBOSE(VB_RECORD, LOC + "OpenPort()"); 140 141 m_open_port_cnt++; 142 143 if (m_priv->handle) 144 return true; 145 146 VERBOSE(VB_RECORD, LOC + "Getting raw1394 handle "<<(m_open_port_cnt-1)); 147 m_priv->handle = raw1394_new_handle_on_port(m_port); 148 149 if (!m_priv->handle) 150 { 151 VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to get handle for " + 152 QString("port: %1").arg(m_port) + ENO); 153 154 return false; 155 } 156 157 if (avc1394_subunit_info(m_priv->handle, m_node, m_priv->unit_table) < 0) 158 bzero(m_priv->unit_table, sizeof(m_priv->unit_table)); 159 160 QString str = "Subunit Types: "; 161 162 if (IsSubunitType(AVC1394_SUBUNIT_TYPE_VIDEO_MONITOR)) 163 str += "Video Monitor, "; 164 if (IsSubunitType(AVC1394_SUBUNIT_TYPE_AUDIO)) 165 str += "Audio, "; 166 if (IsSubunitType(AVC1394_SUBUNIT_TYPE_PRINTER)) 167 str += "Printer, "; 168 if (IsSubunitType(AVC1394_SUBUNIT_TYPE_DISC_RECORDER)) 169 str += "Disk Recorder, "; 170 if (IsSubunitType(AVC1394_SUBUNIT_TYPE_TAPE_RECORDER)) 171 str += "Tape Recorder, "; 172 if (IsSubunitType(AVC1394_SUBUNIT_TYPE_VCR)) 173 str += "VCR, "; 174 if (IsSubunitType(AVC1394_SUBUNIT_TYPE_TUNER)) 175 str += "Tuner, "; 176 if (IsSubunitType(AVC1394_SUBUNIT_TYPE_CA)) 177 str += "CA, "; 178 if (IsSubunitType(AVC1394_SUBUNIT_TYPE_VIDEO_CAMERA)) 179 str += "Camera, "; 180 if (IsSubunitType(AVC1394_SUBUNIT_TYPE_PANEL)) 181 str += "Panel, "; 182 if (IsSubunitType(AVC1394_SUBUNIT_TYPE_BULLETIN_BOARD)) 183 str += "Bulletin Board, "; 184 if (IsSubunitType(AVC1394_SUBUNIT_TYPE_CAMERA_STORAGE)) 185 str += "Camera Storage, "; 186 if (IsSubunitType(AVC1394_SUBUNIT_TYPE_MUSIC)) 187 str += "Music, "; 188 if (IsSubunitType(AVC1394_SUBUNIT_TYPE_VENDOR_UNIQUE)) 189 str += "Vendor Unique, "; 190 191 VERBOSE(VB_RECORD, LOC + str); 192 193 return true; 194 } 195 196 bool LinuxFirewireDevice::ClosePort(void) 197 { 198 QMutexLocker locker(&m_lock); 199 200 VERBOSE(VB_RECORD, LOC + "ClosePort()"); 201 202 if (m_open_port_cnt < 1) 203 return false; 204 205 m_open_port_cnt--; 206 207 if (m_open_port_cnt != 0) 208 return true; 209 210 if (m_priv->handle) 211 { 212 if (IsNodeOpen()) 213 CloseNode(); 214 215 VERBOSE(VB_RECORD, LOC + "Releasing raw1394 handle "<<m_open_port_cnt); 216 raw1394_destroy_handle(m_priv->handle); 217 m_priv->handle = NULL; 218 } 219 220 return true; 221 } 222 223 bool LinuxFirewireDevice::OpenNode(void) 224 { 225 if (m_use_p2p) 226 return OpenP2PNode(); 227 else 228 return OpenBroadcastNode(); 229 } 230 231 bool LinuxFirewireDevice::CloseNode(void) 232 { 233 if (m_priv->is_p2p_node_open) 234 return CloseP2PNode(); 235 236 if (m_priv->is_bcast_node_open) 237 return CloseBroadcastNode(); 238 239 return true; 240 } 241 242 bool LinuxFirewireDevice::OpenP2PNode(void) 243 { 244 if (m_priv->is_bcast_node_open) 245 return false; 246 247 if (m_priv->is_p2p_node_open) 248 return true; 249 250 VERBOSE(VB_RECORD, LOC + "Opening P2P connection"); 251 252 m_priv->channel = m_node; 253 if (iec61883_cmp_create_p2p_output(m_priv->handle, m_node | 0xffc0, 0, 254 m_priv->channel, m_speed) != 0) 255 { 256 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to create P2P connection"); 257 258 m_priv->channel = -1; 259 return false; 260 } 261 262 m_priv->is_p2p_node_open = true; 263 264 return true; 265 } 266 267 bool LinuxFirewireDevice::CloseP2PNode(void) 268 { 269 if (m_priv->is_p2p_node_open && (m_priv->channel >= 0)) 270 { 271 VERBOSE(VB_RECORD, LOC + "Closing P2P connection"); 272 273 if (m_priv->avstream) 274 CloseAVStream(); 275 276 iec61883_cmp_disconnect(m_priv->handle, m_node | 0xffc0, 0, 277 raw1394_get_local_id(m_priv->handle), 278 -1, m_priv->channel, 0); 279 280 m_priv->channel = -1; 281 m_priv->is_p2p_node_open = false; 282 } 283 284 return true; 285 } 286 287 bool LinuxFirewireDevice::OpenBroadcastNode(void) 288 { 289 if (m_priv->is_p2p_node_open) 290 return false; 291 292 if (m_priv->is_bcast_node_open) 293 return true; 294 295 m_priv->channel = kBroadcastChannel - m_node; 296 297 VERBOSE(VB_RECORD, LOC + "Opening broadcast connection on " + 298 QString("node %1, channel %2") 299 .arg(m_node).arg(m_priv->channel)); 300 301 if (m_priv->avstream) 302 CloseAVStream(); 303 304 int err = iec61883_cmp_create_bcast_output( 305 m_priv->handle, m_node | 0xffc0, 0, m_priv->channel, m_speed); 306 307 if (err != 0) 308 { 309 VERBOSE(VB_IMPORTANT, LOC_ERR + 310 "Failed to create Broadcast connection"); 311 312 m_priv->channel = -1; 313 return false; 314 } 315 316 m_priv->is_bcast_node_open = true; 317 318 return true; 319 } 320 321 bool LinuxFirewireDevice::CloseBroadcastNode(void) 322 { 323 if (m_priv->is_bcast_node_open) 324 { 325 VERBOSE(VB_RECORD, LOC + "Closing broadcast connection"); 326 327 m_priv->channel = -1; 328 m_priv->is_bcast_node_open = false; 329 } 330 return true; 331 } 332 333 bool LinuxFirewireDevice::OpenAVStream(void) 334 { 335 VERBOSE(VB_RECORD, LOC + "OpenAVStream"); 336 337 if (!IsNodeOpen() && !OpenNode()) 338 return false; 339 340 if (m_priv->avstream) 341 return true; 342 343 VERBOSE(VB_RECORD, LOC + "Opening A/V stream object"); 344 345 if (!m_priv->handle) 346 { 347 VERBOSE(VB_IMPORTANT, LOC + 348 "Can not open AVStream without IEEE 1394 Port"); 349 350 return false; 351 } 352 353 m_priv->avstream = iec61883_mpeg2_recv_init( 354 m_priv->handle, linux_firewire_device_tspacket_handler, this); 355 356 if (!m_priv->avstream) 357 { 358 VERBOSE(VB_IMPORTANT, LOC + "Unable to open AVStream" + ENO); 359 360 return false; 361 } 362 363 iec61883_mpeg2_set_synch(m_priv->avstream, 1 /* sync on close */); 364 365 if (m_bufsz) 366 SetAVStreamBufferSize(m_bufsz); 367 368 return true; 369 } 370 371 bool LinuxFirewireDevice::CloseAVStream(void) 372 { 373 if (!m_priv->avstream) 374 return true; 375 376 VERBOSE(VB_RECORD, LOC + "Closing A/V stream object"); 377 378 while (!m_resetting && m_listeners.size()) 379 RemoveListener(m_listeners[m_listeners.size() - 1]); 380 381 if (m_priv->is_streaming) 382 StopStreaming(); 383 384 iec61883_mpeg2_close(m_priv->avstream); 385 m_priv->avstream = NULL; 386 387 return true; 388 } 389 390 void *linux_firewire_device_streaming_thunk(void *param) 391 { 392 LinuxFirewireDevice *mon = (LinuxFirewireDevice*) param; 393 mon->RunStreaming(); 394 return NULL; 395 } 396 397 void LinuxFirewireDevice::RunStreaming(void) 398 { 399 VERBOSE(VB_RECORD, LOC + "RunStreaming -- start"); 400 m_lock.lock(); 401 m_priv->is_streaming_running = true; 402 403 uint no_data_cnt = 0; 404 while (m_priv->is_streaming) 405 { 406 no_data_cnt = (LoopIteration(50)) ? 0 : no_data_cnt + 1; 407 408 if (m_priv->is_streaming && (no_data_cnt > 30)) 409 { 410 no_data_cnt = 0; 411 412 iec61883_mpeg2_recv_stop(m_priv->avstream); 413 raw1394_iso_recv_flush(m_priv->handle); 414 m_priv->is_streaming = false; 415 ResetBus(); 416 iec61883_mpeg2_recv_start(m_priv->avstream, m_priv->channel); 417 m_priv->is_streaming = true; 418 } 419 } 420 421 m_priv->is_streaming_running = false; 422 m_lock.unlock(); 423 VERBOSE(VB_RECORD, LOC + "RunStreaming -- end"); 424 } 425 426 bool LinuxFirewireDevice::StartStreaming(void) 427 { 428 VERBOSE(VB_RECORD, LOC + "Starting A/V streaming"); 429 QMutexLocker locker(&m_priv->start_stop_streaming_lock); 430 VERBOSE(VB_RECORD, LOC + "Starting A/V streaming -- locked"); 431 432 if (m_priv->is_streaming) 433 return m_priv->is_streaming; 434 435 assert(!m_priv->is_streaming_running); 436 437 if (!IsAVStreamOpen() && !OpenAVStream()) 438 return false; 439 440 if (!m_priv->avstream) 441 { 442 VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting A/V streaming, no A/V obj"); 443 return false; 444 } 445 446 if (m_priv->channel < 0) 447 { 448 VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting A/V streaming, no channel"); 449 return false; 450 } 451 452 VERBOSE(VB_RECORD, LOC + "Starting A/V streaming -- really"); 453 454 if (iec61883_mpeg2_recv_start(m_priv->avstream, m_priv->channel) == 0) 455 { 456 m_priv->is_streaming = true; 457 458 pthread_create(&m_priv->streaming_thread, NULL, 459 linux_firewire_device_streaming_thunk, this); 460 461 m_lock.unlock(); 462 while (!m_priv->is_streaming_running) 463 usleep(50); 464 m_lock.lock(); 465 } 466 else 467 { 468 VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting A/V streaming " + ENO); 469 } 470 471 return m_priv->is_streaming; 472 } 473 474 bool LinuxFirewireDevice::StopStreaming(void) 475 { 476 VERBOSE(VB_RECORD, LOC + "Stopping A/V streaming"); 477 QMutexLocker locker(&m_priv->start_stop_streaming_lock); 478 VERBOSE(VB_RECORD, LOC + "Stopping A/V streaming -- locked"); 479 480 if (m_priv->is_streaming) 481 { 482 VERBOSE(VB_RECORD, LOC + "Stopping A/V streaming -- really"); 483 484 m_priv->is_streaming = false; 485 486 VERBOSE(VB_RECORD, LOC + "Waiting for A/V streaming to stop"); 487 while (m_priv->is_streaming_running) 488 { 489 m_lock.unlock(); 490 usleep(50); 491 m_lock.lock(); 492 } 493 494 VERBOSE(VB_RECORD, LOC + "Joining A/V streaming thread"); 495 pthread_join(m_priv->streaming_thread, NULL); 496 497 iec61883_mpeg2_recv_stop(m_priv->avstream); 498 499 raw1394_iso_recv_flush(m_priv->handle); 500 } 501 502 VERBOSE(VB_RECORD, LOC + "Stopped A/V streaming"); 503 504 return true; 505 } 506 507 bool LinuxFirewireDevice::StopStreamingLater(void) 508 { 509 // TODO 510 return true; 511 } 512 513 bool LinuxFirewireDevice::SetAVStreamBufferSize(uint size_in_bytes) 514 { 515 if (!m_priv->avstream) 516 return false; 517 518 // Set buffered packets size 519 uint buffer_size = max(size_in_bytes, 50 * TSPacket::SIZE); 520 size_t buffered_packets = min(buffer_size / 4, kMaxBufferedPackets); 521 522 iec61883_mpeg2_set_buffers(m_priv->avstream, buffered_packets); 523 524 VERBOSE(VB_IMPORTANT, LOC + 525 QString("Buffered packets %1 (%2 KB)") 526 .arg(buffered_packets).arg(buffered_packets * 4)); 527 528 return true; 529 } 530 531 bool LinuxFirewireDevice::SetAVStreamSpeed(uint speed) 532 { 533 if (!m_priv->avstream) 534 return false; 535 536 uint curspeed = iec61883_mpeg2_get_speed(m_priv->avstream); 537 538 if (curspeed == speed) 539 { 540 m_speed = speed; 541 return true; 542 } 543 544 VERBOSE(VB_RECORD, LOC + 545 QString("Changing Speed %1 -> %2") 546 .arg(speed_to_string(curspeed)) 547 .arg(speed_to_string(m_speed))); 548 549 iec61883_mpeg2_set_speed(m_priv->avstream, speed); 550 551 if (speed == (uint)iec61883_mpeg2_get_speed(m_priv->avstream)) 552 { 553 m_speed = speed; 554 return true; 555 } 556 557 VERBOSE(VB_IMPORTANT, LOC_WARN + "Unable to set firewire speed."); 558 559 return false; 560 } 561 562 bool LinuxFirewireDevice::IsSubunitType(uint subunit_type) const 563 { 564 for (uint i = 0; i < 8; i++) 565 { 566 for (uint j = 0; j < 32; j += 8) 567 { 568 uint subunit = (m_priv->unit_table[i] >> j) & 0xff; 569 if ((subunit != 0xff) && 570 (subunit >> 3) == AVC1394_GET_SUBUNIT_TYPE(subunit_type)) 571 { 572 return true; 573 } 574 } 575 } 576 return false; 577 } 578 579 bool LinuxFirewireDevice::IsTuner(void) const 580 { 581 QMutexLocker locker(&m_lock); 582 583 return IsSubunitType(AVC1394_SUBUNIT_TYPE_TUNER); 584 } 585 586 bool LinuxFirewireDevice::IsPanel(void) const 587 { 588 QMutexLocker locker(&m_lock); 589 590 return IsSubunitType(AVC1394_SUBUNIT_TYPE_PANEL); 591 } 592 593 bool LinuxFirewireDevice::IsSTB(void) const 594 { 595 QMutexLocker locker(&m_lock); 596 597 return (IsSubunitType(AVC1394_SUBUNIT_TYPE_TUNER) && 598 IsSubunitType(AVC1394_SUBUNIT_TYPE_PANEL)); 599 } 600 601 bool LinuxFirewireDevice::IsPortOpen(void) const 602 { 603 QMutexLocker locker(&m_lock); 604 605 return m_priv->handle; 606 } 607 608 bool LinuxFirewireDevice::IsNodeOpen(void) const 609 { 610 return m_priv->is_p2p_node_open || m_priv->is_bcast_node_open; 611 } 612 613 bool LinuxFirewireDevice::IsAVStreamOpen(void) const 614 { 615 return m_priv->avstream; 616 } 617 618 bool LinuxFirewireDevice::ResetBus(void) 619 { 620 if (m_priv->is_streaming) 621 { 622 VERBOSE(VB_IMPORTANT, LOC_ERR + 623 "ResetBus() can not be called while streaming"); 624 } 625 626 m_resetting = true; 627 VERBOSE(VB_IMPORTANT, LOC + "ResetBus() -- begin"); 628 629 bool open_node = IsNodeOpen(); 630 bool open_avstream = IsAVStreamOpen(); 631 632 CloseAVStream(); 633 CloseNode(); 634 635 bool ok = (raw1394_reset_bus_new(m_priv->handle, RAW1394_LONG_RESET) == 0); 636 if (!ok) 637 VERBOSE(VB_IMPORTANT, LOC_ERR + "Bus Reset failed" + ENO); 638 639 if (open_node) 640 ok &= OpenNode(); 641 642 if (open_avstream) 643 ok &= OpenAVStream(); 644 645 VERBOSE(VB_IMPORTANT, LOC + "ResetBus() -- end"); 646 m_resetting = false; 647 648 return ok; 649 } 650 651 bool LinuxFirewireDevice::LoopIteration(uint timeout_in_msec) 652 { 653 if (m_resetting) 654 return true; 655 656 int fwfd = raw1394_get_fd(m_priv->handle); 657 if (fwfd < 0) 658 return false; 659 660 struct timeval tv; 661 fd_set rfds; 662 663 FD_ZERO(&rfds); 664 FD_SET(fwfd, &rfds); 665 666 tv.tv_sec = timeout_in_msec / 1000; 667 tv.tv_usec = (timeout_in_msec % 1000) * 1000; 668 669 m_lock.unlock(); 670 if (select(fwfd + 1, &rfds, NULL, NULL, &tv) <= 0) 671 { 672 m_lock.lock(); 673 VERBOSE(VB_IMPORTANT, LOC + QString("No Input in %1 msec...") 674 .arg(timeout_in_msec)); 675 676 return false; 677 } 678 m_lock.lock(); 679 680 int ret = raw1394_loop_iterate(m_priv->handle); 681 if (ret) 682 { 683 VERBOSE(VB_IMPORTANT, LOC_ERR + "libraw1394_loop_iterate() " + 684 QString("returned %1").arg(ret)); 685 686 return false; 687 } 688 689 return true; 690 } 691 692 void LinuxFirewireDevice::AddListener(TSDataListener *listener) 693 { 694 FirewireDevice::AddListener(listener); 695 696 QMutexLocker locker(&m_lock); 697 if (!m_listeners.empty()) 698 { 699 OpenNode(); 700 OpenAVStream(); 701 StartStreaming(); 702 } 703 } 704 705 void LinuxFirewireDevice::RemoveListener(TSDataListener *listener) 706 { 707 FirewireDevice::RemoveListener(listener); 708 709 QMutexLocker locker(&m_lock); 710 if (m_listeners.empty()) 711 { 712 StopStreaming(); 713 CloseAVStream(); 714 CloseNode(); 715 } 716 } 717 718 void LinuxFirewireDevice::BroadcastToListeners( 719 const unsigned char *data, uint dataSize) 720 { 721 if ((dataSize >= TSPacket::SIZE) && (data[0] == SYNC_BYTE) && 722 ((data[1] & 0x1f) == 0) && (data[2] == 0)) 723 { 724 ProcessPATPacket(*((const TSPacket*)data)); 725 } 726 727 vector<TSDataListener*>::iterator it = m_listeners.begin(); 728 for (; it != m_listeners.end(); ++it) 729 (*it)->AddData(data, dataSize); 730 } 731 732 bool LinuxFirewireDevice::SetChannel(const QString &panel_model, uint channel) 733 { 734 QMutexLocker locker(&m_lock); 735 736 if (!IsSTBSupported(panel_model)) 737 { 738 VERBOSE(VB_IMPORTANT, LOC_ERR + 739 QString("Model: '%1' ").arg(panel_model) + 740 "is not supported by internal channel changer."); 741 return false; 742 } 743 744 int digit[3]; 745 digit[0] = (channel % 1000) / 100; 746 digit[1] = (channel % 100) / 10; 747 digit[2] = (channel % 10); 748 749 if (panel_model.upper() == "DCT-6200") 750 { 751 for (uint i = 0; i < 3 ;i++) 752 { 753 quadlet_t cmd[2] = 754 { 755 MOT_CMD0 | AVC1394_PANEL_OPERATION_0 | digit[i], 756 0x0, 757 }; 758 759 if (!send_avc_command(m_priv->handle, m_node, cmd, 2)) 760 return false; 761 762 usleep(500000); 763 } 764 765 SetLastChannel(channel); 766 return true; 767 } 768 769 if (panel_model.upper() == "SA4200HD") 770 { 771 quadlet_t cmd[3] = 772 { 773 SA_CMD0 | AVC1394_SA3250_OPERAND_KEY_PRESS, 774 SA_CMD1 | (channel << 8), 775 SA_CMD2, 776 }; 777 778 if (!send_avc_command(m_priv->handle, m_node, cmd, 3)) 779 return false; 780 781 SetLastChannel(channel); 782 return true; 783 } 784 785 if (panel_model == "SA3250HD") 786 { 787 digit[0] |= 0x30; 788 digit[1] |= 0x30; 789 digit[2] |= 0x30; 790 791 quadlet_t cmd[3] = 792 { 793 SA_CMD0 | AVC1394_SA3250_OPERAND_KEY_PRESS, 794 SA_CMD1 | (digit[2] << 16) | (digit[1] << 8) | digit[0], 795 SA_CMD2, 796 }; 797 798 VERBOSE(VB_CHANNEL, LOC + 799 QString("Channel2: %1%2%3 cmds: 0x%4, 0x%5, 0x%6") 800 .arg(digit[0] & 0xf).arg(digit[1] & 0xf) 801 .arg(digit[2] & 0xf) 802 .arg(cmd[0], 0, 16).arg(cmd[1], 0, 16) 803 .arg(cmd[2], 0, 16)); 804 805 if (!send_avc_command(m_priv->handle, m_node, cmd, 3)) 806 return false; 807 808 cmd[0] = SA_CMD0 | AVC1394_SA3250_OPERAND_KEY_RELEASE; 809 cmd[1] = SA_CMD1 | (digit[0] << 16) | (digit[1] << 8) | digit[2]; 810 cmd[2] = SA_CMD2; 811 812 VERBOSE(VB_CHANNEL, LOC + 813 QString("Channel3: %1%2%3 cmds: 0x%4, 0x%5, 0x%6") 814 .arg(digit[0] & 0xf).arg(digit[1] & 0xf) 815 .arg(digit[2] & 0xf) 816 .arg(cmd[0], 0, 16).arg(cmd[1], 0, 16) 817 .arg(cmd[2], 0, 16)); 818 819 if (!send_avc_command(m_priv->handle, m_node, cmd, 3)) 820 return false; 821 822 SetLastChannel(channel); 823 return true; 824 } 825 826 return false; 827 } 828 829 bool LinuxFirewireDevice::SetPowerState(bool on) 830 { 831 QMutexLocker locker(&m_lock); 832 833 quadlet_t cmd = 834 AVC1394_CTYPE_CONTROL | AVC1394_SUBUNIT_TYPE_UNIT | 835 AVC1394_SUBUNIT_ID_IGNORE | AVC1394_COMMAND_POWER; 836 837 cmd |= (on) ? AVC1394_CMD_OPERAND_POWER_ON : AVC1394_CMD_OPERAND_POWER_OFF; 838 839 QString cmdStr = (on) ? "on" : "off"; 840 VERBOSE(VB_RECORD, LOC + QString("Powering %1 (cmd: 0x%2)") 841 .arg(cmdStr).arg(cmd, 0, 16)); 842 843 quadlet_t *rval = send_avc_command(m_priv->handle, m_node, &cmd, 1); 844 845 if (!rval) 846 { 847 close_avc_command(m_priv->handle); 848 VERBOSE(VB_IMPORTANT, LOC + "Power on cmd failed (no response)"); 849 return false; 850 } 851 852 quadlet_t response = rval[0]; 853 close_avc_command(m_priv->handle); 854 855 if (AVC1394_MASK_RESPONSE(response) != AVC1394_RESPONSE_ACCEPTED) 856 { 857 VERBOSE(VB_IMPORTANT, LOC_ERR + 858 QString("Power %1 cmd failed (0x%2)") 859 .arg(cmdStr).arg(response, 0, 16)); 860 861 return false; 862 } 863 864 VERBOSE(VB_RECORD, LOC + 865 QString("Power %1 cmd sent successfully (0x%2)") 866 .arg(cmdStr).arg(response, 0, 16)); 867 868 return true; 869 } 870 871 FirewireDevice::PowerState LinuxFirewireDevice::GetPowerState(void) 872 { 873 QMutexLocker locker(&m_lock); 874 875 quadlet_t cmd = 876 AVC1394_CTYPE_STATUS | AVC1394_SUBUNIT_TYPE_UNIT | 877 AVC1394_SUBUNIT_ID_IGNORE | AVC1394_COMMAND_POWER | 878 AVC1394_CMD_OPERAND_POWER_STATE; 879 880 VERBOSE(VB_CHANNEL, LOC + QString("Requesting STB Power State (cmd: 0x%1)") 881 .arg(cmd, 0, 16)); 882 883 quadlet_t *rval = send_avc_command(m_priv->handle, m_node, &cmd, 1); 884 885 if (!rval) 886 { 887 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to get STB Power State"); 888 return kAVCPowerQueryFailed; 889 } 890 891 quadlet_t response = rval[0]; 892 // TODO we probably need to call close_avc_command(m_priv->handle)... 893 894 QString loc = LOC + "STB Power State: "; 895 QString rs = QString(" (0x%1)").arg(response, 0, 16); 896 897 if (AVC1394_MASK_RESPONSE(response) != AVC1394_RESPONSE_IMPLEMENTED) 898 { 899 VERBOSE(VB_CHANNEL, loc + "Query not implemented" + rs); 900 return kAVCPowerUnknown; 901 } 902 903 if (AVC1394_MASK_OPERAND0(response) == AVC1394_CMD_OPERAND_POWER_ON) 904 { 905 VERBOSE(VB_CHANNEL, loc + "On" + rs); 906 return kAVCPowerOn; 907 } 908 909 if (AVC1394_MASK_OPERAND0(response) == AVC1394_CMD_OPERAND_POWER_OFF) 910 { 911 VERBOSE(VB_CHANNEL, loc + "Off" + rs); 912 return kAVCPowerOff; 913 } 914 915 VERBOSE(VB_IMPORTANT, LOC_ERR + "STB Power State: Unknown Response" + rs); 916 917 return kAVCPowerUnknown; 918 } 919 920 void LinuxFirewireDevice::PrintDropped(uint dropped_packets) 921 { 922 if (dropped_packets == 1) 923 { 924 VERBOSE(VB_RECORD, LOC_ERR + "Dropped a TS packet"); 925 } 926 else if (dropped_packets > 1) 927 { 928 VERBOSE(VB_RECORD, LOC_ERR + 929 QString("Dropped %1 TS packets").arg(dropped_packets)); 930 } 931 } 932 933 int linux_firewire_device_tspacket_handler( 934 unsigned char *tspacket, int len, uint dropped, void *callback_data) 935 { 936 LinuxFirewireDevice *fw = (LinuxFirewireDevice*) callback_data; 937 if (!fw) 938 return 0; 939 940 if (dropped) 941 fw->PrintDropped(dropped); 942 943 if (len > 0) 944 fw->BroadcastToListeners(tspacket, len); 945 946 return 1; 947 } 948 949 static QString speed_to_string(uint speed) 950 { 951 if (speed > RAW1394_ISO_SPEED_400) 952 return QString("Invalid Speed (%1)").arg(speed); 953 954 static const uint speeds[] = { 100, 200, 400, }; 955 return QString("%1Mbps").arg(speeds[speed]); 956 } 957 958 static quadlet_t *send_avc_command(raw1394handle_t handle, 959 uint node, 960 quadlet_t *cmd, 961 uint cmd_len, 962 uint retry_cnt) 963 { 964 if (!handle) 965 return NULL; 966 967 quadlet_t *ret = avc1394_transaction_block( 968 handle, node, cmd, cmd_len, retry_cnt); 969 970 if (!ret) 971 VERBOSE(VB_IMPORTANT, "AVC transaction failed."); 972 973 return ret; 974 } 975 976 static void close_avc_command(raw1394handle_t handle) 977 { 978 if (handle) 979 avc1394_transaction_block_close(handle); 980 } 981
