Ticket #1648: firewire-sm-v28.patch

File firewire-sm-v28.patch, 124.5 KB (added by danielk, 20 years ago)

Updated patch, better channel change detection + some refactoring

  • libs/libmythtv/firewirechannel.cpp

     
    11/**
    22 *  FirewireChannel
    3  *  Copyright (c) 2005 by Jim Westfall
    4  *  SA3250HD support Copyright (c) 2005 by Matt Porter
    5  *  SA4200HD/Alternate 3250 support Copyright (c) 2006 by Chris Ingrassia
     3 *  Copyright (c) 2005 by Jim Westfall, Dave Abrahams
     4 *  Copyright (c) 2006 by Daniel Kristjansson
    65 *  Distributed as part of MythTV under GPL v2 and later.
    76 */
    87
    9 
    10 #include <iostream>
    118#include "mythcontext.h"
     9#include "tv_rec.h"
     10#include "linuxfirewiredevice.h"
     11#include "darwinfirewiredevice.h"
    1212#include "firewirechannel.h"
    1313
    14 class TVRec;
     14#define LOC QString("FireChan(%1): ").arg(GetDevice())
     15#define LOC_WARN QString("FireChan(%1), Warning: ").arg(GetDevice())
     16#define LOC_ERR QString("FireChan(%1), Error: ").arg(GetDevice())
    1517
    16 #define LOC QString("FireChan: ")
    17 #define LOC_ERR QString("FireChan, Error: ")
    18 
    19 #ifndef AVC1394_PANEL_COMMAND_PASS_THROUGH
    20 #define AVC1394_PANEL_COMMAND_PASS_THROUGH     0x000007C00
     18FirewireChannel::FirewireChannel(
     19    const FireWireDBOptions &firewire_opts, TVRec *parent) :
     20    DTVChannel(parent),
     21    fw_opts(firewire_opts),
     22    device(NULL),
     23    current_channel(0),
     24    is_port_open(false)
     25{
     26#ifdef USING_LINUX_FIREWIRE
     27    device = new LinuxFirewireDevice(
     28        fw_opts.port, fw_opts.node, fw_opts.speed,
     29        LinuxFirewireDevice::kConnectionP2P ==
     30        (uint) fw_opts.connection);
     31#elif USING_OSX_FIREWIRE
     32    device = new DarwinFirewireDevice();
    2133#endif
     34}
    2235
    23 #ifndef AVC1394_PANEL_OPERATION_0
    24 #define AVC1394_PANEL_OPERATION_0              0x000000020
    25 #endif
     36bool FirewireChannel::SetChannelByString(const QString &chan)
     37{
     38    inputs[currentInputID]->startChanNum = chan;
     39    curchannelname = chan;
    2640
    27 #define DCT6200_CMD0  (AVC1394_CTYPE_CONTROL | \
    28                        AVC1394_SUBUNIT_TYPE_PANEL | \
    29                        AVC1394_SUBUNIT_ID_0 | \
    30                        AVC1394_PANEL_COMMAND_PASS_THROUGH | \
    31                        AVC1394_PANEL_OPERATION_0)
     41    InputMap::const_iterator it = inputs.find(currentInputID);
    3242
    33 // SA3250HD defines
    34 #define AVC1394_SA3250_OPERAND_KEY_PRESS        0xE7
    35 #define AVC1394_SA3250_OPERAND_KEY_RELEASE      0x67
     43    if (!(*it)->externalChanger.isEmpty())
     44        return ChangeExternalChannel(chan);
    3645
    37 #define SA3250_CMD0   (AVC1394_CTYPE_CONTROL | \
    38                        AVC1394_SUBUNIT_TYPE_PANEL | \
    39                        AVC1394_SUBUNIT_ID_0 | \
    40                        AVC1394_PANEL_COMMAND_PASS_THROUGH)
    41 #define SA3250_CMD1   (0x04 << 24)
    42 #define SA3250_CMD2    0xff000000
     46    return isopen && SetChannelByNumber(chan.toInt());
     47}
    4348
    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)
     49bool FirewireChannel::Open(void)
     50{
     51    if (!InitializeInputs())
     52        return false;
    5153
    52 #define STB_POWER_ON      (AVC1394_CTYPE_CONTROL | \
    53                            AVC1394_SUBUNIT_TYPE_UNIT | \
    54                            AVC1394_SUBUNIT_ID_IGNORE | \
    55                            AVC1394_COMMAND_POWER | \
    56                            AVC1394_CMD_OPERAND_POWER_ON)
     54    InputMap::const_iterator it = inputs.find(currentInputID);
     55    if (!(*it)->externalChanger.isEmpty())
     56        return true;
    5757
    58 static bool is_supported(const QString &model)
    59 {
    60     return ((model == "DCT-6200") ||
    61             (model == "SA3250HD") ||
    62             (model == "SA4200HD"));
    63 }
     58    if (!isopen)
     59        isopen = OpenFirewire();
    6460
    65 FirewireChannel::FirewireChannel(FireWireDBOptions firewire_opts,
    66                                  TVRec *parent)
    67     : FirewireChannelBase(parent), fw_opts(firewire_opts), fwhandle(NULL)
    68 {
     61    return isopen;
    6962}
    7063
    71 FirewireChannel::~FirewireChannel(void)
     64void FirewireChannel::Close(void)
    7265{
    73     Close();
     66    if (isopen)
     67    {
     68        CloseFirewire();
     69        isopen = false;
     70    }
    7471}
    75 
    76 bool FirewireChannel::SetChannelByNumber(int channel)
     72   
     73bool FirewireChannel::OpenFirewire(void)
    7774{
    78     // Change channel using internal changer
     75    if (is_port_open)
     76        return true;
    7977
    80     if (!is_supported(fw_opts.model))
     78    if (!FirewireDevice::IsSTBSupported(fw_opts.model))
    8179    {
    8280        VERBOSE(VB_IMPORTANT, LOC_ERR +
    8381                QString("Model: '%1' ").arg(fw_opts.model) +
    8482                "is not supported by internal channel changer.");
     83
    8584        return false;
    8685    }
    8786
    88     int dig[3];
    89     dig[0] = (channel % 1000) / 100;
    90     dig[1] = (channel % 100)  / 10;
    91     dig[2] = (channel % 10);
     87    if (!device)
     88        return false;
    9289
    93     if (fw_opts.model == "DCT-6200")
    94     {
    95         VERBOSE(VB_CHANNEL, LOC +
    96                 QString("Channel1: %1%2%3 cmds: 0x%4, 0x%5, 0x%6")
    97                 .arg(dig[0]).arg(dig[1])
    98                 .arg(dig[2]).arg(DCT6200_CMD0 | dig[0], 0, 16)
    99                 .arg(DCT6200_CMD0 | dig[1], 0, 16)
    100                 .arg(DCT6200_CMD0 | dig[2], 0, 16));
     90    if (!device->OpenPort())
     91        return false;
    10192
    102         for (uint i = 0; i < 3 ;i++)
    103         {
    104             quadlet_t cmd[2] =  { DCT6200_CMD0 | dig[i], 0x0, };
    105             if (!avc1394_transaction_block(fwhandle, fw_opts.node, cmd, 2, 1))
    106             {
    107                  VERBOSE(VB_IMPORTANT, "AVC transaction failed.");
    108                  return false;
    109             }
    110             usleep(500000);
    111         }
    112     }
    113     else if (fw_opts.model == "SA3250HD")
     93    if (!device->IsSTB())
    11494    {
    115         dig[0] |= 0x30;
    116         dig[1] |= 0x30;
    117         dig[2] |= 0x30;
     95        device->ClosePort();
     96        return false;
     97    }
    11898
    119         quadlet_t cmd[3] =
    120         {
    121             SA3250_CMD0 | AVC1394_SA3250_OPERAND_KEY_PRESS,
    122             SA3250_CMD1 | (dig[2] << 16) | (dig[1] << 8) | dig[0],
    123             SA3250_CMD2,
    124         };
     99    is_port_open = true;
    125100
    126         VERBOSE(VB_CHANNEL, LOC +
    127                 QString("Channel2: %1%2%3 cmds: 0x%4, 0x%5, 0x%6")
    128                 .arg(dig[0] & 0xf).arg(dig[1] & 0xf)
    129                 .arg(dig[2] & 0xf)
    130                 .arg(cmd[0], 0, 16).arg(cmd[1], 0, 16)
    131                 .arg(cmd[2], 0, 16));
     101    return true;
     102}
    132103
    133         if(!avc1394_transaction_block(fwhandle, fw_opts.node, cmd, 3, 1))
    134         {
    135             VERBOSE(VB_IMPORTANT, "AVC transaction failed.");
    136             return false;
    137         }
     104void FirewireChannel::CloseFirewire(void)
     105{
     106    if (!is_port_open)
     107        return;
    138108
    139         cmd[0] = SA3250_CMD0 | AVC1394_SA3250_OPERAND_KEY_RELEASE;
    140         cmd[1] = SA3250_CMD1 | (dig[0] << 16) | (dig[1] << 8) | dig[2];
    141         cmd[2] = SA3250_CMD2;
     109    device->ClosePort();
     110    is_port_open = false;
     111}
    142112
    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));
     113bool FirewireChannel::SwitchToInput(const QString &input,
     114                                        const QString &chan)
     115{
     116    int inputNum = GetInputByName(input);
     117    if (inputNum < 0)
     118        return false;
    149119
    150         if (!avc1394_transaction_block(fwhandle, fw_opts.node, cmd, 3, 1))
    151         {
    152             VERBOSE(VB_IMPORTANT, "AVC transaction failed.");
    153             return false;
    154         }
    155     }
    156     else if (fw_opts.model == "SA4200HD")
    157     {
    158         quadlet_t cmd[3] =
    159         {
    160             SA3250_CMD0 | AVC1394_SA3250_OPERAND_KEY_PRESS,
    161             SA3250_CMD1 | (channel << 8),
    162             SA3250_CMD2,
    163         };
     120    return SetChannelByString(chan);
     121}
    164122
    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));
     123QString FirewireChannel::GetDevice(void) const
     124{
     125    return QString("%1:%2").arg(fw_opts.port).arg(fw_opts.node);
     126}
    170127
    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     }
     128bool FirewireChannel::SetPowerState(bool on)
     129{
     130    return device->SetPowerState(on);
     131}
    177132
    178     return true;
     133FirewireDevice::PowerState FirewireChannel::GetPowerState(void) const
     134{
     135    return device->GetPowerState();
    179136}
    180137
    181 bool FirewireChannel::OpenFirewire(void)
     138bool FirewireChannel::Retune(void)
    182139{
    183     if (!is_supported(fw_opts.model))
     140    VERBOSE(VB_CHANNEL, LOC + "Retune()");
     141
     142    if (FirewireDevice::kAVCPowerOff == GetPowerState())
    184143    {
    185144        VERBOSE(VB_IMPORTANT, LOC_ERR +
    186                 QString("Model: '%1' ").arg(fw_opts.model) +
    187                 "is not supported by internal channel changer.");
    188         return false;
    189     }
     145                "STB is turned off, must be on to retune.");
    190146
    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));
    197147        return false;
    198148    }
    199149
    200     VERBOSE(VB_CHANNEL, LOC + "Allocated raw1394 handle " +
    201             QString("for port %1").arg(fw_opts.port));
     150    if (current_channel)
     151        return SetChannelByNumber(current_channel);
    202152
    203     // verify node looks like a stb
    204     if (!avc1394_check_subunit_type(fwhandle, fw_opts.node,
    205                                     AVC1394_SUBUNIT_TYPE_TUNER))
    206     {
    207         VERBOSE(VB_IMPORTANT, LOC_ERR + QString("node %1 is not subunit "
    208                 "type tuner.").arg(fw_opts.node));
    209         CloseFirewire();
    210         return false;
    211     }
     153    return false;
     154}
    212155
    213     if (!avc1394_check_subunit_type(fwhandle, fw_opts.node,
    214                                     AVC1394_SUBUNIT_TYPE_PANEL))
    215     {
    216         VERBOSE(VB_IMPORTANT, LOC_ERR + QString("node %1 is not subunit "
    217                 "type panel.").arg(fw_opts.node));
    218         CloseFirewire();
    219         return false;
    220     }
     156bool FirewireChannel::SetChannelByNumber(int channel)
     157{
     158    current_channel = channel;
    221159
    222     // check power, power on if off
    223     if (GetPowerState() == Off)
     160    if (FirewireDevice::kAVCPowerOff == GetPowerState())
    224161    {
    225         quadlet_t *rval, response, cmd = STB_POWER_ON;
    226         VERBOSE(VB_IMPORTANT, LOC + QString("Powering on (cmd: 0x%1)")
    227                                             .arg(cmd, 0, 16));
    228         rval = avc1394_transaction_block(fwhandle, fw_opts.node, &cmd, 1, 1);
    229         if (rval)
    230         {
    231             response = rval[0];
     162        VERBOSE(VB_IMPORTANT, LOC_WARN +
     163                "STB is turned off, must be on to set channel.");
    232164
    233             if (AVC1394_MASK_RESPONSE(response) == AVC1394_RESPONSE_ACCEPTED)
    234             {
    235                 VERBOSE(VB_IMPORTANT, LOC + QString("Power on cmd successful "
    236                                                     "(0x%1)")
    237                                                     .arg(response, 0, 16));
    238                 // allow some time for the stb to power on
    239                 sleep(3);
    240                 if (GetPowerState() == Off)
    241                 {
    242                     VERBOSE(VB_IMPORTANT, LOC + "STB is still off!?");
    243                     return false;
    244                 }
    245                 return true;
    246             }
    247             else
    248             {
    249                 VERBOSE(VB_IMPORTANT, LOC + QString("Power on cmd failed "
    250                                                     "(0x%1)")
    251                                                     .arg(response, 0, 16));
    252                 return false;
    253             }
    254         }
    255         else
    256         {
    257             VERBOSE(VB_IMPORTANT, LOC + "Power on cmd failed (no response)");
    258             return false;
    259         }
     165        SetSIStandard("mpeg");
     166        SetCachedATSCInfo(QString("%1-1").arg(channel));
     167
     168        return true; // signal monitor will call retune later...
    260169    }
    261     return true;
    262 }
    263170
    264 void FirewireChannel::CloseFirewire(void)
    265 {
    266     VERBOSE(VB_CHANNEL, LOC + "Releasing raw1394 handle");
    267     raw1394_destroy_handle(fwhandle);
    268 }
     171    if (!device->SetChannel(fw_opts.model, channel))
     172        return false;
    269173
    270 FirewireChannel::PowerState FirewireChannel::GetPowerState(void)
    271 {
    272     quadlet_t *rval, response, cmd = STB_POWER_STATE;
     174    SetSIStandard("mpeg");
     175    SetCachedATSCInfo(QString("%1-1").arg(channel));
    273176
    274     VERBOSE(VB_CHANNEL, LOC + QString("Requesting STB Power State (cmd: 0x%1)")
    275                                       .arg(STB_POWER_STATE, 0, 16));
    276     rval = avc1394_transaction_block(fwhandle, fw_opts.node, &cmd, 1, 1);
    277 
    278     if (rval)
    279     {
    280         response = rval[0];
    281 
    282         if (AVC1394_MASK_RESPONSE(response) == AVC1394_RESPONSE_IMPLEMENTED)
    283         {
    284             if ((response & 0xFF) == AVC1394_CMD_OPERAND_POWER_ON)
    285             {
    286                 VERBOSE(VB_CHANNEL, LOC + QString("STB Power State: ON (0x%1)")
    287                                                   .arg(response, 0, 16));
    288                 return On;
    289             }
    290             else if ((response & 0xFF) == AVC1394_CMD_OPERAND_POWER_OFF)
    291             {
    292                 VERBOSE(VB_IMPORTANT, LOC + QString("STB Power State: OFF "
    293                                                     "(0x%1)")
    294                                                     .arg(response, 0, 16));
    295                 return Off;
    296             }
    297             else
    298             {
    299                 VERBOSE(VB_CHANNEL, LOC + QString("STB Power State: "
    300                                                   "Unknown Response (0x%1)")
    301                                                   .arg(response, 0, 16));
    302                 return Failed;
    303             }
    304         }
    305         else
    306         {
    307             VERBOSE(VB_CHANNEL, LOC + QString("STB Power State: Failed (0x%1)")
    308                                               .arg(response, 0, 16));
    309             return Failed;
    310         }
    311     }
    312     VERBOSE(VB_CHANNEL, LOC + "Failed to get STB Power State");
    313     return Failed;
     177    return true;
    314178}
  • libs/libmythtv/firewirerecorderbase.h

     
    1 /**
    2  *  FirewireRecorderBase
    3  *  Copyright (c) 2005 by Jim Westfall
    4  *  Distributed as part of MythTV under GPL v2 and later.
    5  */
    6 
    7 #ifndef FIREWIRERECORDERBASE_H_
    8 #define FIREWIRERECORDERBASE_H_
    9 
    10 #include "dtvrecorder.h"
    11 #include "tsstats.h"
    12 #include "tspacket.h"
    13 #include "streamlisteners.h"
    14 
    15 /** \class FirewireRecorderBase
    16  *  \brief This is a specialization of DTVRecorder used to
    17  *         handle DVB and ATSC streams from a firewire input.
    18  *
    19  *  \sa DTVRecorder
    20  */
    21 class FirewireRecorderBase : public DTVRecorder,
    22                              public MPEGSingleProgramStreamListener
    23 {
    24     friend class MPEGStreamData;
    25     friend class TSPacketProcessor;
    26 
    27   public:
    28     FirewireRecorderBase(TVRec *rec);
    29     ~FirewireRecorderBase();
    30  
    31     // Commands
    32     void StartRecording(void);
    33     void ProcessTSPacket(const TSPacket &tspacket);
    34     bool PauseAndWait(int timeout = 100);
    35 
    36     // Sets
    37     void SetOptionsFromProfile(RecordingProfile *profile,
    38                                const QString &videodev,
    39                                const QString &audiodev,
    40                                const QString &vbidev);
    41     void SetStreamData(MPEGStreamData*);
    42 
    43     // Gets
    44     MPEGStreamData* StreamData(void) { return _mpeg_stream_data; }
    45 
    46     // MPEG Single Program
    47     void HandleSingleProgramPAT(ProgramAssociationTable*);
    48     void HandleSingleProgramPMT(ProgramMapTable*);
    49 
    50   private:
    51     virtual void Close() = 0;
    52     virtual void start() = 0;
    53     virtual void stop() = 0;
    54     virtual bool grab_frames() = 0;
    55 
    56     MPEGStreamData  *_mpeg_stream_data;
    57     TSStats          _ts_stats;   
    58 
    59   protected:
    60     static const int  kTimeoutInSeconds;
    61 };
    62 
    63 #endif
  • libs/libmythtv/firewirechannelbase.h

     
    1 /**
    2  *  FirewireChannelBase
    3  *  Copyright (c) 2005 by Jim Westfall and Dave Abrahams
    4  *  Distributed as part of MythTV under GPL v2 and later.
    5  */
    6 
    7 
    8 #ifndef LIBMYTHTV_FIREWIRECHANNELBASE_H
    9 #define LIBMYTHTV_FIREWIRECHANNELBASE_H
    10 
    11 #include <qstring.h>
    12 #include "tv_rec.h"
    13 #include "channelbase.h"
    14 
    15 #include "mythconfig.h"
    16 
    17 namespace AVS
    18 {
    19   class AVCDeviceController;
    20   class AVCDevice;
    21 }
    22 
    23 class FirewireChannelBase : public ChannelBase
    24 {
    25   public:
    26     FirewireChannelBase(TVRec *parent)   
    27         : ChannelBase(parent), isopen(false) { }
    28     ~FirewireChannelBase() { Close(); }
    29 
    30     bool Open(void);
    31     void Close(void);
    32 
    33     // Sets
    34     bool SetChannelByString(const QString &chan);
    35     virtual bool SetChannelByNumber(int channel) = 0;
    36 
    37     // Gets
    38     bool IsOpen(void) const { return isopen; }
    39 
    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; }
    44 
    45   private:
    46     virtual bool OpenFirewire() = 0;
    47     virtual void CloseFirewire() = 0;
    48 
    49   protected:
    50     bool isopen;
    51 };
    52 
    53 #endif
  • libs/libmythtv/firewiredevice.cpp

     
     1/**
     2 *  FirewireDevice
     3 *  Copyright (c) 2005 by Jim Westfall
     4 *  Distributed as part of MythTV under GPL v2 and later.
     5 */
     6
     7// MythTV headers
     8#include "firewiredevice.h"
     9#include "mythcontext.h"
     10#include "pespacket.h"
     11
     12#define LOC      QString("FireDev(): ")
     13#define LOC_WARN QString("FireDev(), Warning: ")
     14#define LOC_ERR  QString("FireDev(), Error: ")
     15
     16FirewireDevice::FirewireDevice() :
     17    m_last_channel(0),      m_last_crc(0),
     18    m_buffer_cleared(true), m_open_port_cnt(0),
     19    m_lock(false)
     20{
     21}
     22
     23void FirewireDevice::AddListener(TSDataListener *listener)
     24{
     25    QMutexLocker locker(&m_lock);
     26
     27    if (listener)
     28    {
     29        vector<TSDataListener*>::iterator it =
     30            find(m_listeners.begin(), m_listeners.end(), listener);
     31
     32        if (it == m_listeners.end())
     33            m_listeners.push_back(listener);
     34    }
     35
     36    VERBOSE(VB_RECORD, LOC + "AddListener() "<<m_listeners.size());
     37}
     38
     39void FirewireDevice::RemoveListener(TSDataListener *listener)
     40{
     41    QMutexLocker locker(&m_lock);
     42
     43    vector<TSDataListener*>::iterator it = m_listeners.end();
     44
     45    do
     46    {
     47        it = find(m_listeners.begin(), m_listeners.end(), listener);
     48        if (it != m_listeners.end())
     49            m_listeners.erase(it);
     50    }
     51    while (it != m_listeners.end());
     52
     53    VERBOSE(VB_RECORD, LOC + "RemoveListener() "<<m_listeners.size());
     54}
     55
     56void FirewireDevice::SetLastChannel(const uint channel)
     57{
     58    m_buffer_cleared = (channel == m_last_channel);
     59    m_last_channel   = channel;
     60
     61    VERBOSE(VB_IMPORTANT, QString("SetLastChannel(%1): cleared: %2")
     62            .arg(channel).arg(m_buffer_cleared ? "yes" : "no"));
     63}
     64
     65void FirewireDevice::ProcessPATPacket(const TSPacket &tspacket)
     66{
     67    if (!tspacket.TransportError() && !tspacket.ScramplingControl() &&
     68        tspacket.HasPayload() && tspacket.PayloadStart() && !tspacket.PID())
     69    {
     70        PESPacket pes = PESPacket::View(tspacket);
     71        uint crc = pes.CalcCRC();
     72        m_buffer_cleared |= (crc != m_last_crc);
     73        m_last_crc = crc;
     74        VERBOSE(VB_RECORD, LOC +
     75                QString("ProcessPATPacket: CRC 0x%1 cleared: %2")
     76                .arg(crc,0,16).arg(m_buffer_cleared ? "yes" : "no"));
     77    }
     78    else
     79    {
     80        VERBOSE(VB_IMPORTANT, LOC_ERR + "Can't handle large PAT's");
     81    }
     82}
  • libs/libmythtv/libmythtv.pro

     
    377377    }
    378378
    379379    # Support for cable boxes that provide Firewire out
    380     using_firewire  {
    381         HEADERS += firewirechannelbase.h       firewirerecorderbase.h
    382         SOURCES += firewirechannelbase.cpp     firewirerecorderbase.cpp
     380    using_firewire {
     381        HEADERS += firewirechannel.h           firewirerecorder.h
     382        HEADERS += firewiresignalmonitor.h     firewiredevice.h
     383        SOURCES += firewirechannel.cpp         firewirerecorder.cpp
     384        SOURCES += firewiresignalmonitor.cpp   firewiredevice.cpp
    383385
    384386        macx {
    385             HEADERS += darwinfirewirechannel.h       darwinfirewirerecorder.h
    386             SOURCES += darwinfirewirechannel.cpp     darwinfirewirerecorder.cpp
    387             HEADERS += selectavcdevice.h
    388             SOURCES += selectavcdevice.cpp
     387            HEADERS += darwinfirewiredevice.h
     388            SOURCES += darwinfirewiredevice.cpp
     389            DEFINES += USING_OSX_FIREWIRE
    389390        }
    390391       
    391392        !macx {
    392             HEADERS += firewirechannel.h       firewirerecorder.h
    393             SOURCES += firewirechannel.cpp     firewirerecorder.cpp
     393            HEADERS += linuxfirewiredevice.h
     394            SOURCES += linuxfirewiredevice.cpp
     395            DEFINES += USING_LINUX_FIREWIRE
    394396        }
    395397
    396398        DEFINES += USING_FIREWIRE
  • libs/libmythtv/darwinfirewirerecorder.cpp

     
    1 /**
    2  *  DarwinDarwinFirewireRecorder
    3  *  Copyright (c) 2005 by Jim Westfall and Dave Abrahams
    4  *  Distributed as part of MythTV under GPL v2 and later.
    5  */
    6 
    7 // MythTV includes
    8 #include "darwinfirewirerecorder.h"
    9 #include "tspacket.h"
    10 
    11 #undef always_inline
    12 #include <AVCVideoServices/AVCVideoServices.h>
    13 
    14 DarwinFirewireRecorder::DarwinFirewireRecorder(TVRec *rec, ChannelBase* tuner)
    15  : FirewireRecorderBase(rec),
    16    capture_device(
    17        dynamic_cast<DarwinFirewireChannel*>(tuner)->GetAVCDevice()
    18    ),
    19    message_log(NULL),
    20    video_stream(NULL),
    21    isopen(false)
    22 {;}
    23 
    24 DarwinFirewireRecorder::~DarwinFirewireRecorder()
    25 {
    26     this->Close();
    27 }
    28 
    29 // Various message callbacks.
    30 IOReturn DarwinFirewireRecorder::MPEGNoData(void *pRefCon)
    31 {
    32    
    33     DarwinFirewireRecorder* self = static_cast<DarwinFirewireRecorder*>(pRefCon);
    34     self->no_data();
    35     return 0;
    36 }
    37 
    38 void DarwinFirewireRecorder::no_data()
    39 {
    40     VERBOSE(
    41         VB_IMPORTANT,
    42         QString("Firewire: No Input in %1 seconds").arg(kTimeoutInSeconds));
    43 }
    44 
    45 namespace
    46 {
    47   void avs_log_message(char *pString)
    48   {
    49       // I don't know what QString does with plain char*, but surely it
    50       // treats char const* as an NTBS.
    51       char const* s = pString;
    52 
    53       VERBOSE(VB_GENERAL,QString("Firewire MPEG2Receiver log: %1")
    54               .arg(s));
    55   }
    56 
    57   void avs_message_received(
    58       UInt32 msg, UInt32 param1, UInt32 param2, void *pRefCon)
    59   {
    60       (void)pRefCon;
    61 
    62       VERBOSE(VB_RECORD,QString("Firewire MPEG2Receiver message: %1")
    63               .arg(msg));
    64 
    65       switch (msg)
    66       {
    67       case AVS::kMpeg2ReceiverAllocateIsochPort:
    68           VERBOSE(
    69               VB_RECORD,
    70               QString("Firewire MPEG2Receiver allocated channel: %1, speed %2")
    71                   .arg(param2).arg(param1)
    72           );
    73           break;
    74 
    75       case AVS::kMpeg2ReceiverDCLOverrun:
    76           VERBOSE(
    77               VB_IMPORTANT,
    78               QString("Firewire MPEG2Receiver DCL Overrun")
    79           );
    80           break;
    81 
    82       case AVS::kMpeg2ReceiverReceivedBadPacket:
    83           VERBOSE(
    84               VB_IMPORTANT,
    85               QString("Firewire MPEG2Receiver Received Bad Packet ")
    86           );
    87           break;
    88 
    89       default:
    90           break;
    91       }
    92   }
    93 
    94   bool find_capture_device(AVS::AVCDevice* d)
    95   {
    96       // We'd check isMPEGDevice, but it turns out that for the
    97       // DCT-6200, Apple doesn't set that flag.  So instead we rule
    98       // out DV devices.
    99       // A more general OSX AVCRecorder class that also handles DV
    100       // devices might not check either flag.
    101       return d->isAttached && !d->isDVDevice
    102 //          && (d->hasTapeSubunit || d->hasMonitorOrTunerSubunit)
    103           ;
    104   }
    105 
    106   IOReturn device_controller_notification(AVS::AVCDeviceController *, void *, AVS::AVCDevice*)
    107   {
    108       return 0;
    109   }     
    110 }
    111 
    112 IOReturn DarwinFirewireRecorder::tspacket_callback(UInt32 tsPacketCount, UInt32 **ppBuf,void *pRefCon)
    113 {
    114     DarwinFirewireRecorder* self = static_cast<DarwinFirewireRecorder*>(pRefCon);
    115     if (!self)
    116         return kIOReturnBadArgument;
    117 
    118     for (UInt32 i = 0; i < tsPacketCount; ++i)
    119         self->ProcessTSPacket(*(reinterpret_cast<TSPacket*>(ppBuf[i])));
    120 
    121     return 0;
    122 }
    123 
    124 
    125 bool DarwinFirewireRecorder::Open()
    126 {
    127      if (isopen)
    128          return true;
    129    
    130      VERBOSE(VB_GENERAL,QString("Firewire: Creating logger object"));
    131 
    132      this->message_log = new AVS::StringLogger(avs_log_message);
    133      if (!this->message_log)
    134      {
    135          VERBOSE(VB_IMPORTANT, QString("Firewire: Couldn't create logger") );
    136          return false;
    137      }
    138 
    139      // If we don't set this immediately, Close() will refuse to clean
    140      // up after whatever mess we make here
    141      this->isopen = true;
    142 
    143      VERBOSE(VB_GENERAL,QString("Firewire: Creating MPEG-2 device stream"));
    144      
    145      // This not only builds an MPEG2Receiver object but also starts dedicated real-time threads.
    146      this->video_stream = capture_device->CreateMPEGReceiverForDevicePlug(
    147          0,                // Plug number.  Why is zero always OK?  I
    148                            // don't know, but that's what Apple's
    149                            // examples do.
    150          tspacket_callback,
    151          this,
    152          avs_message_received,
    153          this,
    154          this->message_log,
    155          AVS::kCyclesPerReceiveSegment,
    156          // Why multiply by 2 instead of using the default,
    157          // kNumReceiveSegments?  Because it's what Apple's only
    158          // example of the use of this function does.
    159          AVS::kNumReceiveSegments*2);
    160          
    161      if (!this->video_stream)
    162      {
    163          VERBOSE(VB_IMPORTANT, QString("Firewire: Couldn't create MPEG-2 device stream") );
    164          this->Close();
    165          return false;
    166      }
    167 
    168         // We could set the channel to receive on, but it doesn't seem
    169         // like we need to, and if the device is already transmitting it
    170         // could lead to inefficiency because the device stream is smart
    171         // enough to avoid allocating new bandwidth.
    172 
    173         // Register a no-data notification callback
    174         video_stream->pMPEGReceiver->registerNoDataNotificationCallback(
    175         MPEGNoData, this, kTimeoutInSeconds * 1000);
    176 
    177      return true;
    178 }
    179 
    180 void DarwinFirewireRecorder::Close()
    181 {
    182     if (!isopen)
    183         return;
    184    
    185     isopen = false;
    186 
    187     if (this->video_stream)
    188     {
    189         this->stop();
    190         VERBOSE(VB_RECORD, "Firewire: Destroying device stream");
    191         this->capture_device->DestroyAVCDeviceStream(this->video_stream);
    192         this->video_stream = 0;
    193     }
    194 
    195     delete this->message_log;
    196     this->message_log = 0;
    197 }
    198 
    199 void DarwinFirewireRecorder::start()
    200 {
    201     VERBOSE(VB_RECORD, "Firewire: Starting video stream");
    202     this->capture_device->StartAVCDeviceStream(this->video_stream);
    203 }
    204 
    205 void DarwinFirewireRecorder::stop()
    206 {
    207     VERBOSE(VB_RECORD, "Firewire: Stopping video stream");
    208     this->capture_device->StopAVCDeviceStream(this->video_stream);
    209 }
    210 
    211 bool DarwinFirewireRecorder::grab_frames()
    212 {
    213     usleep(1000000 / 2);  // 2 times a 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/dbcheck.cpp

     
    1010#include "mythdbcon.h"
    1111
    1212/// This is the DB schema version expected by the running MythTV instance.
    13 const QString currentDatabaseVersion = "1172";
     13const QString currentDatabaseVersion = "1173";
    1414
    1515static bool UpdateDBVersionNumber(const QString &newnumber);
    1616static bool performActualUpdate(const QString updates[], QString version,
     
    27722772            return false;
    27732773    }
    27742774
     2775    if (dbver == "1172")
     2776    {
     2777        // Add Firewire and DBox2 default recording profiles..
     2778        const QString updates[] = {
     2779"UPDATE capturecard SET channel_timeout = 9000 WHERE cardtype = 'FIREWIRE';",
     2780""
     2781};
     2782        if (!performActualUpdate(updates, "1173", dbver))
     2783            return false;
     2784    }
     2785
    27752786//"ALTER TABLE cardinput DROP COLUMN preference;" in 0.22
    27762787//"ALTER TABLE channel DROP COLUMN atscsrcid;" in 0.22
    27772788//"ALTER TABLE recordedmarkup DROP COLUMN offset;" in 0.22
  • 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/darwinfirewiredevice.cpp

     
     1/**
     2 *  DarwinFirewireChannel
     3 *  Copyright (c) 2005 by Jim Westfall
     4 *  SA3250HD support Copyright (c) 2005 by Matt Porter
     5 *  Copyright (c) 2006 by Dave Abrahams
     6 *  Distributed as part of MythTV under GPL v2 and later.
     7 */
     8
     9#undef always_inline
     10#include <AVCVideoServices/AVCVideoServices.h>
     11
     12#include "darwinfirewiredevice.h"
     13#include "mythcontext.h"
     14
     15#define LOC      QString("DFireDev(): ")
     16#define LOC_WARN QString("DFireDev(), Warning: ")
     17#define LOC_ERR  QString("DFireDev(), Error: ")
     18
     19namespace AVS
     20{
     21    class AVCDeviceController;
     22    class AVCDevice;
     23    class AVCDeviceStream;
     24    class StringLogger;
     25}
     26
     27static bool dfd_find_panel_device(AVS::AVCDevice *d);
     28static bool dfd_find_capture_device(AVS::AVCDevice *d);
     29static AVS::AVCDevice *dfd_select_device(AVS::AVCDeviceController*,
     30                                         bool (*)(AVS::AVCDevice*));
     31
     32static void dfd_log_message(char *pString);
     33static void dfd_err_message(uint32_t msg, uint32_t param1,
     34                            uint32_t param2, void *callback_data);
     35
     36class DFDPriv
     37{
     38  public:
     39    DFDPriv() :
     40        avc_device_controller(NULL), avc_device(NULL),
     41        avstream(NULL), message_log(NULL), is_streaming(false) { }
     42
     43    AVS::AVCDeviceController *avc_device_controller;
     44    AVS::AVCDevice           *avc_device;
     45    AVS::AVCDeviceStream     *avstream;
     46    AVS::StringLogger        *message_log;
     47    bool                      is_streaming;
     48};
     49
     50DarwinFirewireDevice::DarwinFirewireDevice() : m_priv(new DFDPriv())
     51{
     52}
     53
     54DarwinFirewireDevice::~DarwinFirewireDevice()
     55{
     56    if (IsPortOpen())
     57    {
     58        VERBOSE(VB_IMPORTANT, LOC_ERR + "ctor called with open port");
     59        while (IsPortOpen())
     60            ClosePort();
     61    }
     62
     63    if (m_priv)
     64    {
     65        delete m_priv;
     66        m_priv = NULL;
     67    }
     68}
     69
     70bool DarwinFirewireDevice::OpenPort(void)
     71{
     72    QMutexLocker locker(&m_lock);
     73
     74    VERBOSE(VB_RECORD, LOC + "OpenPort()");
     75
     76    m_open_port_cnt++;
     77
     78    if (m_priv->avc_device)
     79        return true;
     80
     81    int err = AVS::CreateAVCDeviceController(&m_priv->avc_device_controller);
     82    if (err)
     83    {
     84        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to open device controller: " +
     85                QString("%1").arg(err,0,16));
     86
     87        return false;
     88    }
     89
     90    VERBOSE(VB_RECORD, LOC + "Opening AVC Device");
     91
     92    m_priv->avc_device = dfd_select_device(
     93        m_priv->avc_device_controller, dfd_find_panel_device);
     94
     95    if (!m_priv->avc_device)
     96    {
     97        VERBOSE(VB_IMPORTANT, LOC_ERR +
     98                "Unable to find an attached "
     99                "MPEG2 device that supports channel changes");
     100
     101        AVS::DestroyAVCDeviceController(m_priv->avc_device_controller);
     102        m_priv->avc_device_controller = NULL;
     103
     104        return false;
     105    }
     106
     107    err = m_priv->avc_device->openDevice();
     108
     109    if (err)
     110    {
     111        VERBOSE(VB_IMPORTANT, LOC_ERR +
     112                QString("Couldn't open tuner device: %1").arg(err,0,16));
     113
     114        AVS::DestroyAVCDeviceController(m_priv->avc_device_controller);
     115        m_priv->avc_device_controller = NULL;
     116
     117        return false;
     118    }
     119
     120    return true;
     121}
     122
     123bool DarwinFirewireDevice::ClosePort(void)
     124{
     125    QMutexLocker locker(&m_lock);
     126
     127    VERBOSE(VB_RECORD, LOC + "ClosePort()");
     128
     129    if (m_open_port_cnt < 1)
     130        return false;
     131
     132    m_open_port_cnt--;
     133
     134    if (m_open_port_cnt != 0)
     135        return true;
     136
     137    if (m_priv->avc_device)
     138    {
     139        VERBOSE(VB_RECORD, LOC + "Closing AVC Device");
     140
     141        m_priv->avc_device->closeDevice();
     142
     143        //AVS::DestroyAVCDevice(m_priv->avc_device);
     144        m_priv->avc_device = NULL;
     145    }
     146
     147    return true;
     148}
     149
     150bool DarwinFirewireDevice::OpenAVStream(void)
     151{
     152    VERBOSE(VB_RECORD, LOC + "Creating logger object");
     153
     154    m_priv->message_log = new AVS::StringLogger(dfd_log_message);
     155    if (!m_priv->message_log)
     156    {
     157        VERBOSE(VB_IMPORTANT, LOC_ERR + "Couldn't create logger");
     158        return false;
     159    }
     160
     161    // Plug number.  Why is zero always OK?  I don't know, but that's
     162    // what Apple's examples do.
     163    uint plug_num = 0;
     164
     165    // Why multiply by 2 instead of using the default,
     166    // kNumReceiveSegments?  Because it's what Apple's only
     167    // example of the use of this function does.
     168    uint recv_segments = 2 * AVS::kNumReceiveSegments;
     169
     170    // This not only builds an MPEG2Receiver object
     171    // but also starts dedicated real-time threads.
     172    m_priv->avstream = m_priv->avc_device->CreateMPEGReceiverForDevicePlug(
     173        plug_num, dfd_tspacket_handler, this, dfd_err_message, this,
     174        m_priv->message_log, AVS::kCyclesPerReceiveSegment, recv_segments);
     175
     176    if (!m_priv->avstream)
     177    {
     178        VERBOSE(VB_IMPORTANT, LOC_ERR +
     179                "Couldn't create MPEG-2 device stream");
     180
     181        CloseAVStream();
     182
     183        return false;
     184    }
     185
     186    // We could set the channel to receive on, but it doesn't seem
     187    // like we need to, and if the device is already transmitting it
     188    // could lead to inefficiency because the device stream is smart
     189    // enough to avoid allocating new bandwidth.
     190
     191    // Register a no-data notification callback
     192    m_priv->avstream->pMPEGReceiver->registerNoDataNotificationCallback(
     193        dfd_no_data_notification, this, 50 /* msec */);
     194
     195    return true;
     196}
     197
     198bool DarwinFirewireDevice::CloseAVStream(void)
     199{
     200    if (m_priv->avstream)
     201    {
     202        StopStreaming();
     203        VERBOSE(VB_RECORD, LOC + "Destroying device stream");
     204        m_priv->avc_device->DestroyAVCDeviceStream(m_priv->avstream);
     205        m_priv->avstream = NULL;
     206    }
     207
     208    if (m_priv->message_log)
     209    {
     210        delete m_priv->message_log;
     211        m_priv->message_log = NULL;
     212    }
     213
     214    return true;
     215}
     216
     217bool DarwinFirewireDevice::StartStreaming(void)
     218{
     219    if (m_priv->is_streaming)
     220        return m_priv->is_streaming;
     221
     222    VERBOSE(VB_RECORD, LOC + "Starting A/V streaming");
     223
     224    if (!m_priv->avstream)
     225    {
     226        VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting A/V streaming, no A/V obj");
     227        return false;
     228    }
     229
     230    m_priv->avc_device->StartAVCDeviceStream(m_priv->avstream);
     231    m_priv->is_streaming = true;
     232
     233    return m_priv->is_streaming;
     234}
     235
     236bool DarwinFirewireDevice::StopStreaming(void)
     237{
     238    VERBOSE(VB_RECORD, LOC + "Stopping A/V streaming");
     239
     240    if (m_priv->is_streaming)
     241    {
     242        m_priv->is_streaming = false;
     243        m_priv->avc_device->StopAVCDeviceStream(m_priv->avstream);
     244    }
     245
     246    VERBOSE(VB_RECORD, LOC + "Stopped A/V streaming");
     247
     248    return true;
     249}
     250
     251bool DarwinFirewireDevice::SetChannel(const QString &panel_model, uint channel)
     252{
     253    QMutexLocker locker(&m_lock);
     254
     255    (void) panel_model;
     256
     257    AVS::PanelSubunitController panel(m_priv->avc_device);
     258
     259    int err = panel.Tune(channel);
     260    if (err != kIOReturnSuccess)
     261    {
     262        VERBOSE(VB_GENERAL, LOC_ERR + "Tuning failed: " +
     263                QString("0x%1").arg(err,0,16));
     264
     265        return false;
     266    }
     267
     268    return true;
     269}
     270
     271bool DarwinFirewireDevice::SetPowerState(bool on)
     272{
     273    QMutexLocker locker(&m_lock);
     274
     275    if (on)
     276        m_priv->avc_device->SetPowerState(kAVCPowerStateOn);
     277    else
     278        m_priv->avc_device->SetPowerState(kAVCPowerStateOff);
     279
     280    return true;
     281}
     282
     283FirewireDevice::PowerState DarwinFirewireDevice::GetPowerState(void)
     284{
     285    QMutexLocker locker(&m_lock);
     286
     287    uint8_t power_state;
     288
     289    int err = m_priv->avc_device->GetPowerState(&power_state);
     290
     291    if (err != kIOReturnSuccess)
     292        return FirewireDevice::kAVCPowerQueryFailed;
     293    else if (kAVCPowerStateOff == power_state)
     294        return FirewireDevice::kAVCPowerOff;
     295    else if (kAVCPowerStateOn == power_state)
     296        return FirewireDevice::kAVCPowerOn;
     297    else
     298        return FirewireDevice::kAVCPowerUnknown;
     299}
     300
     301bool DarwinFirewireDevice::IsPortOpen(void) const
     302{
     303    QMutexLocker locker(&m_lock);
     304
     305    return m_priv->avc_device;
     306}
     307
     308bool DarwinFirewireDevice::IsTuner(void) const
     309{
     310    return IsPortOpen();
     311}
     312
     313bool DarwinFirewireDevice::IsPanel(void) const
     314{
     315    return IsPortOpen();
     316}
     317
     318bool DarwinFirewireDevice::IsSTB(void) const
     319{
     320    return IsPortOpen();
     321}
     322
     323void DarwinFirewireDevice::AddListener(TSDataListener *listener)
     324{
     325    FirewireDevice::AddListener(listener);
     326
     327    QMutexLocker locker(&m_lock);
     328    if (!m_listeners.empty())
     329        StartStreaming();
     330}
     331
     332void DarwinFirewireDevice::RemoveListener(TSDataListener *listener)
     333{
     334    FirewireDevice::RemoveListener(listener);
     335
     336    QMutexLocker locker(&m_lock);
     337    if (m_priv->is_streaming && m_listeners.empty())
     338    {
     339        StopStreaming();
     340        CloseAVStream();
     341    }
     342}
     343
     344void DarwinFirewireDevice::BroadcastToListeners(
     345    const unsigned char *data, uint dataSize)
     346{
     347    QMutexLocker locker(&m_lock);
     348
     349    if ((dataSize >= TSPacket::SIZE) && (data[0] == SYNC_BYTE) &&
     350        ((data[1] & 0x1f) == 0) && (data[2] == 0))
     351    {
     352        ProcessPATPacket(*((const TSPacket*)data));
     353    }
     354
     355    vector<TSDataListener*>::iterator it = m_listeners.begin();
     356    for (; it != m_listeners.end(); ++it)
     357        (*it)->AddData(data, dataSize);
     358}
     359
     360void DarwinFirewireDevice::no_data(void)
     361{
     362    VERBOSE(VB_IMPORTANT, LOC_WARN + "No Input in 50 msecs");
     363}
     364
     365// Various message callbacks.
     366int dfd_no_data_notification(void *callback_data)
     367{
     368    DarwinFirewireDevice *fw =
     369        static_cast<DarwinFirewireDevice*>(callback_data);
     370
     371    fw->no_data();
     372
     373    return 0;
     374}
     375
     376int dfd_tspacket_handler(uint32_t tsPacketCount, uint32_t **ppBuf,
     377                         void *callback_data)
     378{
     379    DarwinFirewireDevice *fw = (DarwinFirewireDevice*) callback_data;
     380    if (!fw)
     381        return kIOReturnBadArgument;
     382
     383    for (uint32_t i = 0; i < tsPacketCount; ++i)
     384        fw->BroadcastToListeners((const unsigned char*) ppBuf[i], 1);
     385
     386    return 0;
     387}
     388
     389// For the time being, the DarwinFireWireRecorder doesn't
     390// handle DV devices, so there's no point in finding one we
     391// can tune to here.  That saves us from having to search
     392// twice for an eligible device.
     393static bool dfd_find_panel_device(AVS::AVCDevice *d)
     394{
     395    return d->isAttached && d->hasMonitorOrTunerSubunit && !d->isDVDevice;
     396}
     397
     398// We'd check isMPEGDevice, but it turns out that for the
     399// DCT-6200, Apple doesn't set that flag.  So instead we rule
     400// out DV devices.
     401// A more general OSX AVCRecorder class that also handles DV
     402// devices might not check either flag.
     403static bool dfd_find_capture_device(AVS::AVCDevice *d)
     404{
     405    return d->isAttached && !d->isDVDevice;
     406}
     407
     408// TODO This needs to be worked on so that we can handle multiple STBs.
     409static AVS::AVCDevice *dfd_select_device(AVS::AVCDeviceController *controller,
     410                                         bool (*filter)(AVS::AVCDevice*))
     411{
     412    VERBOSE(VB_RECORD, "dfd_select_device()");
     413
     414    uint cnt = CFArrayGetCount(controller->avcDeviceArray);
     415    for (uint i = 0; i < cnt; i++)
     416    {
     417        AVS::AVCDevice *dev = (AVS::AVCDevice*)
     418            CFArrayGetValueAtIndex(controller->avcDeviceArray, i);
     419
     420        VERBOSE(VB_RECORD,
     421                QString("dfd_select_device: "
     422                        "%1, format: %2, attached: %3, type: %4")
     423                .arg(dev->deviceName)
     424                .arg(dev->isDVDevice ? "DV" :
     425                     dev->isMPEGDevice ? "MPEG2-TS" : "unknown")
     426                .arg(dev->isAttached ? "yes" : "no")
     427                .arg(dev->hasTapeSubunit ? "tape" :
     428                     dev->hasMonitorOrTunerSubunit ? "tuner" : "unknown"));
     429
     430        if (filter(dev))
     431        {
     432            VERBOSE(VB_RECORD, "dfd_select_device: FOUND");
     433            return dev;
     434        }
     435    }
     436
     437    VERBOSE(VB_RECORD, "dfd_select_device: NOT FOUND");
     438
     439    return 0;
     440}
     441
     442#define AVC_MSG_LOC     QString("Firewire MPEG2Receiver: ")
     443#define AVC_MSG_LOC_ERR QString("Firewire MPEG2Receiver, Error: ")
     444static void dfd_log_message(char *pString)
     445{
     446    VERBOSE(VB_RECORD, AVC_MSG_LOC + QString("Log: %1").arg(pString));
     447}
     448
     449static void dfd_err_message(
     450    uint32_t msg, uint32_t param1, uint32_t param2, void *callback_data)
     451{
     452    (void) callback_data;
     453
     454    if (AVS::kMpeg2ReceiverAllocateIsochPort == msg)
     455    {
     456        VERBOSE(VB_RECORD, AVC_MSG_LOC +
     457                QString("Allocated channel: %1, speed %2")
     458                .arg(param2).arg(param1));
     459    }
     460    else if (AVS::kMpeg2ReceiverDCLOverrun == msg)
     461        VERBOSE(VB_IMPORTANT, AVC_MSG_LOC_ERR + "DCL Overrun");
     462    else if (AVS::kMpeg2ReceiverReceivedBadPacket == msg)
     463        VERBOSE(VB_IMPORTANT, AVC_MSG_LOC_ERR + "Received Bad Packet");
     464    else
     465        VERBOSE(VB_RECORD, AVC_MSG_LOC + QString("Message: %1").arg(msg));
     466}
     467#undef AVC_MSG_LOC
     468#undef AVC_MSG_LOC_ERR
  • libs/libmythtv/firewirerecorderbase.cpp

     
    1 /**
    2  *  FirewireRecorder
    3  *  Copyright (c) 2005 by Jim Westfall and Dave Abrahams
    4  *  Distributed as part of MythTV under GPL v2 and later.
    5  */
    6 
    7 // MythTV includes
    8 #include "firewirerecorderbase.h"
    9 #include "mythcontext.h"
    10 #include "mpegtables.h"
    11 #include "mpegstreamdata.h"
    12 #include "tv_rec.h"
    13 
    14 #define LOC QString("FireRecBase: ")
    15 #define LOC_ERR QString("FireRecBase, Error: ")
    16 
    17 const int FirewireRecorderBase::kTimeoutInSeconds = 15;
    18 
    19 FirewireRecorderBase::FirewireRecorderBase(TVRec *rec)
    20     : DTVRecorder(rec), _mpeg_stream_data(NULL)
    21 {
    22     SetStreamData(new MPEGStreamData(1, true));
    23 }
    24 
    25 FirewireRecorderBase::~FirewireRecorderBase()
    26 {
    27     SetStreamData(NULL);
    28 }
    29 
    30 void FirewireRecorderBase::StartRecording(void) {
    31  
    32     VERBOSE(VB_RECORD, LOC + "StartRecording");
    33 
    34     if (!Open()) {
    35         _error = true;       
    36         return;
    37     }
    38 
    39     _request_recording = true;
    40     _recording = true;
    41    
    42     start();
    43 
    44     while(_request_recording) {
    45        if (PauseAndWait())
    46            continue;
    47 
    48        if (!grab_frames())
    49        {
    50            _error = true;
    51            return;
    52        }
    53     }       
    54    
    55     stop();
    56     FinishRecording();
    57 
    58     _recording = false;
    59 
    60 
    61 void FirewireRecorderBase::ProcessTSPacket(const TSPacket &tspacket)
    62 {
    63     if (tspacket.TransportError())
    64         return;
    65  
    66     if (tspacket.ScramplingControl())
    67         return;
    68  
    69     if (tspacket.HasAdaptationField())
    70         StreamData()->HandleAdaptationFieldControl(&tspacket);
    71  
    72     if (tspacket.HasPayload())
    73     {
    74         const unsigned int lpid = tspacket.PID();
    75  
    76         // Pass or reject packets based on PID, and parse info from them
    77         if (lpid == StreamData()->VideoPIDSingleProgram())
    78         {
    79             _buffer_packets = !FindMPEG2Keyframes(&tspacket);
    80             BufferedWrite(tspacket);
    81         }
    82         else if (StreamData()->IsAudioPID(lpid))
    83             BufferedWrite(tspacket);
    84         else if (StreamData()->IsListeningPID(lpid))
    85             StreamData()->HandleTSTables(&tspacket);
    86         else if (StreamData()->IsWritingPID(lpid))
    87             BufferedWrite(tspacket);
    88     }
    89  
    90     _ts_stats.IncrTSPacketCount();
    91     if (0 == _ts_stats.TSPacketCount()%1000000)
    92         VERBOSE(VB_RECORD, _ts_stats.toString());
    93 }
    94 
    95 void FirewireRecorderBase::SetOptionsFromProfile(RecordingProfile *profile,
    96                                              const QString &videodev,
    97                                              const QString &audiodev,
    98                                              const QString &vbidev)
    99 {
    100     (void)videodev;
    101     (void)audiodev;
    102     (void)vbidev;
    103     (void)profile;
    104 }
    105 
    106 // documented in recorderbase.cpp
    107 bool FirewireRecorderBase::PauseAndWait(int timeout)
    108 {
    109     if (request_pause)
    110     {
    111         if (!paused)
    112         {
    113             stop();
    114             paused = true;
    115             pauseWait.wakeAll();
    116             if (tvrec)
    117                 tvrec->RecorderPaused();
    118         }
    119         unpauseWait.wait(timeout);
    120     }
    121     if (!request_pause && paused)
    122     {
    123         start();
    124         paused = false;
    125     }
    126     return paused;
    127 }
    128 
    129 void FirewireRecorderBase::SetStreamData(MPEGStreamData *data)
    130 {
    131     if (data == _mpeg_stream_data)
    132         return;
    133 
    134     MPEGStreamData *old_data = _mpeg_stream_data;
    135     _mpeg_stream_data = data;
    136 
    137     if (data)
    138         data->AddMPEGSPListener(this);
    139 
    140     if (old_data)
    141         delete old_data;
    142 }
    143 
    144 void FirewireRecorderBase::HandleSingleProgramPAT(
    145     ProgramAssociationTable *pat)
    146 {
    147     if (!pat)
    148         return;
    149  
    150     int next = (pat->tsheader()->ContinuityCounter()+1)&0xf;
    151     pat->tsheader()->SetContinuityCounter(next);
    152     BufferedWrite(*(reinterpret_cast<const TSPacket*>(pat->tsheader())));
    153 }
    154  
    155 void FirewireRecorderBase::HandleSingleProgramPMT(ProgramMapTable *pmt)
    156 {
    157     if (!pmt)
    158         return;
    159  
    160     int next = (pmt->tsheader()->ContinuityCounter()+1)&0xf;
    161     pmt->tsheader()->SetContinuityCounter(next);
    162     BufferedWrite(*(reinterpret_cast<const TSPacket*>(pmt->tsheader())));
    163 }
  • libs/libmythtv/firewirerecorder.cpp

     
    11/**
    22 *  FirewireRecorder
    3  *  Copyright (c) 2005 by Jim Westfall
     3 *  Copyright (c) 2005 by Jim Westfall and Dave Abrahams
    44 *  Distributed as part of MythTV under GPL v2 and later.
    55 */
    66
    7 // C includes
    8 #include <pthread.h>
    9 #include <sys/select.h>
    10 
    11 // C++ includes
    12 #include <iostream>
    13 using namespace std;
    14 
    157// MythTV includes
    168#include "firewirerecorder.h"
     9#include "firewirechannel.h"
    1710#include "mythcontext.h"
    1811#include "mpegtables.h"
    1912#include "mpegstreamdata.h"
    2013#include "tv_rec.h"
    2114
    22 #define LOC QString("FireRec: ")
    23 #define LOC_ERR QString("FireRec, Error: ")
     15#define LOC QString("FireRecBase: ")
     16#define LOC_ERR QString("FireRecBase, Error: ")
    2417
    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)
     18FirewireRecorder::FirewireRecorder(TVRec *rec, FirewireChannel *chan) :
     19    DTVRecorder(rec), _mpeg_stream_data(NULL),
     20    channel(chan), isopen(false)
    3321{
    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;
    5122}
    5223
    53 static QString speed_to_string(uint speed)
     24FirewireRecorder::~FirewireRecorder()
    5425{
    55     if (speed > RAW1394_ISO_SPEED_400)
    56         return QString("Invalid Speed (%1)").arg(speed);
    57 
    58     static const uint speeds[] = { 100, 200, 400, };
    59     return QString("%1Mbps").arg(speeds[speed]);
     26    SetStreamData(NULL);
     27    Close();
    6028}
    6129
    6230bool FirewireRecorder::Open(void)
    6331{
    64      if (isopen)
    65          return true;
     32    if (!isopen)
     33        isopen = channel->GetFirewireDevice()->OpenPort();
    6634
    67      VERBOSE(VB_RECORD, LOC +
    68              QString("Initializing Port: %1, Node: %2, Speed: %3")
    69              .arg(fwport).arg(fwnode).arg(speed_to_string(fwspeed)));
     35    return isopen;
     36}
    7037
    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      }
     38void FirewireRecorder::Close(void)
     39{
     40    if (isopen)
     41    {
     42        channel->GetFirewireDevice()->ClosePort();
     43        isopen = false;
     44    }
     45}
    7846
    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;
     47void FirewireRecorder::StartStreaming(void)
     48{
     49    channel->GetFirewireDevice()->AddListener(this);
     50}
    9851
    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      }
     52void FirewireRecorder::StopStreaming(void)
     53{
     54    channel->GetFirewireDevice()->RemoveListener(this);
     55}
    11456
    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);
     57void FirewireRecorder::StartRecording(void)
     58{
     59    VERBOSE(VB_RECORD, LOC + "StartRecording");
    12060
    121          // release raw1394 object;
    122          raw1394_destroy_handle(fwhandle);
    123          return false;
    124      }
     61    if (!Open())
     62    {
     63        _error = true;
     64        return;
     65    }
    12566
    126      // Set buffered packets size
    127      size_t buffer_size = gContext->GetNumSetting("HDRingbufferSize",
    128                                                   50 * TSPacket::SIZE);
    129      size_t buffered_packets = min(buffer_size / 4,
    130                                    (size_t) kMaxBufferedPackets);
    131      iec61883_mpeg2_set_buffers(fwmpeg, buffered_packets);
    132      VERBOSE(VB_IMPORTANT, LOC +
    133              QString("Buffered packets %1 (%2 KB)")
    134              .arg(buffered_packets).arg(buffered_packets * 4));
     67    _request_recording = true;
     68    _recording = true;
    13569
    136      // Set speed if needed.
    137      // Probably shouldn't even allow user to set,
    138      // 100Mbps should be more the enough.
    139      int curspeed = iec61883_mpeg2_get_speed(fwmpeg);
    140      if (curspeed != fwspeed)
    141      {
    142          VERBOSE(VB_RECORD, LOC +
    143                  QString("Changing Speed %1 -> %2")
    144                  .arg(speed_to_string(curspeed))
    145                  .arg(speed_to_string(fwspeed)));
     70    StartStreaming();
    14671
    147          iec61883_mpeg2_set_speed(fwmpeg, fwspeed);
    148          if (fwspeed != iec61883_mpeg2_get_speed(fwmpeg))
    149          {
    150               VERBOSE(VB_IMPORTANT, LOC +
    151                       "Unable to set firewire speed, continuing");
    152          }
    153      }
     72    while (_request_recording)
     73    {
     74        if (!PauseAndWait())
     75            usleep(50 * 1000);
     76    }
    15477
    155      fwfd = raw1394_get_fd(fwhandle);
     78    StopStreaming();
     79    FinishRecording();
    15680
    157      return isopen = true;
     81    _recording = false;
    15882}
    15983
    160 void FirewireRecorder::Close(void)
     84void FirewireRecorder::AddData(const unsigned char *data, uint len)
    16185{
    162     if (!isopen)
     86    uint bufsz = buffer.size();
     87    if ((SYNC_BYTE == data[0]) && (TSPacket::SIZE == len) &&
     88        (TSPacket::SIZE > bufsz))
     89    {
     90        if (bufsz)
     91            buffer.clear();
     92
     93        ProcessTSPacket(*(reinterpret_cast<const TSPacket*>(data)));
    16394        return;
     95    }
    16496
    165     isopen = false;
     97    buffer.insert(buffer.end(), data, data + len);
     98    bufsz += len;
    16699
    167     VERBOSE(VB_RECORD, LOC + "Releasing iec61883_mpeg2 object");
    168     iec61883_mpeg2_close(fwmpeg);
     100    int sync_at = -1;
     101    for (uint i = 0; (i < bufsz) && (sync_at < 0); i++)
     102    {
     103        if (buffer[i] == SYNC_BYTE)
     104            sync_at = i;
     105    }
    169106
    170     if (fwconnection == kConnectionP2P && fwchannel > -1)
     107    if (sync_at < 0)
     108        return;
     109
     110    if (bufsz < 30 * TSPacket::SIZE)
     111        return; // build up a little buffer
     112
     113    while (sync_at + TSPacket::SIZE < bufsz)
    171114    {
    172         VERBOSE(VB_RECORD, LOC +
    173                 QString("Disconnecting channel %1").arg(fwchannel));
     115        ProcessTSPacket(*(reinterpret_cast<const TSPacket*>(
     116                              &buffer[0] + sync_at)));
    174117
    175         iec61883_cmp_disconnect(fwhandle, fwnode | 0xffc0, fwoplug,
    176                                 raw1394_get_local_id (fwhandle),
    177                                 fwiplug, fwchannel, fwbandwidth);
     118        sync_at += TSPacket::SIZE;
    178119    }
    179120
    180     VERBOSE(VB_RECORD, LOC + "Releasing raw1394 handle");
    181     raw1394_destroy_handle(fwhandle);
     121    buffer.erase(buffer.begin(), buffer.begin() + sync_at);
     122
     123    return;
    182124}
    183125
    184 bool FirewireRecorder::grab_frames()
     126void FirewireRecorder::ProcessTSPacket(const TSPacket &tspacket)
    185127{
    186     struct timeval tv;
    187     fd_set rfds;
     128    if (tspacket.TransportError())
     129        return;
    188130
    189     FD_ZERO(&rfds);
    190     FD_SET(fwfd, &rfds);
    191     tv.tv_sec = kTimeoutInSeconds;
    192     tv.tv_usec = 0;
     131    if (tspacket.ScramplingControl())
     132        return;
    193133
    194     if (select(fwfd + 1, &rfds, NULL, NULL, &tv)  <= 0)
    195     {
    196         VERBOSE(VB_IMPORTANT, LOC +
    197                 QString("No Input in %1 seconds [P:%2 N:%3] (select)")
    198                 .arg(kTimeoutInSeconds).arg(fwport).arg(fwnode));
    199         return false;
    200     }
     134    if (tspacket.HasAdaptationField())
     135        GetStreamData()->HandleAdaptationFieldControl(&tspacket);
    201136
    202     int ret = raw1394_loop_iterate(fwhandle);
    203     if (ret)
     137    if (tspacket.HasPayload())
    204138    {
    205         VERBOSE(VB_IMPORTANT, LOC_ERR + "libraw1394_loop_iterate() " +
    206                 QString("returned %1").arg(ret));
    207         return false;
    208     }
     139        const unsigned int lpid = tspacket.PID();
    209140
    210     return true;
     141        // Pass or reject packets based on PID, and parse info from them
     142        if (lpid == GetStreamData()->VideoPIDSingleProgram())
     143        {
     144            _buffer_packets = !FindMPEG2Keyframes(&tspacket);
     145            BufferedWrite(tspacket);
     146        }
     147        else if (GetStreamData()->IsAudioPID(lpid))
     148            BufferedWrite(tspacket);
     149        else if (GetStreamData()->IsListeningPID(lpid))
     150            GetStreamData()->HandleTSTables(&tspacket);
     151        else if (GetStreamData()->IsWritingPID(lpid))
     152            BufferedWrite(tspacket);
     153    }
    211154}
    212155
    213 void FirewireRecorder::SetOption(const QString &name, const QString &value)
     156void FirewireRecorder::SetOptionsFromProfile(RecordingProfile *profile,
     157                                                 const QString &videodev,
     158                                                 const QString &audiodev,
     159                                                 const QString &vbidev)
    214160{
    215     if (name == "model")
    216         fwmodel = value;
     161    (void)videodev;
     162    (void)audiodev;
     163    (void)vbidev;
     164    (void)profile;
    217165}
    218166
    219 void FirewireRecorder::SetOption(const QString &name, int value)
     167// documented in recorderbase.cpp
     168bool FirewireRecorder::PauseAndWait(int timeout)
    220169{
    221     if (name == "port")
    222         fwport = value;
    223     else if (name == "node")
    224         fwnode = value;
    225     else if (name == "speed")
     170    if (request_pause)
    226171    {
    227         if (RAW1394_ISO_SPEED_100 != value &&
    228             RAW1394_ISO_SPEED_200 != value &&
    229             RAW1394_ISO_SPEED_400 != value)
     172        VERBOSE(VB_RECORD, LOC + "PauseAndWait("<<timeout<<") -- pause");
     173        if (!paused)
    230174        {
    231             VERBOSE(VB_IMPORTANT, LOC_ERR +
    232                     QString("Unknown speed '%1', will use 100Mbps")
    233                     .arg(value));
    234 
    235             value = RAW1394_ISO_SPEED_100;
     175            StopStreaming();
     176            paused = true;
     177            pauseWait.wakeAll();
     178            if (tvrec)
     179                tvrec->RecorderPaused();
    236180        }
    237         fwspeed = value;
     181        unpauseWait.wait(timeout);
    238182    }
    239     else if (name == "connection")
     183    if (!request_pause && paused)
    240184    {
    241         if (kConnectionP2P       != value &&
    242             kConnectionBroadcast != value)
    243         {
    244             VERBOSE(VB_IMPORTANT, LOC_ERR +
    245                     QString("Unknown connection type '%1', will use P2P")
    246                     .arg(fwconnection));
     185        VERBOSE(VB_RECORD, LOC + "PauseAndWait("<<timeout<<") -- unpause");
     186        StartStreaming();
     187        paused = false;
     188    }
     189    return paused;
     190}
    247191
    248             fwconnection = kConnectionP2P;
    249         }
    250         fwconnection = value;
     192void FirewireRecorder::SetStreamData(MPEGStreamData *data)
     193{
     194    if (data == _mpeg_stream_data)
     195        return;
     196
     197    MPEGStreamData *old_data = _mpeg_stream_data;
     198    _mpeg_stream_data = data;
     199    if (old_data)
     200        delete old_data;
     201
     202    if (data)
     203    {
     204        data->AddMPEGSPListener(this);
     205
     206        if (data->DesiredProgram() >= 0)
     207            data->SetDesiredProgram(data->DesiredProgram());
    251208    }
    252209}
     210
     211void FirewireRecorder::HandleSingleProgramPAT(ProgramAssociationTable *pat)
     212{
     213    if (!pat)
     214        return;
     215
     216    int next = (pat->tsheader()->ContinuityCounter()+1)&0xf;
     217    pat->tsheader()->SetContinuityCounter(next);
     218    BufferedWrite(*(reinterpret_cast<const TSPacket*>(pat->tsheader())));
     219}
     220
     221void FirewireRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt)
     222{
     223    if (!pmt)
     224        return;
     225
     226    int next = (pmt->tsheader()->ContinuityCounter()+1)&0xf;
     227    pmt->tsheader()->SetContinuityCounter(next);
     228    BufferedWrite(*(reinterpret_cast<const TSPacket*>(pmt->tsheader())));
     229}
  • libs/libmythtv/firewirerecorder.h

     
    44 *  Distributed as part of MythTV under GPL v2 and later.
    55 */
    66
    7 #ifndef FIREWIRERECORDER_H_
    8 #define FIREWIRERECORDER_H_
     7#ifndef _FIREWIRERECORDER_H_
     8#define _FIREWIRERECORDER_H_
    99
    10 #include "firewirerecorderbase.h"
    11 #include "tsstats.h"
    12 #include <libraw1394/raw1394.h>
    13 #include <libiec61883/iec61883.h>
     10// MythTV headers
     11#include "dtvrecorder.h"
     12#include "tspacket.h"
     13#include "streamlisteners.h"
    1414
     15class TVRec;
     16class FirewireChannel;
     17
    1518/** \class FirewireRecorder
    16  *  \brief Linux FirewireRFecorder
     19 *  \brief This is a specialization of DTVRecorder used to
     20 *         handle DVB and ATSC streams from a firewire input.
    1721 *
    18  *  \sa FirewireRecorderBase
     22 *  \sa DTVRecorder
    1923 */
    20 class FirewireRecorder : public FirewireRecorderBase
     24class FirewireRecorder : public DTVRecorder,
     25                         public MPEGSingleProgramStreamListener,
     26                         public TSDataListener
    2127{
    22     friend int fw_tspacket_handler(unsigned char*,int,uint,void*);
     28    friend class MPEGStreamData;
     29    friend class TSPacketProcessor;
    2330
    2431  public:
    25     FirewireRecorder(TVRec *rec)
    26         : FirewireRecorderBase(rec),
    27         fwport(-1),     fwchannel(-1), fwspeed(-1),   fwbandwidth(-1),
    28         fwfd(-1),       fwconnection(kConnectionP2P),
    29         fwoplug(-1),    fwiplug(-1),   fwmodel(""),   fwnode(0),
    30         fwhandle(NULL), fwmpeg(NULL),  isopen(false) { }
    31    ~FirewireRecorder() { Close(); }
     32    FirewireRecorder(TVRec *rec, FirewireChannel *chan);
     33    virtual ~FirewireRecorder();
    3234
    3335    // Commands
    34     bool Open(void);
     36    bool Open(void);
     37    void Close(void);
    3538
     39    void StartStreaming(void);
     40    void StopStreaming(void);
     41
     42    void StartRecording(void);
     43    bool PauseAndWait(int timeout = 100);
     44
     45    void AddData(const unsigned char *data, uint dataSize);
     46    void ProcessTSPacket(const TSPacket &tspacket);
     47
    3648    // Sets
    37     void SetOption(const QString &name, const QString &value);
    38     void SetOption(const QString &name, int value);
     49    void SetOptionsFromProfile(RecordingProfile *profile,
     50                               const QString &videodev,
     51                               const QString &audiodev,
     52                               const QString &vbidev);
     53    void SetStreamData(MPEGStreamData*);
    3954
    40   private:
    41     void Close(void);
    42     void start() { iec61883_mpeg2_recv_start(fwmpeg, fwchannel); }
    43     void stop() { iec61883_mpeg2_recv_stop(fwmpeg); }
    44     bool grab_frames();
     55    // Gets
     56    MPEGStreamData *GetStreamData(void) { return _mpeg_stream_data; }
    4557
     58    // MPEG Single Program
     59    void HandleSingleProgramPAT(ProgramAssociationTable*);
     60    void HandleSingleProgramPMT(ProgramMapTable*);
     61
     62  protected:
     63    FirewireRecorder(TVRec *rec);
     64
    4665  private:
    47     int              fwport;
    48     int              fwchannel;
    49     int              fwspeed;
    50     int              fwbandwidth;
    51     int              fwfd;
    52     int              fwconnection;
    53     int              fwoplug;
    54     int              fwiplug;
    55     QString          fwmodel;
    56     nodeid_t         fwnode;
    57     raw1394handle_t  fwhandle;
    58     iec61883_mpeg2_t fwmpeg;
    59     bool             isopen;
    60 
    61     static const int kBroadcastChannel;
    62     static const int kConnectionP2P;
    63     static const int kConnectionBroadcast;
    64     static const uint kMaxBufferedPackets;
     66    MPEGStreamData        *_mpeg_stream_data;
     67    FirewireChannel       *channel;
     68    bool                   isopen;
     69    vector<unsigned char>  buffer;
    6570};
    6671
    67 #endif
     72#endif //  _FIREWIRERECORDER_H_
  • libs/libmythtv/darwinfirewiredevice.h

     
     1#ifndef _DARWIN_FIREWIRE_DEVICE_H_
     2#define _DARWIN_FIREWIRE_DEVICE_H_
     3
     4#include "firewiredevice.h"
     5
     6class DFDPriv;
     7
     8class DarwinFirewireDevice : public FirewireDevice
     9{
     10    friend int dfd_no_data_notification(void *cb_data);
     11    friend int dfd_tspacket_handler(
     12        uint32_t tsPacketCount, uint32_t **ppBuf, void *callback_data);
     13
     14  public:
     15    DarwinFirewireDevice();
     16    ~DarwinFirewireDevice();
     17
     18    virtual bool OpenPort(void);
     19    virtual bool ClosePort(void);
     20
     21    virtual void AddListener(TSDataListener*);
     22    virtual void RemoveListener(TSDataListener*);
     23
     24    // Sets
     25    virtual bool SetPowerState(bool on);
     26    virtual bool SetChannel(const QString &panel_model, uint channel);
     27
     28    // Gets
     29    virtual bool IsPortOpen(void) const;
     30    virtual bool IsTuner(void) const;
     31    virtual bool IsPanel(void) const;
     32    virtual bool IsSTB(void) const;
     33
     34    // non-const Gets
     35    virtual PowerState GetPowerState(void);
     36
     37    void no_data(void);
     38
     39  private:
     40    bool OpenAVStream(void);
     41    bool CloseAVStream(void);
     42
     43    bool StartStreaming(void);
     44    bool StopStreaming(void);
     45
     46    void BroadcastToListeners(const unsigned char *data, uint dataSize);
     47
     48  private:
     49    DFDPriv *m_priv;
     50};
     51
     52#endif // _DARWIN_FIREWIRE_DEVICE_H_
  • libs/libmythtv/darwinfirewirechannel.cpp

     
    1 /**
    2  *  DarwinFirewireChannel
    3  *  Copyright (c) 2005 by Jim Westfall
    4  *  SA3250HD support Copyright (c) 2005 by Matt Porter
    5  *  Distributed as part of MythTV under GPL v2 and later.
    6  */
    7 
    8 
    9 #include <iostream>
    10 #include "mythcontext.h"
    11 #include "darwinfirewirechannel.h"
    12 
    13 #include "selectavcdevice.h"
    14 
    15 #undef always_inline
    16 #include <AVCVideoServices/AVCVideoServices.h>
    17 
    18 
    19 namespace
    20 {
    21   bool find_device(AVS::AVCDevice* d)
    22   {
    23       return d->isAttached && d->hasMonitorOrTunerSubunit
    24           // For the time being, the DarwinFireWireRecorder doesn't
    25           // handle DVB devices, so there's no point in finding one we
    26           // can tune to, here.  That saves us from having to search
    27           // twice for an eligible device.
    28           && !d->isDVDevice 
    29           ;
    30   }
    31 }
    32 
    33 DarwinFirewireChannel::DarwinFirewireChannel(FireWireDBOptions const& firewire_opts,TVRec *parent)
    34   : FirewireChannelBase(parent)
    35   , device_controller(0)
    36   , device(0)
    37 {
    38     (void)firewire_opts;
    39 }
    40 
    41 bool DarwinFirewireChannel::OpenFirewire()
    42 {
    43     IOReturn err = AVS::CreateAVCDeviceController(&this->device_controller);
    44     if (err)
    45     {
    46         VERBOSE(
    47             VB_IMPORTANT,
    48                 QString("unable to open device controller: %1").arg(err,0,16));
    49         return false;
    50     }
    51 
    52     if ((this->device = SelectAVCDevice(device_controller, find_device)))
    53     {
    54         VERBOSE(VB_RECORD, QString("DarwinFirewireChannel: opening device") );
    55         err = this->device->openDevice();
    56         if (!err)
    57             return true;
    58 
    59         VERBOSE(
    60             VB_IMPORTANT,
    61             QString("FireWireChannel: couldn't open tuner device: %1").arg(err,0,16));
    62     }
    63     else
    64     {
    65         VERBOSE(
    66             VB_IMPORTANT,
    67             QString(
    68                 "DarwinFireWireChannel: unable to find an attached"
    69                 " MPEG2 device that supports channel changes"));
    70     }
    71     AVS::DestroyAVCDeviceController(this->device_controller);
    72     return false;
    73 }
    74 
    75 void DarwinFirewireChannel::CloseFirewire()
    76 {
    77     this->device->closeDevice();
    78     AVS::DestroyAVCDeviceController(this->device_controller);
    79     // Leave the device controller for the destructor
    80 }
    81 
    82 AVS::AVCDevice* DarwinFirewireChannel::GetAVCDevice() const
    83 {
    84     return this->device;
    85 }
    86 
    87 bool DarwinFirewireChannel::SetChannelByNumber(int channel)
    88 {
    89      // If the tuner is off, try to turn it on.
    90      UInt8 power_state;
    91      IOReturn err = this->device->GetPowerState(&power_state);
    92      if (err == kIOReturnSuccess && power_state == kAVCPowerStateOff)
    93      {
    94          this->device->SetPowerState(kAVCPowerStateOn);
    95        
    96          // Give it time to power up.
    97          usleep(2000000); // Sleep for two seconds
    98      }
    99 
    100      AVS::PanelSubunitController panel(this->device);
    101      err = panel.Tune(channel);
    102      if (err != kIOReturnSuccess)
    103      {
    104          VERBOSE(VB_GENERAL, QString("DarwinFirewireChannel: Tuning failed: %1").arg(err,0,16));
    105          VERBOSE(VB_GENERAL, QString("Ignoring error per apple example"));
    106      }
    107      // Give it time to transition.       
    108      usleep(1000000); // Sleep for one second
    109      return true;
    110 }
  • libs/libmythtv/firewiresignalmonitor.cpp

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

     
    3333class ServiceDescriptionTable;
    3434class DVBEventInformationTable;
    3535
     36class TSDataListener
     37{
     38  public:
     39    /// Callback function to add MPEG2 TS data
     40    virtual void AddData(const unsigned char *data, uint dataSize) = 0;
     41
     42  protected:
     43    virtual ~TSDataListener() { }
     44};
     45
    3646class MPEGStreamListener
    3747{
    3848  protected:
  • libs/libmythtv/darwinfirewirechannel.h

     
    1 /**
    2  *  DarwinFirewireChannel
    3  *  Copyright (c) 2005 by Dave Abrahams
    4  *  Distributed as part of MythTV under GPL v2 and later.
    5  */
    6 
    7 
    8 #ifndef LIBMYTHTV_DARWINFIREWIRECHANNEL_H
    9 #define LIBMYTHTV_DARWINFIREWIRECHANNEL_H
    10 
    11 #include <qstring.h>
    12 #include "tv_rec.h"
    13 #include "firewirechannelbase.h"
    14 
    15 
    16 namespace AVS
    17 {
    18   class AVCDeviceController;
    19   class AVCDevice;
    20 }
    21 
    22 class DarwinFirewireChannel : public FirewireChannelBase
    23 {
    24   public:
    25     DarwinFirewireChannel(FireWireDBOptions const&, TVRec *parent);
    26 
    27     // Gets
    28     AVS::AVCDevice* GetAVCDevice() const;
    29 
    30     // Sets
    31     bool SetChannelByNumber(int channel);
    32 
    33   private:
    34     bool OpenFirewire();
    35     void CloseFirewire();
    36 
    37   private:
    38     AVS::AVCDeviceController* device_controller;
    39     AVS::AVCDevice* device;
    40 };
    41 
    42 #endif
  • libs/libmythtv/signalmonitor.cpp

     
    3434#   include "iptvchannel.h"
    3535#endif
    3636
     37#ifdef USING_FIREWIRE
     38#   include "firewiresignalmonitor.h"
     39#   include "firewirechannel.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        FirewireChannel *fc = dynamic_cast<FirewireChannel*>(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 "firewiredevice.h"
     12#include "util.h"
     13
     14class FirewireChannel;
     15
     16class FirewireSignalMonitor : public DTVSignalMonitor, public TSDataListener
     17{
     18    Q_OBJECT
     19
     20  public:
     21    FirewireSignalMonitor(int db_cardnum, FirewireChannel *_channel,
     22                          uint _flags = kFWSigMon_WaitForPower,
     23                          const char *_name = "FirewireSignalMonitor");
     24
     25    virtual void HandlePAT(const ProgramAssociationTable*);
     26    virtual void HandlePMT(uint, const ProgramMapTable*);
     27
     28    void Stop(void);
     29
     30  public slots:
     31    void deleteLater(void);
     32
     33  protected:
     34    FirewireSignalMonitor(void);
     35    FirewireSignalMonitor(const FirewireSignalMonitor&);
     36    virtual ~FirewireSignalMonitor();
     37
     38    virtual void UpdateValues(void);
     39    void EmitFirewireSignals(void);
     40
     41    static void *TableMonitorThread(void *param);
     42    void RunTableMonitor(void);
     43
     44    bool SupportsTSMonitoring(void);
     45
     46    void AddData(const unsigned char *data, uint dataSize);
     47
     48  public:
     49    static const uint kPowerTimeout;
     50    static const uint kBufferTimeout;
     51
     52  protected:
     53    bool               dtvMonitorRunning;
     54    pthread_t          table_monitor_thread;
     55    bool               stb_needs_retune;
     56    bool               stb_needs_to_wait_for_pat;
     57    bool               stb_needs_to_wait_for_power;
     58    MythTimer          stb_wait_for_pat_timer;
     59    MythTimer          stb_wait_for_power_timer;
     60
     61    vector<unsigned char> buffer;
     62
     63    static QMap<void*,uint> pat_keys;
     64    static QMutex           pat_keys_lock;
     65};
     66
     67#endif // _FIREWIRESIGNALMONITOR_H_
  • libs/libmythtv/darwinfirewirerecorder.h

     
    1 /**
    2  *  FirewireRecorder
    3  *  Copyright (c) 2005 by Jim Westfall and Dave Abrahams
    4  *  Distributed as part of MythTV under GPL v2 and later.
    5  */
    6 
    7 #ifndef LIBMYTHTV_DARWINFIREWIRERECORDER_H_
    8 #define LIBMYTHTV_DARWINFIREWIRERECORDER_H_
    9 
    10 #include "firewirerecorderbase.h"
    11 #include "darwinfirewirechannel.h"
    12 
    13 //#include <IOKit/IOReturn.h>
    14 //#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacTypes.h>
    15 
    16 typedef unsigned long UInt32;
    17 typedef int IOReturn;
    18 
    19 namespace AVS
    20 {
    21   class AVCDeviceController;
    22   class AVCDevice;
    23   class StringLogger;
    24   class AVCDeviceStream;
    25 }
    26 
    27 /** \class DarwinFirewireRecorder
    28  *  \brief This is a specialization of DTVRecorder used to
    29  *         handle DVB and ATSC streams from a firewire input.
    30  *
    31  *  \sa DTVRecorder
    32  */
    33 class DarwinFirewireRecorder : public FirewireRecorderBase
    34 {
    35   public:
    36     DarwinFirewireRecorder(TVRec *rec, ChannelBase* tuner);
    37     ~DarwinFirewireRecorder();
    38 
    39     bool Open(void);
    40 
    41     void SetOption(const QString &name, const QString &value);
    42     void SetOption(const QString &name, int value);
    43 
    44   private:
    45     void Close();
    46 
    47     void start();
    48     void stop();
    49     void no_data();
    50     bool grab_frames();
    51 
    52     static IOReturn MPEGNoData(void* pRefCon);
    53     static IOReturn tspacket_callback(UInt32 tsPacketCount, UInt32 **ppBuf, void *pRefCon);
    54 
    55     AVS::AVCDevice* capture_device;
    56     AVS::StringLogger* message_log;
    57     AVS::AVCDeviceStream* video_stream;
    58 
    59     bool isopen;
    60 };
    61 
    62 #endif
  • libs/libmythtv/firewirechannel.h

     
    11/**
    22 *  FirewireChannel
    3  *  Copyright (c) 2005 by Jim Westfall
    4  *  SA3250HD support Copyright (c) 2005 by Matt Porter
     3 *  Copyright (c) 2005 by Jim Westfall and Dave Abrahams
    54 *  Distributed as part of MythTV under GPL v2 and later.
    65 */
    76
     7#ifndef _FIREWIRECHANNEL_H_
     8#define _FIREWIRECHANNEL_H_
    89
    9 #ifndef FIREWIRECHANNEL_H
    10 #define FIREWIRECHANNEL_H
    11 
    12 #include <qstring.h>
    1310#include "tv_rec.h"
    14 #include "firewirechannelbase.h"
    15 #include <libavc1394/avc1394.h>
     11#include "dtvchannel.h"
     12#include "firewiredevice.h"
    1613
    17 using namespace std;
    18 
    19 class FirewireChannel : public FirewireChannelBase
     14class FirewireChannel : public DTVChannel
    2015{
    2116  public:
    22     enum PowerState {
    23         On,
    24         Off,
    25         Failed
    26     };
     17    FirewireChannel(const FireWireDBOptions &firewire_opts, TVRec *parent);
    2718
    28     FirewireChannel(FireWireDBOptions firewire_opts, TVRec *parent);
    29     ~FirewireChannel(void);
     19    // Commands
     20    virtual bool Open(void);
     21    virtual void Close(void);
     22    virtual bool SwitchToInput(const QString &inputname, const QString &chan);
     23    virtual bool SwitchToInput(int newcapchannel, bool setstarting)
     24        { (void)newcapchannel; (void)setstarting; return false; }
    3025
    31     bool OpenFirewire(void);
    32     void CloseFirewire(void);
     26    virtual bool TuneMultiplex(uint /*mplexid*/, QString /*inputname*/)
     27        { return false; }
     28    virtual bool Tune(const DTVMultiplex &/*tuning*/, QString /*inputname*/)
     29        { return false; }
     30    virtual bool Retune(void);
    3331
    3432    // Sets
    35     void SetExternalChanger(void);
    36     bool SetChannelByNumber(int channel);
     33    virtual bool SetChannelByString(const QString &chan);
     34    virtual bool SetChannelByNumber(int channel);
     35    virtual bool SetPowerState(bool on);
    3736
    3837    // Gets
    39     bool IsOpen(void) const { return isopen; }
    40     QString GetDevice(void) const
    41         { return QString("%1:%2").arg(fw_opts.port).arg(fw_opts.node); }
    42     PowerState GetPowerState(void);
     38    virtual bool IsOpen(void) const { return isopen; }
     39    virtual FirewireDevice::PowerState GetPowerState(void) const;
     40    virtual QString GetDevice(void) const;
     41    virtual FirewireDevice *GetFirewireDevice(void) { return device; }
    4342
     43  protected:
     44    FirewireChannel(TVRec *parent) :
     45        DTVChannel(parent), isopen(false) { }
     46    ~FirewireChannel() { Close(); }
     47
    4448  private:
     49    virtual bool OpenFirewire(void);
     50    virtual void CloseFirewire(void);
     51
     52  protected:
     53    bool               isopen;
    4554    FireWireDBOptions  fw_opts;
    46     nodeid_t           fwnode;
    47     raw1394handle_t    fwhandle;
     55    FirewireDevice    *device;
     56    uint               current_channel;
     57    bool               is_port_open;
    4858};
    4959
    50 #endif
     60#endif // _FIREWIRECHANNEL_H_
  • libs/libmythtv/videosource.cpp

     
    10311031        hg1->addChild(new FirewireNode(parent));
    10321032        hg1->addChild(new FirewireSpeed(parent));
    10331033        addChild(hg1);
    1034         addChild(new FirewireInput(parent));
     1034
     1035        FirewireInput *defaultinput = new FirewireInput(parent);
     1036        addChild(defaultinput);
     1037        defaultinput->setVisible(false);
     1038
     1039        addChild(new ChannelTimeout(parent, 9000));
    10351040    };
     1041
    10361042  private:
    10371043    CaptureCard &parent;
    10381044};
     
    11861192        HDHRCardInput *defaultinput = new HDHRCardInput(parent);
    11871193        addChild(defaultinput);
    11881194        defaultinput->setVisible(false);
     1195
     1196        addChild(new SignalTimeout(parent, 1000));
     1197        addChild(new ChannelTimeout(parent, 3000));
    11891198    };
    11901199
    11911200  private:
  • libs/libmythtv/selectavcdevice.cpp

     
    1 /**
    2  *  SelectAVCDevice
    3  *  Copyright (c) 2006 by Dave Abrahams
    4  *  Distributed as part of MythTV under GPL v2 and later.
    5  */
    6 
    7 #include "mythconfig.h"
    8 
    9 #ifdef CONFIG_DARWIN
    10 # include "mythcontext.h"
    11 # include "selectavcdevice.h"
    12 # undef always_inline
    13 # include <AVCVideoServices/AVCVideoServices.h>
    14 
    15 AVS::AVCDevice* SelectAVCDevice(
    16     AVS::AVCDeviceController* controller,
    17     bool (*filter)(AVS::AVCDevice*)
    18 )
    19 {
    20     VERBOSE(VB_GENERAL, QString("SelectAVCDevice:"));
    21 
    22     for (unsigned n = CFArrayGetCount(controller->avcDeviceArray),
    23              i = 0; i < n; ++i)
    24     {
    25         AVS::AVCDevice& d = *(AVS::AVCDevice*)CFArrayGetValueAtIndex(controller->avcDeviceArray, i);
    26 
    27         VERBOSE(
    28             VB_GENERAL,
    29             QString("SelectAVCDevice: %1, format: %2, attached: %3, type: %4")
    30                 .arg(d.deviceName)
    31                 .arg(d.isDVDevice ? "DV" : d.isMPEGDevice ? "MPEG2-TS" : "unknown")
    32                 .arg(d.isAttached ? "yes" : "no")
    33                 .arg(d.hasTapeSubunit ? "tape" : d.hasMonitorOrTunerSubunit ? "tuner" : "unknown")
    34         );
    35 
    36         if (filter(&d))
    37         {
    38             VERBOSE(VB_GENERAL, QString("SelectAVCDevice: FOUND"));
    39             return &d;
    40         }
    41     }
    42     VERBOSE(VB_GENERAL, QString("SelectAVCDevice: NOT FOUND"));
    43     return 0;
    44 }
    45 
    46 #endif // CONFIG_DARWIN
    47 
  • libs/libmythtv/firewirechannelbase.cpp

     
    1 /**
    2  *  FirewireChannelBase
    3  *  Copyright (c) 2005 by Jim Westfall Dave Abrahams
    4  *  Distributed as part of MythTV under GPL v2 and later.
    5  */
    6 
    7 
    8 #include <iostream>
    9 #include "mythcontext.h"
    10 #include "firewirechannelbase.h"
    11 
    12 bool FirewireChannelBase::SetChannelByString(const QString &chan)
    13 {
    14     inputs[currentInputID]->startChanNum = chan;
    15     curchannelname = chan;
    16 
    17     InputMap::const_iterator it = inputs.find(currentInputID);
    18 
    19     if (!(*it)->externalChanger.isEmpty())
    20         return ChangeExternalChannel(chan);
    21 
    22     return isopen && SetChannelByNumber(chan.toInt());
    23 }
    24 
    25 bool FirewireChannelBase::Open()
    26 {
    27     if (!InitializeInputs())
    28         return false;
    29 
    30     InputMap::const_iterator it = inputs.find(currentInputID);
    31     if (!(*it)->externalChanger.isEmpty())
    32         return true;
    33 
    34     if (!isopen)
    35     {
    36         isopen = OpenFirewire();
    37         return isopen;
    38     }
    39     return true;
    40 }
    41 
    42 void FirewireChannelBase::Close()
    43 {
    44     if (isopen)
    45         CloseFirewire();
    46     isopen = false;
    47 }
    48    
    49 bool FirewireChannelBase::SwitchToInput(const QString &input,
    50                                         const QString &chan)
    51 {
    52     int inputNum = GetInputByName(input);
    53     if (inputNum < 0)
    54         return false;
    55 
    56     return SetChannelByString(chan);
    57 }
  • libs/libmythtv/linuxfirewiredevice.h

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

     
    4848#include "dbox2channel.h"
    4949#include "hdhrchannel.h"
    5050#include "iptvchannel.h"
     51#include "firewirechannel.h"
    5152
    5253#include "recorderbase.h"
    5354#include "NuppelVideoRecorder.h"
     
    5758#include "dbox2recorder.h"
    5859#include "hdhrrecorder.h"
    5960#include "iptvrecorder.h"
     61#include "firewirerecorder.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
    164153        channel = new FirewireChannel(fwOpt, this);
    165 # endif
    166154        if (!channel->Open())
    167155            return false;
    168156        InitChannel(genOpt.defaultinput, startchannel);
     
    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 = new FirewireRecorder(this, GetFirewireChannel());
     823        if (recorder)
     824        {
     825            recorder->SetOption("port",       fwOpt.port);
     826            recorder->SetOption("node",       fwOpt.node);
     827            recorder->SetOption("speed",      fwOpt.speed);
     828            recorder->SetOption("model",      fwOpt.model);
     829            recorder->SetOption("connection", fwOpt.connection);
     830        }
    844831#endif // USING_FIREWIRE
    845832    }
    846833    else if (genOpt.cardtype == "DBOX2")
     
    11141101#endif // USING_DVB
    11151102}
    11161103
     1104FirewireChannel *TVRec::GetFirewireChannel(void)
     1105{
     1106#ifdef USING_FIREWIRE
     1107    return dynamic_cast<FirewireChannel*>(channel);
     1108#else
     1109    return NULL;
     1110#endif // USING_FIREWIRE
     1111}
     1112
    11171113Channel *TVRec::GetV4LChannel(void)
    11181114{
    11191115#ifdef USING_V4L
  • libs/libmythtv/tv_rec.h

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

     
    1 /**
    2  *  SelectAVCDevice
    3  *  Copyright (c) 2006 by Dave Abrahams
    4  *  Distributed as part of MythTV under GPL v2 and later.
    5  */
    6 
    7 #ifndef LIBMYTHTV_SELECTAVCDEVICE_H_
    8 # define LIBMYTHTV_SELECTAVCDEVICE_H_
    9 
    10 # include "mythconfig.h"
    11 
    12 # ifdef CONFIG_DARWIN
    13 #  undef always_inline
    14 #  include <AVCVideoServices/AVCVideoServices.h>
    15 
    16 AVS::AVCDevice* SelectAVCDevice(
    17     AVS::AVCDeviceController*,
    18     bool (*)(AVS::AVCDevice*)
    19 );
    20 
    21 # endif // CONFIG_DARWIN
    22 
    23 #endif LIBMYTHTV_SELECTAVCDEVICE_H_
    24 
  • libs/libmythtv/firewiredevice.h

     
     1/**
     2 *  FirewireDevice
     3 *  Copyright (c) 2005 by Jim Westfall
     4 *  Distributed as part of MythTV under GPL v2 and later.
     5 */
     6
     7#ifndef _FIREWIRE_DEVICE_H_
     8#define _FIREWIRE_DEVICE_H_
     9
     10// C++ headers
     11#include <vector>
     12using namespace std;
     13
     14// Qt headers
     15#include <qstring.h>
     16#include <qmutex.h>
     17
     18// MythTV headers
     19#include "streamlisteners.h"
     20
     21class TSPacket;
     22
     23class FirewireDevice
     24{
     25  public:
     26    // Public enums
     27    typedef enum
     28    {
     29        kAVCPowerOn,
     30        kAVCPowerOff,
     31        kAVCPowerUnknown,
     32        kAVCPowerQueryFailed,
     33    } PowerState;
     34
     35    FirewireDevice();
     36    virtual ~FirewireDevice() { }
     37
     38    virtual bool OpenPort(void) = 0;
     39    virtual bool ClosePort(void) = 0;
     40
     41    virtual void AddListener(TSDataListener*);
     42    virtual void RemoveListener(TSDataListener*);
     43
     44    // Sets
     45    virtual bool SetPowerState(bool on) = 0;
     46    virtual bool SetChannel(const QString &panel_model, uint channel) = 0;
     47
     48    // Gets
     49    virtual bool IsPortOpen(void) const = 0;
     50    virtual bool IsTuner(void) const = 0;
     51    virtual bool IsPanel(void) const = 0;
     52    virtual bool IsSTB(void) const = 0;
     53    bool IsSTBBufferCleared(void) const { return m_buffer_cleared; }
     54
     55    // non-const Gets
     56    virtual PowerState GetPowerState(void) = 0;
     57
     58    // Statics
     59    static inline bool IsSTBSupported(const QString &model);
     60
     61  protected:
     62    void SetLastChannel(uint channel);
     63    void ProcessPATPacket(const TSPacket&);
     64
     65    uint m_last_channel;
     66    uint m_last_crc;
     67    bool m_buffer_cleared;
     68
     69    uint                     m_open_port_cnt;
     70    vector<TSDataListener*>  m_listeners;
     71    mutable QMutex           m_lock;
     72};
     73
     74inline bool FirewireDevice::IsSTBSupported(const QString &panel_model)
     75{
     76#ifdef USING_LINUX_FIREWIRE
     77    QString model = panel_model.upper();
     78    return ((model == "DCT-6200") ||
     79            (model == "SA3250HD") ||
     80            (model == "SA4200HD"));
     81#elif USING_OSX_FIREWIRE
     82    return true;
     83#else
     84    return false;
     85#endif
     86}
     87
     88#endif // _FIREWIRE_DEVICE_H_
  • libs/libmythtv/linuxfirewiredevice.cpp

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