Ticket #1648: firewire-sm-v37.patch

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

Fix for compilation with --disable-firewire

  • configure

     
    24502450
    24512451if test x"$firewire_cable_box" = x"yes" ; then
    24522452    firewire_cable_box="no"
    2453     if has_library libiec61883 -a has_library libavc1394 ; then
     2453    libavc_5_3="no"
     2454    if has_library libiec61883 -a \
     2455       has_library libavc1394 -a \
     2456       has_library librom1394; then
    24542457        if test x`which pkg-config 2>/dev/null` != x"" ; then
    24552458            if `pkg-config --atleast-version 0.5.0 libavc1394` ; then
    24562459                if `pkg-config --atleast-version 1.0.0 libiec61883` ; then
    24572460                    firewire_cable_box="yes"
     2461                    if `pkg-config --atleast-version 0.5.3 libavc1394` ; then
     2462                        libavc_5_3="yes"
     2463                    fi
    24582464                fi
    24592465            fi
    24602466        fi
     
    34343440  if test x"$darwin" = x"yes" ; then
    34353441      echo "CONFIG_MAC_AVC=$mac_avc" >>  $MYTH_CONFIG_MAK
    34363442  else
    3437       echo "CONFIG_FIREWIRE_LIBS=-lraw1394 -liec61883 -lavc1394" >>  $MYTH_CONFIG_MAK
     3443      echo "CONFIG_FIREWIRE_LIBS=-lraw1394 -liec61883 -lavc1394 -lrom1394" >>  $MYTH_CONFIG_MAK
     3444      if test x"$libavc_5_3" = x"yes" ; then
     3445          CCONFIG="$CCONFIG using_libavc_5_3"
     3446      fi
    34383447  fi
    34393448fi
    34403449
  • 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(TVRec *parent, const QString &_videodevice,
     19                                 const FireWireDBOptions &firewire_opts) :
     20    DTVChannel(parent),
     21    videodevice(_videodevice),
     22    fw_opts(firewire_opts),
     23    device(NULL),
     24    current_channel(0),
     25    isopen(false)
     26{
     27    uint64_t guid = videodevice.toULongLong(NULL, 16);
     28    uint subunitid = 0; // we only support first tuner on STB...
     29#ifdef USING_LINUX_FIREWIRE
     30    device = new LinuxFirewireDevice(
     31        guid, subunitid, fw_opts.speed,
     32        LinuxFirewireDevice::kConnectionP2P == (uint) fw_opts.connection);
     33#elif USING_OSX_FIREWIRE
     34    device = new DarwinFirewireDevice(guid, subunitid, fw_opts.speed);
    2135#endif
    2236
    23 #ifndef AVC1394_PANEL_OPERATION_0
    24 #define AVC1394_PANEL_OPERATION_0              0x000000020
    25 #endif
     37    InitializeInputs();
     38}
    2639
    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)
     40bool FirewireChannel::SetChannelByString(const QString &channum)
     41{
     42    InputMap::const_iterator it = inputs.find(currentInputID);
     43    if (it == inputs.end())
     44        return false;
    3245
    33 // SA3250HD defines
    34 #define AVC1394_SA3250_OPERAND_KEY_PRESS        0xE7
    35 #define AVC1394_SA3250_OPERAND_KEY_RELEASE      0x67
     46    // Fetch tuning data from the database.
     47    QString tvformat, modulation, freqtable, freqid, dtv_si_std;
     48    int finetune;
     49    uint64_t frequency;
     50    int mpeg_prog_num;
     51    uint atsc_major, atsc_minor, mplexid, tsid, netid;
    3652
    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
     53    if (!ChannelUtil::GetChannelData(
     54        (*it)->sourceid, channum,
     55        tvformat, modulation, freqtable, freqid,
     56        finetune, frequency,
     57        dtv_si_std, mpeg_prog_num, atsc_major, atsc_minor, tsid, netid,
     58        mplexid, commfree))
     59    {
     60        return false;
     61    }
    4362
    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)
     63    bool ok = false;
     64    if (!(*it)->externalChanger.isEmpty())
     65        ok = ChangeExternalChannel(freqid);
     66    else
     67    {
     68        uint ichan = freqid.toUInt(&ok);
     69        ok = ok && isopen && SetChannelByNumber(ichan);
     70    }
    5171
    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)
     72    if (ok)
     73    {
     74        // Set the current channum to the new channel's channum
     75        curchannelname = QDeepCopy<QString>(channum);
     76        (*it)->startChanNum = QDeepCopy<QString>(channum);
     77    }
    5778
    58 static bool is_supported(const QString &model)
    59 {
    60     return ((model == "DCT-6200") ||
    61             (model == "SA3250HD") ||
    62             (model == "SA4200HD"));
     79    return ok;
    6380}
    6481
    65 FirewireChannel::FirewireChannel(FireWireDBOptions firewire_opts,
    66                                  TVRec *parent)
    67     : FirewireChannelBase(parent), fw_opts(firewire_opts), fwhandle(NULL)
     82bool FirewireChannel::Open(void)
    6883{
    69 }
     84    VERBOSE(VB_CHANNEL, LOC + "Open()");
    7085
    71 FirewireChannel::~FirewireChannel(void)
    72 {
    73     Close();
    74 }
     86    if (inputs.find(currentInputID) == inputs.end())
     87        return false;
    7588
    76 bool FirewireChannel::SetChannelByNumber(int channel)
    77 {
    78     // Change channel using internal changer
     89    if (!device)
     90        return false;
    7991
    80     if (!is_supported(fw_opts.model))
     92    if (isopen)
     93        return true;
     94
     95    InputMap::const_iterator it = inputs.find(currentInputID);
     96    if (!FirewireDevice::IsSTBSupported(fw_opts.model) &&
     97        (*it)->externalChanger.isEmpty())
    8198    {
    8299        VERBOSE(VB_IMPORTANT, LOC_ERR +
    83                 QString("Model: '%1' ").arg(fw_opts.model) +
    84                 "is not supported by internal channel changer.");
     100                QString("Model: '%1' is not supported.").arg(fw_opts.model));
     101
    85102        return false;
    86103    }
    87104
    88     int dig[3];
    89     dig[0] = (channel % 1000) / 100;
    90     dig[1] = (channel % 100)  / 10;
    91     dig[2] = (channel % 10);
     105    if (!device->OpenPort())
     106        return false;
    92107
    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));
     108    isopen = true;
    101109
    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")
     110    return true;
     111}
     112
     113void FirewireChannel::Close(void)
     114{
     115    VERBOSE(VB_CHANNEL, LOC + "Close()");
     116    if (isopen)
    114117    {
    115         dig[0] |= 0x30;
    116         dig[1] |= 0x30;
    117         dig[2] |= 0x30;
     118        device->ClosePort();
     119        isopen = false;
     120    }
     121}
    118122
    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         };
     123bool FirewireChannel::SwitchToInput(const QString &input, const QString &chan)
     124{
     125    int inputNum = GetInputByName(input);
     126    if (inputNum < 0)
     127        return false;
    125128
    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));
     129    return SetChannelByString(chan);
     130}
    132131
    133         if(!avc1394_transaction_block(fwhandle, fw_opts.node, cmd, 3, 1))
    134         {
    135             VERBOSE(VB_IMPORTANT, "AVC transaction failed.");
    136             return false;
    137         }
     132bool FirewireChannel::SwitchToInput(int newInputNum, bool setstarting)
     133{
     134    (void) setstarting;
    138135
    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;
     136    InputMap::const_iterator it = inputs.find(newInputNum);
     137    if (it == inputs.end() || (*it)->startChanNum.isEmpty())
     138        return false;
    142139
    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));
     140    return SetChannelByString((*it)->startChanNum);
     141}
    149142
    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")
     143QString FirewireChannel::GetDevice(void) const
     144{
     145    return videodevice;
     146}
     147
     148bool FirewireChannel::SetPowerState(bool on)
     149{
     150    if (!isopen)
    157151    {
    158         quadlet_t cmd[3] =
    159         {
    160             SA3250_CMD0 | AVC1394_SA3250_OPERAND_KEY_PRESS,
    161             SA3250_CMD1 | (channel << 8),
    162             SA3250_CMD2,
    163         };
     152        VERBOSE(VB_IMPORTANT, LOC_ERR +
     153                "SetPowerState() called on closed FirewireChannel.");
    164154
    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));
    170 
    171         if (!avc1394_transaction_block(fwhandle, fw_opts.node, cmd, 3, 1))
    172         {
    173             VERBOSE(VB_IMPORTANT, "AVC transaction failed.");
    174             return false;
    175         }
     155        return false;
    176156    }
    177157
    178     return true;
     158    return device->SetPowerState(on);
    179159}
    180160
    181 bool FirewireChannel::OpenFirewire(void)
     161FirewireDevice::PowerState FirewireChannel::GetPowerState(void) const
    182162{
    183     if (!is_supported(fw_opts.model))
     163    if (!isopen)
    184164    {
    185165        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     }
     166                "GetPowerState() called on closed FirewireChannel.");
    190167
    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));
    197         return false;
     168        return FirewireDevice::kAVCPowerQueryFailed;
    198169    }
    199170
    200     VERBOSE(VB_CHANNEL, LOC + "Allocated raw1394 handle " +
    201             QString("for port %1").arg(fw_opts.port));
     171    return device->GetPowerState();
     172}
    202173
    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     }
     174bool FirewireChannel::Retune(void)
     175{
     176    VERBOSE(VB_CHANNEL, LOC + "Retune()");
    212177
    213     if (!avc1394_check_subunit_type(fwhandle, fw_opts.node,
    214                                     AVC1394_SUBUNIT_TYPE_PANEL))
     178    if (FirewireDevice::kAVCPowerOff == GetPowerState())
    215179    {
    216         VERBOSE(VB_IMPORTANT, LOC_ERR + QString("node %1 is not subunit "
    217                 "type panel.").arg(fw_opts.node));
    218         CloseFirewire();
     180        VERBOSE(VB_IMPORTANT, LOC_ERR +
     181                "STB is turned off, must be on to retune.");
     182
    219183        return false;
    220184    }
    221185
    222     // check power, power on if off
    223     if (GetPowerState() == Off)
    224     {
    225         quadlet_t *rval, response, cmd = STB_POWER_ON;
    226         VERBOSE(VB_IMPORTANT, LOC + QString("Powering on (cmd: 0x%1)")
    227                                             .arg(cmd, 0, 16));
    228         rval = avc1394_transaction_block(fwhandle, fw_opts.node, &cmd, 1, 1);
    229         if (rval)
    230         {
    231             response = rval[0];
     186    if (current_channel)
     187        return SetChannelByNumber(current_channel);
    232188
    233             if (AVC1394_MASK_RESPONSE(response) == AVC1394_RESPONSE_ACCEPTED)
    234             {
    235                 VERBOSE(VB_IMPORTANT, LOC + QString("Power on cmd successful "
    236                                                     "(0x%1)")
    237                                                     .arg(response, 0, 16));
    238                 // allow some time for the stb to power on
    239                 sleep(3);
    240                 if (GetPowerState() == Off)
    241                 {
    242                     VERBOSE(VB_IMPORTANT, LOC + "STB is still off!?");
    243                     return false;
    244                 }
    245                 return true;
    246             }
    247             else
    248             {
    249                 VERBOSE(VB_IMPORTANT, LOC + QString("Power on cmd failed "
    250                                                     "(0x%1)")
    251                                                     .arg(response, 0, 16));
    252                 return false;
    253             }
    254         }
    255         else
    256         {
    257             VERBOSE(VB_IMPORTANT, LOC + "Power on cmd failed (no response)");
    258             return false;
    259         }
    260     }
    261     return true;
     189    return false;
    262190}
    263191
    264 void FirewireChannel::CloseFirewire(void)
     192bool FirewireChannel::SetChannelByNumber(int channel)
    265193{
    266     VERBOSE(VB_CHANNEL, LOC + "Releasing raw1394 handle");
    267     raw1394_destroy_handle(fwhandle);
    268 }
     194    current_channel = channel;
    269195
    270 FirewireChannel::PowerState FirewireChannel::GetPowerState(void)
    271 {
    272     quadlet_t *rval, response, cmd = STB_POWER_STATE;
    273 
    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)
     196    if (FirewireDevice::kAVCPowerOff == GetPowerState())
    279197    {
    280         response = rval[0];
     198        VERBOSE(VB_IMPORTANT, LOC_WARN +
     199                "STB is turned off, must be on to set channel.");
    281200
    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         }
     201        SetSIStandard("mpeg");
     202        SetCachedATSCInfo(QString("%1-1").arg(channel));
     203
     204        return true; // signal monitor will call retune later...
    311205    }
    312     VERBOSE(VB_CHANNEL, LOC + "Failed to get STB Power State");
    313     return Failed;
     206
     207    if (!device->SetChannel(fw_opts.model, 0, channel))
     208        return false;
     209
     210    SetSIStandard("mpeg");
     211    SetCachedATSCInfo(QString("%1-1").arg(channel));
     212
     213    return true;
    314214}
  • 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// Qt headers
     8#include <qdeepcopy.h>
     9
     10// MythTV headers
     11#include "linuxfirewiredevice.h"
     12#include "darwinfirewiredevice.h"
     13#include "mythcontext.h"
     14#include "pespacket.h"
     15
     16#define LOC      QString("FireDev(%1): ").arg(m_guid)
     17#define LOC_WARN QString("FireDev(%1), Warning: ").arg(m_guid)
     18#define LOC_ERR  QString("FireDev(%1), Error: ").arg(m_guid)
     19
     20
     21AVCInfo::AVCInfo() :
     22    port(-1), node(-1),
     23    guid(0), specid(0), vendorid(0), modelid(0),
     24    firmware_revision(0), product_name(QString::null)
     25{
     26}
     27
     28AVCInfo::AVCInfo(const AVCInfo &o) :
     29    port(o.port),         node(o.node),
     30    guid(o.guid),         specid(o.specid),
     31    vendorid(o.vendorid), modelid(o.modelid),
     32    firmware_revision(o.firmware_revision),
     33    product_name(QDeepCopy<QString>(o.product_name))
     34{
     35}
     36
     37AVCInfo &AVCInfo::operator=(const AVCInfo &o)
     38{
     39    port     = o.port;
     40    node     = o.node;
     41    guid     = o.guid;
     42    specid   = o.specid;
     43    vendorid = o.vendorid;
     44    modelid  = o.modelid;
     45    firmware_revision = o.firmware_revision;
     46    product_name = QDeepCopy<QString>(o.product_name);
     47
     48    return *this;
     49}
     50
     51QString AVCInfo::GetGUIDString(void) const
     52{
     53    QString g0 = QString("%1").arg((uint32_t) (guid >> 32), 0, 16);
     54    QString g1 = QString("%1").arg((uint32_t) guid, 0, 16);
     55
     56    while (g0.length() < 8)
     57        g0 = "0" + g0;
     58    while (g1.length() < 8)
     59        g1 = "0" + g1;
     60
     61    return QDeepCopy<QString>(g0.upper() + g1.upper());
     62}
     63
     64static void fw_init(QMap<uint64_t,QString> &id_to_model);
     65
     66QMap<uint64_t,QString> FirewireDevice::s_id_to_model;
     67QMutex                 FirewireDevice::s_static_lock;
     68
     69FirewireDevice::FirewireDevice(uint64_t guid, uint subunitid, uint speed) :
     70    m_guid(guid),           m_subunitid(subunitid),
     71    m_speed(speed),
     72    m_last_channel(0),      m_last_crc(0),
     73    m_buffer_cleared(true), m_open_port_cnt(0),
     74    m_lock(false)
     75{
     76}
     77
     78void FirewireDevice::AddListener(TSDataListener *listener)
     79{
     80    QMutexLocker locker(&m_lock);
     81
     82    if (listener)
     83    {
     84        vector<TSDataListener*>::iterator it =
     85            find(m_listeners.begin(), m_listeners.end(), listener);
     86
     87        if (it == m_listeners.end())
     88            m_listeners.push_back(listener);
     89    }
     90
     91    VERBOSE(VB_RECORD, LOC + "AddListener() "<<m_listeners.size());
     92}
     93
     94void FirewireDevice::RemoveListener(TSDataListener *listener)
     95{
     96    QMutexLocker locker(&m_lock);
     97
     98    vector<TSDataListener*>::iterator it = m_listeners.end();
     99
     100    do
     101    {
     102        it = find(m_listeners.begin(), m_listeners.end(), listener);
     103        if (it != m_listeners.end())
     104            m_listeners.erase(it);
     105    }
     106    while (it != m_listeners.end());
     107
     108    VERBOSE(VB_RECORD, LOC + "RemoveListener() "<<m_listeners.size());
     109}
     110
     111bool FirewireDevice::SetPowerState(bool on)
     112{
     113    QMutexLocker locker(&m_lock);
     114
     115    vector<uint8_t> cmd;
     116    vector<uint8_t> ret;
     117
     118    cmd.push_back(kAVCControlCommand);
     119    cmd.push_back(kAVCSubunitTypeUnit | kAVCSubunitIdIgnore);
     120    cmd.push_back(kAVCUnitPowerOpcode);
     121    cmd.push_back((on) ? kAVCPowerStateOn : kAVCPowerStateOff);
     122
     123    QString cmdStr = (on) ? "on" : "off";
     124    VERBOSE(VB_RECORD, LOC + QString("Powering %1").arg(cmdStr));
     125
     126    if (SendAVCCommand(cmd, ret, -1))
     127    {
     128        VERBOSE(VB_IMPORTANT, LOC + "Power on cmd failed (no response)");
     129        return false;
     130    }
     131
     132    if (kAVCAcceptedStatus != ret[0])
     133    {
     134        VERBOSE(VB_IMPORTANT, LOC_ERR +
     135                QString("Power %1 failed").arg(cmdStr));
     136
     137        return false;
     138    }
     139
     140    VERBOSE(VB_RECORD, LOC +
     141            QString("Power %1 cmd sent successfully").arg(cmdStr));
     142
     143    return true;
     144}
     145
     146FirewireDevice::PowerState FirewireDevice::GetPowerState(void)
     147{
     148    QMutexLocker locker(&m_lock);
     149
     150    vector<uint8_t> cmd;
     151    vector<uint8_t> ret;
     152
     153    cmd.push_back(kAVCStatusInquiryCommand);
     154    cmd.push_back(kAVCSubunitTypeUnit | kAVCSubunitIdIgnore);
     155    cmd.push_back(kAVCUnitPowerOpcode);
     156    cmd.push_back(kAVCPowerStateQuery);
     157
     158    VERBOSE(VB_CHANNEL, LOC + "Requesting STB Power State");
     159
     160    if (!SendAVCCommand(cmd, ret, -1))
     161    {
     162        VERBOSE(VB_IMPORTANT, LOC_ERR + "Power cmd failed (no response)");
     163        return kAVCPowerQueryFailed;
     164    }
     165
     166    QString loc = LOC + "STB Power State: ";
     167
     168    if (ret[0] != kAVCResponseImplemented)
     169    {
     170        VERBOSE(VB_CHANNEL, loc + "Query not implemented");
     171        return kAVCPowerUnknown;
     172    }
     173
     174    // check 1st operand..
     175    if (ret[3] == kAVCPowerStateOn)
     176    {
     177        VERBOSE(VB_CHANNEL, loc + "On");
     178        return kAVCPowerOn;
     179    }
     180
     181    if (ret[3] == kAVCPowerStateOff)
     182    {
     183        VERBOSE(VB_CHANNEL, loc + "Off");
     184        return kAVCPowerOff;
     185    }
     186
     187    VERBOSE(VB_IMPORTANT, LOC_ERR + "STB Power State: Unknown Response");
     188
     189    return kAVCPowerUnknown;
     190}
     191
     192bool FirewireDevice::GetSubunitInfo(uint8_t table[32])
     193{
     194    memset(table, 0xff, 32 * sizeof(uint8_t));
     195
     196    for (uint i = 0; i < 8; i++)
     197    {
     198        vector<uint8_t> cmd;
     199        vector<uint8_t> ret;
     200
     201        cmd.push_back(kAVCStatusInquiryCommand);
     202        cmd.push_back(kAVCSubunitTypeUnit | kAVCSubunitIdIgnore);
     203        cmd.push_back(kAVCUnitSubunitInfoOpcode);
     204        cmd.push_back((i<<4) | 0x07);
     205        cmd.push_back(0xFF);
     206        cmd.push_back(0xFF);
     207        cmd.push_back(0xFF);
     208        cmd.push_back(0xFF);
     209
     210        if (!SendAVCCommand(cmd, ret, -1))
     211            return false;
     212
     213        if (ret.size() >= 8)
     214        {
     215            table[(i<<2)+0] = ret[4];
     216            table[(i<<2)+1] = ret[5];
     217            table[(i<<2)+2] = ret[6];
     218            table[(i<<2)+3] = ret[7];
     219        }
     220    }
     221
     222    return true;
     223}
     224
     225bool FirewireDevice::SetChannel(const QString &panel_model,
     226                                uint alt_method, uint channel)
     227{
     228    QMutexLocker locker(&m_lock);
     229
     230    if (!IsSTBSupported(panel_model))
     231    {
     232        VERBOSE(VB_IMPORTANT, LOC_ERR +
     233                QString("Model: '%1' ").arg(panel_model) +
     234                "is not supported by internal channel changer.");
     235        return false;
     236    }
     237
     238    int digit[3];
     239    digit[0] = (channel % 1000) / 100;
     240    digit[1] = (channel % 100)  / 10;
     241    digit[2] = (channel % 10);
     242
     243    if (m_subunitid >= kAVCSubunitIdExtended)
     244        return false;
     245
     246    vector<uint8_t> cmd;
     247    vector<uint8_t> ret;
     248
     249    if ((panel_model.upper() == "GENERIC") ||
     250        (panel_model.upper() == "SA4200HD"))
     251    {
     252        cmd.push_back(kAVCControlCommand);
     253        cmd.push_back(kAVCSubunitTypePanel | m_subunitid);
     254        cmd.push_back(kAVCPanelPassThrough);
     255        cmd.push_back(kAVCPanelKeyTuneFunction | kAVCPanelKeyPress);
     256
     257        cmd.push_back(4); // operand length
     258        cmd.push_back((channel>>8) & 0x0f);
     259        cmd.push_back(channel & 0xff);
     260        cmd.push_back(0x00);
     261        cmd.push_back(0x00);
     262
     263        if (!SendAVCCommand(cmd, ret, -1))
     264            return false;
     265
     266        bool press_ok = (kAVCAcceptedStatus == ret[0]);
     267
     268        cmd[3]= kAVCPanelKeyTuneFunction | kAVCPanelKeyRelease;
     269        if (!SendAVCCommand(cmd, ret, -1))
     270            return false;
     271
     272        bool release_ok = (kAVCAcceptedStatus == ret[0]);
     273
     274        if (!press_ok && !release_ok)
     275        {
     276            VERBOSE(VB_IMPORTANT, LOC_ERR + "Tuning failed");
     277            return false;
     278        }
     279
     280        SetLastChannel(channel);
     281        return true;
     282    }
     283
     284    bool is_mot = ((panel_model.upper() == "DCT-6200") ||
     285                   (panel_model.upper() == "DCT-6212") ||
     286                   (panel_model.upper() == "DCT-6216"));
     287
     288    if (is_mot && !alt_method)
     289    {
     290        for (uint i = 0; i < 3 ;i++)
     291        {
     292            cmd.clear();
     293            cmd.push_back(kAVCControlCommand);
     294            cmd.push_back(kAVCSubunitTypePanel | m_subunitid);
     295            cmd.push_back(kAVCPanelPassThrough);
     296            cmd.push_back(kAVCPanelKey0 + digit[i] | kAVCPanelKeyPress);
     297            cmd.push_back(0x00);
     298            cmd.push_back(0x00);
     299            cmd.push_back(0x00);
     300            cmd.push_back(0x00);
     301
     302            if (!SendAVCCommand(cmd, ret, -1))
     303                return false;
     304
     305            usleep(500000);
     306        }
     307
     308        SetLastChannel(channel);
     309        return true;
     310    }
     311
     312    if (is_mot && alt_method)
     313    {
     314        cmd.push_back(kAVCControlCommand);
     315        cmd.push_back(kAVCSubunitTypePanel | m_subunitid);
     316        cmd.push_back(kAVCPanelPassThrough);
     317        cmd.push_back(kAVCPanelKeyTuneFunction | kAVCPanelKeyPress);
     318
     319        cmd.push_back(4); // operand length
     320        cmd.push_back((channel>>8) & 0x0f);
     321        cmd.push_back(channel & 0xff);
     322        cmd.push_back(0x00);
     323        cmd.push_back(0xff);
     324
     325        if (!SendAVCCommand(cmd, ret, -1))
     326            return false;
     327
     328        SetLastChannel(channel);
     329        return true;
     330    }
     331
     332    if (panel_model.upper() == "SA3250HD")
     333    {
     334        cmd.push_back(kAVCControlCommand);
     335        cmd.push_back(kAVCSubunitTypePanel | m_subunitid);
     336        cmd.push_back(kAVCPanelPassThrough);
     337        cmd.push_back(kAVCPanelKeyTuneFunction | kAVCPanelKeyRelease);
     338
     339        cmd.push_back(4); // operand length
     340        cmd.push_back(0x30 | digit[2]);
     341        cmd.push_back(0x30 | digit[1]);
     342        cmd.push_back(0x30 | digit[0]);
     343        cmd.push_back(0xff);
     344
     345        if (!SendAVCCommand(cmd, ret, -1))
     346            return false;
     347
     348        cmd[5] = 0x30 | digit[0];
     349        cmd[6] = 0x30 | digit[1];
     350        cmd[7] = 0x30 | digit[2];
     351
     352        if (!SendAVCCommand(cmd, ret, -1))
     353            return false;
     354
     355        SetLastChannel(channel);
     356        return true;
     357    }
     358
     359    return false;
     360}
     361
     362void FirewireDevice::BroadcastToListeners(
     363    const unsigned char *data, uint dataSize)
     364{
     365    if ((dataSize >= TSPacket::SIZE) && (data[0] == SYNC_BYTE) &&
     366        ((data[1] & 0x1f) == 0) && (data[2] == 0))
     367    {
     368        ProcessPATPacket(*((const TSPacket*)data));
     369    }
     370
     371    vector<TSDataListener*>::iterator it = m_listeners.begin();
     372    for (; it != m_listeners.end(); ++it)
     373        (*it)->AddData(data, dataSize);
     374}
     375
     376void FirewireDevice::SetLastChannel(const uint channel)
     377{
     378    m_buffer_cleared = (channel == m_last_channel);
     379    m_last_channel   = channel;
     380
     381    VERBOSE(VB_IMPORTANT, QString("SetLastChannel(%1): cleared: %2")
     382            .arg(channel).arg(m_buffer_cleared ? "yes" : "no"));
     383}
     384
     385void FirewireDevice::ProcessPATPacket(const TSPacket &tspacket)
     386{
     387    if (!tspacket.TransportError() && !tspacket.ScramplingControl() &&
     388        tspacket.HasPayload() && tspacket.PayloadStart() && !tspacket.PID())
     389    {
     390        PESPacket pes = PESPacket::View(tspacket);
     391        uint crc = pes.CalcCRC();
     392        m_buffer_cleared |= (crc != m_last_crc);
     393        m_last_crc = crc;
     394        VERBOSE(VB_RECORD, LOC +
     395                QString("ProcessPATPacket: CRC 0x%1 cleared: %2")
     396                .arg(crc,0,16).arg(m_buffer_cleared ? "yes" : "no"));
     397    }
     398    else
     399    {
     400        VERBOSE(VB_IMPORTANT, LOC_ERR + "Can't handle large PAT's");
     401    }
     402}
     403
     404QString FirewireDevice::GetModelName(uint vendor_id, uint model_id)
     405{
     406    QMutexLocker locker(&s_static_lock);
     407    if (s_id_to_model.empty())
     408        fw_init(s_id_to_model);
     409
     410    QString ret = s_id_to_model[(((uint64_t) vendor_id) << 32) | model_id];
     411
     412    if (ret.isEmpty())
     413        return "GENERIC";
     414
     415    return QDeepCopy<QString>(ret);
     416}
     417
     418vector<AVCInfo> FirewireDevice::GetSTBList(void)
     419{
     420    vector<AVCInfo> list;
     421
     422#ifdef USING_LINUX_FIREWIRE
     423    list = LinuxFirewireDevice::GetSTBList();
     424#elif USING_OSX_FIREWIRE
     425    list = DarwinFirewireDevice::GetSTBList();
     426#endif
     427
     428//#define DEBUG_AVC_INFO
     429#ifdef DEBUG_AVC_INFO
     430    AVCInfo info;
     431    info.guid     = 0x0016928a7b600001ULL;
     432    info.specid   = 0x0;
     433    info.vendorid = 0x000014f8;
     434    info.modelid  = 0x00001072;
     435    info.firmware_revision = 0x0;
     436    info.product_name = "Explorer 4200 HD";
     437    list.push_back(info);
     438
     439    info.guid     = 0xff2145a850e39810ULL;
     440    info.specid   = 0x0;
     441    info.vendorid = 0x000014f8;
     442    info.modelid  = 0x00000be0;
     443    info.firmware_revision = 0x0;
     444    info.product_name = "Explorer 3250 HD";
     445    list.push_back(info);
     446#endif // DEBUG_AVC_INFO
     447
     448    return list;
     449}
     450
     451bool FirewireDevice::IsSubunitType(
     452    const uint8_t unit_table[32], IEEE1394UnitAddress subunit_type)
     453{
     454    for (uint i = 0; i < 32; i++)
     455    {
     456        int subunit = unit_table[i];
     457        if ((subunit != 0xff) &&
     458            (subunit & kAVCSubunitTypeUnit) == subunit_type)
     459        {
     460            return true;
     461        }
     462    }
     463
     464    return false;
     465}
     466
     467QString FirewireDevice::GetSubunitInfoString(const uint8_t table[32])
     468{
     469    QString str = "Subunit Types: ";
     470
     471    if (IsSubunitType(table, kAVCSubunitTypeVideoMonitor))
     472        str += "Video Monitor, ";
     473    if (IsSubunitType(table, kAVCSubunitTypeAudio))
     474        str += "Audio, ";
     475    if (IsSubunitType(table, kAVCSubunitTypePrinter))
     476        str += "Printer, ";
     477    if (IsSubunitType(table, kAVCSubunitTypeDiscRecorder))
     478        str += "Disk Recorder, ";
     479    if (IsSubunitType(table, kAVCSubunitTypeTapeRecorder))
     480        str += "Tape Recorder, ";
     481    if (IsSubunitType(table, kAVCSubunitTypeTuner))
     482        str += "Tuner, ";
     483    if (IsSubunitType(table, kAVCSubunitTypeCA))
     484        str += "CA, ";
     485    if (IsSubunitType(table, kAVCSubunitTypeVideoCamera))
     486        str += "Camera, ";
     487    if (IsSubunitType(table, kAVCSubunitTypePanel))
     488        str += "Panel, ";
     489    if (IsSubunitType(table, kAVCSubunitTypeBulletinBoard))
     490        str += "Bulletin Board, ";
     491    if (IsSubunitType(table, kAVCSubunitTypeCameraStorage))
     492        str += "Camera Storage, ";
     493    if (IsSubunitType(table, kAVCSubunitTypeMusic))
     494        str += "Music, ";
     495    if (IsSubunitType(table, kAVCSubunitTypeVendorUnique))
     496        str += "Vendor Unique, ";
     497
     498    return str;
     499}
     500
     501static void fw_init(QMap<uint64_t,QString> &id_to_model)
     502{
     503    id_to_model[0x11e6ULL << 32 | 0x0be0] = "SA3250HD";
     504    id_to_model[0x14f8ULL << 32 | 0x0be0] = "SA3250HD";
     505    id_to_model[0x1692ULL << 32 | 0x0be0] = "SA3250HD";
     506
     507    id_to_model[0x11e6ULL << 32 | 0x1072] = "SA4200HD";
     508    id_to_model[0x14f8ULL << 32 | 0x1072] = "SA4200HD";
     509    id_to_model[0x1692ULL << 32 | 0x1072] = "SA4200HD";
     510
     511    const uint64_t motorolla_vendor_ids[] =
     512    {   /* 6200 */
     513        0x0ce5,    0x0e5c,    0x1225,    0x0f9f,    0x1180,
     514        0x12c9,    0x11ae,    0x152f,    0x14e8,    0x16b5,    0x1371,
     515        /* 6412 */
     516        0x0f9f,    0x152f,
     517        /* 6416 */
     518        0x17ee,
     519    };
     520    const uint motorolla_vendor_id_cnt =
     521        sizeof(motorolla_vendor_ids) / sizeof(uint32_t);
     522
     523    const uint32_t motorolla_6200model_ids[] = { 0x620a, 0x6200, };
     524    const uint32_t motorolla_6212model_ids[] = { 0x64ca, 0x64cb, };
     525    const uint32_t motorolla_6216model_ids[] = { 0x646b, };
     526
     527    for (uint i = 0; i < motorolla_vendor_id_cnt; i++)
     528        for (uint j = 0; j < 2; j++)
     529            id_to_model[motorolla_vendor_ids[i] << 32 |
     530                        motorolla_6200model_ids[j]] = "DCT-6200";
     531
     532    for (uint i = 0; i < motorolla_vendor_id_cnt; i++)
     533        for (uint j = 0; j < 2; j++)
     534            id_to_model[motorolla_vendor_ids[i] << 32 |
     535                        motorolla_6212model_ids[j]] = "DCT-6212";
     536
     537    for (uint i = 0; i < motorolla_vendor_id_cnt; i++)
     538        for (uint j = 0; j < 2; j++)
     539            id_to_model[motorolla_vendor_ids[i] << 32 |
     540                        motorolla_6216model_ids[j]] = "DCT-6216";
     541}
  • libs/libmythtv/videosource.h

     
    413413    DiSEqCDevTree      *diseqc_tree;
    414414};
    415415
     416class FirewireGUID;
     417class FirewireModel : public ComboBoxSetting, public CaptureCardDBStorage
     418{
     419    Q_OBJECT
     420
     421  public:
     422    FirewireModel(const CaptureCard &parent, const FirewireGUID*);
     423
     424  public slots:
     425    void SetGUID(const QString&);
     426
     427  private:
     428    const FirewireGUID *guid;
     429};
     430
     431class FirewireDesc : public TransLabelSetting
     432{
     433    Q_OBJECT
     434
     435  public:
     436    FirewireDesc(const FirewireGUID *_guid) :
     437        TransLabelSetting(), guid(_guid) { }
     438
     439  public slots:
     440    void SetGUID(const QString&);
     441
     442  private:
     443    const FirewireGUID *guid;
     444};
     445
     446
    416447class CaptureCardGroup : public TriggeredConfigurationGroup
    417448{
    418449    Q_OBJECT
  • 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   darwinavcinfo.h
     388            SOURCES += darwinfirewiredevice.cpp darwinavcinfo.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
     399        using_libavc_5_3:DEFINES += USING_LIBAVC_5_3
    397400    }
    398401
    399402    # Support for set top boxes (Nokia DBox2 etc.)
  • 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/scanwizardhelpers.h

     
    4949class AnalogPane;
    5050class STPane;
    5151class DVBUtilsImportPane;
     52class QApplication;
    5253
    5354/// Max range of the ScanProgressPopup progress bar
    5455#define PROGRESS_MAX  1000
     
    8687
    8788class ScannerEvent : public QCustomEvent
    8889{
     90    friend class QApplication; // to suppress Apple gcc warning
     91
    8992  public:
    9093    enum TYPE
    9194    {
  • 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 = "1173";
     13const QString currentDatabaseVersion = "1174";
    1414
    1515static bool UpdateDBVersionNumber(const QString &newnumber);
    1616static bool performActualUpdate(const QString updates[], QString version,
     
    27822782            return false;
    27832783    }
    27842784
     2785    if (dbver == "1173")
     2786    {
     2787        const QString updates[] = {
     2788"DELETE FROM capturecard WHERE cardtype = 'FIREWIRE';",
     2789""
     2790};
     2791        if (!performActualUpdate(updates, "1174", dbver))
     2792            return false;
     2793    }
     2794
    27852795//"ALTER TABLE cardinput DROP COLUMN preference;" in 0.22
    27862796//"ALTER TABLE channel DROP COLUMN atscsrcid;" in 0.22
    27872797//"ALTER TABLE recordedmarkup DROP COLUMN offset;" in 0.22
     
    27902800//"ALTER TABLE cardinput DROP lnb_lof_switch;" in 0.22
    27912801//"ALTER TABLE cardinput DROP lnb_lof_hi;" in 0.22
    27922802//"ALTER TABLE cardinput DROP lnb_lof_lo;" in 0.22
     2803//"ALTER TABLE capturecard DROP firewire_port;" in 0.22
     2804//"ALTER TABLE capturecard DROP firewire_node;" in 0.22
    27932805
    27942806    return true;
    27952807}
  • 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// POSIX headers
     10#include <pthread.h>
     11
     12// OS X headers
     13#undef always_inline
     14#include <IOKit/IOMessage.h>
     15#include <IOKit/IOKitLib.h>
     16#include <IOKit/firewire/IOFireWireLib.h>
     17#include <IOKit/firewire/IOFireWireLibIsoch.h>
     18#include <IOKit/firewire/IOFireWireFamilyCommon.h>
     19#include <IOKit/avc/IOFireWireAVCLib.h>
     20
     21// Std C++ headers
     22#include <vector>
     23using namespace std;
     24
     25// MythTV headers
     26#include "darwinfirewiredevice.h"
     27#include "darwinavcinfo.h"
     28#include "mythcontext.h"
     29
     30// Apple Firewire example headers
     31#include <AVCVideoServices/StringLogger.h>
     32#include <AVCVideoServices/MPEG2Receiver.h>
     33
     34// header not used because it also requires MPEG2Transmitter.h
     35//#include <AVCVideoServices/FireWireMPEG.h>
     36namespace AVS
     37{
     38    IOReturn CreateMPEG2Receiver(
     39        MPEG2Receiver           **ppReceiver,
     40        DataPushProc              dataPushProcHandler,
     41        void                     *pDataPushProcRefCon = nil,
     42        MPEG2ReceiverMessageProc  messageProcHandler  = nil,
     43        void                     *pMessageProcRefCon  = nil,
     44        StringLogger             *stringLogger        = nil,
     45        IOFireWireLibNubRef       nubInterface        = nil,
     46        unsigned int              cyclesPerSegment    =
     47            kCyclesPerReceiveSegment,
     48        unsigned int              numSegments         =
     49            kNumReceiveSegments,
     50        bool                      doIRMAllocations    = false);
     51    IOReturn DestroyMPEG2Receiver(MPEG2Receiver *pReceiver);
     52}
     53
     54#define LOC      QString("DFireDev(): ")
     55#define LOC_WARN QString("DFireDev(), Warning: ")
     56#define LOC_ERR  QString("DFireDev(), Error: ")
     57
     58#define kAnyAvailableIsochChannel 0xFFFFFFFF
     59#define kNoDataTimeout            250 /* msec */
     60
     61static IOReturn dfd_tspacket_handler_thunk(
     62    long unsigned int tsPacketCount, UInt32 **ppBuf, void *callback_data);
     63static void dfd_update_device_list(void *dfd, io_iterator_t iterator);
     64static void dfd_streaming_log_message(char *pString);
     65
     66class DFDPriv
     67{
     68  public:
     69    DFDPriv() :
     70        controller_thread_cf_ref(NULL), controller_thread_running(false),
     71        notify_port(NULL), notify_source(NULL), deviter(NULL),
     72        actual_fwchan(-1), is_streaming(false), avstream(NULL), logger(NULL)
     73    {
     74        logger = new AVS::StringLogger(dfd_streaming_log_message);
     75    }
     76
     77    ~DFDPriv()
     78    {
     79        avcinfo_list_t::iterator it = devices.begin();
     80        for (; it != devices.end(); ++it)
     81            delete (*it);
     82        devices.clear();
     83
     84        if (logger)
     85        {
     86            delete logger;
     87            logger = NULL;
     88        }
     89    }
     90
     91    pthread_t                 controller_thread;
     92    CFRunLoopRef              controller_thread_cf_ref;
     93    bool                      controller_thread_running;
     94
     95    IONotificationPortRef     notify_port;
     96    CFRunLoopSourceRef        notify_source;
     97    io_iterator_t             deviter;
     98
     99    int                       actual_fwchan;
     100    bool                      is_streaming;
     101    AVS::MPEG2Receiver       *avstream;
     102    AVS::StringLogger        *logger;
     103
     104    avcinfo_list_t            devices;
     105};
     106
     107DarwinFirewireDevice::DarwinFirewireDevice(
     108    uint64_t guid, uint subunitid, uint speed) :
     109    FirewireDevice(guid, subunitid, speed),
     110    m_node(0), m_priv(new DFDPriv())
     111{
     112}
     113
     114DarwinFirewireDevice::~DarwinFirewireDevice()
     115{
     116    if (IsPortOpen())
     117    {
     118        VERBOSE(VB_IMPORTANT, LOC_ERR + "ctor called with open port");
     119        while (IsPortOpen())
     120            ClosePort();
     121    }
     122
     123    if (m_priv)
     124    {
     125        delete m_priv;
     126        m_priv = NULL;
     127    }
     128}
     129
     130void DarwinFirewireDevice::RunController(void)
     131{
     132    m_priv->controller_thread_cf_ref = CFRunLoopGetCurrent();
     133
     134    // Set up IEEE-1394 bus change notification
     135    mach_port_t master_port;
     136    int ret = IOMasterPort(bootstrap_port, &master_port);
     137    if (kIOReturnSuccess == ret)
     138    {
     139        m_priv->notify_port   = IONotificationPortCreate(master_port);
     140        m_priv->notify_source = IONotificationPortGetRunLoopSource(
     141            m_priv->notify_port);
     142
     143        CFRunLoopAddSource(m_priv->controller_thread_cf_ref,
     144                           m_priv->notify_source,
     145                           kCFRunLoopDefaultMode);
     146
     147        ret = IOServiceAddMatchingNotification(
     148            m_priv->notify_port, kIOMatchedNotification,
     149            IOServiceMatching("IOFireWireAVCUnit"),
     150            dfd_update_device_list, this, &m_priv->deviter);
     151    }
     152
     153    if (kIOReturnSuccess == ret)
     154        dfd_update_device_list(this, m_priv->deviter);
     155
     156    m_priv->controller_thread_running = true;
     157
     158    if (kIOReturnSuccess == ret)
     159        CFRunLoopRun();
     160
     161    QMutexLocker locker(&m_lock); // ensure that controller_thread_running seen
     162
     163    m_priv->controller_thread_running = false;
     164}
     165
     166void DarwinFirewireDevice::StartController(void)
     167{
     168    m_lock.unlock();
     169
     170    pthread_create(&m_priv->controller_thread, NULL,
     171                   dfd_controller_thunk, this);
     172
     173    m_lock.lock();
     174    while (!m_priv->controller_thread_running)
     175    {
     176        m_lock.unlock();
     177        usleep(5000);
     178        m_lock.lock();
     179    }
     180}
     181
     182void DarwinFirewireDevice::StopController(void)
     183{
     184    if (!m_priv->controller_thread_running)
     185        return;
     186
     187    if (m_priv->deviter)
     188    {
     189        IOObjectRelease(m_priv->deviter);
     190        m_priv->deviter = NULL;
     191    }
     192   
     193    if (m_priv->notify_source)
     194    {
     195        CFRunLoopSourceInvalidate(m_priv->notify_source);
     196        m_priv->notify_source = NULL;
     197    }
     198
     199    if (m_priv->notify_port)
     200    {
     201        IONotificationPortDestroy(m_priv->notify_port);
     202        m_priv->notify_port = NULL;
     203    }
     204
     205    CFRunLoopStop(m_priv->controller_thread_cf_ref);
     206   
     207    while (m_priv->controller_thread_running)
     208    {
     209        m_lock.unlock();
     210        usleep(100 * 1000);
     211        m_lock.lock();
     212    }
     213}
     214
     215bool DarwinFirewireDevice::OpenPort(void)
     216{
     217    QMutexLocker locker(&m_lock);
     218
     219    VERBOSE(VB_RECORD, LOC + "OpenPort()");
     220
     221    if (GetInfoPtr() && GetInfoPtr()->IsOpen())
     222    {
     223        m_open_port_cnt++;
     224        return true;
     225    }
     226
     227    StartController();
     228
     229    if (!m_priv->controller_thread_running)
     230    {
     231        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to start firewire thread.");
     232        return false;
     233    }
     234
     235    if (!GetInfoPtr())
     236    {
     237        VERBOSE(VB_IMPORTANT, LOC_ERR + "No IEEE-1394 device at " +
     238                QString("guid: 0x%1").arg(m_guid,0,16));
     239       
     240        StopController();
     241        return false;
     242    }
     243
     244    VERBOSE(VB_RECORD, LOC + "Opening AVC Device");
     245    VERBOSE(VB_RECORD, LOC + GetSubunitInfoString(GetInfoPtr()->unit_table));
     246
     247    if (!IsSubunitType(GetInfoPtr()->unit_table, kAVCSubunitTypeTuner) ||
     248        !IsSubunitType(GetInfoPtr()->unit_table, kAVCSubunitTypePanel))
     249    {
     250        VERBOSE(VB_IMPORTANT, LOC_ERR + QString("No STB at guid: 0x%1")
     251                .arg(m_guid,0,16));
     252
     253        StopController();
     254        return false;
     255    }
     256
     257    bool ok = GetInfoPtr()->Open(m_priv->controller_thread_cf_ref);
     258    if (!ok)
     259    {
     260        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to get handle for port");
     261
     262        return false;
     263    }
     264
     265    // TODO we should set m_node...
     266
     267    m_open_port_cnt++;
     268
     269    return true;
     270}
     271
     272bool DarwinFirewireDevice::ClosePort(void)
     273{
     274    QMutexLocker locker(&m_lock);
     275
     276    VERBOSE(VB_RECORD, LOC + "ClosePort()");
     277
     278    if (m_open_port_cnt < 1)
     279        return false;
     280
     281    m_open_port_cnt--;
     282
     283    if (m_open_port_cnt != 0)
     284        return true;
     285
     286    if (GetInfoPtr() && GetInfoPtr()->IsOpen())
     287    {
     288        VERBOSE(VB_RECORD, LOC + "Closing AVC Device");
     289
     290        GetInfoPtr()->Close();
     291    }
     292
     293    StopController();
     294
     295    return true;
     296}
     297
     298bool DarwinFirewireDevice::OpenAVStream(void)
     299{
     300    if (IsAVStreamOpen())
     301        return true;
     302
     303    int max_speed = GetMaxSpeed();
     304    VERBOSE(VB_IMPORTANT, "Max Speed: "<<max_speed<<" Our speed: "<<m_speed);
     305    m_speed = min((uint)max_speed, m_speed);
     306
     307    uint fwchan = 0;
     308    bool streaming = IsSTBStreaming(&fwchan);
     309    VERBOSE(VB_IMPORTANT, QString("STB is %1already streaming on fwchan: %2")
     310            .arg(streaming?"":"not ").arg(fwchan));
     311
     312    // TODO we should use the stream if it already exists,
     313    //      this is especially true if it is a broadcast stream...
     314
     315    int ret = AVS::CreateMPEG2Receiver(
     316        &m_priv->avstream,
     317        dfd_tspacket_handler_thunk, this,
     318        dfd_stream_msg, this,
     319        m_priv->logger /* StringLogger */,
     320        GetInfoPtr()->fw_handle,
     321        AVS::kCyclesPerReceiveSegment,
     322        AVS::kNumReceiveSegments,
     323        true /* p2p */);
     324
     325    if (kIOReturnSuccess != ret)
     326    {
     327        VERBOSE(VB_IMPORTANT, LOC_ERR + "Couldn't create A/V stream object");
     328        return false;
     329    }
     330
     331    m_priv->avstream->registerNoDataNotificationCallback(
     332        dfd_no_data_notification, this, kNoDataTimeout);
     333
     334    return true;
     335}
     336
     337int DarwinFirewireDevice::GetMaxSpeed(void) // oMPR read
     338{
     339    IOFireWireLibDeviceRef fw_handle = GetInfoPtr()->fw_handle;
     340    io_object_t dev = (*fw_handle)->GetDevice(fw_handle);
     341
     342    FWAddress addr(0xffff, 0xf0000900, m_node);
     343    uint32_t val;
     344    int ret = (*fw_handle)->ReadQuadlet(
     345        fw_handle, dev, &addr, (UInt32*) &val, false, 0);
     346
     347    return (int)((ret == kIOReturnSuccess) ? ((val>>30) & 0x3) : 0xffffffff);
     348}
     349
     350bool DarwinFirewireDevice::IsSTBStreaming(uint *fw_channel)
     351{
     352    IOFireWireLibDeviceRef fw_handle = GetInfoPtr()->fw_handle;
     353    io_object_t dev = (*fw_handle)->GetDevice(fw_handle);
     354
     355    FWAddress addr(0xffff, 0xf0000904, m_node);
     356    uint32_t val;
     357    int ret = (*fw_handle)->ReadQuadlet(
     358        fw_handle, dev, &addr, (UInt32*) &val, false, 0);
     359
     360    if (ret != kIOReturnSuccess)
     361        return false;
     362
     363    if (val & (kIOFWPCRBroadcast | kIOFWPCRP2PCount))
     364    {
     365        if (fw_channel)
     366            *fw_channel = (val & kIOFWPCRChannel) >> kIOFWPCRChannelPhase;
     367
     368        return true;
     369    }
     370
     371    return false;
     372}
     373
     374bool DarwinFirewireDevice::CloseAVStream(void)
     375{
     376    if (!m_priv->avstream)
     377        return true;
     378
     379    StopStreaming();
     380
     381    VERBOSE(VB_RECORD, LOC + "Destroying A/V stream object");
     382    AVS::DestroyMPEG2Receiver(m_priv->avstream);
     383    m_priv->avstream = NULL;
     384
     385    return true;
     386}
     387
     388bool DarwinFirewireDevice::IsAVStreamOpen(void) const
     389{
     390    return m_priv->avstream;
     391}
     392
     393bool DarwinFirewireDevice::StartStreaming(void)
     394{
     395    if (m_priv->is_streaming)
     396        return m_priv->is_streaming;
     397
     398    VERBOSE(VB_RECORD, LOC + "Starting A/V streaming");
     399
     400    if (!IsAVStreamOpen() && !OpenAVStream())
     401    {
     402        VERBOSE(VB_IMPORTANT, LOC + "Starting A/V streaming: FAILED");
     403        return false;
     404    }
     405
     406    m_priv->avstream->setReceiveIsochChannel(kAnyAvailableIsochChannel);
     407    m_priv->avstream->setReceiveIsochSpeed((IOFWSpeed) m_speed);
     408    int ret = m_priv->avstream->startReceive();
     409
     410    m_priv->is_streaming = (kIOReturnSuccess == ret);
     411
     412    VERBOSE(VB_IMPORTANT, LOC + "Starting A/V streaming: "
     413            <<((m_priv->is_streaming)?"success":"failure"));
     414
     415    return m_priv->is_streaming;
     416}
     417
     418bool DarwinFirewireDevice::StopStreaming(void)
     419{
     420    if (!m_priv->is_streaming)
     421        return true;
     422
     423    VERBOSE(VB_RECORD, LOC + "Stopping A/V streaming");
     424
     425    bool ok = (kIOReturnSuccess == m_priv->avstream->stopReceive());
     426    m_priv->is_streaming = !ok;
     427
     428    if (!ok)
     429    {
     430        VERBOSE(VB_RECORD, LOC_ERR + "Failed to stop A/V streaming");
     431        return false;
     432    }
     433
     434    VERBOSE(VB_RECORD, LOC + "Stopped A/V streaming");
     435    return true;
     436}
     437
     438bool DarwinFirewireDevice::SendAVCCommand(const vector<uint8_t> &cmd,
     439                                          vector<uint8_t>       &result,
     440                                          int                   retry_cnt)
     441{
     442    return GetInfoPtr()->SendAVCCommand(cmd, result, retry_cnt);
     443}
     444
     445bool DarwinFirewireDevice::IsPortOpen(void) const
     446{
     447    QMutexLocker locker(&m_lock);
     448
     449    if (!GetInfoPtr())
     450        return false;
     451
     452    return GetInfoPtr()->IsOpen();
     453}
     454
     455void DarwinFirewireDevice::AddListener(TSDataListener *listener)
     456{
     457    FirewireDevice::AddListener(listener);
     458
     459    QMutexLocker locker(&m_lock);
     460    if (!m_listeners.empty())
     461        StartStreaming();
     462}
     463
     464void DarwinFirewireDevice::RemoveListener(TSDataListener *listener)
     465{
     466    FirewireDevice::RemoveListener(listener);
     467
     468    QMutexLocker locker(&m_lock);
     469    if (m_priv->is_streaming && m_listeners.empty())
     470    {
     471        StopStreaming();
     472        CloseAVStream();
     473    }
     474}
     475
     476void DarwinFirewireDevice::BroadcastToListeners(
     477    const unsigned char *data, uint dataSize)
     478{
     479    QMutexLocker locker(&m_lock);
     480    FirewireDevice::BroadcastToListeners(data, dataSize);
     481}
     482
     483void DarwinFirewireDevice::PrintNoDataMessage(void)
     484{
     485    VERBOSE(VB_IMPORTANT, LOC_WARN +
     486            QString("No Input in %1 msecs").arg(kNoDataTimeout));
     487}
     488
     489void DarwinFirewireDevice::ProcessStreamingMessage(
     490    uint32_t msg, uint32_t param1, uint32_t param2)
     491{
     492    int plug_number = 0;
     493
     494    if (AVS::kMpeg2ReceiverAllocateIsochPort == msg)
     495    {
     496        int speed = param1, fw_channel = param2;
     497
     498        bool ok = UpdatePlugRegister(
     499            plug_number, fw_channel, speed, true, false);
     500
     501        VERBOSE(VB_IMPORTANT, LOC + QString("AllocateIsochPort(%1,%2) %3")
     502                .arg(fw_channel).arg(speed).arg(((ok)?"ok":"error")));
     503    }
     504    else if (AVS::kMpeg2ReceiverReleaseIsochPort == msg)
     505    {
     506        int ret = UpdatePlugRegister(plug_number, -1, -1, false, true);
     507
     508        VERBOSE(VB_IMPORTANT, LOC + "ReleaseIsochPort "
     509                <<((kIOReturnSuccess == ret)?"ok":"error"));
     510    }
     511    else if (AVS::kMpeg2ReceiverDCLOverrun == msg)
     512    {
     513        VERBOSE(VB_IMPORTANT, LOC_ERR + "DCL Overrun");
     514    }
     515    else if (AVS::kMpeg2ReceiverReceivedBadPacket == msg)
     516    {
     517        VERBOSE(VB_IMPORTANT, LOC_ERR + "Received Bad Packet");
     518    }
     519    else
     520    {
     521        VERBOSE(VB_GENERAL, LOC +
     522                QString("Streaming Message: %1").arg(msg));
     523    }
     524}
     525
     526vector<AVCInfo> DarwinFirewireDevice::GetSTBList(void)
     527{
     528    vector<AVCInfo> list;
     529
     530    {
     531        DarwinFirewireDevice dev(0,0,0);
     532
     533        dev.m_lock.lock();
     534        dev.StartController();
     535        dev.m_lock.unlock();
     536
     537        list = dev.GetSTBListPrivate();
     538
     539        dev.m_lock.lock();
     540        dev.StopController();
     541        dev.m_lock.unlock();
     542    }
     543
     544    return list;
     545}
     546
     547vector<AVCInfo> DarwinFirewireDevice::GetSTBListPrivate(void)
     548{
     549    VERBOSE(VB_IMPORTANT, "GetSTBListPrivate -- begin");
     550    QMutexLocker locker(&m_lock);
     551    VERBOSE(VB_IMPORTANT, "GetSTBListPrivate -- got lock");
     552
     553    vector<AVCInfo> list;
     554
     555    avcinfo_list_t::iterator it = m_priv->devices.begin();
     556    for (; it != m_priv->devices.end(); ++it)
     557    {
     558        if (IsSubunitType((*it)->unit_table, kAVCSubunitTypeTuner) &&
     559            IsSubunitType((*it)->unit_table, kAVCSubunitTypePanel))
     560        {
     561            list.push_back(*(*it));
     562        }
     563    }
     564
     565    VERBOSE(VB_IMPORTANT, "GetSTBListPrivate -- end");
     566    return list;
     567}
     568
     569void DarwinFirewireDevice::UpdateDeviceListItem(uint64_t guid, void *pitem)
     570{
     571    QMutexLocker locker(&m_lock);
     572
     573    avcinfo_list_t::iterator it = m_priv->devices.find(guid);
     574
     575    if (it == m_priv->devices.end())
     576    {
     577        DarwinAVCInfo *ptr = new DarwinAVCInfo();
     578
     579        VERBOSE(VB_IMPORTANT, "Adding device list item 0x"
     580                <<hex<<guid<<" ptr: "<<ptr<<dec);
     581
     582        m_priv->devices[guid] = ptr;
     583        it = m_priv->devices.find(guid);
     584    }
     585
     586    io_object_t &item = *((io_object_t*) pitem);
     587    if (it != m_priv->devices.end())
     588    {
     589        (*it)->Update(guid, this, m_priv->notify_port,
     590                      m_priv->controller_thread_cf_ref, item);
     591    }
     592}
     593
     594DarwinAVCInfo *DarwinFirewireDevice::GetInfoPtr(void)
     595{
     596    avcinfo_list_t::iterator it = m_priv->devices.find(m_guid);
     597    return (it == m_priv->devices.end()) ? NULL : *it;
     598}
     599
     600const DarwinAVCInfo *DarwinFirewireDevice::GetInfoPtr(void) const
     601{
     602    avcinfo_list_t::iterator it = m_priv->devices.find(m_guid);
     603    return (it == m_priv->devices.end()) ? NULL : *it;
     604}
     605
     606
     607bool DarwinFirewireDevice::UpdatePlugRegisterPrivate(
     608    uint plug_number, int new_fw_chan, int new_speed,
     609    bool add_plug, bool remove_plug)
     610{
     611    if (!GetInfoPtr())
     612        return false;
     613
     614    IOFireWireLibDeviceRef fw_handle = GetInfoPtr()->fw_handle;
     615    if (!fw_handle)
     616        return false;
     617
     618    io_object_t dev = (*fw_handle)->GetDevice(fw_handle);
     619
     620    // Read the register
     621    uint      low_addr = kPCRBaseAddress + 4 + (plug_number << 2);
     622    FWAddress addr(0xffff, low_addr, m_node);
     623    uint32_t  old_plug_val;
     624    if (kIOReturnSuccess != (*fw_handle)->ReadQuadlet(
     625            fw_handle, dev, &addr, (UInt32*) &old_plug_val, false, 0))
     626    {
     627        return false;
     628    }
     629
     630    int old_plug_cnt = (old_plug_val >> 24) & 0x3f;
     631    int old_fw_chan  = (old_plug_val >> 16) & 0x3f;
     632    int old_speed    = (old_plug_val >> 14) & 0x03;
     633
     634    int new_plug_cnt = (int) old_plug_cnt;
     635    new_plug_cnt += ((add_plug) ? 1 : 0) - ((remove_plug) ? 1 : 0);
     636    if ((new_plug_cnt > 0x3f) || (new_plug_cnt < 0))
     637    {
     638        VERBOSE(VB_IMPORTANT, LOC_ERR + "Invalid Plug Count "<<new_plug_cnt);
     639
     640        return false;
     641    }
     642
     643    new_fw_chan = (new_fw_chan >= 0) ? new_fw_chan : old_fw_chan;
     644    if (old_plug_cnt && (new_fw_chan != old_fw_chan))
     645    {
     646        VERBOSE(VB_IMPORTANT, LOC_WARN +
     647                "Ignoring FWChan change request, plug already open");
     648
     649        new_fw_chan = old_fw_chan;
     650    }
     651
     652    new_speed = (new_speed >= 0) ? new_speed : old_speed;
     653    if (old_plug_cnt && (new_speed != old_speed))
     654    {
     655        VERBOSE(VB_IMPORTANT, LOC_WARN +
     656                "Ignoring speed change request, plug already open");
     657
     658        new_speed = old_speed;
     659    }
     660
     661    uint32_t new_plug_val = old_plug_val;
     662
     663    new_plug_val &= ~(0x3f<<24);
     664    new_plug_val &= (remove_plug) ? ~kIOFWPCRBroadcast : ~0x0;
     665    new_plug_val |= (new_plug_cnt & 0x3f) << 24;
     666
     667    new_plug_val &= ~(0x3f<<16);
     668    new_plug_val |= (new_fw_chan & 0x3F) << 16;
     669
     670    new_plug_val &= ~(0x03<<14);
     671    new_plug_val |= (new_speed & 0x03) << 14;
     672
     673    return (kIOReturnSuccess == (*fw_handle)->CompareSwap(
     674                fw_handle, dev, &addr, old_plug_val, new_plug_val, false, 0));
     675}
     676
     677void DarwinFirewireDevice::HandleBusReset(void)
     678{
     679    int plug_number = 0;
     680    if (!GetInfoPtr())
     681        return;
     682
     683    int fw_channel = m_priv->actual_fwchan;
     684    bool ok = UpdatePlugRegister(plug_number, fw_channel,
     685                                 m_speed, true, false);
     686    if (!ok)
     687    {
     688        ok = UpdatePlugRegister(plug_number, kAnyAvailableIsochChannel,
     689                                m_speed, true, false);
     690    }
     691
     692    if (!ok)
     693        VERBOSE(VB_IMPORTANT, LOC + "Reset: Failed to reconnect");
     694    else
     695        VERBOSE(VB_RECORD, LOC + "Reset: Reconnected succesfully");
     696}
     697
     698bool DarwinFirewireDevice::UpdatePlugRegister(
     699    uint plug_number, int fw_chan, int speed,
     700    bool add_plug, bool remove_plug, uint retry_cnt)
     701{
     702    if (!GetInfoPtr() || !GetInfoPtr()->fw_handle)
     703        return false;
     704
     705    bool ok = false;
     706
     707    for (uint i = 0; (i < retry_cnt) && !ok; i++)
     708    {
     709        ok = UpdatePlugRegisterPrivate(
     710            plug_number, fw_chan, speed, add_plug, remove_plug);
     711    }
     712
     713    m_priv->actual_fwchan = (ok) ? fw_chan : kAnyAvailableIsochChannel;
     714
     715    return ok;
     716}
     717
     718void DarwinFirewireDevice::HandleDeviceChange(uint messageType)
     719{
     720    QString loc = LOC + "HandleDeviceChange: ";
     721
     722    if (kIOMessageServiceIsTerminated == messageType)
     723    {
     724        VERBOSE(VB_RECORD, loc + "Disconnect");
     725        // stop printing no data messages.. don't try to open
     726        return;
     727    }
     728
     729    if (kIOMessageServiceIsAttemptingOpen == messageType)
     730    {
     731        VERBOSE(VB_RECORD, loc + "Attempting open");
     732        return;
     733    }
     734
     735    if (kIOMessageServiceWasClosed == messageType)
     736    {
     737        VERBOSE(VB_RECORD, loc + "Device Closed");
     738        // fill unit_table
     739        return;
     740    }
     741
     742    if (kIOMessageServiceIsSuspended == messageType)
     743    {
     744        VERBOSE(VB_RECORD, loc + "kIOMessageServiceIsSuspended");
     745        // start of reset
     746        return;
     747    }
     748
     749    if (kIOMessageServiceIsResumed == messageType)
     750    {
     751        // end of reset
     752        HandleBusReset();
     753    }
     754
     755    if (kIOMessageServiceIsTerminated == messageType)
     756        VERBOSE(VB_RECORD, loc + "kIOMessageServiceIsTerminated");
     757    else if (kIOMessageServiceIsRequestingClose == messageType)
     758        VERBOSE(VB_RECORD, loc + "kIOMessageServiceIsRequestingClose");
     759    else if (kIOMessageServiceIsAttemptingOpen == messageType)
     760        VERBOSE(VB_RECORD, loc + "kIOMessageServiceIsAttemptingOpen");
     761    else if (kIOMessageServiceWasClosed == messageType)
     762        VERBOSE(VB_RECORD, loc + "kIOMessageServiceWasClosed");
     763    else if (kIOMessageServiceBusyStateChange == messageType)
     764        VERBOSE(VB_RECORD, loc + "kIOMessageServiceBusyStateChange");
     765    else if (kIOMessageCanDevicePowerOff == messageType)
     766        VERBOSE(VB_RECORD, loc + "kIOMessageCanDevicePowerOff");
     767    else if (kIOMessageDeviceWillPowerOff == messageType)
     768        VERBOSE(VB_RECORD, loc + "kIOMessageDeviceWillPowerOff");
     769    else if (kIOMessageDeviceWillNotPowerOff == messageType)
     770        VERBOSE(VB_RECORD, loc + "kIOMessageDeviceWillNotPowerOff");
     771    else if (kIOMessageDeviceHasPoweredOn == messageType)
     772        VERBOSE(VB_RECORD, loc + "kIOMessageDeviceHasPoweredOn");
     773    else if (kIOMessageCanSystemPowerOff == messageType)
     774        VERBOSE(VB_RECORD, loc + "kIOMessageCanSystemPowerOff");
     775    else if (kIOMessageSystemWillPowerOff == messageType)
     776        VERBOSE(VB_RECORD, loc + "kIOMessageSystemWillPowerOff");
     777    else if (kIOMessageSystemWillNotPowerOff == messageType)
     778        VERBOSE(VB_RECORD, loc + "kIOMessageSystemWillNotPowerOff");
     779    else if (kIOMessageCanSystemSleep == messageType)
     780        VERBOSE(VB_RECORD, loc + "kIOMessageCanSystemSleep");
     781    else if (kIOMessageSystemWillSleep == messageType)
     782        VERBOSE(VB_RECORD, loc + "kIOMessageSystemWillSleep");
     783    else if (kIOMessageSystemWillNotSleep == messageType)
     784        VERBOSE(VB_RECORD, loc + "kIOMessageSystemWillNotSleep");
     785    else if (kIOMessageSystemHasPoweredOn == messageType)
     786        VERBOSE(VB_RECORD, loc + "kIOMessageSystemHasPoweredOn");
     787    else if (kIOMessageSystemWillRestart == messageType)
     788        VERBOSE(VB_RECORD, loc + "kIOMessageSystemWillRestart");
     789    else
     790    {
     791        VERBOSE(VB_RECORD, loc + "unknown message 0x"
     792                <<hex<<messageType<<dec);
     793    }
     794}
     795
     796// Various message callbacks.
     797
     798void *dfd_controller_thunk(void *param)
     799{
     800    ((DarwinFirewireDevice*)param)->RunController();
     801    return NULL;
     802}
     803
     804void dfd_update_device_list_item(
     805    DarwinFirewireDevice *dev, uint64_t guid, void *item)
     806{
     807    dev->UpdateDeviceListItem(guid, item);
     808}
     809
     810int dfd_no_data_notification(void *callback_data)
     811{
     812    ((DarwinFirewireDevice*)callback_data)->PrintNoDataMessage();
     813
     814    return kIOReturnSuccess;
     815}
     816
     817void dfd_stream_msg(long unsigned int msg, long unsigned int param1,
     818                    long unsigned int param2, void *callback_data)
     819{
     820    ((DarwinFirewireDevice*)callback_data)->
     821        ProcessStreamingMessage(msg, param1, param2);
     822}
     823
     824int dfd_tspacket_handler(uint tsPacketCount, uint32_t **ppBuf,
     825                         void *callback_data)
     826{
     827    DarwinFirewireDevice *fw = (DarwinFirewireDevice*) callback_data;
     828    if (!fw)
     829        return kIOReturnBadArgument;
     830
     831    for (uint32_t i = 0; i < tsPacketCount; ++i)
     832        fw->BroadcastToListeners((const unsigned char*) ppBuf[i], 188);
     833
     834    return kIOReturnSuccess;
     835}
     836
     837static IOReturn dfd_tspacket_handler_thunk(
     838    long unsigned int tsPacketCount, UInt32 **ppBuf, void *callback_data)
     839{
     840    return dfd_tspacket_handler(
     841        tsPacketCount, (uint32_t**)ppBuf, callback_data);
     842}
     843
     844static void dfd_update_device_list(void *dfd, io_iterator_t deviter)
     845{
     846    DarwinFirewireDevice *dev = (DarwinFirewireDevice*) dfd;
     847
     848    io_object_t it = NULL;
     849    while ((it = IOIteratorNext(deviter)))
     850    {
     851        uint64_t guid = 0;
     852
     853        CFMutableDictionaryRef props;
     854        int ret = IORegistryEntryCreateCFProperties(
     855            it, &props, kCFAllocatorDefault, kNilOptions);
     856
     857        if (kIOReturnSuccess == ret)
     858        {
     859            CFNumberRef GUIDDesc = (CFNumberRef)
     860                CFDictionaryGetValue(props, CFSTR("GUID"));
     861            CFNumberGetValue(GUIDDesc, kCFNumberSInt64Type, &guid);
     862            CFRelease(props);
     863            dfd_update_device_list_item(dev, guid, &it);
     864        }
     865    }
     866}
     867
     868static void dfd_streaming_log_message(char *msg)
     869{
     870    VERBOSE(VB_RECORD, QString("MPEG2Receiver: %1").arg(msg));
     871}
  • 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(%1): ").arg(channel->GetDevice())
     16#define LOC_ERR QString("FireRecBase(%1), Error: ").arg(channel->GetDevice())
    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/darwinavcinfo.cpp

     
     1/**
     2 *  DarwinFirewireChannel
     3 *  Copyright (c) 2006 by Daniel Kristjansson
     4 *  Distributed as part of MythTV under GPL v2 and later.
     5 */
     6
     7// Std C++ headers
     8#include <vector>
     9using namespace std;
     10
     11// MythTV headers
     12#include "darwinfirewiredevice.h"
     13#include "darwinavcinfo.h"
     14#include "mythcontext.h"
     15
     16#ifndef kIOFireWireAVCLibUnitInterfaceID2
     17#define kIOFireWireAVCLibUnitInterfaceID2 \
     18    CFUUIDGetConstantUUIDWithBytes( \
     19        NULL, \
     20        0x85, 0xB5, 0xE9, 0x54, 0x0A, 0xEF, 0x11, 0xD8, \
     21        0x8D, 0x19, 0x00, 0x03, 0x93, 0x91, 0x4A, 0xBA)
     22#endif
     23
     24static void dfd_device_change_msg(
     25    void*, io_service_t, natural_t messageType, void*);
     26
     27void DarwinAVCInfo::Update(uint64_t _guid, DarwinFirewireDevice *dev,
     28                           IONotificationPortRef notify_port,
     29                           CFRunLoopRef &thread_cf_ref, io_object_t obj)
     30{
     31    IOObjectRelease(fw_device_notifier_ref);
     32    IOObjectRelease(fw_node_ref);
     33    IOObjectRelease(fw_device_ref);
     34    IOObjectRelease(fw_service_ref);
     35    IOObjectRelease(avc_service_ref);
     36
     37    avc_service_ref = obj;
     38
     39    IORegistryEntryGetParentEntry(
     40        avc_service_ref, kIOServicePlane, &fw_service_ref);
     41    IORegistryEntryGetParentEntry(
     42        fw_service_ref,  kIOServicePlane, &fw_device_ref);
     43    IORegistryEntryGetParentEntry(
     44        fw_device_ref,   kIOServicePlane, &fw_node_ref);
     45
     46    if (notify_port)
     47    {
     48        IOServiceAddInterestNotification(
     49            notify_port, obj, kIOGeneralInterest,
     50            dfd_device_change_msg, dev,
     51            &fw_device_notifier_ref);
     52    }
     53
     54    if (guid == _guid)
     55        return; // we're done
     56
     57    guid = _guid;
     58
     59    //////////////////////////
     60    // get basic info
     61
     62    CFMutableDictionaryRef props;
     63    int ret = IORegistryEntryCreateCFProperties(
     64        obj, &props, kCFAllocatorDefault, kNilOptions);
     65    if (kIOReturnSuccess != ret)
     66        return; // this is bad
     67
     68    CFNumberRef specDesc = (CFNumberRef)
     69        CFDictionaryGetValue(props, CFSTR("Unit_Spec_ID"));
     70    CFNumberGetValue(specDesc, kCFNumberSInt32Type, &specid);
     71
     72    CFNumberRef typeDesc = (CFNumberRef)
     73        CFDictionaryGetValue(props, CFSTR("Unit_Type"));
     74    CFNumberGetValue(typeDesc, kCFNumberSInt32Type, &modelid);
     75
     76    CFNumberRef vendorDesc = (CFNumberRef)
     77        CFDictionaryGetValue(props, CFSTR("Vendor_ID"));
     78    CFNumberGetValue(vendorDesc, kCFNumberSInt32Type, &vendorid);
     79
     80    CFNumberRef versionDesc = (CFNumberRef)
     81        CFDictionaryGetValue(props, CFSTR("Unit_SW_Version"));
     82    CFNumberGetValue(versionDesc, kCFNumberSInt32Type, &firmware_revision);
     83
     84    CFStringRef tmp0 = (CFStringRef)
     85        CFDictionaryGetValue(props, CFSTR("FireWire Product Name"));
     86    if (tmp0)
     87    {
     88        char tmp1[1024];
     89        bzero(tmp1, sizeof(tmp1));
     90        CFStringGetCString(tmp0, tmp1, sizeof(tmp1) - sizeof(char),
     91                           kCFStringEncodingMacRoman);
     92        product_name = QString("%1").arg(tmp1);
     93    }
     94
     95    CFRelease(props);
     96
     97    //////////////////////////
     98    // get subunit info
     99
     100    VERBOSE(VB_RECORD, "Scanning guid: 0x"<<hex<<guid<<dec);
     101
     102    bool wasOpen = IsAVCInterfaceOpen();
     103    if (OpenAVCInterface(thread_cf_ref))
     104    {
     105        memset(unit_table, 0xff, 32 * sizeof(uint8_t));
     106
     107        for (uint i = 0; i < 8; i++)
     108        {
     109            vector<uint8_t> cmd;
     110            vector<uint8_t> ret;
     111
     112            cmd.push_back(FirewireDevice::kAVCStatusInquiryCommand);
     113            cmd.push_back(FirewireDevice::kAVCSubunitTypeUnit |
     114                          FirewireDevice::kAVCSubunitIdIgnore);
     115            cmd.push_back(FirewireDevice::kAVCUnitSubunitInfoOpcode);
     116            cmd.push_back((i<<4) | 0x07);
     117            cmd.push_back(0xFF);
     118            cmd.push_back(0xFF);
     119            cmd.push_back(0xFF);
     120            cmd.push_back(0xFF);
     121
     122            if (!SendAVCCommand(cmd, ret, -1))
     123            {
     124                VERBOSE(VB_IMPORTANT, "SendAVCCommand failed");
     125                continue;
     126            }
     127
     128            if (ret.size() >= 8)
     129            {
     130                unit_table[(i<<2)+0] = ret[4];
     131                unit_table[(i<<2)+1] = ret[5];
     132                unit_table[(i<<2)+2] = ret[6];
     133                unit_table[(i<<2)+3] = ret[7];
     134
     135                VERBOSE(VB_RECORD, "Added subunits:"<<hex
     136                        <<" 0x"<<((int)ret[4])<<" 0x"<<((int)ret[5])
     137                        <<" 0x"<<((int)ret[6])<<" 0x"<<((int)ret[7])
     138                        <<" filt:"
     139                        <<" 0x"<<(ret[4] & FirewireDevice::kAVCSubunitTypeUnit)
     140                        <<" 0x"<<(ret[5] & FirewireDevice::kAVCSubunitTypeUnit)
     141                        <<" 0x"<<(ret[6] & FirewireDevice::kAVCSubunitTypeUnit)
     142                        <<" 0x"<<(ret[7] & FirewireDevice::kAVCSubunitTypeUnit)
     143                        <<dec);
     144            }
     145        }
     146
     147        if (!wasOpen)
     148            CloseAVCInterface();
     149    }
     150}
     151
     152bool DarwinAVCInfo::SendAVCCommand(
     153    const vector<uint8_t> &cmd,
     154    vector<uint8_t>       &result,
     155    int                   /*retry_cnt*/)
     156{
     157    result.clear();
     158
     159    uint32_t result_length = 4096;
     160    uint8_t response[4096];
     161
     162    if (!avc_handle)
     163        return false;
     164
     165    int ret = (*avc_handle)->
     166        AVCCommand(avc_handle, (const UInt8*) &cmd[0], cmd.size(),
     167                   response, (UInt32*) &result_length);
     168
     169    if (ret != kIOReturnSuccess)
     170        return false;
     171
     172    if (result_length)
     173        result.insert(result.end(), response, response + result_length);
     174
     175    return true;
     176}
     177
     178bool DarwinAVCInfo::Open(CFRunLoopRef &thread_cf_ref)
     179{
     180    if (IsOpen())
     181        return true;
     182
     183    if (!OpenAVCInterface(thread_cf_ref))
     184        return false;
     185
     186    if (!OpenDeviceInterface(thread_cf_ref))
     187    {
     188        CloseAVCInterface();
     189        return false;
     190    }
     191
     192    return true;
     193}
     194
     195void DarwinAVCInfo::Close(void)
     196{
     197    CloseDeviceInterface();
     198    CloseAVCInterface();
     199}
     200
     201bool DarwinAVCInfo::OpenAVCInterface(CFRunLoopRef &thread_cf_ref)
     202{
     203    if (IsAVCInterfaceOpen())
     204        return true;
     205
     206    if (!avc_service_ref)
     207        return false;
     208
     209    IOCFPlugInInterface **input_plug;
     210    int32_t dummy;
     211    int ret = IOCreatePlugInInterfaceForService(
     212        avc_service_ref, kIOFireWireAVCLibUnitTypeID, kIOCFPlugInInterfaceID,
     213        &input_plug, (SInt32*) &dummy);
     214
     215    if (kIOReturnSuccess != ret)
     216        return false;
     217
     218    // Try to get post-Jaguar interface
     219    HRESULT err = (*input_plug)->QueryInterface(
     220            input_plug, CFUUIDGetUUIDBytes(kIOFireWireAVCLibUnitInterfaceID2),
     221            (void**) &avc_handle);
     222
     223    // On failure, try Jaguar interface
     224    if (S_OK != err)
     225    {
     226        err = (*input_plug)->QueryInterface(
     227            input_plug, CFUUIDGetUUIDBytes(kIOFireWireAVCLibUnitInterfaceID),
     228            (void**) &avc_handle);
     229    }
     230
     231    if (S_OK != err)
     232    {
     233        (*input_plug)->Release(input_plug);
     234        return false;
     235    }
     236
     237    // Add avc_handle to the event loop
     238    ret = (*avc_handle)->addCallbackDispatcherToRunLoop(
     239        avc_handle, thread_cf_ref);
     240
     241    (*input_plug)->Release(input_plug);
     242
     243    if (kIOReturnSuccess != ret)
     244    {
     245        (*avc_handle)->Release(avc_handle);
     246        avc_handle = NULL;
     247        return false;
     248    }
     249
     250    ret = (*avc_handle)->open(avc_handle);
     251    if (kIOReturnSuccess != ret)
     252    {
     253        (*avc_handle)->Release(avc_handle);
     254        avc_handle = NULL;
     255        return false;
     256    }
     257
     258    return true;
     259}
     260
     261void DarwinAVCInfo::CloseAVCInterface(void)
     262{
     263    if (!avc_handle)
     264        return;
     265
     266    (*avc_handle)->removeCallbackDispatcherFromRunLoop(avc_handle);
     267    (*avc_handle)->close(avc_handle);
     268    (*avc_handle)->Release(avc_handle);
     269
     270    avc_handle = NULL;
     271}
     272
     273bool DarwinAVCInfo::OpenDeviceInterface(CFRunLoopRef &thread_cf_ref)
     274{
     275    if (fw_handle)
     276        return true;
     277
     278    if (!avc_handle)
     279        return false;
     280
     281    IOCFPlugInInterface **input_plug;
     282    int32_t dummy;
     283    int ret = IOCreatePlugInInterfaceForService(
     284        fw_device_ref, kIOFireWireLibTypeID, kIOCFPlugInInterfaceID,
     285        &input_plug, (SInt32*) &dummy);
     286
     287    if (kIOReturnSuccess != ret)
     288        return false;
     289
     290    HRESULT err = (*input_plug)->QueryInterface(
     291        input_plug, CFUUIDGetUUIDBytes(kIOFireWireNubInterfaceID),
     292        (void**) &fw_handle);
     293
     294    if (S_OK != err)
     295    {
     296        (*input_plug)->Release(input_plug);
     297        return false;
     298    }
     299
     300    // Add fw_handle to the event loop
     301    ret = (*fw_handle)->AddCallbackDispatcherToRunLoop(
     302        fw_handle, thread_cf_ref);
     303
     304    (*input_plug)->Release(input_plug);
     305
     306    if (kIOReturnSuccess == ret)
     307    {
     308        // open the interface
     309        ret = (*fw_handle)->OpenWithSessionRef(
     310            fw_handle, (*avc_handle)->getSessionRef(avc_handle));
     311    }
     312
     313    if (kIOReturnSuccess != ret)
     314    {
     315        (*fw_handle)->Release(fw_handle);
     316        fw_handle = NULL;
     317        return false;
     318    }
     319
     320    return true;
     321}
     322
     323void DarwinAVCInfo::CloseDeviceInterface(void)
     324{
     325    if (!fw_handle)
     326        return;
     327
     328    (*fw_handle)->RemoveCallbackDispatcherFromRunLoop(fw_handle);
     329    (*fw_handle)->Close(fw_handle);
     330    (*fw_handle)->Release(fw_handle);
     331
     332    fw_handle = NULL;
     333}
     334
     335static void dfd_device_change_msg(
     336    void *dfd, io_service_t, natural_t messageType, void*)
     337{
     338    DarwinFirewireDevice *dev = (DarwinFirewireDevice*) dfd;
     339    dev->HandleDeviceChange(messageType);
     340}
  • libs/libmythtv/darwinfirewiredevice.h

     
     1#ifndef _DARWIN_FIREWIRE_DEVICE_H_
     2#define _DARWIN_FIREWIRE_DEVICE_H_
     3
     4#include "firewiredevice.h"
     5
     6class DFDPriv;
     7class DarwinAVCInfo;
     8
     9class DarwinFirewireDevice : public FirewireDevice
     10{
     11    friend void *dfd_controller_thunk(void *param);
     12    friend void dfd_update_device_list_item(DarwinFirewireDevice *dev,
     13                                       uint64_t guid, void *item);
     14    friend int dfd_no_data_notification(void *cb_data);
     15    friend void dfd_stream_msg(
     16        long unsigned int msg, long unsigned int param1,
     17        long unsigned int param2, void *callback_data);
     18    friend int dfd_tspacket_handler(
     19        uint tsPacketCount, uint32_t **ppBuf, void *callback_data);
     20
     21
     22  public:
     23    DarwinFirewireDevice(uint64_t guid, uint subunitid, uint speed);
     24    ~DarwinFirewireDevice();
     25
     26    virtual bool OpenPort(void);
     27    virtual bool ClosePort(void);
     28    void HandleDeviceChange(uint messageType);
     29
     30    virtual void AddListener(TSDataListener*);
     31    virtual void RemoveListener(TSDataListener*);
     32
     33    // Gets
     34    virtual bool IsPortOpen(void) const;
     35
     36    // Statics
     37    static vector<AVCInfo> GetSTBList(void);
     38
     39  private:
     40    void StartController(void);
     41    void StopController(void);
     42
     43    bool OpenAVStream(void);
     44    bool CloseAVStream(void);
     45    bool IsAVStreamOpen(void) const;
     46
     47    bool StartStreaming(void);
     48    bool StopStreaming(void);
     49
     50    virtual bool SendAVCCommand(
     51        const vector<uint8_t> &cmd,
     52        vector<uint8_t>       &result,
     53        int                   /*retry_cnt*/);
     54
     55    void HandleBusReset(void);
     56    bool UpdatePlugRegisterPrivate(
     57        uint plug_number, int fw_chan, int new_speed,
     58        bool add_plug, bool remove_plug);
     59    bool UpdatePlugRegister(
     60        uint plug_number, int fw_chan, int speed,
     61        bool add_plug, bool remove_plug, uint retry_cnt = 4);
     62
     63    void RunController(void);
     64    void BroadcastToListeners(const unsigned char *data, uint dataSize);
     65    void UpdateDeviceListItem(uint64_t guid, void *item);
     66    void PrintNoDataMessage(void);
     67    void ProcessStreamingMessage(
     68        uint32_t msg, uint32_t param1, uint32_t param2);
     69
     70    DarwinAVCInfo *GetInfoPtr(void);
     71    const DarwinAVCInfo *GetInfoPtr(void) const;
     72
     73    int GetMaxSpeed(void);
     74    bool IsSTBStreaming(uint *fw_channel = NULL);
     75
     76    vector<AVCInfo> GetSTBListPrivate(void);
     77
     78  private:
     79    uint     m_node;
     80    DFDPriv *m_priv;
     81};
     82
     83#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/darwinavcinfo.h

     
     1#ifndef _DARWIN_AVC_INFO_H_
     2#define _DARWIN_AVC_INFO_H_
     3
     4#ifdef USING_OSX_FIREWIRE
     5
     6// OS X headers
     7#undef always_inline
     8#include <IOKit/IOKitLib.h>
     9#include <IOKit/firewire/IOFireWireLib.h>
     10#include <IOKit/firewire/IOFireWireLibIsoch.h>
     11#include <IOKit/firewire/IOFireWireFamilyCommon.h>
     12#include <IOKit/avc/IOFireWireAVCLib.h>
     13
     14// Qt headers
     15#include <qmap.h>
     16
     17// MythTV headers
     18#include "firewiredevice.h"
     19
     20class DarwinFirewireDevice;
     21
     22class DarwinAVCInfo : public AVCInfo
     23{
     24  public:
     25    DarwinAVCInfo() :
     26        fw_node_ref(NULL), fw_device_ref(NULL),
     27        fw_service_ref(NULL), avc_service_ref(NULL),
     28        fw_device_notifier_ref(NULL),
     29        avc_handle(NULL), fw_handle(NULL)
     30    {
     31        memset(unit_table, 0xff, sizeof(unit_table));
     32    }
     33
     34    void Update(uint64_t _guid, DarwinFirewireDevice *dev,
     35                IONotificationPortRef notify_port,
     36                CFRunLoopRef &thread_cf_ref, io_object_t obj);
     37
     38    bool Open(CFRunLoopRef &thread_cf_ref);
     39    void Close(void);
     40
     41    bool OpenAVCInterface(CFRunLoopRef &thread_cf_ref);
     42    void CloseAVCInterface(void);
     43
     44    bool OpenDeviceInterface(CFRunLoopRef &thread_cf_ref);
     45    void CloseDeviceInterface(void);
     46
     47    bool SendAVCCommand(
     48        const vector<uint8_t> &cmd,
     49        vector<uint8_t>       &result,
     50        int                   retry_cnt);
     51
     52    bool IsAVCInterfaceOpen(void) const
     53        { return avc_handle; }
     54
     55    bool IsOpen(void) const
     56        { return fw_handle; }
     57
     58  public:
     59    uint8_t      unit_table[32];
     60
     61    io_service_t fw_node_ref;     // parent of fw_device_ref
     62    io_service_t fw_device_ref;   // parent of fw_service_ref
     63    io_service_t fw_service_ref;  // parent of avc_service_ref
     64    io_service_t avc_service_ref;
     65
     66    io_object_t  fw_device_notifier_ref;
     67
     68    IOFireWireAVCLibUnitInterface **avc_handle;
     69    IOFireWireLibDeviceRef          fw_handle;
     70};
     71typedef QMap<uint64_t,DarwinAVCInfo*> avcinfo_list_t;
     72
     73#endif // USING_OSX_FIREWIRE
     74
     75#endif // _DARWIN_AVC_INFO_H_
  • 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/cardutil.cpp

     
    680680{
    681681    QString label = QString::null;
    682682
    683     if (cardtype == "FIREWIRE")
     683    if (cardtype == "DBOX2")
    684684    {
    685685        MSqlQuery query(MSqlQuery::InitCon());
    686686        query.prepare(
    687             "SELECT firewire_port, firewire_node "
    688             "FROM capturecard "
    689             "WHERE cardid = :CARDID");
    690         query.bindValue(":CARDID", cardid);
    691 
    692         if (!query.exec() || !query.isActive() || !query.next())
    693             label = "[ DB ERROR ]";
    694         else
    695             label = QString("[ FIREWIRE : Port %2 Node %3 ]")
    696                 .arg(query.value(0).toString())
    697                 .arg(query.value(1).toString());
    698  
    699     }
    700     else if (cardtype == "DBOX2")
    701     {
    702         MSqlQuery query(MSqlQuery::InitCon());
    703         query.prepare(
    704687            "SELECT dbox2_host, dbox2_port, dbox2_httpport "
    705688            "FROM capturecard "
    706689            "WHERE cardid = :CARDID");
  • 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(TVRec *parent, const QString &videodevice,
     18                    const FireWireDBOptions &firewire_opts);
     19    ~FirewireChannel() { Close(); }
    2720
    28     FirewireChannel(FireWireDBOptions firewire_opts, TVRec *parent);
    29     ~FirewireChannel(void);
     21    // Commands
     22    virtual bool Open(void);
     23    virtual void Close(void);
     24    virtual bool SwitchToInput(const QString &inputname, const QString &chan);
     25    virtual bool SwitchToInput(int newcapchannel, bool setstarting);
    3026
    31     bool OpenFirewire(void);
    32     void CloseFirewire(void);
     27    virtual bool TuneMultiplex(uint /*mplexid*/, QString /*inputname*/)
     28        { return false; }
     29    virtual bool Tune(const DTVMultiplex &/*tuning*/, QString /*inputname*/)
     30        { return false; }
     31    virtual bool Retune(void);
    3332
    3433    // Sets
    35     void SetExternalChanger(void);
    36     bool SetChannelByNumber(int channel);
     34    virtual bool SetChannelByString(const QString &chan);
     35    virtual bool SetChannelByNumber(int channel);
     36    virtual bool SetPowerState(bool on);
    3737
    3838    // 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);
     39    virtual bool IsOpen(void) const { return isopen; }
     40    virtual FirewireDevice::PowerState GetPowerState(void) const;
     41    virtual QString GetDevice(void) const;
     42    virtual FirewireDevice *GetFirewireDevice(void) { return device; }
    4343
    44   private:
     44  protected:
     45    QString            videodevice;
    4546    FireWireDBOptions  fw_opts;
    46     nodeid_t           fwnode;
    47     raw1394handle_t    fwhandle;
     47    FirewireDevice    *device;
     48    uint               current_channel;
     49    bool               isopen;
    4850};
    4951
    50 #endif
     52#endif // _FIREWIRECHANNEL_H_
  • libs/libmythtv/videosource.cpp

     
    88#include <sys/stat.h>
    99
    1010// C++ headers
    11 #include <iostream>
     11#include <algorithm>
     12using namespace std;
    1213
    1314// Qt headers
    1415#include <qapplication.h>
     
    3334#include "channelutil.h"
    3435#include "frequencies.h"
    3536#include "diseqcsettings.h"
     37#include "firewiredevice.h"
    3638
    3739#ifdef USING_DVB
    3840#include "dvbtypes.h"
     
    929931    };
    930932};
    931933
    932 class FirewireModel : public ComboBoxSetting, public CaptureCardDBStorage
     934class FirewireGUID : public ComboBoxSetting, public CaptureCardDBStorage
    933935{
    934936  public:
    935     FirewireModel(const CaptureCard &parent) :
     937    FirewireGUID(const CaptureCard &parent) :
    936938        ComboBoxSetting(this),
    937         CaptureCardDBStorage(this, parent, "firewire_model")
     939        CaptureCardDBStorage(this, parent, "videodevice")
    938940    {
    939         setLabel(QObject::tr("Cable box model"));
    940         addSelection(QObject::tr("Other"));
    941         addSelection("DCT-6200");
    942         addSelection("SA3250HD");
    943         addSelection("SA4200HD");
    944         QString help = QObject::tr(
    945             "Choose the model that most closely resembles your set top box. "
    946             "Depending on firmware revision SA4200HD may work better for a "
    947             "SA3250HD box.");
    948         setHelpText(help);
     941        setLabel(QObject::tr("GUID"));
     942#ifdef USING_FIREWIRE
     943        vector<AVCInfo> list = FirewireDevice::GetSTBList();
     944        for (uint i = 0; i < list.size(); i++)
     945        {
     946            QString guid = list[i].GetGUIDString();
     947            guid_to_avcinfo[guid] = list[i];
     948            addSelection(guid);
     949        }
     950#endif // USING_FIREWIRE
    949951    }
     952
     953    AVCInfo GetAVCInfo(const QString &guid) const
     954        { return guid_to_avcinfo[guid]; }
     955
     956  private:
     957    QMap<QString,AVCInfo> guid_to_avcinfo;
    950958};
    951959
     960FirewireModel::FirewireModel(const CaptureCard  &parent,
     961                             const FirewireGUID *_guid) :
     962    ComboBoxSetting(this),
     963    CaptureCardDBStorage(this, parent, "firewire_model"),
     964    guid(_guid)
     965{
     966    setLabel(QObject::tr("Cable box model"));
     967    addSelection(QObject::tr("Generic"), "GENERIC");
     968    addSelection("DCT-6200");
     969    addSelection("DCT-6212");
     970    addSelection("DCT-6216");
     971    addSelection("SA3250HD");
     972    addSelection("SA4200HD");
     973    QString help = QObject::tr(
     974        "Choose the model that most closely resembles your set top box. "
     975        "Depending on firmware revision SA4200HD may work better for a "
     976        "SA3250HD box.");
     977    setHelpText(help);
     978}
     979
     980void FirewireModel::SetGUID(const QString &_guid)
     981{
     982#ifdef USING_FIREWIRE
     983    AVCInfo info = guid->GetAVCInfo(_guid);
     984    QString model = FirewireDevice::GetModelName(info.vendorid, info.modelid);
     985    setValue(max(getValueIndex(model), 0));
     986#endif // USING_FIREWIRE
     987}
     988
     989void FirewireDesc::SetGUID(const QString &_guid)
     990{
     991    setLabel(tr("Description"));
     992
     993#ifdef USING_FIREWIRE
     994    QString name = guid->GetAVCInfo(_guid).product_name;
     995    name.replace("Scientific-Atlanta", "SA");
     996    name.replace(", Inc.", "");
     997    name.replace("Explorer(R)", "");
     998    name = name.simplifyWhiteSpace();
     999    setValue((name.isEmpty()) ? "" : name);
     1000#endif // USING_FIREWIRE
     1001}
     1002
    9521003class FirewireConnection : public ComboBoxSetting, public CaptureCardDBStorage
    9531004{
    9541005  public:
     
    9621013    }
    9631014};
    9641015
    965 class FirewirePort : public SpinBoxSetting, public CaptureCardDBStorage
    966 {
    967   public:
    968     FirewirePort(const CaptureCard &parent) :
    969         SpinBoxSetting(this, 0, 63, 1),
    970         CaptureCardDBStorage(this, parent, "firewire_port")
    971     {
    972         setValue(0);
    973         setLabel(QObject::tr("IEEE-1394 Port"));
    974         setHelpText(QObject::tr("Firewire port on your firewire card."));
    975     }
    976 };
    977 
    978 class FirewireNode : public SpinBoxSetting, public CaptureCardDBStorage
    979 {
    980   public:
    981     FirewireNode(const CaptureCard &parent) :
    982         SpinBoxSetting(this, 0, 63, 1),
    983         CaptureCardDBStorage(this, parent, "firewire_node")
    984     {
    985         setValue(2);
    986         setLabel(QObject::tr("Node"));
    987         setHelpText(QObject::tr("Firewire node is the remote device."));
    988     }
    989 };
    990 
    9911016class FirewireSpeed : public ComboBoxSetting, public CaptureCardDBStorage
    9921017{
    9931018  public:
     
    9991024        addSelection(QObject::tr("100Mbps"),"0");
    10001025        addSelection(QObject::tr("200Mbps"),"1");
    10011026        addSelection(QObject::tr("400Mbps"),"2");
     1027        addSelection(QObject::tr("800Mbps"),"3");
    10021028    }
    10031029};
    10041030
     
    10071033  public:
    10081034    FirewireConfigurationGroup(CaptureCard& a_parent) :
    10091035        VerticalConfigurationGroup(false, true, false, false),
    1010         parent(a_parent)
     1036        parent(a_parent),
     1037        dev(new FirewireGUID(parent)),
     1038        desc(new FirewireDesc(dev)),
     1039        model(new FirewireModel(parent, dev))
    10111040    {
    1012         HorizontalConfigurationGroup *hg0 =
    1013             new HorizontalConfigurationGroup(false, false, true, true);
    1014         hg0->addChild(new FirewireModel(parent));
    1015         hg0->addChild(new FirewireConnection(parent));
    1016         addChild(hg0);
    1017         HorizontalConfigurationGroup *hg1 =
    1018             new HorizontalConfigurationGroup(false, false, true, true);
    1019         hg1->addChild(new FirewirePort(parent));
    1020         hg1->addChild(new FirewireNode(parent));
    1021         hg1->addChild(new FirewireSpeed(parent));
    1022         addChild(hg1);
     1041        addChild(dev);
     1042        addChild(desc);
     1043        addChild(model);
     1044
     1045#ifdef USING_LINUX_FIREWIRE
     1046        addChild(new FirewireConnection(parent));
     1047        addChild(new FirewireSpeed(parent));
     1048#endif // USING_LINUX_FIREWIRE
     1049
     1050        addChild(new SignalTimeout(parent, 2000, 1000));
     1051        addChild(new ChannelTimeout(parent, 9000, 1750));
    10231052        addChild(new SingleCardInput(parent));
     1053
     1054        connect(dev,   SIGNAL(valueChanged(const QString&)),
     1055                model, SLOT(  SetGUID(     const QString&)));
     1056        connect(dev,   SIGNAL(valueChanged(const QString&)),
     1057                desc,  SLOT(  SetGUID(     const QString&)));
    10241058    };
     1059
    10251060  private:
    1026     CaptureCard &parent;
     1061    CaptureCard   &parent;
     1062    FirewireGUID  *dev;
     1063    FirewireDesc  *desc;
     1064    FirewireModel *model;
    10271065};
    10281066
    10291067class DBOX2Port : public LineEditSetting, public CaptureCardDBStorage
  • 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    LinuxFirewireDevice(uint64_t guid, uint subunitid,
     22                        uint speed, bool use_p2p,
     23                        uint av_buffer_size_in_bytes = 0);
     24    ~LinuxFirewireDevice();
     25
     26    // Commands
     27    virtual bool OpenPort(void);
     28    virtual bool ClosePort(void);
     29    void HandleBusReset(uint);
     30
     31    virtual void AddListener(TSDataListener*);
     32    virtual void RemoveListener(TSDataListener*);
     33
     34    // Gets
     35    virtual bool IsPortOpen(void) const;
     36
     37    // Statics
     38    static vector<AVCInfo> GetSTBList(void);
     39
     40    // Constants
     41    static const uint kBroadcastChannel;
     42    static const uint kConnectionP2P;
     43    static const uint kConnectionBroadcast;
     44    static const uint kMaxBufferedPackets;
     45
     46  private:
     47    bool GetPortAndNode(void);
     48
     49    bool OpenNode(void);
     50    bool CloseNode(void);
     51
     52    bool OpenAVStream(void);
     53    bool CloseAVStream(void);
     54
     55    bool OpenP2PNode(void);
     56    bool CloseP2PNode(void);
     57
     58    bool OpenBroadcastNode(void);
     59    bool CloseBroadcastNode(void);
     60
     61    bool StartStreaming(void);
     62    bool StopStreaming(void);
     63    bool StopStreamingLater(void);
     64
     65    bool ResetBus(void);
     66
     67    void RunStreaming(void);
     68    bool LoopIteration(uint timeout_in_msec);
     69    void PrintDropped(uint dropped_packets);
     70
     71    bool SetAVStreamBufferSize(uint size_in_bytes);
     72    bool SetAVStreamSpeed(uint speed);
     73
     74    bool IsNodeOpen(void) const;
     75    bool IsAVStreamOpen(void) const;
     76
     77    virtual bool SendAVCCommand(const vector<uint8_t> &cmd,
     78                                vector<uint8_t>       &result,
     79                                int                    retry_cnt);
     80
     81  private:
     82    int                      m_port;
     83    int                      m_node;
     84    uint                     m_bufsz;
     85    bool                     m_use_p2p;
     86    bool                     m_resetting;
     87    LFDPriv                 *m_priv;
     88};
     89
     90#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
    164         channel = new FirewireChannel(fwOpt, this);
    165 # endif
     153        channel = new FirewireChannel(this, genOpt.videodev, fwOpt);
    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());
    844823#endif // USING_FIREWIRE
    845824    }
    846825    else if (genOpt.cardtype == "DBOX2")
     
    11141093#endif // USING_DVB
    11151094}
    11161095
     1096FirewireChannel *TVRec::GetFirewireChannel(void)
     1097{
     1098#ifdef USING_FIREWIRE
     1099    return dynamic_cast<FirewireChannel*>(channel);
     1100#else
     1101    return NULL;
     1102#endif // USING_FIREWIRE
     1103}
     1104
    11171105Channel *TVRec::GetV4LChannel(void)
    11181106{
    11191107#ifdef USING_V4L
     
    14181406        ""
    14191407        "       dvb_on_demand,    dvb_tuning_delay, "
    14201408        ""
    1421         "       firewire_port,    firewire_node,       firewire_speed,  "
    1422         "       firewire_model,   firewire_connection,                  "
     1409        "       firewire_speed,   firewire_model,      firewire_connection, "
    14231410        ""
    14241411        "       dbox2_port,       dbox2_host,          dbox2_httpport   "
    14251412        ""
     
    14791466
    14801467    // Firewire options
    14811468    uint fireoff = dvboff + 2;
    1482     firewire_opts.port        = query.value(fireoff + 0).toUInt();
    1483     firewire_opts.node        = query.value(fireoff + 1).toUInt();
    1484     firewire_opts.speed       = query.value(fireoff + 2).toUInt();
     1469    firewire_opts.speed       = query.value(fireoff + 0).toUInt();
    14851470
    1486     test = query.value(fireoff + 3).toString();
     1471    test = query.value(fireoff + 1).toString();
    14871472    if (test != QString::null)
    14881473        firewire_opts.model = QString::fromUtf8(test);
    14891474
    1490     firewire_opts.connection  = query.value(fireoff + 4).toUInt();
     1475    firewire_opts.connection  = query.value(fireoff + 2).toUInt();
    14911476
    14921477    // DBOX2/HDHomeRun options
    1493     uint dbox2off = fireoff + 5;
     1478    uint dbox2off = fireoff + 3;
    14941479    dbox2_opts.port = query.value(dbox2off + 0).toUInt();
    14951480
    14961481    test = query.value(dbox2off + 1).toString();
  • libs/libmythtv/tv_rec.h

     
    3535class DBox2Channel;
    3636class DTVChannel;
    3737class DVBChannel;
     38class FirewireChannel;
    3839class Channel;
    3940class HDHRChannel;
    4041
     
    8586class FireWireDBOptions
    8687{
    8788  public:
    88     FireWireDBOptions() :
    89         port(-1), node(-1), speed(-1), connection(-1), model("") {;}
    90        
    91     int port;
    92     int node;
     89    FireWireDBOptions() : speed(-1), connection(-1), model("") {;}
     90
    9391    int speed;
    9492    int connection;
    9593    QString model;
     
    261259    DTVChannel   *GetDTVChannel(void);
    262260    HDHRChannel  *GetHDHRChannel(void);
    263261    DVBChannel   *GetDVBChannel(void);
     262    FirewireChannel *GetFirewireChannel(void);
    264263    Channel      *GetV4LChannel(void);
    265264
    266265    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 AVCInfo
     24{
     25  public:
     26    int      port;
     27    int      node;
     28    uint64_t guid;
     29    uint     specid;
     30    uint     vendorid;
     31    uint     modelid;
     32    uint     firmware_revision;
     33    QString  product_name;
     34
     35    AVCInfo();
     36    AVCInfo(const AVCInfo &o);
     37    AVCInfo &operator=(const AVCInfo &o);
     38
     39    QString GetGUIDString(void) const;
     40};
     41
     42class FirewireDevice
     43{
     44  public:
     45
     46    // Public enums
     47    typedef enum
     48    {
     49        kAVCPowerOn,
     50        kAVCPowerOff,
     51        kAVCPowerUnknown,
     52        kAVCPowerQueryFailed,
     53    } PowerState;
     54
     55    // AVC commands
     56    typedef enum
     57    {
     58        kAVCControlCommand         = 0x00,
     59        kAVCStatusInquiryCommand   = 0x01,
     60        kAVCSpecificInquiryCommand = 0x02,
     61        kAVCNotifyCommand          = 0x03,
     62        kAVCGeneralInquiryCommand  = 0x04,
     63
     64        kAVCNotImplementedStatus   = 0x08,
     65        kAVCAcceptedStatus         = 0x09,
     66        kAVCRejectedStatus         = 0x0a,
     67        kAVCInTransitionStatus     = 0x0b,
     68        kAVCImplementedStatus      = 0x0c,
     69        kAVCChangedStatus          = 0x0d,
     70
     71        kAVCInterimStatus          = 0x0f,
     72        kAVCResponseImplemented    = 0x0c,
     73    } IEEE1394Command;
     74
     75    // AVC unit addresses
     76    typedef enum
     77    {
     78        kAVCSubunitId0                = 0x00,
     79        kAVCSubunitId1                = 0x01,
     80        kAVCSubunitId2                = 0x02,
     81        kAVCSubunitId3                = 0x03,
     82        kAVCSubunitId4                = 0x04,
     83        kAVCSubunitIdExtended         = 0x05,
     84        kAVCSubunitIdIgnore           = 0x07,
     85
     86        kAVCSubunitTypeVideoMonitor   = (0x00 << 3),
     87        kAVCSubunitTypeAudio          = (0x01 << 3),
     88        kAVCSubunitTypePrinter        = (0x02 << 3),
     89        kAVCSubunitTypeDiscRecorder   = (0x03 << 3),
     90        kAVCSubunitTypeTapeRecorder   = (0x04 << 3),
     91        kAVCSubunitTypeTuner          = (0x05 << 3),
     92        kAVCSubunitTypeCA             = (0x06 << 3),
     93        kAVCSubunitTypeVideoCamera    = (0x07 << 3),
     94        kAVCSubunitTypePanel          = (0x09 << 3),
     95        kAVCSubunitTypeBulletinBoard  = (0x0a << 3),
     96        kAVCSubunitTypeCameraStorage  = (0x0b << 3),
     97        kAVCSubunitTypeMusic          = (0x0c << 3),
     98        kAVCSubunitTypeVendorUnique   = (0x1c << 3),
     99        kAVCSubunitTypeExtended       = (0x1e << 3),
     100        kAVCSubunitTypeUnit           = (0x1f << 3),
     101    } IEEE1394UnitAddress;
     102
     103    // AVC opcode
     104    typedef enum
     105    {
     106        // Unit
     107        kAVCUnitPlugInfoOpcode               = 0x02,
     108        kAVCUnitDigitalOutputOpcode          = 0x10,
     109        kAVCUnitDigitalInputOpcode           = 0x11,
     110        kAVCUnitChannelUsageOpcode           = 0x12,
     111        kAVCUnitOutputPlugSignalFormatOpcode = 0x18,
     112        kAVCUnitInputPlugSignalFormatOpcode  = 0x19,
     113        kAVCUnitConnectAVOpcode              = 0x20,
     114        kAVCUnitDisconnectAVOpcode           = 0x21,
     115        kAVCUnitConnectionsOpcode            = 0x22,
     116        kAVCUnitConnectOpcode                = 0x24,
     117        kAVCUnitDisconnectOpcode             = 0x25,
     118        kAVCUnitUnitInfoOpcode               = 0x30,
     119        kAVCUnitSubunitInfoOpcode            = 0x31,
     120        kAVCUnitSignalSourceOpcode           = 0x1a,
     121        kAVCUnitPowerOpcode                  = 0xb2,
     122
     123        // Common Unit + Subunit
     124        kAVCCommonOpenDescriptorOpcode       = 0x08,
     125        kAVCCommonReadDescriptorOpcode       = 0x09,
     126        kAVCCommonWriteDescriptorOpcode      = 0x0A,
     127        kAVCCommonSearchDescriptorOpcode     = 0x0B,
     128        kAVCCommonObjectNumberSelectOpcode   = 0x0D,
     129        kAVCCommonPowerOpcode                = 0xB2,
     130        kAVCCommonReserveOpcode              = 0x01,
     131        kAVCCommonPlugInfoOpcode             = 0x02,
     132        kAVCCommonVendorDependentOpcode      = 0x00,
     133
     134        // Panel
     135        kAVCPanelPassThrough                 = 0x7c,
     136    } IEEE1394Opcode;
     137
     138    // AVC param 0
     139    typedef enum
     140    {
     141        kAVCPowerStateOn           = 0x70,
     142        kAVCPowerStateOff          = 0x60,
     143        kAVCPowerStateQuery        = 0x7f,
     144    } IEEE1394UnitPowerParam0;
     145
     146    typedef enum
     147    {
     148        kAVCPanelKeySelect          = 0x00,
     149        kAVCPanelKeyUp              = 0x01,
     150        kAVCPanelKeyDown            = 0x02,
     151        kAVCPanelKeyLeft            = 0x03,
     152        kAVCPanelKeyRight           = 0x04,
     153        kAVCPanelKeyRightUp         = 0x05,
     154        kAVCPanelKeyRightDown       = 0x06,
     155        kAVCPanelKeyLeftUp          = 0x07,
     156        kAVCPanelKeyLeftDown        = 0x08,
     157        kAVCPanelKeyRootMenu        = 0x09,
     158        kAVCPanelKeySetupMenu       = 0x0A,
     159        kAVCPanelKeyContentsMenu    = 0x0B,
     160        kAVCPanelKeyFavoriteMenu    = 0x0C,
     161        kAVCPanelKeyExit            = 0x0D,
     162
     163        kAVCPanelKey0               = 0x20,
     164        kAVCPanelKey1               = 0x21,
     165        kAVCPanelKey2               = 0x22,
     166        kAVCPanelKey3               = 0x23,
     167        kAVCPanelKey4               = 0x24,
     168        kAVCPanelKey5               = 0x25,
     169        kAVCPanelKey6               = 0x26,
     170        kAVCPanelKey7               = 0x27,
     171        kAVCPanelKey8               = 0x28,
     172        kAVCPanelKey9               = 0x29,
     173        kAVCPanelKeyDot             = 0x2A,
     174        kAVCPanelKeyEnter           = 0x2B,
     175        kAVCPanelKeyClear           = 0x2C,
     176
     177        kAVCPanelKeyChannelUp       = 0x30,
     178        kAVCPanelKeyChannelDown     = 0x31,
     179        kAVCPanelKeyPreviousChannel = 0x32,
     180        kAVCPanelKeySoundSelect     = 0x33,
     181        kAVCPanelKeyInputSelect     = 0x34,
     182        kAVCPanelKeyDisplayInfo     = 0x35,
     183        kAVCPanelKeyHelp            = 0x36,
     184        kAVCPanelKeyPageUp          = 0x37,
     185        kAVCPanelKeyPageDown        = 0x38,
     186
     187        kAVCPanelKeyPower           = 0x40,
     188        kAVCPanelKeyVolumeUp        = 0x41,
     189        kAVCPanelKeyVolumeDown      = 0x42,
     190        kAVCPanelKeyMute            = 0x43,
     191        kAVCPanelKeyPlay            = 0x44,
     192        kAVCPanelKeyStop            = 0x45,
     193        kAVCPanelKeyPause           = 0x46,
     194        kAVCPanelKeyRecord          = 0x47,
     195        kAVCPanelKeyRewind          = 0x48,
     196        kAVCPanelKeyFastForward     = 0x49,
     197        kAVCPanelKeyEject           = 0x4a,
     198        kAVCPanelKeyForward         = 0x4b,
     199        kAVCPanelKeyBackward        = 0x4c,
     200
     201        kAVCPanelKeyAngle           = 0x50,
     202        kAVCPanelKeySubPicture      = 0x51,
     203
     204        kAVCPanelKeyTuneFunction    = 0x67,
     205
     206        kAVCPanelKeyPress           = 0x00,
     207        kAVCPanelKeyRelease         = 0x80,
     208
     209    } IEEE1394PanelPassThroughParam0;
     210
     211    virtual ~FirewireDevice() { }
     212
     213    // Commands
     214    virtual bool OpenPort(void) = 0;
     215    virtual bool ClosePort(void) = 0;
     216
     217    virtual void AddListener(TSDataListener*);
     218    virtual void RemoveListener(TSDataListener*);
     219
     220    // Sets
     221    virtual bool SetPowerState(bool on);
     222    virtual bool SetChannel(const QString &panel_model,
     223                            uint alt_method, uint channel);
     224
     225    // Gets
     226    virtual bool IsPortOpen(void) const = 0;
     227    bool IsSTBBufferCleared(void) const { return m_buffer_cleared; }
     228
     229    // non-const Gets
     230    virtual PowerState GetPowerState(void);
     231
     232    // Statics
     233    static inline bool IsSTBSupported(const QString &model);
     234    static QString GetModelName(uint vendorid, uint modelid);
     235    static vector<AVCInfo> GetSTBList(void);
     236    static bool IsSubunitType(
     237        const uint8_t unit_table[32], IEEE1394UnitAddress subunit_type);
     238    static QString GetSubunitInfoString(const uint8_t table[32]);
     239
     240  protected:
     241    FirewireDevice(uint64_t guid, uint subunitid, uint speed);
     242
     243    virtual bool SendAVCCommand(const vector<uint8_t> &cmd,
     244                                vector<uint8_t> &result,
     245                                int retry_cnt) = 0;
     246    bool GetSubunitInfo(uint8_t table[32]);
     247
     248    void SetLastChannel(uint channel);
     249    void ProcessPATPacket(const TSPacket&);
     250    virtual void BroadcastToListeners(
     251        const unsigned char *data, uint dataSize);
     252
     253    uint64_t                 m_guid;
     254    uint                     m_subunitid;
     255    uint                     m_speed;
     256    uint                     m_last_channel;
     257    uint                     m_last_crc;
     258    bool                     m_buffer_cleared;
     259
     260    uint                     m_open_port_cnt;
     261    vector<TSDataListener*>  m_listeners;
     262    mutable QMutex           m_lock;
     263
     264    /// Vendor ID + Model ID to FirewireDevice STB model string
     265    static QMap<uint64_t,QString> s_id_to_model;
     266    static QMutex                 s_static_lock;
     267};
     268
     269inline bool FirewireDevice::IsSTBSupported(const QString &panel_model)
     270{
     271    QString model = panel_model.upper();
     272    return ((model == "DCT-6200") ||
     273            (model == "DCT-6212") ||
     274            (model == "DCT-6216") ||
     275            (model == "SA3250HD") ||
     276            (model == "SA4200HD") ||
     277            (model == "GENERIC"));
     278}
     279
     280#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 <libraw1394/csr.h>
     19#include <libiec61883/iec61883.h>
     20#include <libavc1394/avc1394.h>
     21#include <libavc1394/rom1394.h>
     22
     23//#include <unistd.h>
     24//#include <string.h>
     25//#include <stdio.h>
     26//#include <stdlib.h>
     27#include <netinet/in.h>
     28
     29// C++ headers
     30#include <algorithm>
     31using namespace std;
     32
     33// Qt headers
     34#include <qdatetime.h>
     35
     36// MythTV headers
     37#include "linuxfirewiredevice.h"
     38#include "firewirerecorder.h"
     39#include "mythcontext.h"
     40
     41#define LOC      QString("LFireDev(%1:%2): ").arg(m_port).arg(m_node)
     42#define LOC_WARN QString("LFireDev(%1:%2), Warning: ").arg(m_port).arg(m_node)
     43#define LOC_ERR  QString("LFireDev(%1:%2), Error: ").arg(m_port).arg(m_node)
     44
     45#define kNoDataTimeout            50 /* msec */
     46
     47typedef QMap<raw1394handle_t,LinuxFirewireDevice*> handle_to_lfd_t;
     48
     49class LFDPriv
     50{
     51  public:
     52    LFDPriv() :
     53        handle(NULL), generation(0), reset_start(true),
     54        avstream(NULL), channel(-1),
     55        is_p2p_node_open(false), is_bcast_node_open(false),
     56        is_streaming(false), is_streaming_running(false)
     57    {
     58        memset(unit_table, 0xff, sizeof(unit_table));
     59    }
     60
     61    raw1394handle_t  handle;
     62    uint             generation;
     63    bool             reset_start;
     64    uint8_t          unit_table[32];
     65
     66    iec61883_mpeg2_t avstream;
     67    int              channel;
     68
     69    bool             is_p2p_node_open;
     70    bool             is_bcast_node_open;
     71    bool             is_streaming;
     72    bool             is_streaming_running;
     73
     74    QDateTime        stop_streaming_timer;
     75    pthread_t        streaming_thread;
     76    QMutex           start_stop_streaming_lock;
     77
     78    static QMutex          s_lock;
     79    static handle_to_lfd_t s_handle_info;
     80};
     81QMutex          LFDPriv::s_lock;
     82handle_to_lfd_t LFDPriv::s_handle_info;
     83
     84const uint LinuxFirewireDevice::kBroadcastChannel    = 63;
     85const uint LinuxFirewireDevice::kConnectionP2P       = 0;
     86const uint LinuxFirewireDevice::kConnectionBroadcast = 1;
     87const uint LinuxFirewireDevice::kMaxBufferedPackets  = 2000;
     88
     89// callback function for libiec61883
     90int linux_firewire_device_tspacket_handler(
     91    unsigned char *tspacket, int len, uint dropped, void *callback_data);
     92static QString speed_to_string(uint speed);
     93static int linux_firewire_device_bus_reset_handler(
     94    raw1394handle_t handle, uint generation);
     95static uint64_t get_guid(raw1394handle_t handle, nodeid_t node);
     96
     97LinuxFirewireDevice::LinuxFirewireDevice(
     98    uint64_t guid, uint subunitid,
     99    uint speed, bool use_p2p, uint av_buffer_size_in_bytes) :
     100    FirewireDevice(guid, subunitid, speed),
     101    m_port(-1),         m_node(-1),
     102    m_bufsz(av_buffer_size_in_bytes),
     103    m_use_p2p(use_p2p), m_resetting(false),
     104    m_priv(new LFDPriv())
     105{
     106    if (!m_bufsz)
     107        m_bufsz = gContext->GetNumSetting("HDRingbufferSize");
     108}
     109
     110LinuxFirewireDevice::~LinuxFirewireDevice()
     111{
     112    if (IsPortOpen())
     113    {
     114        VERBOSE(VB_IMPORTANT, LOC_ERR + "ctor called with open port");
     115        while (IsPortOpen())
     116            ClosePort();
     117    }
     118
     119    if (m_priv)
     120    {
     121        delete m_priv;
     122        m_priv = NULL;
     123    }
     124}
     125
     126void LinuxFirewireDevice::HandleBusReset(uint generation)
     127{
     128    QString loc = LOC + QString("HandleBusReset(%1->%2)")
     129        .arg(m_priv->generation).arg(generation);
     130
     131    m_priv->generation = generation;
     132
     133    if (m_priv->reset_start)
     134    {
     135        m_priv->reset_start = false;
     136        if (m_priv->is_streaming)
     137        {
     138            VERBOSE(VB_IMPORTANT, loc + ": Stopping Streaming");
     139            iec61883_mpeg2_recv_stop(m_priv->avstream);
     140            VERBOSE(VB_IMPORTANT, loc + ": Stopped Streaming");
     141        }
     142        return;
     143    }
     144    m_priv->reset_start = true;
     145
     146    raw1394_update_generation(m_priv->handle, generation);
     147
     148    if (m_priv->channel >= 0)
     149    {
     150        int bandwidth = 1;
     151        int oplug = -1, iplug = -1;
     152        int fwchan = iec61883_cmp_reconnect(
     153            m_priv->handle, m_node | 0xffc0, &oplug,
     154            raw1394_get_local_id(m_priv->handle), &iplug,
     155            &bandwidth, m_priv->channel);
     156
     157        if (fwchan < 0)
     158        {
     159            VERBOSE(VB_IMPORTANT, LOC_ERR + "Bus Reset: Failed to reconnect");
     160        }
     161        else if (fwchan != m_priv->channel)
     162        {
     163            VERBOSE(VB_IMPORTANT, LOC_WARN + QString("FWChan changed %1->%2")
     164                    .arg(m_priv->channel).arg(fwchan));
     165        }
     166        m_priv->channel = fwchan;
     167
     168        VERBOSE(VB_IMPORTANT, loc + ": Reconnected fwchan: "<<fwchan);
     169
     170        if (m_priv->is_streaming)
     171        {
     172            VERBOSE(VB_IMPORTANT, loc + ": Starting Streaming");
     173            iec61883_mpeg2_recv_start(m_priv->avstream, m_priv->channel);
     174            VERBOSE(VB_IMPORTANT, loc + ": Started Streaming");
     175        }
     176    }
     177}
     178
     179bool LinuxFirewireDevice::OpenPort(void)
     180{
     181    QMutexLocker mlocker(&m_lock);
     182    QMutexLocker slocker(&LFDPriv::s_lock);
     183
     184    VERBOSE(VB_RECORD, LOC + "OpenPort()");
     185
     186    if (m_priv->handle)
     187    {
     188        m_open_port_cnt++;
     189        return true;
     190    }
     191
     192    if (!GetPortAndNode())
     193        return false;
     194
     195    VERBOSE(VB_RECORD, LOC + "Getting raw1394 handle "<<(m_open_port_cnt-1));
     196    m_priv->handle = raw1394_new_handle_on_port(m_port);
     197
     198    if (!m_priv->handle)
     199    {
     200        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to get handle for " +
     201                QString("port: %1").arg(m_port) + ENO);
     202
     203        return false;
     204    }
     205
     206    LFDPriv::s_handle_info[m_priv->handle] = this;
     207
     208    m_priv->generation = raw1394_get_generation(m_priv->handle);
     209    raw1394_set_bus_reset_handler(
     210        m_priv->handle, linux_firewire_device_bus_reset_handler);
     211
     212    GetSubunitInfo(m_priv->unit_table);
     213    VERBOSE(VB_RECORD, LOC + GetSubunitInfoString(m_priv->unit_table));
     214
     215    if (!IsSubunitType(m_priv->unit_table, kAVCSubunitTypeTuner) ||
     216        !IsSubunitType(m_priv->unit_table, kAVCSubunitTypePanel))
     217    {
     218        VERBOSE(VB_IMPORTANT, LOC_ERR + QString("No STB at guid: 0x%1")
     219                .arg(m_guid,0,16));
     220
     221        ClosePort();
     222        return false;
     223    }
     224
     225    m_open_port_cnt++;
     226
     227    return true;
     228}
     229
     230bool LinuxFirewireDevice::ClosePort(void)
     231{
     232    QMutexLocker mlocker(&m_lock);
     233    QMutexLocker slocker(&LFDPriv::s_lock);
     234
     235    VERBOSE(VB_RECORD, LOC + "ClosePort()");
     236
     237    if (m_open_port_cnt < 1)
     238        return false;
     239
     240    m_open_port_cnt--;
     241
     242    if (m_open_port_cnt != 0)
     243        return true;
     244
     245    if (m_priv->handle)
     246    {
     247        if (IsNodeOpen())
     248            CloseNode();
     249
     250        VERBOSE(VB_RECORD, LOC + "Releasing raw1394 handle "<<m_open_port_cnt);
     251        raw1394_destroy_handle(m_priv->handle);
     252        LFDPriv::s_handle_info.erase(m_priv->handle);
     253        m_priv->handle = NULL;
     254    }
     255
     256    return true;
     257}
     258
     259void LinuxFirewireDevice::AddListener(TSDataListener *listener)
     260{
     261    FirewireDevice::AddListener(listener);
     262
     263    QMutexLocker locker(&m_lock);
     264    if (!m_listeners.empty())
     265    {
     266        OpenNode();
     267        OpenAVStream();
     268        StartStreaming();
     269    }
     270}
     271
     272void LinuxFirewireDevice::RemoveListener(TSDataListener *listener)
     273{
     274    FirewireDevice::RemoveListener(listener);
     275
     276    QMutexLocker locker(&m_lock);
     277    if (m_listeners.empty())
     278    {
     279        StopStreaming();
     280        CloseAVStream();
     281        CloseNode();
     282    }
     283}
     284
     285bool LinuxFirewireDevice::SendAVCCommand(
     286    const vector<uint8_t>  &_cmd,
     287    vector<uint8_t>        &result,
     288    int                     retry_cnt)
     289{
     290    retry_cnt = (retry_cnt < 0) ? 2 : retry_cnt;
     291
     292    result.clear();
     293
     294    if (!m_priv->handle || (m_node < 0))
     295        return false;
     296
     297    vector<uint8_t> cmd = _cmd;
     298    while (cmd.size() & 0x3)
     299        cmd.push_back(0x00);
     300
     301    if (cmd.size() > 4096)
     302        return false;
     303
     304    uint32_t cmdbuf[1024];
     305    for (uint i = 0; i < cmd.size(); i+=4)
     306        cmdbuf[i>>2] = cmd[i]<<24 | cmd[i+1]<<16 | cmd[i+2]<<8 | cmd[i+3];
     307
     308    uint result_length = 0;
     309
     310#ifdef USING_LIBAVC_5_3
     311    uint32_t *ret = avc1394_transaction_block2(
     312        m_priv->handle, m_node, cmdbuf, cmd.size() >> 2,
     313        &result_length, retry_cnt);
     314#else // if !USING_LIBAVC_5_3
     315    uint32_t *ret = avc1394_transaction_block(
     316        m_priv->handle, m_node, cmdbuf, cmd.size() >> 2, retry_cnt);
     317    result_length = cmd.size() >> 2;
     318#endif // !USING_LIBAVC_5_3
     319
     320    if (!ret)
     321        return false;
     322
     323    for (uint i = 0; i < result_length; i++)
     324    {
     325        result.push_back((ret[i]>>24) & 0xff);
     326        result.push_back((ret[i]>>16) & 0xff);
     327        result.push_back((ret[i]>>8)  & 0xff);
     328        result.push_back((ret[i])     & 0xff);
     329    }
     330
     331#ifdef USING_LIBAVC_5_3
     332    avc1394_transaction_block_close(m_priv->handle);
     333#endif // USING_LIBAVC_5_3
     334
     335    return true;
     336}
     337
     338bool LinuxFirewireDevice::IsPortOpen(void) const
     339{
     340    QMutexLocker locker(&m_lock);
     341
     342    return m_priv->handle;
     343}
     344
     345///////////////////////////////////////////////////////////////////////////////
     346// Private methods
     347
     348bool LinuxFirewireDevice::GetPortAndNode(void)
     349{
     350    m_port = m_node = -1;
     351
     352    vector<AVCInfo> list = GetSTBList();
     353    for (uint i = 0; i < list.size(); i++)
     354    {
     355        if (list[i].guid == m_guid)
     356        {
     357            m_port = list[i].port;
     358            m_node = list[i].node;
     359            break;
     360        }
     361    }
     362
     363    bool ok = (m_port >= 0) && (m_node >= 0);
     364
     365    if (!ok)
     366    {
     367        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to find port and node " +
     368                QString("for guid: 0x%1").arg(m_guid,0,16));
     369    }
     370    else
     371    {
     372        VERBOSE(VB_RECORD, LOC + QString("port: %1, node: %2")
     373                .arg(m_port).arg(m_node));
     374    }
     375
     376    return ok;
     377}
     378
     379bool LinuxFirewireDevice::OpenNode(void)
     380{
     381    if (m_use_p2p)
     382        return OpenP2PNode();
     383    else
     384        return OpenBroadcastNode();
     385}
     386
     387bool LinuxFirewireDevice::CloseNode(void)
     388{
     389    if (m_priv->is_p2p_node_open)
     390        return CloseP2PNode();
     391
     392    if (m_priv->is_bcast_node_open)
     393        return CloseBroadcastNode();
     394
     395    return true;
     396}
     397
     398bool LinuxFirewireDevice::OpenP2PNode(void)
     399{
     400    if (m_priv->is_bcast_node_open)
     401        return false;
     402
     403    if (m_priv->is_p2p_node_open)
     404        return true;
     405
     406    VERBOSE(VB_RECORD, LOC + "Opening P2P connection");
     407
     408    m_priv->channel = m_node;
     409    if (iec61883_cmp_create_p2p_output(m_priv->handle, m_node | 0xffc0, 0,
     410                                       m_priv->channel, m_speed) != 0)
     411    {
     412        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to create P2P connection");
     413
     414        m_priv->channel = -1;
     415        return false;
     416    }
     417
     418    m_priv->is_p2p_node_open = true;
     419
     420    return true;
     421}
     422
     423bool LinuxFirewireDevice::CloseP2PNode(void)
     424{
     425    if (m_priv->is_p2p_node_open && (m_priv->channel >= 0))
     426    {
     427        VERBOSE(VB_RECORD, LOC + "Closing P2P connection");
     428
     429        if (m_priv->avstream)
     430            CloseAVStream();
     431
     432        iec61883_cmp_disconnect(m_priv->handle, m_node | 0xffc0, 0,
     433                                raw1394_get_local_id(m_priv->handle),
     434                                -1, m_priv->channel, 0);
     435
     436        m_priv->channel = -1;
     437        m_priv->is_p2p_node_open = false;
     438    }
     439
     440    return true;
     441}
     442
     443bool LinuxFirewireDevice::OpenBroadcastNode(void)
     444{
     445    if (m_priv->is_p2p_node_open)
     446        return false;
     447
     448    if (m_priv->is_bcast_node_open)
     449        return true;
     450
     451    m_priv->channel = kBroadcastChannel - m_node;
     452
     453    VERBOSE(VB_RECORD, LOC + "Opening broadcast connection on " +
     454            QString("node %1, channel %2")
     455            .arg(m_node).arg(m_priv->channel));
     456
     457    if (m_priv->avstream)
     458        CloseAVStream();
     459
     460    int err = iec61883_cmp_create_bcast_output(
     461        m_priv->handle, m_node | 0xffc0, 0, m_priv->channel, m_speed);
     462
     463    if (err != 0)
     464    {
     465        VERBOSE(VB_IMPORTANT, LOC_ERR +
     466                "Failed to create Broadcast connection");
     467
     468        m_priv->channel = -1;
     469        return false;
     470    }
     471
     472    m_priv->is_bcast_node_open = true;
     473
     474    return true;
     475}
     476
     477bool LinuxFirewireDevice::CloseBroadcastNode(void)
     478{
     479    if (m_priv->is_bcast_node_open)
     480    {
     481        VERBOSE(VB_RECORD, LOC + "Closing broadcast connection");
     482
     483        m_priv->channel = -1;
     484        m_priv->is_bcast_node_open = false;
     485    }
     486    return true;
     487}
     488
     489bool LinuxFirewireDevice::OpenAVStream(void)
     490{
     491    VERBOSE(VB_RECORD, LOC + "OpenAVStream");
     492
     493    if (!IsNodeOpen() && !OpenNode())
     494        return false;
     495
     496    if (m_priv->avstream)
     497        return true;
     498
     499    VERBOSE(VB_RECORD, LOC + "Opening A/V stream object");
     500
     501    if (!m_priv->handle)
     502    {
     503        VERBOSE(VB_IMPORTANT, LOC +
     504                "Can not open AVStream without IEEE 1394 Port");
     505
     506        return false;
     507    }
     508
     509    m_priv->avstream = iec61883_mpeg2_recv_init(
     510        m_priv->handle, linux_firewire_device_tspacket_handler, this);
     511
     512    if (!m_priv->avstream)
     513    {
     514        VERBOSE(VB_IMPORTANT, LOC + "Unable to open AVStream" + ENO);
     515
     516        return false;
     517    }
     518
     519    iec61883_mpeg2_set_synch(m_priv->avstream, 1 /* sync on close */);
     520
     521    if (m_bufsz)
     522        SetAVStreamBufferSize(m_bufsz);
     523
     524    return true;
     525}
     526
     527bool LinuxFirewireDevice::CloseAVStream(void)
     528{
     529    if (!m_priv->avstream)
     530        return true;
     531
     532    VERBOSE(VB_RECORD, LOC + "Closing A/V stream object");
     533
     534    while (!m_resetting && m_listeners.size())
     535        RemoveListener(m_listeners[m_listeners.size() - 1]);
     536
     537    if (m_priv->is_streaming)
     538        StopStreaming();
     539
     540    iec61883_mpeg2_close(m_priv->avstream);
     541    m_priv->avstream = NULL;
     542
     543    return true;
     544}
     545
     546void *linux_firewire_device_streaming_thunk(void *param)
     547{
     548    LinuxFirewireDevice *mon = (LinuxFirewireDevice*) param;
     549    mon->RunStreaming();
     550    return NULL;
     551}
     552
     553void LinuxFirewireDevice::RunStreaming(void)
     554{
     555    VERBOSE(VB_RECORD, LOC + "RunStreaming -- start");
     556    m_lock.lock();
     557    m_priv->is_streaming_running = true;
     558
     559    uint no_data_cnt = 0;
     560    while (m_priv->is_streaming)
     561    {
     562        no_data_cnt = (LoopIteration(kNoDataTimeout)) ? 0 : no_data_cnt + 1;
     563
     564        if (m_priv->is_streaming && (no_data_cnt > 30))
     565        {
     566            no_data_cnt = 0;
     567            ResetBus();
     568        }
     569    }
     570
     571    m_priv->is_streaming_running = false;
     572    m_lock.unlock();
     573    VERBOSE(VB_RECORD, LOC + "RunStreaming -- end");
     574}
     575
     576bool LinuxFirewireDevice::StartStreaming(void)
     577{
     578    VERBOSE(VB_RECORD, LOC + "Starting A/V streaming");
     579    QMutexLocker locker(&m_priv->start_stop_streaming_lock);
     580    VERBOSE(VB_RECORD, LOC + "Starting A/V streaming -- locked");
     581
     582    if (m_priv->is_streaming)
     583        return m_priv->is_streaming;
     584
     585    assert(!m_priv->is_streaming_running);
     586
     587    if (!IsAVStreamOpen() && !OpenAVStream())
     588        return false;
     589
     590    if (m_priv->channel < 0)
     591    {
     592        VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting A/V streaming, no channel");
     593        return false;
     594    }
     595
     596    VERBOSE(VB_RECORD, LOC + "Starting A/V streaming -- really");
     597
     598    if (iec61883_mpeg2_recv_start(m_priv->avstream, m_priv->channel) == 0)
     599    {
     600        m_priv->is_streaming = true;
     601
     602        pthread_create(&m_priv->streaming_thread, NULL,
     603                       linux_firewire_device_streaming_thunk, this);
     604
     605        m_lock.unlock();
     606        while (!m_priv->is_streaming_running)
     607            usleep(5000);
     608        m_lock.lock();
     609    }
     610    else
     611    {
     612        VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting A/V streaming " + ENO);
     613    }
     614
     615    return m_priv->is_streaming;
     616}
     617
     618bool LinuxFirewireDevice::StopStreaming(void)
     619{
     620    VERBOSE(VB_RECORD, LOC + "Stopping A/V streaming");
     621    QMutexLocker locker(&m_priv->start_stop_streaming_lock);
     622    VERBOSE(VB_RECORD, LOC + "Stopping A/V streaming -- locked");
     623
     624    if (m_priv->is_streaming)
     625    {
     626        VERBOSE(VB_RECORD, LOC + "Stopping A/V streaming -- really");
     627
     628        m_priv->is_streaming = false;
     629
     630        VERBOSE(VB_RECORD, LOC + "Waiting for A/V streaming to stop");
     631        while (m_priv->is_streaming_running)
     632        {
     633            m_lock.unlock();
     634            usleep(5000);
     635            m_lock.lock();
     636        }
     637
     638        VERBOSE(VB_RECORD, LOC + "Joining A/V streaming thread");
     639        pthread_join(m_priv->streaming_thread, NULL);
     640
     641        iec61883_mpeg2_recv_stop(m_priv->avstream);
     642
     643        raw1394_iso_recv_flush(m_priv->handle);
     644    }
     645
     646    VERBOSE(VB_RECORD, LOC + "Stopped A/V streaming");
     647
     648    return true;
     649}
     650
     651bool LinuxFirewireDevice::StopStreamingLater(void)
     652{
     653    // TODO
     654    return true;
     655}
     656
     657bool LinuxFirewireDevice::SetAVStreamBufferSize(uint size_in_bytes)
     658{
     659    if (!m_priv->avstream)
     660        return false;
     661
     662    // Set buffered packets size
     663    uint   buffer_size      = max(size_in_bytes, 50 * TSPacket::SIZE);
     664    size_t buffered_packets = min(buffer_size / 4, kMaxBufferedPackets);
     665
     666    iec61883_mpeg2_set_buffers(m_priv->avstream, buffered_packets);
     667
     668    VERBOSE(VB_IMPORTANT, LOC +
     669            QString("Buffered packets %1 (%2 KB)")
     670            .arg(buffered_packets).arg(buffered_packets * 4));
     671
     672    return true;
     673}
     674
     675bool LinuxFirewireDevice::SetAVStreamSpeed(uint speed)
     676{
     677    if (!m_priv->avstream)
     678        return false;
     679
     680    uint curspeed = iec61883_mpeg2_get_speed(m_priv->avstream);
     681
     682    if (curspeed == speed)
     683    {
     684        m_speed = speed;
     685        return true;
     686    }
     687
     688    VERBOSE(VB_RECORD, LOC +
     689            QString("Changing Speed %1 -> %2")
     690            .arg(speed_to_string(curspeed))
     691            .arg(speed_to_string(m_speed)));
     692
     693    iec61883_mpeg2_set_speed(m_priv->avstream, speed);
     694
     695    if (speed == (uint)iec61883_mpeg2_get_speed(m_priv->avstream))
     696    {
     697        m_speed = speed;
     698        return true;
     699    }
     700
     701    VERBOSE(VB_IMPORTANT, LOC_WARN + "Unable to set firewire speed.");
     702
     703    return false;
     704}
     705
     706bool LinuxFirewireDevice::IsNodeOpen(void) const
     707{
     708    return m_priv->is_p2p_node_open || m_priv->is_bcast_node_open;
     709}
     710
     711bool LinuxFirewireDevice::IsAVStreamOpen(void) const
     712{
     713    return m_priv->avstream;
     714}
     715
     716bool LinuxFirewireDevice::ResetBus(void)
     717{
     718    VERBOSE(VB_IMPORTANT, LOC + "ResetBus() -- begin");
     719
     720    bool ok = (raw1394_reset_bus_new(m_priv->handle, RAW1394_LONG_RESET) == 0);
     721    if (!ok)
     722        VERBOSE(VB_IMPORTANT, LOC_ERR + "Bus Reset failed" + ENO);
     723
     724    VERBOSE(VB_IMPORTANT, LOC + "ResetBus() -- end");
     725
     726    return ok;
     727}
     728
     729bool LinuxFirewireDevice::LoopIteration(uint timeout_in_msec)
     730{
     731    if (m_resetting)
     732        return true;
     733
     734    int fwfd = raw1394_get_fd(m_priv->handle);
     735    if (fwfd < 0)
     736        return false;
     737
     738    struct timeval tv;
     739    fd_set rfds;
     740
     741    FD_ZERO(&rfds);
     742    FD_SET(fwfd, &rfds);
     743
     744    tv.tv_sec  = timeout_in_msec / 1000;
     745    tv.tv_usec = (timeout_in_msec % 1000) * 1000;
     746
     747    m_lock.unlock();
     748    if (select(fwfd + 1, &rfds, NULL, NULL, &tv) <= 0)
     749    {
     750        m_lock.lock();
     751        VERBOSE(VB_IMPORTANT, LOC + QString("No Input in %1 msec...")
     752                .arg(timeout_in_msec));
     753
     754        return false;
     755    }
     756    m_lock.lock();
     757
     758    int ret = raw1394_loop_iterate(m_priv->handle);
     759    if (ret)
     760    {
     761        VERBOSE(VB_IMPORTANT, LOC_ERR + "libraw1394_loop_iterate() " +
     762                QString("returned %1").arg(ret));
     763
     764        return false;
     765    }
     766
     767    return true;
     768}
     769
     770void LinuxFirewireDevice::PrintDropped(uint dropped_packets)
     771{
     772    if (dropped_packets == 1)
     773    {
     774        VERBOSE(VB_RECORD, LOC_ERR + "Dropped a TS packet");
     775    }
     776    else if (dropped_packets > 1)
     777    {
     778        VERBOSE(VB_RECORD, LOC_ERR +
     779                QString("Dropped %1 TS packets").arg(dropped_packets));
     780    }
     781}
     782
     783vector<AVCInfo> LinuxFirewireDevice::GetSTBList(void)
     784{
     785    vector<AVCInfo> list;
     786
     787    raw1394handle_t handle = raw1394_new_handle();
     788    if (!handle)
     789    {
     790        VERBOSE(VB_IMPORTANT, "Couldn't get handle" + ENO);
     791        return list;
     792    }
     793
     794    struct raw1394_portinfo port_info[16];
     795    int numcards = raw1394_get_port_info(handle, port_info, 16);
     796    if (numcards < 1)
     797    {
     798        raw1394_destroy_handle(handle);
     799        return list;
     800    }
     801
     802    for (int port = 0; port < numcards; port++)
     803    {
     804        if (raw1394_set_port(handle, port) < 0)
     805        {
     806            VERBOSE(VB_IMPORTANT, "Couldn't set port to " << port);
     807            continue;
     808        }
     809
     810        for (int node = 0; node < raw1394_get_nodecount(handle); node++)
     811        {
     812            AVCInfo info;
     813
     814            info.guid = get_guid(handle, 0xffc0 | node);
     815
     816            rom1394_directory dir;
     817            if (rom1394_get_directory(handle, node, &dir) < 0)
     818            {
     819                continue;
     820            }
     821            info.port     = port;
     822            info.node     = node;
     823            info.vendorid = dir.vendor_id;
     824            info.modelid  = dir.model_id;
     825            info.specid   = dir.unit_spec_id;
     826            info.firmware_revision = dir.unit_sw_version;
     827            info.product_name = QString("%1").arg(dir.label);
     828
     829            uint8_t unit_table[32];
     830           
     831            if (avc1394_subunit_info(handle, node, (uint32_t*)unit_table) < 0)
     832                memset(unit_table, 0xff, sizeof(unit_table));
     833
     834            if (IsSubunitType(unit_table, kAVCSubunitTypeTuner) &&
     835                IsSubunitType(unit_table, kAVCSubunitTypePanel))
     836            {
     837                list.push_back(info);
     838            }
     839        }
     840
     841        raw1394_destroy_handle(handle);
     842
     843        handle = raw1394_new_handle();
     844        if (!handle)
     845        {
     846            VERBOSE(VB_IMPORTANT, "Couldn't get handle "
     847                    "(after setting port "<<port<<")" + ENO);
     848            handle = NULL;
     849            break;
     850        }
     851
     852        numcards = raw1394_get_port_info(handle, port_info, 16);
     853    }
     854
     855    if (handle)
     856        raw1394_destroy_handle(handle);
     857
     858    return list;
     859}
     860
     861int linux_firewire_device_tspacket_handler(
     862    unsigned char *tspacket, int len, uint dropped, void *callback_data)
     863{
     864    LinuxFirewireDevice *fw = (LinuxFirewireDevice*) callback_data;
     865    if (!fw)
     866        return 0;
     867
     868    if (dropped)
     869        fw->PrintDropped(dropped);
     870
     871    if (len > 0)
     872        fw->BroadcastToListeners(tspacket, len);
     873
     874    return 1;
     875}
     876
     877static QString speed_to_string(uint speed)
     878{
     879    if (speed > 3)
     880        return QString("Invalid Speed (%1)").arg(speed);
     881
     882    static const uint speeds[] = { 100, 200, 400, 800 };
     883    return QString("%1Mbps").arg(speeds[speed]);
     884}
     885
     886static int linux_firewire_device_bus_reset_handler(
     887    raw1394handle_t handle, unsigned int generation)
     888{
     889    QMutexLocker locker(&LFDPriv::s_lock);
     890
     891    handle_to_lfd_t::iterator it = LFDPriv::s_handle_info.find(handle);
     892
     893    if (it != LFDPriv::s_handle_info.end())
     894        (*it)->HandleBusReset(generation);
     895
     896    return 0;
     897}
     898
     899// get_guid copied from plugreport, Copyright 2002-2004 Dan Dennedy GPL v2+
     900#define PLUGREPORT_GUID_HI 0x0C
     901#define PLUGREPORT_GUID_LO 0x10
     902static uint64_t get_guid(raw1394handle_t handle, nodeid_t node)
     903{
     904    uint32_t quadlet;
     905    uint64_t offset;
     906    uint64_t guid = 0;
     907
     908    offset = CSR_REGISTER_BASE + CSR_CONFIG_ROM + PLUGREPORT_GUID_HI;
     909    raw1394_read(handle, node, offset, sizeof(uint32_t), &quadlet);
     910    quadlet = htonl(quadlet);
     911    guid = quadlet;
     912    guid <<= 32;
     913    offset = CSR_REGISTER_BASE + CSR_CONFIG_ROM + PLUGREPORT_GUID_LO;
     914    raw1394_read(handle, node, offset, sizeof(uint32_t), &quadlet);
     915    quadlet = htonl(quadlet);
     916    guid += quadlet;
     917
     918    return guid;
     919}
  • programs/mythbackend/backendutil.cpp

     
    22#ifdef CONFIG_DARWIN
    33#include <sys/param.h>
    44#include <sys/mount.h>
     5unsigned long long int abs(long long int v)
     6    { return (unsigned long long int) ((v < 0) ? -v : v); }
    57#elif __linux__
    68#include <sys/vfs.h>
    79#endif