mirror of
https://github.com/livekit/livekit.git
synced 2026-03-31 17:35:39 +00:00
211 lines
4.2 KiB
Go
211 lines
4.2 KiB
Go
package commands
|
|
|
|
import (
|
|
"bufio"
|
|
"errors"
|
|
"fmt"
|
|
"net/url"
|
|
"os"
|
|
"os/signal"
|
|
"path/filepath"
|
|
"syscall"
|
|
|
|
"github.com/gorilla/websocket"
|
|
"github.com/manifoldco/promptui"
|
|
"github.com/pion/webrtc/v3"
|
|
"github.com/urfave/cli/v2"
|
|
|
|
"github.com/livekit/livekit-server/cmd/cli/client"
|
|
"github.com/livekit/livekit-server/pkg/logger"
|
|
)
|
|
|
|
var (
|
|
RTCCommands = []*cli.Command{
|
|
{
|
|
Name: "join",
|
|
Action: joinRoom,
|
|
Flags: []cli.Flag{
|
|
roomFlag,
|
|
rtcHostFlag,
|
|
&cli.StringFlag{
|
|
Name: "token",
|
|
Usage: "room token, not required in dev mode",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "name",
|
|
Usage: "name of participant",
|
|
Required: true,
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "audio",
|
|
Usage: "an ogg file to publish upon connection",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "video",
|
|
Usage: "an ivf file to publish upon connection",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
)
|
|
|
|
func joinRoom(c *cli.Context) error {
|
|
u, err := url.Parse(c.String("host") + "/rtc")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v := url.Values{}
|
|
v.Set("room_id", c.String("room-id"))
|
|
v.Set("token", c.String("token"))
|
|
v.Set("name", c.String("name"))
|
|
u.RawQuery = v.Encode()
|
|
|
|
log := logger.GetLogger()
|
|
|
|
log.Infow("connecting to Websocket signal", "url", u.String())
|
|
conn, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer conn.Close()
|
|
|
|
rc, err := client.NewRTCClient(conn)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
handleSignals(rc)
|
|
|
|
// add tracks if needed
|
|
audioFile := c.String("audio")
|
|
videoFile := c.String("video")
|
|
if audioFile != "" {
|
|
rc.AddTrack(audioFile, webrtc.RTPCodecTypeAudio, "audio", filepath.Base(audioFile))
|
|
}
|
|
if videoFile != "" {
|
|
rc.AddTrack(videoFile, webrtc.RTPCodecTypeVideo, "video", filepath.Base(videoFile))
|
|
}
|
|
|
|
// start loop to detect input
|
|
go func() {
|
|
for {
|
|
r := bufio.NewReader(os.Stdin)
|
|
_, _, err := r.ReadLine()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
// pause client output and wait
|
|
rc.PauseLogs()
|
|
|
|
err = handleCommand(rc)
|
|
if err != nil {
|
|
log.Errorw("could not handle command", "err", err)
|
|
}
|
|
|
|
rc.ResumeLogs()
|
|
}
|
|
}()
|
|
|
|
return rc.Run()
|
|
}
|
|
|
|
func handleCommand(rc *client.RTCClient) error {
|
|
cmdPrompt := promptui.Select{
|
|
Label: "select command",
|
|
Items: []string{
|
|
"add video",
|
|
"add audio",
|
|
//"add data",
|
|
//"send data",
|
|
"remove track",
|
|
},
|
|
}
|
|
|
|
idx, _, err := cmdPrompt.Run()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
switch idx {
|
|
case 0:
|
|
return handleAddMedia(rc, false)
|
|
case 1:
|
|
return handleAddMedia(rc, true)
|
|
default:
|
|
return errors.New("unimplemented command")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func handleAddMedia(rc *client.RTCClient, isAudio bool) error {
|
|
fileType := "vp8, h264"
|
|
codecType := webrtc.RTPCodecTypeVideo
|
|
if isAudio {
|
|
fileType = "opus"
|
|
codecType = webrtc.RTPCodecTypeAudio
|
|
}
|
|
// get media location
|
|
p := promptui.Prompt{
|
|
Label: fmt.Sprintf("media path (%s)", fileType),
|
|
Validate: func(s string) error {
|
|
s = ExpandUser(s)
|
|
// ensure it exists
|
|
st, err := os.Stat(s)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if st.IsDir() {
|
|
return errors.New("cannot be a directory")
|
|
}
|
|
return nil
|
|
},
|
|
}
|
|
|
|
mediaPath, err := p.Run()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
mediaPath = ExpandUser(mediaPath)
|
|
|
|
// TODO: see what the ID should be
|
|
err = rc.AddTrack(mediaPath, codecType, codecType.String(), filepath.Base(mediaPath))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fmt.Printf("added %s track: %s\n", codecType.String(), mediaPath)
|
|
|
|
if isAudio {
|
|
return nil
|
|
}
|
|
|
|
// for video files, also look for the .ogg at the same path
|
|
videoExt := filepath.Ext(mediaPath)
|
|
if len(videoExt) == 0 {
|
|
return nil
|
|
}
|
|
|
|
audioPath := mediaPath[0:len(mediaPath)-len(videoExt)] + ".ogg"
|
|
if _, err = os.Stat(audioPath); err == nil {
|
|
err = rc.AddTrack(audioPath, webrtc.RTPCodecTypeAudio, codecType.String(), filepath.Base(audioPath))
|
|
if err != nil {
|
|
fmt.Printf("added audio track: %s\n", audioPath)
|
|
}
|
|
}
|
|
return err
|
|
}
|
|
|
|
func handleSignals(rc *client.RTCClient) {
|
|
// signal to stop client
|
|
sigChan := make(chan os.Signal, 1)
|
|
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
|
|
|
|
go func() {
|
|
sig := <-sigChan
|
|
logger.GetLogger().Infow("exit requested, shutting down", "signal", sig)
|
|
rc.Stop()
|
|
}()
|
|
}
|