Time Sync Improvement
Создано: 21 ноября 2024 г.
Отвечено с использованием OpenAI 01 Mini от OpenAI01
Создано: 21 ноября 2024 г.
Отвечено с использованием OpenAI 01 Mini от OpenAI01
评估代码的准确性
查看代码计算单向时延(OWD)和往返时延(RTT)的方法,特别是启动和接收片段的处理逻辑。
分析时间同步
我正在计算RTT和OWD。在视频接收器片段中,发送时间同步请求,接收方设定时间戳并回复。RTT通过计算时差得到,时钟偏移量通过时间戳差的平均值计算。
考核OWD论文
计算传输时间
我正在计算从发送方到接收方的往返时间(RTT)。通过发送方和接收方的时钟差异以及传输时间和接收时间,最终得到 RTT = t4 - t1 - (t3 - t2)。
考量时间同步
时间同步可能不准确,代码计算OWD为(t2 - t1) - clockOffset,但实际无法用单向消息精确测量OWD,需依赖RTT。时间同步可以估计OWD,但需要知道发送方和接收方的时钟是否已经同步。ერთ rekey_request, rekey_response和others вызовы на управляющей части.
调整时间设置
现在我们在看VideoReceiverFragment,t2和t3指的是请求收到和处理后的发送时间。这说明响应发送是即时的,处理时间不包含在内。
纠正SDK错误
调整时间同步
在解析和处理时间同步请求时,设置接收时间t2,然后处理,最后设置发送时间t3。这确保t3 - t2包括处理延迟,从而获得准确的时钟偏移和往返时间。
检测问题并调整时间同步
您的代码在计算单向时延(OWD)和往返时延(RTT)时存在一些潜在的问题,主要集中在时间同步(Time Synchronization)的实现上。以下是详细分析和建议:
发起方(VideoInitiatorFragment):
time_sync_request
,包含发送时间 t1
。time_sync_response
后,记录接收时间 t4
,并使用 t2
和 t3
来计算 RTT 和时钟偏移量(clockOffset)。接收方(VideoReceiverFragment):
time_sync_request
后,立即记录接收时间 t2
和发送时间 t3
,并发送回 time_sync_response
。t2
和 t3
的设定方式:
VideoReceiverFragment
中,t2
和 t3
是在接收到请求后立即设定的,没有考虑任何处理时间。这意味着 t3 - t2 ≈ 0
,导致 RTT 计算为 t4 - t1
,忽略了接收方处理请求并发送响应所需的时间。这会使 RTT 的计算不准确,从而影响 clockOffset
和 OWD 的计算。单向时延(OWD)的计算:
(t2 - t1) - clockOffset
。然而,由于 clockOffset
的计算基于不准确的 RTT,这导致 OWD 的估计也不准确。时间同步的准确性:
t2
和 t3
设定:确保 t3
记录的是发送响应的准确时间,应该在发送响应之前设定 t3
,而不是与 t2
相同。例如:
private fun handleSignalingData(data: JSONObject) { Log.d(TAG, "Handling signaling data: $data") when (data.getString("type")) { "time_sync_request" -> { val t1 = data.getLong("t1") val t2 = System.currentTimeMillis() // 模拟一些处理延迟(如果有的话) // 例如,等待某个条件或执行一些操作 val t3 = System.currentTimeMillis() // 确保 t3 > t2 val syncResponse = JSONObject().apply { put("type", "time_sync_response") put("t1", t1) put("t2", t2) put("t3", t3) put("room", currentRoom) } socket.emit("signal", syncResponse) Log.d(TAG, "回复 time_sync_request: t1=$t1, t2=$t2, t3=$t3") } // 其他信令类型处理 } }
为了提高时间同步的准确性,可以进行多次时间同步测量,并取平均值或其他统计方法来减少网络抖动的影响。
private fun startTimeSync(intervalMs: Long = 5000L, attempts: Int = 5) { viewLifecycleOwner.lifecycleScope.launch { while (isActive) { delay(intervalMs) repeat(attempts) { requestTimeSync() delay(100) // 每次请求之间的间隔 } } } }
确保 RTT 和 OWD 的计算基于准确的 clockOffset
,并考虑多次测量后的平均值。例如:
private val clockOffsets = mutableListOf<Long>() private val rttValues = mutableListOf<Long>() private fun handleSignalingData(data: JSONObject) { // 现有的代码... when (data.getString("type")) { "time_sync_response" -> { val t1 = data.getLong("t1") val t2 = data.getLong("t2") val t3 = data.getLong("t3") val t4 = System.currentTimeMillis() val rtt = t4 - t1 - (t3 - t2) val offset = ((t2 - t1) + (t3 - t4)) / 2 // 保存 RTT 和 clockOffset rttValues.add(rtt) clockOffsets.add(offset) // 计算平均 RTT 和 clockOffset val avgRtt = rttValues.average().toLong() val avgOffset = clockOffsets.average().toLong() // 计算 OWD val owd = (t2 - t1) - avgOffset if (owd >= 0) { viewLifecycleOwner.lifecycleScope.launch { // 更新 RTT 和 OWD 状态 rttState.longValue = avgRtt owdState.longValue = owd // 更新历史记录和统计信息 // (现有的代码) } } else { Log.e(TAG, "计算出的 OWD 为负数,可能时钟同步有误。") } } // 其他信令类型处理 } }
如果需要更高精度的时间同步,可以考虑使用专门的时间同步库或协议,如 NTP 或 PTP。这些协议经过优化,可以提供更准确的时钟同步。
权限检查:
异常处理:
性能优化:
您的代码在基本的 RTT 和 OWD 计算逻辑上是正确的,但由于时间同步过程中 t3
被设定为与 t2
相同,导致 RTT 和 clockOffset 的计算不准确,进而影响 OWD 的估计。通过确保 t3
记录的是准确的响应发送时间,并考虑多次测量来提高同步精度,可以显著改善时延计算的准确性。
如果您有进一步的问题或需要更详细的帮助,请随时提问!
时间同步的问题
我在分析代码时发现,接收者片段中t3设定得很紧,影响了RTT和clockOffset计算。问t3可以正确设置吗?可以模拟一些处理时延来使t3-t2不为零。
确保时钟同步
在实际应用中,处理时间会影响RTT和clockOffset计算的准确性。为了确保t3准确,在接收器片段中安排处理延迟或测量实际处理时间是重要的。
时间同步请求处理中合理利用系统时间以提高精度。
安排时间发送
为了处理数据时序问题,我在接收端模拟处理延迟,通过协程异步发送响应。我还计划在"处理请求"时明确设置发送时间点。
设定正确条件
在代码处理中,确保 time_sync_request
条件成立时,t2
被设定为当前时间,t3
在响应发送前设置。
是的,您可以通过正确地设置 t3
来改进当前的单向时延(OWD)和往返时延(RTT)计算。目前,t3
被设置为与 t2
相同,这会导致 t3 - t2 ≈ 0
,从而使 RTT 和 clockOffset
的计算不准确。以下是详细的解决方案和代码示例,帮助您正确地设置 t3
并改进时延计算。
t2
和 t3
在 VideoReceiverFragment
中,t2
应该是在接收到 time_sync_request
时记录的时间,而 t3
应该是在发送 time_sync_response
之前记录的时间。这意味着 t3
代表了处理请求所花费的时间。
handleSignalingData
方法以下是如何在 VideoReceiverFragment
中正确设置 t2
和 t3
的示例:
private fun handleSignalingData(data: JSONObject) { Log.d(TAG, "Handling signaling data: $data") when (data.getString("type")) { "time_sync_request" -> { val t1 = data.getLong("t1") val t2 = System.currentTimeMillis() // 模拟处理时间(如果有实际的处理任务,可以在这里执行) // 如果没有,可以选择不添加延迟,t3 将紧随 t2 // 例如,添加一个短暂的延迟来模拟处理时间 // viewLifecycleOwner.lifecycleScope.launch { // delay(10) // 模拟10毫秒的处理时间 // val t3 = System.currentTimeMillis() // sendTimeSyncResponse(t1, t2, t3) // } // 如果没有实际的处理任务,直接设置 t3 val t3 = System.currentTimeMillis() sendTimeSyncResponse(t1, t2, t3) } // 其他信令类型处理 else -> { Log.e(TAG, "Unknown signaling type: ${data.getString("type")}") } } } private fun sendTimeSyncResponse(t1: Long, t2: Long, t3: Long) { val syncResponse = JSONObject().apply { put("type", "time_sync_response") put("t1", t1) put("t2", t2) put("t3", t3) put("room", currentRoom) } socket.emit("signal", syncResponse) Log.d(TAG, "回复 time_sync_request: t1=$t1, t2=$t2, t3=$t3") }
记录 t1
和 t2
:
t1
是 initiator 发送请求时的时间戳。t2
是 receiver 接收到请求时的时间戳。处理请求并记录 t3
:
t3
。t3
之前添加适当的延迟。发送响应:
t1
、t2
和 t3
作为响应的一部分发送回 initiator。如果您希望模拟实际的处理延迟,可以取消注释相关代码:
viewLifecycleOwner.lifecycleScope.launch { delay(10) // 模拟10毫秒的处理时间 val t3 = System.currentTimeMillis() sendTimeSyncResponse(t1, t2, t3) }
这样,t3 - t2
将包含模拟的处理时间,使 RTT 的计算更为准确。
确保在 VideoInitiatorFragment
中正确处理 time_sync_response
,并使用 t1
、t2
和 t3
来计算 RTT 和 clockOffset
。以下是改进后的代码示例:
private fun handleSignalingData(data: JSONObject) { Log.d(TAG, "Handling signaling data: $data") when (data.getString("type")) { "offer" -> { /* 现有代码 */ } "answer" -> { /* 现有代码 */ } "ice" -> { /* 现有代码 */ } "time_sync_response" -> { Log.d(TAG, "Received time_sync_response") val t1 = data.getLong("t1") val t2 = data.getLong("t2") val t3 = data.getLong("t3") val t4 = System.currentTimeMillis() // 计算 RTT 和时钟偏移量 val rtt = t4 - t1 - (t3 - t2) val clockOffset = ((t2 - t1) + (t3 - t4)) / 2 Log.d(TAG, "时间同步: RTT=$rtt ms, 时钟偏移量= $clockOffset ms") // 计算单向时延 OWD val owd = (t2 - t1) - clockOffset if (owd >= 0) { viewLifecycleOwner.lifecycleScope.launch { // 更新 RTT 状态 rttState.longValue = rtt // 更新 RTT 历史记录 rttHistory.add(rtt) if (rttHistory.size > 60) { rttHistory.removeAt(0) } // 计算 RTT 的最大、最小和平均值 val maxRtt = rttHistory.maxOrNull() ?: 0L val minRtt = rttHistory.minOrNull() ?: 0L val averageRtt = if (rttHistory.isNotEmpty()) { rttHistory.average().toLong() } else { 0L } // 更新 OWD 状态 owdState.longValue = owd // 更新 OWD 历史记录 owdHistory.add(owd) if (owdHistory.size > 60) { owdHistory.removeAt(0) } // 计算 OWD 的最大、最小和平均值 val maxOwd = owdHistory.maxOrNull() ?: 0L val minOwd = owdHistory.minOrNull() ?: 0L val averageOwd = if (owdHistory.isNotEmpty()) { owdHistory.average().toLong() } else { 0L } Log.d(TAG, "RTT - 最新: $rtt ms, 最大: $maxRtt ms, 最小: $minRtt ms, 平均: $averageRtt ms") Log.d(TAG, "单向时延 (OWD) - 最新: $owd ms, 最大: $maxOwd ms, 最小: $minOwd ms, 平均: $averageOwd ms") } } else { Log.e(TAG, "计算出的 OWD 为负数,可能时钟同步有误。") } } else -> { Log.e(TAG, "Unknown signaling type: ${data.getString("type")}") } } }
接收响应并提取时间戳:
time_sync_response
中提取 t1
、t2
和 t3
。计算 RTT 和 clockOffset
:
RTT = t4 - t1 - (t3 - t2)
t4
是接收响应时的当前时间。t3 - t2
是 receiver 处理请求并发送响应所花费的时间。clockOffset = ((t2 - t1) + (t3 - t4)) / 2
计算 OWD:
OWD = (t2 - t1) - clockOffset
OWD
为非负值。更新状态和历史记录:
为了提高时间同步的准确性,建议进行多次同步测量并取平均值。这可以减少网络抖动和偶发延迟对结果的影响。
startTimeSync
方法private fun startTimeSync(intervalMs: Long = 5000L, attemptsPerSync: Int = 5) { viewLifecycleOwner.lifecycleScope.launch { while (isActive) { delay(intervalMs) repeat(attemptsPerSync) { requestTimeSync() delay(100) // 每次请求之间的间隔 } } } }
handleSignalingData
方法在 handleSignalingData
中,收集多个 RTT 和 clockOffset
值,并计算平均值:
private val rttValues = mutableListOf<Long>() private val clockOffsets = mutableListOf<Long>() private fun handleSignalingData(data: JSONObject) { Log.d(TAG, "Handling signaling data: $data") when (data.getString("type")) { "time_sync_request" -> { val t1 = data.getLong("t1") val t2 = System.currentTimeMillis() val t3 = System.currentTimeMillis() sendTimeSyncResponse(t1, t2, t3) } "time_sync_response" -> { Log.d(TAG, "Received time_sync_response") val t1 = data.getLong("t1") val t2 = data.getLong("t2") val t3 = data.getLong("t3") val t4 = System.currentTimeMillis() val rtt = t4 - t1 - (t3 - t2) val clockOffset = ((t2 - t1) + (t3 - t4)) / 2 // 保存 RTT 和 clockOffset rttValues.add(rtt) clockOffsets.add(clockOffset) // 只保留最近的 N 个值 if (rttValues.size > 20) rttValues.removeAt(0) if (clockOffsets.size > 20) clockOffsets.removeAt(0) // 计算平均 RTT 和 clockOffset val avgRtt = rttValues.average().toLong() val avgClockOffset = clockOffsets.average().toLong() // 计算 OWD val owd = (t2 - t1) - avgClockOffset if (owd >= 0) { viewLifecycleOwner.lifecycleScope.launch { // 更新 RTT 状态 rttState.longValue = avgRtt // 更新 RTT 历史记录 rttHistory.add(avgRtt) if (rttHistory.size > 60) { rttHistory.removeAt(0) } // 计算 RTT 的最大、最小和平均值 val maxRtt = rttHistory.maxOrNull() ?: 0L val minRtt = rttHistory.minOrNull() ?: 0L val averageRtt = if (rttHistory.isNotEmpty()) { rttHistory.average().toLong() } else { 0L } // 更新 OWD 状态 owdState.longValue = owd // 更新 OWD 历史记录 owdHistory.add(owd) if (owdHistory.size > 60) { owdHistory.removeAt(0) } // 计算 OWD 的最大、最小和平均值 val maxOwd = owdHistory.maxOrNull() ?: 0L val minOwd = owdHistory.minOrNull() ?: 0L val averageOwd = if (owdHistory.isNotEmpty()) { owdHistory.average().toLong() } else { 0L } Log.d(TAG, "RTT - 最新: $avgRtt ms, 最大: $maxRtt ms, 最小: $minRtt ms, 平均: $averageRtt ms") Log.d(TAG, "单向时延 (OWD) - 最新: $owd ms, 最大: $maxOwd ms, 最小: $minOwd ms, 平均: $averageOwd ms") } } else { Log.e(TAG, "计算出的 OWD 为负数,可能时钟同步有误。") } } else -> { Log.e(TAG, "Unknown signaling type: ${data.getString("type")}") } } }
收集多次 RTT 和 clockOffset
值:
rttValues
和 clockOffsets
列表来存储多次同步的结果。计算平均 RTT 和 clockOffset
:
clockOffset
。计算 OWD:
clockOffset
来计算 OWD,确保更准确的单向时延估计。System.currentTimeMillis()
具有较低的精度,可能导致 RTT 和 OWD 的计算不够精确。建议使用 System.nanoTime()
或 SystemClock.elapsedRealtime()
来获取更高精度的时间戳。
// 使用 System.nanoTime() 获取高精度时间戳 private fun handleSignalingData(data: JSONObject) { when (data.getString("type")) { "time_sync_request" -> { val t1 = data.getLong("t1") val t2 = System.nanoTime() / 1_000_000 // 转换为毫秒 val t3 = System.nanoTime() / 1_000_000 sendTimeSyncResponse(t1, t2, t3) } "time_sync_response" -> { val t1 = data.getLong("t1") val t2 = data.getLong("t2") val t3 = data.getLong("t3") val t4 = System.nanoTime() / 1_000_000 val rtt = t4 - t1 - (t3 - t2) val clockOffset = ((t2 - t1) + (t3 - t4)) / 2 // 其余逻辑不变 } // 其他信令类型处理 } }
尽管上述改进可以提高时延计算的准确性,但时钟漂移和网络抖动仍然可能影响结果。为此,建议:
以下是经过上述改进后的 VideoReceiverFragment
和 VideoInitiatorFragment
的关键部分代码示例。
private fun handleSignalingData(data: JSONObject) { Log.d(TAG, "Handling signaling data: $data") when (data.getString("type")) { "time_sync_request" -> { val t1 = data.getLong("t1") val t2 = System.nanoTime() / 1_000_000 // 毫秒 // 如果有实际的处理任务,可以在这里执行 // 模拟处理时间(可选) // delay(10) // 使用协程延迟模拟处理时间 val t3 = System.nanoTime() / 1_000_000 sendTimeSyncResponse(t1, t2, t3) } "time_sync_response" -> { Log.d(TAG, "Received time_sync_response") val t1 = data.getLong("t1") val t2 = data.getLong("t2") val t3 = data.getLong("t3") val t4 = System.nanoTime() / 1_000_000 // 毫秒 val rtt = t4 - t1 - (t3 - t2) val clockOffset = ((t2 - t1) + (t3 - t4)) / 2 // 保存 RTT 和 clockOffset rttValues.add(rtt) clockOffsets.add(clockOffset) // 保持最近的 20 个值 if (rttValues.size > 20) rttValues.removeAt(0) if (clockOffsets.size > 20) clockOffsets.removeAt(0) // 计算平均 RTT 和 clockOffset val avgRtt = rttValues.average().toLong() val avgClockOffset = clockOffsets.average().toLong() // 计算 OWD val owd = (t2 - t1) - avgClockOffset if (owd >= 0) { viewLifecycleOwner.lifecycleScope.launch { // 更新 RTT 状态 rttState.longValue = avgRtt // 更新 RTT 历史记录 rttHistory.add(avgRtt) if (rttHistory.size > 60) { rttHistory.removeAt(0) } // 计算 RTT 的最大、最小和平均值 val maxRtt = rttHistory.maxOrNull() ?: 0L val minRtt = rttHistory.minOrNull() ?: 0L val averageRtt = if (rttHistory.isNotEmpty()) { rttHistory.average().toLong() } else { 0L } // 更新 OWD 状态 owdState.longValue = owd // 更新 OWD 历史记录 owdHistory.add(owd) if (owdHistory.size > 60) { owdHistory.removeAt(0) } // 计算 OWD 的最大、最小和平均值 val maxOwd = owdHistory.maxOrNull() ?: 0L val minOwd = owdHistory.minOrNull() ?: 0L val averageOwd = if (owdHistory.isNotEmpty()) { owdHistory.average().toLong() } else { 0L } Log.d(TAG, "RTT - 最新: $avgRtt ms, 最大: $maxRtt ms, 最小: $minRtt ms, 平均: $averageRtt ms") Log.d(TAG, "单向时延 (OWD) - 最新: $owd ms, 最大: $maxOwd ms, 最小: $minOwd ms, 平均: $averageOwd ms") } } else { Log.e(TAG, "计算出的 OWD 为负数,可能时钟同步有误。") } } else -> { Log.e(TAG, "Unknown signaling type: ${data.getString("type")}") } } } private fun sendTimeSyncResponse(t1: Long, t2: Long, t3: Long) { val syncResponse = JSONObject().apply { put("type", "time_sync_response") put("t1", t1) put("t2", t2) put("t3", t3) put("room", currentRoom) } socket.emit("signal", syncResponse) Log.d(TAG, "回复 time_sync_request: t1=$t1, t2=$t2, t3=$t3") }
private fun handleSignalingData(data: JSONObject) { Log.d(TAG, "Handling signaling data: $data") when (data.getString("type")) { "offer" -> { /* 现有代码 */ } "answer" -> { /* 现有代码 */ } "ice" -> { /* 现有代码 */ } "time_sync_response" -> { Log.d(TAG, "Received time_sync_response") val t1 = data.getLong("t1") val t2 = data.getLong("t2") val t3 = data.getLong("t3") val t4 = System.nanoTime() / 1_000_000 // 毫秒 val rtt = t4 - t1 - (t3 - t2) val clockOffset = ((t2 - t1) + (t3 - t4)) / 2 Log.d(TAG, "时间同步: RTT=$rtt ms, 时钟偏移量= $clockOffset ms") // 计算单向时延 OWD val owd = (t2 - t1) - clockOffset if (owd >= 0) { viewLifecycleOwner.lifecycleScope.launch { // 更新 RTT 状态 rttState.longValue = rtt // 更新 RTT 历史记录 rttHistory.add(rtt) if (rttHistory.size > 60) { rttHistory.removeAt(0) } // 计算 RTT 的最大、最小和平均值 val maxRtt = rttHistory.maxOrNull() ?: 0L val minRtt = rttHistory.minOrNull() ?: 0L val averageRtt = if (rttHistory.isNotEmpty()) { rttHistory.average().toLong() } else { 0L } // 更新 OWD 状态 owdState.longValue = owd // 更新 OWD 历史记录 owdHistory.add(owd) if (owdHistory.size > 60) { owdHistory.removeAt(0) } // 计算 OWD 的最大、最小和平均值 val maxOwd = owdHistory.maxOrNull() ?: 0L val minOwd = owdHistory.minOrNull() ?: 0L val averageOwd = if (owdHistory.isNotEmpty()) { owdHistory.average().toLong() } else { 0L } Log.d(TAG, "RTT - 最新: $rtt ms, 最大: $maxRtt ms, 最小: $minRtt ms, 平均: $averageRtt ms") Log.d(TAG, "单向时延 (OWD) - 最新: $owd ms, 最大: $maxOwd ms, 最小: $minOwd ms, 平均: $averageOwd ms") } } else { Log.e(TAG, "计算出的 OWD 为负数,可能时钟同步有误。") } } else -> { Log.e(TAG, "Unknown signaling type: ${data.getString("type")}") } } }
正确记录时间戳:
t2
在接收到请求时记录。t3
在发送响应前记录。t4
在接收到响应时记录。计算 RTT 和 clockOffset
:
RTT = t4 - t1 - (t3 - t2)
clockOffset = ((t2 - t1) + (t3 - t4)) / 2
计算 OWD:
OWD = (t2 - t1) - clockOffset
多次同步测量:
clockOffset
值,取平均值以提高准确性。使用高精度时间戳:
System.nanoTime()
或 SystemClock.elapsedRealtime()
代替 System.currentTimeMillis()
以获得更高的时间精度。处理负值 OWD:
OWD
为负数时,记录错误日志,并考虑重新进行时间同步以纠正时钟偏移。private val rttValues = mutableListOf<Long>() private val clockOffsets = mutableListOf<Long>() private fun handleSignalingData(data: JSONObject) { Log.d(TAG, "Handling signaling data: $data") when (data.getString("type")) { "time_sync_request" -> { val t1 = data.getLong("t1") val t2 = System.nanoTime() / 1_000_000 // 毫秒 // 如果有实际的处理任务,可以在这里执行 // 模拟处理时间(可选) // viewLifecycleOwner.lifecycleScope.launch { // delay(10) // 模拟10毫秒的处理时间 // val t3 = System.nanoTime() / 1_000_000 // sendTimeSyncResponse(t1, t2, t3) // } // 如果没有实际的处理任务,直接设置 t3 val t3 = System.nanoTime() / 1_000_000 sendTimeSyncResponse(t1, t2, t3) } "time_sync_response" -> { Log.d(TAG, "Received time_sync_response") val t1 = data.getLong("t1") val t2 = data.getLong("t2") val t3 = data.getLong("t3") val t4 = System.nanoTime() / 1_000_000 // 毫秒 val rtt = t4 - t1 - (t3 - t2) val clockOffset = ((t2 - t1) + (t3 - t4)) / 2 // 保存 RTT 和 clockOffset rttValues.add(rtt) clockOffsets.add(clockOffset) // 保持最近的 20 个值 if (rttValues.size > 20) rttValues.removeAt(0) if (clockOffsets.size > 20) clockOffsets.removeAt(0) // 计算平均 RTT 和 clockOffset val avgRtt = rttValues.average().toLong() val avgClockOffset = clockOffsets.average().toLong() // 计算 OWD val owd = (t2 - t1) - avgClockOffset if (owd >= 0) { viewLifecycleOwner.lifecycleScope.launch { // 更新 RTT 状态 rttState.longValue = avgRtt // 更新 RTT 历史记录 rttHistory.add(avgRtt) if (rttHistory.size > 60) { rttHistory.removeAt(0) } // 计算 RTT 的最大、最小和平均值 val maxRtt = rttHistory.maxOrNull() ?: 0L val minRtt = rttHistory.minOrNull() ?: 0L val averageRtt = if (rttHistory.isNotEmpty()) { rttHistory.average().toLong() } else { 0L } // 更新 OWD 状态 owdState.longValue = owd // 更新 OWD 历史记录 owdHistory.add(owd) if (owdHistory.size > 60) { owdHistory.removeAt(0) } // 计算 OWD 的最大、最小和平均值 val maxOwd = owdHistory.maxOrNull() ?: 0L val minOwd = owdHistory.minOrNull() ?: 0L val averageOwd = if (owdHistory.isNotEmpty()) { owdHistory.average().toLong() } else { 0L } Log.d(TAG, "RTT - 最新: $avgRtt ms, 最大: $maxRtt ms, 最小: $minRtt ms, 平均: $averageRtt ms") Log.d(TAG, "单向时延 (OWD) - 最新: $owd ms, 最大: $maxOwd ms, 最小: $minOwd ms, 平均: $averageOwd ms") } } else { Log.e(TAG, "计算出的 OWD 为负数,可能时钟同步有误。") } } else -> { Log.e(TAG, "Unknown signaling type: ${data.getString("type")}") } } } private fun sendTimeSyncResponse(t1: Long, t2: Long, t3: Long) { val syncResponse = JSONObject().apply { put("type", "time_sync_response") put("t1", t1) put("t2", t2) put("t3", t3) put("room", currentRoom) } socket.emit("signal", syncResponse) Log.d(TAG, "回复 time_sync_request: t1=$t1, t2=$t2, t3=$t3") }
private val rttValues = mutableListOf<Long>() private val clockOffsets = mutableListOf<Long>() private fun handleSignalingData(data: JSONObject) { Log.d(TAG, "Handling signaling data: $data") when (data.getString("type")) { "offer" -> { /* 现有代码 */ } "answer" -> { /* 现有代码 */ } "ice" -> { /* 现有代码 */ } "time_sync_response" -> { Log.d(TAG, "Received time_sync_response") val t1 = data.getLong("t1") val t2 = data.getLong("t2") val t3 = data.getLong("t3") val t4 = System.nanoTime() / 1_000_000 // 毫秒 val rtt = t4 - t1 - (t3 - t2) val clockOffset = ((t2 - t1) + (t3 - t4)) / 2 Log.d(TAG, "时间同步: RTT=$rtt ms, 时钟偏移量= $clockOffset ms") // 保存 RTT 和 clockOffset rttValues.add(rtt) clockOffsets.add(clockOffset) // 保持最近的 20 个值 if (rttValues.size > 20) rttValues.removeAt(0) if (clockOffsets.size > 20) clockOffsets.removeAt(0) // 计算平均 RTT 和 clockOffset val avgRtt = rttValues.average().toLong() val avgClockOffset = clockOffsets.average().toLong() // 计算 OWD val owd = (t2 - t1) - avgClockOffset if (owd >= 0) { viewLifecycleOwner.lifecycleScope.launch { // 更新 RTT 状态 rttState.longValue = avgRtt // 更新 RTT 历史记录 rttHistory.add(avgRtt) if (rttHistory.size > 60) { rttHistory.removeAt(0) } // 计算 RTT 的最大、最小和平均值 val maxRtt = rttHistory.maxOrNull() ?: 0L val minRtt = rttHistory.minOrNull() ?: 0L val averageRtt = if (rttHistory.isNotEmpty()) { rttHistory.average().toLong() } else { 0L } // 更新 OWD 状态 owdState.longValue = owd // 更新 OWD 历史记录 owdHistory.add(owd) if (owdHistory.size > 60) { owdHistory.removeAt(0) } // 计算 OWD 的最大、最小和平均值 val maxOwd = owdHistory.maxOrNull() ?: 0L val minOwd = owdHistory.minOrNull() ?: 0L val averageOwd = if (owdHistory.isNotEmpty()) { owdHistory.average().toLong() } else { 0L } Log.d(TAG, "RTT - 最新: $avgRtt ms, 最大: $maxRtt ms, 最小: $minRtt ms, 平均: $averageRtt ms") Log.d(TAG, "单向时延 (OWD) - 最新: $owd ms, 最大: $maxOwd ms, 最小: $minOwd ms, 平均: $averageOwd ms") } } else { Log.e(TAG, "计算出的 OWD 为负数,可能时钟同步有误。") } } else -> { Log.e(TAG, "Unknown signaling type: ${data.getString("type")}") } } }
通过以上修改,您可以确保 t3
在发送响应时被正确设置,从而提高 RTT 和 OWD 计算的准确性。此外,通过进行多次同步测量并取平均值,可以进一步减少网络抖动对结果的影响。以下是关键步骤的总结:
正确记录时间戳:
t2
在接收到请求时记录。t3
在发送响应前记录。计算 RTT 和 clockOffset
:
clockOffset
。计算 OWD:
clockOffset
计算单向时延,确保其为非负值。多次同步测量:
clockOffset
,并计算平均值以提高准确性。使用高精度时间戳:
System.nanoTime()
或 SystemClock.elapsedRealtime()
来获取更高精度的时间戳。通过这些改进,您的应用程序将能够更准确地测量和显示单向时延和往返时延,从而提供更可靠的网络性能指标。
如果您有任何进一步的问题或需要更多帮助,请随时提问!