Ticket #1648: firewire-sm-v41.patch

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

Adds self-resetting ability to OSX recorder, so it can recover after switching from a 5C channel.

  • 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 <algorithm>
     23#include <vector>
     24using namespace std;
     25
     26// MythTV headers
     27#include "darwinfirewiredevice.h"
     28#include "darwinavcinfo.h"
     29#include "mythcontext.h"
     30
     31// Apple Firewire example headers
     32#include <AVCVideoServices/StringLogger.h>
     33#include <AVCVideoServices/MPEG2Receiver.h>
     34
     35// header not used because it also requires MPEG2Transmitter.h
     36//#include <AVCVideoServices/FireWireMPEG.h>
     37namespace AVS
     38{
     39    IOReturn CreateMPEG2Receiver(
     40        MPEG2Receiver           **ppReceiver,
     41        DataPushProc              dataPushProcHandler,
     42        void                     *pDataPushProcRefCon = nil,
     43        MPEG2ReceiverMessageProc  messageProcHandler  = nil,
     44        void                     *pMessageProcRefCon  = nil,
     45        StringLogger             *stringLogger        = nil,
     46        IOFireWireLibNubRef       nubInterface        = nil,
     47        unsigned int              cyclesPerSegment    =
     48            kCyclesPerReceiveSegment,
     49        unsigned int              numSegments         =
     50            kNumReceiveSegments,
     51        bool                      doIRMAllocations    = false);
     52    IOReturn DestroyMPEG2Receiver(MPEG2Receiver *pReceiver);
     53}
     54
     55#define LOC      QString("DFireDev(%1): ").arg(m_guid)
     56#define LOC_WARN QString("DFireDev(%1), Warning: ").arg(m_guid)
     57#define LOC_ERR  QString("DFireDev(%1), Error: ").arg(m_guid)
     58
     59#define kAnyAvailableIsochChannel 0xFFFFFFFF
     60#define kNoDataTimeout            300  /* msec */
     61#define kResetTimeout             1500 /* msec */
     62
     63static IOReturn dfd_tspacket_handler_thunk(
     64    long unsigned int tsPacketCount, UInt32 **ppBuf, void *callback_data);
     65static void dfd_update_device_list(void *dfd, io_iterator_t iterator);
     66static void dfd_streaming_log_message(char *pString);
     67
     68class DFDPriv
     69{
     70  public:
     71    DFDPriv() :
     72        controller_thread_cf_ref(NULL), controller_thread_running(false),
     73        notify_port(NULL), notify_source(NULL), deviter(NULL),
     74        actual_fwchan(-1), is_streaming(false), avstream(NULL), logger(NULL),
     75        no_data_cnt(0), no_data_timer_set(false)
     76    {
     77        logger = new AVS::StringLogger(dfd_streaming_log_message);
     78    }
     79
     80    ~DFDPriv()
     81    {
     82        avcinfo_list_t::iterator it = devices.begin();
     83        for (; it != devices.end(); ++it)
     84            delete (*it);
     85        devices.clear();
     86
     87        if (logger)
     88        {
     89            delete logger;
     90            logger = NULL;
     91        }
     92    }
     93
     94    pthread_t                 controller_thread;
     95    CFRunLoopRef              controller_thread_cf_ref;
     96    bool                      controller_thread_running;
     97
     98    IONotificationPortRef     notify_port;
     99    CFRunLoopSourceRef        notify_source;
     100    io_iterator_t             deviter;
     101
     102    int                       actual_fwchan;
     103    bool                      is_streaming;
     104    AVS::MPEG2Receiver       *avstream;
     105    AVS::StringLogger        *logger;
     106    uint                      no_data_cnt;
     107    bool                      no_data_timer_set;
     108    MythTimer                 no_data_timer;
     109
     110    avcinfo_list_t            devices;
     111};
     112
     113DarwinFirewireDevice::DarwinFirewireDevice(
     114    uint64_t guid, uint subunitid, uint speed) :
     115    FirewireDevice(guid, subunitid, speed),
     116    m_local_node(-1), m_remote_node(-1), m_priv(new DFDPriv())
     117{
     118}
     119
     120DarwinFirewireDevice::~DarwinFirewireDevice()
     121{
     122    if (IsPortOpen())
     123    {
     124        VERBOSE(VB_IMPORTANT, LOC_ERR + "ctor called with open port");
     125        while (IsPortOpen())
     126            ClosePort();
     127    }
     128
     129    if (m_priv)
     130    {
     131        delete m_priv;
     132        m_priv = NULL;
     133    }
     134}
     135
     136void DarwinFirewireDevice::RunController(void)
     137{
     138    m_priv->controller_thread_cf_ref = CFRunLoopGetCurrent();
     139
     140    // Set up IEEE-1394 bus change notification
     141    mach_port_t master_port;
     142    int ret = IOMasterPort(bootstrap_port, &master_port);
     143    if (kIOReturnSuccess == ret)
     144    {
     145        m_priv->notify_port   = IONotificationPortCreate(master_port);
     146        m_priv->notify_source = IONotificationPortGetRunLoopSource(
     147            m_priv->notify_port);
     148
     149        CFRunLoopAddSource(m_priv->controller_thread_cf_ref,
     150                           m_priv->notify_source,
     151                           kCFRunLoopDefaultMode);
     152
     153        ret = IOServiceAddMatchingNotification(
     154            m_priv->notify_port, kIOMatchedNotification,
     155            IOServiceMatching("IOFireWireAVCUnit"),
     156            dfd_update_device_list, this, &m_priv->deviter);
     157    }
     158
     159    if (kIOReturnSuccess == ret)
     160        dfd_update_device_list(this, m_priv->deviter);
     161
     162    m_priv->controller_thread_running = true;
     163
     164    if (kIOReturnSuccess == ret)
     165        CFRunLoopRun();
     166
     167    QMutexLocker locker(&m_lock); // ensure that controller_thread_running seen
     168
     169    m_priv->controller_thread_running = false;
     170}
     171
     172void DarwinFirewireDevice::StartController(void)
     173{
     174    m_lock.unlock();
     175
     176    pthread_create(&m_priv->controller_thread, NULL,
     177                   dfd_controller_thunk, this);
     178
     179    m_lock.lock();
     180    while (!m_priv->controller_thread_running)
     181    {
     182        m_lock.unlock();
     183        usleep(5000);
     184        m_lock.lock();
     185    }
     186}
     187
     188void DarwinFirewireDevice::StopController(void)
     189{
     190    if (!m_priv->controller_thread_running)
     191        return;
     192
     193    if (m_priv->deviter)
     194    {
     195        IOObjectRelease(m_priv->deviter);
     196        m_priv->deviter = NULL;
     197    }
     198   
     199    if (m_priv->notify_source)
     200    {
     201        CFRunLoopSourceInvalidate(m_priv->notify_source);
     202        m_priv->notify_source = NULL;
     203    }
     204
     205    if (m_priv->notify_port)
     206    {
     207        IONotificationPortDestroy(m_priv->notify_port);
     208        m_priv->notify_port = NULL;
     209    }
     210
     211    CFRunLoopStop(m_priv->controller_thread_cf_ref);
     212   
     213    while (m_priv->controller_thread_running)
     214    {
     215        m_lock.unlock();
     216        usleep(100 * 1000);
     217        m_lock.lock();
     218    }
     219}
     220
     221bool DarwinFirewireDevice::OpenPort(void)
     222{
     223    QMutexLocker locker(&m_lock);
     224
     225    VERBOSE(VB_RECORD, LOC + "OpenPort()");
     226
     227    if (GetInfoPtr() && GetInfoPtr()->IsOpen())
     228    {
     229        m_open_port_cnt++;
     230        return true;
     231    }
     232
     233    StartController();
     234
     235    if (!m_priv->controller_thread_running)
     236    {
     237        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to start firewire thread.");
     238        return false;
     239    }
     240
     241    if (!GetInfoPtr())
     242    {
     243        VERBOSE(VB_IMPORTANT, LOC_ERR + "No IEEE-1394 device at " +
     244                QString("guid: 0x%1").arg(m_guid,0,16));
     245       
     246        StopController();
     247        return false;
     248    }
     249
     250    VERBOSE(VB_RECORD, LOC + "Opening AVC Device");
     251    VERBOSE(VB_RECORD, LOC + GetSubunitInfoString(GetInfoPtr()->unit_table));
     252
     253    if (!IsSubunitType(GetInfoPtr()->unit_table, kAVCSubunitTypeTuner) ||
     254        !IsSubunitType(GetInfoPtr()->unit_table, kAVCSubunitTypePanel))
     255    {
     256        VERBOSE(VB_IMPORTANT, LOC_ERR + QString("No STB at guid: 0x%1")
     257                .arg(m_guid,0,16));
     258
     259        StopController();
     260        return false;
     261    }
     262
     263    bool ok = GetInfoPtr()->Open(m_priv->controller_thread_cf_ref);
     264    if (!ok)
     265    {
     266        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to get handle for port");
     267
     268        return false;
     269    }
     270
     271    if (!GetInfoPtr()->GetDeviceNodes(m_local_node, m_remote_node))
     272    {
     273        if (m_local_node < 0)
     274        {
     275            VERBOSE(VB_IMPORTANT, LOC_WARN + "Failed to query local node");
     276            m_local_node = 0;
     277        }
     278
     279        if (m_remote_node < 0)
     280        {
     281            VERBOSE(VB_IMPORTANT, LOC_WARN + "Failed to query remote node");
     282            m_remote_node = 0;
     283        }
     284    }
     285
     286    m_open_port_cnt++;
     287
     288    return true;
     289}
     290
     291bool DarwinFirewireDevice::ClosePort(void)
     292{
     293    QMutexLocker locker(&m_lock);
     294
     295    VERBOSE(VB_RECORD, LOC + "ClosePort()");
     296
     297    if (m_open_port_cnt < 1)
     298        return false;
     299
     300    m_open_port_cnt--;
     301
     302    if (m_open_port_cnt != 0)
     303        return true;
     304
     305    if (GetInfoPtr() && GetInfoPtr()->IsOpen())
     306    {
     307        VERBOSE(VB_RECORD, LOC + "Closing AVC Device");
     308
     309        GetInfoPtr()->Close();
     310    }
     311
     312    StopController();
     313    m_local_node  = -1;
     314    m_remote_node = -1;
     315
     316    return true;
     317}
     318
     319bool DarwinFirewireDevice::OpenAVStream(void)
     320{
     321    if (IsAVStreamOpen())
     322        return true;
     323
     324    int max_speed = GetMaxSpeed();
     325    VERBOSE(VB_IMPORTANT, "Max Speed: "<<max_speed<<" Our speed: "<<m_speed);
     326    m_speed = min((uint)max_speed, m_speed);
     327
     328    uint fwchan = 0;
     329    bool streaming = IsSTBStreaming(&fwchan);
     330    VERBOSE(VB_IMPORTANT, QString("STB is %1already streaming on fwchan: %2")
     331            .arg(streaming?"":"not ").arg(fwchan));
     332
     333    // TODO we should use the stream if it already exists,
     334    //      this is especially true if it is a broadcast stream...
     335
     336    int ret = AVS::CreateMPEG2Receiver(
     337        &m_priv->avstream,
     338        dfd_tspacket_handler_thunk, this,
     339        dfd_stream_msg, this,
     340        m_priv->logger /* StringLogger */,
     341        GetInfoPtr()->fw_handle,
     342        AVS::kCyclesPerReceiveSegment,
     343        AVS::kNumReceiveSegments,
     344        true /* p2p */);
     345
     346    if (kIOReturnSuccess != ret)
     347    {
     348        VERBOSE(VB_IMPORTANT, LOC_ERR + "Couldn't create A/V stream object");
     349        return false;
     350    }
     351
     352    m_priv->avstream->registerNoDataNotificationCallback(
     353        dfd_no_data_notification, this, kNoDataTimeout);
     354
     355    return true;
     356}
     357
     358int DarwinFirewireDevice::GetMaxSpeed(void)
     359{
     360    IOFireWireLibDeviceRef fw_handle = GetInfoPtr()->fw_handle;
     361
     362    if ((*fw_handle)->version < 4)
     363    {
     364        // Just get the STB's info & assume we can handle it
     365        io_object_t dev = (*fw_handle)->GetDevice(fw_handle);
     366
     367        FWAddress addr(0xffff, 0xf0000900, m_remote_node);
     368        uint32_t val;
     369        int ret = (*fw_handle)->ReadQuadlet(
     370            fw_handle, dev, &addr, (UInt32*) &val, false, 0);
     371
     372        return (ret == kIOReturnSuccess) ? (int)((val>>30) & 0x3) : -1;
     373    }
     374
     375    uint32_t generation = 0;
     376    IOFWSpeed speed;
     377    int ret = (*fw_handle)->GetBusGeneration(fw_handle, (UInt32*)&generation);
     378    if (kIOReturnSuccess == ret)
     379    {
     380        ret = (*fw_handle)->GetSpeedBetweenNodes(
     381            fw_handle, generation, m_remote_node, m_local_node, &speed) ;
     382    }
     383
     384    return (ret == kIOReturnSuccess) ? (int)speed : -1;
     385}
     386
     387bool DarwinFirewireDevice::IsSTBStreaming(uint *fw_channel)
     388{
     389    IOFireWireLibDeviceRef fw_handle = GetInfoPtr()->fw_handle;
     390    io_object_t dev = (*fw_handle)->GetDevice(fw_handle);
     391
     392    FWAddress addr(0xffff, 0xf0000904, m_remote_node);
     393    uint32_t val;
     394    int ret = (*fw_handle)->ReadQuadlet(
     395        fw_handle, dev, &addr, (UInt32*) &val, false, 0);
     396
     397    if (ret != kIOReturnSuccess)
     398        return false;
     399
     400    if (val & (kIOFWPCRBroadcast | kIOFWPCRP2PCount))
     401    {
     402        if (fw_channel)
     403            *fw_channel = (val & kIOFWPCRChannel) >> kIOFWPCRChannelPhase;
     404
     405        return true;
     406    }
     407
     408    return false;
     409}
     410
     411bool DarwinFirewireDevice::CloseAVStream(void)
     412{
     413    if (!m_priv->avstream)
     414        return true;
     415
     416    StopStreaming();
     417
     418    VERBOSE(VB_RECORD, LOC + "Destroying A/V stream object");
     419    AVS::DestroyMPEG2Receiver(m_priv->avstream);
     420    m_priv->avstream = NULL;
     421
     422    return true;
     423}
     424
     425bool DarwinFirewireDevice::IsAVStreamOpen(void) const
     426{
     427    return m_priv->avstream;
     428}
     429
     430bool DarwinFirewireDevice::ResetBus(void)
     431{
     432    VERBOSE(VB_IMPORTANT, LOC + "ResetBus() -- begin");
     433
     434    if (!GetInfoPtr() || !GetInfoPtr()->fw_handle)
     435        return false;
     436
     437    IOFireWireLibDeviceRef fw_handle = GetInfoPtr()->fw_handle;
     438    bool ok = (*fw_handle)->BusReset(fw_handle) == kIOReturnSuccess;
     439
     440    if (!ok)
     441        VERBOSE(VB_IMPORTANT, LOC_ERR + "Bus Reset failed" + ENO);
     442
     443    VERBOSE(VB_IMPORTANT, LOC + "ResetBus() -- end");
     444
     445    return ok;
     446}
     447
     448bool DarwinFirewireDevice::StartStreaming(void)
     449{
     450    if (m_priv->is_streaming)
     451        return m_priv->is_streaming;
     452
     453    VERBOSE(VB_RECORD, LOC + "Starting A/V streaming");
     454
     455    if (!IsAVStreamOpen() && !OpenAVStream())
     456    {
     457        VERBOSE(VB_IMPORTANT, LOC + "Starting A/V streaming: FAILED");
     458        return false;
     459    }
     460
     461    m_priv->avstream->setReceiveIsochChannel(kAnyAvailableIsochChannel);
     462    m_priv->avstream->setReceiveIsochSpeed((IOFWSpeed) m_speed);
     463    int ret = m_priv->avstream->startReceive();
     464
     465    m_priv->is_streaming = (kIOReturnSuccess == ret);
     466
     467    VERBOSE(VB_IMPORTANT, LOC + "Starting A/V streaming: "
     468            <<((m_priv->is_streaming)?"success":"failure"));
     469
     470    return m_priv->is_streaming;
     471}
     472
     473bool DarwinFirewireDevice::StopStreaming(void)
     474{
     475    if (!m_priv->is_streaming)
     476        return true;
     477
     478    VERBOSE(VB_RECORD, LOC + "Stopping A/V streaming");
     479
     480    bool ok = (kIOReturnSuccess == m_priv->avstream->stopReceive());
     481    m_priv->is_streaming = !ok;
     482
     483    if (!ok)
     484    {
     485        VERBOSE(VB_RECORD, LOC_ERR + "Failed to stop A/V streaming");
     486        return false;
     487    }
     488
     489    VERBOSE(VB_RECORD, LOC + "Stopped A/V streaming");
     490    return true;
     491}
     492
     493bool DarwinFirewireDevice::SendAVCCommand(const vector<uint8_t> &cmd,
     494                                          vector<uint8_t>       &result,
     495                                          int                   retry_cnt)
     496{
     497    return GetInfoPtr()->SendAVCCommand(cmd, result, retry_cnt);
     498}
     499
     500bool DarwinFirewireDevice::IsPortOpen(void) const
     501{
     502    QMutexLocker locker(&m_lock);
     503
     504    if (!GetInfoPtr())
     505        return false;
     506
     507    return GetInfoPtr()->IsOpen();
     508}
     509
     510void DarwinFirewireDevice::AddListener(TSDataListener *listener)
     511{
     512    FirewireDevice::AddListener(listener);
     513
     514    QMutexLocker locker(&m_lock);
     515    if (!m_listeners.empty())
     516        StartStreaming();
     517}
     518
     519void DarwinFirewireDevice::RemoveListener(TSDataListener *listener)
     520{
     521    FirewireDevice::RemoveListener(listener);
     522
     523    QMutexLocker locker(&m_lock);
     524    if (m_priv->is_streaming && m_listeners.empty())
     525    {
     526        StopStreaming();
     527        CloseAVStream();
     528    }
     529}
     530
     531void DarwinFirewireDevice::BroadcastToListeners(
     532    const unsigned char *data, uint dataSize)
     533{
     534    QMutexLocker locker(&m_lock);
     535    FirewireDevice::BroadcastToListeners(data, dataSize);
     536}
     537
     538void DarwinFirewireDevice::ProcessNoDataMessage(void)
     539{
     540    if (m_priv->no_data_timer_set)
     541    {
     542        int short_interval = kNoDataTimeout + (kNoDataTimeout>>1);
     543        bool recent = m_priv->no_data_timer.elapsed() <= short_interval;
     544        m_priv->no_data_cnt = (recent) ? m_priv->no_data_cnt + 1 : 1;
     545    }
     546    m_priv->no_data_timer_set = true;
     547    m_priv->no_data_timer.start();
     548
     549    VERBOSE(VB_IMPORTANT, LOC_WARN + QString("No Input in %1 msecs")
     550            .arg(m_priv->no_data_cnt * kNoDataTimeout));
     551
     552    if (m_priv->no_data_cnt > (kResetTimeout / kNoDataTimeout))
     553    {
     554        m_priv->no_data_timer_set = false;
     555        m_priv->no_data_cnt = 0;
     556        ResetBus();
     557    }
     558}
     559
     560void DarwinFirewireDevice::ProcessStreamingMessage(
     561    uint32_t msg, uint32_t param1, uint32_t param2)
     562{
     563    int plug_number = 0;
     564
     565    if (AVS::kMpeg2ReceiverAllocateIsochPort == msg)
     566    {
     567        int speed = param1, fw_channel = param2;
     568
     569        bool ok = UpdatePlugRegister(
     570            plug_number, fw_channel, speed, true, false);
     571
     572        VERBOSE(VB_IMPORTANT, LOC + QString("AllocateIsochPort(%1,%2) %3")
     573                .arg(fw_channel).arg(speed).arg(((ok)?"ok":"error")));
     574    }
     575    else if (AVS::kMpeg2ReceiverReleaseIsochPort == msg)
     576    {
     577        int ret = UpdatePlugRegister(plug_number, -1, -1, false, true);
     578
     579        VERBOSE(VB_IMPORTANT, LOC + "ReleaseIsochPort "
     580                <<((kIOReturnSuccess == ret)?"ok":"error"));
     581    }
     582    else if (AVS::kMpeg2ReceiverDCLOverrun == msg)
     583    {
     584        VERBOSE(VB_IMPORTANT, LOC_ERR + "DCL Overrun");
     585    }
     586    else if (AVS::kMpeg2ReceiverReceivedBadPacket == msg)
     587    {
     588        VERBOSE(VB_IMPORTANT, LOC_ERR + "Received Bad Packet");
     589    }
     590    else
     591    {
     592        VERBOSE(VB_GENERAL, LOC +
     593                QString("Streaming Message: %1").arg(msg));
     594    }
     595}
     596
     597vector<AVCInfo> DarwinFirewireDevice::GetSTBList(void)
     598{
     599    vector<AVCInfo> list;
     600
     601    {
     602        DarwinFirewireDevice dev(0,0,0);
     603
     604        dev.m_lock.lock();
     605        dev.StartController();
     606        dev.m_lock.unlock();
     607
     608        list = dev.GetSTBListPrivate();
     609
     610        dev.m_lock.lock();
     611        dev.StopController();
     612        dev.m_lock.unlock();
     613    }
     614
     615    return list;
     616}
     617
     618vector<AVCInfo> DarwinFirewireDevice::GetSTBListPrivate(void)
     619{
     620    VERBOSE(VB_IMPORTANT, "GetSTBListPrivate -- begin");
     621    QMutexLocker locker(&m_lock);
     622    VERBOSE(VB_IMPORTANT, "GetSTBListPrivate -- got lock");
     623
     624    vector<AVCInfo> list;
     625
     626    avcinfo_list_t::iterator it = m_priv->devices.begin();
     627    for (; it != m_priv->devices.end(); ++it)
     628    {
     629        if (IsSubunitType((*it)->unit_table, kAVCSubunitTypeTuner) &&
     630            IsSubunitType((*it)->unit_table, kAVCSubunitTypePanel))
     631        {
     632            list.push_back(*(*it));
     633        }
     634    }
     635
     636    VERBOSE(VB_IMPORTANT, "GetSTBListPrivate -- end");
     637    return list;
     638}
     639
     640void DarwinFirewireDevice::UpdateDeviceListItem(uint64_t guid, void *pitem)
     641{
     642    QMutexLocker locker(&m_lock);
     643
     644    avcinfo_list_t::iterator it = m_priv->devices.find(guid);
     645
     646    if (it == m_priv->devices.end())
     647    {
     648        DarwinAVCInfo *ptr = new DarwinAVCInfo();
     649
     650        VERBOSE(VB_IMPORTANT, "Adding device list item 0x"
     651                <<hex<<guid<<" ptr: "<<ptr<<dec);
     652
     653        m_priv->devices[guid] = ptr;
     654        it = m_priv->devices.find(guid);
     655    }
     656
     657    io_object_t &item = *((io_object_t*) pitem);
     658    if (it != m_priv->devices.end())
     659    {
     660        (*it)->Update(guid, this, m_priv->notify_port,
     661                      m_priv->controller_thread_cf_ref, item);
     662    }
     663}
     664
     665DarwinAVCInfo *DarwinFirewireDevice::GetInfoPtr(void)
     666{
     667    avcinfo_list_t::iterator it = m_priv->devices.find(m_guid);
     668    return (it == m_priv->devices.end()) ? NULL : *it;
     669}
     670
     671const DarwinAVCInfo *DarwinFirewireDevice::GetInfoPtr(void) const
     672{
     673    avcinfo_list_t::iterator it = m_priv->devices.find(m_guid);
     674    return (it == m_priv->devices.end()) ? NULL : *it;
     675}
     676
     677
     678bool DarwinFirewireDevice::UpdatePlugRegisterPrivate(
     679    uint plug_number, int new_fw_chan, int new_speed,
     680    bool add_plug, bool remove_plug)
     681{
     682    if (!GetInfoPtr())
     683        return false;
     684
     685    IOFireWireLibDeviceRef fw_handle = GetInfoPtr()->fw_handle;
     686    if (!fw_handle)
     687        return false;
     688
     689    io_object_t dev = (*fw_handle)->GetDevice(fw_handle);
     690
     691    // Read the register
     692    uint      low_addr = kPCRBaseAddress + 4 + (plug_number << 2);
     693    FWAddress addr(0xffff, low_addr, m_remote_node);
     694    uint32_t  old_plug_val;
     695    if (kIOReturnSuccess != (*fw_handle)->ReadQuadlet(
     696            fw_handle, dev, &addr, (UInt32*) &old_plug_val, false, 0))
     697    {
     698        return false;
     699    }
     700
     701    int old_plug_cnt = (old_plug_val >> 24) & 0x3f;
     702    int old_fw_chan  = (old_plug_val >> 16) & 0x3f;
     703    int old_speed    = (old_plug_val >> 14) & 0x03;
     704
     705    int new_plug_cnt = (int) old_plug_cnt;
     706    new_plug_cnt += ((add_plug) ? 1 : 0) - ((remove_plug) ? 1 : 0);
     707    if ((new_plug_cnt > 0x3f) || (new_plug_cnt < 0))
     708    {
     709        VERBOSE(VB_IMPORTANT, LOC_ERR + "Invalid Plug Count "<<new_plug_cnt);
     710
     711        return false;
     712    }
     713
     714    new_fw_chan = (new_fw_chan >= 0) ? new_fw_chan : old_fw_chan;
     715    if (old_plug_cnt && (new_fw_chan != old_fw_chan))
     716    {
     717        VERBOSE(VB_IMPORTANT, LOC_WARN +
     718                "Ignoring FWChan change request, plug already open");
     719
     720        new_fw_chan = old_fw_chan;
     721    }
     722
     723    new_speed = (new_speed >= 0) ? new_speed : old_speed;
     724    if (old_plug_cnt && (new_speed != old_speed))
     725    {
     726        VERBOSE(VB_IMPORTANT, LOC_WARN +
     727                "Ignoring speed change request, plug already open");
     728
     729        new_speed = old_speed;
     730    }
     731
     732    uint32_t new_plug_val = old_plug_val;
     733
     734    new_plug_val &= ~(0x3f<<24);
     735    new_plug_val &= (remove_plug) ? ~kIOFWPCRBroadcast : ~0x0;
     736    new_plug_val |= (new_plug_cnt & 0x3f) << 24;
     737
     738    new_plug_val &= ~(0x3f<<16);
     739    new_plug_val |= (new_fw_chan & 0x3F) << 16;
     740
     741    new_plug_val &= ~(0x03<<14);
     742    new_plug_val |= (new_speed & 0x03) << 14;
     743
     744    return (kIOReturnSuccess == (*fw_handle)->CompareSwap(
     745                fw_handle, dev, &addr, old_plug_val, new_plug_val, false, 0));
     746}
     747
     748void DarwinFirewireDevice::HandleBusReset(void)
     749{
     750    int plug_number = 0;
     751    if (!GetInfoPtr())
     752        return;
     753
     754    int fw_channel = m_priv->actual_fwchan;
     755    bool ok = UpdatePlugRegister(plug_number, fw_channel,
     756                                 m_speed, true, false);
     757    if (!ok)
     758    {
     759        ok = UpdatePlugRegister(plug_number, kAnyAvailableIsochChannel,
     760                                m_speed, true, false);
     761    }
     762
     763    if (!ok)
     764        VERBOSE(VB_IMPORTANT, LOC + "Reset: Failed to reconnect");
     765    else
     766        VERBOSE(VB_RECORD, LOC + "Reset: Reconnected succesfully");
     767}
     768
     769bool DarwinFirewireDevice::UpdatePlugRegister(
     770    uint plug_number, int fw_chan, int speed,
     771    bool add_plug, bool remove_plug, uint retry_cnt)
     772{
     773    if (!GetInfoPtr() || !GetInfoPtr()->fw_handle)
     774        return false;
     775
     776    bool ok = false;
     777
     778    for (uint i = 0; (i < retry_cnt) && !ok; i++)
     779    {
     780        ok = UpdatePlugRegisterPrivate(
     781            plug_number, fw_chan, speed, add_plug, remove_plug);
     782    }
     783
     784    m_priv->actual_fwchan = (ok) ? fw_chan : kAnyAvailableIsochChannel;
     785
     786    return ok;
     787}
     788
     789void DarwinFirewireDevice::HandleDeviceChange(uint messageType)
     790{
     791    QString loc = LOC + "HandleDeviceChange: ";
     792
     793    if (kIOMessageServiceIsTerminated == messageType)
     794    {
     795        VERBOSE(VB_RECORD, loc + "Disconnect");
     796        // stop printing no data messages.. don't try to open
     797        return;
     798    }
     799
     800    if (kIOMessageServiceIsAttemptingOpen == messageType)
     801    {
     802        VERBOSE(VB_RECORD, loc + "Attempting open");
     803        return;
     804    }
     805
     806    if (kIOMessageServiceWasClosed == messageType)
     807    {
     808        VERBOSE(VB_RECORD, loc + "Device Closed");
     809        // fill unit_table
     810        return;
     811    }
     812
     813    if (kIOMessageServiceIsSuspended == messageType)
     814    {
     815        VERBOSE(VB_RECORD, loc + "kIOMessageServiceIsSuspended");
     816        // start of reset
     817        return;
     818    }
     819
     820    if (kIOMessageServiceIsResumed == messageType)
     821    {
     822        // end of reset
     823        HandleBusReset();
     824    }
     825
     826    if (kIOMessageServiceIsTerminated == messageType)
     827        VERBOSE(VB_RECORD, loc + "kIOMessageServiceIsTerminated");
     828    else if (kIOMessageServiceIsRequestingClose == messageType)
     829        VERBOSE(VB_RECORD, loc + "kIOMessageServiceIsRequestingClose");
     830    else if (kIOMessageServiceIsAttemptingOpen == messageType)
     831        VERBOSE(VB_RECORD, loc + "kIOMessageServiceIsAttemptingOpen");
     832    else if (kIOMessageServiceWasClosed == messageType)
     833        VERBOSE(VB_RECORD, loc + "kIOMessageServiceWasClosed");
     834    else if (kIOMessageServiceBusyStateChange == messageType)
     835        VERBOSE(VB_RECORD, loc + "kIOMessageServiceBusyStateChange");
     836    else if (kIOMessageCanDevicePowerOff == messageType)
     837        VERBOSE(VB_RECORD, loc + "kIOMessageCanDevicePowerOff");
     838    else if (kIOMessageDeviceWillPowerOff == messageType)
     839        VERBOSE(VB_RECORD, loc + "kIOMessageDeviceWillPowerOff");
     840    else if (kIOMessageDeviceWillNotPowerOff == messageType)
     841        VERBOSE(VB_RECORD, loc + "kIOMessageDeviceWillNotPowerOff");
     842    else if (kIOMessageDeviceHasPoweredOn == messageType)
     843        VERBOSE(VB_RECORD, loc + "kIOMessageDeviceHasPoweredOn");
     844    else if (kIOMessageCanSystemPowerOff == messageType)
     845        VERBOSE(VB_RECORD, loc + "kIOMessageCanSystemPowerOff");
     846    else if (kIOMessageSystemWillPowerOff == messageType)
     847        VERBOSE(VB_RECORD, loc + "kIOMessageSystemWillPowerOff");
     848    else if (kIOMessageSystemWillNotPowerOff == messageType)
     849        VERBOSE(VB_RECORD, loc + "kIOMessageSystemWillNotPowerOff");
     850    else if (kIOMessageCanSystemSleep == messageType)
     851        VERBOSE(VB_RECORD, loc + "kIOMessageCanSystemSleep");
     852    else if (kIOMessageSystemWillSleep == messageType)
     853        VERBOSE(VB_RECORD, loc + "kIOMessageSystemWillSleep");
     854    else if (kIOMessageSystemWillNotSleep == messageType)
     855        VERBOSE(VB_RECORD, loc + "kIOMessageSystemWillNotSleep");
     856    else if (kIOMessageSystemHasPoweredOn == messageType)
     857        VERBOSE(VB_RECORD, loc + "kIOMessageSystemHasPoweredOn");
     858    else if (kIOMessageSystemWillRestart == messageType)
     859        VERBOSE(VB_RECORD, loc + "kIOMessageSystemWillRestart");
     860    else
     861    {
     862        VERBOSE(VB_RECORD, loc + "unknown message 0x"
     863                <<hex<<messageType<<dec);
     864    }
     865}
     866
     867// Various message callbacks.
     868
     869void *dfd_controller_thunk(void *param)
     870{
     871    ((DarwinFirewireDevice*)param)->RunController();
     872    return NULL;
     873}
     874
     875void dfd_update_device_list_item(
     876    DarwinFirewireDevice *dev, uint64_t guid, void *item)
     877{
     878    dev->UpdateDeviceListItem(guid, item);
     879}
     880
     881int dfd_no_data_notification(void *callback_data)
     882{
     883    ((DarwinFirewireDevice*)callback_data)->ProcessNoDataMessage();
     884
     885    return kIOReturnSuccess;
     886}
     887
     888void dfd_stream_msg(long unsigned int msg, long unsigned int param1,
     889                    long unsigned int param2, void *callback_data)
     890{
     891    ((DarwinFirewireDevice*)callback_data)->
     892        ProcessStreamingMessage(msg, param1, param2);
     893}
     894
     895int dfd_tspacket_handler(uint tsPacketCount, uint32_t **ppBuf,
     896                         void *callback_data)
     897{
     898    DarwinFirewireDevice *fw = (DarwinFirewireDevice*) callback_data;
     899    if (!fw)
     900        return kIOReturnBadArgument;
     901
     902    for (uint32_t i = 0; i < tsPacketCount; ++i)
     903        fw->BroadcastToListeners((const unsigned char*) ppBuf[i], 188);
     904
     905    return kIOReturnSuccess;
     906}
     907
     908static IOReturn dfd_tspacket_handler_thunk(
     909    long unsigned int tsPacketCount, UInt32 **ppBuf, void *callback_data)
     910{
     911    return dfd_tspacket_handler(
     912        tsPacketCount, (uint32_t**)ppBuf, callback_data);
     913}
     914
     915static void dfd_update_device_list(void *dfd, io_iterator_t deviter)
     916{
     917    DarwinFirewireDevice *dev = (DarwinFirewireDevice*) dfd;
     918
     919    io_object_t it = NULL;
     920    while ((it = IOIteratorNext(deviter)))
     921    {
     922        uint64_t guid = 0;
     923
     924        CFMutableDictionaryRef props;
     925        int ret = IORegistryEntryCreateCFProperties(
     926            it, &props, kCFAllocatorDefault, kNilOptions);
     927
     928        if (kIOReturnSuccess == ret)
     929        {
     930            CFNumberRef GUIDDesc = (CFNumberRef)
     931                CFDictionaryGetValue(props, CFSTR("GUID"));
     932            CFNumberGetValue(GUIDDesc, kCFNumberSInt64Type, &guid);
     933            CFRelease(props);
     934            dfd_update_device_list_item(dev, guid, &it);
     935        }
     936    }
     937}
     938
     939static void dfd_streaming_log_message(char *msg)
     940{
     941    VERBOSE(VB_RECORD, QString("MPEG2Receiver: %1").arg(msg));
     942}
  • 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
     335bool DarwinAVCInfo::GetDeviceNodes(int &local_node, int &remote_node)
     336{
     337    uint32_t generation = 0;
     338    uint16_t node       = 0;
     339    local_node  = -1;
     340    remote_node = -1;
     341
     342    if ((*fw_handle)->version < 4)
     343    {
     344        if (kIOReturnSuccess == (*fw_handle)->GetGenerationAndNodeID(
     345                fw_handle, (UInt32*) &generation, (UInt16*) &node))
     346        {
     347            remote_node = node;
     348        }
     349
     350        if (kIOReturnSuccess == (*fw_handle)->GetLocalNodeID(
     351                fw_handle, (UInt16*) &node))
     352        {
     353            local_node = node;
     354        }
     355    }
     356
     357    int ret = (*fw_handle)->GetBusGeneration(fw_handle, (UInt32*)&generation);
     358    if (kIOReturnSuccess == ret)
     359    {
     360        if (kIOReturnSuccess == (*fw_handle)->GetLocalNodeIDWithGeneration(
     361                fw_handle, generation, (UInt16*) &node))
     362        {
     363            local_node = node;
     364        }
     365
     366        if (kIOReturnSuccess == (*fw_handle)->GetRemoteNodeID(
     367                fw_handle, generation, (UInt16*) &node))
     368        {
     369            remote_node = node;
     370        }
     371    }
     372
     373    return (local_node >= 0) && (remote_node >= 0);
     374}
     375
     376static void dfd_device_change_msg(
     377    void *dfd, io_service_t, natural_t messageType, void*)
     378{
     379    DarwinFirewireDevice *dev = (DarwinFirewireDevice*) dfd;
     380    dev->HandleDeviceChange(messageType);
     381}
  • 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    virtual bool ResetBus(void);
     29
     30    void HandleDeviceChange(uint messageType);
     31
     32    virtual void AddListener(TSDataListener*);
     33    virtual void RemoveListener(TSDataListener*);
     34
     35    // Gets
     36    virtual bool IsPortOpen(void) const;
     37
     38    // Statics
     39    static vector<AVCInfo> GetSTBList(void);
     40
     41  private:
     42    void StartController(void);
     43    void StopController(void);
     44
     45    bool OpenAVStream(void);
     46    bool CloseAVStream(void);
     47    bool IsAVStreamOpen(void) const;
     48
     49    bool StartStreaming(void);
     50    bool StopStreaming(void);
     51
     52    virtual bool SendAVCCommand(
     53        const vector<uint8_t> &cmd,
     54        vector<uint8_t>       &result,
     55        int                   /*retry_cnt*/);
     56
     57    void HandleBusReset(void);
     58    bool UpdatePlugRegisterPrivate(
     59        uint plug_number, int fw_chan, int new_speed,
     60        bool add_plug, bool remove_plug);
     61    bool UpdatePlugRegister(
     62        uint plug_number, int fw_chan, int speed,
     63        bool add_plug, bool remove_plug, uint retry_cnt = 4);
     64
     65    void RunController(void);
     66    void BroadcastToListeners(const unsigned char *data, uint dataSize);
     67    void UpdateDeviceListItem(uint64_t guid, void *item);
     68    void ProcessNoDataMessage(void);
     69    void ProcessStreamingMessage(
     70        uint32_t msg, uint32_t param1, uint32_t param2);
     71
     72    DarwinAVCInfo *GetInfoPtr(void);
     73    const DarwinAVCInfo *GetInfoPtr(void) const;
     74
     75    int GetMaxSpeed(void);
     76    bool IsSTBStreaming(uint *fw_channel = NULL);
     77
     78    vector<AVCInfo> GetSTBListPrivate(void);
     79
     80  private:
     81    int      m_local_node;
     82    int      m_remote_node;
     83    DFDPriv *m_priv;
     84};
     85
     86#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 GetDeviceNodes(int &local_node, int &remote_node);
     53
     54    bool IsAVCInterfaceOpen(void) const
     55        { return avc_handle; }
     56
     57    bool IsOpen(void) const
     58        { return fw_handle; }
     59
     60  public:
     61    uint8_t      unit_table[32];
     62
     63    io_service_t fw_node_ref;     // parent of fw_device_ref
     64    io_service_t fw_device_ref;   // parent of fw_service_ref
     65    io_service_t fw_service_ref;  // parent of avc_service_ref
     66    io_service_t avc_service_ref;
     67
     68    io_object_t  fw_device_notifier_ref;
     69
     70    IOFireWireAVCLibUnitInterface **avc_handle;
     71    IOFireWireLibDeviceRef          fw_handle;
     72};
     73typedef QMap<uint64_t,DarwinAVCInfo*> avcinfo_list_t;
     74
     75#endif // USING_OSX_FIREWIRE
     76
     77#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    virtual bool ResetBus(void);
     30
     31    void HandleBusReset(uint);
     32
     33    virtual void AddListener(TSDataListener*);
     34    virtual void RemoveListener(TSDataListener*);
     35
     36    // Gets
     37    virtual bool IsPortOpen(void) const;
     38
     39    // Statics
     40    static vector<AVCInfo> GetSTBList(void);
     41
     42    // Constants
     43    static const uint kBroadcastChannel;
     44    static const uint kConnectionP2P;
     45    static const uint kConnectionBroadcast;
     46    static const uint kMaxBufferedPackets;
     47
     48  private:
     49    bool GetPortAndNode(void);
     50
     51    bool OpenNode(void);
     52    bool CloseNode(void);
     53
     54    bool OpenAVStream(void);
     55    bool CloseAVStream(void);
     56
     57    bool OpenP2PNode(void);
     58    bool CloseP2PNode(void);
     59
     60    bool OpenBroadcastNode(void);
     61    bool CloseBroadcastNode(void);
     62
     63    bool StartStreaming(void);
     64    bool StopStreaming(void);
     65    bool StopStreamingLater(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    LFDPriv                 *m_priv;
     87};
     88
     89#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    virtual bool ResetBus(void) { return false; }
     217
     218    virtual void AddListener(TSDataListener*);
     219    virtual void RemoveListener(TSDataListener*);
     220
     221    // Sets
     222    virtual bool SetPowerState(bool on);
     223    virtual bool SetChannel(const QString &panel_model,
     224                            uint alt_method, uint channel);
     225
     226    // Gets
     227    virtual bool IsPortOpen(void) const = 0;
     228    bool IsSTBBufferCleared(void) const { return m_buffer_cleared; }
     229
     230    // non-const Gets
     231    virtual PowerState GetPowerState(void);
     232
     233    // Statics
     234    static inline bool IsSTBSupported(const QString &model);
     235    static QString GetModelName(uint vendorid, uint modelid);
     236    static vector<AVCInfo> GetSTBList(void);
     237    static bool IsSubunitType(
     238        const uint8_t unit_table[32], IEEE1394UnitAddress subunit_type);
     239    static QString GetSubunitInfoString(const uint8_t table[32]);
     240
     241  protected:
     242    FirewireDevice(uint64_t guid, uint subunitid, uint speed);
     243
     244    virtual bool SendAVCCommand(const vector<uint8_t> &cmd,
     245                                vector<uint8_t> &result,
     246                                int retry_cnt) = 0;
     247    bool GetSubunitInfo(uint8_t table[32]);
     248
     249    void SetLastChannel(uint channel);
     250    void ProcessPATPacket(const TSPacket&);
     251    virtual void BroadcastToListeners(
     252        const unsigned char *data, uint dataSize);
     253
     254    uint64_t                 m_guid;
     255    uint                     m_subunitid;
     256    uint                     m_speed;
     257    uint                     m_last_channel;
     258    uint                     m_last_crc;
     259    bool                     m_buffer_cleared;
     260
     261    uint                     m_open_port_cnt;
     262    vector<TSDataListener*>  m_listeners;
     263    mutable QMutex           m_lock;
     264
     265    /// Vendor ID + Model ID to FirewireDevice STB model string
     266    static QMap<uint64_t,QString> s_id_to_model;
     267    static QMutex                 s_static_lock;
     268};
     269
     270inline bool FirewireDevice::IsSTBSupported(const QString &panel_model)
     271{
     272    QString model = panel_model.upper();
     273    return ((model == "DCT-6200") ||
     274            (model == "DCT-6212") ||
     275            (model == "DCT-6216") ||
     276            (model == "SA3250HD") ||
     277            (model == "SA4200HD") ||
     278            (model == "GENERIC"));
     279}
     280
     281#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): ").arg(m_guid)
     42#define LOC_WARN QString("LFireDev(%1), Warning: ").arg(m_guid)
     43#define LOC_ERR  QString("LFireDev(%1), Error: ").arg(m_guid)
     44
     45#define kNoDataTimeout            50   /* msec */
     46#define kResetTimeout             1500 /* msec */
     47
     48typedef QMap<raw1394handle_t,LinuxFirewireDevice*> handle_to_lfd_t;
     49
     50class LFDPriv
     51{
     52  public:
     53    LFDPriv() :
     54        handle(NULL), generation(0), reset_start(true),
     55        avstream(NULL), channel(-1),
     56        output_plug(-1), input_plug(-1), bandwidth(0), no_data_cnt(0),
     57        is_p2p_node_open(false), is_bcast_node_open(false),
     58        is_streaming(false), is_streaming_running(false)
     59    {
     60        memset(unit_table, 0xff, sizeof(unit_table));
     61    }
     62
     63    raw1394handle_t  handle;
     64    uint             generation;
     65    bool             reset_start;
     66    uint8_t          unit_table[32];
     67
     68    iec61883_mpeg2_t avstream;
     69    int              channel;
     70    int              output_plug;
     71    int              input_plug;
     72    int              bandwidth;
     73    uint             no_data_cnt;
     74
     75    bool             is_p2p_node_open;
     76    bool             is_bcast_node_open;
     77    bool             is_streaming;
     78    bool             is_streaming_running;
     79
     80    QDateTime        stop_streaming_timer;
     81    pthread_t        streaming_thread;
     82    QMutex           start_stop_streaming_lock;
     83
     84    static QMutex          s_lock;
     85    static handle_to_lfd_t s_handle_info;
     86};
     87QMutex          LFDPriv::s_lock;
     88handle_to_lfd_t LFDPriv::s_handle_info;
     89
     90const uint LinuxFirewireDevice::kBroadcastChannel    = 63;
     91const uint LinuxFirewireDevice::kConnectionP2P       = 0;
     92const uint LinuxFirewireDevice::kConnectionBroadcast = 1;
     93const uint LinuxFirewireDevice::kMaxBufferedPackets  = 2000;
     94
     95// callback function for libiec61883
     96int linux_firewire_device_tspacket_handler(
     97    unsigned char *tspacket, int len, uint dropped, void *callback_data);
     98static QString speed_to_string(uint speed);
     99static int linux_firewire_device_bus_reset_handler(
     100    raw1394handle_t handle, uint generation);
     101static uint64_t get_guid(raw1394handle_t handle, nodeid_t node);
     102
     103LinuxFirewireDevice::LinuxFirewireDevice(
     104    uint64_t guid, uint subunitid,
     105    uint speed, bool use_p2p, uint av_buffer_size_in_bytes) :
     106    FirewireDevice(guid, subunitid, speed),
     107    m_port(-1),         m_node(-1),
     108    m_bufsz(av_buffer_size_in_bytes),
     109    m_use_p2p(use_p2p), m_priv(new LFDPriv())
     110{
     111    if (!m_bufsz)
     112        m_bufsz = gContext->GetNumSetting("HDRingbufferSize");
     113}
     114
     115LinuxFirewireDevice::~LinuxFirewireDevice()
     116{
     117    if (IsPortOpen())
     118    {
     119        VERBOSE(VB_IMPORTANT, LOC_ERR + "ctor called with open port");
     120        while (IsPortOpen())
     121            ClosePort();
     122    }
     123
     124    if (m_priv)
     125    {
     126        delete m_priv;
     127        m_priv = NULL;
     128    }
     129}
     130
     131void LinuxFirewireDevice::HandleBusReset(uint generation)
     132{
     133    QString loc = LOC + QString("HandleBusReset(%1->%2)")
     134        .arg(m_priv->generation).arg(generation);
     135
     136    m_priv->generation = generation;
     137
     138    if (m_priv->reset_start)
     139    {
     140        m_priv->reset_start = false;
     141        if (m_priv->is_streaming)
     142        {
     143            VERBOSE(VB_IMPORTANT, loc + ": Stopping Streaming");
     144            iec61883_mpeg2_recv_stop(m_priv->avstream);
     145            VERBOSE(VB_IMPORTANT, loc + ": Stopped Streaming");
     146        }
     147        return;
     148    }
     149    m_priv->reset_start = true;
     150
     151    raw1394_update_generation(m_priv->handle, generation);
     152
     153    if (m_priv->is_p2p_node_open)
     154    {
     155        nodeid_t output = m_node | 0xffc0;
     156        nodeid_t input  = raw1394_get_local_id(m_priv->handle);
     157
     158        int fwchan = iec61883_cmp_reconnect(
     159            m_priv->handle,
     160            output, &m_priv->output_plug,
     161            input,  &m_priv->input_plug,
     162            &m_priv->bandwidth, m_priv->channel);
     163
     164        if (fwchan < 0)
     165        {
     166            VERBOSE(VB_IMPORTANT, LOC_ERR + "Bus Reset: Failed to reconnect");
     167        }
     168        else if (fwchan != m_priv->channel)
     169        {
     170            VERBOSE(VB_IMPORTANT, LOC_WARN + QString("FWChan changed %1->%2")
     171                    .arg(m_priv->channel).arg(fwchan));
     172        }
     173        m_priv->channel = fwchan;
     174
     175        VERBOSE(VB_IMPORTANT, loc + ": Reconnected fwchan: "<<fwchan);
     176    }
     177
     178    if (m_priv->is_bcast_node_open)
     179    {
     180        m_priv->is_bcast_node_open = false;
     181        OpenBroadcastNode();
     182    }
     183
     184    if (m_priv->is_streaming)
     185    {
     186        VERBOSE(VB_IMPORTANT, loc + ": Restarting Streaming");
     187        iec61883_mpeg2_recv_start(m_priv->avstream, m_priv->channel);
     188        VERBOSE(VB_IMPORTANT, loc + ": Restarted Streaming");
     189    }
     190}
     191
     192bool LinuxFirewireDevice::OpenPort(void)
     193{
     194    QMutexLocker mlocker(&m_lock);
     195    QMutexLocker slocker(&LFDPriv::s_lock);
     196
     197    VERBOSE(VB_RECORD, LOC + "OpenPort()");
     198
     199    if (m_priv->handle)
     200    {
     201        m_open_port_cnt++;
     202        return true;
     203    }
     204
     205    if (!GetPortAndNode())
     206        return false;
     207
     208    VERBOSE(VB_RECORD, LOC + "Getting raw1394 handle "<<(m_open_port_cnt-1));
     209    m_priv->handle = raw1394_new_handle_on_port(m_port);
     210
     211    if (!m_priv->handle)
     212    {
     213        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to get handle for " +
     214                QString("port: %1").arg(m_port) + ENO);
     215
     216        return false;
     217    }
     218
     219    LFDPriv::s_handle_info[m_priv->handle] = this;
     220
     221    m_priv->generation = raw1394_get_generation(m_priv->handle);
     222    raw1394_set_bus_reset_handler(
     223        m_priv->handle, linux_firewire_device_bus_reset_handler);
     224
     225    GetSubunitInfo(m_priv->unit_table);
     226    VERBOSE(VB_RECORD, LOC + GetSubunitInfoString(m_priv->unit_table));
     227
     228    if (!IsSubunitType(m_priv->unit_table, kAVCSubunitTypeTuner) ||
     229        !IsSubunitType(m_priv->unit_table, kAVCSubunitTypePanel))
     230    {
     231        VERBOSE(VB_IMPORTANT, LOC_ERR + QString("No STB at guid: 0x%1")
     232                .arg(m_guid,0,16));
     233
     234        ClosePort();
     235        return false;
     236    }
     237
     238    m_open_port_cnt++;
     239
     240    return true;
     241}
     242
     243bool LinuxFirewireDevice::ClosePort(void)
     244{
     245    QMutexLocker mlocker(&m_lock);
     246    QMutexLocker slocker(&LFDPriv::s_lock);
     247
     248    VERBOSE(VB_RECORD, LOC + "ClosePort()");
     249
     250    if (m_open_port_cnt < 1)
     251        return false;
     252
     253    m_open_port_cnt--;
     254
     255    if (m_open_port_cnt != 0)
     256        return true;
     257
     258    if (m_priv->handle)
     259    {
     260        if (IsNodeOpen())
     261            CloseNode();
     262
     263        VERBOSE(VB_RECORD, LOC + "Releasing raw1394 handle "<<m_open_port_cnt);
     264        raw1394_destroy_handle(m_priv->handle);
     265        LFDPriv::s_handle_info.erase(m_priv->handle);
     266        m_priv->handle = NULL;
     267    }
     268
     269    return true;
     270}
     271
     272void LinuxFirewireDevice::AddListener(TSDataListener *listener)
     273{
     274    FirewireDevice::AddListener(listener);
     275
     276    QMutexLocker locker(&m_lock);
     277    if (!m_listeners.empty())
     278    {
     279        OpenNode();
     280        OpenAVStream();
     281        StartStreaming();
     282    }
     283}
     284
     285void LinuxFirewireDevice::RemoveListener(TSDataListener *listener)
     286{
     287    FirewireDevice::RemoveListener(listener);
     288
     289    QMutexLocker locker(&m_lock);
     290    if (m_listeners.empty())
     291    {
     292        StopStreaming();
     293        CloseAVStream();
     294        CloseNode();
     295    }
     296}
     297
     298bool LinuxFirewireDevice::SendAVCCommand(
     299    const vector<uint8_t>  &_cmd,
     300    vector<uint8_t>        &result,
     301    int                     retry_cnt)
     302{
     303    retry_cnt = (retry_cnt < 0) ? 2 : retry_cnt;
     304
     305    result.clear();
     306
     307    if (!m_priv->handle || (m_node < 0))
     308        return false;
     309
     310    vector<uint8_t> cmd = _cmd;
     311    while (cmd.size() & 0x3)
     312        cmd.push_back(0x00);
     313
     314    if (cmd.size() > 4096)
     315        return false;
     316
     317    uint32_t cmdbuf[1024];
     318    for (uint i = 0; i < cmd.size(); i+=4)
     319        cmdbuf[i>>2] = cmd[i]<<24 | cmd[i+1]<<16 | cmd[i+2]<<8 | cmd[i+3];
     320
     321    uint result_length = 0;
     322
     323#ifdef USING_LIBAVC_5_3
     324    uint32_t *ret = avc1394_transaction_block2(
     325        m_priv->handle, m_node, cmdbuf, cmd.size() >> 2,
     326        &result_length, retry_cnt);
     327#else // if !USING_LIBAVC_5_3
     328    uint32_t *ret = avc1394_transaction_block(
     329        m_priv->handle, m_node, cmdbuf, cmd.size() >> 2, retry_cnt);
     330    result_length = cmd.size() >> 2;
     331#endif // !USING_LIBAVC_5_3
     332
     333    if (!ret)
     334        return false;
     335
     336    for (uint i = 0; i < result_length; i++)
     337    {
     338        result.push_back((ret[i]>>24) & 0xff);
     339        result.push_back((ret[i]>>16) & 0xff);
     340        result.push_back((ret[i]>>8)  & 0xff);
     341        result.push_back((ret[i])     & 0xff);
     342    }
     343
     344#ifdef USING_LIBAVC_5_3
     345    avc1394_transaction_block_close(m_priv->handle);
     346#endif // USING_LIBAVC_5_3
     347
     348    return true;
     349}
     350
     351bool LinuxFirewireDevice::IsPortOpen(void) const
     352{
     353    QMutexLocker locker(&m_lock);
     354
     355    return m_priv->handle;
     356}
     357
     358///////////////////////////////////////////////////////////////////////////////
     359// Private methods
     360
     361bool LinuxFirewireDevice::GetPortAndNode(void)
     362{
     363    m_port = m_node = -1;
     364
     365    vector<AVCInfo> list = GetSTBList();
     366    for (uint i = 0; i < list.size(); i++)
     367    {
     368        if (list[i].guid == m_guid)
     369        {
     370            m_port = list[i].port;
     371            m_node = list[i].node;
     372            break;
     373        }
     374    }
     375
     376    bool ok = (m_port >= 0) && (m_node >= 0);
     377
     378    if (!ok)
     379    {
     380        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to find port and node " +
     381                QString("for guid: 0x%1").arg(m_guid,0,16));
     382    }
     383    else
     384    {
     385        VERBOSE(VB_RECORD, LOC + QString("port: %1, node: %2")
     386                .arg(m_port).arg(m_node));
     387    }
     388
     389    return ok;
     390}
     391
     392bool LinuxFirewireDevice::OpenNode(void)
     393{
     394    if (m_use_p2p)
     395        return OpenP2PNode();
     396    else
     397        return OpenBroadcastNode();
     398}
     399
     400bool LinuxFirewireDevice::CloseNode(void)
     401{
     402    if (m_priv->is_p2p_node_open)
     403        return CloseP2PNode();
     404
     405    if (m_priv->is_bcast_node_open)
     406        return CloseBroadcastNode();
     407
     408    return true;
     409}
     410
     411// This may in fact open a broadcast connection, but it tries to open
     412// a P2P connection first.
     413bool LinuxFirewireDevice::OpenP2PNode(void)
     414{
     415    if (m_priv->is_bcast_node_open)
     416        return false;
     417
     418    if (m_priv->is_p2p_node_open)
     419        return true;
     420
     421    VERBOSE(VB_RECORD, LOC + "Opening P2P connection");
     422
     423    m_priv->bandwidth   = +1; // +1 == allocate bandwidth
     424    m_priv->output_plug = -1; // -1 == find first online plug
     425    m_priv->input_plug  = -1; // -1 == find first online plug
     426    nodeid_t output     = m_node | 0xffc0;
     427    nodeid_t input      = raw1394_get_local_id(m_priv->handle);
     428    m_priv->channel     = iec61883_cmp_connect(m_priv->handle,
     429                                               output, &m_priv->output_plug,
     430                                               input,  &m_priv->input_plug,
     431                                               &m_priv->bandwidth);
     432
     433    if (m_priv->channel < 0)
     434    {
     435        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to create P2P connection");
     436
     437        m_priv->bandwidth = 0;
     438
     439        return false;
     440    }
     441
     442    m_priv->is_p2p_node_open = true;
     443
     444    return true;
     445}
     446
     447bool LinuxFirewireDevice::CloseP2PNode(void)
     448{
     449    if (m_priv->is_p2p_node_open && (m_priv->channel >= 0))
     450    {
     451        VERBOSE(VB_RECORD, LOC + "Closing P2P connection");
     452
     453        if (m_priv->avstream)
     454            CloseAVStream();
     455
     456        nodeid_t output     = m_node | 0xffc0;
     457        nodeid_t input      = raw1394_get_local_id(m_priv->handle);
     458
     459        iec61883_cmp_disconnect(m_priv->handle,
     460                                output, m_priv->output_plug,
     461                                input,  m_priv->input_plug,
     462                                m_priv->channel, m_priv->bandwidth);
     463
     464        m_priv->channel     = -1;
     465        m_priv->output_plug = -1;
     466        m_priv->input_plug  = -1;
     467        m_priv->is_p2p_node_open = false;
     468    }
     469
     470    return true;
     471}
     472
     473bool LinuxFirewireDevice::OpenBroadcastNode(void)
     474{
     475    if (m_priv->is_p2p_node_open)
     476        return false;
     477
     478    if (m_priv->is_bcast_node_open)
     479        return true;
     480
     481    if (m_priv->avstream)
     482        CloseAVStream();
     483
     484    m_priv->channel     = kBroadcastChannel - m_node;
     485    m_priv->output_plug = 0;
     486    m_priv->input_plug  = 0;
     487    nodeid_t output     = m_node | 0xffc0;
     488    nodeid_t input      = raw1394_get_local_id(m_priv->handle);
     489
     490    VERBOSE(VB_RECORD, LOC + "Opening broadcast connection on " +
     491            QString("node %1, channel %2")
     492            .arg(m_node).arg(m_priv->channel));
     493
     494    int err = iec61883_cmp_create_bcast(m_priv->handle,
     495                                        output, m_priv->output_plug,
     496                                        input,  m_priv->input_plug,
     497                                        m_priv->channel, m_speed);
     498
     499    if (err != 0)
     500    {
     501        VERBOSE(VB_IMPORTANT, LOC_ERR +
     502                "Failed to create Broadcast connection");
     503
     504        m_priv->channel     = -1;
     505        m_priv->output_plug = -1;
     506        m_priv->input_plug  = -1;
     507
     508        return false;
     509    }
     510
     511    m_priv->is_bcast_node_open = true;
     512
     513    return true;
     514}
     515
     516bool LinuxFirewireDevice::CloseBroadcastNode(void)
     517{
     518    if (m_priv->is_bcast_node_open)
     519    {
     520        VERBOSE(VB_RECORD, LOC + "Closing broadcast connection");
     521
     522        m_priv->channel     = -1;
     523        m_priv->output_plug = -1;
     524        m_priv->input_plug  = -1;
     525        m_priv->is_bcast_node_open = false;
     526    }
     527    return true;
     528}
     529
     530bool LinuxFirewireDevice::OpenAVStream(void)
     531{
     532    VERBOSE(VB_RECORD, LOC + "OpenAVStream");
     533
     534    if (!IsNodeOpen() && !OpenNode())
     535        return false;
     536
     537    if (m_priv->avstream)
     538        return true;
     539
     540    VERBOSE(VB_RECORD, LOC + "Opening A/V stream object");
     541
     542    if (!m_priv->handle)
     543    {
     544        VERBOSE(VB_IMPORTANT, LOC +
     545                "Can not open AVStream without IEEE 1394 Port");
     546
     547        return false;
     548    }
     549
     550    m_priv->avstream = iec61883_mpeg2_recv_init(
     551        m_priv->handle, linux_firewire_device_tspacket_handler, this);
     552
     553    if (!m_priv->avstream)
     554    {
     555        VERBOSE(VB_IMPORTANT, LOC + "Unable to open AVStream" + ENO);
     556
     557        return false;
     558    }
     559
     560    iec61883_mpeg2_set_synch(m_priv->avstream, 1 /* sync on close */);
     561
     562    if (m_bufsz)
     563        SetAVStreamBufferSize(m_bufsz);
     564
     565    return true;
     566}
     567
     568bool LinuxFirewireDevice::CloseAVStream(void)
     569{
     570    if (!m_priv->avstream)
     571        return true;
     572
     573    VERBOSE(VB_RECORD, LOC + "Closing A/V stream object");
     574
     575    while (m_listeners.size())
     576        RemoveListener(m_listeners[m_listeners.size() - 1]);
     577
     578    if (m_priv->is_streaming)
     579        StopStreaming();
     580
     581    iec61883_mpeg2_close(m_priv->avstream);
     582    m_priv->avstream = NULL;
     583
     584    return true;
     585}
     586
     587void *linux_firewire_device_streaming_thunk(void *param)
     588{
     589    LinuxFirewireDevice *mon = (LinuxFirewireDevice*) param;
     590    mon->RunStreaming();
     591    return NULL;
     592}
     593
     594void LinuxFirewireDevice::RunStreaming(void)
     595{
     596    VERBOSE(VB_RECORD, LOC + "RunStreaming -- start");
     597    m_lock.lock();
     598    m_priv->is_streaming_running = true;
     599
     600    m_priv->no_data_cnt = 0;
     601    while (m_priv->is_streaming)
     602    {
     603        bool ok = LoopIteration(kNoDataTimeout);
     604        m_priv->no_data_cnt = (ok) ? 0 : m_priv->no_data_cnt + 1;
     605
     606        if (m_priv->is_streaming &&
     607            (m_priv->no_data_cnt > (kResetTimeout / kNoDataTimeout)))
     608        {
     609            m_priv->no_data_cnt = 0;
     610            ResetBus();
     611        }
     612    }
     613
     614    m_priv->is_streaming_running = false;
     615    m_lock.unlock();
     616    VERBOSE(VB_RECORD, LOC + "RunStreaming -- end");
     617}
     618
     619bool LinuxFirewireDevice::StartStreaming(void)
     620{
     621    VERBOSE(VB_RECORD, LOC + "Starting A/V streaming");
     622    QMutexLocker locker(&m_priv->start_stop_streaming_lock);
     623    VERBOSE(VB_RECORD, LOC + "Starting A/V streaming -- locked");
     624
     625    if (m_priv->is_streaming)
     626        return m_priv->is_streaming;
     627
     628    assert(!m_priv->is_streaming_running);
     629
     630    if (!IsAVStreamOpen() && !OpenAVStream())
     631        return false;
     632
     633    if (m_priv->channel < 0)
     634    {
     635        VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting A/V streaming, no channel");
     636        return false;
     637    }
     638
     639    VERBOSE(VB_RECORD, LOC + "Starting A/V streaming -- really");
     640
     641    if (iec61883_mpeg2_recv_start(m_priv->avstream, m_priv->channel) == 0)
     642    {
     643        m_priv->is_streaming = true;
     644
     645        pthread_create(&m_priv->streaming_thread, NULL,
     646                       linux_firewire_device_streaming_thunk, this);
     647
     648        m_lock.unlock();
     649        while (!m_priv->is_streaming_running)
     650            usleep(5000);
     651        m_lock.lock();
     652    }
     653    else
     654    {
     655        VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting A/V streaming " + ENO);
     656    }
     657
     658    return m_priv->is_streaming;
     659}
     660
     661bool LinuxFirewireDevice::StopStreaming(void)
     662{
     663    VERBOSE(VB_RECORD, LOC + "Stopping A/V streaming");
     664    QMutexLocker locker(&m_priv->start_stop_streaming_lock);
     665    VERBOSE(VB_RECORD, LOC + "Stopping A/V streaming -- locked");
     666
     667    if (m_priv->is_streaming)
     668    {
     669        VERBOSE(VB_RECORD, LOC + "Stopping A/V streaming -- really");
     670
     671        m_priv->is_streaming = false;
     672
     673        VERBOSE(VB_RECORD, LOC + "Waiting for A/V streaming to stop");
     674        while (m_priv->is_streaming_running)
     675        {
     676            m_lock.unlock();
     677            usleep(5000);
     678            m_lock.lock();
     679        }
     680
     681        VERBOSE(VB_RECORD, LOC + "Joining A/V streaming thread");
     682        pthread_join(m_priv->streaming_thread, NULL);
     683
     684        iec61883_mpeg2_recv_stop(m_priv->avstream);
     685
     686        raw1394_iso_recv_flush(m_priv->handle);
     687    }
     688
     689    VERBOSE(VB_RECORD, LOC + "Stopped A/V streaming");
     690
     691    return true;
     692}
     693
     694bool LinuxFirewireDevice::StopStreamingLater(void)
     695{
     696    // TODO
     697    return true;
     698}
     699
     700bool LinuxFirewireDevice::SetAVStreamBufferSize(uint size_in_bytes)
     701{
     702    if (!m_priv->avstream)
     703        return false;
     704
     705    // Set buffered packets size
     706    uint   buffer_size      = max(size_in_bytes, 50 * TSPacket::SIZE);
     707    size_t buffered_packets = min(buffer_size / 4, kMaxBufferedPackets);
     708
     709    iec61883_mpeg2_set_buffers(m_priv->avstream, buffered_packets);
     710
     711    VERBOSE(VB_IMPORTANT, LOC +
     712            QString("Buffered packets %1 (%2 KB)")
     713            .arg(buffered_packets).arg(buffered_packets * 4));
     714
     715    return true;
     716}
     717
     718bool LinuxFirewireDevice::SetAVStreamSpeed(uint speed)
     719{
     720    if (!m_priv->avstream)
     721        return false;
     722
     723    uint curspeed = iec61883_mpeg2_get_speed(m_priv->avstream);
     724
     725    if (curspeed == speed)
     726    {
     727        m_speed = speed;
     728        return true;
     729    }
     730
     731    VERBOSE(VB_RECORD, LOC +
     732            QString("Changing Speed %1 -> %2")
     733            .arg(speed_to_string(curspeed))
     734            .arg(speed_to_string(m_speed)));
     735
     736    iec61883_mpeg2_set_speed(m_priv->avstream, speed);
     737
     738    if (speed == (uint)iec61883_mpeg2_get_speed(m_priv->avstream))
     739    {
     740        m_speed = speed;
     741        return true;
     742    }
     743
     744    VERBOSE(VB_IMPORTANT, LOC_WARN + "Unable to set firewire speed.");
     745
     746    return false;
     747}
     748
     749bool LinuxFirewireDevice::IsNodeOpen(void) const
     750{
     751    return m_priv->is_p2p_node_open || m_priv->is_bcast_node_open;
     752}
     753
     754bool LinuxFirewireDevice::IsAVStreamOpen(void) const
     755{
     756    return m_priv->avstream;
     757}
     758
     759bool LinuxFirewireDevice::ResetBus(void)
     760{
     761    VERBOSE(VB_IMPORTANT, LOC + "ResetBus() -- begin");
     762
     763    bool ok = (raw1394_reset_bus_new(m_priv->handle, RAW1394_LONG_RESET) == 0);
     764    if (!ok)
     765        VERBOSE(VB_IMPORTANT, LOC_ERR + "Bus Reset failed" + ENO);
     766
     767    VERBOSE(VB_IMPORTANT, LOC + "ResetBus() -- end");
     768
     769    return ok;
     770}
     771
     772bool LinuxFirewireDevice::LoopIteration(uint timeout_in_msec)
     773{
     774    int fwfd = raw1394_get_fd(m_priv->handle);
     775    if (fwfd < 0)
     776        return false;
     777
     778    struct timeval tv;
     779    fd_set rfds;
     780
     781    FD_ZERO(&rfds);
     782    FD_SET(fwfd, &rfds);
     783
     784    tv.tv_sec  = timeout_in_msec / 1000;
     785    tv.tv_usec = (timeout_in_msec % 1000) * 1000;
     786
     787    m_lock.unlock();
     788    if (select(fwfd + 1, &rfds, NULL, NULL, &tv) <= 0)
     789    {
     790        m_lock.lock();
     791        VERBOSE(VB_IMPORTANT, LOC_WARN + QString("No Input in %1 msec...")
     792                .arg((m_priv->no_data_cnt + 1) * timeout_in_msec));
     793
     794        return false;
     795    }
     796    m_lock.lock();
     797
     798    int ret = raw1394_loop_iterate(m_priv->handle);
     799    if (ret)
     800    {
     801        VERBOSE(VB_IMPORTANT, LOC_ERR + "libraw1394_loop_iterate() " +
     802                QString("returned %1").arg(ret));
     803
     804        return false;
     805    }
     806
     807    return true;
     808}
     809
     810void LinuxFirewireDevice::PrintDropped(uint dropped_packets)
     811{
     812    if (dropped_packets == 1)
     813    {
     814        VERBOSE(VB_RECORD, LOC_ERR + "Dropped a TS packet");
     815    }
     816    else if (dropped_packets > 1)
     817    {
     818        VERBOSE(VB_RECORD, LOC_ERR +
     819                QString("Dropped %1 TS packets").arg(dropped_packets));
     820    }
     821}
     822
     823vector<AVCInfo> LinuxFirewireDevice::GetSTBList(void)
     824{
     825    vector<AVCInfo> list;
     826
     827    raw1394handle_t handle = raw1394_new_handle();
     828    if (!handle)
     829    {
     830        VERBOSE(VB_IMPORTANT, "Couldn't get handle" + ENO);
     831        return list;
     832    }
     833
     834    struct raw1394_portinfo port_info[16];
     835    int numcards = raw1394_get_port_info(handle, port_info, 16);
     836    if (numcards < 1)
     837    {
     838        raw1394_destroy_handle(handle);
     839        return list;
     840    }
     841
     842    for (int port = 0; port < numcards; port++)
     843    {
     844        if (raw1394_set_port(handle, port) < 0)
     845        {
     846            VERBOSE(VB_IMPORTANT, "Couldn't set port to " << port);
     847            continue;
     848        }
     849
     850        for (int node = 0; node < raw1394_get_nodecount(handle); node++)
     851        {
     852            AVCInfo info;
     853
     854            info.guid = get_guid(handle, 0xffc0 | node);
     855
     856            rom1394_directory dir;
     857            if (rom1394_get_directory(handle, node, &dir) < 0)
     858            {
     859                continue;
     860            }
     861            info.port     = port;
     862            info.node     = node;
     863            info.vendorid = dir.vendor_id;
     864            info.modelid  = dir.model_id;
     865            info.specid   = dir.unit_spec_id;
     866            info.firmware_revision = dir.unit_sw_version;
     867            info.product_name = QString("%1").arg(dir.label);
     868
     869            uint8_t unit_table[32];
     870           
     871            if (avc1394_subunit_info(handle, node, (uint32_t*)unit_table) < 0)
     872                memset(unit_table, 0xff, sizeof(unit_table));
     873
     874            if (IsSubunitType(unit_table, kAVCSubunitTypeTuner) &&
     875                IsSubunitType(unit_table, kAVCSubunitTypePanel))
     876            {
     877                list.push_back(info);
     878            }
     879        }
     880
     881        raw1394_destroy_handle(handle);
     882
     883        handle = raw1394_new_handle();
     884        if (!handle)
     885        {
     886            VERBOSE(VB_IMPORTANT, "Couldn't get handle "
     887                    "(after setting port "<<port<<")" + ENO);
     888            handle = NULL;
     889            break;
     890        }
     891
     892        numcards = raw1394_get_port_info(handle, port_info, 16);
     893    }
     894
     895    if (handle)
     896        raw1394_destroy_handle(handle);
     897
     898    return list;
     899}
     900
     901int linux_firewire_device_tspacket_handler(
     902    unsigned char *tspacket, int len, uint dropped, void *callback_data)
     903{
     904    LinuxFirewireDevice *fw = (LinuxFirewireDevice*) callback_data;
     905    if (!fw)
     906        return 0;
     907
     908    if (dropped)
     909        fw->PrintDropped(dropped);
     910
     911    if (len > 0)
     912        fw->BroadcastToListeners(tspacket, len);
     913
     914    return 1;
     915}
     916
     917static QString speed_to_string(uint speed)
     918{
     919    if (speed > 3)
     920        return QString("Invalid Speed (%1)").arg(speed);
     921
     922    static const uint speeds[] = { 100, 200, 400, 800 };
     923    return QString("%1Mbps").arg(speeds[speed]);
     924}
     925
     926static int linux_firewire_device_bus_reset_handler(
     927    raw1394handle_t handle, unsigned int generation)
     928{
     929    QMutexLocker locker(&LFDPriv::s_lock);
     930
     931    handle_to_lfd_t::iterator it = LFDPriv::s_handle_info.find(handle);
     932
     933    if (it != LFDPriv::s_handle_info.end())
     934        (*it)->HandleBusReset(generation);
     935
     936    return 0;
     937}
     938
     939// get_guid copied from plugreport, Copyright 2002-2004 Dan Dennedy GPL v2+
     940#define PLUGREPORT_GUID_HI 0x0C
     941#define PLUGREPORT_GUID_LO 0x10
     942static uint64_t get_guid(raw1394handle_t handle, nodeid_t node)
     943{
     944    uint32_t quadlet;
     945    uint64_t offset;
     946    uint64_t guid = 0;
     947
     948    offset = CSR_REGISTER_BASE + CSR_CONFIG_ROM + PLUGREPORT_GUID_HI;
     949    raw1394_read(handle, node, offset, sizeof(uint32_t), &quadlet);
     950    quadlet = htonl(quadlet);
     951    guid = quadlet;
     952    guid <<= 32;
     953    offset = CSR_REGISTER_BASE + CSR_CONFIG_ROM + PLUGREPORT_GUID_LO;
     954    raw1394_read(handle, node, offset, sizeof(uint32_t), &quadlet);
     955    quadlet = htonl(quadlet);
     956    guid += quadlet;
     957
     958    return guid;
     959}
  • 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