RoomService.updateParticipantMetadata, participant permissions

This commit is contained in:
David Zhao
2021-03-16 01:22:21 -07:00
parent e04eaeb480
commit f7ed2cee60
19 changed files with 1113 additions and 325 deletions
+9 -2
View File
@@ -23,7 +23,14 @@ type MessageSource interface {
ReadChan() <-chan proto.Message
}
type NewParticipantCallback func(roomName, identity, metadata string, reconnect bool, requestSource MessageSource, responseSink MessageSink)
type ParticipantInit struct {
Identity string
Metadata string
Reconnect bool
Permission *livekit.ParticipantPermission
}
type NewParticipantCallback func(roomName string, pi ParticipantInit, requestSource MessageSource, responseSink MessageSink)
type RTCMessageCallback func(roomName, identity string, msg *livekit.RTCNodeMessage)
// Router allows multiple nodes to coordinate the participant session
@@ -39,7 +46,7 @@ type Router interface {
ListNodes() ([]*livekit.Node, error)
// participant signal connection is ready to start
StartParticipantSignal(roomName, identity, metadata string, reconnect bool) (connectionId string, reqSink MessageSink, resSource MessageSource, err error)
StartParticipantSignal(roomName string, pi ParticipantInit) (connectionId string, reqSink MessageSink, resSource MessageSource, err error)
// sends a message to RTC node
CreateRTCSink(roomName, identity string) (MessageSink, error)
+4 -6
View File
@@ -71,7 +71,7 @@ func (r *LocalRouter) ListNodes() ([]*livekit.Node, error) {
}, nil
}
func (r *LocalRouter) StartParticipantSignal(roomName, identity, metadata string, reconnect bool) (connectionId string, reqSink MessageSink, resSource MessageSource, err error) {
func (r *LocalRouter) StartParticipantSignal(roomName string, pi ParticipantInit) (connectionId string, reqSink MessageSink, resSource MessageSource, err error) {
// treat it as a new participant connecting
if r.onNewParticipant == nil {
err = ErrHandlerNotDefined
@@ -79,21 +79,19 @@ func (r *LocalRouter) StartParticipantSignal(roomName, identity, metadata string
}
// index channels by roomName | identity
key := participantKey(roomName, identity)
key := participantKey(roomName, pi.Identity)
reqChan := r.getOrCreateMessageChannel(r.requestChannels, key)
resChan := r.getOrCreateMessageChannel(r.responseChannels, key)
r.onNewParticipant(
roomName,
identity,
metadata,
reconnect,
pi,
// request source
reqChan,
// response sink
resChan,
)
return identity, reqChan, resChan, nil
return pi.Identity, reqChan, resChan, nil
}
func (r *LocalRouter) CreateRTCSink(roomName, identity string) (MessageSink, error) {
+14 -8
View File
@@ -129,7 +129,7 @@ func (r *RedisRouter) ListNodes() ([]*livekit.Node, error) {
}
// signal connection sets up paths to the RTC node, and starts to route messages to that message queue
func (r *RedisRouter) StartParticipantSignal(roomName, identity, metadata string, reconnect bool) (connectionId string, reqSink MessageSink, resSource MessageSource, err error) {
func (r *RedisRouter) StartParticipantSignal(roomName string, pi ParticipantInit) (connectionId string, reqSink MessageSink, resSource MessageSource, err error) {
// find the node where the room is hosted at
rtcNode, err := r.GetNodeForRoom(roomName)
if err != nil {
@@ -138,7 +138,7 @@ func (r *RedisRouter) StartParticipantSignal(roomName, identity, metadata string
// create a new connection id
connectionId = utils.NewGuid("CO_")
pKey := participantKey(roomName, identity)
pKey := participantKey(roomName, pi.Identity)
// map signal & rtc nodes
if err = r.setParticipantSignalNode(connectionId, r.currentNode.Id); err != nil {
@@ -150,11 +150,12 @@ func (r *RedisRouter) StartParticipantSignal(roomName, identity, metadata string
// sends a message to start session
err = sink.WriteMessage(&livekit.StartSession{
RoomName: roomName,
Identity: identity,
Metadata: metadata,
Identity: pi.Identity,
Metadata: pi.Metadata,
// connection id is to allow the RTC node to identify where to route the message back to
ConnectionId: connectionId,
Reconnect: reconnect,
Reconnect: pi.Reconnect,
Permission: pi.Permission,
})
if err != nil {
return
@@ -215,13 +216,18 @@ func (r *RedisRouter) startParticipantRTC(ss *livekit.StartSession, participantK
}
}
pi := ParticipantInit{
Identity: ss.Identity,
Metadata: ss.Metadata,
Reconnect: ss.Reconnect,
Permission: ss.Permission,
}
reqChan := r.getOrCreateMessageChannel(r.requestChannels, participantKey)
resSink := NewSignalNodeSink(r.rc, signalNode, ss.ConnectionId)
r.onNewParticipant(
ss.RoomName,
ss.Identity,
ss.Metadata,
ss.Reconnect,
pi,
reqChan,
resSink,
)
+10 -14
View File
@@ -124,13 +124,11 @@ type FakeRouter struct {
startReturnsOnCall map[int]struct {
result1 error
}
StartParticipantSignalStub func(string, string, string, bool) (string, routing.MessageSink, routing.MessageSource, error)
StartParticipantSignalStub func(string, routing.ParticipantInit) (string, routing.MessageSink, routing.MessageSource, error)
startParticipantSignalMutex sync.RWMutex
startParticipantSignalArgsForCall []struct {
arg1 string
arg2 string
arg3 string
arg4 bool
arg2 routing.ParticipantInit
}
startParticipantSignalReturns struct {
result1 string
@@ -757,21 +755,19 @@ func (fake *FakeRouter) StartReturnsOnCall(i int, result1 error) {
}{result1}
}
func (fake *FakeRouter) StartParticipantSignal(arg1 string, arg2 string, arg3 string, arg4 bool) (string, routing.MessageSink, routing.MessageSource, error) {
func (fake *FakeRouter) StartParticipantSignal(arg1 string, arg2 routing.ParticipantInit) (string, routing.MessageSink, routing.MessageSource, error) {
fake.startParticipantSignalMutex.Lock()
ret, specificReturn := fake.startParticipantSignalReturnsOnCall[len(fake.startParticipantSignalArgsForCall)]
fake.startParticipantSignalArgsForCall = append(fake.startParticipantSignalArgsForCall, struct {
arg1 string
arg2 string
arg3 string
arg4 bool
}{arg1, arg2, arg3, arg4})
arg2 routing.ParticipantInit
}{arg1, arg2})
stub := fake.StartParticipantSignalStub
fakeReturns := fake.startParticipantSignalReturns
fake.recordInvocation("StartParticipantSignal", []interface{}{arg1, arg2, arg3, arg4})
fake.recordInvocation("StartParticipantSignal", []interface{}{arg1, arg2})
fake.startParticipantSignalMutex.Unlock()
if stub != nil {
return stub(arg1, arg2, arg3, arg4)
return stub(arg1, arg2)
}
if specificReturn {
return ret.result1, ret.result2, ret.result3, ret.result4
@@ -785,17 +781,17 @@ func (fake *FakeRouter) StartParticipantSignalCallCount() int {
return len(fake.startParticipantSignalArgsForCall)
}
func (fake *FakeRouter) StartParticipantSignalCalls(stub func(string, string, string, bool) (string, routing.MessageSink, routing.MessageSource, error)) {
func (fake *FakeRouter) StartParticipantSignalCalls(stub func(string, routing.ParticipantInit) (string, routing.MessageSink, routing.MessageSource, error)) {
fake.startParticipantSignalMutex.Lock()
defer fake.startParticipantSignalMutex.Unlock()
fake.StartParticipantSignalStub = stub
}
func (fake *FakeRouter) StartParticipantSignalArgsForCall(i int) (string, string, string, bool) {
func (fake *FakeRouter) StartParticipantSignalArgsForCall(i int) (string, routing.ParticipantInit) {
fake.startParticipantSignalMutex.RLock()
defer fake.startParticipantSignalMutex.RUnlock()
argsForCall := fake.startParticipantSignalArgsForCall[i]
return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4
return argsForCall.arg1, argsForCall.arg2
}
func (fake *FakeRouter) StartParticipantSignalReturns(result1 string, result2 routing.MessageSink, result3 routing.MessageSource, result4 error) {
+41 -9
View File
@@ -38,9 +38,10 @@ type ParticipantImpl struct {
conf *WebRTCConfig
identity string
// JSON encoded metadata to pass to clients
metadata string
state atomic.Value // livekit.ParticipantInfo_State
rtcpCh chan []rtcp.Packet
metadata string
permission *livekit.ParticipantPermission
state atomic.Value // livekit.ParticipantInfo_State
rtcpCh chan []rtcp.Packet
// hold reference for MediaTrack
twcc *twcc.Responder
@@ -59,6 +60,7 @@ type ParticipantImpl struct {
onTrackPublished func(types.Participant, types.PublishedTrack)
onTrackUpdated func(types.Participant, types.PublishedTrack)
onStateChange func(p types.Participant, oldState livekit.ParticipantInfo_State)
onMetadataUpdate func(types.Participant)
onClose func(types.Participant)
}
@@ -140,18 +142,24 @@ func (p *ParticipantImpl) IsReady() bool {
func (p *ParticipantImpl) SetMetadata(metadata map[string]interface{}) error {
if metadata == nil {
p.metadata = ""
return nil
}
if data, err := json.Marshal(metadata); err != nil {
return err
} else {
p.metadata = string(data)
if data, err := json.Marshal(metadata); err != nil {
return err
} else {
p.metadata = string(data)
}
}
if p.onMetadataUpdate != nil {
p.onMetadataUpdate(p)
}
return nil
}
func (p *ParticipantImpl) SetPermission(permission *livekit.ParticipantPermission) {
p.permission = permission
}
func (p *ParticipantImpl) RTCPChan() chan []rtcp.Packet {
return p.rtcpCh
}
@@ -197,6 +205,10 @@ func (p *ParticipantImpl) OnTrackUpdated(callback func(types.Participant, types.
p.onTrackUpdated = callback
}
func (p *ParticipantImpl) OnMetadataUpdate(callback func(types.Participant)) {
p.onMetadataUpdate = callback
}
func (p *ParticipantImpl) OnClose(callback func(types.Participant)) {
p.onClose = callback
}
@@ -459,6 +471,14 @@ func (p *ParticipantImpl) GetAudioLevel() (level uint8, noisy bool) {
return
}
func (p *ParticipantImpl) CanPublish() bool {
return p.permission == nil || p.permission.CanPublish
}
func (p *ParticipantImpl) CanSubscribe() bool {
return p.permission == nil || p.permission.CanSubscribe
}
func (p *ParticipantImpl) SubscriberPC() *webrtc.PeerConnection {
return p.subscriber.pc
}
@@ -580,6 +600,12 @@ func (p *ParticipantImpl) onMediaTrack(track *webrtc.TrackRemote, rtpReceiver *w
"remoteTrack", track.ID(),
"rid", track.RID())
if !p.CanPublish() {
logger.Warnw("no permission to publish mediaTrack",
"participant", p.Identity())
return
}
// delete pending track if it's not simulcasting
ti := p.getPendingTrack(track.ID(), ToProtoTrackKind(track.Kind()), track.RID() == "")
if ti == nil {
@@ -620,6 +646,12 @@ func (p *ParticipantImpl) onDataChannel(dc *webrtc.DataChannel) {
}
logger.Debugw("dataChannel added", "participant", p.Identity(), "label", dc.Label())
if !p.CanPublish() {
logger.Warnw("no permission to publish dataTrack",
"participant", p.Identity())
return
}
// data channels have numeric ids, so we use its label to identify
ti := p.getPendingTrack(dc.Label(), livekit.TrackType_DATA, true)
if ti == nil {
+15 -7
View File
@@ -137,7 +137,7 @@ func (r *Room) Join(participant types.Participant) error {
if r.onParticipantChanged != nil {
r.onParticipantChanged(participant)
}
r.broadcastParticipantState(p)
r.broadcastParticipantState(p, true)
if p.State() == livekit.ParticipantInfo_ACTIVE {
// subscribe participant to existing publishedTracks
@@ -161,7 +161,7 @@ func (r *Room) Join(participant types.Participant) error {
}
})
participant.OnTrackUpdated(r.onTrackUpdated)
participant.OnMetadataUpdate(r.onParticipantMetadataUpdate)
logger.Infow("new participant joined",
"id", participant.ID(),
"identity", participant.Identity(),
@@ -213,7 +213,7 @@ func (r *Room) RemoveParticipant(identity string) {
if r.onParticipantChanged != nil {
r.onParticipantChanged(p)
}
r.broadcastParticipantState(p)
r.broadcastParticipantState(p, true)
}
}
@@ -288,7 +288,7 @@ func (r *Room) OnParticipantChanged(f func(participant types.Participant)) {
// a ParticipantImpl in the room added a new remoteTrack, subscribe other participants to it
func (r *Room) onTrackAdded(participant types.Participant, track types.PublishedTrack) {
// publish participant update, since track state is changed
r.broadcastParticipantState(participant)
r.broadcastParticipantState(participant, true)
r.lock.RLock()
defer r.lock.RUnlock()
@@ -322,19 +322,27 @@ func (r *Room) onTrackAdded(participant types.Participant, track types.Published
}
func (r *Room) onTrackUpdated(p types.Participant, track types.PublishedTrack) {
r.broadcastParticipantState(p)
// send track updates to everyone, especially if track was updated by admin
r.broadcastParticipantState(p, false)
if r.onParticipantChanged != nil {
r.onParticipantChanged(p)
}
}
func (r *Room) onParticipantMetadataUpdate(p types.Participant) {
r.broadcastParticipantState(p, false)
if r.onParticipantChanged != nil {
r.onParticipantChanged(p)
}
}
// broadcast an update about participant p
func (r *Room) broadcastParticipantState(p types.Participant) {
func (r *Room) broadcastParticipantState(p types.Participant, skipSource bool) {
updates := ToProtoParticipants([]types.Participant{p})
participants := r.GetParticipants()
for _, op := range participants {
// skip itself && closed participants
if p.ID() == op.ID() || op.State() == livekit.ParticipantInfo_DISCONNECTED {
if (skipSource && p.ID() == op.ID()) || op.State() == livekit.ParticipantInfo_DISCONNECTED {
continue
}
+6
View File
@@ -29,6 +29,7 @@ type Participant interface {
ToProto() *livekit.ParticipantInfo
RTCPChan() chan []rtcp.Packet
SetMetadata(metadata map[string]interface{}) error
SetPermission(permission *livekit.ParticipantPermission)
GetResponseSink() routing.MessageSink
SetResponseSink(sink routing.MessageSink)
SubscriberMediaEngine() *webrtc.MediaEngine
@@ -47,6 +48,10 @@ type Participant interface {
SetTrackMuted(trackId string, muted bool)
GetAudioLevel() (level uint8, noisy bool)
// permissions
CanPublish() bool
CanSubscribe() bool
Start()
Close() error
@@ -56,6 +61,7 @@ type Participant interface {
OnTrackPublished(func(Participant, PublishedTrack))
// OnTrackUpdated - one of its publishedTracks changed in status
OnTrackUpdated(callback func(Participant, PublishedTrack))
OnMetadataUpdate(callback func(Participant))
OnClose(func(Participant))
// package methods
@@ -48,6 +48,26 @@ type FakeParticipant struct {
arg2 string
arg3 livekit.TrackType
}
CanPublishStub func() bool
canPublishMutex sync.RWMutex
canPublishArgsForCall []struct {
}
canPublishReturns struct {
result1 bool
}
canPublishReturnsOnCall map[int]struct {
result1 bool
}
CanSubscribeStub func() bool
canSubscribeMutex sync.RWMutex
canSubscribeArgsForCall []struct {
}
canSubscribeReturns struct {
result1 bool
}
canSubscribeReturnsOnCall map[int]struct {
result1 bool
}
CloseStub func() error
closeMutex sync.RWMutex
closeArgsForCall []struct {
@@ -159,6 +179,11 @@ type FakeParticipant struct {
onCloseArgsForCall []struct {
arg1 func(types.Participant)
}
OnMetadataUpdateStub func(func(types.Participant))
onMetadataUpdateMutex sync.RWMutex
onMetadataUpdateArgsForCall []struct {
arg1 func(types.Participant)
}
OnStateChangeStub func(func(p types.Participant, oldState livekit.ParticipantInfo_State))
onStateChangeMutex sync.RWMutex
onStateChangeArgsForCall []struct {
@@ -241,6 +266,11 @@ type FakeParticipant struct {
setMetadataReturnsOnCall map[int]struct {
result1 error
}
SetPermissionStub func(*livekit.ParticipantPermission)
setPermissionMutex sync.RWMutex
setPermissionArgsForCall []struct {
arg1 *livekit.ParticipantPermission
}
SetResponseSinkStub func(routing.MessageSink)
setResponseSinkMutex sync.RWMutex
setResponseSinkArgsForCall []struct {
@@ -490,6 +520,112 @@ func (fake *FakeParticipant) AddTrackArgsForCall(i int) (string, string, livekit
return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3
}
func (fake *FakeParticipant) CanPublish() bool {
fake.canPublishMutex.Lock()
ret, specificReturn := fake.canPublishReturnsOnCall[len(fake.canPublishArgsForCall)]
fake.canPublishArgsForCall = append(fake.canPublishArgsForCall, struct {
}{})
stub := fake.CanPublishStub
fakeReturns := fake.canPublishReturns
fake.recordInvocation("CanPublish", []interface{}{})
fake.canPublishMutex.Unlock()
if stub != nil {
return stub()
}
if specificReturn {
return ret.result1
}
return fakeReturns.result1
}
func (fake *FakeParticipant) CanPublishCallCount() int {
fake.canPublishMutex.RLock()
defer fake.canPublishMutex.RUnlock()
return len(fake.canPublishArgsForCall)
}
func (fake *FakeParticipant) CanPublishCalls(stub func() bool) {
fake.canPublishMutex.Lock()
defer fake.canPublishMutex.Unlock()
fake.CanPublishStub = stub
}
func (fake *FakeParticipant) CanPublishReturns(result1 bool) {
fake.canPublishMutex.Lock()
defer fake.canPublishMutex.Unlock()
fake.CanPublishStub = nil
fake.canPublishReturns = struct {
result1 bool
}{result1}
}
func (fake *FakeParticipant) CanPublishReturnsOnCall(i int, result1 bool) {
fake.canPublishMutex.Lock()
defer fake.canPublishMutex.Unlock()
fake.CanPublishStub = nil
if fake.canPublishReturnsOnCall == nil {
fake.canPublishReturnsOnCall = make(map[int]struct {
result1 bool
})
}
fake.canPublishReturnsOnCall[i] = struct {
result1 bool
}{result1}
}
func (fake *FakeParticipant) CanSubscribe() bool {
fake.canSubscribeMutex.Lock()
ret, specificReturn := fake.canSubscribeReturnsOnCall[len(fake.canSubscribeArgsForCall)]
fake.canSubscribeArgsForCall = append(fake.canSubscribeArgsForCall, struct {
}{})
stub := fake.CanSubscribeStub
fakeReturns := fake.canSubscribeReturns
fake.recordInvocation("CanSubscribe", []interface{}{})
fake.canSubscribeMutex.Unlock()
if stub != nil {
return stub()
}
if specificReturn {
return ret.result1
}
return fakeReturns.result1
}
func (fake *FakeParticipant) CanSubscribeCallCount() int {
fake.canSubscribeMutex.RLock()
defer fake.canSubscribeMutex.RUnlock()
return len(fake.canSubscribeArgsForCall)
}
func (fake *FakeParticipant) CanSubscribeCalls(stub func() bool) {
fake.canSubscribeMutex.Lock()
defer fake.canSubscribeMutex.Unlock()
fake.CanSubscribeStub = stub
}
func (fake *FakeParticipant) CanSubscribeReturns(result1 bool) {
fake.canSubscribeMutex.Lock()
defer fake.canSubscribeMutex.Unlock()
fake.CanSubscribeStub = nil
fake.canSubscribeReturns = struct {
result1 bool
}{result1}
}
func (fake *FakeParticipant) CanSubscribeReturnsOnCall(i int, result1 bool) {
fake.canSubscribeMutex.Lock()
defer fake.canSubscribeMutex.Unlock()
fake.CanSubscribeStub = nil
if fake.canSubscribeReturnsOnCall == nil {
fake.canSubscribeReturnsOnCall = make(map[int]struct {
result1 bool
})
}
fake.canSubscribeReturnsOnCall[i] = struct {
result1 bool
}{result1}
}
func (fake *FakeParticipant) Close() error {
fake.closeMutex.Lock()
ret, specificReturn := fake.closeReturnsOnCall[len(fake.closeArgsForCall)]
@@ -1074,6 +1210,38 @@ func (fake *FakeParticipant) OnCloseArgsForCall(i int) func(types.Participant) {
return argsForCall.arg1
}
func (fake *FakeParticipant) OnMetadataUpdate(arg1 func(types.Participant)) {
fake.onMetadataUpdateMutex.Lock()
fake.onMetadataUpdateArgsForCall = append(fake.onMetadataUpdateArgsForCall, struct {
arg1 func(types.Participant)
}{arg1})
stub := fake.OnMetadataUpdateStub
fake.recordInvocation("OnMetadataUpdate", []interface{}{arg1})
fake.onMetadataUpdateMutex.Unlock()
if stub != nil {
fake.OnMetadataUpdateStub(arg1)
}
}
func (fake *FakeParticipant) OnMetadataUpdateCallCount() int {
fake.onMetadataUpdateMutex.RLock()
defer fake.onMetadataUpdateMutex.RUnlock()
return len(fake.onMetadataUpdateArgsForCall)
}
func (fake *FakeParticipant) OnMetadataUpdateCalls(stub func(func(types.Participant))) {
fake.onMetadataUpdateMutex.Lock()
defer fake.onMetadataUpdateMutex.Unlock()
fake.OnMetadataUpdateStub = stub
}
func (fake *FakeParticipant) OnMetadataUpdateArgsForCall(i int) func(types.Participant) {
fake.onMetadataUpdateMutex.RLock()
defer fake.onMetadataUpdateMutex.RUnlock()
argsForCall := fake.onMetadataUpdateArgsForCall[i]
return argsForCall.arg1
}
func (fake *FakeParticipant) OnStateChange(arg1 func(p types.Participant, oldState livekit.ParticipantInfo_State)) {
fake.onStateChangeMutex.Lock()
fake.onStateChangeArgsForCall = append(fake.onStateChangeArgsForCall, struct {
@@ -1554,6 +1722,38 @@ func (fake *FakeParticipant) SetMetadataReturnsOnCall(i int, result1 error) {
}{result1}
}
func (fake *FakeParticipant) SetPermission(arg1 *livekit.ParticipantPermission) {
fake.setPermissionMutex.Lock()
fake.setPermissionArgsForCall = append(fake.setPermissionArgsForCall, struct {
arg1 *livekit.ParticipantPermission
}{arg1})
stub := fake.SetPermissionStub
fake.recordInvocation("SetPermission", []interface{}{arg1})
fake.setPermissionMutex.Unlock()
if stub != nil {
fake.SetPermissionStub(arg1)
}
}
func (fake *FakeParticipant) SetPermissionCallCount() int {
fake.setPermissionMutex.RLock()
defer fake.setPermissionMutex.RUnlock()
return len(fake.setPermissionArgsForCall)
}
func (fake *FakeParticipant) SetPermissionCalls(stub func(*livekit.ParticipantPermission)) {
fake.setPermissionMutex.Lock()
defer fake.setPermissionMutex.Unlock()
fake.SetPermissionStub = stub
}
func (fake *FakeParticipant) SetPermissionArgsForCall(i int) *livekit.ParticipantPermission {
fake.setPermissionMutex.RLock()
defer fake.setPermissionMutex.RUnlock()
argsForCall := fake.setPermissionArgsForCall[i]
return argsForCall.arg1
}
func (fake *FakeParticipant) SetResponseSink(arg1 routing.MessageSink) {
fake.setResponseSinkMutex.Lock()
fake.setResponseSinkArgsForCall = append(fake.setResponseSinkArgsForCall, struct {
@@ -1866,6 +2066,10 @@ func (fake *FakeParticipant) Invocations() map[string][][]interface{} {
defer fake.addSubscriberMutex.RUnlock()
fake.addTrackMutex.RLock()
defer fake.addTrackMutex.RUnlock()
fake.canPublishMutex.RLock()
defer fake.canPublishMutex.RUnlock()
fake.canSubscribeMutex.RLock()
defer fake.canSubscribeMutex.RUnlock()
fake.closeMutex.RLock()
defer fake.closeMutex.RUnlock()
fake.getAudioLevelMutex.RLock()
@@ -1888,6 +2092,8 @@ func (fake *FakeParticipant) Invocations() map[string][][]interface{} {
defer fake.isReadyMutex.RUnlock()
fake.onCloseMutex.RLock()
defer fake.onCloseMutex.RUnlock()
fake.onMetadataUpdateMutex.RLock()
defer fake.onMetadataUpdateMutex.RUnlock()
fake.onStateChangeMutex.RLock()
defer fake.onStateChangeMutex.RUnlock()
fake.onTrackPublishedMutex.RLock()
@@ -1908,6 +2114,8 @@ func (fake *FakeParticipant) Invocations() map[string][][]interface{} {
defer fake.sendParticipantUpdateMutex.RUnlock()
fake.setMetadataMutex.RLock()
defer fake.setMetadataMutex.RUnlock()
fake.setPermissionMutex.RLock()
defer fake.setPermissionMutex.RUnlock()
fake.setResponseSinkMutex.RLock()
defer fake.setResponseSinkMutex.RUnlock()
fake.setTrackMutedMutex.RLock()
+29 -9
View File
@@ -172,22 +172,22 @@ func (r *RoomManager) CloseIdleRooms() {
}
// starts WebRTC session when a new participant is connected, takes place on RTC node
func (r *RoomManager) StartSession(roomName, identity, metadata string, reconnect bool, requestSource routing.MessageSource, responseSink routing.MessageSink) {
func (r *RoomManager) StartSession(roomName string, pi routing.ParticipantInit, requestSource routing.MessageSource, responseSink routing.MessageSink) {
room, err := r.getOrCreateRoom(roomName)
if err != nil {
logger.Errorw("could not create room", "error", err)
return
}
participant := room.GetParticipant(identity)
participant := room.GetParticipant(pi.Identity)
if participant != nil {
// When reconnecting, it means WS has interrupted by underlying peer connection is still ok
// in this mode, we'll keep the participant SID, and just swap the sink for the underlying connection
if reconnect {
if pi.Reconnect {
logger.Debugw("resuming RTC session",
"room", roomName,
"node", r.currentNode.Id,
"participant", identity,
"participant", pi.Identity,
)
// close previous sink, and link to new one
prevSink := participant.GetResponseSink()
@@ -206,22 +206,26 @@ func (r *RoomManager) StartSession(roomName, identity, metadata string, reconnec
logger.Debugw("starting RTC session",
"room", roomName,
"node", r.currentNode.Id,
"participant", identity,
"participant", pi.Identity,
"num_participants", len(room.GetParticipants()),
)
participant, err = rtc.NewParticipant(identity, r.rtcConfig, responseSink, r.config.Audio)
participant, err = rtc.NewParticipant(pi.Identity, r.rtcConfig, responseSink, r.config.Audio)
if err != nil {
logger.Errorw("could not create participant", "error", err)
return
}
if metadata != "" {
if pi.Metadata != "" {
var md map[string]interface{}
if err := json.Unmarshal([]byte(metadata), &md); err == nil {
if err := json.Unmarshal([]byte(pi.Metadata), &md); err == nil {
participant.SetMetadata(md)
}
}
if pi.Permission != nil {
participant.SetPermission(pi.Permission)
}
// join room
if err := room.Join(participant); err != nil {
logger.Errorw("could not join room", "error", err)
@@ -334,7 +338,13 @@ 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)
if participant.CanSubscribe() {
room.UpdateSubscriptions(participant, msg.Subscription)
} else {
logger.Warnw("rejected participant subscription",
"participant", participant.Identity(),
"tracks", msg.Subscription.TrackSids)
}
case *livekit.SignalRequest_TrackSetting:
for _, subTrack := range participant.GetSubscribedTracks() {
for _, sid := range msg.TrackSetting.TrackSids {
@@ -373,6 +383,16 @@ func (r *RoomManager) handleRTCMessage(roomName, identity string, msg *livekit.R
logger.Debugw("setting track muted", "room", roomName, "participant", identity,
"track", rm.MuteTrack.TrackSid, "muted", rm.MuteTrack.Muted)
participant.SetTrackMuted(rm.MuteTrack.TrackSid, rm.MuteTrack.Muted)
case *livekit.RTCNodeMessage_UpdateMetadata:
logger.Debugw("updating metadata", "room", roomName, "participant", identity)
var md map[string]interface{}
if rm.UpdateMetadata.Metadata != "" {
if err := json.Unmarshal([]byte(rm.UpdateMetadata.Metadata), &md); err != nil {
logger.Errorw("could not update metadata", "error", err)
return
}
}
participant.SetMetadata(md)
}
}
+52 -26
View File
@@ -7,6 +7,7 @@ import (
"github.com/thoas/go-funk"
"github.com/twitchtv/twirp"
"github.com/livekit/livekit-server/pkg/routing"
livekit "github.com/livekit/livekit-server/proto"
)
@@ -97,16 +98,8 @@ func (s *RoomService) GetParticipant(ctx context.Context, req *livekit.RoomParti
}
func (s *RoomService) RemoveParticipant(ctx context.Context, req *livekit.RoomParticipantIdentity) (res *livekit.RemoveParticipantResponse, err error) {
if err = EnsureAdminPermission(ctx, req.Room); err != nil {
return nil, twirpAuthError(err)
}
rtcSink, err := s.createRTCSink(ctx, req.Room, req.Identity)
participant, err := s.roomManager.roomStore.GetParticipant(req.Room, req.Identity)
if err != nil {
return
}
rtcSink, err := s.roomManager.router.CreateRTCSink(req.Room, participant.Identity)
if err != nil {
return
}
@@ -122,30 +115,16 @@ func (s *RoomService) RemoveParticipant(ctx context.Context, req *livekit.RoomPa
}
func (s *RoomService) MutePublishedTrack(ctx context.Context, req *livekit.MuteRoomTrackRequest) (res *livekit.MuteRoomTrackResponse, err error) {
if err = EnsureAdminPermission(ctx, req.Room); err != nil {
return nil, twirpAuthError(err)
}
participant, err := s.roomManager.roomStore.GetParticipant(req.Room, req.Identity)
if err != nil {
return
}
rtcSink, err := s.roomManager.router.CreateRTCSink(req.Room, participant.Identity)
rtcSink, err := s.createRTCSink(ctx, req.Room, req.Identity)
if err != nil {
return
}
defer rtcSink.Close()
err = rtcSink.WriteMessage(&livekit.RTCNodeMessage{
Message: &livekit.RTCNodeMessage_MuteTrack{
MuteTrack: req,
},
})
participant, err := s.roomManager.roomStore.GetParticipant(req.Room, req.Identity)
if err != nil {
return
return nil, err
}
// find the track
track := funk.Find(participant.Tracks, func(t *livekit.TrackInfo) bool {
return t.Sid == req.TrackSid
@@ -153,8 +132,55 @@ func (s *RoomService) MutePublishedTrack(ctx context.Context, req *livekit.MuteR
if track == nil {
return nil, twirp.NotFoundError(ErrTrackNotFound.Error())
}
err = rtcSink.WriteMessage(&livekit.RTCNodeMessage{
Message: &livekit.RTCNodeMessage_MuteTrack{
MuteTrack: req,
},
})
if err != nil {
return
}
res = &livekit.MuteRoomTrackResponse{
Track: track.(*livekit.TrackInfo),
}
// mute might not have happened, reflect desired state
res.Track.Muted = req.Muted
return
}
func (s *RoomService) UpdateParticipantMetadata(ctx context.Context, req *livekit.UpdateParticipantMetadataRequest) (*livekit.ParticipantInfo, error) {
rtcSink, err := s.createRTCSink(ctx, req.Target.Room, req.Target.Identity)
if err != nil {
return nil, err
}
defer rtcSink.Close()
participant, err := s.roomManager.roomStore.GetParticipant(req.Target.Room, req.Target.Identity)
if err != nil {
return nil, err
}
err = rtcSink.WriteMessage(&livekit.RTCNodeMessage{
Message: &livekit.RTCNodeMessage_UpdateMetadata{
UpdateMetadata: req,
},
})
participant.Metadata = req.Metadata
return participant, nil
}
func (s *RoomService) createRTCSink(ctx context.Context, room, identity string) (routing.MessageSink, error) {
if err := EnsureAdminPermission(ctx, room); err != nil {
return nil, twirpAuthError(err)
}
_, err := s.roomManager.roomStore.GetParticipant(room, identity)
if err != nil {
return nil, err
}
return s.roomManager.router.CreateRTCSink(room, identity)
}
+23 -11
View File
@@ -56,14 +56,24 @@ func (s *RTCService) ServeHTTP(w http.ResponseWriter, r *http.Request) {
roomName := r.FormValue("room")
reconnectParam := r.FormValue("reconnect")
isReconnect := reconnectParam == "1" || reconnectParam == "true"
claims := GetGrants(r.Context())
// require a claim
if claims == nil || claims.Video == nil {
handleError(w, http.StatusUnauthorized, rtc.ErrPermissionDenied.Error())
return
}
identity := claims.Identity
pi := routing.ParticipantInit{
Reconnect: reconnectParam == "1" || reconnectParam == "true",
Identity: claims.Identity,
}
// only use permissions if any of them are set, default permissive
if claims.Video.CanPublish || claims.Video.CanSubscribe {
pi.Permission = &livekit.ParticipantPermission{
CanSubscribe: claims.Video.CanSubscribe,
CanPublish: claims.Video.CanPublish,
}
}
onlyName, err := EnsureJoinPermission(r.Context())
if err != nil {
@@ -81,17 +91,16 @@ func (s *RTCService) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
var metadata string
if claims.Metadata != nil {
if data, err := json.Marshal(claims.Metadata); err != nil {
logger.Warnw("unable to encode metadata", "error", err)
} else {
metadata = string(data)
pi.Metadata = string(data)
}
}
// this needs to be started first *before* using router functions on this node
connId, reqSink, resSource, err := s.router.StartParticipantSignal(roomName, identity, metadata, isReconnect)
connId, reqSink, resSource, err := s.router.StartParticipantSignal(roomName, pi)
if err != nil {
handleError(w, http.StatusInternalServerError, "could not start session: "+err.Error())
return
@@ -100,7 +109,7 @@ func (s *RTCService) ServeHTTP(w http.ResponseWriter, r *http.Request) {
done := make(chan bool, 1)
// function exits when websocket terminates, it'll close the event reading off of response sink as well
defer func() {
logger.Infow("WS connection closed", "participant", identity, "connectionId", connId)
logger.Infow("WS connection closed", "participant", pi.Identity, "connectionId", connId)
reqSink.Close()
close(done)
}()
@@ -120,7 +129,7 @@ func (s *RTCService) ServeHTTP(w http.ResponseWriter, r *http.Request) {
"connectionId", connId,
"room", rm.Sid,
"roomName", rm.Name,
"name", identity,
"name", pi.Identity,
)
// handle responses
@@ -137,7 +146,8 @@ func (s *RTCService) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
case msg := <-resSource.ReadChan():
if msg == nil {
logger.Infow("source closed connection", "participant", identity,
logger.Infow("source closed connection",
"participant", pi.Identity,
"connectionId", connId)
return
}
@@ -145,7 +155,7 @@ func (s *RTCService) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if !ok {
logger.Errorw("unexpected message type",
"type", fmt.Sprintf("%T", msg),
"participant", identity,
"participant", pi.Identity,
"connectionId", connId)
continue
}
@@ -172,8 +182,10 @@ func (s *RTCService) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
}
if err := reqSink.WriteMessage(req); err != nil {
logger.Warnw("error writing to request sink", "error", err,
"participant", identity, "connectionId", connId)
logger.Warnw("error writing to request sink",
"error", err,
"participant", pi.Identity,
"connectionId", connId)
}
}
}