Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/sip-pin-answer-time-attrs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"github.com/livekit/protocol": patch
"@livekit/protocol": patch
---

Add `lk.sip.pinEnteredTime` and `lk.sip.answerTime` SIP participant attributes, with helpers to set and parse them
4 changes: 4 additions & 0 deletions livekit/attrs.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ const (
AttrSIPHeaderPrefix = AttrSIPPrefix + "h."
// AttrSIPInviteTime attribute contains the time the inbound INVITE was received, in Unix milliseconds.
AttrSIPInviteTime = "lk.sip.inviteTime"
// AttrSIPPinEnteredTime attribute contains the time the caller finished entering the PIN on an inbound PIN call, in Unix milliseconds.
AttrSIPPinEnteredTime = "lk.sip.pinEnteredTime"
// AttrSIPAnswerTime attribute contains the time the callee answered an outbound call, in Unix milliseconds.
AttrSIPAnswerTime = "lk.sip.answerTime"

// AttrIngressPrefix is shared for all Ingress attributes
AttrIngressPrefix = "ingress."
Expand Down
34 changes: 30 additions & 4 deletions sip/attrs.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,40 @@ import (
)

func InviteTimeAttributes(t time.Time) map[string]string {
return map[string]string{
livekit.AttrSIPInviteTime: strconv.FormatInt(t.UnixMilli(), 10),
}
return timeAttributes(livekit.AttrSIPInviteTime, t)
}

// ParseInviteTime returns the zero time if the attribute is missing or malformed.
func ParseInviteTime(attrs map[string]string) time.Time {
ms, err := strconv.ParseInt(attrs[livekit.AttrSIPInviteTime], 10, 64)
return parseTimeAttribute(attrs, livekit.AttrSIPInviteTime)
}

func PinEnteredTimeAttributes(t time.Time) map[string]string {
return timeAttributes(livekit.AttrSIPPinEnteredTime, t)
}

// ParsePinEnteredTime returns the zero time if the attribute is missing or malformed.
func ParsePinEnteredTime(attrs map[string]string) time.Time {
return parseTimeAttribute(attrs, livekit.AttrSIPPinEnteredTime)
}

func AnswerTimeAttributes(t time.Time) map[string]string {
return timeAttributes(livekit.AttrSIPAnswerTime, t)
}

// ParseAnswerTime returns the zero time if the attribute is missing or malformed.
func ParseAnswerTime(attrs map[string]string) time.Time {
return parseTimeAttribute(attrs, livekit.AttrSIPAnswerTime)
}

func timeAttributes(key string, t time.Time) map[string]string {
return map[string]string{
key: strconv.FormatInt(t.UnixMilli(), 10),
}
}

func parseTimeAttribute(attrs map[string]string, key string) time.Time {
ms, err := strconv.ParseInt(attrs[key], 10, 64)
if err != nil {
return time.Time{}
}
Expand Down
23 changes: 19 additions & 4 deletions sip/attrs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,25 @@ import (
"github.com/livekit/protocol/livekit"
)

func TestInviteTimeAttributes(t *testing.T) {
func TestTimeAttributes(t *testing.T) {
cases := []struct {
key string
format func(time.Time) map[string]string
parse func(map[string]string) time.Time
}{
{livekit.AttrSIPInviteTime, InviteTimeAttributes, ParseInviteTime},
{livekit.AttrSIPPinEnteredTime, PinEnteredTimeAttributes, ParsePinEnteredTime},
{livekit.AttrSIPAnswerTime, AnswerTimeAttributes, ParseAnswerTime},
}
at := time.UnixMilli(time.Now().UnixMilli())
require.True(t, at.Equal(ParseInviteTime(InviteTimeAttributes(at))))
for _, c := range cases {
t.Run(c.key, func(t *testing.T) {
attrs := c.format(at)
require.Contains(t, attrs, c.key)
require.True(t, at.Equal(c.parse(attrs)))

require.True(t, ParseInviteTime(nil).IsZero())
require.True(t, ParseInviteTime(map[string]string{livekit.AttrSIPInviteTime: "bad"}).IsZero())
require.True(t, c.parse(nil).IsZero())
require.True(t, c.parse(map[string]string{c.key: "bad"}).IsZero())
})
}
}
Loading