Skip to content

Commit c06f448

Browse files
authored
Move NTP function to ntp package and add ToTime32 (#301)
Moves all NTP related functions to the NTP package and adds a function to recover a time.Time from a uint32 encoded NTP timestamp.
1 parent e0e97ec commit c06f448

File tree

4 files changed

+53
-49
lines changed

4 files changed

+53
-49
lines changed

internal/ntp/ntp.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ func ToNTP(t time.Time) uint64 {
2020
return uint64(integerPart)<<32 | uint64(fractionalPart)
2121
}
2222

23+
// ToNTP32 converts a time.Time object to a uint32 NTP timestamp
24+
func ToNTP32(t time.Time) uint32 {
25+
return uint32(ToNTP(t) >> 16)
26+
}
27+
2328
// ToTime converts a uint64 NTP timestamps to a time.Time object
2429
func ToTime(t uint64) time.Time {
2530
seconds := (t & 0xFFFFFFFF00000000) >> 32
@@ -28,3 +33,12 @@ func ToTime(t uint64) time.Time {
2833

2934
return time.Unix(0, 0).Add(-2208988800 * time.Second).Add(d)
3035
}
36+
37+
// ToTime32 converts a uint32 NTP timestamp to a time.Time object, using the
38+
// highest 16 bit of the reference to recover the lost bits. The low 16 bits are
39+
// not recovered.
40+
func ToTime32(t uint32, reference time.Time) time.Time {
41+
referenceNTP := ToNTP(reference) & 0xFFFF000000000000
42+
tu64 := ((uint64(t) << 16) & 0x0000FFFFFFFF0000) | referenceNTP
43+
return ToTime(tu64)
44+
}

internal/ntp/ntp_test.go

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
"github.com/stretchr/testify/assert"
1212
)
1313

14-
func TestNTPTimeConverstion(t *testing.T) {
14+
func TestNTPToTimeConverstion(t *testing.T) {
1515
for i, cc := range []struct {
1616
ts time.Time
1717
}{
@@ -24,6 +24,7 @@ func TestNTPTimeConverstion(t *testing.T) {
2424
} {
2525
t.Run(fmt.Sprintf("TimeToNTP/%v", i), func(t *testing.T) {
2626
assert.InDelta(t, cc.ts.UnixNano(), ToTime(ToNTP(cc.ts)).UnixNano(), float64(time.Millisecond.Nanoseconds()))
27+
assert.InDelta(t, cc.ts.UnixNano(), ToTime32(ToNTP32(cc.ts), cc.ts).UnixNano(), float64(time.Millisecond.Nanoseconds()))
2728
})
2829
}
2930
}
@@ -50,3 +51,38 @@ func TestTimeToNTPConverstion(t *testing.T) {
5051
})
5152
}
5253
}
54+
55+
func TestNTPTime32(t *testing.T) {
56+
zero := time.Date(1900, time.January, 1, 0, 0, 0, 0, time.UTC)
57+
notSoLongAgo := time.Date(2022, time.May, 5, 14, 48, 20, 0, time.UTC)
58+
for i, cc := range []struct {
59+
input time.Time
60+
expected uint32
61+
}{
62+
{
63+
input: zero,
64+
expected: 0,
65+
},
66+
{
67+
input: zero.Add(time.Second),
68+
expected: 1 << 16,
69+
},
70+
{
71+
input: notSoLongAgo,
72+
expected: uint32(uint(notSoLongAgo.Sub(zero).Seconds())&0xffff) << 16,
73+
},
74+
{
75+
input: zero.Add(400 * time.Millisecond),
76+
expected: 26214,
77+
},
78+
{
79+
input: zero.Add(1400 * time.Millisecond),
80+
expected: 1<<16 + 26214,
81+
},
82+
} {
83+
t.Run(fmt.Sprintf("%v", i), func(t *testing.T) {
84+
res := ToNTP32(cc.input)
85+
assert.Equalf(t, cc.expected, res, "%b != %b", cc.expected, res)
86+
})
87+
}
88+
}

pkg/rfc8888/recorder.go

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package rfc8888
66
import (
77
"time"
88

9+
"github.com/pion/interceptor/internal/ntp"
910
"github.com/pion/rtcp"
1011
)
1112

@@ -44,7 +45,7 @@ func (r *Recorder) BuildReport(now time.Time, maxSize int) *rtcp.CCFeedbackRepor
4445
report := &rtcp.CCFeedbackReport{
4546
SenderSSRC: r.ssrc,
4647
ReportBlocks: []rtcp.CCFeedbackReportBlock{},
47-
ReportTimestamp: ntpTime32(now),
48+
ReportTimestamp: ntp.ToNTP32(now),
4849
}
4950

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

6667
return report
6768
}
68-
69-
func ntpTime32(t time.Time) uint32 {
70-
// seconds since 1st January 1900
71-
s := (float64(t.UnixNano()) / 1000000000.0) + 2208988800
72-
73-
integerPart := uint32(s)
74-
fractionalPart := uint32((s - float64(integerPart)) * 0xFFFFFFFF)
75-
76-
// higher 32 bits are the integer part, lower 32 bits are the fractional part
77-
return uint32(((uint64(integerPart)<<32 | uint64(fractionalPart)) >> 16) & 0xFFFFFFFF)
78-
}

pkg/rfc8888/recorder_test.go

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
package rfc8888
55

66
import (
7-
"fmt"
87
"testing"
98
"time"
109

@@ -161,38 +160,3 @@ func TestRecorder(t *testing.T) {
161160
}
162161
})
163162
}
164-
165-
func TestNTPTime32(t *testing.T) {
166-
zero := time.Date(1900, time.January, 1, 0, 0, 0, 0, time.UTC)
167-
notSoLongAgo := time.Date(2022, time.May, 5, 14, 48, 20, 0, time.UTC)
168-
for i, cc := range []struct {
169-
input time.Time
170-
expected uint32
171-
}{
172-
{
173-
input: zero,
174-
expected: 0,
175-
},
176-
{
177-
input: zero.Add(time.Second),
178-
expected: 1 << 16,
179-
},
180-
{
181-
input: notSoLongAgo,
182-
expected: uint32(uint(notSoLongAgo.Sub(zero).Seconds())&0xffff) << 16,
183-
},
184-
{
185-
input: zero.Add(400 * time.Millisecond),
186-
expected: 26214,
187-
},
188-
{
189-
input: zero.Add(1400 * time.Millisecond),
190-
expected: 1<<16 + 26214,
191-
},
192-
} {
193-
t.Run(fmt.Sprintf("%v", i), func(t *testing.T) {
194-
res := ntpTime32(cc.input)
195-
assert.Equalf(t, cc.expected, res, "%b != %b", cc.expected, res)
196-
})
197-
}
198-
}

0 commit comments

Comments
 (0)