diff --git a/cmd/cli/client/client.go b/cmd/cli/client/client.go index 9917153c2..aeb88c0d4 100644 --- a/cmd/cli/client/client.go +++ b/cmd/cli/client/client.go @@ -12,13 +12,11 @@ import ( "github.com/gorilla/websocket" "github.com/pion/webrtc/v3" - "github.com/pkg/errors" "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" "github.com/livekit/livekit-server/pkg/logger" "github.com/livekit/livekit-server/pkg/rtc" - "github.com/livekit/livekit-server/pkg/rtc/types" "github.com/livekit/livekit-server/proto/livekit" ) @@ -39,6 +37,7 @@ type RTCClient struct { // pending actions to start after connected to peer pendingCandidates []*webrtc.ICECandidate pendingTrackWriters []*TrackWriter + OnConnected func() // navigate log ring buffer. saving the last N entries writer *ring.Ring @@ -78,9 +77,10 @@ func NewRTCClient(conn *websocket.Conn) (*RTCClient, error) { reader: logRing, writer: logRing, PeerConn: peerConn, + me: &webrtc.MediaEngine{}, } c.ctx, c.cancel = context.WithCancel(context.Background()) - + c.me.RegisterDefaultCodecs() peerConn.OnICECandidate(func(ic *webrtc.ICECandidate) { if ic == nil { return @@ -102,24 +102,14 @@ func NewRTCClient(conn *websocket.Conn) (*RTCClient, error) { peerConn.OnTrack(func(track *webrtc.TrackRemote, rtpReceiver *webrtc.RTPReceiver) { c.AppendLog("track received", "label", track.StreamID(), "id", track.ID()) - r := rtc.NewReceiver(nil, rtpReceiver, track) - c.lock.Lock() - c.receivers = append(c.receivers, r) - go c.consumeReceiver(track.ID(), r) - c.lock.Unlock() + go c.consumeReceiver(track) }) peerConn.OnNegotiationNeeded(func() { - // do nothing - //c.AppendLog("negotiate needed") - //if !c.connected { - // c.AppendLog("not yet connected, skipping negotiate") - // return - //} - //err := c.Negotiate() - //if err != nil { - // c.AppendLog("error negotiating", "err", err) - //} + if !c.iceConnected { + return + } + c.requestNegotiation() }) peerConn.OnDataChannel(func(channel *webrtc.DataChannel) { @@ -137,8 +127,13 @@ func NewRTCClient(conn *websocket.Conn) (*RTCClient, error) { } } + initialConnect := !c.iceConnected c.pendingTrackWriters = nil c.iceConnected = true + + if initialConnect && c.OnConnected != nil { + go c.OnConnected() + } } }) @@ -157,7 +152,7 @@ func (c *RTCClient) Run() error { }) // create a data channel, in order to work - dc, err := c.PeerConn.CreateDataChannel("default", nil) + dc, err := c.PeerConn.CreateDataChannel("_private", nil) if err != nil { return err } @@ -204,21 +199,7 @@ func (c *RTCClient) Run() error { defer c.PeerConn.Close() case *livekit.SignalResponse_Answer: - c.AppendLog("connected to remote, setting desc") - // remote answered the offer, establish connection - err = c.PeerConn.SetRemoteDescription(rtc.FromProtoSessionDescription(msg.Answer)) - if err != nil { - return err - } - c.connected = true - - // add all the pending items - c.lock.Lock() - for _, ic := range c.pendingCandidates { - c.SendIceCandidate(ic) - } - c.pendingCandidates = nil - c.lock.Unlock() + c.handleAnswer(rtc.FromProtoSessionDescription(msg.Answer)) case *livekit.SignalResponse_Offer: c.AppendLog("received server offer", "type", msg.Offer.Type) @@ -226,6 +207,8 @@ func (c *RTCClient) Run() error { if err := c.handleOffer(desc); err != nil { return err } + case *livekit.SignalResponse_Negotiate: + c.negotiate() case *livekit.SignalResponse_Trickle: candidateInit := rtc.FromProtoTrickle(msg.Trickle) c.AppendLog("adding remote candidate", "candidate", candidateInit.Candidate) @@ -314,39 +297,6 @@ func (c *RTCClient) SendIceCandidate(ic *webrtc.ICECandidate) error { }) } -func (c *RTCClient) handleOffer(desc webrtc.SessionDescription) error { - // always set remote description for both offer and answer - if err := c.PeerConn.SetRemoteDescription(desc); err != nil { - return err - } - - // if we received an offer, we'd have to answer - if desc.Type == webrtc.SDPTypeOffer { - // create media engine - c.me = &webrtc.MediaEngine{} - if err := c.me.RegisterDefaultCodecs(); err != nil { - return errors.Wrapf(err, "could not parse SDP") - } - - answer, err := c.PeerConn.CreateAnswer(nil) - if err != nil { - return err - } - - if err := c.PeerConn.SetLocalDescription(answer); err != nil { - return err - } - - // send remote an answer - return c.SendRequest(&livekit.SignalRequest{ - Message: &livekit.SignalRequest_Answer{ - Answer: rtc.ToProtoSessionDescription(answer), - }, - }) - } - return nil -} - func (c *RTCClient) AddTrack(path string, id string, label string) error { // determine file mime mime, ok := extMimeMapping[filepath.Ext(path)] @@ -354,7 +304,7 @@ func (c *RTCClient) AddTrack(path string, id string, label string) error { return fmt.Errorf("%s has an unsupported extension", filepath.Base(path)) } - logger.GetLogger().Infow("adding track", + c.AppendLog("adding track", "mime", mime, ) @@ -367,6 +317,15 @@ func (c *RTCClient) AddTrack(path string, id string, label string) error { return err } + trackType := livekit.TrackType_AUDIO + if strings.HasPrefix(mime, "video") { + trackType = livekit.TrackType_VIDEO + } + + if err := c.SendAddTrack(id, label, trackType); err != nil { + return err + } + c.lock.Lock() defer c.lock.Unlock() c.localTracks = append(c.localTracks, track) @@ -385,12 +344,7 @@ func (c *RTCClient) AddTrack(path string, id string, label string) error { return nil } - trackType := livekit.TrackType_AUDIO - if strings.HasPrefix(mime, "video") { - trackType = livekit.TrackType_VIDEO - } - - return c.SendAddTrack(id, label, trackType) + return nil } // send AddTrack command to server to initiate server-side negotiation @@ -406,6 +360,80 @@ func (c *RTCClient) SendAddTrack(cid string, name string, trackType livekit.Trac }) } +func (c *RTCClient) handleOffer(desc webrtc.SessionDescription) error { + // always set remote description for both offer and answer + if err := c.PeerConn.SetRemoteDescription(desc); err != nil { + return err + } + + // if we received an offer, we'd have to answer + answer, err := c.PeerConn.CreateAnswer(nil) + if err != nil { + return err + } + + if err := c.PeerConn.SetLocalDescription(answer); err != nil { + return err + } + + // send remote an answer + c.AppendLog("sending answer") + return c.SendRequest(&livekit.SignalRequest{ + Message: &livekit.SignalRequest_Answer{ + Answer: rtc.ToProtoSessionDescription(answer), + }, + }) +} + +func (c *RTCClient) handleAnswer(desc webrtc.SessionDescription) error { + c.AppendLog("handling server answer") + // remote answered the offer, establish connection + err := c.PeerConn.SetRemoteDescription(desc) + if err != nil { + return err + } + + if !c.connected { + c.connected = true + + // add all the pending items + c.lock.Lock() + for _, ic := range c.pendingCandidates { + c.SendIceCandidate(ic) + } + c.pendingCandidates = nil + c.lock.Unlock() + } + return nil +} + +func (c *RTCClient) requestNegotiation() error { + c.AppendLog("requesting negotiation") + return c.SendRequest(&livekit.SignalRequest{ + Message: &livekit.SignalRequest_Negotiate{ + Negotiate: &livekit.NegotiationRequest{}, + }, + }) +} + +func (c *RTCClient) negotiate() error { + c.AppendLog("starting negotiation") + offer, err := c.PeerConn.CreateOffer(nil) + if err != nil { + return err + } + + if err := c.PeerConn.SetLocalDescription(offer); err != nil { + return err + } + + return c.SendRequest(&livekit.SignalRequest{ + Message: &livekit.SignalRequest_Offer{ + Offer: rtc.ToProtoSessionDescription(offer), + }, + }) +} + type logEntry struct { msg string args []interface{} @@ -443,11 +471,22 @@ func (c *RTCClient) logLoop() { } } -func (c *RTCClient) consumeReceiver(trackId string, r types.Receiver) { +func (c *RTCClient) consumeReceiver(track *webrtc.TrackRemote) { lastUpdate := time.Time{} - peerId, trackId := rtc.UnpackTrackId(trackId) + peerId, trackId := rtc.UnpackTrackId(track.ID()) numBytes := 0 - for pkt := range r.RTPChan() { + for { + pkt, _, err := track.ReadRTP() + if c.ctx.Err() != nil { + break + } + if rtc.IsEOF(err) { + break + } + if err != nil { + c.AppendLog("error reading RTP", "err", err) + continue + } numBytes += pkt.MarshalSize() if time.Now().Sub(lastUpdate) > 30*time.Second { c.AppendLog("consumed from peer", @@ -455,9 +494,5 @@ func (c *RTCClient) consumeReceiver(trackId string, r types.Receiver) { "size", numBytes) lastUpdate = time.Now() } - - if c.ctx.Err() != nil { - return - } } } diff --git a/cmd/cli/commands/rtc.go b/cmd/cli/commands/rtc.go index 2dce65861..2b24737fe 100644 --- a/cmd/cli/commands/rtc.go +++ b/cmd/cli/commands/rtc.go @@ -112,11 +112,14 @@ func joinRoom(c *cli.Context) error { // add tracks if needed audioFile := c.String("audio") videoFile := c.String("video") - if audioFile != "" { - rc.AddTrack(audioFile, "audio", filepath.Base(audioFile)) - } - if videoFile != "" { - rc.AddTrack(videoFile, "video", filepath.Base(videoFile)) + rc.OnConnected = func() { + // add after connection, since we need proper publish track APIs + if audioFile != "" { + rc.AddTrack(audioFile, "audio", filepath.Base(audioFile)) + } + if videoFile != "" { + rc.AddTrack(videoFile, "video", filepath.Base(videoFile)) + } } // start loop to detect input diff --git a/cmd/cli/commands/token.go b/cmd/cli/commands/token.go index 3740db6c4..b0f9c3cc5 100644 --- a/cmd/cli/commands/token.go +++ b/cmd/cli/commands/token.go @@ -35,6 +35,7 @@ var ( Aliases: []string{"r"}, Usage: "name of the room to join, empty to allow joining all rooms", }, + devFlag, }, }, } diff --git a/cmd/cli/commands/utils.go b/cmd/cli/commands/utils.go index 47d70d706..de0e618b9 100644 --- a/cmd/cli/commands/utils.go +++ b/cmd/cli/commands/utils.go @@ -36,6 +36,10 @@ var ( EnvVars: []string{"LK_API_SECRET"}, Required: true, } + devFlag = &cli.BoolFlag{ + Name: "dev", + Usage: "enables dev mode, longer expiration for tokens", + } ) func PrintJSON(obj interface{}) { @@ -60,9 +64,14 @@ func accessToken(c *cli.Context, grant *auth.VideoGrant, identity string) (value return } + isDev := c.Bool("dev") + at := auth.NewAccessToken(apiKey, apiSecret). AddGrant(grant). - SetIdentity(identity). - SetValidFor(time.Hour * 24) + SetIdentity(identity) + if isDev { + fmt.Println("creating dev token") + at.SetValidFor(time.Hour * 24 * 30) + } return at.ToJWT() } diff --git a/go.mod b/go.mod index ef49512a2..9b6f9b278 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/manifoldco/promptui v0.8.0 github.com/maxbrunsfeld/counterfeiter/v6 v6.3.0 github.com/pion/ion-log v1.0.0 - github.com/pion/ion-sfu v1.7.2 + github.com/pion/ion-sfu v1.7.7 github.com/pion/rtcp v1.2.6 github.com/pion/rtp v1.6.2 github.com/pion/stun v0.3.5 diff --git a/go.sum b/go.sum index b6eccdee4..379e78a28 100644 --- a/go.sum +++ b/go.sum @@ -316,6 +316,8 @@ github.com/pion/ion-log v1.0.0 h1:2lJLImCmfCWCR38hLWsjQfBWe6NFz/htbqiYHwvOP/Q= github.com/pion/ion-log v1.0.0/go.mod h1:jwcla9KoB9bB/4FxYDSRJPcPYSLp5XiUUMnOLaqwl4E= github.com/pion/ion-sfu v1.7.2 h1:jW59IxIQtcGotK/BYlTqOF1Vsp/UqM4BoRD6MMnYw1Y= github.com/pion/ion-sfu v1.7.2/go.mod h1:61HfTCWVx6rTpYCc7kmvnTToEpyBoMwDhOyvMiUtNhk= +github.com/pion/ion-sfu v1.7.7 h1:qbBOsUJrU8ZlFUC8Gmz8P3FBfZ5rzr6X/FErt87dioA= +github.com/pion/ion-sfu v1.7.7/go.mod h1:D6Qnd7GHbYiRI1ye5a1IHst6cbbATawCb8fDs0oLxEI= 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.4 h1:O4vvVqr4DGX63vzmO6Fw9vpy3lfztVWHGCQfyw0ZLSY= diff --git a/pkg/auth/accesstoken.go b/pkg/auth/accesstoken.go index 888418810..616693dfd 100644 --- a/pkg/auth/accesstoken.go +++ b/pkg/auth/accesstoken.go @@ -55,7 +55,7 @@ func (t *AccessToken) ToJWT() (string, error) { validFor := defaultValidDuration if t.validFor > 0 { - t.validFor = validFor + validFor = t.validFor } cl := jwt.Claims{ diff --git a/pkg/config/config.go b/pkg/config/config.go index 3631c8283..3e4c3e012 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -21,7 +21,7 @@ type RTCConfig struct { StunServers []string `yaml:"stun_servers"` UseExternalIP bool `yaml:"use_external_ip"` - MaxBandwidth uint64 `yaml:"max_bandwidth"` + MaxBitrate uint64 `yaml:"max_bandwidth"` MaxBufferTime int `yaml:"max_buffer_time"` } diff --git a/pkg/rtc/config.go b/pkg/rtc/config.go index a8c7a16b9..a1c64be44 100644 --- a/pkg/rtc/config.go +++ b/pkg/rtc/config.go @@ -11,12 +11,11 @@ import ( type WebRTCConfig struct { Configuration webrtc.Configuration SettingEngine webrtc.SettingEngine - - receiver ReceiverConfig + Receiver ReceiverConfig } type ReceiverConfig struct { - maxBandwidth uint64 + maxBitrate uint64 maxBufferTime int } @@ -48,8 +47,8 @@ func NewWebRTCConfig(conf *config.RTCConfig, externalIP string) (*WebRTCConfig, return &WebRTCConfig{ Configuration: c, SettingEngine: s, - receiver: ReceiverConfig{ - maxBandwidth: conf.MaxBandwidth, + Receiver: ReceiverConfig{ + maxBitrate: conf.MaxBitrate, maxBufferTime: conf.MaxBufferTime, }, }, nil diff --git a/pkg/rtc/datatrack.go b/pkg/rtc/datatrack.go index 2777cfbe0..4bde3e56e 100644 --- a/pkg/rtc/datatrack.go +++ b/pkg/rtc/datatrack.go @@ -7,7 +7,6 @@ import ( "github.com/livekit/livekit-server/pkg/logger" "github.com/livekit/livekit-server/pkg/rtc/types" - "github.com/livekit/livekit-server/pkg/utils" "github.com/livekit/livekit-server/proto/livekit" ) @@ -30,10 +29,10 @@ type DataTrack struct { subscribers map[string]*DownDataChannel } -func NewDataTrack(participantId string, dc *webrtc.DataChannel) *DataTrack { +func NewDataTrack(trackId, participantId string, dc *webrtc.DataChannel) *DataTrack { t := &DataTrack{ //ctx: context.Background(), - id: utils.NewGuid(utils.TrackPrefix), + id: trackId, name: dc.Label(), participantId: participantId, dataChannel: dc, diff --git a/pkg/rtc/errors.go b/pkg/rtc/errors.go index 829b0f1cf..4dd4e946b 100644 --- a/pkg/rtc/errors.go +++ b/pkg/rtc/errors.go @@ -3,9 +3,10 @@ package rtc import "errors" var ( - ErrRoomIdMissing = errors.New("room is not passed in") - ErrInvalidRoomName = errors.New("room must have a unique name") - ErrRoomNotFound = errors.New("requested room does not exist") - ErrPermissionDenied = errors.New("no permissions to access the room") - ErrUnexpectedOffer = errors.New("expected answer SDP, received offer") + ErrRoomIdMissing = errors.New("room is not passed in") + ErrInvalidRoomName = errors.New("room must have a unique name") + ErrRoomNotFound = errors.New("requested room does not exist") + ErrPermissionDenied = errors.New("no permissions to access the room") + ErrUnexpectedOffer = errors.New("expected answer SDP, received offer") + ErrUnexpectedNegotiation = errors.New("client negotiation has not been granted") ) diff --git a/pkg/rtc/mediatrack.go b/pkg/rtc/mediatrack.go index e49c6e6c4..5169e29cc 100644 --- a/pkg/rtc/mediatrack.go +++ b/pkg/rtc/mediatrack.go @@ -16,7 +16,6 @@ import ( "github.com/livekit/livekit-server/pkg/logger" "github.com/livekit/livekit-server/pkg/rtc/types" "github.com/livekit/livekit-server/pkg/sfu" - "github.com/livekit/livekit-server/pkg/utils" "github.com/livekit/livekit-server/proto/livekit" ) @@ -54,10 +53,10 @@ type MediaTrack struct { lastPLI time.Time } -func NewMediaTrack(pId string, rtcpCh chan []rtcp.Packet, track *webrtc.TrackRemote, receiver types.Receiver) *MediaTrack { +func NewMediaTrack(trackId string, pId string, rtcpCh chan []rtcp.Packet, track *webrtc.TrackRemote, receiver types.Receiver) *MediaTrack { t := &MediaTrack{ ctx: context.Background(), - id: utils.NewGuid(utils.TrackPrefix), + id: trackId, participantId: pId, ssrc: track.SSRC(), name: track.StreamID(), @@ -135,7 +134,7 @@ func (t *MediaTrack) AddSubscriber(participant types.Participant) error { t.handleRTCP(outTrack, pkt) }) } - //go sub.sendStreamDownTracksReports(recv.Name()) + //go t.scheduleDownTrackBindingReports(recv.Name()) }) outTrack.OnCloseHandler(func() { t.lock.Lock() @@ -188,26 +187,69 @@ func (t *MediaTrack) RemoveAllSubscribers() { t.downtracks = make(map[string]types.DownTrack) } -// forwardRTPWorker reads from the receiver and writes to each sender +//func (t *MediaTrack) scheduleDownTrackBindingReports(streamId string) { +// var sd []rtcp.SourceDescriptionChunk +// +// p.lock.RLock() +// dts := p.subscribedTracks[streamId] +// for _, dt := range dts { +// if !dt.IsBound() { +// continue +// } +// chunks := dt.CreateSourceDescriptionChunks() +// if chunks != nil { +// sd = append(sd, chunks...) +// } +// } +// p.lock.RUnlock() +// +// pkts := []rtcp.Packet{ +// &rtcp.SourceDescription{Chunks: sd}, +// } +// +// go func() { +// batch := pkts +// i := 0 +// for { +// if err := p.peerConn.WriteRTCP(batch); err != nil { +// logger.GetLogger().Debugw("error sending track binding reports", +// "participant", p.id, +// "err", err) +// } +// if i > 5 { +// return +// } +// i++ +// time.Sleep(20 * time.Millisecond) +// } +// }() +//} + +// b reads from the receiver and writes to each sender func (t *MediaTrack) forwardRTPWorker() { defer func() { + logger.GetLogger().Debugw("stopping forward RTP worker") t.RemoveAllSubscribers() // TODO: send unpublished events? t.nackWorker.Stop() }() for pkt := range t.receiver.RTPChan() { + //logger.GetLogger().Debugw("read packet from remoteTrack", + // "participant", t.participantId, + // "track", t.ID()) // when track is muted, it's "disabled" on the client side, and will still be sending black frames // when our metadata is updated as such, we shortcircuit forwarding of black frames if t.muted { continue } - //logger.GetLogger().Debugw("read packet from remoteTrack", - // "participantId", t.participantId, - // "remoteTrack", t.remoteTrack.ID()) t.lock.RLock() for dstId, dt := range t.downtracks { + //logger.GetLogger().Debugw("read packet from remoteTrack", + // "srcParticipant", t.participantId, + // "destParticipant", dstId, + // "track", t.ID()) err := dt.WriteRTP(pkt) if IsEOF(err) { // this participant unsubscribed, remove it diff --git a/pkg/rtc/participant.go b/pkg/rtc/participant.go index a8c624b15..aa0f9dd4a 100644 --- a/pkg/rtc/participant.go +++ b/pkg/rtc/participant.go @@ -2,7 +2,6 @@ package rtc import ( "context" - "fmt" "io" "sync" "time" @@ -25,10 +24,17 @@ const ( negotiationFrequency = 100 * time.Millisecond ) +const ( + negotiationStateNone = iota + negotiationStateClient + negotiationStateServer +) + type ParticipantImpl struct { id string peerConn types.PeerConnection sigConn types.SignalConnection + receiverConfig ReceiverConfig ctx context.Context cancel context.CancelFunc mediaEngine *webrtc.MediaEngine @@ -39,7 +45,10 @@ type ParticipantImpl struct { // publishedTracks that participant is publishing publishedTracks map[string]types.PublishedTrack // client intended to publish, yet to be reconciled - pendingTracks map[string]*livekit.TrackInfo + pendingTracks map[string]*livekit.TrackInfo + + negotiationCond *sync.Cond + negotiationState int debouncedNegotiate func(func()) lock sync.RWMutex @@ -63,7 +72,7 @@ func NewPeerConnection(conf *WebRTCConfig) (*webrtc.PeerConnection, error) { return api.NewPeerConnection(conf.Configuration) } -func NewParticipant(pc types.PeerConnection, sc types.SignalConnection, name string) (*ParticipantImpl, error) { +func NewParticipant(pc types.PeerConnection, sc types.SignalConnection, name string, receiverConfig ReceiverConfig) (*ParticipantImpl, error) { me := &webrtc.MediaEngine{} me.RegisterDefaultCodecs() @@ -73,12 +82,14 @@ func NewParticipant(pc types.PeerConnection, sc types.SignalConnection, name str name: name, peerConn: pc, sigConn: sc, + receiverConfig: receiverConfig, ctx: ctx, cancel: cancel, rtcpCh: make(chan []rtcp.Packet, 10), subscribedTracks: make(map[string][]*sfu.DownTrack), state: livekit.ParticipantInfo_JOINING, lock: sync.RWMutex{}, + negotiationCond: sync.NewCond(&sync.Mutex{}), publishedTracks: make(map[string]types.PublishedTrack, 0), pendingTracks: make(map[string]*livekit.TrackInfo), mediaEngine: me, @@ -86,7 +97,6 @@ func NewParticipant(pc types.PeerConnection, sc types.SignalConnection, name str } log := logger.GetLogger() - pc.ConnectionState() pc.OnTrack(participant.onMediaTrack) pc.OnICECandidate(func(c *webrtc.ICECandidate) { @@ -119,9 +129,18 @@ func NewParticipant(pc types.PeerConnection, sc types.SignalConnection, name str } }) - // TODO: handle data channel pc.OnDataChannel(participant.onDataChannel) + // only set after answered + pc.OnNegotiationNeeded(func() { + if participant.state != livekit.ParticipantInfo_JOINED && participant.state != livekit.ParticipantInfo_ACTIVE { + // ignore negotiation requests before connected + return + } + logger.GetLogger().Debugw("negotiation needed", "participantId", participant.ID()) + participant.scheduleNegotiate() + }) + return participant, nil } @@ -173,6 +192,12 @@ func (p *ParticipantImpl) OnClose(callback func(types.Participant)) { // Answer an offer from remote participant, used when clients make the initial connection func (p *ParticipantImpl) Answer(sdp webrtc.SessionDescription) (answer webrtc.SessionDescription, err error) { + if p.state != livekit.ParticipantInfo_JOINING && p.negotiationState != negotiationStateClient { + // not in a valid state to continue + err = ErrUnexpectedNegotiation + return + } + if err = p.peerConn.SetRemoteDescription(sdp); err != nil { return } @@ -188,11 +213,13 @@ func (p *ParticipantImpl) Answer(sdp webrtc.SessionDescription) (answer webrtc.S return } - // only set after answered - p.peerConn.OnNegotiationNeeded(func() { - logger.GetLogger().Debugw("negotiation needed", "participantId", p.ID()) - p.scheduleNegotiate() - }) + // if this is a client initiated re-negotiation, we'll need to flip back our state + p.negotiationCond.L.Lock() + if p.negotiationState == negotiationStateClient { + p.negotiationState = negotiationStateNone + p.negotiationCond.Broadcast() + } + p.negotiationCond.L.Unlock() err = p.sigConn.WriteResponse(&livekit.SignalResponse{ Message: &livekit.SignalResponse_Answer{ @@ -211,21 +238,29 @@ func (p *ParticipantImpl) AddTrack(clientId, name string, trackType livekit.Trac p.lock.Lock() defer p.lock.Unlock() - p.pendingTracks[clientId] = &livekit.TrackInfo{ + ti := &livekit.TrackInfo{ Type: trackType, Name: name, + Sid: utils.NewGuid(utils.TrackPrefix), } + p.pendingTracks[clientId] = ti - p.scheduleNegotiate() + p.sigConn.WriteResponse(&livekit.SignalResponse{ + Message: &livekit.SignalResponse_TrackPublished{ + TrackPublished: &livekit.TrackPublishedResponse{ + Cid: clientId, + Track: ti, + }, + }, + }) } func (p *ParticipantImpl) RemoveTrack(sid string) error { p.lock.Lock() defer p.lock.Unlock() - // + // TODO: handle removal properly - p.scheduleNegotiate() return nil } @@ -237,9 +272,31 @@ func (p *ParticipantImpl) HandleAnswer(sdp webrtc.SessionDescription) error { if err := p.peerConn.SetRemoteDescription(sdp); err != nil { return errors.Wrap(err, "could not set remote description") } + + // negotiated, reset flag + p.negotiationCond.L.Lock() + p.negotiationState = negotiationStateNone + p.negotiationCond.Broadcast() + p.negotiationCond.L.Unlock() return nil } +// client requested negotiation, when it's able to, send a signal to let it +func (p *ParticipantImpl) HandleClientNegotiation() { + // wait until client is able to request negotiation + p.negotiationCond.L.Lock() + for p.negotiationState != negotiationStateNone { + p.negotiationCond.Wait() + } + p.negotiationState = negotiationStateClient + p.negotiationCond.L.Unlock() + p.sigConn.WriteResponse(&livekit.SignalResponse{ + Message: &livekit.SignalResponse_Negotiate{ + Negotiate: &livekit.NegotiationResponse{}, + }, + }) +} + // AddICECandidate adds candidates for remote peer func (p *ParticipantImpl) AddICECandidate(candidate webrtc.ICECandidateInit) error { if err := p.peerConn.AddICECandidate(candidate); err != nil { @@ -346,9 +403,9 @@ func (p *ParticipantImpl) AddDownTrack(streamId string, dt *sfu.DownTrack) { p.lock.Lock() p.subscribedTracks[streamId] = append(p.subscribedTracks[streamId], dt) p.lock.Unlock() - dt.OnBind(func() { - go p.scheduleDownTrackBindingReports(streamId) - }) + //dt.OnBind(func() { + // go p.scheduleDownTrackBindingReports(streamId) + //}) } func (p *ParticipantImpl) RemoveDownTrack(streamId string, dt *sfu.DownTrack) { @@ -368,7 +425,16 @@ func (p *ParticipantImpl) scheduleNegotiate() { p.debouncedNegotiate(p.negotiate) } +// initiates server-driven negotiation by creating an offer func (p *ParticipantImpl) negotiate() { + p.negotiationCond.L.Lock() + for p.negotiationState != negotiationStateNone { + p.negotiationCond.Wait() + p.negotiationState = negotiationStateServer + } + p.negotiationCond.L.Unlock() + + logger.GetLogger().Debugw("starting negotiation", "participant", p.ID()) offer, err := p.peerConn.CreateOffer(nil) if err != nil { logger.GetLogger().Errorw("could not create offer", "err", err) @@ -415,13 +481,18 @@ func (p *ParticipantImpl) updateState(state livekit.ParticipantInfo_State) { // when a new remoteTrack is created, creates a Track and adds it to room func (p *ParticipantImpl) onMediaTrack(track *webrtc.TrackRemote, rtpReceiver *webrtc.RTPReceiver) { - logger.GetLogger().Debugw("remoteTrack added", "participantId", p.ID(), "remoteTrack", track.ID()) + logger.GetLogger().Debugw("mediaTrack added", "participantId", p.ID(), "remoteTrack", track.ID()) + + ti := p.popPendingTrack(track.ID()) + if ti == nil { + return + } // create ReceiverImpl - receiver := NewReceiver(p.rtcpCh, rtpReceiver, track) - mt := NewMediaTrack(p.id, p.rtcpCh, track, receiver) + receiver := NewReceiver(p.rtcpCh, rtpReceiver, track, p.receiverConfig) + mt := NewMediaTrack(ti.Sid, p.id, p.rtcpCh, track, receiver) - p.handleTrackPublished(track.ID(), mt) + p.handleTrackPublished(mt) } func (p *ParticipantImpl) onDataChannel(dc *webrtc.DataChannel) { @@ -430,38 +501,37 @@ func (p *ParticipantImpl) onDataChannel(dc *webrtc.DataChannel) { } logger.GetLogger().Debugw("dataChannel added", "participantId", p.ID(), "label", dc.Label()) - dt := NewDataTrack(p.id, dc) - p.lock.Lock() - p.publishedTracks[dt.id] = dt - p.lock.Unlock() + // data channels have numeric ids, so we use its label to identify + ti := p.popPendingTrack(dc.Label()) + if ti == nil { + return + } - dt.Start() + dt := NewDataTrack(ti.Sid, p.id, dc) - cid := fmt.Sprintf("%d", dc.ID()) - p.handleTrackPublished(cid, dt) + p.handleTrackPublished(dt) } -func (p *ParticipantImpl) handleTrackPublished(clientId string, track types.PublishedTrack) { - // fill in +func (p *ParticipantImpl) popPendingTrack(clientId string) *livekit.TrackInfo { p.lock.Lock() defer p.lock.Unlock() ti := p.pendingTracks[clientId] if ti == nil { logger.GetLogger().Errorw("track info not published prior to track", "clientId", clientId) } else { - track.SetName(ti.Name) delete(p.pendingTracks, clientId) } + return ti +} + +func (p *ParticipantImpl) handleTrackPublished(track types.PublishedTrack) { + // fill in + p.lock.Lock() + defer p.lock.Unlock() p.publishedTracks[track.ID()] = track track.Start() - // confirm publication - p.sigConn.WriteResponse(&livekit.SignalResponse{ - Message: &livekit.SignalResponse_TrackPublished{ - TrackPublished: ToProtoTrack(track), - }, - }) if p.onTrackPublished != nil { go p.onTrackPublished(p, track) } @@ -492,7 +562,7 @@ func (p *ParticipantImpl) scheduleDownTrackBindingReports(streamId string) { i := 0 for { if err := p.peerConn.WriteRTCP(batch); err != nil { - logger.GetLogger().Debugw("Sending track binding reports", + logger.GetLogger().Debugw("error sending track binding reports", "participant", p.id, "err", err) } diff --git a/pkg/rtc/receiver.go b/pkg/rtc/receiver.go index af96dba72..79b41cbed 100644 --- a/pkg/rtc/receiver.go +++ b/pkg/rtc/receiver.go @@ -23,7 +23,7 @@ type ReceiverImpl struct { rtcpChan chan []rtcp.Packet } -func NewReceiver(rtcpCh chan []rtcp.Packet, rtpReceiver *webrtc.RTPReceiver, track *webrtc.TrackRemote) *ReceiverImpl { +func NewReceiver(rtcpCh chan []rtcp.Packet, rtpReceiver *webrtc.RTPReceiver, track *webrtc.TrackRemote, config ReceiverConfig) *ReceiverImpl { r := &ReceiverImpl{ rtpReceiver: rtpReceiver, rtcpChan: rtcpCh, @@ -43,6 +43,11 @@ func NewReceiver(rtcpCh chan []rtcp.Packet, rtpReceiver *webrtc.RTPReceiver, tra // TODO: figure out how to handle this }) + r.buffer.Bind(rtpReceiver.GetParameters(), buffer.Options{ + BufferTime: config.maxBufferTime, + MaxBitRate: config.maxBitrate, + }) + // received sender updates r.rtcpReader.OnPacket(func(bytes []byte) { pkts, err := rtcp.Unmarshal(bytes) diff --git a/pkg/rtc/room.go b/pkg/rtc/room.go index ed7582cd0..ff5e14dda 100644 --- a/pkg/rtc/room.go +++ b/pkg/rtc/room.go @@ -68,7 +68,8 @@ func (r *Room) Join(participant types.Participant) error { // it's important to set this before connection, we don't want to miss out on any publishedTracks participant.OnTrackPublished(r.onTrackAdded) participant.OnStateChange(func(p types.Participant, oldState livekit.ParticipantInfo_State) { - log.Debugw("participant state changed", "state", p.State(), "participant", p.ID()) + log.Debugw("participant state changed", "state", p.State(), "participant", p.ID(), + "oldState", oldState) r.broadcastParticipantState(p) if oldState == livekit.ParticipantInfo_JOINING && p.State() == livekit.ParticipantInfo_JOINED { @@ -140,10 +141,14 @@ func (r *Room) onTrackAdded(participant types.Participant, track types.Published // skip publishing participant continue } - if existingParticipant.State() != livekit.ParticipantInfo_JOINED { + if existingParticipant.State() != livekit.ParticipantInfo_JOINED && existingParticipant.State() != livekit.ParticipantInfo_ACTIVE { // not fully joined. don't subscribe yet continue } + logger.GetLogger().Debugw("subscribing to new track", + "srcParticipant", participant.ID(), + "remoteTrack", track.ID(), + "dstParticipant", existingParticipant.ID()) if err := track.AddSubscriber(existingParticipant); err != nil { logger.GetLogger().Errorw("could not subscribe to remoteTrack", "srcParticipant", participant.ID(), diff --git a/pkg/service/rtc.go b/pkg/service/rtc.go index 3849f1b82..c47c23f1a 100644 --- a/pkg/service/rtc.go +++ b/pkg/service/rtc.go @@ -85,7 +85,7 @@ func (s *RTCService) ServeHTTP(w http.ResponseWriter, r *http.Request) { writeJSONError(w, http.StatusInternalServerError, "could not create peerConnection", err.Error()) return } - participant, err := rtc.NewParticipant(pc, signalConn, pName) + participant, err := rtc.NewParticipant(pc, signalConn, pName, s.manager.Config().Receiver) if err != nil { writeJSONError(w, http.StatusInternalServerError, "could not create participant", err.Error()) return @@ -149,6 +149,8 @@ func (s *RTCService) ServeHTTP(w http.ResponseWriter, r *http.Request) { // jsonError(http.StatusInternalServerError, "could not handle negotiate", err.Error())) return } + case *livekit.SignalRequest_Negotiate: + participant.HandleClientNegotiation() case *livekit.SignalRequest_Trickle: if participant.State() == livekit.ParticipantInfo_JOINING { log.Errorw("cannot trickle before peer offer", "participant", participant.ID()) @@ -185,7 +187,7 @@ func (s *RTCService) handleOffer(participant types.Participant, offer *livekit.S func (s *RTCService) handleTrickle(participant types.Participant, trickle *livekit.TrickleRequest) error { candidateInit := rtc.FromProtoTrickle(trickle) - logger.GetLogger().Debugw("adding peer candidate", "participant", participant.ID()) + //logger.GetLogger().Debugw("adding peer candidate", "participant", participant.ID()) if err := participant.AddICECandidate(candidateInit); err != nil { return err } diff --git a/proto/livekit/rtc.pb.go b/proto/livekit/rtc.pb.go index d68bb45c3..e304aa427 100644 --- a/proto/livekit/rtc.pb.go +++ b/proto/livekit/rtc.pb.go @@ -37,6 +37,7 @@ type SignalRequest struct { // *SignalRequest_AddTrack // *SignalRequest_Mute // *SignalRequest_RemoveTrack + // *SignalRequest_Negotiate Message isSignalRequest_Message `protobuf_oneof:"message"` } @@ -121,6 +122,13 @@ func (x *SignalRequest) GetRemoveTrack() *RemoveTrackRequest { return nil } +func (x *SignalRequest) GetNegotiate() *NegotiationRequest { + if x, ok := x.GetMessage().(*SignalRequest_Negotiate); ok { + return x.Negotiate + } + return nil +} + type isSignalRequest_Message interface { isSignalRequest_Message() } @@ -151,6 +159,11 @@ type SignalRequest_RemoveTrack struct { RemoveTrack *RemoveTrackRequest `protobuf:"bytes,6,opt,name=remove_track,json=removeTrack,proto3,oneof"` } +type SignalRequest_Negotiate struct { + // when client needs to negotiate + Negotiate *NegotiationRequest `protobuf:"bytes,7,opt,name=negotiate,proto3,oneof"` +} + func (*SignalRequest_Offer) isSignalRequest_Message() {} func (*SignalRequest_Answer) isSignalRequest_Message() {} @@ -163,6 +176,8 @@ func (*SignalRequest_Mute) isSignalRequest_Message() {} func (*SignalRequest_RemoveTrack) isSignalRequest_Message() {} +func (*SignalRequest_Negotiate) isSignalRequest_Message() {} + type SignalResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -175,6 +190,7 @@ type SignalResponse struct { // *SignalResponse_Trickle // *SignalResponse_Update // *SignalResponse_TrackPublished + // *SignalResponse_Negotiate Message isSignalResponse_Message `protobuf_oneof:"message"` } @@ -252,13 +268,20 @@ func (x *SignalResponse) GetUpdate() *ParticipantUpdate { return nil } -func (x *SignalResponse) GetTrackPublished() *TrackInfo { +func (x *SignalResponse) GetTrackPublished() *TrackPublishedResponse { if x, ok := x.GetMessage().(*SignalResponse_TrackPublished); ok { return x.TrackPublished } return nil } +func (x *SignalResponse) GetNegotiate() *NegotiationResponse { + if x, ok := x.GetMessage().(*SignalResponse_Negotiate); ok { + return x.Negotiate + } + return nil +} + type isSignalResponse_Message interface { isSignalResponse_Message() } @@ -290,7 +313,12 @@ type SignalResponse_Update struct { type SignalResponse_TrackPublished struct { // sent to the participant when their track has been published - TrackPublished *TrackInfo `protobuf:"bytes,6,opt,name=track_published,json=trackPublished,proto3,oneof"` + TrackPublished *TrackPublishedResponse `protobuf:"bytes,6,opt,name=track_published,json=trackPublished,proto3,oneof"` +} + +type SignalResponse_Negotiate struct { + // sent to participant when they should initiate negotiation + Negotiate *NegotiationResponse `protobuf:"bytes,7,opt,name=negotiate,proto3,oneof"` } func (*SignalResponse_Join) isSignalResponse_Message() {} @@ -305,15 +333,17 @@ func (*SignalResponse_Update) isSignalResponse_Message() {} func (*SignalResponse_TrackPublished) isSignalResponse_Message() {} +func (*SignalResponse_Negotiate) isSignalResponse_Message() {} + type AddTrackRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Type TrackType `protobuf:"varint,2,opt,name=type,proto3,enum=livekit.TrackType" json:"type,omitempty"` // client ID of track, to match it when RTC track is received - Cid string `protobuf:"bytes,3,opt,name=cid,proto3" json:"cid,omitempty"` + Cid string `protobuf:"bytes,1,opt,name=cid,proto3" json:"cid,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Type TrackType `protobuf:"varint,3,opt,name=type,proto3,enum=livekit.TrackType" json:"type,omitempty"` } func (x *AddTrackRequest) Reset() { @@ -348,6 +378,13 @@ func (*AddTrackRequest) Descriptor() ([]byte, []int) { return file_rtc_proto_rawDescGZIP(), []int{2} } +func (x *AddTrackRequest) GetCid() string { + if x != nil { + return x.Cid + } + return "" +} + func (x *AddTrackRequest) GetName() string { if x != nil { return x.Name @@ -362,13 +399,6 @@ func (x *AddTrackRequest) GetType() TrackType { return TrackType_AUDIO } -func (x *AddTrackRequest) GetCid() string { - if x != nil { - return x.Cid - } - return "" -} - type TrickleRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -463,17 +493,17 @@ func (x *RemoveTrackRequest) GetSid() string { return "" } -type SessionDescription struct { +type MuteTrackRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` // "answer" | "offer" | "pranswer" | "rollback" - Sdp string `protobuf:"bytes,2,opt,name=sdp,proto3" json:"sdp,omitempty"` + Sid string `protobuf:"bytes,1,opt,name=sid,proto3" json:"sid,omitempty"` + Muted bool `protobuf:"varint,2,opt,name=muted,proto3" json:"muted,omitempty"` } -func (x *SessionDescription) Reset() { - *x = SessionDescription{} +func (x *MuteTrackRequest) Reset() { + *x = MuteTrackRequest{} if protoimpl.UnsafeEnabled { mi := &file_rtc_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -481,13 +511,13 @@ func (x *SessionDescription) Reset() { } } -func (x *SessionDescription) String() string { +func (x *MuteTrackRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*SessionDescription) ProtoMessage() {} +func (*MuteTrackRequest) ProtoMessage() {} -func (x *SessionDescription) ProtoReflect() protoreflect.Message { +func (x *MuteTrackRequest) ProtoReflect() protoreflect.Message { mi := &file_rtc_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -499,23 +529,61 @@ func (x *SessionDescription) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use SessionDescription.ProtoReflect.Descriptor instead. -func (*SessionDescription) Descriptor() ([]byte, []int) { +// Deprecated: Use MuteTrackRequest.ProtoReflect.Descriptor instead. +func (*MuteTrackRequest) Descriptor() ([]byte, []int) { return file_rtc_proto_rawDescGZIP(), []int{5} } -func (x *SessionDescription) GetType() string { +func (x *MuteTrackRequest) GetSid() string { if x != nil { - return x.Type + return x.Sid } return "" } -func (x *SessionDescription) GetSdp() string { +func (x *MuteTrackRequest) GetMuted() bool { if x != nil { - return x.Sdp + return x.Muted } - return "" + return false +} + +type NegotiationRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *NegotiationRequest) Reset() { + *x = NegotiationRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_rtc_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NegotiationRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NegotiationRequest) ProtoMessage() {} + +func (x *NegotiationRequest) ProtoReflect() protoreflect.Message { + mi := &file_rtc_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NegotiationRequest.ProtoReflect.Descriptor instead. +func (*NegotiationRequest) Descriptor() ([]byte, []int) { + return file_rtc_proto_rawDescGZIP(), []int{6} } type JoinResponse struct { @@ -531,7 +599,7 @@ type JoinResponse struct { func (x *JoinResponse) Reset() { *x = JoinResponse{} if protoimpl.UnsafeEnabled { - mi := &file_rtc_proto_msgTypes[6] + mi := &file_rtc_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -544,7 +612,7 @@ func (x *JoinResponse) String() string { func (*JoinResponse) ProtoMessage() {} func (x *JoinResponse) ProtoReflect() protoreflect.Message { - mi := &file_rtc_proto_msgTypes[6] + mi := &file_rtc_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -557,7 +625,7 @@ func (x *JoinResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use JoinResponse.ProtoReflect.Descriptor instead. func (*JoinResponse) Descriptor() ([]byte, []int) { - return file_rtc_proto_rawDescGZIP(), []int{6} + return file_rtc_proto_rawDescGZIP(), []int{7} } func (x *JoinResponse) GetRoom() *RoomInfo { @@ -581,32 +649,32 @@ func (x *JoinResponse) GetOtherParticipants() []*ParticipantInfo { return nil } -type MuteTrackRequest struct { +type TrackPublishedResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Sid string `protobuf:"bytes,1,opt,name=sid,proto3" json:"sid,omitempty"` - Muted bool `protobuf:"varint,2,opt,name=muted,proto3" json:"muted,omitempty"` + Cid string `protobuf:"bytes,1,opt,name=cid,proto3" json:"cid,omitempty"` + Track *TrackInfo `protobuf:"bytes,2,opt,name=track,proto3" json:"track,omitempty"` } -func (x *MuteTrackRequest) Reset() { - *x = MuteTrackRequest{} +func (x *TrackPublishedResponse) Reset() { + *x = TrackPublishedResponse{} if protoimpl.UnsafeEnabled { - mi := &file_rtc_proto_msgTypes[7] + mi := &file_rtc_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *MuteTrackRequest) String() string { +func (x *TrackPublishedResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*MuteTrackRequest) ProtoMessage() {} +func (*TrackPublishedResponse) ProtoMessage() {} -func (x *MuteTrackRequest) ProtoReflect() protoreflect.Message { - mi := &file_rtc_proto_msgTypes[7] +func (x *TrackPublishedResponse) ProtoReflect() protoreflect.Message { + mi := &file_rtc_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -617,23 +685,116 @@ func (x *MuteTrackRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use MuteTrackRequest.ProtoReflect.Descriptor instead. -func (*MuteTrackRequest) Descriptor() ([]byte, []int) { - return file_rtc_proto_rawDescGZIP(), []int{7} +// Deprecated: Use TrackPublishedResponse.ProtoReflect.Descriptor instead. +func (*TrackPublishedResponse) Descriptor() ([]byte, []int) { + return file_rtc_proto_rawDescGZIP(), []int{8} } -func (x *MuteTrackRequest) GetSid() string { +func (x *TrackPublishedResponse) GetCid() string { if x != nil { - return x.Sid + return x.Cid } return "" } -func (x *MuteTrackRequest) GetMuted() bool { +func (x *TrackPublishedResponse) GetTrack() *TrackInfo { if x != nil { - return x.Muted + return x.Track } - return false + return nil +} + +type NegotiationResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *NegotiationResponse) Reset() { + *x = NegotiationResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_rtc_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NegotiationResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NegotiationResponse) ProtoMessage() {} + +func (x *NegotiationResponse) ProtoReflect() protoreflect.Message { + mi := &file_rtc_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NegotiationResponse.ProtoReflect.Descriptor instead. +func (*NegotiationResponse) Descriptor() ([]byte, []int) { + return file_rtc_proto_rawDescGZIP(), []int{9} +} + +type SessionDescription struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` // "answer" | "offer" | "pranswer" | "rollback" + Sdp string `protobuf:"bytes,2,opt,name=sdp,proto3" json:"sdp,omitempty"` +} + +func (x *SessionDescription) Reset() { + *x = SessionDescription{} + if protoimpl.UnsafeEnabled { + mi := &file_rtc_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SessionDescription) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SessionDescription) ProtoMessage() {} + +func (x *SessionDescription) ProtoReflect() protoreflect.Message { + mi := &file_rtc_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SessionDescription.ProtoReflect.Descriptor instead. +func (*SessionDescription) Descriptor() ([]byte, []int) { + return file_rtc_proto_rawDescGZIP(), []int{10} +} + +func (x *SessionDescription) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *SessionDescription) GetSdp() string { + if x != nil { + return x.Sdp + } + return "" } type ParticipantUpdate struct { @@ -647,7 +808,7 @@ type ParticipantUpdate struct { func (x *ParticipantUpdate) Reset() { *x = ParticipantUpdate{} if protoimpl.UnsafeEnabled { - mi := &file_rtc_proto_msgTypes[8] + mi := &file_rtc_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -660,7 +821,7 @@ func (x *ParticipantUpdate) String() string { func (*ParticipantUpdate) ProtoMessage() {} func (x *ParticipantUpdate) ProtoReflect() protoreflect.Message { - mi := &file_rtc_proto_msgTypes[8] + mi := &file_rtc_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -673,7 +834,7 @@ func (x *ParticipantUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use ParticipantUpdate.ProtoReflect.Descriptor instead. func (*ParticipantUpdate) Descriptor() ([]byte, []int) { - return file_rtc_proto_rawDescGZIP(), []int{8} + return file_rtc_proto_rawDescGZIP(), []int{11} } func (x *ParticipantUpdate) GetParticipants() []*ParticipantInfo { @@ -688,7 +849,7 @@ var File_rtc_proto protoreflect.FileDescriptor var file_rtc_proto_rawDesc = []byte{ 0x0a, 0x09, 0x72, 0x74, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x1a, 0x0b, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x22, 0xe7, 0x02, 0x0a, 0x0d, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, + 0x6f, 0x22, 0xa4, 0x03, 0x0a, 0x0d, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x33, 0x0a, 0x05, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x48, @@ -710,69 +871,86 @@ var file_rtc_proto_rawDesc = []byte{ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0b, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x72, 0x61, 0x63, 0x6b, - 0x42, 0x09, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xde, 0x02, 0x0a, 0x0e, - 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, - 0x0a, 0x04, 0x6a, 0x6f, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6c, - 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x04, 0x6a, 0x6f, 0x69, 0x6e, 0x12, 0x35, 0x0a, 0x06, 0x61, - 0x6e, 0x73, 0x77, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6c, 0x69, - 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x06, 0x61, 0x6e, 0x73, 0x77, - 0x65, 0x72, 0x12, 0x33, 0x0a, 0x05, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1b, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x53, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, - 0x52, 0x05, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x12, 0x33, 0x0a, 0x07, 0x74, 0x72, 0x69, 0x63, 0x6b, - 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, - 0x69, 0x74, 0x2e, 0x54, 0x72, 0x69, 0x63, 0x6b, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x48, 0x00, 0x52, 0x07, 0x74, 0x72, 0x69, 0x63, 0x6b, 0x6c, 0x65, 0x12, 0x34, 0x0a, 0x06, - 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6c, - 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, - 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x06, 0x75, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x12, 0x3d, 0x0a, 0x0f, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x5f, 0x70, 0x75, 0x62, 0x6c, - 0x69, 0x73, 0x68, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x69, - 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x48, - 0x00, 0x52, 0x0e, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, - 0x64, 0x42, 0x09, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x5f, 0x0a, 0x0f, - 0x41, 0x64, 0x64, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x12, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x54, 0x72, 0x61, 0x63, - 0x6b, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x63, - 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x63, 0x69, 0x64, 0x22, 0x36, 0x0a, - 0x0e, 0x54, 0x72, 0x69, 0x63, 0x6b, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x24, 0x0a, 0x0d, 0x63, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x69, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, - 0x65, 0x49, 0x6e, 0x69, 0x74, 0x22, 0x26, 0x0a, 0x12, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, - 0x72, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x73, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x69, 0x64, 0x22, 0x3a, 0x0a, - 0x12, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x64, 0x70, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x64, 0x70, 0x22, 0xba, 0x01, 0x0a, 0x0c, 0x4a, 0x6f, - 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x04, 0x72, 0x6f, - 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, - 0x69, 0x74, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x72, 0x6f, 0x6f, - 0x6d, 0x12, 0x3a, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, - 0x2e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, - 0x52, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x12, 0x47, 0x0a, - 0x12, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, - 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6c, 0x69, 0x76, 0x65, - 0x6b, 0x69, 0x74, 0x2e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x11, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, - 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, 0x22, 0x3a, 0x0a, 0x10, 0x4d, 0x75, 0x74, 0x65, 0x54, 0x72, - 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, - 0x6d, 0x75, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x6d, 0x75, 0x74, - 0x65, 0x64, 0x22, 0x51, 0x0a, 0x11, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, - 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x3c, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x74, 0x69, - 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, - 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, - 0x61, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, - 0x70, 0x61, 0x6e, 0x74, 0x73, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2f, 0x6c, 0x69, 0x76, 0x65, - 0x6b, 0x69, 0x74, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x12, 0x3b, 0x0a, 0x09, 0x6e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, 0x65, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x4e, 0x65, + 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x48, 0x00, 0x52, 0x09, 0x6e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, 0x65, 0x42, 0x09, 0x0a, + 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xa9, 0x03, 0x0a, 0x0e, 0x53, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x04, 0x6a, + 0x6f, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6c, 0x69, 0x76, 0x65, + 0x6b, 0x69, 0x74, 0x2e, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x48, 0x00, 0x52, 0x04, 0x6a, 0x6f, 0x69, 0x6e, 0x12, 0x35, 0x0a, 0x06, 0x61, 0x6e, 0x73, 0x77, + 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, + 0x69, 0x74, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x06, 0x61, 0x6e, 0x73, 0x77, 0x65, 0x72, 0x12, + 0x33, 0x0a, 0x05, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, + 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x05, 0x6f, + 0x66, 0x66, 0x65, 0x72, 0x12, 0x33, 0x0a, 0x07, 0x74, 0x72, 0x69, 0x63, 0x6b, 0x6c, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, + 0x54, 0x72, 0x69, 0x63, 0x6b, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, + 0x52, 0x07, 0x74, 0x72, 0x69, 0x63, 0x6b, 0x6c, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x75, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6c, 0x69, 0x76, 0x65, + 0x6b, 0x69, 0x74, 0x2e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x06, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, + 0x4a, 0x0a, 0x0f, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, + 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, + 0x69, 0x74, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, + 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0e, 0x74, 0x72, 0x61, + 0x63, 0x6b, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x3c, 0x0a, 0x09, 0x6e, + 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, + 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x4e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x09, + 0x6e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x22, 0x5f, 0x0a, 0x0f, 0x41, 0x64, 0x64, 0x54, 0x72, 0x61, 0x63, 0x6b, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x63, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x6c, 0x69, + 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x52, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x36, 0x0a, 0x0e, 0x54, 0x72, 0x69, 0x63, 0x6b, 0x6c, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x63, 0x61, 0x6e, 0x64, 0x69, + 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x63, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x69, 0x74, 0x22, 0x26, 0x0a, + 0x12, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x73, 0x69, 0x64, 0x22, 0x3a, 0x0a, 0x10, 0x4d, 0x75, 0x74, 0x65, 0x54, 0x72, 0x61, + 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6d, + 0x75, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x6d, 0x75, 0x74, 0x65, + 0x64, 0x22, 0x14, 0x0a, 0x12, 0x4e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xba, 0x01, 0x0a, 0x0c, 0x4a, 0x6f, 0x69, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, + 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x12, + 0x3a, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x50, + 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0b, + 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x12, 0x6f, + 0x74, 0x68, 0x65, 0x72, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, + 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, + 0x74, 0x2e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x49, 0x6e, 0x66, + 0x6f, 0x52, 0x11, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, + 0x61, 0x6e, 0x74, 0x73, 0x22, 0x54, 0x0a, 0x16, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x50, 0x75, 0x62, + 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, + 0x0a, 0x03, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x63, 0x69, 0x64, + 0x12, 0x28, 0x0a, 0x05, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x12, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x22, 0x15, 0x0a, 0x13, 0x4e, 0x65, + 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x3a, 0x0a, 0x12, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x73, + 0x64, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x64, 0x70, 0x22, 0x51, 0x0a, + 0x11, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x12, 0x3c, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, + 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, + 0x69, 0x74, 0x2e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, + 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, + 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2d, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6c, 0x69, 0x76, 0x65, + 0x6b, 0x69, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -787,45 +965,51 @@ func file_rtc_proto_rawDescGZIP() []byte { return file_rtc_proto_rawDescData } -var file_rtc_proto_msgTypes = make([]protoimpl.MessageInfo, 9) +var file_rtc_proto_msgTypes = make([]protoimpl.MessageInfo, 12) var file_rtc_proto_goTypes = []interface{}{ - (*SignalRequest)(nil), // 0: livekit.SignalRequest - (*SignalResponse)(nil), // 1: livekit.SignalResponse - (*AddTrackRequest)(nil), // 2: livekit.AddTrackRequest - (*TrickleRequest)(nil), // 3: livekit.TrickleRequest - (*RemoveTrackRequest)(nil), // 4: livekit.RemoveTrackRequest - (*SessionDescription)(nil), // 5: livekit.SessionDescription - (*JoinResponse)(nil), // 6: livekit.JoinResponse - (*MuteTrackRequest)(nil), // 7: livekit.MuteTrackRequest - (*ParticipantUpdate)(nil), // 8: livekit.ParticipantUpdate - (*TrackInfo)(nil), // 9: livekit.TrackInfo - (TrackType)(0), // 10: livekit.TrackType - (*RoomInfo)(nil), // 11: livekit.RoomInfo - (*ParticipantInfo)(nil), // 12: livekit.ParticipantInfo + (*SignalRequest)(nil), // 0: livekit.SignalRequest + (*SignalResponse)(nil), // 1: livekit.SignalResponse + (*AddTrackRequest)(nil), // 2: livekit.AddTrackRequest + (*TrickleRequest)(nil), // 3: livekit.TrickleRequest + (*RemoveTrackRequest)(nil), // 4: livekit.RemoveTrackRequest + (*MuteTrackRequest)(nil), // 5: livekit.MuteTrackRequest + (*NegotiationRequest)(nil), // 6: livekit.NegotiationRequest + (*JoinResponse)(nil), // 7: livekit.JoinResponse + (*TrackPublishedResponse)(nil), // 8: livekit.TrackPublishedResponse + (*NegotiationResponse)(nil), // 9: livekit.NegotiationResponse + (*SessionDescription)(nil), // 10: livekit.SessionDescription + (*ParticipantUpdate)(nil), // 11: livekit.ParticipantUpdate + (TrackType)(0), // 12: livekit.TrackType + (*RoomInfo)(nil), // 13: livekit.RoomInfo + (*ParticipantInfo)(nil), // 14: livekit.ParticipantInfo + (*TrackInfo)(nil), // 15: livekit.TrackInfo } var file_rtc_proto_depIdxs = []int32{ - 5, // 0: livekit.SignalRequest.offer:type_name -> livekit.SessionDescription - 5, // 1: livekit.SignalRequest.answer:type_name -> livekit.SessionDescription + 10, // 0: livekit.SignalRequest.offer:type_name -> livekit.SessionDescription + 10, // 1: livekit.SignalRequest.answer:type_name -> livekit.SessionDescription 3, // 2: livekit.SignalRequest.trickle:type_name -> livekit.TrickleRequest 2, // 3: livekit.SignalRequest.add_track:type_name -> livekit.AddTrackRequest - 7, // 4: livekit.SignalRequest.mute:type_name -> livekit.MuteTrackRequest + 5, // 4: livekit.SignalRequest.mute:type_name -> livekit.MuteTrackRequest 4, // 5: livekit.SignalRequest.remove_track:type_name -> livekit.RemoveTrackRequest - 6, // 6: livekit.SignalResponse.join:type_name -> livekit.JoinResponse - 5, // 7: livekit.SignalResponse.answer:type_name -> livekit.SessionDescription - 5, // 8: livekit.SignalResponse.offer:type_name -> livekit.SessionDescription - 3, // 9: livekit.SignalResponse.trickle:type_name -> livekit.TrickleRequest - 8, // 10: livekit.SignalResponse.update:type_name -> livekit.ParticipantUpdate - 9, // 11: livekit.SignalResponse.track_published:type_name -> livekit.TrackInfo - 10, // 12: livekit.AddTrackRequest.type:type_name -> livekit.TrackType - 11, // 13: livekit.JoinResponse.room:type_name -> livekit.RoomInfo - 12, // 14: livekit.JoinResponse.participant:type_name -> livekit.ParticipantInfo - 12, // 15: livekit.JoinResponse.other_participants:type_name -> livekit.ParticipantInfo - 12, // 16: livekit.ParticipantUpdate.participants:type_name -> livekit.ParticipantInfo - 17, // [17:17] is the sub-list for method output_type - 17, // [17:17] is the sub-list for method input_type - 17, // [17:17] is the sub-list for extension type_name - 17, // [17:17] is the sub-list for extension extendee - 0, // [0:17] is the sub-list for field type_name + 6, // 6: livekit.SignalRequest.negotiate:type_name -> livekit.NegotiationRequest + 7, // 7: livekit.SignalResponse.join:type_name -> livekit.JoinResponse + 10, // 8: livekit.SignalResponse.answer:type_name -> livekit.SessionDescription + 10, // 9: livekit.SignalResponse.offer:type_name -> livekit.SessionDescription + 3, // 10: livekit.SignalResponse.trickle:type_name -> livekit.TrickleRequest + 11, // 11: livekit.SignalResponse.update:type_name -> livekit.ParticipantUpdate + 8, // 12: livekit.SignalResponse.track_published:type_name -> livekit.TrackPublishedResponse + 9, // 13: livekit.SignalResponse.negotiate:type_name -> livekit.NegotiationResponse + 12, // 14: livekit.AddTrackRequest.type:type_name -> livekit.TrackType + 13, // 15: livekit.JoinResponse.room:type_name -> livekit.RoomInfo + 14, // 16: livekit.JoinResponse.participant:type_name -> livekit.ParticipantInfo + 14, // 17: livekit.JoinResponse.other_participants:type_name -> livekit.ParticipantInfo + 15, // 18: livekit.TrackPublishedResponse.track:type_name -> livekit.TrackInfo + 14, // 19: livekit.ParticipantUpdate.participants:type_name -> livekit.ParticipantInfo + 20, // [20:20] is the sub-list for method output_type + 20, // [20:20] is the sub-list for method input_type + 20, // [20:20] is the sub-list for extension type_name + 20, // [20:20] is the sub-list for extension extendee + 0, // [0:20] is the sub-list for field type_name } func init() { file_rtc_proto_init() } @@ -896,30 +1080,6 @@ func file_rtc_proto_init() { } } file_rtc_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SessionDescription); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_rtc_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JoinResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_rtc_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*MuteTrackRequest); i { case 0: return &v.state @@ -931,7 +1091,67 @@ func file_rtc_proto_init() { return nil } } + file_rtc_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NegotiationRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rtc_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*JoinResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } file_rtc_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TrackPublishedResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rtc_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NegotiationResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rtc_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SessionDescription); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rtc_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ParticipantUpdate); i { case 0: return &v.state @@ -951,6 +1171,7 @@ func file_rtc_proto_init() { (*SignalRequest_AddTrack)(nil), (*SignalRequest_Mute)(nil), (*SignalRequest_RemoveTrack)(nil), + (*SignalRequest_Negotiate)(nil), } file_rtc_proto_msgTypes[1].OneofWrappers = []interface{}{ (*SignalResponse_Join)(nil), @@ -959,6 +1180,7 @@ func file_rtc_proto_init() { (*SignalResponse_Trickle)(nil), (*SignalResponse_Update)(nil), (*SignalResponse_TrackPublished)(nil), + (*SignalResponse_Negotiate)(nil), } type x struct{} out := protoimpl.TypeBuilder{ @@ -966,7 +1188,7 @@ func file_rtc_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_rtc_proto_rawDesc, NumEnums: 0, - NumMessages: 9, + NumMessages: 12, NumExtensions: 0, NumServices: 0, }, diff --git a/proto/rtc.proto b/proto/rtc.proto index baf141708..2f142a37f 100644 --- a/proto/rtc.proto +++ b/proto/rtc.proto @@ -15,6 +15,8 @@ message SignalRequest { AddTrackRequest add_track = 4; MuteTrackRequest mute = 5; RemoveTrackRequest remove_track = 6; + // when client needs to negotiate + NegotiationRequest negotiate = 7; } } @@ -31,15 +33,17 @@ message SignalResponse { // sent when participants in the room has changed ParticipantUpdate update = 5; // sent to the participant when their track has been published - TrackInfo track_published = 6; + TrackPublishedResponse track_published = 6; + // sent to participant when they should initiate negotiation + NegotiationResponse negotiate = 7; } } message AddTrackRequest { - string name = 1; - TrackType type = 2; // client ID of track, to match it when RTC track is received - string cid = 3; + string cid = 1; + string name = 2; + TrackType type = 3; } message TrickleRequest { @@ -50,9 +54,13 @@ message RemoveTrackRequest { string sid = 1; } -message SessionDescription { - string type = 1; // "answer" | "offer" | "pranswer" | "rollback" - string sdp = 2; +message MuteTrackRequest { + string sid = 1; + bool muted = 2; +} + +message NegotiationRequest { + // empty } message JoinResponse { @@ -61,11 +69,21 @@ message JoinResponse { repeated ParticipantInfo other_participants = 3; } -message MuteTrackRequest { - string sid = 1; - bool muted = 2; +message TrackPublishedResponse { + string cid = 1; + TrackInfo track = 2; } +message NegotiationResponse { + // empty +} + +message SessionDescription { + string type = 1; // "answer" | "offer" | "pranswer" | "rollback" + string sdp = 2; +} + + message ParticipantUpdate { repeated ParticipantInfo participants = 1; }