abssendtimeextension.go 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
  2. // SPDX-License-Identifier: MIT
  3. package rtp
  4. import (
  5. "time"
  6. )
  7. const (
  8. absSendTimeExtensionSize = 3
  9. )
  10. // AbsSendTimeExtension is a extension payload format in
  11. // http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
  12. type AbsSendTimeExtension struct {
  13. Timestamp uint64
  14. }
  15. // Marshal serializes the members to buffer.
  16. func (t AbsSendTimeExtension) Marshal() ([]byte, error) {
  17. return []byte{
  18. byte(t.Timestamp & 0xFF0000 >> 16),
  19. byte(t.Timestamp & 0xFF00 >> 8),
  20. byte(t.Timestamp & 0xFF),
  21. }, nil
  22. }
  23. // Unmarshal parses the passed byte slice and stores the result in the members.
  24. func (t *AbsSendTimeExtension) Unmarshal(rawData []byte) error {
  25. if len(rawData) < absSendTimeExtensionSize {
  26. return errTooSmall
  27. }
  28. t.Timestamp = uint64(rawData[0])<<16 | uint64(rawData[1])<<8 | uint64(rawData[2])
  29. return nil
  30. }
  31. // Estimate absolute send time according to the receive time.
  32. // Note that if the transmission delay is larger than 64 seconds, estimated time will be wrong.
  33. func (t *AbsSendTimeExtension) Estimate(receive time.Time) time.Time {
  34. receiveNTP := toNtpTime(receive)
  35. ntp := receiveNTP&0xFFFFFFC000000000 | (t.Timestamp&0xFFFFFF)<<14
  36. if receiveNTP < ntp {
  37. // Receive time must be always later than send time
  38. ntp -= 0x1000000 << 14
  39. }
  40. return toTime(ntp)
  41. }
  42. // NewAbsSendTimeExtension makes new AbsSendTimeExtension from time.Time.
  43. func NewAbsSendTimeExtension(sendTime time.Time) *AbsSendTimeExtension {
  44. return &AbsSendTimeExtension{
  45. Timestamp: toNtpTime(sendTime) >> 14,
  46. }
  47. }
  48. func toNtpTime(t time.Time) uint64 {
  49. var s uint64
  50. var f uint64
  51. u := uint64(t.UnixNano())
  52. s = u / 1e9
  53. s += 0x83AA7E80 // offset in seconds between unix epoch and ntp epoch
  54. f = u % 1e9
  55. f <<= 32
  56. f /= 1e9
  57. s <<= 32
  58. return s | f
  59. }
  60. func toTime(t uint64) time.Time {
  61. s := t >> 32
  62. f := t & 0xFFFFFFFF
  63. f *= 1e9
  64. f >>= 32
  65. s -= 0x83AA7E80
  66. u := s*1e9 + f
  67. return time.Unix(0, int64(u))
  68. }