Ticket #10277: firewire_noinput_fix_final.patch
File firewire_noinput_fix_final.patch, 12.4 KB (added by , 12 years ago) |
---|
-
mythtv/libs/libmythtv/firewiredevice.cpp
a b 30 30 m_speed(speed), 31 31 m_last_channel(0), m_last_crc(0), 32 32 m_buffer_cleared(true), m_open_port_cnt(0), 33 m_lock() 33 m_lock(), m_is_no_input(false), m_error(false) 34 34 { 35 35 } 36 36 … … 66 66 VERBOSE(VB_RECORD, LOC + "RemoveListener() "<<m_listeners.size()); 67 67 } 68 68 69 TSDataListener * FirewireDevice::GetTopListener(void) const 70 { 71 if (m_listeners.empty()) 72 return NULL; 73 return m_listeners.back(); 74 } 75 76 bool 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 69 87 bool FirewireDevice::SetPowerState(bool on) 70 88 { 71 89 QMutexLocker locker(&m_lock); -
mythtv/libs/libmythtv/firewiredevice.h
a b 199 199 200 200 virtual void AddListener(TSDataListener*); 201 201 virtual void RemoveListener(TSDataListener*); 202 bool GetAndResetIsNoInput(void); 202 203 203 204 // Sets 204 205 virtual bool SetPowerState(bool on); … … 208 209 // Gets 209 210 virtual bool IsPortOpen(void) const = 0; 210 211 bool IsSTBBufferCleared(void) const { return m_buffer_cleared; } 212 TSDataListener * GetTopListener(void) const; 213 bool IsError(void) const { return m_error; } 211 214 212 215 // non-const Gets 213 216 virtual PowerState GetPowerState(void); … … 240 243 uint m_open_port_cnt; 241 244 vector<TSDataListener*> m_listeners; 242 245 mutable QMutex m_lock; 246 // Indicator for trapping "No Input in xxx msec" errors 247 bool m_is_no_input; 248 bool m_error; 243 249 244 250 /// Vendor ID + Model ID to FirewireDevice STB model string 245 251 static QMap<uint64_t,QString> s_id_to_model; -
mythtv/libs/libmythtv/firewirerecorder.cpp
a b 28 28 29 29 bool FirewireRecorder::Open(void) 30 30 { 31 if (!isopen) 32 isopen = channel->GetFirewireDevice()->OpenPort(); 33 31 isopen = channel->GetFirewireDevice()->OpenPort(); 34 32 return isopen; 35 33 } 36 34 37 voidFirewireRecorder::Close(void)35 bool FirewireRecorder::Close(void) 38 36 { 39 if (isopen) 40 { 41 channel->GetFirewireDevice()->ClosePort(); 42 isopen = false; 43 } 37 channel->GetFirewireDevice()->ClosePort(); 38 isopen = channel->GetFirewireDevice()->IsPortOpen(); 39 return isopen; 44 40 } 45 41 46 42 void FirewireRecorder::StartStreaming(void) … … 55 51 56 52 void FirewireRecorder::StartRecording(void) 57 53 { 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 } 75 166 } 167 while(!saved_listeners.empty()); 76 168 77 169 StopStreaming(); 170 Close(); 78 171 FinishRecording(); 79 172 80 173 _recording = false; -
mythtv/libs/libmythtv/firewirerecorder.h
a b 34 34 35 35 // Commands 36 36 bool Open(void); 37 voidClose(void);37 bool Close(void); 38 38 39 39 void StartStreaming(void); 40 40 void StopStreaming(void); -
mythtv/libs/libmythtv/linuxfirewiredevice.cpp
a b 269 269 VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Not an STB")); 270 270 271 271 m_lock.unlock(); 272 m_priv->start_stop_port_handler_lock.unlock(); 272 273 ClosePort(); 273 274 m_lock.lock(); 274 275 … … 362 363 363 364 if (!m_listeners.empty()) 364 365 { 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(); 368 371 } 369 372 } 370 373 … … 608 611 { 609 612 VERBOSE(VB_RECORD, LOC + "RunPortHandler -- start"); 610 613 m_lock.lock(); 614 m_is_no_input = false; 611 615 VERBOSE(VB_RECORD, LOC + "RunPortHandler -- got first lock"); 612 616 m_priv->is_port_handler_running = true; 613 617 … … 659 663 660 664 VERBOSE(VB_IMPORTANT, LOC_WARN + QString("No Input in %1 msec...") 661 665 .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 } 662 672 } 663 673 664 674 // Confirm that we won't block, now that we have the lock... … … 676 686 } 677 687 } 678 688 } 679 680 689 m_priv->is_port_handler_running = false; 681 690 m_lock.unlock(); 682 691 VERBOSE(VB_RECORD, LOC + "RunPortHandler -- end"); -
mythtv/libs/libmythtv/firewiresignalmonitor.cpp
a b 150 150 151 151 FirewireDevice *dev = lchan->GetFirewireDevice(); 152 152 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 } 155 186 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()); 158 226 159 227 VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- shutdown "); 160 228