Ticket #10277: firewire_noinput_fix_V0_25_final.patch
| File firewire_noinput_fix_V0_25_final.patch, 15.1 KB (added by , 14 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 … … 68 68 QString("RemoveListener() %1").arg(m_listeners.size())); 69 69 } 70 70 71 TSDataListener * FirewireDevice::GetTopListener(void) const 72 { 73 if (m_listeners.empty()) 74 return NULL; 75 return m_listeners.back(); 76 } 77 78 bool FirewireDevice::GetAndResetIsNoInput(void) 79 { 80 if (!m_is_no_input) 81 return false; 82 QMutexLocker locker(&m_lock); 83 bool ret = m_is_no_input; 84 m_is_no_input = false; 85 return ret; 86 } 87 88 71 89 bool FirewireDevice::SetPowerState(bool on) 72 90 { 73 91 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 27 27 28 28 bool FirewireRecorder::Open(void) 29 29 { 30 if (!isopen) 31 { 32 isopen = channel->GetFirewireDevice()->OpenPort(); 33 ResetForNewFile(); 34 } 30 // Note that the firewire device can be opened multiple 31 // times without being closed in between. The close 32 // keeps track of this and actually only closes when 33 // the number of opens gets down to 0 34 35 isopen = channel->GetFirewireDevice()->OpenPort(); 36 37 // ResetForNewFile was called from here. Moved to run() 38 // because Open() can be called more than once per file 39 // and we should call ResetForNewFile only once per file. 40 // -- Peter Bennett 2012-04-06 41 35 42 return isopen; 36 43 } 37 44 38 voidFirewireRecorder::Close(void)45 bool FirewireRecorder::Close(void) 39 46 { 40 if (isopen)41 {42 channel->GetFirewireDevice()->ClosePort();43 isopen = false;44 }47 // Close decrements the open count and may leave 48 // the device open if the open count is not zero. 49 channel->GetFirewireDevice()->ClosePort(); 50 isopen = channel->GetFirewireDevice()->IsPortOpen(); 51 return isopen; 45 52 } 46 53 47 54 void FirewireRecorder::StartStreaming(void) … … 56 63 57 64 void FirewireRecorder::run(void) 58 65 { 59 LOG(VB_RECORD, LOG_INFO, LOC + "run"); 60 61 if (!Open()) 62 { 63 _error = "Failed to open firewire device"; 64 LOG(VB_GENERAL, LOG_ERR, LOC + _error); 65 return; 66 } 67 68 { 69 QMutexLocker locker(&pauseLock); 70 request_recording = true; 71 recording = true; 72 recordingWait.wakeAll(); 73 } 66 bool is_no_input = false; 67 bool must_save_listeners = false; 68 vector<TSDataListener*> saved_listeners; 69 int number_opens = 1; 70 time_t time_last_reset = 0; 71 bool done_wakeAll = false; 72 bool done_ResetForNewFile = false; 73 74 LOG(VB_RECORD, LOG_INFO, LOC + "run " + curRecording->GetTitle()); 75 76 // This loop contains logic to handle a firewire no input 77 // error. When the firewire device reports no input 78 // received for 400 msec, this is indication of a problem 79 // that does not go away. To fix the error we close the 80 // firewire port and open it again in this loop. 81 // -- Peter Bennett 2012-04-05 82 83 do { 84 while(number_opens > 0) 85 { 86 if (!Open()) 87 { 88 _error = "Failed to open firewire device"; 89 LOG(VB_GENERAL, LOG_ERR, LOC + _error); 90 return; 91 } 92 number_opens--; 93 } 94 // Moved here from Open() because Open() can be called more 95 // than once per file and we should call ResetForNewFile only 96 // once per file 97 // -- Peter Bennett 2012-04-06 98 if (!done_ResetForNewFile) 99 { 100 ResetForNewFile(); 101 done_ResetForNewFile = true; 102 } 103 if (!done_wakeAll) 104 { 105 QMutexLocker locker(&pauseLock); 106 request_recording = true; 107 recording = true; 108 recordingWait.wakeAll(); 109 done_wakeAll = true; 110 } 111 else 112 { 113 request_recording = true; 114 recording = true; 115 } 74 116 75 StartStreaming(); 117 if (saved_listeners.empty()) 118 StartStreaming(); 119 else 120 { 121 // Restore Listeners 122 int count = 0; 123 TSDataListener* listener; 124 listener = saved_listeners.back(); 125 while (listener!=NULL) 126 { 127 LOG(VB_RECORD, LOG_INFO, LOC + QString("Restoring listener %1").arg(++count)); 128 channel->GetFirewireDevice()->AddListener(listener); 129 saved_listeners.pop_back(); 130 if (saved_listeners.empty()) 131 listener = NULL; 132 else 133 listener = saved_listeners.back(); 134 } 135 } 136 // If adding listeners caused a failure, cancel recording 137 if (channel->GetFirewireDevice()->IsError()) { 138 _error = "Failed to add listeners to firewire device"; 139 LOG(VB_GENERAL, LOG_ERR, LOC + _error); 140 } 141 while (IsRecordingRequested() && !IsErrored()) 142 { 143 if (is_no_input) 144 { 145 time_t now = time(NULL); 146 time_t elapsed = now - time_last_reset; 147 // if less than 30 seconds since last reset, 148 // ignore the error and let bus reset maybe fix it 149 if (elapsed <= 30) { 150 LOG(VB_RECORD, LOG_ERR, LOC + QString("Repeated Firewire No Input Error - Try Bus Reset.")); 151 is_no_input = false; 152 } 153 // if between 30 seconds and 5 minutes since 154 // last reset - we have a persistent error - 155 // fail the recording 156 if (elapsed > 30 && elapsed <= 300) { 157 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Repeated Firewire No Input Error - Recording Fails.")); 158 is_no_input = false; 159 _error = "Repeated Firewire No Input Error - Recording Fails."; 160 request_recording = false; 161 } 162 // if more than 5 minutes since last reset, 163 // or this is the first reset, proceed with reset 164 if (elapsed > 300) { 165 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Firewire No Input Error - Resetting device.")); 166 request_recording = false; 167 is_no_input = false; 168 must_save_listeners = true; 169 time_last_reset = now; 170 } 171 } 172 if (PauseAndWait()) 173 continue; 76 174 77 while (IsRecordingRequested() && !IsErrored()) 78 { 79 if (PauseAndWait()) 80 continue; 175 if (!IsRecordingRequested()) 176 break; 81 177 82 if (!IsRecordingRequested()) 83 break; 178 { // sleep 0.25 seconds unless StopRecording() or Unpause() is called, 179 // just to avoid running this too often. 180 // Changed from 1 second to 250ms to reduce delay in recovering 181 // from "No Input in 400 msec" errors - Peter Bennett 5/3/2012 182 QMutexLocker locker(&pauseLock); 183 if (!request_recording || request_pause) 184 continue; 185 unpauseWait.wait(&pauseLock, 250); 186 } 187 188 // Look at firewire device to see if it is having 189 // an error. The call GetAndResetIsNoInput 190 // resets the indicator in thread safe way so that 191 // only one thread will handle repairing 192 // the broken firewire connection. 193 if (!must_save_listeners && channel->GetFirewireDevice()->GetAndResetIsNoInput()) 194 is_no_input = true; 195 } 84 196 85 { // sleep 1 seconds unless StopRecording() or Unpause() is called, 86 // just to avoid running this too often. 87 QMutexLocker locker(&pauseLock); 88 if (!request_recording || request_pause) 89 continue; 90 unpauseWait.wait(&pauseLock, 1000); 197 if (must_save_listeners) 198 { 199 // Remove And Save Listeners. This may not be thread 200 // safe if others are concurrently adding or removing 201 // listeners. That should not happen. 202 int count = 0; 203 TSDataListener* listener; 204 listener = channel->GetFirewireDevice()->GetTopListener(); 205 while (listener != NULL) 206 { 207 LOG(VB_RECORD, LOG_INFO, LOC + QString("Saving listener %1").arg(++count)); 208 saved_listeners.push_back(listener); 209 channel->GetFirewireDevice()->RemoveListener(listener); 210 listener = channel->GetFirewireDevice()->GetTopListener(); 211 } 212 must_save_listeners = false; 213 number_opens = 0; 214 while(Close()) 215 number_opens++; 216 LOG(VB_RECORD, LOG_INFO, LOC + QString("Number of closes: %1").arg(++number_opens)); 91 217 } 92 218 } 219 while(!saved_listeners.empty()); 93 220 94 221 StopStreaming(); 222 Close(); 95 223 FinishRecording(); 96 224 97 225 QMutexLocker locker(&pauseLock); -
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/firewiresignalmonitor.cpp
a b 152 152 153 153 FirewireDevice *dev = lchan->GetFirewireDevice(); 154 154 155 dev->OpenPort(); 156 dev->AddListener(this); 155 // This loop contains logic to handle a firewire no input 156 // error. When the firewire device reports no input 157 // received for 400 msec, this is indication of a problem 158 // that does not go away. To fix the error we close the 159 // firewire port and open it again in this loop. 160 // -- Peter Bennett 2012-04-05 161 162 bool is_no_input = false; 163 bool must_save_listeners = false; 164 vector<TSDataListener*> saved_listeners; 165 int number_opens = 1; 166 167 do { 168 while(number_opens > 0) 169 { 170 dev->OpenPort(); 171 number_opens--; 172 } 173 if (saved_listeners.empty()) 174 dev->AddListener(this); 175 else 176 { 177 // Restore Listeners 178 int count = 0; 179 TSDataListener* listener; 180 listener = saved_listeners.back(); 181 while (listener!=NULL) 182 { 183 LOG(VB_CHANNEL, LOG_INFO, LOC + QString("Restoring listener %1").arg(++count)); 184 dev->AddListener(listener); 185 saved_listeners.pop_back(); 186 if (saved_listeners.empty()) 187 listener = NULL; 188 else 189 listener = saved_listeners.back(); 190 } 191 } 192 while (dtvMonitorRunning && GetStreamData() && !must_save_listeners) 193 { 194 if (is_no_input) 195 { 196 // proceed with reset 197 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Firewire No Input Error - Resetting device.")); 198 is_no_input = false; 199 must_save_listeners = true; 200 } 201 usleep(10000); 202 203 // Look at firewire device to see if it is having 204 // an error. The call GetAndResetIsNoInput 205 // resets the indicator in thread safe way so that 206 // only one thread will handle repairing 207 // the broken firewire connection. 208 if (!must_save_listeners && dev->GetAndResetIsNoInput()) 209 is_no_input = true; 210 } 211 if (must_save_listeners) 212 { 213 // Remove And Save Listeners. This may not be thread 214 // safe if others are concurrently adding or removing 215 // listeners. That should not happen. 216 int count = 0; 217 TSDataListener* listener; 218 listener = dev->GetTopListener(); 219 while (listener != NULL) 220 { 221 LOG(VB_CHANNEL, LOG_INFO, LOC + QString("Saving listener %1").arg(++count)); 222 saved_listeners.push_back(listener); 223 dev->RemoveListener(listener); 224 listener = dev->GetTopListener(); 225 } 226 must_save_listeners = false; 227 number_opens = 0; 228 while(dev->ClosePort()) 229 number_opens++; 230 LOG(VB_CHANNEL, LOG_INFO, LOC + QString("Number of closes: %1").arg(++number_opens)); 231 } 232 } 233 while(!saved_listeners.empty()); 157 234 158 while (dtvMonitorRunning && GetStreamData())159 usleep(10000);160 235 161 236 LOG(VB_CHANNEL, LOG_INFO, LOC + "RunTableMonitor(): -- shutdown "); 162 237 -
mythtv/libs/libmythtv/linuxfirewiredevice.cpp
a b 274 274 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Not an STB")); 275 275 276 276 mlocker.unlock(); 277 locker.unlock(); 277 278 ClosePort(); 278 279 279 280 return false; … … 352 353 353 354 if (!m_listeners.empty()) 354 355 { 355 OpenNode(); 356 OpenAVStream(); 357 StartStreaming(); 356 m_error = !OpenNode(); 357 if (!m_error) 358 m_error = !OpenAVStream(); 359 if (!m_error) 360 m_error = !StartStreaming(); 358 361 } 359 362 } 360 363 … … 590 593 { 591 594 LOG(VB_RECORD, LOG_INFO, LOC + "RunPortHandler -- start"); 592 595 m_lock.lock(); 596 m_is_no_input = false; 593 597 LOG(VB_RECORD, LOG_INFO, LOC + "RunPortHandler -- got first lock"); 594 598 m_priv->is_port_handler_running = true; 595 599 m_priv->port_handler_wait.wakeAll(); … … 644 648 645 649 LOG(VB_GENERAL, LOG_WARNING, LOC + QString("No Input in %1 msec...") 646 650 .arg(m_priv->no_data_cnt * kNoDataTimeout)); 651 // Set indicator for endless no data errors 652 // so that FirewireRecorder can reset the device 653 if (m_priv->no_data_cnt == 8) 654 { 655 m_is_no_input = true; 656 } 647 657 } 648 658 649 659 // Confirm that we won't block, now that we have the lock...
