in AmazonChimeSDK/AmazonChimeSDK/internal/video/VideoFrameResender.swift [45:99]
func frameDidSend(videoFrame: VideoFrame) {
lastSendTimestamp = CMClockGetTime(CMClockGetHostTimeClock())
lastVideoFrame = videoFrame
if let resendTimer = resendTimer,
resendTimer.isCancelled == false {
// There is already a timer running
return
}
let timer = DispatchSource.makeTimerSource(flags: .strict, queue: resendQueue)
resendTimer = timer
// This timer is invoked every resendTimeInterval when no frame is sent from video source
timer.setEventHandler(handler: { [weak self] in
guard let `self` = self else {
timer.cancel()
return
}
guard let lastSendTimestamp = self.lastSendTimestamp,
let lastVideoFrame = self.lastVideoFrame else { return }
let currentTimestamp = CMClockGetTime(CMClockGetHostTimeClock())
let delta = CMTimeSubtract(currentTimestamp, lastSendTimestamp)
// Resend the last input frame if there is no new input frame after resendTimeInterval
if delta > self.resendTimeInterval {
// Update the timestamp so it's not dropped by downstream as a duplicate
let lastVideoFrameTime = CMTimeMake(value: lastVideoFrame.timestampNs,
timescale: Int32(Constants.nanosecondsPerSecond))
let newVideoFrame = VideoFrame(timestampNs: Int64(CMTimeAdd(lastVideoFrameTime, delta).seconds
* Double(Constants.nanosecondsPerSecond)),
rotation: lastVideoFrame.rotation,
buffer: lastVideoFrame.buffer)
// Cancel the current timer so that new frames will kick it off again
self.resendTimer?.cancel()
self.resendTimer = nil
self.resendFrameHandler(newVideoFrame)
} else {
// Reset resending schedule if there is an input frame between internals
let remainingSeconds = self.resendTimeInterval.seconds - delta.seconds
let deadline = DispatchTime.now() + DispatchTimeInterval.milliseconds(Int(remainingSeconds *
Double(Constants.millisecondsPerSecond)))
self.resendTimer?.schedule(deadline: deadline, leeway: self.resendScheduleLeewayMs)
}
})
let deadline = DispatchTime.now()
+ DispatchTimeInterval.milliseconds(Constants.millisecondsPerSecond / Int(minFrameRate))
timer.schedule(deadline: deadline, leeway: resendScheduleLeewayMs)
timer.activate()
}