@@ -125,6 +125,7 @@ func NewMediaPortWith(log logger.Logger, mon *stats.CallMonitor, conn UDPConn, o
125
125
mon : mon ,
126
126
externalIP : opts .IP ,
127
127
mediaTimeout : mediaTimeout ,
128
+ timeoutReset : make (chan struct {}, 1 ),
128
129
jitterEnabled : opts .EnableJitterBuffer ,
129
130
port : newUDPConn (conn ),
130
131
audioOut : media .NewSwitchWriter (sampleRate ),
@@ -148,6 +149,7 @@ type MediaPort struct {
148
149
packetCount atomic.Uint64
149
150
mediaTimeout <- chan struct {}
150
151
timeoutStart atomic.Pointer [time.Time ]
152
+ timeoutReset chan struct {}
151
153
closed core.Fuse
152
154
dtmfAudioEnabled bool
153
155
jitterEnabled bool
@@ -179,32 +181,66 @@ func (p *MediaPort) EnableTimeout(enabled bool) {
179
181
p .timeoutStart .Store (nil )
180
182
return
181
183
}
184
+ select {
185
+ case p .timeoutReset <- struct {}{}:
186
+ default :
187
+ }
182
188
now := time .Now ()
183
189
p .timeoutStart .Store (& now )
190
+ p .log .Infow ("media timeout enabled" ,
191
+ "packets" , p .packetCount .Load (),
192
+ )
184
193
}
185
194
186
195
func (p * MediaPort ) timeoutLoop (timeoutCallback func ()) {
187
- ticker := time .NewTicker (p .opts .MediaTimeout )
196
+ tickInterval := p .opts .MediaTimeout
197
+ ticker := time .NewTicker (tickInterval )
188
198
defer ticker .Stop ()
189
199
190
- var lastPackets uint64
200
+ var (
201
+ lastPackets uint64
202
+ startPackets uint64
203
+ lastTime time.Time
204
+ )
191
205
for {
192
206
select {
193
207
case <- p .closed .Watch ():
194
208
return
209
+ case <- p .timeoutReset :
210
+ ticker .Reset (tickInterval )
211
+ startPackets = p .packetCount .Load ()
212
+ lastTime = time .Now ()
195
213
case <- ticker .C :
196
214
curPackets := p .packetCount .Load ()
197
215
if curPackets != lastPackets {
198
216
lastPackets = curPackets
199
- continue
217
+ lastTime = time .Now ()
218
+ continue // wait for the next tick
200
219
}
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
204
223
}
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 {
206
228
continue
207
229
}
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
+ )
208
244
timeoutCallback ()
209
245
return
210
246
}
0 commit comments