Ticket #10277: firewire_noinput_fix_final.patch

File firewire_noinput_fix_final.patch, 12.4 KB (added by Peter Bennett <pgbennett@…>, 15 months ago)

patch to fix this problem

  • mythtv/libs/libmythtv/firewiredevice.cpp

    a b  
    3030    m_speed(speed), 
    3131    m_last_channel(0),      m_last_crc(0), 
    3232    m_buffer_cleared(true), m_open_port_cnt(0), 
    33     m_lock() 
     33    m_lock(), m_is_no_input(false), m_error(false) 
    3434{ 
    3535} 
    3636 
     
    6666    VERBOSE(VB_RECORD, LOC + "RemoveListener() "<<m_listeners.size()); 
    6767} 
    6868 
     69TSDataListener * FirewireDevice::GetTopListener(void) const 
     70{ 
     71    if (m_listeners.empty()) 
     72        return NULL; 
     73    return m_listeners.back(); 
     74} 
     75 
     76bool  FirewireDevice::GetAndResetIsNoInput(void) 
     77{ 
     78    if (!m_is_no_input) 
     79        return false; 
     80    QMutexLocker locker(&m_lock); 
     81    bool ret = m_is_no_input; 
     82    m_is_no_input = false; 
     83    return ret; 
     84} 
     85 
     86 
    6987bool FirewireDevice::SetPowerState(bool on) 
    7088{ 
    7189    QMutexLocker locker(&m_lock); 
  • mythtv/libs/libmythtv/firewiredevice.h

    a b  
    199199 
    200200    virtual void AddListener(TSDataListener*); 
    201201    virtual void RemoveListener(TSDataListener*); 
     202    bool GetAndResetIsNoInput(void); 
    202203 
    203204    // Sets 
    204205    virtual bool SetPowerState(bool on); 
     
    208209    // Gets 
    209210    virtual bool IsPortOpen(void) const = 0; 
    210211    bool IsSTBBufferCleared(void) const { return m_buffer_cleared; } 
     212    TSDataListener * GetTopListener(void) const; 
     213    bool IsError(void) const { return m_error; } 
    211214 
    212215    // non-const Gets 
    213216    virtual PowerState GetPowerState(void); 
     
    240243    uint                     m_open_port_cnt; 
    241244    vector<TSDataListener*>  m_listeners; 
    242245    mutable QMutex           m_lock; 
     246    // Indicator for trapping "No Input in xxx msec" errors 
     247    bool                     m_is_no_input; 
     248    bool                     m_error; 
    243249 
    244250    /// Vendor ID + Model ID to FirewireDevice STB model string 
    245251    static QMap<uint64_t,QString> s_id_to_model; 
  • mythtv/libs/libmythtv/firewirerecorder.cpp

    a b  
    2828 
    2929bool FirewireRecorder::Open(void) 
    3030{ 
    31     if (!isopen) 
    32         isopen = channel->GetFirewireDevice()->OpenPort(); 
    33  
     31    isopen = channel->GetFirewireDevice()->OpenPort(); 
    3432    return isopen; 
    3533} 
    3634 
    37 void FirewireRecorder::Close(void) 
     35bool FirewireRecorder::Close(void) 
    3836{ 
    39     if (isopen) 
    40     { 
    41         channel->GetFirewireDevice()->ClosePort(); 
    42         isopen = false; 
    43     } 
     37    channel->GetFirewireDevice()->ClosePort(); 
     38    isopen = channel->GetFirewireDevice()->IsPortOpen(); 
     39    return isopen; 
    4440} 
    4541 
    4642void FirewireRecorder::StartStreaming(void) 
     
    5551 
    5652void FirewireRecorder::StartRecording(void) 
    5753{ 
    58     VERBOSE(VB_RECORD, LOC + "StartRecording"); 
    59  
    60     if (!Open()) 
    61     { 
    62         _error = true; 
    63         return; 
    64     } 
    65  
    66     _request_recording = true; 
    67     _recording = true; 
    68  
    69     StartStreaming(); 
    70  
    71     while (_request_recording) 
    72     { 
    73         if (!PauseAndWait()) 
    74             usleep(50 * 1000); 
     54    bool is_no_input = false; 
     55    bool must_save_listeners = false; 
     56    vector<TSDataListener*>  saved_listeners; 
     57    int number_opens = 1; 
     58    time_t time_last_reset = 0; 
     59 
     60    VERBOSE(VB_RECORD, LOC + "StartRecording " + curRecording->GetTitle()); 
     61 
     62    // This loop contains logic to handle a firewire no input error 
     63    // When the firewire device reports no input received for 400 msec 
     64    // this is indication of a problem that does not go away. To fix the error 
     65    // we close the firewire port and open it again in this loop. 
     66    do { 
     67        while(number_opens > 0) 
     68        { 
     69            if (!Open()) 
     70            { 
     71                _error = true; 
     72                return; 
     73            } 
     74            number_opens--; 
     75        } 
     76 
     77        _request_recording = true; 
     78        _recording = true; 
     79 
     80        if (saved_listeners.empty()) 
     81            StartStreaming(); 
     82        else 
     83        { 
     84            // Restore Listeners 
     85            int count = 0; 
     86            TSDataListener* listener; 
     87            listener = saved_listeners.back(); 
     88            while (listener!=NULL) 
     89            { 
     90                VERBOSE(VB_RECORD, LOC + QString("Restoring listener %1").arg(++count)); 
     91                channel->GetFirewireDevice()->AddListener(listener); 
     92                saved_listeners.pop_back(); 
     93                if (saved_listeners.empty()) 
     94                    listener = NULL; 
     95                else 
     96                    listener = saved_listeners.back(); 
     97            } 
     98        } 
     99        // If adding listeners caused a failure, cancel recording 
     100        if (channel->GetFirewireDevice()->IsError()) { 
     101            _error = true; 
     102            StopRecording(); 
     103        } 
     104 
     105        while (_request_recording) 
     106        { 
     107            if (is_no_input) 
     108            { 
     109                time_t now = time(NULL); 
     110                time_t elapsed = now - time_last_reset; 
     111                // if less than 30 seconds since last reset, ignore the error 
     112                // and let bus reset maybe fix it 
     113                if (elapsed <= 30) { 
     114                    VERBOSE(VB_RECORD, LOC + QString("Repeated Firewire No Input Error - Try Bus Reset.")); 
     115                    is_no_input = false; 
     116                } 
     117                // if between 30 seconds and 5 minutes since last reset - we 
     118                // have a persistent error - fail the recording 
     119                if (elapsed > 30 && elapsed <= 300) { 
     120                    VERBOSE(VB_IMPORTANT, LOC + QString("Repeated Firewire No Input Error - Recording Fails.")); 
     121                    is_no_input = false; 
     122                    _error = true; 
     123                    StopRecording(); 
     124                } 
     125                // if more than 5 minutes since last reset, or this is the first, 
     126                // proceed with reset 
     127                if (elapsed > 300) { 
     128                    VERBOSE(VB_IMPORTANT, LOC + QString("Firewire No Input Error - Resetting device.")); 
     129                    StopRecording(); 
     130                    is_no_input = false; 
     131                    must_save_listeners = true; 
     132                    time_last_reset = now; 
     133                } 
     134            } 
     135 
     136            if (!PauseAndWait()) 
     137                usleep(50 * 1000); 
     138 
     139            // Look at firewire device to see if it is having an error. The call GetAndResetIsNoInput 
     140            // resets the indicator in thread safe way so that only one thread will handle repairing 
     141            // the broken firewire connection. 
     142            if (!must_save_listeners && channel->GetFirewireDevice()->GetAndResetIsNoInput()) 
     143                is_no_input = true; 
     144        } 
     145 
     146        if (must_save_listeners) 
     147        { 
     148            // Remove And Save Listeners - may not be thread safe if others are concurrently 
     149            // adding or removing listeners 
     150            int count = 0; 
     151            TSDataListener* listener; 
     152            listener = channel->GetFirewireDevice()->GetTopListener(); 
     153            while (listener != NULL) 
     154            { 
     155                VERBOSE(VB_RECORD, LOC + QString("Saving listener %1").arg(++count)); 
     156                saved_listeners.push_back(listener); 
     157                channel->GetFirewireDevice()->RemoveListener(listener); 
     158                listener = channel->GetFirewireDevice()->GetTopListener(); 
     159            } 
     160            must_save_listeners = false; 
     161            number_opens = 0; 
     162            while(Close()) 
     163                number_opens++; 
     164            VERBOSE(VB_RECORD, LOC + QString("Number of closes: %1").arg(++number_opens)); 
     165        } 
    75166    } 
     167    while(!saved_listeners.empty()); 
    76168 
    77169    StopStreaming(); 
     170    Close(); 
    78171    FinishRecording(); 
    79172 
    80173    _recording = false; 
  • mythtv/libs/libmythtv/firewirerecorder.h

    a b  
    3434 
    3535    // Commands 
    3636    bool Open(void); 
    37     void Close(void); 
     37    bool Close(void); 
    3838 
    3939    void StartStreaming(void); 
    4040    void StopStreaming(void); 
  • mythtv/libs/libmythtv/linuxfirewiredevice.cpp

    a b  
    269269        VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Not an STB")); 
    270270 
    271271        m_lock.unlock(); 
     272        m_priv->start_stop_port_handler_lock.unlock(); 
    272273        ClosePort(); 
    273274        m_lock.lock(); 
    274275 
     
    362363 
    363364    if (!m_listeners.empty()) 
    364365    { 
    365         OpenNode(); 
    366         OpenAVStream(); 
    367         StartStreaming(); 
     366        m_error = !OpenNode(); 
     367        if (!m_error) 
     368            m_error = !OpenAVStream(); 
     369        if (!m_error) 
     370            m_error = !StartStreaming(); 
    368371    } 
    369372} 
    370373 
     
    608611{ 
    609612    VERBOSE(VB_RECORD, LOC + "RunPortHandler -- start"); 
    610613    m_lock.lock(); 
     614    m_is_no_input = false; 
    611615    VERBOSE(VB_RECORD, LOC + "RunPortHandler -- got first lock"); 
    612616    m_priv->is_port_handler_running = true; 
    613617 
     
    659663 
    660664            VERBOSE(VB_IMPORTANT, LOC_WARN + QString("No Input in %1 msec...") 
    661665                    .arg(m_priv->no_data_cnt * kNoDataTimeout)); 
     666            // Set indicator for endless no data errors 
     667            // so that FirewireRecorder can reset the device 
     668            if (m_priv->no_data_cnt == 8) 
     669            { 
     670                m_is_no_input = true; 
     671            } 
    662672        } 
    663673 
    664674        // Confirm that we won't block, now that we have the lock... 
     
    676686            } 
    677687        } 
    678688    } 
    679  
    680689    m_priv->is_port_handler_running = false; 
    681690    m_lock.unlock(); 
    682691    VERBOSE(VB_RECORD, LOC + "RunPortHandler -- end"); 
  • mythtv/libs/libmythtv/firewiresignalmonitor.cpp

    a b  
    150150 
    151151    FirewireDevice *dev = lchan->GetFirewireDevice(); 
    152152 
    153     dev->OpenPort(); 
    154     dev->AddListener(this); 
     153    // This loop contains logic to handle a firewire no input error 
     154    // When the firewire device reports no input received for 400 msec 
     155    // this is indication of a problem that does not go away. To fix the error 
     156    // we close the firewire port and open it again in this loop. 
     157    bool is_no_input = false; 
     158    bool must_save_listeners = false; 
     159    vector<TSDataListener*>  saved_listeners; 
     160    int number_opens = 1; 
     161    do { 
     162        while(number_opens > 0) 
     163        { 
     164            dev->OpenPort(); 
     165            number_opens--; 
     166        } 
     167        if (saved_listeners.empty()) 
     168            dev->AddListener(this); 
     169        else 
     170        { 
     171            // Restore Listeners 
     172            int count = 0; 
     173            TSDataListener* listener; 
     174            listener = saved_listeners.back(); 
     175            while (listener!=NULL) 
     176            { 
     177                VERBOSE(VB_CHANNEL, LOC + QString("Restoring listener %1").arg(++count)); 
     178                dev->AddListener(listener); 
     179                saved_listeners.pop_back(); 
     180                if (saved_listeners.empty()) 
     181                    listener = NULL; 
     182                else 
     183                    listener = saved_listeners.back(); 
     184            } 
     185        } 
    155186 
    156     while (dtvMonitorRunning && GetStreamData()) 
    157         usleep(100000); 
     187        while (dtvMonitorRunning && GetStreamData() && !must_save_listeners) 
     188        { 
     189            if (is_no_input) 
     190            { 
     191                // proceed with reset 
     192                VERBOSE(VB_IMPORTANT, LOC + QString("Firewire No Input Error - Resetting device.")); 
     193                is_no_input = false; 
     194                must_save_listeners = true; 
     195            } 
     196            usleep(100000); 
     197 
     198            // Look at firewire device to see if it is having an error. The call GetAndResetIsNoInput 
     199            // resets the indicator in thread safe way so that only one thread will handle repairing 
     200            // the broken firewire connection. 
     201            if (!must_save_listeners && dev->GetAndResetIsNoInput()) 
     202                is_no_input = true; 
     203        } 
     204        if (must_save_listeners) 
     205        { 
     206            // Remove And Save Listeners - may not be thread safe if others are concurrently 
     207            // adding or removing listeners 
     208            int count = 0; 
     209            TSDataListener* listener; 
     210            listener = dev->GetTopListener(); 
     211            while (listener != NULL) 
     212            { 
     213                VERBOSE(VB_CHANNEL, LOC + QString("Saving listener %1").arg(++count)); 
     214                saved_listeners.push_back(listener); 
     215                dev->RemoveListener(listener); 
     216                listener = dev->GetTopListener(); 
     217            } 
     218            must_save_listeners = false; 
     219            number_opens = 0; 
     220            while(dev->ClosePort()) 
     221                number_opens++; 
     222            VERBOSE(VB_CHANNEL, LOC + QString("Number of closes: %1").arg(++number_opens)); 
     223        } 
     224    } 
     225    while(!saved_listeners.empty()); 
    158226 
    159227    VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- shutdown "); 
    160228