Repository navigation
Data tracks: core - #990
Conversation
f15a229 to
b7b6532
Compare
b7b6532 to
1c85018
Compare
5572d61 to
dc69ba0
Compare
| func (d *depacketizer) frameFromSingle(packet dtp.Packet, options depacketizerPushOptions) depacketizerPushResult { | ||
| var result depacketizerPushResult | ||
| if len(d.partials) >= options.maxPartialFrames { | ||
| result.drop = d.evictOldest(packet.FrameNumber) |
There was a problem hiding this comment.
The single frame has not been appended to the partials, do we still need to evict one?
There was a problem hiding this comment.
A Single arriving while the partials map is at capacity is treated as a signal that the oldest in-flight partial is stale: the publisher has moved on to a later frame, and on an unordered channel with no retransmits its missing packets aren't coming. It doesn't change what gets dropped (the next Start would evict it anyway), only that the drop is reported promptly and attributed to the frame that actually superseded it. This matches the Rust implementation.
c9fa55a to
ae3dc6f
Compare
c2ca3f6 to
5692ffc
Compare
5692ffc to
5810844
Compare
boks1971
left a comment
There was a problem hiding this comment.
Left a bunch of small comment. Good stuff @ladvoc !
Would be good to act on the extension ID collision ASAP. I will look into moving the internal one to 255 and accept both on read side for a deploy and then we can replace ID at 1 with e2ee extension id.
| nanos = 0 | ||
| } | ||
| seconds, remainder := uint64(nanos)/1_000_000_000, uint64(nanos)%1_000_000_000 | ||
| return uint32(seconds*clockRate + (remainder*clockRate+500_000_000)/1_000_000_000) |
There was a problem hiding this comment.
Can potentially make this simpler.
d.Seconds()
returns float64. So, you can just multiply that by clockRate and cast back to uint32 I think. Something like
return uint32(float64(clockRate) * d.Seconds())
There was a problem hiding this comment.
May need bounds check though of < 0 or > something which will actually overflow uint32. I don't think there is great handling for greater than uint32 other than just let it wrap. So, maybe something like
return uint32(max(0, float64(clockRate) * d.Seconds()))
There was a problem hiding this comment.
Went back and forth on this with an agent, and it pointed me to this:
In all non-constant conversions involving floating-point or complex values, if the result type cannot represent the value the conversion succeeds but the result value is implementation-dependent.
Which I think means the cast to uint32 may wrap on some arches and saturate on others if we use float64. For reference, this is the same calculation in the Rust implementation; the main difference there is Duration is guaranteed to not be negative.
| return 0, errHandlesExhausted | ||
| } | ||
| a.value++ | ||
| return trackHandle(a.value), nil |
There was a problem hiding this comment.
guessing this might be locked from outside. If not, should protect this.
There was a problem hiding this comment.
Yes, handle allocator is owned by LocalManager (defined in #991) which locks this.
| var ErrInvalidSID = errors.New("invalid data track SID") | ||
|
|
||
| // SID is the server-assigned identifier of a data track. | ||
| type SID string |
There was a problem hiding this comment.
If you want a type, can we use livekit.TrackID? I think that is what server uses for all TrackID (both media and data)
| type depacketizerDropReason int | ||
|
|
||
| const ( | ||
| dropReasonInterrupted depacketizerDropReason = iota |
There was a problem hiding this comment.
I usually do the enum prefix fully depacketizerDropReason... so that collisions are avoided just in case and also makes me think less :-)
| } | ||
|
|
||
| func (d *depacketizer) push(packet dtp.Packet, options depacketizerPushOptions) depacketizerPushResult { | ||
| switch markerOf(&packet.Header) { |
There was a problem hiding this comment.
can this method be pushed to protocol? Yeah, server does not need that, but it may at some point if it has to do sub-sampling. Also feels cleaner to have all packet utilities there.
When server needs to depacketize, this whole thing could move to protocol too, but that is later. Would be good to have all packet utilities in protocol for now.
There was a problem hiding this comment.
I agree, this is something that will likely be shared in the future. I'm assuming you're talking about the markerOf helper in particular?
There was a problem hiding this comment.
Yeah, meant markerOf. Basically, anything to do with packet. Can be unit tested there.
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| var defaultPushOptions = depacketizerPushOptions{maxPartialFrames: 1} |
There was a problem hiding this comment.
Recommend renaming this to something like testDefaultPushOptions. defaultPushOptions seems like it is in the implementation.
| supportedVersion = 0 | ||
|
|
||
| extensionIDE2EE uint8 = 1 | ||
| extensionIDUserTimestamp uint8 = 2 |
There was a problem hiding this comment.
We have to fix this for the relay stuff. Maybe, we allocate 3 (or maybe the highest number for relay and in one version, the read side has to check for both)
There was a problem hiding this comment.
And let us move these to proto definitions.
There was a problem hiding this comment.
I moved most of this to livekit/protocol in livekit/protocol#1834 (except client specific parts) and integrated in 0e0a11b. I didn't add the extension IDs to the Protobuf enum over there yet since that would require re-naming DTEI_PARTICIPANT_SID_LOW—although maybe it is time to do that now. Let me know your thoughts.
There was a problem hiding this comment.
Thank you @ladvoc . Let's wait on adding the extension IDs to the proto definition for a little bit more.
There was a problem hiding this comment.
This is now defined in protocol - livekit/protocol#1861
| return nil, errMTUTooShort | ||
| } | ||
| header.FrameNumber = p.frameNumber | ||
| p.frameNumber++ |
There was a problem hiding this comment.
guessing there is locking outside
There was a problem hiding this comment.
Correct, in #991, each local track owns a packetizer which it locks.
| msg.FrameEncoding = frameEncodingToProto(info.FrameEncoding) | ||
| } | ||
| return msg | ||
| } |
There was a problem hiding this comment.
Till this point, I think it can go into protocol. Also, feels like there may be some protobuf library to do some of this. I am not sure though.
5810844 to
0caac7c
Compare
0e0a11b to
3436ef7
Compare
For consistency with other client SDKs.
3436ef7 to
9283287
Compare
Adds core types (e.g., info, frame, schema, etc.) and packetizer/depacketizer.
Closes BOT-541