Skip to content

Commit

Permalink
Move NTP function to ntp package and add ToTime32 (#301)
Browse files Browse the repository at this point in the history
Moves all NTP related functions to the NTP package and adds a function
to recover a time.Time from a uint32 encoded NTP timestamp.
  • Loading branch information
mengelbart authored Jan 27, 2025
1 parent e0e97ec commit c06f448
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 49 deletions.
14 changes: 14 additions & 0 deletions internal/ntp/ntp.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ func ToNTP(t time.Time) uint64 {
return uint64(integerPart)<<32 | uint64(fractionalPart)
}

// ToNTP32 converts a time.Time object to a uint32 NTP timestamp
func ToNTP32(t time.Time) uint32 {
return uint32(ToNTP(t) >> 16)
}

// ToTime converts a uint64 NTP timestamps to a time.Time object
func ToTime(t uint64) time.Time {
seconds := (t & 0xFFFFFFFF00000000) >> 32
Expand All @@ -28,3 +33,12 @@ func ToTime(t uint64) time.Time {

return time.Unix(0, 0).Add(-2208988800 * time.Second).Add(d)
}

// ToTime32 converts a uint32 NTP timestamp to a time.Time object, using the
// highest 16 bit of the reference to recover the lost bits. The low 16 bits are
// not recovered.
func ToTime32(t uint32, reference time.Time) time.Time {
referenceNTP := ToNTP(reference) & 0xFFFF000000000000
tu64 := ((uint64(t) << 16) & 0x0000FFFFFFFF0000) | referenceNTP
return ToTime(tu64)
}
38 changes: 37 additions & 1 deletion internal/ntp/ntp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"github.com/stretchr/testify/assert"
)

func TestNTPTimeConverstion(t *testing.T) {
func TestNTPToTimeConverstion(t *testing.T) {
for i, cc := range []struct {
ts time.Time
}{
Expand All @@ -24,6 +24,7 @@ func TestNTPTimeConverstion(t *testing.T) {
} {
t.Run(fmt.Sprintf("TimeToNTP/%v", i), func(t *testing.T) {
assert.InDelta(t, cc.ts.UnixNano(), ToTime(ToNTP(cc.ts)).UnixNano(), float64(time.Millisecond.Nanoseconds()))
assert.InDelta(t, cc.ts.UnixNano(), ToTime32(ToNTP32(cc.ts), cc.ts).UnixNano(), float64(time.Millisecond.Nanoseconds()))
})
}
}
Expand All @@ -50,3 +51,38 @@ func TestTimeToNTPConverstion(t *testing.T) {
})
}
}

func TestNTPTime32(t *testing.T) {
zero := time.Date(1900, time.January, 1, 0, 0, 0, 0, time.UTC)
notSoLongAgo := time.Date(2022, time.May, 5, 14, 48, 20, 0, time.UTC)
for i, cc := range []struct {
input time.Time
expected uint32
}{
{
input: zero,
expected: 0,
},
{
input: zero.Add(time.Second),
expected: 1 << 16,
},
{
input: notSoLongAgo,
expected: uint32(uint(notSoLongAgo.Sub(zero).Seconds())&0xffff) << 16,
},
{
input: zero.Add(400 * time.Millisecond),
expected: 26214,
},
{
input: zero.Add(1400 * time.Millisecond),
expected: 1<<16 + 26214,
},
} {
t.Run(fmt.Sprintf("%v", i), func(t *testing.T) {
res := ToNTP32(cc.input)
assert.Equalf(t, cc.expected, res, "%b != %b", cc.expected, res)
})
}
}
14 changes: 2 additions & 12 deletions pkg/rfc8888/recorder.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package rfc8888
import (
"time"

"github.com/pion/interceptor/internal/ntp"
"github.com/pion/rtcp"
)

Expand Down Expand Up @@ -44,7 +45,7 @@ func (r *Recorder) BuildReport(now time.Time, maxSize int) *rtcp.CCFeedbackRepor
report := &rtcp.CCFeedbackReport{
SenderSSRC: r.ssrc,
ReportBlocks: []rtcp.CCFeedbackReportBlock{},
ReportTimestamp: ntpTime32(now),
ReportTimestamp: ntp.ToNTP32(now),
}

maxReportBlocks := (maxSize - 12 - (8 * len(r.streams))) / 2
Expand All @@ -65,14 +66,3 @@ func (r *Recorder) BuildReport(now time.Time, maxSize int) *rtcp.CCFeedbackRepor

return report
}

func ntpTime32(t time.Time) uint32 {
// seconds since 1st January 1900
s := (float64(t.UnixNano()) / 1000000000.0) + 2208988800

integerPart := uint32(s)
fractionalPart := uint32((s - float64(integerPart)) * 0xFFFFFFFF)

// higher 32 bits are the integer part, lower 32 bits are the fractional part
return uint32(((uint64(integerPart)<<32 | uint64(fractionalPart)) >> 16) & 0xFFFFFFFF)
}
36 changes: 0 additions & 36 deletions pkg/rfc8888/recorder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
package rfc8888

import (
"fmt"
"testing"
"time"

Expand Down Expand Up @@ -161,38 +160,3 @@ func TestRecorder(t *testing.T) {
}
})
}

func TestNTPTime32(t *testing.T) {
zero := time.Date(1900, time.January, 1, 0, 0, 0, 0, time.UTC)
notSoLongAgo := time.Date(2022, time.May, 5, 14, 48, 20, 0, time.UTC)
for i, cc := range []struct {
input time.Time
expected uint32
}{
{
input: zero,
expected: 0,
},
{
input: zero.Add(time.Second),
expected: 1 << 16,
},
{
input: notSoLongAgo,
expected: uint32(uint(notSoLongAgo.Sub(zero).Seconds())&0xffff) << 16,
},
{
input: zero.Add(400 * time.Millisecond),
expected: 26214,
},
{
input: zero.Add(1400 * time.Millisecond),
expected: 1<<16 + 26214,
},
} {
t.Run(fmt.Sprintf("%v", i), func(t *testing.T) {
res := ntpTime32(cc.input)
assert.Equalf(t, cc.expected, res, "%b != %b", cc.expected, res)
})
}
}

0 comments on commit c06f448

Please sign in to comment.