Repository navigation
Data tracks: publishing #991
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
9f56242
Add data track publish request conversions
ladvoc e859b33
Add local data track manager
ladvoc 53b2e01
Wire the local data track manager into the room
ladvoc 0a37ffb
Add LocalParticipant.PublishDataTrack
ladvoc 455fa50
Add data track publisher example
ladvoc 0f0d168
Fix handle allocator error check in Publish
ladvoc 8c07cdc
Expose public error type for handle exhaustion
ladvoc 5a1d122
Let ensurePublisherConnected give up when its context ends
ladvoc 6121020
Pass the publish context through the data track transport
ladvoc 5e18927
Drop references to Rust
ladvoc 1084300
Use cli package for example
ladvoc 7ffff3e
Use upstream E2EE extension and TrackID types in local track code
ladvoc 859d92a
Move data track implmentation to internal package
ladvoc 50338cf
Use type alias for frame packets
ladvoc ae3e8bd
Don't alias datatrack package
ladvoc fba89d6
Expose set logger for local manager
ladvoc 0bbd109
Relocate local manager to local participant
ladvoc 6d411e9
Lower bound on test timeout
ladvoc c008b83
Explicit unlock at end of test
ladvoc 89d603a
Mark data track unpublished after republish fail
ladvoc 953bf0c
Use single mutex for sync inside local manager
ladvoc d905ce7
Don't send requests after cancellation
ladvoc 81fb6a1
Note empty payloads are dropped.
ladvoc File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| // Copyright 2026 LiveKit, Inc. | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| // Package datatrack is the public API for data tracks. Publish a track with | ||
| // [github.com/livekit/server-sdk-go/v2.LocalParticipant.PublishDataTrack]. | ||
| package datatrack | ||
|
|
||
| import ( | ||
| backend "github.com/livekit/server-sdk-go/v2/internal/datatrack" | ||
| ) | ||
|
|
||
| type ( | ||
| // LocalTrack is a data track published by the local participant. | ||
| LocalTrack = backend.LocalTrack | ||
| // Info describes a published data track. | ||
| Info = backend.Info | ||
| // Frame is a frame published on a data track. | ||
| Frame = backend.Frame | ||
|
|
||
| // PublishOptions describe a data track to publish. | ||
| PublishOptions = backend.PublishOptions | ||
| // PublishOption customizes a publication. | ||
| PublishOption = backend.PublishOption | ||
|
|
||
| // SchemaID identifies a data track schema. | ||
| SchemaID = backend.SchemaID | ||
| // SchemaEncoding is the encoding of a schema definition: a WellKnownSchemaEncoding or a | ||
| // CustomSchemaEncoding. | ||
| SchemaEncoding = backend.SchemaEncoding | ||
| // WellKnownSchemaEncoding is a schema encoding defined by the protocol. | ||
| WellKnownSchemaEncoding = backend.WellKnownSchemaEncoding | ||
| // CustomSchemaEncoding is an application-defined schema encoding identified by name. | ||
| CustomSchemaEncoding = backend.CustomSchemaEncoding | ||
|
|
||
| // FrameEncoding is the encoding of frames pushed on a data track: a WellKnownFrameEncoding or | ||
| // a CustomFrameEncoding. | ||
| FrameEncoding = backend.FrameEncoding | ||
| // WellKnownFrameEncoding is a frame encoding defined by the protocol. | ||
| WellKnownFrameEncoding = backend.WellKnownFrameEncoding | ||
| // CustomFrameEncoding is an application-defined frame encoding identified by name. | ||
| CustomFrameEncoding = backend.CustomFrameEncoding | ||
| ) | ||
|
|
||
| var ( | ||
| ErrNotAllowed = backend.ErrNotAllowed | ||
| ErrDuplicateName = backend.ErrDuplicateName | ||
| ErrInvalidName = backend.ErrInvalidName | ||
| ErrLimitReached = backend.ErrLimitReached | ||
| ErrPublishTimeout = backend.ErrPublishTimeout | ||
| ErrDisconnected = backend.ErrDisconnected | ||
| ErrUnpublished = backend.ErrUnpublished | ||
| ErrQueueFull = backend.ErrQueueFull | ||
|
|
||
| ErrSchemaMissingFrameEncoding = backend.ErrSchemaMissingFrameEncoding | ||
| ErrSchemaMissingID = backend.ErrSchemaMissingID | ||
| ErrSchemaIncompatible = backend.ErrSchemaIncompatible | ||
| ) | ||
|
|
||
| const ( | ||
| // SchemaEncodingOther is a well-known encoding not known to this SDK version. | ||
| SchemaEncodingOther = backend.SchemaEncodingOther | ||
| SchemaEncodingProtobuf = backend.SchemaEncodingProtobuf | ||
| SchemaEncodingFlatbuffer = backend.SchemaEncodingFlatbuffer | ||
| SchemaEncodingROS1Msg = backend.SchemaEncodingROS1Msg | ||
| SchemaEncodingROS2Msg = backend.SchemaEncodingROS2Msg | ||
| SchemaEncodingROS2IDL = backend.SchemaEncodingROS2IDL | ||
| SchemaEncodingOMGIDL = backend.SchemaEncodingOMGIDL | ||
| SchemaEncodingJSONSchema = backend.SchemaEncodingJSONSchema | ||
| ) | ||
|
|
||
| const ( | ||
| // FrameEncodingOther is a well-known encoding not known to this SDK version. | ||
| FrameEncodingOther = backend.FrameEncodingOther | ||
| FrameEncodingROS1 = backend.FrameEncodingROS1 | ||
| FrameEncodingCDR = backend.FrameEncodingCDR | ||
| FrameEncodingProtobuf = backend.FrameEncodingProtobuf | ||
| FrameEncodingFlatbuffer = backend.FrameEncodingFlatbuffer | ||
| FrameEncodingCBOR = backend.FrameEncodingCBOR | ||
| FrameEncodingMsgPack = backend.FrameEncodingMsgPack | ||
| FrameEncodingJSON = backend.FrameEncodingJSON | ||
| ) | ||
|
|
||
| // WithSchema associates a schema with the track's frames. | ||
| func WithSchema(schema SchemaID) PublishOption { | ||
| return backend.WithSchema(schema) | ||
| } | ||
|
|
||
| // WithFrameEncoding declares the encoding of the track's frames. | ||
| func WithFrameEncoding(encoding FrameEncoding) PublishOption { | ||
| return backend.WithFrameEncoding(encoding) | ||
| } | ||
|
|
||
| // UserTimestampNow returns the current Unix time in milliseconds, the interpretation | ||
| // Frame.DurationSinceTimestamp expects. | ||
| func UserTimestampNow() *uint64 { | ||
| return backend.UserTimestampNow() | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "bytes" | ||
| "context" | ||
| "fmt" | ||
| "os" | ||
| "os/signal" | ||
| "syscall" | ||
| "time" | ||
|
|
||
| "github.com/livekit/protocol/logger" | ||
| lksdk "github.com/livekit/server-sdk-go/v2" | ||
| "github.com/livekit/server-sdk-go/v2/datatrack" | ||
| "github.com/urfave/cli/v3" | ||
| ) | ||
|
|
||
| func main() { | ||
| logger.InitFromConfig(&logger.Config{Level: "info"}, "datatrack-publisher") | ||
| lksdk.SetLogger(logger.GetLogger()) | ||
|
|
||
| cmd := &cli.Command{ | ||
| Name: "datatrack-publisher", | ||
| Usage: "publish sensor data on a data track", | ||
| Flags: []cli.Flag{ | ||
| &cli.StringFlag{Name: "host", Usage: "livekit server host", Required: true, Sources: cli.EnvVars("LIVEKIT_URL")}, | ||
| &cli.StringFlag{Name: "api-key", Usage: "livekit api key", Required: true, Sources: cli.EnvVars("LIVEKIT_API_KEY")}, | ||
| &cli.StringFlag{Name: "api-secret", Usage: "livekit api secret", Required: true, Sources: cli.EnvVars("LIVEKIT_API_SECRET")}, | ||
| &cli.StringFlag{Name: "room-name", Usage: "room name", Required: true}, | ||
| &cli.StringFlag{Name: "identity", Usage: "participant identity", Value: "publisher"}, | ||
| }, | ||
| Action: run, | ||
| } | ||
|
|
||
| ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) | ||
| defer stop() | ||
| if err := cmd.Run(ctx, os.Args); err != nil { | ||
| fmt.Fprintln(os.Stderr, err) | ||
| os.Exit(1) | ||
| } | ||
| } | ||
|
|
||
| func run(ctx context.Context, cmd *cli.Command) error { | ||
| room, err := lksdk.ConnectToRoom(cmd.String("host"), lksdk.ConnectInfo{ | ||
| APIKey: cmd.String("api-key"), | ||
| APISecret: cmd.String("api-secret"), | ||
| RoomName: cmd.String("room-name"), | ||
| ParticipantIdentity: cmd.String("identity"), | ||
| }, nil) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| defer room.Disconnect() | ||
|
|
||
| track, err := room.LocalParticipant.PublishDataTrack(ctx, "my_sensor_data") | ||
| if err != nil { | ||
| return err | ||
| } | ||
| defer track.Unpublish() | ||
|
|
||
| pushFrames(ctx, track) | ||
| return nil | ||
| } | ||
|
|
||
| func readSensor() []byte { | ||
| // Dynamically read some sensor data... | ||
| return bytes.Repeat([]byte{0xfa}, 256) | ||
| } | ||
|
|
||
| func pushFrames(ctx context.Context, track *datatrack.LocalTrack) { | ||
| for { | ||
| logger.Infow("pushing frame") | ||
|
|
||
| frame := datatrack.Frame{ | ||
| Payload: readSensor(), | ||
| UserTimestamp: datatrack.UserTimestampNow(), | ||
| } | ||
| if err := track.TryPush(frame); err != nil { | ||
| logger.Warnw("failed to push frame", err) | ||
| } | ||
|
|
||
| select { | ||
| case <-ctx.Done(): | ||
| return | ||
| case <-time.After(500 * time.Millisecond): | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
File renamed without changes.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.