PageRenderTime 25ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/src/org/jitsi/impl/neomedia/rtp/remotebitrateestimator/InterArrival.java

https://gitlab.com/bickelj/libjitsi
Java | 283 lines | 155 code | 33 blank | 95 comment | 21 complexity | 9700971d838e6183cd6d18f349dffd04 MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause
  1. /*
  2. * Copyright @ 2015 Atlassian Pty Ltd
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.jitsi.impl.neomedia.rtp.remotebitrateestimator;
  17. import org.jitsi.util.*;
  18. /**
  19. * Helper class to compute the inter-arrival time delta and the size delta
  20. * between two timestamp groups. A timestamp is a 32 bit unsigned number with a
  21. * client defined rate.
  22. *
  23. * webrtc/modules/remote_bitrate_estimator/inter_arrival.cc
  24. * webrtc/modules/remote_bitrate_estimator/inter_arrival.h
  25. *
  26. * @author Lyubomir Marinov
  27. */
  28. class InterArrival
  29. {
  30. private static final int kBurstDeltaThresholdMs = 5;
  31. private static final Logger logger = Logger.getLogger(InterArrival.class);
  32. /**
  33. * webrtc/modules/include/module_common_types.h
  34. *
  35. * @param timestamp
  36. * @param prevTimestamp
  37. * @return
  38. */
  39. private static boolean isNewerTimestamp(long timestamp, long prevTimestamp)
  40. {
  41. return TimestampUtils.isNewerTimestamp(timestamp, prevTimestamp);
  42. }
  43. /**
  44. * webrtc/modules/include/module_common_types.h
  45. *
  46. * @param timestamp1
  47. * @param timestamp2
  48. * @return
  49. */
  50. private static long latestTimestamp(long timestamp1, long timestamp2)
  51. {
  52. return TimestampUtils.latestTimestamp(timestamp1, timestamp2);
  53. }
  54. private boolean burstGrouping;
  55. private TimestampGroup currentTimestampGroup = new TimestampGroup();
  56. private final long kTimestampGroupLengthTicks;
  57. private TimestampGroup prevTimestampGroup = new TimestampGroup();
  58. private double timestampToMsCoeff;
  59. /**
  60. * A timestamp group is defined as all packets with a timestamp which are at
  61. * most {@code timestampGroupLengthTicks} older than the first timestamp in
  62. * that group.
  63. *
  64. * @param timestampGroupLengthTicks
  65. * @param timestampToMsCoeff
  66. * @param enableBurstGrouping
  67. */
  68. public InterArrival(
  69. long timestampGroupLengthTicks,
  70. double timestampToMsCoeff,
  71. boolean enableBurstGrouping)
  72. {
  73. kTimestampGroupLengthTicks = timestampGroupLengthTicks;
  74. this.timestampToMsCoeff = timestampToMsCoeff;
  75. burstGrouping = enableBurstGrouping;
  76. }
  77. private boolean belongsToBurst(long arrivalTimeMs, long timestamp)
  78. {
  79. if (!burstGrouping)
  80. return false;
  81. if (currentTimestampGroup.completeTimeMs < 0)
  82. {
  83. throw new IllegalStateException(
  84. "currentTimestampGroup.completeTimeMs");
  85. }
  86. long arrivalTimeDeltaMs
  87. = arrivalTimeMs - currentTimestampGroup.completeTimeMs;
  88. long timestampDiff = timestamp - currentTimestampGroup.timestamp;
  89. long tsDeltaMs = (long) (timestampToMsCoeff * timestampDiff + 0.5);
  90. if (tsDeltaMs == 0)
  91. return true;
  92. long propagationDeltaMs = arrivalTimeDeltaMs - tsDeltaMs;
  93. return
  94. propagationDeltaMs < 0
  95. && arrivalTimeDeltaMs <= kBurstDeltaThresholdMs;
  96. }
  97. /**
  98. * Returns {@code true} if a delta was computed, or {@code false} if the
  99. * current group is still incomplete or if only one group has been
  100. * completed.
  101. *
  102. * @param timestamp is the timestamp.
  103. * @param arrivalTimeMs is the local time at which the packet arrived.
  104. * @param packetSize is the size of the packet.
  105. * @param deltas {@code timestampDelta} is the computed timestamp delta,
  106. * {@code arrivalTimeDeltaMs} is the computed arrival-time delta,
  107. * {@code packetSizeDelta} is the computed size delta.
  108. * @return
  109. */
  110. public boolean computeDeltas(
  111. long timestamp,
  112. long arrivalTimeMs,
  113. int packetSize,
  114. long[] deltas)
  115. {
  116. if (deltas == null)
  117. throw new NullPointerException("deltas");
  118. if (deltas.length != 3)
  119. throw new IllegalArgumentException("deltas.length");
  120. boolean calculatedDeltas = false;
  121. if (currentTimestampGroup.isFirstPacket())
  122. {
  123. // We don't have enough data to update the filter, so we store it
  124. // until we have two frames of data to process.
  125. currentTimestampGroup.timestamp = timestamp;
  126. currentTimestampGroup.firstTimestamp = timestamp;
  127. }
  128. else if (!isPacketInOrder(timestamp))
  129. {
  130. return false;
  131. }
  132. else if (isNewTimestampGroup(arrivalTimeMs, timestamp))
  133. {
  134. // First packet of a later frame, the previous frame sample is
  135. // ready.
  136. if (prevTimestampGroup.completeTimeMs >= 0)
  137. {
  138. /* long timestampDelta */ deltas[0]
  139. = currentTimestampGroup.timestamp
  140. - prevTimestampGroup.timestamp;
  141. long arrivalTimeDeltaMs
  142. = deltas[1]
  143. = currentTimestampGroup.completeTimeMs
  144. - prevTimestampGroup.completeTimeMs;
  145. if (arrivalTimeDeltaMs < 0)
  146. {
  147. // The group of packets has been reordered since receiving
  148. // its local arrival timestamp.
  149. logger.warn(
  150. "Packets are being reordered on the path from the "
  151. + "socket to the bandwidth estimator. Ignoring "
  152. + "this packet for bandwidth estimation.");
  153. return false;
  154. }
  155. /* int packetSizeDelta */ deltas[2]
  156. = (int)
  157. (currentTimestampGroup.size - prevTimestampGroup.size);
  158. calculatedDeltas = true;
  159. }
  160. prevTimestampGroup.copy(currentTimestampGroup);
  161. // The new timestamp is now the current frame.
  162. currentTimestampGroup.firstTimestamp = timestamp;
  163. currentTimestampGroup.timestamp = timestamp;
  164. currentTimestampGroup.size = 0;
  165. }
  166. else
  167. {
  168. currentTimestampGroup.timestamp = latestTimestamp(
  169. currentTimestampGroup.timestamp, timestamp);
  170. }
  171. // Accumulate the frame size.
  172. currentTimestampGroup.size += packetSize;
  173. currentTimestampGroup.completeTimeMs = arrivalTimeMs;
  174. return calculatedDeltas;
  175. }
  176. /**
  177. * Returns {@code true} if the last packet was the end of the current batch
  178. * and the packet with {@code timestamp} is the first of a new batch.
  179. *
  180. * @param arrivalTimeMs
  181. * @param timestamp
  182. * @return
  183. */
  184. private boolean isNewTimestampGroup(long arrivalTimeMs, long timestamp)
  185. {
  186. if (currentTimestampGroup.isFirstPacket())
  187. {
  188. return false;
  189. }
  190. else if (belongsToBurst(arrivalTimeMs, timestamp))
  191. {
  192. return false;
  193. }
  194. else
  195. {
  196. long timestampDiff
  197. = timestamp - currentTimestampGroup.firstTimestamp;
  198. return timestampDiff > kTimestampGroupLengthTicks;
  199. }
  200. }
  201. /**
  202. * Returns {@code true} if the packet with timestamp {@code timestamp}
  203. * arrived in order.
  204. *
  205. * @param timestamp
  206. * @return
  207. */
  208. private boolean isPacketInOrder(long timestamp)
  209. {
  210. if (currentTimestampGroup.isFirstPacket())
  211. {
  212. return true;
  213. }
  214. else
  215. {
  216. // Assume that a diff which is bigger than half the timestamp
  217. // interval (32 bits) must be due to reordering. This code is almost
  218. // identical to that in isNewerTimestamp() in module_common_types.h.
  219. long timestampDiff
  220. = TimestampUtils.subtractAsUnsignedInt32(timestamp, currentTimestampGroup.firstTimestamp);
  221. return timestampDiff < 0x80000000L;
  222. }
  223. }
  224. private static class TimestampGroup
  225. {
  226. public long completeTimeMs = -1L;
  227. public long size = 0L;
  228. public long firstTimestamp = 0L;
  229. public long timestamp = 0L;
  230. /**
  231. * Assigns the values of the fields of <tt>source</tt> to the respective
  232. * fields of this {@code TimestampGroup}.
  233. *
  234. * @param source the {@code TimestampGroup} the values of the fields of
  235. * which are to be assigned to the respective fields of this
  236. * {@code TimestampGroup}
  237. */
  238. public void copy(TimestampGroup source)
  239. {
  240. completeTimeMs = source.completeTimeMs;
  241. firstTimestamp = source.firstTimestamp;
  242. size = source.size;
  243. timestamp = source.timestamp;
  244. }
  245. public boolean isFirstPacket()
  246. {
  247. return completeTimeMs == -1L;
  248. }
  249. }
  250. }