From e402d0d0afb6f9cfbc25e4b94040ffc6585171dd Mon Sep 17 00:00:00 2001 From: David Zhao Date: Tue, 16 Feb 2021 13:52:50 -0800 Subject: [PATCH] subscriber control of tracks (unsubscribe/mute/quality), support simulcast (#23) * subscription control & simulcast RTC APIs * don't remove tracks for simulcast --- pkg/rtc/datatrack.go | 9 +- pkg/rtc/mediatrack.go | 3 - pkg/rtc/participant.go | 27 +- pkg/rtc/room.go | 27 + pkg/rtc/subscribedtrack.go | 12 + pkg/rtc/types/interfaces.go | 4 + pkg/rtc/types/typesfakes/fake_participant.go | 130 ++++ .../types/typesfakes/fake_subscribed_track.go | 105 ++++ pkg/service/roommanager.go | 12 + proto/livekit/rtc.pb.go | 555 +++++++++++++----- proto/rtc.proto | 25 +- 11 files changed, 745 insertions(+), 164 deletions(-) diff --git a/pkg/rtc/datatrack.go b/pkg/rtc/datatrack.go index 46a8f403f..64d54a2d6 100644 --- a/pkg/rtc/datatrack.go +++ b/pkg/rtc/datatrack.go @@ -89,6 +89,13 @@ func (t *DataTrack) OnClose(f func()) { } func (t *DataTrack) AddSubscriber(participant types.Participant) error { + t.lock.Lock() + defer t.lock.Unlock() + + if t.subscribers[participant.ID()] != nil { + return nil + } + label := PackDataTrackLabel(t.participantId, t.ID(), t.dataChannel.Label()) downChannel, err := participant.SubscriberPC().CreateDataChannel(label, t.dataChannelOptions()) if err != nil { @@ -100,9 +107,7 @@ func (t *DataTrack) AddSubscriber(participant types.Participant) error { dataChannel: downChannel, } - t.lock.Lock() t.subscribers[participant.ID()] = sub - t.lock.Unlock() downChannel.OnClose(func() { t.RemoveSubscriber(sub.participantId) diff --git a/pkg/rtc/mediatrack.go b/pkg/rtc/mediatrack.go index 6b62e1c4c..0c8577011 100644 --- a/pkg/rtc/mediatrack.go +++ b/pkg/rtc/mediatrack.go @@ -117,9 +117,6 @@ func (t *MediaTrack) AddSubscriber(sub types.Participant) error { // don't subscribe to the same track multiple times if existingSt != nil { - logger.Warnw("participant already subscribed to track", - "sub", sub.Identity(), - "track", t.ID()) return nil } diff --git a/pkg/rtc/participant.go b/pkg/rtc/participant.go index 951a8bc91..04fd69dbc 100644 --- a/pkg/rtc/participant.go +++ b/pkg/rtc/participant.go @@ -265,6 +265,12 @@ func (p *ParticipantImpl) AddTrack(clientId, name string, trackType livekit.Trac }) } +func (p *ParticipantImpl) GetPublishedTracks() []types.PublishedTrack { + p.lock.RUnlock() + defer p.lock.RUnlock() + return funk.Values(p.publishedTracks).([]types.PublishedTrack) +} + // handles a client answer response, with subscriber PC, server initiates the offer // and client answers func (p *ParticipantImpl) HandleAnswer(sdp webrtc.SessionDescription) error { @@ -455,6 +461,12 @@ func (p *ParticipantImpl) SubscriberPC() *webrtc.PeerConnection { return p.subscriber.pc } +func (p *ParticipantImpl) GetSubscribedTracks() []types.SubscribedTrack { + p.lock.RLock() + defer p.lock.RUnlock() + return funk.Values(p.subscribedTracks).([]types.SubscribedTrack) +} + // add a track to the participant's subscribed list func (p *ParticipantImpl) AddSubscribedTrack(pubId string, subTrack types.SubscribedTrack) { logger.Debugw("added subscribedTrack", "srcParticipant", pubId, @@ -561,9 +573,13 @@ func (p *ParticipantImpl) writeMessage(msg *livekit.SignalResponse) error { // 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.Debugw("mediaTrack added", "participant", p.Identity(), "remoteTrack", track.ID()) + logger.Debugw("mediaTrack added", + "participant", p.Identity(), + "remoteTrack", track.ID(), + "rid", track.RID()) - ti := p.popPendingTrack(track.ID(), ToProtoTrackKind(track.Kind())) + // delete pending track if it's not simulcasting + ti := p.getPendingTrack(track.ID(), ToProtoTrackKind(track.Kind()), track.RID() == "") if ti == nil { return } @@ -575,7 +591,6 @@ func (p *ParticipantImpl) onMediaTrack(track *webrtc.TrackRemote, rtpReceiver *w var mt *MediaTrack var newTrack bool if trk, ok := ptrack.(*MediaTrack); ok { - logger.Debugw("using existing mediatrack, simulcast", "rid", track.RID()) mt = trk } else { mt = NewMediaTrack(ti.Sid, p.id, p.rtcpCh, track, p.receiverConfig, p.audioConfig) @@ -604,7 +619,7 @@ func (p *ParticipantImpl) onDataChannel(dc *webrtc.DataChannel) { logger.Debugw("dataChannel added", "participant", p.Identity(), "label", dc.Label()) // data channels have numeric ids, so we use its label to identify - ti := p.popPendingTrack(dc.Label(), livekit.TrackType_DATA) + ti := p.getPendingTrack(dc.Label(), livekit.TrackType_DATA, true) if ti == nil { return } @@ -615,7 +630,7 @@ func (p *ParticipantImpl) onDataChannel(dc *webrtc.DataChannel) { p.handleTrackPublished(dt) } -func (p *ParticipantImpl) popPendingTrack(clientId string, kind livekit.TrackType) *livekit.TrackInfo { +func (p *ParticipantImpl) getPendingTrack(clientId string, kind livekit.TrackType, deleteAfter bool) *livekit.TrackInfo { p.lock.Lock() defer p.lock.Unlock() ti := p.pendingTracks[clientId] @@ -635,7 +650,7 @@ func (p *ParticipantImpl) popPendingTrack(clientId string, kind livekit.TrackTyp // if still not found, we are done if ti == nil { logger.Errorw("track info not published prior to track", "clientId", clientId) - } else { + } else if deleteAfter { delete(p.pendingTracks, clientId) } return ti diff --git a/pkg/rtc/room.go b/pkg/rtc/room.go index 7a0c86982..4a48a164e 100644 --- a/pkg/rtc/room.go +++ b/pkg/rtc/room.go @@ -215,6 +215,33 @@ func (r *Room) RemoveParticipant(identity string) { } } +func (r *Room) UpdateSubscriptions(participant types.Participant, subscription *livekit.UpdateSubscription) error { + // find all matching tracks + var tracks []types.PublishedTrack + participants := r.GetParticipants() + for _, p := range participants { + for _, sid := range subscription.TrackSids { + for _, track := range p.GetPublishedTracks() { + if sid == track.ID() { + tracks = append(tracks, track) + } + } + } + } + + // handle subscription changes + for _, track := range tracks { + if subscription.Subscribe { + if err := track.AddSubscriber(participant); err != nil { + return err + } + } else { + track.RemoveSubscriber(participant.ID()) + } + } + return nil +} + // Close the room if all participants had left, or it's still empty past timeout func (r *Room) CloseIfEmpty() { if r.isClosed.Get() { diff --git a/pkg/rtc/subscribedtrack.go b/pkg/rtc/subscribedtrack.go index 775957bab..0f1ce4411 100644 --- a/pkg/rtc/subscribedtrack.go +++ b/pkg/rtc/subscribedtrack.go @@ -2,8 +2,10 @@ package rtc import ( "github.com/pion/ion-sfu/pkg/sfu" + "github.com/pion/webrtc/v3" "github.com/livekit/livekit-server/pkg/utils" + "github.com/livekit/livekit-server/proto/livekit" ) type SubscribedTrack struct { @@ -18,6 +20,10 @@ func NewSubscribedTrack(dt *sfu.DownTrack) *SubscribedTrack { } } +func (t *SubscribedTrack) ID() string { + return t.dt.ID() +} + func (t *SubscribedTrack) DownTrack() *sfu.DownTrack { return t.dt } @@ -38,6 +44,12 @@ func (t *SubscribedTrack) SetPublisherMuted(muted bool) { t.updateDownTrackMute() } +func (t *SubscribedTrack) SetVideoQuality(quality livekit.VideoQuality) { + if t.dt.Kind() == webrtc.RTPCodecTypeVideo { + t.dt.SwitchSpatialLayer(int64(quality), true) + } +} + func (t *SubscribedTrack) updateDownTrackMute() { muted := t.subMuted.Get() || t.pubMuted.Get() t.dt.Mute(muted) diff --git a/pkg/rtc/types/interfaces.go b/pkg/rtc/types/interfaces.go index dc584e9fe..3f44275de 100644 --- a/pkg/rtc/types/interfaces.go +++ b/pkg/rtc/types/interfaces.go @@ -34,6 +34,8 @@ type Participant interface { SubscriberMediaEngine() *webrtc.MediaEngine AddTrack(clientId, name string, trackType livekit.TrackType) + GetPublishedTracks() []PublishedTrack + GetSubscribedTracks() []SubscribedTrack HandleOffer(sdp webrtc.SessionDescription) (answer webrtc.SessionDescription, err error) HandleAnswer(sdp webrtc.SessionDescription) error AddICECandidate(candidate webrtc.ICECandidateInit, target livekit.SignalTarget) error @@ -82,9 +84,11 @@ type PublishedTrack interface { //counterfeiter:generate . SubscribedTrack type SubscribedTrack interface { + ID() string DownTrack() *sfu.DownTrack IsMuted() bool SetMuted(muted bool) + SetVideoQuality(quality livekit.VideoQuality) SetPublisherMuted(muted bool) } diff --git a/pkg/rtc/types/typesfakes/fake_participant.go b/pkg/rtc/types/typesfakes/fake_participant.go index ce996f3ca..3c5214d96 100644 --- a/pkg/rtc/types/typesfakes/fake_participant.go +++ b/pkg/rtc/types/typesfakes/fake_participant.go @@ -70,6 +70,16 @@ type FakeParticipant struct { result1 uint8 result2 bool } + GetPublishedTracksStub func() []types.PublishedTrack + getPublishedTracksMutex sync.RWMutex + getPublishedTracksArgsForCall []struct { + } + getPublishedTracksReturns struct { + result1 []types.PublishedTrack + } + getPublishedTracksReturnsOnCall map[int]struct { + result1 []types.PublishedTrack + } GetResponseSinkStub func() routing.MessageSink getResponseSinkMutex sync.RWMutex getResponseSinkArgsForCall []struct { @@ -80,6 +90,16 @@ type FakeParticipant struct { getResponseSinkReturnsOnCall map[int]struct { result1 routing.MessageSink } + GetSubscribedTracksStub func() []types.SubscribedTrack + getSubscribedTracksMutex sync.RWMutex + getSubscribedTracksArgsForCall []struct { + } + getSubscribedTracksReturns struct { + result1 []types.SubscribedTrack + } + getSubscribedTracksReturnsOnCall map[int]struct { + result1 []types.SubscribedTrack + } HandleAnswerStub func(webrtc.SessionDescription) error handleAnswerMutex sync.RWMutex handleAnswerArgsForCall []struct { @@ -578,6 +598,59 @@ func (fake *FakeParticipant) GetAudioLevelReturnsOnCall(i int, result1 uint8, re }{result1, result2} } +func (fake *FakeParticipant) GetPublishedTracks() []types.PublishedTrack { + fake.getPublishedTracksMutex.Lock() + ret, specificReturn := fake.getPublishedTracksReturnsOnCall[len(fake.getPublishedTracksArgsForCall)] + fake.getPublishedTracksArgsForCall = append(fake.getPublishedTracksArgsForCall, struct { + }{}) + stub := fake.GetPublishedTracksStub + fakeReturns := fake.getPublishedTracksReturns + fake.recordInvocation("GetPublishedTracks", []interface{}{}) + fake.getPublishedTracksMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeParticipant) GetPublishedTracksCallCount() int { + fake.getPublishedTracksMutex.RLock() + defer fake.getPublishedTracksMutex.RUnlock() + return len(fake.getPublishedTracksArgsForCall) +} + +func (fake *FakeParticipant) GetPublishedTracksCalls(stub func() []types.PublishedTrack) { + fake.getPublishedTracksMutex.Lock() + defer fake.getPublishedTracksMutex.Unlock() + fake.GetPublishedTracksStub = stub +} + +func (fake *FakeParticipant) GetPublishedTracksReturns(result1 []types.PublishedTrack) { + fake.getPublishedTracksMutex.Lock() + defer fake.getPublishedTracksMutex.Unlock() + fake.GetPublishedTracksStub = nil + fake.getPublishedTracksReturns = struct { + result1 []types.PublishedTrack + }{result1} +} + +func (fake *FakeParticipant) GetPublishedTracksReturnsOnCall(i int, result1 []types.PublishedTrack) { + fake.getPublishedTracksMutex.Lock() + defer fake.getPublishedTracksMutex.Unlock() + fake.GetPublishedTracksStub = nil + if fake.getPublishedTracksReturnsOnCall == nil { + fake.getPublishedTracksReturnsOnCall = make(map[int]struct { + result1 []types.PublishedTrack + }) + } + fake.getPublishedTracksReturnsOnCall[i] = struct { + result1 []types.PublishedTrack + }{result1} +} + func (fake *FakeParticipant) GetResponseSink() routing.MessageSink { fake.getResponseSinkMutex.Lock() ret, specificReturn := fake.getResponseSinkReturnsOnCall[len(fake.getResponseSinkArgsForCall)] @@ -631,6 +704,59 @@ func (fake *FakeParticipant) GetResponseSinkReturnsOnCall(i int, result1 routing }{result1} } +func (fake *FakeParticipant) GetSubscribedTracks() []types.SubscribedTrack { + fake.getSubscribedTracksMutex.Lock() + ret, specificReturn := fake.getSubscribedTracksReturnsOnCall[len(fake.getSubscribedTracksArgsForCall)] + fake.getSubscribedTracksArgsForCall = append(fake.getSubscribedTracksArgsForCall, struct { + }{}) + stub := fake.GetSubscribedTracksStub + fakeReturns := fake.getSubscribedTracksReturns + fake.recordInvocation("GetSubscribedTracks", []interface{}{}) + fake.getSubscribedTracksMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeParticipant) GetSubscribedTracksCallCount() int { + fake.getSubscribedTracksMutex.RLock() + defer fake.getSubscribedTracksMutex.RUnlock() + return len(fake.getSubscribedTracksArgsForCall) +} + +func (fake *FakeParticipant) GetSubscribedTracksCalls(stub func() []types.SubscribedTrack) { + fake.getSubscribedTracksMutex.Lock() + defer fake.getSubscribedTracksMutex.Unlock() + fake.GetSubscribedTracksStub = stub +} + +func (fake *FakeParticipant) GetSubscribedTracksReturns(result1 []types.SubscribedTrack) { + fake.getSubscribedTracksMutex.Lock() + defer fake.getSubscribedTracksMutex.Unlock() + fake.GetSubscribedTracksStub = nil + fake.getSubscribedTracksReturns = struct { + result1 []types.SubscribedTrack + }{result1} +} + +func (fake *FakeParticipant) GetSubscribedTracksReturnsOnCall(i int, result1 []types.SubscribedTrack) { + fake.getSubscribedTracksMutex.Lock() + defer fake.getSubscribedTracksMutex.Unlock() + fake.GetSubscribedTracksStub = nil + if fake.getSubscribedTracksReturnsOnCall == nil { + fake.getSubscribedTracksReturnsOnCall = make(map[int]struct { + result1 []types.SubscribedTrack + }) + } + fake.getSubscribedTracksReturnsOnCall[i] = struct { + result1 []types.SubscribedTrack + }{result1} +} + func (fake *FakeParticipant) HandleAnswer(arg1 webrtc.SessionDescription) error { fake.handleAnswerMutex.Lock() ret, specificReturn := fake.handleAnswerReturnsOnCall[len(fake.handleAnswerArgsForCall)] @@ -1737,8 +1863,12 @@ func (fake *FakeParticipant) Invocations() map[string][][]interface{} { defer fake.closeMutex.RUnlock() fake.getAudioLevelMutex.RLock() defer fake.getAudioLevelMutex.RUnlock() + fake.getPublishedTracksMutex.RLock() + defer fake.getPublishedTracksMutex.RUnlock() fake.getResponseSinkMutex.RLock() defer fake.getResponseSinkMutex.RUnlock() + fake.getSubscribedTracksMutex.RLock() + defer fake.getSubscribedTracksMutex.RUnlock() fake.handleAnswerMutex.RLock() defer fake.handleAnswerMutex.RUnlock() fake.handleOfferMutex.RLock() diff --git a/pkg/rtc/types/typesfakes/fake_subscribed_track.go b/pkg/rtc/types/typesfakes/fake_subscribed_track.go index 004394a3d..397cc52c1 100644 --- a/pkg/rtc/types/typesfakes/fake_subscribed_track.go +++ b/pkg/rtc/types/typesfakes/fake_subscribed_track.go @@ -5,6 +5,7 @@ import ( "sync" "github.com/livekit/livekit-server/pkg/rtc/types" + "github.com/livekit/livekit-server/proto/livekit" "github.com/pion/ion-sfu/pkg/sfu" ) @@ -19,6 +20,16 @@ type FakeSubscribedTrack struct { downTrackReturnsOnCall map[int]struct { result1 *sfu.DownTrack } + IDStub func() string + iDMutex sync.RWMutex + iDArgsForCall []struct { + } + iDReturns struct { + result1 string + } + iDReturnsOnCall map[int]struct { + result1 string + } IsMutedStub func() bool isMutedMutex sync.RWMutex isMutedArgsForCall []struct { @@ -39,6 +50,11 @@ type FakeSubscribedTrack struct { setPublisherMutedArgsForCall []struct { arg1 bool } + SetVideoQualityStub func(livekit.VideoQuality) + setVideoQualityMutex sync.RWMutex + setVideoQualityArgsForCall []struct { + arg1 livekit.VideoQuality + } invocations map[string][][]interface{} invocationsMutex sync.RWMutex } @@ -96,6 +112,59 @@ func (fake *FakeSubscribedTrack) DownTrackReturnsOnCall(i int, result1 *sfu.Down }{result1} } +func (fake *FakeSubscribedTrack) ID() string { + fake.iDMutex.Lock() + ret, specificReturn := fake.iDReturnsOnCall[len(fake.iDArgsForCall)] + fake.iDArgsForCall = append(fake.iDArgsForCall, struct { + }{}) + stub := fake.IDStub + fakeReturns := fake.iDReturns + fake.recordInvocation("ID", []interface{}{}) + fake.iDMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeSubscribedTrack) IDCallCount() int { + fake.iDMutex.RLock() + defer fake.iDMutex.RUnlock() + return len(fake.iDArgsForCall) +} + +func (fake *FakeSubscribedTrack) IDCalls(stub func() string) { + fake.iDMutex.Lock() + defer fake.iDMutex.Unlock() + fake.IDStub = stub +} + +func (fake *FakeSubscribedTrack) IDReturns(result1 string) { + fake.iDMutex.Lock() + defer fake.iDMutex.Unlock() + fake.IDStub = nil + fake.iDReturns = struct { + result1 string + }{result1} +} + +func (fake *FakeSubscribedTrack) IDReturnsOnCall(i int, result1 string) { + fake.iDMutex.Lock() + defer fake.iDMutex.Unlock() + fake.IDStub = nil + if fake.iDReturnsOnCall == nil { + fake.iDReturnsOnCall = make(map[int]struct { + result1 string + }) + } + fake.iDReturnsOnCall[i] = struct { + result1 string + }{result1} +} + func (fake *FakeSubscribedTrack) IsMuted() bool { fake.isMutedMutex.Lock() ret, specificReturn := fake.isMutedReturnsOnCall[len(fake.isMutedArgsForCall)] @@ -213,17 +282,53 @@ func (fake *FakeSubscribedTrack) SetPublisherMutedArgsForCall(i int) bool { return argsForCall.arg1 } +func (fake *FakeSubscribedTrack) SetVideoQuality(arg1 livekit.VideoQuality) { + fake.setVideoQualityMutex.Lock() + fake.setVideoQualityArgsForCall = append(fake.setVideoQualityArgsForCall, struct { + arg1 livekit.VideoQuality + }{arg1}) + stub := fake.SetVideoQualityStub + fake.recordInvocation("SetVideoQuality", []interface{}{arg1}) + fake.setVideoQualityMutex.Unlock() + if stub != nil { + fake.SetVideoQualityStub(arg1) + } +} + +func (fake *FakeSubscribedTrack) SetVideoQualityCallCount() int { + fake.setVideoQualityMutex.RLock() + defer fake.setVideoQualityMutex.RUnlock() + return len(fake.setVideoQualityArgsForCall) +} + +func (fake *FakeSubscribedTrack) SetVideoQualityCalls(stub func(livekit.VideoQuality)) { + fake.setVideoQualityMutex.Lock() + defer fake.setVideoQualityMutex.Unlock() + fake.SetVideoQualityStub = stub +} + +func (fake *FakeSubscribedTrack) SetVideoQualityArgsForCall(i int) livekit.VideoQuality { + fake.setVideoQualityMutex.RLock() + defer fake.setVideoQualityMutex.RUnlock() + argsForCall := fake.setVideoQualityArgsForCall[i] + return argsForCall.arg1 +} + func (fake *FakeSubscribedTrack) Invocations() map[string][][]interface{} { fake.invocationsMutex.RLock() defer fake.invocationsMutex.RUnlock() fake.downTrackMutex.RLock() defer fake.downTrackMutex.RUnlock() + fake.iDMutex.RLock() + defer fake.iDMutex.RUnlock() fake.isMutedMutex.RLock() defer fake.isMutedMutex.RUnlock() fake.setMutedMutex.RLock() defer fake.setMutedMutex.RUnlock() fake.setPublisherMutedMutex.RLock() defer fake.setPublisherMutedMutex.RUnlock() + fake.setVideoQualityMutex.RLock() + defer fake.setVideoQualityMutex.RUnlock() copiedInvocations := map[string][][]interface{}{} for key, value := range fake.invocations { copiedInvocations[key] = value diff --git a/pkg/service/roommanager.go b/pkg/service/roommanager.go index 889d9d7d9..1a31ee7c7 100644 --- a/pkg/service/roommanager.go +++ b/pkg/service/roommanager.go @@ -302,6 +302,18 @@ func (r *RoomManager) rtcSessionWorker(room *rtc.Room, participant types.Partici } case *livekit.SignalRequest_Mute: participant.SetTrackMuted(msg.Mute.Sid, msg.Mute.Muted) + case *livekit.SignalRequest_Subscription: + room.UpdateSubscriptions(participant, msg.Subscription) + case *livekit.SignalRequest_TrackSetting: + for _, subTrack := range participant.GetSubscribedTracks() { + for _, sid := range msg.TrackSetting.TrackSids { + if subTrack.ID() != sid { + continue + } + subTrack.SetMuted(msg.TrackSetting.Mute) + subTrack.SetVideoQuality(msg.TrackSetting.Quality) + } + } } } } diff --git a/proto/livekit/rtc.pb.go b/proto/livekit/rtc.pb.go index a05d31947..ecfb7498e 100644 --- a/proto/livekit/rtc.pb.go +++ b/proto/livekit/rtc.pb.go @@ -71,6 +71,55 @@ func (SignalTarget) EnumDescriptor() ([]byte, []int) { return file_rtc_proto_rawDescGZIP(), []int{0} } +type VideoQuality int32 + +const ( + VideoQuality_LOW VideoQuality = 0 + VideoQuality_MEDIUM VideoQuality = 1 + VideoQuality_HIGH VideoQuality = 2 +) + +// Enum value maps for VideoQuality. +var ( + VideoQuality_name = map[int32]string{ + 0: "LOW", + 1: "MEDIUM", + 2: "HIGH", + } + VideoQuality_value = map[string]int32{ + "LOW": 0, + "MEDIUM": 1, + "HIGH": 2, + } +) + +func (x VideoQuality) Enum() *VideoQuality { + p := new(VideoQuality) + *p = x + return p +} + +func (x VideoQuality) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (VideoQuality) Descriptor() protoreflect.EnumDescriptor { + return file_rtc_proto_enumTypes[1].Descriptor() +} + +func (VideoQuality) Type() protoreflect.EnumType { + return &file_rtc_proto_enumTypes[1] +} + +func (x VideoQuality) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use VideoQuality.Descriptor instead. +func (VideoQuality) EnumDescriptor() ([]byte, []int) { + return file_rtc_proto_rawDescGZIP(), []int{1} +} + type SignalRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -82,7 +131,8 @@ type SignalRequest struct { // *SignalRequest_Trickle // *SignalRequest_AddTrack // *SignalRequest_Mute - // *SignalRequest_MuteSubscribed + // *SignalRequest_Subscription + // *SignalRequest_TrackSetting Message isSignalRequest_Message `protobuf_oneof:"message"` } @@ -160,9 +210,16 @@ func (x *SignalRequest) GetMute() *MuteTrackRequest { return nil } -func (x *SignalRequest) GetMuteSubscribed() *MuteTrackRequest { - if x, ok := x.GetMessage().(*SignalRequest_MuteSubscribed); ok { - return x.MuteSubscribed +func (x *SignalRequest) GetSubscription() *UpdateSubscription { + if x, ok := x.GetMessage().(*SignalRequest_Subscription); ok { + return x.Subscription + } + return nil +} + +func (x *SignalRequest) GetTrackSetting() *UpdateTrackSettings { + if x, ok := x.GetMessage().(*SignalRequest_TrackSetting); ok { + return x.TrackSetting } return nil } @@ -194,9 +251,14 @@ type SignalRequest_Mute struct { Mute *MuteTrackRequest `protobuf:"bytes,5,opt,name=mute,proto3,oneof"` } -type SignalRequest_MuteSubscribed struct { - // mute a track client is subscribed to - MuteSubscribed *MuteTrackRequest `protobuf:"bytes,6,opt,name=mute_subscribed,json=muteSubscribed,proto3,oneof"` +type SignalRequest_Subscription struct { + // Subscribe or unsubscribe from tracks + Subscription *UpdateSubscription `protobuf:"bytes,6,opt,name=subscription,proto3,oneof"` +} + +type SignalRequest_TrackSetting struct { + // Update settings of subscribed tracks + TrackSetting *UpdateTrackSettings `protobuf:"bytes,7,opt,name=track_setting,json=trackSetting,proto3,oneof"` } func (*SignalRequest_Offer) isSignalRequest_Message() {} @@ -209,7 +271,9 @@ func (*SignalRequest_AddTrack) isSignalRequest_Message() {} func (*SignalRequest_Mute) isSignalRequest_Message() {} -func (*SignalRequest_MuteSubscribed) isSignalRequest_Message() {} +func (*SignalRequest_Subscription) isSignalRequest_Message() {} + +func (*SignalRequest_TrackSetting) isSignalRequest_Message() {} type SignalResponse struct { state protoimpl.MessageState @@ -920,12 +984,146 @@ func (x *SpeakerInfo) GetActive() bool { return false } +type UpdateSubscription struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TrackSids []string `protobuf:"bytes,1,rep,name=track_sids,json=trackSids,proto3" json:"track_sids,omitempty"` + Subscribe bool `protobuf:"varint,2,opt,name=subscribe,proto3" json:"subscribe,omitempty"` + Mute bool `protobuf:"varint,3,opt,name=mute,proto3" json:"mute,omitempty"` + Quality VideoQuality `protobuf:"varint,4,opt,name=quality,proto3,enum=livekit.VideoQuality" json:"quality,omitempty"` +} + +func (x *UpdateSubscription) Reset() { + *x = UpdateSubscription{} + if protoimpl.UnsafeEnabled { + mi := &file_rtc_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateSubscription) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateSubscription) ProtoMessage() {} + +func (x *UpdateSubscription) ProtoReflect() protoreflect.Message { + mi := &file_rtc_proto_msgTypes[12] + 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 UpdateSubscription.ProtoReflect.Descriptor instead. +func (*UpdateSubscription) Descriptor() ([]byte, []int) { + return file_rtc_proto_rawDescGZIP(), []int{12} +} + +func (x *UpdateSubscription) GetTrackSids() []string { + if x != nil { + return x.TrackSids + } + return nil +} + +func (x *UpdateSubscription) GetSubscribe() bool { + if x != nil { + return x.Subscribe + } + return false +} + +func (x *UpdateSubscription) GetMute() bool { + if x != nil { + return x.Mute + } + return false +} + +func (x *UpdateSubscription) GetQuality() VideoQuality { + if x != nil { + return x.Quality + } + return VideoQuality_LOW +} + +type UpdateTrackSettings struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TrackSids []string `protobuf:"bytes,1,rep,name=track_sids,json=trackSids,proto3" json:"track_sids,omitempty"` + Mute bool `protobuf:"varint,3,opt,name=mute,proto3" json:"mute,omitempty"` + Quality VideoQuality `protobuf:"varint,4,opt,name=quality,proto3,enum=livekit.VideoQuality" json:"quality,omitempty"` +} + +func (x *UpdateTrackSettings) Reset() { + *x = UpdateTrackSettings{} + if protoimpl.UnsafeEnabled { + mi := &file_rtc_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateTrackSettings) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateTrackSettings) ProtoMessage() {} + +func (x *UpdateTrackSettings) ProtoReflect() protoreflect.Message { + mi := &file_rtc_proto_msgTypes[13] + 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 UpdateTrackSettings.ProtoReflect.Descriptor instead. +func (*UpdateTrackSettings) Descriptor() ([]byte, []int) { + return file_rtc_proto_rawDescGZIP(), []int{13} +} + +func (x *UpdateTrackSettings) GetTrackSids() []string { + if x != nil { + return x.TrackSids + } + return nil +} + +func (x *UpdateTrackSettings) GetMute() bool { + if x != nil { + return x.Mute + } + return false +} + +func (x *UpdateTrackSettings) GetQuality() VideoQuality { + if x != nil { + return x.Quality + } + return VideoQuality_LOW +} + 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, 0xeb, 0x02, 0x0a, 0x0d, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, + 0x6f, 0x22, 0xad, 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, @@ -942,101 +1140,125 @@ var file_rtc_proto_rawDesc = []byte{ 0x74, 0x48, 0x00, 0x52, 0x08, 0x61, 0x64, 0x64, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x75, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x4d, 0x75, 0x74, 0x65, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x04, 0x6d, 0x75, 0x74, 0x65, 0x12, 0x44, - 0x0a, 0x0f, 0x6d, 0x75, 0x74, 0x65, 0x5f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, - 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, - 0x74, 0x2e, 0x4d, 0x75, 0x74, 0x65, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x48, 0x00, 0x52, 0x0e, 0x6d, 0x75, 0x74, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, - 0x69, 0x62, 0x65, 0x64, 0x42, 0x09, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, - 0xa5, 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, 0x38, 0x0a, 0x07, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x65, 0x72, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x41, 0x63, - 0x74, 0x69, 0x76, 0x65, 0x53, 0x70, 0x65, 0x61, 0x6b, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x48, 0x00, 0x52, 0x07, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x65, 0x72, 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, 0x65, 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, - 0x12, 0x2d, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x15, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, - 0x6c, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 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, 0xdd, 0x01, 0x0a, 0x0c, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x21, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0d, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 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, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 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, 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, 0x22, 0x47, 0x0a, 0x13, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, - 0x53, 0x70, 0x65, 0x61, 0x6b, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x30, 0x0a, - 0x08, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x14, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x53, 0x70, 0x65, 0x61, 0x6b, 0x65, - 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x65, 0x72, 0x73, 0x22, - 0x4d, 0x0a, 0x0b, 0x53, 0x70, 0x65, 0x61, 0x6b, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, - 0x0a, 0x03, 0x73, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x69, 0x64, - 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x02, 0x52, - 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2a, 0x2d, - 0x0a, 0x0c, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x0d, - 0x0a, 0x09, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x45, 0x52, 0x10, 0x00, 0x12, 0x0e, 0x0a, - 0x0a, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x52, 0x10, 0x01, 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, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x04, 0x6d, 0x75, 0x74, 0x65, 0x12, 0x41, + 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x48, 0x00, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x43, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, + 0x6e, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, + 0x69, 0x74, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x53, 0x65, + 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x48, 0x00, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x53, + 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x42, 0x09, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x22, 0xa5, 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, 0x38, 0x0a, 0x07, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x65, 0x72, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, + 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x53, 0x70, 0x65, 0x61, 0x6b, 0x65, 0x72, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x07, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x65, 0x72, 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, 0x65, 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, 0x12, 0x2d, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x53, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, + 0x74, 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, 0xdd, 0x01, 0x0a, 0x0c, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x52, 0x6f, 0x6f, + 0x6d, 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, 0x12, 0x25, 0x0a, 0x0e, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 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, 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, 0x22, 0x47, 0x0a, 0x13, 0x41, 0x63, 0x74, 0x69, + 0x76, 0x65, 0x53, 0x70, 0x65, 0x61, 0x6b, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, + 0x30, 0x0a, 0x08, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x53, 0x70, 0x65, 0x61, + 0x6b, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x65, 0x72, + 0x73, 0x22, 0x4d, 0x0a, 0x0b, 0x53, 0x70, 0x65, 0x61, 0x6b, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, + 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, + 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x02, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, + 0x76, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, + 0x22, 0x96, 0x01, 0x0a, 0x12, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x72, 0x61, 0x63, 0x6b, + 0x5f, 0x73, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x74, 0x72, 0x61, + 0x63, 0x6b, 0x53, 0x69, 0x64, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, + 0x69, 0x62, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x75, 0x62, 0x73, 0x63, + 0x72, 0x69, 0x62, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x75, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x04, 0x6d, 0x75, 0x74, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x71, 0x75, 0x61, 0x6c, + 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x6c, 0x69, 0x76, 0x65, + 0x6b, 0x69, 0x74, 0x2e, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x51, 0x75, 0x61, 0x6c, 0x69, 0x74, 0x79, + 0x52, 0x07, 0x71, 0x75, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x22, 0x79, 0x0a, 0x13, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, + 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x5f, 0x73, 0x69, 0x64, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x53, 0x69, 0x64, 0x73, 0x12, + 0x12, 0x0a, 0x04, 0x6d, 0x75, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x6d, + 0x75, 0x74, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x71, 0x75, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x56, + 0x69, 0x64, 0x65, 0x6f, 0x51, 0x75, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x07, 0x71, 0x75, 0x61, + 0x6c, 0x69, 0x74, 0x79, 0x2a, 0x2d, 0x0a, 0x0c, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x54, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x12, 0x0d, 0x0a, 0x09, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x45, + 0x52, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, + 0x52, 0x10, 0x01, 0x2a, 0x2d, 0x0a, 0x0c, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x51, 0x75, 0x61, 0x6c, + 0x69, 0x74, 0x79, 0x12, 0x07, 0x0a, 0x03, 0x4c, 0x4f, 0x57, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, + 0x4d, 0x45, 0x44, 0x49, 0x55, 0x4d, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x49, 0x47, 0x48, + 0x10, 0x02, 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 ( @@ -1051,54 +1273,60 @@ func file_rtc_proto_rawDescGZIP() []byte { return file_rtc_proto_rawDescData } -var file_rtc_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_rtc_proto_msgTypes = make([]protoimpl.MessageInfo, 12) +var file_rtc_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_rtc_proto_msgTypes = make([]protoimpl.MessageInfo, 14) var file_rtc_proto_goTypes = []interface{}{ (SignalTarget)(0), // 0: livekit.SignalTarget - (*SignalRequest)(nil), // 1: livekit.SignalRequest - (*SignalResponse)(nil), // 2: livekit.SignalResponse - (*AddTrackRequest)(nil), // 3: livekit.AddTrackRequest - (*TrickleRequest)(nil), // 4: livekit.TrickleRequest - (*MuteTrackRequest)(nil), // 5: livekit.MuteTrackRequest - (*NegotiationRequest)(nil), // 6: livekit.NegotiationRequest - (*JoinResponse)(nil), // 7: livekit.JoinResponse - (*TrackPublishedResponse)(nil), // 8: livekit.TrackPublishedResponse - (*SessionDescription)(nil), // 9: livekit.SessionDescription - (*ParticipantUpdate)(nil), // 10: livekit.ParticipantUpdate - (*ActiveSpeakerUpdate)(nil), // 11: livekit.ActiveSpeakerUpdate - (*SpeakerInfo)(nil), // 12: livekit.SpeakerInfo - (TrackType)(0), // 13: livekit.TrackType - (*Room)(nil), // 14: livekit.Room - (*ParticipantInfo)(nil), // 15: livekit.ParticipantInfo - (*TrackInfo)(nil), // 16: livekit.TrackInfo + (VideoQuality)(0), // 1: livekit.VideoQuality + (*SignalRequest)(nil), // 2: livekit.SignalRequest + (*SignalResponse)(nil), // 3: livekit.SignalResponse + (*AddTrackRequest)(nil), // 4: livekit.AddTrackRequest + (*TrickleRequest)(nil), // 5: livekit.TrickleRequest + (*MuteTrackRequest)(nil), // 6: livekit.MuteTrackRequest + (*NegotiationRequest)(nil), // 7: livekit.NegotiationRequest + (*JoinResponse)(nil), // 8: livekit.JoinResponse + (*TrackPublishedResponse)(nil), // 9: livekit.TrackPublishedResponse + (*SessionDescription)(nil), // 10: livekit.SessionDescription + (*ParticipantUpdate)(nil), // 11: livekit.ParticipantUpdate + (*ActiveSpeakerUpdate)(nil), // 12: livekit.ActiveSpeakerUpdate + (*SpeakerInfo)(nil), // 13: livekit.SpeakerInfo + (*UpdateSubscription)(nil), // 14: livekit.UpdateSubscription + (*UpdateTrackSettings)(nil), // 15: livekit.UpdateTrackSettings + (TrackType)(0), // 16: livekit.TrackType + (*Room)(nil), // 17: livekit.Room + (*ParticipantInfo)(nil), // 18: livekit.ParticipantInfo + (*TrackInfo)(nil), // 19: livekit.TrackInfo } var file_rtc_proto_depIdxs = []int32{ - 9, // 0: livekit.SignalRequest.offer:type_name -> livekit.SessionDescription - 9, // 1: livekit.SignalRequest.answer:type_name -> livekit.SessionDescription - 4, // 2: livekit.SignalRequest.trickle:type_name -> livekit.TrickleRequest - 3, // 3: livekit.SignalRequest.add_track:type_name -> livekit.AddTrackRequest - 5, // 4: livekit.SignalRequest.mute:type_name -> livekit.MuteTrackRequest - 5, // 5: livekit.SignalRequest.mute_subscribed:type_name -> livekit.MuteTrackRequest - 7, // 6: livekit.SignalResponse.join:type_name -> livekit.JoinResponse - 9, // 7: livekit.SignalResponse.answer:type_name -> livekit.SessionDescription - 9, // 8: livekit.SignalResponse.offer:type_name -> livekit.SessionDescription - 4, // 9: livekit.SignalResponse.trickle:type_name -> livekit.TrickleRequest - 10, // 10: livekit.SignalResponse.update:type_name -> livekit.ParticipantUpdate - 8, // 11: livekit.SignalResponse.track_published:type_name -> livekit.TrackPublishedResponse - 11, // 12: livekit.SignalResponse.speaker:type_name -> livekit.ActiveSpeakerUpdate - 13, // 13: livekit.AddTrackRequest.type:type_name -> livekit.TrackType - 0, // 14: livekit.TrickleRequest.target:type_name -> livekit.SignalTarget - 14, // 15: livekit.JoinResponse.room:type_name -> livekit.Room - 15, // 16: livekit.JoinResponse.participant:type_name -> livekit.ParticipantInfo - 15, // 17: livekit.JoinResponse.other_participants:type_name -> livekit.ParticipantInfo - 16, // 18: livekit.TrackPublishedResponse.track:type_name -> livekit.TrackInfo - 15, // 19: livekit.ParticipantUpdate.participants:type_name -> livekit.ParticipantInfo - 12, // 20: livekit.ActiveSpeakerUpdate.speakers:type_name -> livekit.SpeakerInfo - 21, // [21:21] is the sub-list for method output_type - 21, // [21:21] is the sub-list for method input_type - 21, // [21:21] is the sub-list for extension type_name - 21, // [21:21] is the sub-list for extension extendee - 0, // [0:21] is the sub-list for field type_name + 10, // 0: livekit.SignalRequest.offer:type_name -> livekit.SessionDescription + 10, // 1: livekit.SignalRequest.answer:type_name -> livekit.SessionDescription + 5, // 2: livekit.SignalRequest.trickle:type_name -> livekit.TrickleRequest + 4, // 3: livekit.SignalRequest.add_track:type_name -> livekit.AddTrackRequest + 6, // 4: livekit.SignalRequest.mute:type_name -> livekit.MuteTrackRequest + 14, // 5: livekit.SignalRequest.subscription:type_name -> livekit.UpdateSubscription + 15, // 6: livekit.SignalRequest.track_setting:type_name -> livekit.UpdateTrackSettings + 8, // 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 + 5, // 10: livekit.SignalResponse.trickle:type_name -> livekit.TrickleRequest + 11, // 11: livekit.SignalResponse.update:type_name -> livekit.ParticipantUpdate + 9, // 12: livekit.SignalResponse.track_published:type_name -> livekit.TrackPublishedResponse + 12, // 13: livekit.SignalResponse.speaker:type_name -> livekit.ActiveSpeakerUpdate + 16, // 14: livekit.AddTrackRequest.type:type_name -> livekit.TrackType + 0, // 15: livekit.TrickleRequest.target:type_name -> livekit.SignalTarget + 17, // 16: livekit.JoinResponse.room:type_name -> livekit.Room + 18, // 17: livekit.JoinResponse.participant:type_name -> livekit.ParticipantInfo + 18, // 18: livekit.JoinResponse.other_participants:type_name -> livekit.ParticipantInfo + 19, // 19: livekit.TrackPublishedResponse.track:type_name -> livekit.TrackInfo + 18, // 20: livekit.ParticipantUpdate.participants:type_name -> livekit.ParticipantInfo + 13, // 21: livekit.ActiveSpeakerUpdate.speakers:type_name -> livekit.SpeakerInfo + 1, // 22: livekit.UpdateSubscription.quality:type_name -> livekit.VideoQuality + 1, // 23: livekit.UpdateTrackSettings.quality:type_name -> livekit.VideoQuality + 24, // [24:24] is the sub-list for method output_type + 24, // [24:24] is the sub-list for method input_type + 24, // [24:24] is the sub-list for extension type_name + 24, // [24:24] is the sub-list for extension extendee + 0, // [0:24] is the sub-list for field type_name } func init() { file_rtc_proto_init() } @@ -1252,6 +1480,30 @@ func file_rtc_proto_init() { return nil } } + file_rtc_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateSubscription); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rtc_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateTrackSettings); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } file_rtc_proto_msgTypes[0].OneofWrappers = []interface{}{ (*SignalRequest_Offer)(nil), @@ -1259,7 +1511,8 @@ func file_rtc_proto_init() { (*SignalRequest_Trickle)(nil), (*SignalRequest_AddTrack)(nil), (*SignalRequest_Mute)(nil), - (*SignalRequest_MuteSubscribed)(nil), + (*SignalRequest_Subscription)(nil), + (*SignalRequest_TrackSetting)(nil), } file_rtc_proto_msgTypes[1].OneofWrappers = []interface{}{ (*SignalResponse_Join)(nil), @@ -1275,8 +1528,8 @@ func file_rtc_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_rtc_proto_rawDesc, - NumEnums: 1, - NumMessages: 12, + NumEnums: 2, + NumMessages: 14, NumExtensions: 0, NumServices: 0, }, diff --git a/proto/rtc.proto b/proto/rtc.proto index 13a2249d0..33f42e268 100644 --- a/proto/rtc.proto +++ b/proto/rtc.proto @@ -15,8 +15,10 @@ message SignalRequest { AddTrackRequest add_track = 4; // mute the participant's own tracks MuteTrackRequest mute = 5; - // mute a track client is subscribed to - MuteTrackRequest mute_subscribed = 6; + // Subscribe or unsubscribe from tracks + UpdateSubscription subscription = 6; + // Update settings of subscribed tracks + UpdateTrackSettings track_setting = 7; } } @@ -97,3 +99,22 @@ message SpeakerInfo { // true if speaker is currently active bool active = 3; } + +enum VideoQuality { + LOW = 0; + MEDIUM = 1; + HIGH = 2; +} + +message UpdateSubscription { + repeated string track_sids = 1; + bool subscribe = 2; + bool mute = 3; + VideoQuality quality = 4; +} + +message UpdateTrackSettings { + repeated string track_sids = 1; + bool mute = 3; + VideoQuality quality = 4; +} \ No newline at end of file