From cd1d6dcbc660f556c0d8683b6b1beba2d2e17bb4 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Wed, 18 Oct 2023 23:08:15 -0700 Subject: [PATCH] Improve create-room and join-room - updated to Go SDK 1.1.1 - added --exit-after-publish option to join-room - added --min-playout-delay and --sync-stream to create-room --- .../examples/room-composite-file.json | 18 ++-- .../examples/room-composite-stream.json | 12 +-- cmd/livekit-cli/join.go | 88 +++++++++++++------ cmd/livekit-cli/room.go | 32 ++++--- go.mod | 14 +-- go.sum | 23 ++--- 6 files changed, 118 insertions(+), 69 deletions(-) diff --git a/cmd/livekit-cli/examples/room-composite-file.json b/cmd/livekit-cli/examples/room-composite-file.json index beb151f2..706b5c9a 100644 --- a/cmd/livekit-cli/examples/room-composite-file.json +++ b/cmd/livekit-cli/examples/room-composite-file.json @@ -1,13 +1,15 @@ { "room_name": "my-room", "layout": "speaker-dark", - "file": { - "filepath": "livekit-demo/my-room-test.mp4", - "s3": { - "access_key": "aws-access-key", - "secret": "aws-access-secret", - "region": "aws-region", - "bucket": "my-bucket" + "file_outputs": [ + { + "filepath": "livekit-demo/my-room-test.mp4", + "s3": { + "access_key": "aws-access-key", + "secret": "aws-access-secret", + "region": "aws-region", + "bucket": "my-bucket" + } } - } + ] } diff --git a/cmd/livekit-cli/examples/room-composite-stream.json b/cmd/livekit-cli/examples/room-composite-stream.json index 32c74c71..a896c8c7 100644 --- a/cmd/livekit-cli/examples/room-composite-stream.json +++ b/cmd/livekit-cli/examples/room-composite-stream.json @@ -1,9 +1,11 @@ { "room_name": "my-room", "layout": "speaker-dark", - "stream": { - "urls": [ - "rtmp://live.twitch.tv/app/" - ] - } + "stream_outputs": [ + { + "urls": [ + "rtmp://live.twitch.tv/app/" + ] + } + ] } diff --git a/cmd/livekit-cli/join.go b/cmd/livekit-cli/join.go index 272522a6..8f22ec58 100644 --- a/cmd/livekit-cli/join.go +++ b/cmd/livekit-cli/join.go @@ -25,6 +25,7 @@ import ( "syscall" "time" + "github.com/pion/rtcp" "github.com/pion/webrtc/v3" "github.com/urfave/cli/v2" @@ -58,6 +59,10 @@ var ( Name: "fps", Usage: "if video files are published, indicates FPS of video", }, + &cli.BoolFlag{ + Name: "exit-after-publish", + Usage: "when publishing, exit after file or stream is complete", + }, ), }, } @@ -71,6 +76,7 @@ func joinRoom(c *cli.Context) error { return err } + done := make(chan os.Signal, 1) roomCB := &lksdk.RoomCallback{ ParticipantCallback: lksdk.ParticipantCallback{ OnDataReceived: func(data []byte, rp *lksdk.RemoteParticipant) { @@ -135,6 +141,7 @@ func joinRoom(c *cli.Context) error { }, OnDisconnected: func() { logger.Infow("disconnected from room") + close(done) }, } room, err := lksdk.ConnectToRoom(pc.URL, lksdk.ConnectInfo{ @@ -150,7 +157,6 @@ func joinRoom(c *cli.Context) error { logger.Infow("connected to room", "room", room.Name()) - done := make(chan os.Signal, 1) signal.Notify(done, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) if c.Bool("publish-demo") { @@ -162,7 +168,20 @@ func joinRoom(c *cli.Context) error { if c.StringSlice("publish") != nil { fps := c.Float64("fps") for _, pub := range c.StringSlice("publish") { - if err = handlePublish(room, pub, fps); err != nil { + var onPublishComplete func(pub *lksdk.LocalTrackPublication) + if c.Bool("exit-after-publish") { + onPublishComplete = func(pub *lksdk.LocalTrackPublication) { + if c.Bool("exit-after-publish") { + close(done) + return + } + if pub != nil { + fmt.Printf("finished writing %s\n", pub.Name()) + _ = room.LocalParticipant.UnpublishTrack(pub.SID()) + } + } + } + if err = handlePublish(room, pub, fps, onPublishComplete); err != nil { return err } } @@ -172,17 +191,19 @@ func joinRoom(c *cli.Context) error { return nil } -func handlePublish(room *lksdk.Room, name string, fps float64) error { - // See if we're dealing with a socket +func handlePublish(room *lksdk.Room, + name string, + fps float64, + onPublishComplete func(pub *lksdk.LocalTrackPublication), +) error { if isSocketFormat(name) { mimeType, socketType, address, err := parseSocketFromName(name) if err != nil { return err } - return publishSocket(room, mimeType, socketType, address, fps) + return publishSocket(room, mimeType, socketType, address, fps, onPublishComplete) } - // Else, handle file - return publishFile(room, name, fps) + return publishFile(room, name, fps, onPublishComplete) } func publishDemo(room *lksdk.Room) error { @@ -211,17 +232,26 @@ func publishDemo(room *lksdk.Room) error { return err } -func publishFile(room *lksdk.Room, filename string, fps float64) error { +func publishFile(room *lksdk.Room, + filename string, + fps float64, + onPublishComplete func(pub *lksdk.LocalTrackPublication), +) error { // Configure provider - var pub *lksdk.LocalTrackPublication opts := []lksdk.ReaderSampleProviderOption{ - lksdk.ReaderTrackWithOnWriteComplete(func() { - fmt.Println("finished writing file", filename) - if pub != nil { - _ = room.LocalParticipant.UnpublishTrack(pub.SID()) + lksdk.ReaderTrackWithRTCPHandler(func(packet rtcp.Packet) { + switch packet.(type) { + case *rtcp.PictureLossIndication: + logger.Infow("received PLI", "filename", filename) } }), } + var pub *lksdk.LocalTrackPublication + if onPublishComplete != nil { + opts = append(opts, lksdk.ReaderTrackWithOnWriteComplete(func() { + onPublishComplete(pub) + })) + } // Set frame rate if it's a video stream and FPS is set ext := filepath.Ext(filename) @@ -277,7 +307,13 @@ func isSocketFormat(name string) bool { return strings.Contains(name, mimeDelimiter) } -func publishSocket(room *lksdk.Room, mimeType string, socketType string, address string, fps float64) error { +func publishSocket(room *lksdk.Room, + mimeType string, + socketType string, + address string, + fps float64, + onPublishComplete func(pub *lksdk.LocalTrackPublication), +) error { var mime string switch { case strings.Contains(mimeType, "h264"): @@ -297,25 +333,27 @@ func publishSocket(room *lksdk.Room, mimeType string, socketType string, address } // Publish to room - err = publishReader(room, sock, mime, fps) + err = publishReader(room, sock, mime, fps, onPublishComplete) return err } -func publishReader(room *lksdk.Room, in io.ReadCloser, mime string, fps float64) error { +func publishReader(room *lksdk.Room, + in io.ReadCloser, + mime string, + fps float64, + onPublishComplete func(pub *lksdk.LocalTrackPublication), +) error { // Configure provider + var opts []lksdk.ReaderSampleProviderOption var pub *lksdk.LocalTrackPublication - opts := []lksdk.ReaderSampleProviderOption{ - lksdk.ReaderTrackWithOnWriteComplete(func() { - fmt.Printf("finished writing %s stream\n", mime) - if pub != nil { - _ = room.LocalParticipant.UnpublishTrack(pub.SID()) - } - }), + if onPublishComplete != nil { + opts = append(opts, lksdk.ReaderTrackWithOnWriteComplete(func() { + onPublishComplete(pub) + })) } // Set frame rate if it's a video stream and FPS is set - if strings.EqualFold(mime, webrtc.MimeTypeVP8) || - strings.EqualFold(mime, webrtc.MimeTypeH264) { + if strings.HasPrefix(strings.ToLower(mime), "video") { if fps != 0 { frameDuration := time.Second / time.Duration(fps) opts = append(opts, lksdk.ReaderTrackWithFrameDuration(frameDuration)) diff --git a/cmd/livekit-cli/room.go b/cmd/livekit-cli/room.go index a7eedd06..4285e970 100644 --- a/cmd/livekit-cli/room.go +++ b/cmd/livekit-cli/room.go @@ -43,19 +43,24 @@ var ( Required: true, }, &cli.StringFlag{ - Name: "room-egress-file", - Usage: "RoomCompositeRequest json file (see examples/room-composite-file.json)", - Required: false, + Name: "room-egress-file", + Usage: "RoomCompositeRequest json file (see examples/room-composite-file.json)", }, &cli.StringFlag{ - Name: "track-egress-file", - Usage: "AutoTrackEgress json file (see examples/auto-track-egress.json)", - Required: false, + Name: "participant-egress-file", + Usage: "ParticipantEgress json file (see examples/auto-participant-egress.json)", + }, + &cli.StringFlag{ + Name: "track-egress-file", + Usage: "AutoTrackEgress json file (see examples/auto-track-egress.json)", }, &cli.UintFlag{ - Name: "min-playout-delay", - Usage: "minimum playout delay", - Required: false, + Name: "min-playout-delay", + Usage: "minimum playout delay for video (in ms), unsupported for audio", + }, + &cli.BoolFlag{ + Name: "sync-streams", + Usage: "improve A/V sync by placing them in the same stream. when enabled, transceivers will not be reused", }, ), }, @@ -254,6 +259,11 @@ func createRoom(c *cli.Context) error { req.MinPlayoutDelay = uint32(c.Uint("min-playout-delay")) } + if syncStreams := c.Bool("sync-streams"); syncStreams { + fmt.Printf("setting sync streams: %t\n", syncStreams) + req.SyncStreams = syncStreams + } + room, err := roomClient.CreateRoom(context.Background(), req) if err != nil { return err @@ -290,10 +300,6 @@ func listRoom(c *cli.Context) error { } rm := res.Rooms[0] PrintJSON(rm) - playoutDelay := rm.GetPlayoutDelay() - if playoutDelay != nil { - fmt.Printf("playout delay: %s\n", playoutDelay.String()) - } return nil } diff --git a/go.mod b/go.mod index 3bb21a24..94a30a74 100644 --- a/go.mod +++ b/go.mod @@ -6,12 +6,13 @@ require ( github.com/frostbyte73/core v0.0.9 github.com/ggwhite/go-masker v1.0.9 github.com/go-logr/logr v1.2.4 - github.com/livekit/protocol v1.7.2 - github.com/livekit/server-sdk-go v1.0.17-0.20230918212012-3a26309be9c5 + github.com/livekit/protocol v1.8.0 + github.com/livekit/server-sdk-go v1.1.1 github.com/manifoldco/promptui v0.9.0 github.com/olekukonko/tablewriter v0.0.5 - github.com/pion/rtp v1.8.1 - github.com/pion/webrtc/v3 v3.2.20 + github.com/pion/rtcp v1.2.10 + github.com/pion/rtp v1.8.2 + github.com/pion/webrtc/v3 v3.2.21 github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.8.4 @@ -43,7 +44,7 @@ require ( github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/lithammer/shortuuid/v4 v4.0.0 // indirect github.com/livekit/mageutil v0.0.0-20230125210925-54e8a70427c1 // indirect - github.com/livekit/mediatransportutil v0.0.0-20230906055425-e81fd5f6fb3f // indirect + github.com/livekit/mediatransportutil v0.0.0-20231017082622-43f077b4e60e // indirect github.com/livekit/psrpc v0.3.3 // indirect github.com/mackerelio/go-osstat v0.2.4 // indirect github.com/magefile/mage v1.15.0 // indirect @@ -55,11 +56,10 @@ require ( github.com/pion/datachannel v1.5.5 // indirect github.com/pion/dtls/v2 v2.2.7 // indirect github.com/pion/ice/v2 v2.3.11 // indirect - github.com/pion/interceptor v0.1.19 // indirect + github.com/pion/interceptor v0.1.21 // indirect github.com/pion/logging v0.2.2 // indirect github.com/pion/mdns v0.0.9 // indirect github.com/pion/randutil v0.1.0 // indirect - github.com/pion/rtcp v1.2.10 // indirect github.com/pion/sctp v1.8.9 // indirect github.com/pion/sdp/v3 v3.0.6 // indirect github.com/pion/srtp/v2 v2.0.17 // indirect diff --git a/go.sum b/go.sum index 0d67610b..150e271d 100644 --- a/go.sum +++ b/go.sum @@ -78,14 +78,14 @@ github.com/lithammer/shortuuid/v4 v4.0.0 h1:QRbbVkfgNippHOS8PXDkti4NaWeyYfcBTHtw github.com/lithammer/shortuuid/v4 v4.0.0/go.mod h1:Zs8puNcrvf2rV9rTH51ZLLcj7ZXqQI3lv67aw4KiB1Y= github.com/livekit/mageutil v0.0.0-20230125210925-54e8a70427c1 h1:jm09419p0lqTkDaKb5iXdynYrzB84ErPPO4LbRASk58= github.com/livekit/mageutil v0.0.0-20230125210925-54e8a70427c1/go.mod h1:Rs3MhFwutWhGwmY1VQsygw28z5bWcnEYmS1OG9OxjOQ= -github.com/livekit/mediatransportutil v0.0.0-20230906055425-e81fd5f6fb3f h1:b4ri7hQESRSzJWzXXcmANG2hJ4HTj5LM01Ekm8lnQmg= -github.com/livekit/mediatransportutil v0.0.0-20230906055425-e81fd5f6fb3f/go.mod h1:+WIOYwiBMive5T81V8B2wdAc2zQNRjNQiJIcPxMTILY= -github.com/livekit/protocol v1.7.2 h1:TPk8rIv5ZZSx1IU5jaGA2W+RdoDlE8dp4CFHE0MKoGo= -github.com/livekit/protocol v1.7.2/go.mod h1:zbh0QPUcLGOeZeIO/VeigwWWbudz4Lv+Px94FnVfQH0= +github.com/livekit/mediatransportutil v0.0.0-20231017082622-43f077b4e60e h1:yNeIo7MSMUWgoLu7LkNKnBYnJBFPFH9Wq4S6h1kS44M= +github.com/livekit/mediatransportutil v0.0.0-20231017082622-43f077b4e60e/go.mod h1:+WIOYwiBMive5T81V8B2wdAc2zQNRjNQiJIcPxMTILY= +github.com/livekit/protocol v1.8.0 h1:0z2eRmEXFFXiJ7WPAxRLMNCyUu55w41iikbbeT8dvlQ= +github.com/livekit/protocol v1.8.0/go.mod h1:zbh0QPUcLGOeZeIO/VeigwWWbudz4Lv+Px94FnVfQH0= github.com/livekit/psrpc v0.3.3 h1:+lltbuN39IdaynXhLLxRShgYqYsRMWeeXKzv60oqyWo= github.com/livekit/psrpc v0.3.3/go.mod h1:n6JntEg+zT6Ji8InoyTpV7wusPNwGqqtxmHlkNhDN0U= -github.com/livekit/server-sdk-go v1.0.17-0.20230918212012-3a26309be9c5 h1:JZttHKxyzGFuMpsl3Mmt84WU+DZsZg00FCOPfr6CmBY= -github.com/livekit/server-sdk-go v1.0.17-0.20230918212012-3a26309be9c5/go.mod h1:hx8+3zlGcKAmQFUOnmHA1kY4mi67W8L0dp/OrNGt3mc= +github.com/livekit/server-sdk-go v1.1.1 h1:TkDD/Ecyh7XNuxgxhpsDQ1uzbTlDWwwJrbkyUjQmcbY= +github.com/livekit/server-sdk-go v1.1.1/go.mod h1:724BcsVjpsQu8zK9VX2TfdEWt+DtsBeT3EnMrDbyT3I= github.com/mackerelio/go-osstat v0.2.4 h1:qxGbdPkFo65PXOb/F/nhDKpF2nGmGaCFDLXoZjJTtUs= github.com/mackerelio/go-osstat v0.2.4/go.mod h1:Zy+qzGdZs3A9cuIqmgbJvwbmLQH9dJvtio5ZjJTbdlQ= github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg= @@ -123,8 +123,8 @@ github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ github.com/pion/ice/v2 v2.3.11 h1:rZjVmUwyT55cmN8ySMpL7rsS8KYsJERsrxJLLxpKhdw= github.com/pion/ice/v2 v2.3.11/go.mod h1:hPcLC3kxMa+JGRzMHqQzjoSj3xtE9F+eoncmXLlCL4E= github.com/pion/interceptor v0.1.18/go.mod h1:tpvvF4cPM6NGxFA1DUMbhabzQBxdWMATDGEUYOR9x6I= -github.com/pion/interceptor v0.1.19 h1:tq0TGBzuZQqipyBhaC1mVUCfCh8XjDKUuibq9rIl5t4= -github.com/pion/interceptor v0.1.19/go.mod h1:VANhFxdJezB8mwToMMmrmyHyP9gym6xLqIUch31xryg= +github.com/pion/interceptor v0.1.21 h1:owpNzUHITYK5IqP83LoPECO5Rq6uK4io7dGUx1SQJoo= +github.com/pion/interceptor v0.1.21/go.mod h1:wkbPYAak5zKsfpVDYMtEfWEy8D4zL+rpxCxPImLOg3Y= github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= github.com/pion/mdns v0.0.8/go.mod h1:hYE72WX8WDveIhg7fmXgMKivD3Puklk0Ymzog0lSyaI= @@ -134,8 +134,9 @@ github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= github.com/pion/rtcp v1.2.10 h1:nkr3uj+8Sp97zyItdN60tE/S6vk4al5CPRR6Gejsdjc= github.com/pion/rtcp v1.2.10/go.mod h1:ztfEwXZNLGyF1oQDttz/ZKIBaeeg/oWbRYqzBM9TL1I= -github.com/pion/rtp v1.8.1 h1:26OxTc6lKg/qLSGir5agLyj0QKaOv8OP5wps2SFnVNQ= github.com/pion/rtp v1.8.1/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= +github.com/pion/rtp v1.8.2 h1:oKMM0K1/QYQ5b5qH+ikqDSZRipP5mIxPJcgcvw5sH0w= +github.com/pion/rtp v1.8.2/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= github.com/pion/sctp v1.8.5/go.mod h1:SUFFfDpViyKejTAdwD1d/HQsCu+V/40cCs2nZIvC3s0= github.com/pion/sctp v1.8.8/go.mod h1:igF9nZBrjh5AtmKc7U30jXltsFHicFCXSmWA2GWRaWs= github.com/pion/sctp v1.8.9 h1:TP5ZVxV5J7rz7uZmbyvnUvsn7EJ2x/5q9uhsTtXbI3g= @@ -157,8 +158,8 @@ github.com/pion/transport/v3 v3.0.1 h1:gDTlPJwROfSfz6QfSi0ZmeCSkFcnWWiiR9ES0ouAN github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= github.com/pion/turn/v2 v2.1.3 h1:pYxTVWG2gpC97opdRc5IGsQ1lJ9O/IlNhkzj7MMrGAA= github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= -github.com/pion/webrtc/v3 v3.2.20 h1:BQJiXQsJq9LgLp3op7rLy1y8d2WD+LtiS9cpY0uQ22A= -github.com/pion/webrtc/v3 v3.2.20/go.mod h1:vVURQTBOG5BpWKOJz3nlr23NfTDeyKVmubRNqzQp+Tg= +github.com/pion/webrtc/v3 v3.2.21 h1:c8fy5JcqJkAQBwwy3Sk9huQLTBUSqaggyRlv9Lnh2zY= +github.com/pion/webrtc/v3 v3.2.21/go.mod h1:vVURQTBOG5BpWKOJz3nlr23NfTDeyKVmubRNqzQp+Tg= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=