@@ -125,6 +125,7 @@ func NewMediaPortWith(log logger.Logger, mon *stats.CallMonitor, conn UDPConn, o
125125 mon : mon ,
126126 externalIP : opts .IP ,
127127 mediaTimeout : mediaTimeout ,
128+ timeoutReset : make (chan struct {}, 1 ),
128129 jitterEnabled : opts .EnableJitterBuffer ,
129130 port : newUDPConn (conn ),
130131 audioOut : media .NewSwitchWriter (sampleRate ),
@@ -148,6 +149,7 @@ type MediaPort struct {
148149 packetCount atomic.Uint64
149150 mediaTimeout <- chan struct {}
150151 timeoutStart atomic.Pointer [time.Time ]
152+ timeoutReset chan struct {}
151153 closed core.Fuse
152154 dtmfAudioEnabled bool
153155 jitterEnabled bool
@@ -179,32 +181,66 @@ func (p *MediaPort) EnableTimeout(enabled bool) {
179181 p .timeoutStart .Store (nil )
180182 return
181183 }
184+ select {
185+ case p .timeoutReset <- struct {}{}:
186+ default :
187+ }
182188 now := time .Now ()
183189 p .timeoutStart .Store (& now )
190+ p .log .Infow ("media timeout enabled" ,
191+ "packets" , p .packetCount .Load (),
192+ )
184193}
185194
186195func (p * MediaPort ) timeoutLoop (timeoutCallback func ()) {
187- ticker := time .NewTicker (p .opts .MediaTimeout )
196+ tickInterval := p .opts .MediaTimeout
197+ ticker := time .NewTicker (tickInterval )
188198 defer ticker .Stop ()
189199
190- var lastPackets uint64
200+ var (
201+ lastPackets uint64
202+ startPackets uint64
203+ lastTime time.Time
204+ )
191205 for {
192206 select {
193207 case <- p .closed .Watch ():
194208 return
209+ case <- p .timeoutReset :
210+ ticker .Reset (tickInterval )
211+ startPackets = p .packetCount .Load ()
212+ lastTime = time .Now ()
195213 case <- ticker .C :
196214 curPackets := p .packetCount .Load ()
197215 if curPackets != lastPackets {
198216 lastPackets = curPackets
199- continue
217+ lastTime = time .Now ()
218+ continue // wait for the next tick
200219 }
201- start := p .timeoutStart .Load ()
202- if start == nil {
203- continue // temporary disabled
220+ startPtr := p .timeoutStart .Load ()
221+ if startPtr == nil {
222+ continue // timeout disabled
204223 }
205- if lastPackets == 0 && time .Since (* start ) < p .opts .MediaTimeoutInitial {
224+
225+ // First timeout is allowed to be longer. Skip ticks if it's too early.
226+ sinceStart := time .Since (* startPtr )
227+ if lastPackets == startPackets && sinceStart < p .opts .MediaTimeoutInitial {
206228 continue
207229 }
230+
231+ // Ticker is allowed to fire earlier than the full timeout interval. Skip if it's not a full timeout yet.
232+ sinceLast := time .Since (lastTime )
233+ if sinceLast < p .opts .MediaTimeout {
234+ continue
235+ }
236+ p .log .Infow ("triggering media timeout" ,
237+ "packets" , lastPackets ,
238+ "startPackets" , startPackets ,
239+ "sinceStart" , sinceStart ,
240+ "sinceLast" , sinceLast ,
241+ "initial" , p .opts .MediaTimeoutInitial ,
242+ "timeout" , p .opts .MediaTimeout ,
243+ )
208244 timeoutCallback ()
209245 return
210246 }
0 commit comments