Ticket #1648: firewire-sm-v18.patch

File firewire-sm-v18.patch, 87.6 KB (added by danielk, 17 years ago)

Updated patch, this monitors the PAT for changes so that we can short circuit the 5 second STB buffer flush.

  • libs/libmythtv/firewirechannel.cpp

     
    11/**
    22 *  FirewireChannel
    33 *  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
    64 *  Distributed as part of MythTV under GPL v2 and later.
    75 */
    86
    9 
    10 #include <iostream>
     7// MythTV headers
    118#include "mythcontext.h"
    129#include "firewirechannel.h"
     10#include "linuxfirewiredevice.h"
    1311
    1412class TVRec;
    1513
    16 #define LOC QString("FireChan: ")
    17 #define LOC_ERR QString("FireChan, Error: ")
     14#define LOC QString("FireChan(%1): ").arg(GetDevice())
     15#define LOC_WARN QString("FireChan(%1), Warning: ").arg(GetDevice())
     16#define LOC_ERR QString("FireChan(%1), Error: ").arg(GetDevice())
    1817
    19 #ifndef AVC1394_PANEL_COMMAND_PASS_THROUGH
    20 #define AVC1394_PANEL_COMMAND_PASS_THROUGH     0x000007C00
    21 #endif
    22 
    23 #ifndef AVC1394_PANEL_OPERATION_0
    24 #define AVC1394_PANEL_OPERATION_0              0x000000020
    25 #endif
    26 
    27 #define DCT6200_CMD0  (AVC1394_CTYPE_CONTROL | \
    28                        AVC1394_SUBUNIT_TYPE_PANEL | \
    29                        AVC1394_SUBUNIT_ID_0 | \
    30                        AVC1394_PANEL_COMMAND_PASS_THROUGH | \
    31                        AVC1394_PANEL_OPERATION_0)
    32 
    33 // SA3250HD defines
    34 #define AVC1394_SA3250_OPERAND_KEY_PRESS        0xE7
    35 #define AVC1394_SA3250_OPERAND_KEY_RELEASE      0x67
    36 
    37 #define SA3250_CMD0   (AVC1394_CTYPE_CONTROL | \
    38                        AVC1394_SUBUNIT_TYPE_PANEL | \
    39                        AVC1394_SUBUNIT_ID_0 | \
    40                        AVC1394_PANEL_COMMAND_PASS_THROUGH)
    41 #define SA3250_CMD1   (0x04 << 24)
    42 #define SA3250_CMD2    0xff000000
    43 
    44 // power defines
    45 #define AVC1394_CMD_OPERAND_POWER_STATE        0x7F
    46 #define STB_POWER_STATE   (AVC1394_CTYPE_STATUS | \
    47                            AVC1394_SUBUNIT_TYPE_UNIT | \
    48                            AVC1394_SUBUNIT_ID_IGNORE | \
    49                            AVC1394_COMMAND_POWER | \
    50                            AVC1394_CMD_OPERAND_POWER_STATE)
    51 
    52 #define STB_POWER_ON      (AVC1394_CTYPE_CONTROL | \
    53                            AVC1394_SUBUNIT_TYPE_UNIT | \
    54                            AVC1394_SUBUNIT_ID_IGNORE | \
    55                            AVC1394_COMMAND_POWER | \
    56                            AVC1394_CMD_OPERAND_POWER_ON)
    57 
    58 static bool is_supported(const QString &model)
     18LinuxFirewireChannel::LinuxFirewireChannel(
     19    FireWireDBOptions firewire_opts, TVRec *parent) :
     20    FirewireChannelBase(parent),
     21    fw_opts(firewire_opts),
     22    device(new LinuxFirewireDevice(
     23               fw_opts.port, fw_opts.node, fw_opts.speed,
     24               LinuxFirewireDevice::kConnectionP2P ==
     25               (uint) fw_opts.connection)),
     26    current_channel(0),
     27    is_port_open(false)
    5928{
    60     return ((model == "DCT-6200") ||
    61             (model == "SA3250HD") ||
    62             (model == "SA4200HD"));
    6329}
    6430
    65 FirewireChannel::FirewireChannel(FireWireDBOptions firewire_opts,
    66                                  TVRec *parent)
    67     : FirewireChannelBase(parent), fw_opts(firewire_opts), fwhandle(NULL)
     31LinuxFirewireChannel::~LinuxFirewireChannel(void)
    6832{
    69 }
    70 
    71 FirewireChannel::~FirewireChannel(void)
    72 {
    7333    Close();
    7434}
    7535
    76 bool FirewireChannel::SetChannelByNumber(int channel)
     36bool LinuxFirewireChannel::Retune(void)
    7737{
    78     // Change channel using internal changer
     38    VERBOSE(VB_CHANNEL, LOC + "Retune()");
    7939
    80     if (!is_supported(fw_opts.model))
     40    if (FirewireDevice::kAVCPowerOff == GetPowerState())
    8141    {
    8242        VERBOSE(VB_IMPORTANT, LOC_ERR +
    83                 QString("Model: '%1' ").arg(fw_opts.model) +
    84                 "is not supported by internal channel changer.");
     43                "STB is turned off, must be on to retune.");
     44
    8545        return false;
    8646    }
    8747
    88     int dig[3];
    89     dig[0] = (channel % 1000) / 100;
    90     dig[1] = (channel % 100)  / 10;
    91     dig[2] = (channel % 10);
     48    if (current_channel)
     49        return SetChannelByNumber(current_channel);
    9250
    93     if (fw_opts.model == "DCT-6200")
    94     {
    95         VERBOSE(VB_CHANNEL, LOC +
    96                 QString("Channel1: %1%2%3 cmds: 0x%4, 0x%5, 0x%6")
    97                 .arg(dig[0]).arg(dig[1])
    98                 .arg(dig[2]).arg(DCT6200_CMD0 | dig[0], 0, 16)
    99                 .arg(DCT6200_CMD0 | dig[1], 0, 16)
    100                 .arg(DCT6200_CMD0 | dig[2], 0, 16));
     51    return false;
     52}
    10153
    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")
     54bool LinuxFirewireChannel::SetChannelByNumber(int channel)
     55{
     56    current_channel = channel;
     57
     58    if (FirewireDevice::kAVCPowerOff == GetPowerState())
    11459    {
    115         dig[0] |= 0x30;
    116         dig[1] |= 0x30;
    117         dig[2] |= 0x30;
     60        VERBOSE(VB_IMPORTANT, LOC_WARN +
     61                "STB is turned off, must be on to set channel.");
    11862
    119         quadlet_t cmd[3] =
    120         {
    121             SA3250_CMD0 | AVC1394_SA3250_OPERAND_KEY_PRESS,
    122             SA3250_CMD1 | (dig[2] << 16) | (dig[1] << 8) | dig[0],
    123             SA3250_CMD2,
    124         };
     63        SetSIStandard("mpeg");
     64        SetCachedATSCInfo(QString("%1-1").arg(channel));
    12565
    126         VERBOSE(VB_CHANNEL, LOC +
    127                 QString("Channel2: %1%2%3 cmds: 0x%4, 0x%5, 0x%6")
    128                 .arg(dig[0] & 0xf).arg(dig[1] & 0xf)
    129                 .arg(dig[2] & 0xf)
    130                 .arg(cmd[0], 0, 16).arg(cmd[1], 0, 16)
    131                 .arg(cmd[2], 0, 16));
    132 
    133         if(!avc1394_transaction_block(fwhandle, fw_opts.node, cmd, 3, 1))
    134         {
    135             VERBOSE(VB_IMPORTANT, "AVC transaction failed.");
    136             return false;
    137         }
    138 
    139         cmd[0] = SA3250_CMD0 | AVC1394_SA3250_OPERAND_KEY_RELEASE;
    140         cmd[1] = SA3250_CMD1 | (dig[0] << 16) | (dig[1] << 8) | dig[2];
    141         cmd[2] = SA3250_CMD2;
    142 
    143         VERBOSE(VB_CHANNEL, LOC +
    144                 QString("Channel3: %1%2%3 cmds: 0x%4, 0x%5, 0x%6")
    145                 .arg(dig[0] & 0xf).arg(dig[1] & 0xf)
    146                 .arg(dig[2] & 0xf)
    147                 .arg(cmd[0], 0, 16).arg(cmd[1], 0, 16)
    148                 .arg(cmd[2], 0, 16));
    149 
    150         if (!avc1394_transaction_block(fwhandle, fw_opts.node, cmd, 3, 1))
    151         {
    152             VERBOSE(VB_IMPORTANT, "AVC transaction failed.");
    153             return false;
    154         }
     66        return true; // signal monitor will call retune later...
    15567    }
    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         };
    16468
    165         VERBOSE(VB_CHANNEL, LOC +
    166                 QString("SA4200Channel: %1 cmds: 0x%2 0x%3 0x%4")
    167                 .arg(channel).arg(cmd[0], 0, 16)
    168                 .arg(cmd[1], 0, 16)
    169                 .arg(cmd[2], 0, 16));
     69    if (!device->SetChannel(fw_opts.model, channel))
     70        return false;
    17071
    171         if (!avc1394_transaction_block(fwhandle, fw_opts.node, cmd, 3, 1))
    172         {
    173             VERBOSE(VB_IMPORTANT, "AVC transaction failed.");
    174             return false;
    175         }
    176     }
     72    SetSIStandard("mpeg");
     73    SetCachedATSCInfo(QString("%1-1").arg(channel));
    17774
    17875    return true;
    17976}
    18077
    181 bool FirewireChannel::OpenFirewire(void)
     78bool LinuxFirewireChannel::OpenFirewire(void)
    18279{
    183     if (!is_supported(fw_opts.model))
     80    VERBOSE(VB_IMPORTANT, LOC + "OpenFirewire()");
     81
     82    if (is_port_open)
     83        return true;
     84
     85    if (!LinuxFirewireDevice::IsSTBSupported(fw_opts.model))
    18486    {
    18587        VERBOSE(VB_IMPORTANT, LOC_ERR +
    18688                QString("Model: '%1' ").arg(fw_opts.model) +
    18789                "is not supported by internal channel changer.");
    188         return false;
    189     }
    19090
    191     // Open channel
    192     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));
    19791        return false;
    19892    }
    19993
    200     VERBOSE(VB_CHANNEL, LOC + "Allocated raw1394 handle " +
    201             QString("for port %1").arg(fw_opts.port));
    202 
    203     // verify node looks like a stb
    204     if (!avc1394_check_subunit_type(fwhandle, fw_opts.node,
    205                                     AVC1394_SUBUNIT_TYPE_TUNER))
    206     {
    207         VERBOSE(VB_IMPORTANT, LOC_ERR + QString("node %1 is not subunit "
    208                 "type tuner.").arg(fw_opts.node));
    209         CloseFirewire();
     94    if (!device->OpenPort())
    21095        return false;
    211     }
    21296
    213     if (!avc1394_check_subunit_type(fwhandle, fw_opts.node,
    214                                     AVC1394_SUBUNIT_TYPE_PANEL))
     97    if (!device->IsSTB())
    21598    {
    216         VERBOSE(VB_IMPORTANT, LOC_ERR + QString("node %1 is not subunit "
    217                 "type panel.").arg(fw_opts.node));
    218         CloseFirewire();
     99        device->ClosePort();
    219100        return false;
    220101    }
    221102
    222     // check power, power on if off
    223     if (GetPowerState() == Off)
    224     {
    225         quadlet_t *rval, response, cmd = STB_POWER_ON;
    226         VERBOSE(VB_IMPORTANT, LOC + QString("Powering on (cmd: 0x%1)")
    227                                             .arg(cmd, 0, 16));
    228         rval = avc1394_transaction_block(fwhandle, fw_opts.node, &cmd, 1, 1);
    229         if (rval)
    230         {
    231             response = rval[0];
     103    is_port_open = true;
    232104
    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         }
    260     }
    261105    return true;
    262106}
    263107
    264 void FirewireChannel::CloseFirewire(void)
     108void LinuxFirewireChannel::CloseFirewire(void)
    265109{
    266     VERBOSE(VB_CHANNEL, LOC + "Releasing raw1394 handle");
    267     raw1394_destroy_handle(fwhandle);
     110    VERBOSE(VB_IMPORTANT, LOC + "CloseFirewire()");
     111
     112    if (!is_port_open)
     113        return;
     114
     115    device->ClosePort();
     116    is_port_open = false;
    268117}
    269118
    270 FirewireChannel::PowerState FirewireChannel::GetPowerState(void)
     119bool LinuxFirewireChannel::SetPowerState(bool on)
    271120{
    272     quadlet_t *rval, response, cmd = STB_POWER_STATE;
     121    return device->SetPowerState(on);
     122}
    273123
    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;
     124FirewireDevice::PowerState LinuxFirewireChannel::GetPowerState(void) const
     125{
     126    return device->GetPowerState();
    314127}
  • libs/libmythtv/firewirerecorderbase.h

     
    1212#include "tspacket.h"
    1313#include "streamlisteners.h"
    1414
     15class TVRec;
     16class FirewireChannelBase;
     17
    1518/** \class FirewireRecorderBase
    1619 *  \brief This is a specialization of DTVRecorder used to
    1720 *         handle DVB and ATSC streams from a firewire input.
     
    2528    friend class TSPacketProcessor;
    2629
    2730  public:
    28     FirewireRecorderBase(TVRec *rec);
    29     ~FirewireRecorderBase();
     31    virtual ~FirewireRecorderBase();
    3032 
    3133    // Commands
    3234    void StartRecording(void);
     
    4143    void SetStreamData(MPEGStreamData*);
    4244
    4345    // Gets
    44     MPEGStreamData* StreamData(void) { return _mpeg_stream_data; }
     46    MPEGStreamData *GetStreamData(void) { return _mpeg_stream_data; }
    4547
    4648    // MPEG Single Program
    4749    void HandleSingleProgramPAT(ProgramAssociationTable*);
    4850    void HandleSingleProgramPMT(ProgramMapTable*);
    4951
     52    // Factory
     53    static FirewireRecorderBase *Init(
     54        TVRec *rec, FirewireChannelBase *channel);
     55
     56  protected:
     57    FirewireRecorderBase(TVRec *rec);
     58
    5059  private:
    5160    virtual void Close() = 0;
    52     virtual void start() = 0;
    53     virtual void stop() = 0;
    54     virtual bool grab_frames() = 0;
     61    virtual void StartStreaming(void) = 0;
     62    virtual void StopStreaming(void) = 0;
    5563
    5664    MPEGStreamData  *_mpeg_stream_data;
    5765    TSStats          _ts_stats;   
  • libs/libmythtv/firewirechannelbase.h

     
    88#ifndef LIBMYTHTV_FIREWIRECHANNELBASE_H
    99#define LIBMYTHTV_FIREWIRECHANNELBASE_H
    1010
    11 #include <qstring.h>
    12 #include "tv_rec.h"
    13 #include "channelbase.h"
     11#include "dtvchannel.h"
     12#include "firewiredevice.h"
    1413
    15 #include "mythconfig.h"
     14class TVRec;
     15class FireWireDBOptions;
    1616
    17 namespace AVS
     17class FirewireChannelBase : public DTVChannel
    1818{
    19   class AVCDeviceController;
    20   class AVCDevice;
    21 }
    22 
    23 class FirewireChannelBase : public ChannelBase
    24 {
    2519  public:
    26     FirewireChannelBase(TVRec *parent)   
    27         : ChannelBase(parent), isopen(false) { }
    28     ~FirewireChannelBase() { Close(); }
     20    // Commands
     21    virtual bool Open(void);
     22    virtual void Close(void);
     23    virtual bool SwitchToInput(const QString &inputname, const QString &chan);
     24    virtual bool SwitchToInput(int newcapchannel, bool setstarting)
     25        { (void)newcapchannel; (void)setstarting; return false; }
    2926
    30     bool Open(void);
    31     void Close(void);
     27    virtual bool TuneMultiplex(uint /*mplexid*/, QString /*inputname*/)
     28        { return false; }
     29    virtual bool Tune(const DTVMultiplex &/*tuning*/, QString /*inputname*/)
     30        { return false; }
     31    virtual bool Retune(void)
     32        { return false; }
    3233
    3334    // Sets
    34     bool SetChannelByString(const QString &chan);
     35    virtual bool SetChannelByString(const QString &chan);
    3536    virtual bool SetChannelByNumber(int channel) = 0;
     37    virtual bool SetPowerState(bool /*on*/) = 0;
    3638
    3739    // Gets
    38     bool IsOpen(void) const { return isopen; }
     40    virtual bool IsOpen(void) const { return isopen; }
     41    virtual FirewireDevice::PowerState GetPowerState(void) const = 0;
    3942
    40     // Commands
    41     bool SwitchToInput(const QString &inputname, const QString &chan);
    42     bool SwitchToInput(int newcapchannel, bool setstarting)
    43         { (void)newcapchannel; (void)setstarting; return false; }
     43    // Factory method
     44    static FirewireChannelBase *Init(
     45        const FireWireDBOptions &firewire_opts, TVRec *parent);
    4446
     47  protected:
     48    FirewireChannelBase(TVRec *parent) :
     49        DTVChannel(parent), isopen(false) { }
     50    ~FirewireChannelBase() { Close(); }
     51
    4552  private:
    46     virtual bool OpenFirewire() = 0;
    47     virtual void CloseFirewire() = 0;
     53    virtual bool OpenFirewire(void) = 0;
     54    virtual void CloseFirewire(void) = 0;
    4855
    4956  protected:
    5057    bool isopen;
  • libs/libmythtv/libmythtv.pro

     
    380380    using_firewire  {
    381381        HEADERS += firewirechannelbase.h       firewirerecorderbase.h
    382382        SOURCES += firewirechannelbase.cpp     firewirerecorderbase.cpp
     383        HEADERS += firewiresignalmonitor.h     firewiredevice.h
     384        SOURCES += firewiresignalmonitor.cpp
    383385
    384386        macx {
    385387            HEADERS += darwinfirewirechannel.h       darwinfirewirerecorder.h
     
    391393        !macx {
    392394            HEADERS += firewirechannel.h       firewirerecorder.h
    393395            SOURCES += firewirechannel.cpp     firewirerecorder.cpp
     396            HEADERS += linuxfirewiredevice.h
     397            SOURCES += linuxfirewiredevice.cpp
    394398        }
    395399
    396400        DEFINES += USING_FIREWIRE
  • libs/libmythtv/darwinfirewirerecorder.cpp

     
    1111#undef always_inline
    1212#include <AVCVideoServices/AVCVideoServices.h>
    1313
    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 {;}
     14DarwinFirewireRecorder::DarwinFirewireRecorder(
     15    TVRec *rec, DarwinFirewireChannel *channel) :
     16    FirewireRecorderBase(rec),
     17    capture_device(channel->GetAVCDevice()),
     18    message_log(NULL),
     19    video_stream(NULL),
     20    isopen(false)
     21{
     22    SetStreamData(new MPEGStreamData(1, true));
     23}
    2324
    2425DarwinFirewireRecorder::~DarwinFirewireRecorder()
    2526{
     
    196197    this->message_log = 0;
    197198}
    198199
    199 void DarwinFirewireRecorder::start()
     200void DarwinFirewireRecorder::StartStreaming(void)
    200201{
    201202    VERBOSE(VB_RECORD, "Firewire: Starting video stream");
    202203    this->capture_device->StartAVCDeviceStream(this->video_stream);
    203204}
    204205
    205 void DarwinFirewireRecorder::stop()
     206void DarwinFirewireRecorder::StopStreaming(void)
    206207{
    207208    VERBOSE(VB_RECORD, "Firewire: Stopping video stream");
    208209    this->capture_device->StopAVCDeviceStream(this->video_stream);
    209210}
    210 
    211 bool DarwinFirewireRecorder::grab_frames()
    212 {
    213     usleep(1000000 / 2);  // 2 times a second
    214     return true;
    215 }       
    216 
    217 void DarwinFirewireRecorder::SetOption(const QString &name, const QString &value)
    218 {
    219     (void)name;
    220     (void)value;
    221 }
    222 
    223 void DarwinFirewireRecorder::SetOption(const QString &name, int value)
    224 {
    225     (void)name;
    226     (void)value;
    227 }
  • libs/libmythtv/signalmonitor.h

     
    285285    return (CardUtil::IsDVBCardType(cardtype) ||
    286286            (cardtype.upper() == "HDTV")      ||
    287287            (cardtype.upper() == "HDHOMERUN") ||
     288            (cardtype.upper() == "FIREWIRE")  ||
    288289            (cardtype.upper() == "FREEBOX"));
    289290}
    290291
  • libs/libmythtv/firewirerecorderbase.cpp

     
    55 */
    66
    77// MythTV includes
     8#include "mythconfig.h" // for CONFIG_DARWIN
    89#include "firewirerecorderbase.h"
    910#include "mythcontext.h"
    1011#include "mpegtables.h"
    1112#include "mpegstreamdata.h"
    1213#include "tv_rec.h"
    1314
     15#ifdef CONFIG_DARWIN
     16#   include "darwinfirewirechannel.h"
     17#   include "darwinfirewirerecorder.h"
     18#else
     19#   include "firewirechannel.h"
     20#   include "firewirerecorder.h"
     21#   include "linuxfirewiredevice.h"
     22#endif
     23
    1424#define LOC QString("FireRecBase: ")
    1525#define LOC_ERR QString("FireRecBase, Error: ")
    1626
    1727const int FirewireRecorderBase::kTimeoutInSeconds = 15;
    1828
     29FirewireRecorderBase *FirewireRecorderBase::Init(
     30    TVRec *rec, FirewireChannelBase *channel)
     31{
     32#ifdef CONFIG_DARWIN
     33    DarwinFirewireChannel *dfch =
     34        dynamic_cast<DarwinFirewireChannel*>(channel);
     35    if (dfch)
     36        return new DarwinFirewireRecorder(rec, channel);
     37#else
     38    LinuxFirewireChannel *lfch =
     39        dynamic_cast<LinuxFirewireChannel*>(channel);
     40    if (lfch)
     41        return new LinuxFirewireRecorder(rec, lfch);
     42#endif
     43
     44    return NULL;
     45}
     46
    1947FirewireRecorderBase::FirewireRecorderBase(TVRec *rec)
    2048    : DTVRecorder(rec), _mpeg_stream_data(NULL)
    2149{
    22     SetStreamData(new MPEGStreamData(1, true));
    2350}
    2451
    2552FirewireRecorderBase::~FirewireRecorderBase()
     
    3966    _request_recording = true;
    4067    _recording = true;
    4168   
    42     start();
     69    StartStreaming();
    4370
    44     while(_request_recording) {
    45        if (PauseAndWait())
    46            continue;
    47 
    48        if (!grab_frames())
    49        {
    50            _error = true;
    51            return;
    52        }
     71    while (_request_recording)
     72    {
     73        if (!PauseAndWait())
     74            usleep(250 * 1000);
    5375    }       
    5476   
    55     stop();
     77    StopStreaming();
    5678    FinishRecording();
    5779
    5880    _recording = false;
     
    6789        return;
    6890 
    6991    if (tspacket.HasAdaptationField())
    70         StreamData()->HandleAdaptationFieldControl(&tspacket);
     92        GetStreamData()->HandleAdaptationFieldControl(&tspacket);
    7193 
    7294    if (tspacket.HasPayload())
    7395    {
    7496        const unsigned int lpid = tspacket.PID();
    7597 
    7698        // Pass or reject packets based on PID, and parse info from them
    77         if (lpid == StreamData()->VideoPIDSingleProgram())
     99        if (lpid == GetStreamData()->VideoPIDSingleProgram())
    78100        {
    79101            _buffer_packets = !FindMPEG2Keyframes(&tspacket);
    80102            BufferedWrite(tspacket);
    81103        }
    82         else if (StreamData()->IsAudioPID(lpid))
     104        else if (GetStreamData()->IsAudioPID(lpid))
    83105            BufferedWrite(tspacket);
    84         else if (StreamData()->IsListeningPID(lpid))
    85             StreamData()->HandleTSTables(&tspacket);
    86         else if (StreamData()->IsWritingPID(lpid))
     106        else if (GetStreamData()->IsListeningPID(lpid))
     107            GetStreamData()->HandleTSTables(&tspacket);
     108        else if (GetStreamData()->IsWritingPID(lpid))
    87109            BufferedWrite(tspacket);
    88110    }
    89111 
     
    108130{
    109131    if (request_pause)
    110132    {
     133        VERBOSE(VB_RECORD, LOC + "PauseAndWait("<<timeout<<") -- pause");
    111134        if (!paused)
    112135        {
    113             stop();
     136            StopStreaming();
    114137            paused = true;
    115138            pauseWait.wakeAll();
    116139            if (tvrec)
     
    120143    }
    121144    if (!request_pause && paused)
    122145    {
    123         start();
     146        VERBOSE(VB_RECORD, LOC + "PauseAndWait("<<timeout<<") -- unpause");
     147        StartStreaming();
    124148        paused = false;
    125149    }
    126150    return paused;
  • libs/libmythtv/firewirerecorder.cpp

     
    88#include <pthread.h>
    99#include <sys/select.h>
    1010
    11 // C++ includes
    12 #include <iostream>
    13 using namespace std;
     11// Linux C includes
     12#include <libraw1394/raw1394.h>
    1413
    1514// MythTV includes
    1615#include "firewirerecorder.h"
     16#include "firewirechannel.h"
     17#include "linuxfirewiredevice.h"
    1718#include "mythcontext.h"
    1819#include "mpegtables.h"
    1920#include "mpegstreamdata.h"
    2021#include "tv_rec.h"
    2122
    22 #define LOC QString("FireRec: ")
    23 #define LOC_ERR QString("FireRec, Error: ")
     23#define LOC QString("FireRec(%1): ").arg(channel->GetDevice())
     24#define LOC_ERR QString("FireRec(%1), Error: ").arg(tvrec->GetDevice())
    2425
    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)
     26LinuxFirewireRecorder::LinuxFirewireRecorder(
     27    TVRec *rec,
     28    LinuxFirewireChannel *chan) :
     29    FirewireRecorderBase(rec), channel(chan), isopen(false)
    3330{
    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;
    5131}
    5232
    53 static QString speed_to_string(uint speed)
     33LinuxFirewireRecorder::~LinuxFirewireRecorder()
    5434{
    55     if (speed > RAW1394_ISO_SPEED_400)
    56         return QString("Invalid Speed (%1)").arg(speed);
    57 
    58     static const uint speeds[] = { 100, 200, 400, };
    59     return QString("%1Mbps").arg(speeds[speed]);
     35    Close();
    6036}
    6137
    62 bool FirewireRecorder::Open(void)
     38bool LinuxFirewireRecorder::Open(void)
    6339{
    64      if (isopen)
    65          return true;
     40     if (!isopen)
     41         isopen = channel->GetFirewireDevice()->OpenPort();
    6642
    67      VERBOSE(VB_RECORD, LOC +
    68              QString("Initializing Port: %1, Node: %2, Speed: %3")
    69              .arg(fwport).arg(fwnode).arg(speed_to_string(fwspeed)));
    70 
    71      fwhandle = raw1394_new_handle_on_port(fwport);
    72      if (!fwhandle)
    73      {
    74          VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to get handle for " +
    75                  QString("port: %1, bailing").arg(fwport) + ENO);
    76          return false;
    77      }
    78 
    79      if (kConnectionP2P == fwconnection)
    80      {
    81           VERBOSE(VB_RECORD, LOC + "Creating P2P Connection " +
    82                   QString("with Node: %1").arg(fwnode));
    83           fwchannel = iec61883_cmp_connect(fwhandle,
    84                                            fwnode | 0xffc0, &fwoplug,
    85                                            raw1394_get_local_id(fwhandle),
    86                                            &fwiplug, &fwbandwidth);
    87           if (fwchannel > -1)
    88           {
    89               VERBOSE(VB_RECORD, LOC +
    90                       QString("Created Channel: %1, "
    91                               "Bandwidth Allocation: %2")
    92                       .arg(fwchannel).arg(fwbandwidth));
    93           }
    94      }
    95      else
    96      {
    97          fwchannel = kBroadcastChannel - fwnode;
    98 
    99          VERBOSE(VB_RECORD, LOC + "Creating Broadcast Connection " +
    100                  QString("with Node: %1, Channel: %2").arg(fwnode)
    101                  .arg(fwchannel));
    102          if (iec61883_cmp_create_bcast_output(fwhandle,
    103                                               fwnode | 0xffc0, 0,
    104                                               fwchannel,
    105                                               fwspeed) != 0)
    106          {
    107              VERBOSE(VB_IMPORTANT, LOC + "Failed to create connection");
    108              // release raw1394 object;
    109              raw1394_destroy_handle(fwhandle);
    110              return false;
    111          }
    112          fwbandwidth = 0;
    113      }
    114 
    115      fwmpeg = iec61883_mpeg2_recv_init(fwhandle, fw_tspacket_handler, this);
    116      if (!fwmpeg)
    117      {
    118          VERBOSE(VB_IMPORTANT, LOC +
    119                  "Unable to init iec61883_mpeg2 object, bailing" + ENO);
    120 
    121          // release raw1394 object;
    122          raw1394_destroy_handle(fwhandle);
    123          return false;
    124      }
    125 
    126      // Set buffered packets size
    127      size_t buffer_size = gContext->GetNumSetting("HDRingbufferSize",
    128                                                   50 * TSPacket::SIZE);
    129      size_t buffered_packets = min(buffer_size / 4,
    130                                    (size_t) kMaxBufferedPackets);
    131      iec61883_mpeg2_set_buffers(fwmpeg, buffered_packets);
    132      VERBOSE(VB_IMPORTANT, LOC +
    133              QString("Buffered packets %1 (%2 KB)")
    134              .arg(buffered_packets).arg(buffered_packets * 4));
    135 
    136      // Set speed if needed.
    137      // Probably shouldn't even allow user to set,
    138      // 100Mbps should be more the enough.
    139      int curspeed = iec61883_mpeg2_get_speed(fwmpeg);
    140      if (curspeed != fwspeed)
    141      {
    142          VERBOSE(VB_RECORD, LOC +
    143                  QString("Changing Speed %1 -> %2")
    144                  .arg(speed_to_string(curspeed))
    145                  .arg(speed_to_string(fwspeed)));
    146 
    147          iec61883_mpeg2_set_speed(fwmpeg, fwspeed);
    148          if (fwspeed != iec61883_mpeg2_get_speed(fwmpeg))
    149          {
    150               VERBOSE(VB_IMPORTANT, LOC +
    151                       "Unable to set firewire speed, continuing");
    152          }
    153      }
    154 
    155      fwfd = raw1394_get_fd(fwhandle);
    156 
    157      return isopen = true;
     43     return isopen;
    15844}
    15945
    160 void FirewireRecorder::Close(void)
     46void LinuxFirewireRecorder::Close(void)
    16147{
    162     if (!isopen)
    163         return;
    164 
    165     isopen = false;
    166 
    167     VERBOSE(VB_RECORD, LOC + "Releasing iec61883_mpeg2 object");
    168     iec61883_mpeg2_close(fwmpeg);
    169 
    170     if (fwconnection == kConnectionP2P && fwchannel > -1)
     48    if (isopen)
    17149    {
    172         VERBOSE(VB_RECORD, LOC +
    173                 QString("Disconnecting channel %1").arg(fwchannel));
    174 
    175         iec61883_cmp_disconnect(fwhandle, fwnode | 0xffc0, fwoplug,
    176                                 raw1394_get_local_id (fwhandle),
    177                                 fwiplug, fwchannel, fwbandwidth);
     50        channel->GetFirewireDevice()->ClosePort();
     51        isopen = false;
    17852    }
     53}
    17954
    180     VERBOSE(VB_RECORD, LOC + "Releasing raw1394 handle");
    181     raw1394_destroy_handle(fwhandle);
     55void LinuxFirewireRecorder::StartStreaming(void)
     56{
     57    channel->GetFirewireDevice()->AddListener(this);
    18258}
    18359
    184 bool FirewireRecorder::grab_frames()
     60void LinuxFirewireRecorder::StopStreaming(void)
    18561{
    186     struct timeval tv;
    187     fd_set rfds;
     62    channel->GetFirewireDevice()->RemoveListener(this);
     63}
    18864
    189     FD_ZERO(&rfds);
    190     FD_SET(fwfd, &rfds);
    191     tv.tv_sec = kTimeoutInSeconds;
    192     tv.tv_usec = 0;
     65void LinuxFirewireRecorder::AddData(const unsigned char *data, uint len)
     66{
     67    //cout<<":";
    19368
    194     if (select(fwfd + 1, &rfds, NULL, NULL, &tv)  <= 0)
    195     {
    196         VERBOSE(VB_IMPORTANT, LOC +
    197                 QString("No Input in %1 seconds [P:%2 N:%3] (select)")
    198                 .arg(kTimeoutInSeconds).arg(fwport).arg(fwnode));
    199         return false;
     69    uint bufsz = buffer.size();
     70    if ((SYNC_BYTE == data[0]) && (TSPacket::SIZE == len) &&
     71        (TSPacket::SIZE > bufsz))
     72    {
     73        if (bufsz)
     74            buffer.clear();
     75
     76        ProcessTSPacket(*(reinterpret_cast<const TSPacket*>(data)));
     77        return;
    20078    }
    20179
    202     int ret = raw1394_loop_iterate(fwhandle);
    203     if (ret)
     80    buffer.insert(buffer.end(), data, data + len);
     81    bufsz += len;
     82
     83    int sync_at = -1;
     84    for (uint i = 0; (i < bufsz) && (sync_at < 0); i++)
    20485    {
    205         VERBOSE(VB_IMPORTANT, LOC_ERR + "libraw1394_loop_iterate() " +
    206                 QString("returned %1").arg(ret));
    207         return false;
     86        if (buffer[i] == SYNC_BYTE)
     87            sync_at = i;
    20888    }
    20989
    210     return true;
    211 }
     90    if (sync_at < 0)
     91        return;
    21292
    213 void FirewireRecorder::SetOption(const QString &name, const QString &value)
    214 {
    215     if (name == "model")
    216         fwmodel = value;
    217 }
     93    if (bufsz < 30 * TSPacket::SIZE)
     94        return; // build up a little buffer
    21895
    219 void FirewireRecorder::SetOption(const QString &name, int value)
    220 {
    221     if (name == "port")
    222         fwport = value;
    223     else if (name == "node")
    224         fwnode = value;
    225     else if (name == "speed")
     96    while (sync_at + TSPacket::SIZE < bufsz)
    22697    {
    227         if (RAW1394_ISO_SPEED_100 != value &&
    228             RAW1394_ISO_SPEED_200 != value &&
    229             RAW1394_ISO_SPEED_400 != value)
    230         {
    231             VERBOSE(VB_IMPORTANT, LOC_ERR +
    232                     QString("Unknown speed '%1', will use 100Mbps")
    233                     .arg(value));
     98        ProcessTSPacket(*(reinterpret_cast<const TSPacket*>(
     99                              &buffer[0] + sync_at)));
    234100
    235             value = RAW1394_ISO_SPEED_100;
    236         }
    237         fwspeed = value;
     101        sync_at += TSPacket::SIZE;
    238102    }
    239     else if (name == "connection")
    240     {
    241         if (kConnectionP2P       != value &&
    242             kConnectionBroadcast != value)
    243         {
    244             VERBOSE(VB_IMPORTANT, LOC_ERR +
    245                     QString("Unknown connection type '%1', will use P2P")
    246                     .arg(fwconnection));
    247103
    248             fwconnection = kConnectionP2P;
    249         }
    250         fwconnection = value;
    251     }
     104    buffer.erase(buffer.begin(), buffer.begin() + sync_at);
     105
     106    return;
    252107}
  • libs/libmythtv/firewirerecorder.h

     
    44 *  Distributed as part of MythTV under GPL v2 and later.
    55 */
    66
    7 #ifndef FIREWIRERECORDER_H_
    8 #define FIREWIRERECORDER_H_
     7#ifndef _LINUX_FIREWIRE_RECORDER_H_
     8#define _LINUX_FIREWIRE_RECORDER_H_
    99
    1010#include "firewirerecorderbase.h"
    11 #include "tsstats.h"
    12 #include <libraw1394/raw1394.h>
    13 #include <libiec61883/iec61883.h>
     11#include "linuxfirewiredevice.h"
    1412
    15 /** \class FirewireRecorder
    16  *  \brief Linux FirewireRFecorder
     13class LinuxFirewireChannel;
     14
     15/** \class LinuxFirewireRecorder
     16 *  \brief Linux Firewire Recorder
    1717 *
    1818 *  \sa FirewireRecorderBase
    1919 */
    20 class FirewireRecorder : public FirewireRecorderBase
     20class LinuxFirewireRecorder :
     21    public FirewireRecorderBase, public TSDataListener
    2122{
    22     friend int fw_tspacket_handler(unsigned char*,int,uint,void*);
    23 
    2423  public:
    25     FirewireRecorder(TVRec *rec)
    26         : FirewireRecorderBase(rec),
    27         fwport(-1),     fwchannel(-1), fwspeed(-1),   fwbandwidth(-1),
    28         fwfd(-1),       fwconnection(kConnectionP2P),
    29         fwoplug(-1),    fwiplug(-1),   fwmodel(""),   fwnode(0),
    30         fwhandle(NULL), fwmpeg(NULL),  isopen(false) { }
    31    ~FirewireRecorder() { Close(); }
     24    LinuxFirewireRecorder(TVRec *rec, LinuxFirewireChannel *chan);
     25    ~LinuxFirewireRecorder();
    3226
    3327    // Commands
    34     bool Open(void);
    35 
    36     // Sets
    37     void SetOption(const QString &name, const QString &value);
    38     void SetOption(const QString &name, int value);
    39 
    40   private:
     28    bool Open(void);
     29    void StartStreaming(void);
     30    void StopStreaming(void);
    4131    void Close(void);
    42     void start() { iec61883_mpeg2_recv_start(fwmpeg, fwchannel); }
    43     void stop() { iec61883_mpeg2_recv_stop(fwmpeg); }
    44     bool grab_frames();
    4532
    4633  private:
    47     int              fwport;
    48     int              fwchannel;
    49     int              fwspeed;
    50     int              fwbandwidth;
    51     int              fwfd;
    52     int              fwconnection;
    53     int              fwoplug;
    54     int              fwiplug;
    55     QString          fwmodel;
    56     nodeid_t         fwnode;
    57     raw1394handle_t  fwhandle;
    58     iec61883_mpeg2_t fwmpeg;
    59     bool             isopen;
     34    void AddData(const unsigned char *data, uint dataSize);
    6035
    61     static const int kBroadcastChannel;
    62     static const int kConnectionP2P;
    63     static const int kConnectionBroadcast;
    64     static const uint kMaxBufferedPackets;
     36  private:
     37    LinuxFirewireChannel *channel;
     38    bool                  isopen;
     39    vector<unsigned char> buffer;
    6540};
    6641
    67 #endif
     42#endif // _LINUX_FIREWIRE_RECORDER_H_
  • libs/libmythtv/darwinfirewirechannel.cpp

     
    1515#undef always_inline
    1616#include <AVCVideoServices/AVCVideoServices.h>
    1717
     18#define LOC QString("DarwinFirewireChannel: ")
     19#define LOC_ERR QString("DarwinFirewireChannel, Error: ")
    1820
    1921namespace
    2022{
     
    8486    return this->device;
    8587}
    8688
     89FirewireDevice::PowerState DarwinFirewireChannel::GetPowerState(void) const
     90{
     91    UInt8 power_state;
     92    IOReturn err = device->GetPowerState(&power_state);
     93
     94    if (err != kIOReturnSuccess)
     95        return FirewireDevice::kAVCPowerQueryFailed;
     96    else if (kAVCPowerStateOff == power_state)
     97        return FirewireDevice::kAVCPowerOff;
     98    else if (kAVCPowerStateOn == power_state)
     99        return FirewireDevice::kAVCPowerOn;
     100    else
     101        return FirewireDevice::kAVCPowerUnknown;
     102}
     103
     104bool DarwinFirewireChannel::SetPowerState(bool on)
     105{
     106    if (on)
     107        SetPowerState(kAVCPowerStateOn);
     108    else
     109        SetPowerState(kAVCPowerStateOff);
     110
     111    return true;
     112}
     113
    87114bool DarwinFirewireChannel::SetChannelByNumber(int channel)
    88115{
    89116     // If the tuner is off, try to turn it on.
    90      UInt8 power_state;
    91      IOReturn err = this->device->GetPowerState(&power_state);
    92      if (err == kIOReturnSuccess && power_state == kAVCPowerStateOff)
     117     if (FirewireDevice::kAVCPowerOff == GetPowerState())
    93118     {
    94          this->device->SetPowerState(kAVCPowerStateOn);
     119         SetPowerState(true);
    95120       
    96121         // Give it time to power up.
    97122         usleep(2000000); // Sleep for two seconds
     
    101126     err = panel.Tune(channel);
    102127     if (err != kIOReturnSuccess)
    103128     {
    104          VERBOSE(VB_GENERAL, QString("DarwinFirewireChannel: Tuning failed: %1").arg(err,0,16));
    105          VERBOSE(VB_GENERAL, QString("Ignoring error per apple example"));
     129         VERBOSE(VB_GENERAL, LOC_ERR +
     130                 QString("Tuning failed: %1").arg(err,0,16) +
     131                 QString("Ignoring error per apple example"));
    106132     }
     133
    107134     // Give it time to transition.       
    108135     usleep(1000000); // Sleep for one second
     136
    109137     return true;
    110138}
  • libs/libmythtv/firewiresignalmonitor.cpp

     
     1// -*- Mode: c++ -*-
     2// Copyright (c) 2006, Daniel Thor Kristjansson
     3
     4#include <pthread.h>
     5#include <fcntl.h>
     6#include <unistd.h>
     7#include <sys/select.h>
     8
     9#include "mythcontext.h"
     10#include "mythdbcon.h"
     11#include "firewiresignalmonitor.h"
     12#include "atscstreamdata.h"
     13#include "mpegtables.h"
     14#include "atsctables.h"
     15
     16#include "firewirechannelbase.h"
     17
     18#include "firewirechannel.h"
     19
     20#define LOC QString("FireSM(%1): ").arg(channel->GetDevice())
     21#define LOC_WARN QString("FireSM(%1), Warning: ").arg(channel->GetDevice())
     22#define LOC_ERR QString("FireSM(%1), Error: ").arg(channel->GetDevice())
     23
     24const uint FirewireSignalMonitor::kPowerTimeout  = 3000; /* ms */
     25const uint FirewireSignalMonitor::kBufferTimeout = 5000; /* ms */
     26
     27QMap<void*,uint> FirewireSignalMonitor::pat_keys;
     28QMutex           FirewireSignalMonitor::pat_keys_lock;
     29
     30/** \fn FirewireSignalMonitor::FirewireSignalMonitor(int,FirewireChannel*,uint,const char*)
     31 *  \brief Initializes signal lock and signal values.
     32 *
     33 *   Start() must be called to actually begin continuous
     34 *   signal monitoring. The timeout is set to 3 seconds,
     35 *   and the signal threshold is initialized to 0%.
     36 *
     37 *  \param db_cardnum Recorder number to monitor,
     38 *                    if this is less than 0, SIGNAL events will not be
     39 *                    sent to the frontend even if SetNotifyFrontend(true)
     40 *                    is called.
     41 *  \param _channel FirewireChannel for card
     42 *  \param _flags   Flags to start with
     43 *  \param _name    Name for Qt signal debugging
     44 */
     45FirewireSignalMonitor::FirewireSignalMonitor(
     46    int db_cardnum,
     47    FirewireChannelBase *_channel,
     48    uint _flags, const char *_name) :
     49    DTVSignalMonitor(db_cardnum, _channel, _flags, _name),
     50    dtvMonitorRunning(false),
     51    stb_needs_retune(true),
     52    stb_needs_to_wait_for_pat(false),
     53    stb_needs_to_wait_for_power(false)
     54{
     55    VERBOSE(VB_CHANNEL, LOC + "ctor");
     56
     57    signalStrength.SetThreshold(65);
     58
     59    AddFlags(kDTVSigMon_WaitForSig);
     60
     61    stb_needs_retune =
     62        (FirewireDevice::kAVCPowerOff == _channel->GetPowerState());
     63}
     64
     65/** \fn FirewireSignalMonitor::~FirewireSignalMonitor()
     66 *  \brief Stops signal monitoring and table monitoring threads.
     67 */
     68FirewireSignalMonitor::~FirewireSignalMonitor()
     69{
     70    VERBOSE(VB_CHANNEL, LOC + "dtor");
     71    Stop();
     72}
     73
     74void FirewireSignalMonitor::deleteLater(void)
     75{
     76    disconnect(); // disconnect signals we may be sending...
     77    Stop();
     78    DTVSignalMonitor::deleteLater();
     79}
     80
     81/** \fn FirewireSignalMonitor::Stop(void)
     82 *  \brief Stop signal monitoring and table monitoring threads.
     83 */
     84void FirewireSignalMonitor::Stop(void)
     85{
     86    VERBOSE(VB_CHANNEL, LOC + "Stop() -- begin");
     87    SignalMonitor::Stop();
     88    if (dtvMonitorRunning)
     89    {
     90        dtvMonitorRunning = false;
     91        pthread_join(table_monitor_thread, NULL);
     92    }
     93    VERBOSE(VB_CHANNEL, LOC + "Stop() -- end");
     94}
     95
     96void FirewireSignalMonitor::HandlePAT(const ProgramAssociationTable *pat)
     97{
     98    AddFlags(kDTVSigMon_PATSeen);
     99
     100    {
     101        QMutexLocker locker(&pat_keys_lock);
     102        const uint crc = pat_keys[channel];
     103
     104        VERBOSE(VB_CHANNEL, LOC + "HandlePAT() CRC: 0x"
     105                <<hex<<pat->CalcCRC()<<"|0x"<<crc<<dec);
     106
     107        bool crc_bogus = (pat->CalcCRC() == crc);
     108        if (crc_bogus && stb_needs_to_wait_for_pat &&
     109            (stb_wait_for_pat_timer.elapsed() < kBufferTimeout))
     110        {
     111            VERBOSE(VB_CHANNEL, LOC + "HandlePAT() ignoring PAT");
     112            uint tsid = pat->TransportStreamID();
     113            GetStreamData()->SetVersionPAT(tsid, -1,0);
     114            return;
     115        }
     116
     117        if (crc_bogus && stb_needs_to_wait_for_pat)
     118        {
     119            VERBOSE(VB_IMPORTANT, LOC_WARN + "Wait for valid PAT timed out");
     120            stb_needs_to_wait_for_pat = false;
     121        }
     122           
     123        pat_keys[channel] = pat->CalcCRC();
     124    }
     125
     126    DTVSignalMonitor::HandlePAT(pat);
     127}
     128
     129void FirewireSignalMonitor::HandlePMT(uint pnum, const ProgramMapTable *pmt)
     130{
     131    VERBOSE(VB_CHANNEL, LOC + "HandlePMT()");
     132
     133    AddFlags(kDTVSigMon_PMTSeen);
     134
     135    if (!HasFlags(kDTVSigMon_PATMatch))
     136    {
     137        GetStreamData()->SetVersionPMT(pnum, -1,0);
     138        VERBOSE(VB_CHANNEL, LOC + "HandlePMT() ignoring PMT");
     139        return;
     140    }
     141
     142    DTVSignalMonitor::HandlePMT(pnum, pmt);
     143}
     144
     145void *FirewireSignalMonitor::TableMonitorThread(void *param)
     146{
     147    FirewireSignalMonitor *mon = (FirewireSignalMonitor*) param;
     148    mon->RunTableMonitor();
     149    return NULL;
     150}
     151
     152void FirewireSignalMonitor::RunTableMonitor(void)
     153{
     154    stb_needs_to_wait_for_pat = true;
     155    stb_wait_for_pat_timer.start();
     156    dtvMonitorRunning = true;
     157
     158    VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- begin");
     159
     160    LinuxFirewireChannel *lchan = dynamic_cast<LinuxFirewireChannel*>(channel);
     161    if (!lchan)
     162    {
     163        VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- err end");
     164        dtvMonitorRunning = false;
     165        return;
     166    }
     167
     168    LinuxFirewireDevice *dev = lchan->GetFirewireDevice();
     169
     170    dev->OpenPort();
     171    dev->AddListener(this);
     172
     173    while (dtvMonitorRunning && GetStreamData())
     174        usleep(100000);
     175
     176    VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- shutdown ");
     177
     178    dev->RemoveListener(this);
     179    dev->ClosePort();
     180
     181    dtvMonitorRunning = false;
     182
     183    VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- end");
     184}
     185
     186void FirewireSignalMonitor::AddData(const unsigned char *data, uint len)
     187{
     188    if (!dtvMonitorRunning)
     189        return;
     190
     191    if (GetStreamData())
     192        GetStreamData()->ProcessData((unsigned char *)data, len);
     193}
     194
     195/** \fn FirewireSignalMonitor::UpdateValues(void)
     196 *  \brief Fills in frontend stats and emits status Qt signals.
     197 *
     198 *   This function uses five ioctl's FE_READ_SNR, FE_READ_SIGNAL_STRENGTH
     199 *   FE_READ_BER, FE_READ_UNCORRECTED_BLOCKS, and FE_READ_STATUS to obtain
     200 *   statistics from the frontend.
     201 *
     202 *   This is automatically called by MonitorLoop(), after Start()
     203 *   has been used to start the signal monitoring thread.
     204 */
     205void FirewireSignalMonitor::UpdateValues(void)
     206{
     207    if (!running || exit)
     208        return;
     209
     210    if (dtvMonitorRunning)
     211    {
     212        EmitFirewireSignals();
     213        if (IsAllGood())
     214            emit AllGood();
     215        // TODO dtv signals...
     216
     217        update_done = true;
     218        return;
     219    }
     220
     221    if (stb_needs_to_wait_for_power &&
     222        (stb_wait_for_power_timer.elapsed() < (int)kPowerTimeout))
     223    {
     224        return;
     225    }
     226    stb_needs_to_wait_for_power = false;
     227
     228    FirewireChannelBase *fwchan = dynamic_cast<FirewireChannelBase*>(channel);
     229
     230    if (HasFlags(kFWSigMon_WaitForPower) && !HasFlags(kFWSigMon_PowerMatch))
     231    {
     232        FirewireDevice::PowerState power = fwchan->GetPowerState();
     233        if (FirewireDevice::kAVCPowerOn == power)
     234        {
     235            AddFlags(kFWSigMon_PowerSeen | kFWSigMon_PowerMatch);
     236        }
     237        else if (FirewireDevice::kAVCPowerOff == power)
     238        {
     239            AddFlags(kFWSigMon_PowerSeen);
     240            fwchan->SetPowerState(true);
     241            stb_wait_for_power_timer.start();
     242            stb_needs_to_wait_for_power = true;
     243        }
     244    }
     245
     246    bool isLocked = !HasFlags(kFWSigMon_WaitForPower) ||
     247        HasFlags(kFWSigMon_WaitForPower | kFWSigMon_PowerMatch);
     248
     249    if (isLocked && stb_needs_retune)
     250    {
     251        fwchan->Retune();
     252        isLocked = stb_needs_retune = false;
     253    }
     254
     255    // Set SignalMonitorValues from info from card.
     256    {
     257        QMutexLocker locker(&statusLock);
     258        signalStrength.SetValue(isLocked ? 100 : 0);
     259        signalLock.SetValue(isLocked ? 1 : 0);
     260    }
     261
     262    EmitFirewireSignals();
     263    if (IsAllGood())
     264        emit AllGood();
     265
     266    // Start table monitoring if we are waiting on any table
     267    // and we have a lock.
     268    if (isLocked && GetStreamData() &&
     269        HasAnyFlag(kDTVSigMon_WaitForPAT | kDTVSigMon_WaitForPMT |
     270                   kDTVSigMon_WaitForMGT | kDTVSigMon_WaitForVCT |
     271                   kDTVSigMon_WaitForNIT | kDTVSigMon_WaitForSDT))
     272    {
     273        pthread_create(&table_monitor_thread, NULL,
     274                       TableMonitorThread, this);
     275
     276        VERBOSE(VB_CHANNEL, LOC + "UpdateValues() -- "
     277                "Waiting for table monitor to start");
     278
     279        while (!dtvMonitorRunning)
     280            usleep(50);
     281
     282        VERBOSE(VB_CHANNEL, LOC + "UpdateValues() -- "
     283                "Table monitor started");
     284    }
     285
     286    update_done = true;
     287}
     288
     289#define EMIT(SIGNAL_FUNC, SIGNAL_VAL) \
     290    do { statusLock.lock(); \
     291         SignalMonitorValue val = SIGNAL_VAL; \
     292         statusLock.unlock(); \
     293         emit SIGNAL_FUNC(val); } while (false)
     294
     295/** \fn FirewireSignalMonitor::EmitFirewireSignals(void)
     296 *  \brief Emits signals for lock, signal strength, etc.
     297 */
     298void FirewireSignalMonitor::EmitFirewireSignals(void)
     299{
     300    // Emit signals..
     301    EMIT(StatusSignalLock, signalLock);
     302    if (HasFlags(kDTVSigMon_WaitForSig))
     303        EMIT(StatusSignalStrength, signalStrength);
     304}
     305
     306#undef EMIT
  • libs/libmythtv/darwinfirewirechannel.h

     
    2424  public:
    2525    DarwinFirewireChannel(FireWireDBOptions const&, TVRec *parent);
    2626
     27    // Sets
     28    virtual bool SetChannelByNumber(int channel);
     29    virtual bool SetPowerState(bool on);
     30
    2731    // Gets
    28     AVS::AVCDevice* GetAVCDevice() const;
     32    AVS::AVCDevice* GetAVCDevice(void) const;
     33    virtual FirewireDevice::PowerState GetPowerState(void) const;
    2934
    30     // Sets
    31     bool SetChannelByNumber(int channel);
    32 
    3335  private:
    34     bool OpenFirewire();
    35     void CloseFirewire();
     36    virtual bool OpenFirewire(void);
     37    virtual void CloseFirewire(void);
    3638
    3739  private:
    3840    AVS::AVCDeviceController* device_controller;
  • libs/libmythtv/signalmonitor.cpp

     
    3434#   include "iptvchannel.h"
    3535#endif
    3636
     37#ifdef USING_FIREWIRE
     38#   include "firewiresignalmonitor.h"
     39#   include "firewirechannelbase.h"
     40#endif
     41
    3742#undef DBG_SM
    3843#define DBG_SM(FUNC, MSG) VERBOSE(VB_CHANNEL, \
    3944    "SM("<<channel->GetDevice()<<")::"<<FUNC<<": "<<MSG);
     
    117122    }
    118123#endif
    119124
     125#ifdef USING_FIREWIRE
     126    if (cardtype.upper() == "FIREWIRE")
     127    {
     128        FirewireChannelBase *fc = dynamic_cast<FirewireChannelBase*>(channel);
     129        if (fc)
     130            signalMonitor = new FirewireSignalMonitor(db_cardnum, fc);
     131    }
     132#endif
     133
    120134    if (!signalMonitor)
    121135    {
    122136        VERBOSE(VB_IMPORTANT,
  • libs/libmythtv/firewiresignalmonitor.h

     
     1// -*- Mode: c++ -*-
     2
     3#ifndef _FIREWIRESIGNALMONITOR_H_
     4#define _FIREWIRESIGNALMONITOR_H_
     5
     6#include <qmap.h>
     7#include <qmutex.h>
     8#include <qdatetime.h>
     9
     10#include "dtvsignalmonitor.h"
     11#include "linuxfirewiredevice.h"
     12#include "util.h"
     13
     14class FirewireChannelBase;
     15
     16class FirewireSignalMonitor : public DTVSignalMonitor, public TSDataListener
     17{
     18    Q_OBJECT
     19
     20  public:
     21    FirewireSignalMonitor(int db_cardnum, FirewireChannelBase* _channel,
     22                          uint _flags = kFWSigMon_WaitForPower,
     23                          const char *_name = "FirewireSignalMonitor");
     24
     25    virtual void HandlePAT(const ProgramAssociationTable*);
     26    virtual void HandlePMT(uint, const ProgramMapTable*);
     27
     28    void Stop(void);
     29
     30  public slots:
     31    void deleteLater(void);
     32
     33  protected:
     34    FirewireSignalMonitor(void);
     35    FirewireSignalMonitor(const FirewireSignalMonitor&);
     36    virtual ~FirewireSignalMonitor();
     37
     38    virtual void UpdateValues(void);
     39    void EmitFirewireSignals(void);
     40
     41    static void *TableMonitorThread(void *param);
     42    void RunTableMonitor(void);
     43
     44    bool SupportsTSMonitoring(void);
     45
     46    void AddData(const unsigned char *data, uint dataSize);
     47
     48  public:
     49    static const uint kPowerTimeout;
     50    static const uint kBufferTimeout;
     51
     52  protected:
     53    bool               dtvMonitorRunning;
     54    pthread_t          table_monitor_thread;
     55    bool               stb_needs_retune;
     56    bool               stb_needs_to_wait_for_pat;
     57    bool               stb_needs_to_wait_for_power;
     58    MythTimer          stb_wait_for_pat_timer;
     59    MythTimer          stb_wait_for_power_timer;
     60
     61    vector<unsigned char> buffer;
     62
     63    static QMap<void*,uint> pat_keys;
     64    static QMutex           pat_keys_lock;
     65};
     66
     67#endif // _FIREWIRESIGNALMONITOR_H_
  • libs/libmythtv/darwinfirewirerecorder.h

     
    3333class DarwinFirewireRecorder : public FirewireRecorderBase
    3434{
    3535  public:
    36     DarwinFirewireRecorder(TVRec *rec, ChannelBase* tuner);
     36    DarwinFirewireRecorder(TVRec *rec, DarwinFirewireChannel *channel);
    3737    ~DarwinFirewireRecorder();
    3838
    3939    bool Open(void);
    4040
    41     void SetOption(const QString &name, const QString &value);
    42     void SetOption(const QString &name, int value);
    43 
    4441  private:
    4542    void Close();
    4643
    4744    void start();
    4845    void stop();
    4946    void no_data();
    50     bool grab_frames();
    5147
    5248    static IOReturn MPEGNoData(void* pRefCon);
    5349    static IOReturn tspacket_callback(UInt32 tsPacketCount, UInt32 **ppBuf, void *pRefCon);
  • libs/libmythtv/firewirechannel.h

     
    55 *  Distributed as part of MythTV under GPL v2 and later.
    66 */
    77
     8#ifndef _LINUX_FIREWIRE_CHANNEL_H_
     9#define _LINUX_FIREWIRE_CHANNEL_H_
    810
    9 #ifndef FIREWIRECHANNEL_H
    10 #define FIREWIRECHANNEL_H
    11 
    1211#include <qstring.h>
    1312#include "tv_rec.h"
    1413#include "firewirechannelbase.h"
    15 #include <libavc1394/avc1394.h>
    1614
    1715using namespace std;
    1816
    19 class FirewireChannel : public FirewireChannelBase
     17class LinuxFirewireDevice;
     18
     19class LinuxFirewireChannel : public FirewireChannelBase
    2020{
    2121  public:
    22     enum PowerState {
    23         On,
    24         Off,
    25         Failed
    26     };
     22    LinuxFirewireChannel(FireWireDBOptions firewire_opts, TVRec *parent);
     23    ~LinuxFirewireChannel(void);
    2724
    28     FirewireChannel(FireWireDBOptions firewire_opts, TVRec *parent);
    29     ~FirewireChannel(void);
     25    // Commands
     26    virtual bool Retune(void);
    3027
    31     bool OpenFirewire(void);
    32     void CloseFirewire(void);
    33 
    3428    // Sets
    35     void SetExternalChanger(void);
    36     bool SetChannelByNumber(int channel);
     29    virtual bool SetChannelByNumber(int channel);
     30    virtual bool SetPowerState(bool on);
    3731
    3832    // Gets
    39     bool IsOpen(void) const { return isopen; }
    40     QString GetDevice(void) const
     33    virtual QString GetDevice(void) const
    4134        { return QString("%1:%2").arg(fw_opts.port).arg(fw_opts.node); }
    42     PowerState GetPowerState(void);
     35    virtual LinuxFirewireDevice *GetFirewireDevice(void)
     36        { return device; }
     37    virtual FirewireDevice::PowerState GetPowerState(void) const;
    4338
    4439  private:
    45     FireWireDBOptions  fw_opts;
    46     nodeid_t           fwnode;
    47     raw1394handle_t    fwhandle;
     40    virtual bool OpenFirewire(void);
     41    virtual void CloseFirewire(void);
     42
     43  private:
     44    FireWireDBOptions    fw_opts;
     45    LinuxFirewireDevice *device;
     46    uint                 current_channel;
     47    bool                 is_port_open;
    4848};
    4949
    50 #endif
     50#endif // _LINUX_FIREWIRE_CHANNEL_H_
  • libs/libmythtv/firewirechannelbase.cpp

     
    55 */
    66
    77
    8 #include <iostream>
     8#include "mythconfig.h" // for CONFIG_DARWIN
    99#include "mythcontext.h"
    1010#include "firewirechannelbase.h"
     11#include "tv_rec.h"
    1112
     13#ifdef CONFIG_DARWIN
     14#   include "darwinfirewirechannel.h"
     15#else
     16#   include "firewirechannel.h"
     17#endif
     18
     19FirewireChannelBase *FirewireChannelBase::Init(
     20    const FireWireDBOptions &firewire_opts, TVRec *parent)
     21{
     22#ifdef CONFIG_DARWIN
     23    return new DarwinFirewireChannel(firewire_opts, parent);
     24#else
     25    return new LinuxFirewireChannel(firewire_opts, parent);
     26#endif
     27}
     28
    1229bool FirewireChannelBase::SetChannelByString(const QString &chan)
    1330{
    1431    inputs[currentInputID]->startChanNum = chan;
     
    2239    return isopen && SetChannelByNumber(chan.toInt());
    2340}
    2441
    25 bool FirewireChannelBase::Open()
     42bool FirewireChannelBase::Open(void)
    2643{
    2744    if (!InitializeInputs())
    2845        return false;
     
    3956    return true;
    4057}
    4158
    42 void FirewireChannelBase::Close()
     59void FirewireChannelBase::Close(void)
    4360{
    4461    if (isopen)
    4562        CloseFirewire();
  • libs/libmythtv/linuxfirewiredevice.h

     
     1/**
     2 *  LinuxFirewireDevice
     3 *  Copyright (c) 2005 by Jim Westfall
     4 *  Distributed as part of MythTV under GPL v2 and later.
     5 */
     6
     7#ifndef _LINUX_FIREWIRE_DEVICE_H_
     8#define _LINUX_FIREWIRE_DEVICE_H_
     9
     10#include "firewiredevice.h"
     11
     12class FWPriv;
     13
     14class LinuxFirewireDevice : public FirewireDevice
     15{
     16  public:
     17
     18    LinuxFirewireDevice(uint port, uint node, uint speed, bool use_p2p,
     19                        uint av_buffer_size_in_bytes = 0);
     20    ~LinuxFirewireDevice();
     21
     22    bool OpenPort(void);
     23    bool ClosePort(void);
     24
     25    void AddListener(TSDataListener*);
     26    void RemoveListener(TSDataListener*);
     27
     28    // Sets
     29    bool SetPowerState(bool on);
     30    bool SetChannel(const QString &panel_model, uint channel);
     31
     32    // Gets
     33    bool IsPortOpen(void) const;
     34    bool IsNodeOpen(void) const;
     35    bool IsAVStreamOpen(void) const;
     36    bool IsTuner(void) const;
     37    bool IsPanel(void) const;
     38    bool IsSTB(void) const { return IsTuner() && IsPanel(); }
     39
     40    // non-const Gets
     41    PowerState GetPowerState(void);
     42
     43    // Commands
     44    bool ResetBus(void);
     45
     46    void RunStreaming(void);
     47    bool LoopIteration(uint timeout_in_msec);
     48
     49    void PrintDropped(uint dropped_packets);
     50    void BroadcastToListeners(const unsigned char *data, uint dataSize);
     51
     52    // Statics
     53    static inline bool IsSTBSupported(const QString &model);
     54
     55    // Constants
     56    static const uint kBroadcastChannel;
     57    static const uint kConnectionP2P;
     58    static const uint kConnectionBroadcast;
     59    static const uint kMaxBufferedPackets;
     60
     61  private:
     62    bool OpenNode(void);
     63    bool CloseNode(void);
     64
     65    bool OpenAVStream(void);
     66    bool CloseAVStream(void);
     67
     68    bool OpenP2PNode(void);
     69    bool CloseP2PNode(void);
     70
     71    bool OpenBroadcastNode(void);
     72    bool CloseBroadcastNode(void);
     73
     74    bool StartStreaming(void);
     75    bool StopStreaming(void);
     76    bool StopStreamingLater(void);
     77
     78    bool SetAVStreamBufferSize(uint size_in_bytes);
     79    bool SetAVStreamSpeed(uint speed);
     80
     81    bool IsSubunitType(uint subunit_type) const;
     82
     83  private:
     84    uint                     m_port;
     85    uint                     m_node;
     86    uint                     m_speed;
     87    uint                     m_bufsz;
     88    bool                     m_use_p2p;
     89    uint                     m_open_port_cnt;
     90    FWPriv                  *m_priv;
     91    vector<TSDataListener*>  m_listeners;
     92};
     93
     94inline bool LinuxFirewireDevice::IsSTBSupported(const QString &panel_model)
     95{
     96    QString model = panel_model.upper();
     97    return ((model == "DCT-6200") ||
     98            (model == "SA3250HD") ||
     99            (model == "SA4200HD"));
     100}
     101
     102#endif // _LINUX_FIREWIRE_DEVICE_H_
  • libs/libmythtv/dtvsignalmonitor.h

     
    8383    bool WaitForLock(int timeout=-1);
    8484
    8585    // MPEG
    86     void HandlePAT(const ProgramAssociationTable*);
    87     void HandleCAT(const ConditionalAccessTable*) {}
    88     void HandlePMT(uint, const ProgramMapTable*);
     86    virtual void HandlePAT(const ProgramAssociationTable*);
     87    virtual void HandleCAT(const ConditionalAccessTable*) {}
     88    virtual void HandlePMT(uint, const ProgramMapTable*);
    8989
    9090    // ATSC Main
    9191    void HandleSTT(const SystemTimeTable*) {}
  • libs/libmythtv/tv_rec.cpp

     
    4848#include "dbox2channel.h"
    4949#include "hdhrchannel.h"
    5050#include "iptvchannel.h"
     51#include "firewirechannelbase.h"
    5152
    5253#include "recorderbase.h"
    5354#include "NuppelVideoRecorder.h"
     
    5758#include "dbox2recorder.h"
    5859#include "hdhrrecorder.h"
    5960#include "iptvrecorder.h"
     61#include "firewirerecorderbase.h"
    6062
    6163#ifdef USING_V4L
    6264#include "channel.h"
    6365#endif
    6466
    65 #ifdef USING_FIREWIRE
    66 #ifdef CONFIG_DARWIN
    67 #include "darwinfirewirerecorder.h"
    68 #include "darwinfirewirechannel.h"
    69 #else
    70 #include "firewirerecorder.h"
    71 #include "firewirechannel.h"
    72 #endif
    73 #endif
    74 
    7567#define DEBUG_CHANNEL_PREFIX 0 /**< set to 1 to channel prefixing */
    7668
    7769#define LOC QString("TVRec(%1): ").arg(cardid)
     
    158150    else if (genOpt.cardtype == "FIREWIRE")
    159151    {
    160152#ifdef USING_FIREWIRE
    161 # ifdef CONFIG_DARWIN
    162         channel = new DarwinFirewireChannel(fwOpt, this);
    163 # else
    164         channel = new FirewireChannel(fwOpt, this);
    165 # endif
    166         if (!channel->Open())
     153        channel = FirewireChannelBase::Init(fwOpt, this);
     154        if (!channel || !channel->Open())
    167155            return false;
    168156        InitChannel(genOpt.defaultinput, startchannel);
    169157        init_run = true;
     
    831819    else if (genOpt.cardtype == "FIREWIRE")
    832820    {
    833821#ifdef USING_FIREWIRE
    834 # ifdef CONFIG_DARWIN
    835         recorder = new DarwinFirewireRecorder(this, this->channel);
    836 # else
    837         recorder = new FirewireRecorder(this);
    838         recorder->SetOption("port",       fwOpt.port);
    839         recorder->SetOption("node",       fwOpt.node);
    840         recorder->SetOption("speed",      fwOpt.speed);
    841         recorder->SetOption("model",      fwOpt.model);
    842         recorder->SetOption("connection", fwOpt.connection);
    843 # endif // !CONFIG_DARWIN
     822        recorder = FirewireRecorderBase::Init(this, GetFirewireChannel());
     823        if (recorder)
     824        {
     825            recorder->SetOption("port",       fwOpt.port);
     826            recorder->SetOption("node",       fwOpt.node);
     827            recorder->SetOption("speed",      fwOpt.speed);
     828            recorder->SetOption("model",      fwOpt.model);
     829            recorder->SetOption("connection", fwOpt.connection);
     830        }
    844831#endif // USING_FIREWIRE
    845832    }
    846833    else if (genOpt.cardtype == "DBOX2")
     
    11141101#endif // USING_DVB
    11151102}
    11161103
     1104FirewireChannelBase *TVRec::GetFirewireChannel(void)
     1105{
     1106#ifdef USING_FIREWIRE
     1107    return dynamic_cast<FirewireChannelBase*>(channel);
     1108#else
     1109    return NULL;
     1110#endif // USING_FIREWIRE
     1111}
     1112
    11171113Channel *TVRec::GetV4LChannel(void)
    11181114{
    11191115#ifdef USING_V4L
  • libs/libmythtv/tv_rec.h

     
    3535class DBox2Channel;
    3636class DTVChannel;
    3737class DVBChannel;
     38class FirewireChannelBase;
    3839class Channel;
    3940class HDHRChannel;
    4041
     
    261262    DTVChannel   *GetDTVChannel(void);
    262263    HDHRChannel  *GetHDHRChannel(void);
    263264    DVBChannel   *GetDVBChannel(void);
     265    FirewireChannelBase *GetFirewireChannel(void);
    264266    Channel      *GetV4LChannel(void);
    265267
    266268    bool SetupSignalMonitor(bool enable_table_monitoring, bool notify);
  • libs/libmythtv/firewiredevice.h

     
     1/**
     2 *  FirewireDevice
     3 *  Copyright (c) 2005 by Jim Westfall
     4 *  Distributed as part of MythTV under GPL v2 and later.
     5 */
     6
     7#ifndef _FIREWIRE_DEVICE_H_
     8#define _FIREWIRE_DEVICE_H_
     9
     10// C++ headers
     11#include <vector>
     12using namespace std;
     13
     14#include <qstring.h>
     15
     16class TSDataListener
     17{
     18  public:
     19    /// Callback function to add MPEG2 TS data
     20    virtual void AddData(const unsigned char *data, uint dataSize) = 0;
     21
     22  protected:
     23    virtual ~TSDataListener() { }
     24};
     25
     26class FirewireDevice
     27{
     28  public:
     29    // Public enums
     30    typedef enum
     31    {
     32        kAVCPowerOn,
     33        kAVCPowerOff,
     34        kAVCPowerUnknown,
     35        kAVCPowerQueryFailed,
     36    } PowerState;
     37};
     38
     39#endif // _FIREWIRE_DEVICE_H_
  • libs/libmythtv/linuxfirewiredevice.cpp

     
     1/**
     2 *  LinuxFirewireDevice
     3 *  Copyright (c) 2005 by Jim Westfall
     4 *  Copyright (c) 2006 by Daniel Kristjansson
     5 *  SA3250HD support Copyright (c) 2005 by Matt Porter
     6 *  SA4200HD/Alternate 3250 support Copyright (c) 2006 by Chris Ingrassia
     7 *  Distributed as part of MythTV under GPL v2 and later.
     8 */
     9
     10// POSIX headers
     11#include <pthread.h>
     12#include <sys/select.h>
     13
     14// Linux headers
     15#include <libraw1394/raw1394.h>
     16#include <libiec61883/iec61883.h>
     17#include <libavc1394/avc1394.h>
     18
     19// C++ headers
     20#include <algorithm>
     21using namespace std;
     22
     23// Qt headers
     24#include <qdatetime.h>
     25
     26// MythTV headers
     27#include "linuxfirewiredevice.h"
     28#include "firewirerecorder.h"
     29#include "mythcontext.h"
     30
     31#define LOC QString("FireDev(%1:%2): ").arg(m_port).arg(m_node)
     32#define LOC_WARN QString("FireDev(%1:%2), Warning: ").arg(m_port).arg(m_node)
     33#define LOC_ERR QString("FireDev(%1:%2), Error: ").arg(m_port).arg(m_node)
     34
     35
     36#ifndef AVC1394_PANEL_COMMAND_PASS_THROUGH
     37#define AVC1394_PANEL_COMMAND_PASS_THROUGH     0x000007C00
     38#endif
     39
     40#ifndef AVC1394_PANEL_OPERATION_0
     41#define AVC1394_PANEL_OPERATION_0              0x000000020
     42#endif
     43
     44#define AVC1394_CMD_OPERAND_POWER_STATE        0x7F
     45
     46// Basic Panel commands
     47#define PANEL_CMD0 (AVC1394_CTYPE_CONTROL | \
     48                    AVC1394_SUBUNIT_TYPE_PANEL | \
     49                    AVC1394_SUBUNIT_ID_0 | \
     50                    AVC1394_PANEL_COMMAND_PASS_THROUGH)
     51
     52// Scientific Atlanta defines
     53#define AVC1394_SA3250_OPERAND_KEY_PRESS        0xE7
     54#define AVC1394_SA3250_OPERAND_KEY_RELEASE      0x67
     55#define SA_CMD0     PANEL_CMD0
     56#define SA_CMD1     AVC1394_CTYPE_GENERAL_INQUIRY
     57#define SA_CMD2     0xff000000
     58
     59// Motorola defines
     60#define MOT_CMD0  (PANEL_CMD0 | AVC1394_PANEL_OPERATION_0)
     61
     62class FWPriv
     63{
     64  public:
     65    FWPriv() :
     66        handle(0), avstream(0),
     67        channel(-1),
     68        is_p2p_node_open(false), is_bcast_node_open(false),
     69        is_streaming(false), stop_streaming_timer_on(false)
     70    {
     71        bzero(unit_table, sizeof(unit_table));
     72    }
     73
     74    raw1394handle_t  handle;
     75    iec61883_mpeg2_t avstream;
     76    quadlet_t        unit_table[8];
     77    int              channel;
     78    int              open_node;
     79    bool             is_p2p_node_open;
     80    bool             is_bcast_node_open;
     81    bool             is_streaming;
     82    bool             is_streaming_running;
     83    bool             stop_streaming_timer_on;
     84    QDateTime        stop_streaming_timer;
     85    pthread_t        streaming_thread;
     86};
     87
     88const uint LinuxFirewireDevice::kBroadcastChannel    = 63;
     89const uint LinuxFirewireDevice::kConnectionP2P       = 0;
     90const uint LinuxFirewireDevice::kConnectionBroadcast = 1;
     91const uint LinuxFirewireDevice::kMaxBufferedPackets  = 2000;
     92
     93// callback function for libiec61883
     94static int fw_tspacket_handler(unsigned char *tspacket, int len,
     95                               uint dropped, void *callback_data);
     96static QString speed_to_string(uint speed);
     97static quadlet_t *send_avc_command(raw1394handle_t handle,
     98                                   uint            node,
     99                                   quadlet_t      *cmd,
     100                                   uint            cmd_len,
     101                                   uint            retry_cnt = 1);
     102static void close_avc_command(raw1394handle_t handle);
     103
     104
     105LinuxFirewireDevice::LinuxFirewireDevice(
     106    uint port, uint node, uint speed, bool use_p2p,
     107    uint av_buffer_size_in_bytes) :
     108    m_port(port),       m_node(node),
     109    m_speed(speed),     m_bufsz(av_buffer_size_in_bytes),
     110    m_use_p2p(use_p2p),
     111    m_open_port_cnt(0), m_priv(new FWPriv())
     112{
     113    if (!m_bufsz)
     114        m_bufsz = gContext->GetNumSetting("HDRingbufferSize");
     115}
     116
     117LinuxFirewireDevice::~LinuxFirewireDevice()
     118{
     119    if (IsPortOpen())
     120    {
     121        VERBOSE(VB_IMPORTANT, LOC_ERR + "ctor called with open port");
     122        while (IsPortOpen())
     123            ClosePort();
     124    }
     125
     126    if (m_priv)
     127    {
     128        delete m_priv;
     129        m_priv = NULL;
     130    }
     131}
     132
     133bool LinuxFirewireDevice::OpenPort(void)
     134{
     135    VERBOSE(VB_RECORD, LOC + "OpenPort()");
     136
     137    m_open_port_cnt++;
     138
     139    if (m_priv->handle)
     140        return true;
     141
     142    VERBOSE(VB_RECORD, LOC + "Getting raw1394 handle "<<(m_open_port_cnt-1));
     143    m_priv->handle = raw1394_new_handle_on_port(m_port);
     144
     145    if (!m_priv->handle)
     146    {
     147        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to get handle for " +
     148                QString("port: %1").arg(m_port) + ENO);
     149
     150        return false;
     151    }
     152
     153    if (avc1394_subunit_info(m_priv->handle, m_node, m_priv->unit_table) < 0)
     154        bzero(m_priv->unit_table, sizeof(m_priv->unit_table));
     155
     156    QString str = "Subunit Types: ";
     157
     158    if (IsSubunitType(AVC1394_SUBUNIT_TYPE_VIDEO_MONITOR))
     159        str += "Video Monitor, ";
     160    if (IsSubunitType(AVC1394_SUBUNIT_TYPE_AUDIO))
     161        str += "Audio, ";
     162    if (IsSubunitType(AVC1394_SUBUNIT_TYPE_PRINTER))
     163        str += "Printer, ";
     164    if (IsSubunitType(AVC1394_SUBUNIT_TYPE_DISC_RECORDER))
     165        str += "Disk Recorder, ";
     166    if (IsSubunitType(AVC1394_SUBUNIT_TYPE_TAPE_RECORDER))
     167        str += "Tape Recorder, ";
     168    if (IsSubunitType(AVC1394_SUBUNIT_TYPE_VCR))
     169        str += "VCR, ";
     170    if (IsSubunitType(AVC1394_SUBUNIT_TYPE_TUNER))
     171        str += "Tuner, ";
     172    if (IsSubunitType(AVC1394_SUBUNIT_TYPE_CA))
     173        str += "CA, ";
     174    if (IsSubunitType(AVC1394_SUBUNIT_TYPE_VIDEO_CAMERA))
     175        str += "Camera, ";
     176    if (IsSubunitType(AVC1394_SUBUNIT_TYPE_PANEL))
     177        str += "Panel, ";
     178    if (IsSubunitType(AVC1394_SUBUNIT_TYPE_BULLETIN_BOARD))
     179        str += "Bulletin Board, ";
     180    if (IsSubunitType(AVC1394_SUBUNIT_TYPE_CAMERA_STORAGE))
     181        str += "Camera Storage, ";
     182    if (IsSubunitType(AVC1394_SUBUNIT_TYPE_MUSIC))
     183        str += "Music, ";
     184    if (IsSubunitType(AVC1394_SUBUNIT_TYPE_VENDOR_UNIQUE))
     185        str += "Vendor Unique, ";
     186
     187    VERBOSE(VB_RECORD, LOC + str);
     188
     189    return true;
     190}
     191
     192bool LinuxFirewireDevice::ClosePort(void)
     193{
     194    VERBOSE(VB_RECORD, LOC + "ClosePort()");
     195
     196    if (m_open_port_cnt < 1)
     197        return false;
     198
     199    m_open_port_cnt--;
     200
     201    if (m_open_port_cnt != 0)
     202        return true;
     203
     204    if (m_priv->handle)
     205    {
     206        if (IsNodeOpen())
     207            CloseNode();
     208
     209        VERBOSE(VB_RECORD, LOC + "Releasing raw1394 handle "<<m_open_port_cnt);
     210        raw1394_destroy_handle(m_priv->handle);
     211        m_priv->handle = NULL;
     212    }
     213
     214    return true;
     215}
     216
     217bool LinuxFirewireDevice::OpenNode(void)
     218{
     219    if (m_use_p2p)
     220        return OpenP2PNode();
     221    else
     222        return OpenBroadcastNode();
     223}
     224
     225bool LinuxFirewireDevice::CloseNode(void)
     226{
     227    if (m_priv->is_p2p_node_open)
     228        return CloseP2PNode();
     229
     230    if (m_priv->is_bcast_node_open)
     231        return CloseBroadcastNode();
     232
     233    return true;
     234}
     235
     236bool LinuxFirewireDevice::OpenP2PNode(void)
     237{
     238    if (m_priv->is_bcast_node_open)
     239        return false;
     240
     241    if (m_priv->is_p2p_node_open)
     242        return true;
     243
     244    VERBOSE(VB_RECORD, LOC + "Opening P2P connection");
     245
     246    m_priv->channel = m_node;
     247    if (iec61883_cmp_create_p2p_output(m_priv->handle, m_node | 0xffc0, 0,
     248                                       m_priv->channel, m_speed) != 0)
     249    {
     250        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to create P2P connection");
     251
     252        m_priv->channel = -1;
     253        return false;
     254    }
     255
     256    m_priv->is_p2p_node_open = true;
     257
     258    return true;
     259}
     260
     261bool LinuxFirewireDevice::CloseP2PNode(void)
     262{
     263    if (m_priv->is_p2p_node_open && (m_priv->channel >= 0))
     264    {
     265        VERBOSE(VB_RECORD, LOC + "Closing P2P connection");
     266
     267        if (m_priv->avstream)
     268            CloseAVStream();
     269
     270        iec61883_cmp_disconnect(m_priv->handle, m_node | 0xffc0, 0,
     271                                raw1394_get_local_id(m_priv->handle),
     272                                -1, m_priv->channel, 0);
     273
     274        m_priv->channel = -1;
     275        m_priv->is_p2p_node_open = false;
     276    }
     277
     278    return true;
     279}
     280
     281bool LinuxFirewireDevice::OpenBroadcastNode(void)
     282{
     283    if (m_priv->is_p2p_node_open)
     284        return false;
     285
     286    if (m_priv->is_bcast_node_open)
     287        return true;
     288
     289    m_priv->channel = kBroadcastChannel - m_node;
     290
     291    VERBOSE(VB_RECORD, LOC + "Opening broadcast connection on " +
     292            QString("node %1, channel %2")
     293            .arg(m_node).arg(m_priv->channel));
     294
     295    if (m_priv->avstream)
     296        CloseAVStream();
     297
     298    int err = iec61883_cmp_create_bcast_output(
     299        m_priv->handle, m_node | 0xffc0, 0, m_priv->channel, m_speed);
     300
     301    if (err != 0)
     302    {
     303        VERBOSE(VB_IMPORTANT, LOC_ERR +
     304                "Failed to create Broadcast connection");
     305
     306        m_priv->channel = -1;
     307        return false;
     308    }
     309
     310    m_priv->is_bcast_node_open = true;
     311
     312    return true;
     313}
     314
     315bool LinuxFirewireDevice::CloseBroadcastNode(void)
     316{
     317    if (m_priv->is_bcast_node_open)
     318    {
     319        VERBOSE(VB_RECORD, LOC + "Closing broadcast connection");
     320
     321        m_priv->channel = -1;
     322        m_priv->is_bcast_node_open = false;
     323    }
     324    return true;
     325}
     326
     327bool LinuxFirewireDevice::OpenAVStream(void)
     328{
     329    VERBOSE(VB_RECORD, LOC + "OpenAVStream");
     330
     331    if (!IsNodeOpen() && !OpenNode())
     332        return false;
     333
     334    if (m_priv->avstream)
     335        return true;
     336
     337    VERBOSE(VB_RECORD, LOC + "Opening A/V stream object");
     338
     339    if (!m_priv->handle)
     340    {
     341        VERBOSE(VB_IMPORTANT, LOC +
     342                "Can not open AVStream without IEEE 1394 Port");
     343
     344        return false;
     345    }
     346
     347    m_priv->avstream = iec61883_mpeg2_recv_init(
     348        m_priv->handle, fw_tspacket_handler, this);
     349
     350    if (!m_priv->avstream)
     351    {
     352        VERBOSE(VB_IMPORTANT, LOC + "Unable to open AVStream" + ENO);
     353
     354        return false;
     355    }
     356
     357    iec61883_mpeg2_set_synch(m_priv->avstream, 1 /* sync on close */);
     358
     359    if (m_bufsz)
     360        SetAVStreamBufferSize(m_bufsz);
     361
     362    return true;
     363}
     364
     365bool LinuxFirewireDevice::CloseAVStream(void)
     366{
     367    if (!m_priv->avstream)
     368        return true;
     369
     370    VERBOSE(VB_RECORD, LOC + "Closing A/V stream object");
     371
     372    while (m_listeners.size())
     373        RemoveListener(m_listeners[m_listeners.size() - 1]);
     374
     375    if (m_priv->is_streaming)
     376        StopStreaming();
     377
     378    iec61883_mpeg2_close(m_priv->avstream);
     379    m_priv->avstream = NULL;
     380
     381    return true;
     382}
     383
     384static void *streaming_thunk(void *param)
     385{
     386    LinuxFirewireDevice *mon = (LinuxFirewireDevice*) param;
     387    mon->RunStreaming();
     388    return NULL;
     389}
     390
     391void LinuxFirewireDevice::RunStreaming(void)
     392{
     393    m_priv->is_streaming_running = true;
     394
     395    uint no_data_cnt = 0;
     396    while (m_priv->is_streaming)
     397    {
     398        if (m_priv->stop_streaming_timer_on)
     399        {
     400            if (m_priv->stop_streaming_timer < QDateTime::currentDateTime())
     401                break;
     402
     403            usleep(50000);
     404            continue;
     405        }
     406
     407        no_data_cnt = (LoopIteration(250)) ? 0 : no_data_cnt + 1;
     408        if (no_data_cnt > 6)
     409        {
     410            ResetBus();
     411            no_data_cnt = 0;
     412        }
     413    }
     414
     415    m_priv->is_streaming_running = false;
     416    if (m_priv->stop_streaming_timer_on)
     417    {
     418        CloseAVStream();
     419        CloseNode();
     420        m_priv->stop_streaming_timer_on = false;
     421    }
     422}
     423
     424bool LinuxFirewireDevice::StartStreaming(void)
     425{
     426    m_priv->stop_streaming_timer_on = false;
     427
     428    if (m_priv->is_streaming)
     429        return m_priv->is_streaming;
     430
     431    if (!IsAVStreamOpen() && !OpenAVStream())
     432        return false;
     433
     434    VERBOSE(VB_RECORD, LOC + "Starting A/V streaming");
     435
     436    if (!m_priv->avstream)
     437    {
     438        VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting A/V streaming, no A/V obj");
     439        return false;
     440    }
     441
     442    if (m_priv->channel < 0)
     443    {
     444        VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting A/V streaming, no channel");
     445        return false;
     446    }
     447
     448    if (iec61883_mpeg2_recv_start(m_priv->avstream, m_priv->channel) == 0)
     449    {
     450        m_priv->is_streaming = true;
     451
     452        pthread_create(&m_priv->streaming_thread, NULL,
     453                       streaming_thunk, this);
     454
     455        while (!m_priv->is_streaming_running)
     456            usleep(50);
     457    }
     458    else
     459    {
     460        VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting A/V streaming " + ENO);
     461    }
     462
     463    return m_priv->is_streaming;
     464}
     465
     466bool LinuxFirewireDevice::StopStreaming(void)
     467{
     468    VERBOSE(VB_RECORD, LOC + "Stopping A/V streaming");
     469
     470    if (m_priv->is_streaming)
     471    {
     472        m_priv->stop_streaming_timer_on = false;
     473        m_priv->is_streaming = false;
     474
     475        pthread_join(m_priv->streaming_thread, NULL);
     476
     477        iec61883_mpeg2_recv_stop(m_priv->avstream);
     478
     479        raw1394_iso_recv_flush(m_priv->handle);
     480    }
     481
     482    return true;
     483}
     484
     485bool LinuxFirewireDevice::StopStreamingLater(void)
     486{
     487    if (m_priv->is_streaming && !m_priv->stop_streaming_timer_on)
     488    {
     489        m_priv->stop_streaming_timer =
     490            QDateTime::currentDateTime().addSecs(2);
     491        m_priv->stop_streaming_timer_on = true;
     492    }
     493
     494    return true;
     495}
     496
     497bool LinuxFirewireDevice::SetAVStreamBufferSize(uint size_in_bytes)
     498{
     499    if (!m_priv->avstream)
     500        return false;
     501
     502    // Set buffered packets size
     503    uint   buffer_size      = max(size_in_bytes, 50 * TSPacket::SIZE);
     504    size_t buffered_packets = min(buffer_size / 4, kMaxBufferedPackets);
     505
     506    iec61883_mpeg2_set_buffers(m_priv->avstream, buffered_packets);
     507
     508    VERBOSE(VB_IMPORTANT, LOC +
     509            QString("Buffered packets %1 (%2 KB)")
     510            .arg(buffered_packets).arg(buffered_packets * 4));
     511
     512    return true;
     513}
     514
     515bool LinuxFirewireDevice::SetAVStreamSpeed(uint speed)
     516{
     517    if (!m_priv->avstream)
     518        return false;
     519
     520    uint curspeed = iec61883_mpeg2_get_speed(m_priv->avstream);
     521
     522    if (curspeed == speed)
     523    {
     524        m_speed = speed;
     525        return true;
     526    }
     527
     528    VERBOSE(VB_RECORD, LOC +
     529            QString("Changing Speed %1 -> %2")
     530            .arg(speed_to_string(curspeed))
     531            .arg(speed_to_string(m_speed)));
     532
     533    iec61883_mpeg2_set_speed(m_priv->avstream, speed);
     534
     535    if (speed == (uint)iec61883_mpeg2_get_speed(m_priv->avstream))
     536    {
     537        m_speed = speed;
     538        return true;
     539    }
     540
     541    VERBOSE(VB_IMPORTANT, LOC_WARN + "Unable to set firewire speed.");
     542
     543    return false;
     544}
     545
     546bool LinuxFirewireDevice::IsSubunitType(uint subunit_type) const
     547{
     548    for (uint i = 0; i < 8; i++)
     549    {
     550        for (uint j = 0; j < 32; j += 8)
     551        {
     552            uint subunit = (m_priv->unit_table[i] >> j) & 0xff;
     553            if ((subunit != 0xff) &&
     554                (subunit >> 3) == AVC1394_GET_SUBUNIT_TYPE(subunit_type))
     555            {
     556                return true;
     557            }
     558        }
     559    }
     560    return false;
     561}
     562
     563bool LinuxFirewireDevice::IsTuner(void) const
     564{
     565    return IsSubunitType(AVC1394_SUBUNIT_TYPE_TUNER);
     566}
     567
     568bool LinuxFirewireDevice::IsPanel(void) const
     569{
     570    return IsSubunitType(AVC1394_SUBUNIT_TYPE_PANEL);
     571}
     572
     573bool LinuxFirewireDevice::IsPortOpen(void) const
     574{
     575    return m_priv->handle;
     576}
     577
     578bool LinuxFirewireDevice::IsNodeOpen(void) const
     579{
     580    return m_priv->is_p2p_node_open || m_priv->is_bcast_node_open;
     581}
     582
     583bool LinuxFirewireDevice::IsAVStreamOpen(void) const
     584{
     585    return m_priv->avstream;
     586}
     587
     588bool LinuxFirewireDevice::ResetBus(void)
     589{
     590/*
     591    VERBOSE(VB_IMPORTANT, LOC + "ResetBus()");
     592
     593    bool open_node = IsNodeOpen();
     594    bool open_avstream = IsAVStreamOpen();
     595    bool restart_streaming = m_priv->is_streaming;
     596
     597    StopStreaming();
     598    CloseAVStream();
     599    CloseNode();
     600
     601    bool ok = (raw1394_reset_bus_new(m_priv->handle, RAW1394_LONG_RESET) != 0);
     602    if (!ok)
     603        VERBOSE(VB_IMPORTANT, LOC_ERR + "Bus Reset failed");
     604
     605    if (open_node)
     606        ok &= OpenNode();
     607
     608    if (open_avstream)
     609        ok &= OpenAVStream();
     610
     611    if (restart_streaming)
     612        ok &= StartStreaming();
     613
     614    return ok;
     615*/
     616    return true;
     617}
     618
     619bool LinuxFirewireDevice::LoopIteration(uint timeout_in_msec)
     620{
     621    int fwfd = raw1394_get_fd(m_priv->handle);
     622    if (fwfd < 0)
     623        return false;
     624
     625    struct timeval tv;
     626    fd_set rfds;
     627
     628    FD_ZERO(&rfds);
     629    FD_SET(fwfd, &rfds);
     630
     631    tv.tv_sec  = timeout_in_msec / 1000;
     632    tv.tv_usec = (timeout_in_msec % 1000) * 1000;
     633
     634    if (select(fwfd + 1, &rfds, NULL, NULL, &tv) <= 0)
     635    {
     636        VERBOSE(VB_IMPORTANT, LOC + QString("No Input in %1 msec...")
     637                .arg(timeout_in_msec));
     638
     639        return false;
     640    }
     641
     642    int ret = raw1394_loop_iterate(m_priv->handle);
     643    if (ret)
     644    {
     645        VERBOSE(VB_IMPORTANT, LOC_ERR + "libraw1394_loop_iterate() " +
     646                QString("returned %1").arg(ret));
     647
     648        return false;
     649    }
     650
     651    return true;
     652}
     653
     654void LinuxFirewireDevice::AddListener(TSDataListener *listener)
     655{
     656    if (listener)
     657    {
     658        RemoveListener(listener);
     659        m_listeners.push_back(listener);
     660    }
     661
     662    VERBOSE(VB_RECORD, LOC + "AddListener() "<<m_listeners.size());
     663
     664    if (!m_listeners.empty())
     665        StartStreaming();
     666}
     667
     668void LinuxFirewireDevice::RemoveListener(TSDataListener *listener)
     669{
     670    vector<TSDataListener*>::iterator it = m_listeners.end();
     671
     672    uint cnt = 0;
     673
     674    do
     675    {
     676        it = find(m_listeners.begin(), m_listeners.end(), listener);
     677        if (it != m_listeners.end())
     678        {
     679            m_listeners.erase(it);
     680            cnt++;
     681        }
     682    }
     683    while (it != m_listeners.end());
     684
     685    if (cnt)
     686    {
     687        VERBOSE(VB_RECORD, LOC + "RemoveListener() "<<m_listeners.size());
     688
     689//        if (m_priv->is_streaming && m_listeners.empty())
     690//            StopStreamingLater();
     691
     692        if (m_priv->is_streaming && m_listeners.empty())
     693            StopStreaming();
     694
     695        CloseAVStream();
     696        CloseNode();
     697    }
     698}
     699
     700void LinuxFirewireDevice::BroadcastToListeners(
     701    const unsigned char *data, uint dataSize)
     702{
     703    vector<TSDataListener*>::iterator it = m_listeners.begin();
     704    for (; it != m_listeners.end(); ++it)
     705        (*it)->AddData(data, dataSize);
     706}
     707
     708bool LinuxFirewireDevice::SetChannel(const QString &panel_model, uint channel)
     709{
     710    if (!IsSTBSupported(panel_model))
     711    {
     712        VERBOSE(VB_IMPORTANT, LOC_ERR +
     713                QString("Model: '%1' ").arg(panel_model) +
     714                "is not supported by internal channel changer.");
     715        return false;
     716    }
     717
     718    int digit[3];
     719    digit[0] = (channel % 1000) / 100;
     720    digit[1] = (channel % 100)  / 10;
     721    digit[2] = (channel % 10);
     722
     723    if (panel_model.upper() == "DCT-6200")
     724    {
     725        for (uint i = 0; i < 3 ;i++)
     726        {
     727            quadlet_t cmd[2] =
     728            {
     729                MOT_CMD0 | AVC1394_PANEL_OPERATION_0 | digit[i],
     730                0x0,
     731            };
     732
     733            if (!send_avc_command(m_priv->handle, m_node, cmd, 2))
     734                return false;
     735
     736            usleep(500000);
     737        }
     738
     739        return true;
     740    }
     741
     742    if (panel_model.upper() == "SA4200HD")
     743    {
     744        quadlet_t cmd[3] =
     745        {
     746            SA_CMD0 | AVC1394_SA3250_OPERAND_KEY_PRESS,
     747            SA_CMD1 | (channel << 8),
     748            SA_CMD2,
     749        };
     750
     751        if (!send_avc_command(m_priv->handle, m_node, cmd, 3))
     752            return false;
     753
     754        return true;
     755    }
     756   
     757    if (panel_model == "SA3250HD")
     758    {
     759        digit[0] |= 0x30;
     760        digit[1] |= 0x30;
     761        digit[2] |= 0x30;
     762
     763        quadlet_t cmd[3] =
     764        {
     765            SA_CMD0 | AVC1394_SA3250_OPERAND_KEY_PRESS,
     766            SA_CMD1 | (digit[2] << 16) | (digit[1] << 8) | digit[0],
     767            SA_CMD2,
     768        };
     769
     770        VERBOSE(VB_CHANNEL, LOC +
     771                QString("Channel2: %1%2%3 cmds: 0x%4, 0x%5, 0x%6")
     772                .arg(digit[0] & 0xf).arg(digit[1] & 0xf)
     773                .arg(digit[2] & 0xf)
     774                .arg(cmd[0], 0, 16).arg(cmd[1], 0, 16)
     775                .arg(cmd[2], 0, 16));
     776
     777        if (!send_avc_command(m_priv->handle, m_node, cmd, 3))
     778            return false;
     779
     780        cmd[0] = SA_CMD0 | AVC1394_SA3250_OPERAND_KEY_RELEASE;
     781        cmd[1] = SA_CMD1 | (digit[0] << 16) | (digit[1] << 8) | digit[2];
     782        cmd[2] = SA_CMD2;
     783
     784        VERBOSE(VB_CHANNEL, LOC +
     785                QString("Channel3: %1%2%3 cmds: 0x%4, 0x%5, 0x%6")
     786                .arg(digit[0] & 0xf).arg(digit[1] & 0xf)
     787                .arg(digit[2] & 0xf)
     788                .arg(cmd[0], 0, 16).arg(cmd[1], 0, 16)
     789                .arg(cmd[2], 0, 16));
     790
     791        if (!send_avc_command(m_priv->handle, m_node, cmd, 3))
     792            return false;
     793
     794        return true;
     795    }
     796
     797    return false;
     798}
     799
     800bool LinuxFirewireDevice::SetPowerState(bool on)
     801{
     802    quadlet_t cmd =
     803        AVC1394_CTYPE_CONTROL     | AVC1394_SUBUNIT_TYPE_UNIT |
     804        AVC1394_SUBUNIT_ID_IGNORE | AVC1394_COMMAND_POWER;
     805
     806    cmd |= (on) ? AVC1394_CMD_OPERAND_POWER_ON : AVC1394_CMD_OPERAND_POWER_OFF;
     807
     808    QString cmdStr = (on) ? "on" : "off";
     809    VERBOSE(VB_RECORD, LOC + QString("Powering %1 (cmd: 0x%2)")
     810            .arg(cmdStr).arg(cmd, 0, 16));
     811
     812    quadlet_t *rval = send_avc_command(m_priv->handle, m_node, &cmd, 1);
     813
     814    if (!rval)
     815    {
     816        close_avc_command(m_priv->handle);
     817        VERBOSE(VB_IMPORTANT, LOC + "Power on cmd failed (no response)");
     818        return false;
     819    }
     820
     821    quadlet_t response = rval[0];
     822    close_avc_command(m_priv->handle);
     823
     824    if (AVC1394_MASK_RESPONSE(response) != AVC1394_RESPONSE_ACCEPTED)
     825    {
     826        VERBOSE(VB_IMPORTANT, LOC_ERR +
     827                QString("Power %1 cmd failed (0x%2)")
     828                .arg(cmdStr).arg(response, 0, 16));
     829
     830        return false;
     831    }
     832
     833    VERBOSE(VB_RECORD, LOC +
     834            QString("Power %1 cmd sent successfully (0x%2)")
     835            .arg(cmdStr).arg(response, 0, 16));
     836
     837    return true;
     838}
     839
     840FirewireDevice::PowerState LinuxFirewireDevice::GetPowerState(void)
     841{
     842    quadlet_t cmd =
     843        AVC1394_CTYPE_STATUS      | AVC1394_SUBUNIT_TYPE_UNIT |
     844        AVC1394_SUBUNIT_ID_IGNORE | AVC1394_COMMAND_POWER     |
     845        AVC1394_CMD_OPERAND_POWER_STATE;
     846
     847    VERBOSE(VB_CHANNEL, LOC + QString("Requesting STB Power State (cmd: 0x%1)")
     848            .arg(cmd, 0, 16));
     849
     850    quadlet_t *rval = send_avc_command(m_priv->handle, m_node, &cmd, 1);
     851
     852    if (!rval)
     853    {
     854        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to get STB Power State");
     855        return kAVCPowerQueryFailed;
     856    }
     857
     858    quadlet_t response = rval[0];
     859    // TODO we probably need to call close_avc_command(m_priv->handle)...
     860
     861    QString loc = LOC + "STB Power State: ";
     862    QString rs  = QString(" (0x%1)").arg(response, 0, 16);
     863
     864    if (AVC1394_MASK_RESPONSE(response) != AVC1394_RESPONSE_IMPLEMENTED)
     865    {
     866        VERBOSE(VB_CHANNEL, loc + "Query not implemented" + rs);
     867        return kAVCPowerUnknown;
     868    }
     869
     870    if (AVC1394_MASK_OPERAND0(response) == AVC1394_CMD_OPERAND_POWER_ON)
     871    {
     872        VERBOSE(VB_CHANNEL, loc + "On" + rs);
     873        return kAVCPowerOn;
     874    }
     875
     876    if (AVC1394_MASK_OPERAND0(response) == AVC1394_CMD_OPERAND_POWER_OFF)
     877    {
     878        VERBOSE(VB_CHANNEL, loc + "Off" + rs);
     879        return kAVCPowerOff;
     880    }
     881   
     882    VERBOSE(VB_IMPORTANT, LOC_ERR + "STB Power State: Unknown Response" + rs);
     883
     884    return kAVCPowerUnknown;
     885}
     886
     887void LinuxFirewireDevice::PrintDropped(uint dropped_packets)
     888{
     889    if (dropped_packets == 1)
     890    {
     891        VERBOSE(VB_RECORD, LOC_ERR + "Dropped a TS packet");
     892    }
     893    else if (dropped_packets > 1)
     894    {
     895        VERBOSE(VB_RECORD, LOC_ERR +
     896                QString("Dropped %1 TS packets").arg(dropped_packets));
     897    }
     898}
     899
     900static int fw_tspacket_handler(unsigned char *tspacket, int len,
     901                               uint dropped, void *callback_data)
     902{
     903    LinuxFirewireDevice *fw = (LinuxFirewireDevice*) callback_data;
     904    if (!fw)
     905        return 0;
     906
     907    if (dropped)
     908        fw->PrintDropped(dropped);
     909
     910    if (len > 0)
     911        fw->BroadcastToListeners(tspacket, len);
     912
     913    return 1;
     914}
     915
     916static QString speed_to_string(uint speed)
     917{
     918    if (speed > RAW1394_ISO_SPEED_400)
     919        return QString("Invalid Speed (%1)").arg(speed);
     920
     921    static const uint speeds[] = { 100, 200, 400, };
     922    return QString("%1Mbps").arg(speeds[speed]);
     923}
     924
     925static quadlet_t *send_avc_command(raw1394handle_t handle,
     926                                   uint            node,
     927                                   quadlet_t      *cmd,
     928                                   uint            cmd_len,
     929                                   uint            retry_cnt)
     930{
     931    if (!handle)
     932        return NULL;
     933
     934    quadlet_t *ret = avc1394_transaction_block(
     935        handle, node, cmd, cmd_len, retry_cnt);
     936
     937    if (!ret)
     938        VERBOSE(VB_IMPORTANT, "AVC transaction failed.");
     939
     940    return ret;
     941}
     942
     943static void close_avc_command(raw1394handle_t handle)
     944{
     945    if (handle)
     946        avc1394_transaction_block_close(handle);
     947}
     948