Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions callback.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,11 @@ type RoomCallback struct {
OnSignalReconnecting func()
OnLocalTrackSubscribed func(publication *LocalTrackPublication, lp *LocalParticipant)

// OnRoomSIDChanged is called when the room's session ID changes after it was first
// known, either because the server started a new session for the room or because
// the participant was moved to another room.
OnRoomSIDChanged func(roomSID string)

// participant events are sent to the room as well
ParticipantCallback
}
Expand All @@ -197,6 +202,7 @@ func NewRoomCallback() *RoomCallback {
OnRecordingStatusChanged: func(isRecording bool) {},
OnRoomMoved: func(roomName string, token string) {},
OnRoomMovedWithSID: func(roomName string, roomSID string, token string) {},
OnRoomSIDChanged: func(roomSID string) {},
OnReconnecting: func() {},
OnReconnected: func() {},
OnSignalReconnecting: func() {},
Expand Down Expand Up @@ -237,6 +243,9 @@ func (cb *RoomCallback) Merge(other *RoomCallback) {
if other.OnRoomMovedWithSID != nil {
cb.OnRoomMovedWithSID = other.OnRoomMovedWithSID
}
if other.OnRoomSIDChanged != nil {
cb.OnRoomSIDChanged = other.OnRoomSIDChanged
}
if other.OnReconnecting != nil {
cb.OnReconnecting = other.OnReconnecting
}
Expand Down
32 changes: 21 additions & 11 deletions room.go
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ func (r *Room) Name() string {

// SID returns the unique session ID of the room.
// This will block until session ID is available, which could take up to 2s after joining the room.
// The ID can change while connected, see RoomCallback.OnRoomSIDChanged.
func (r *Room) SID() string {
<-r.sidReady
r.lock.RLock()
Expand Down Expand Up @@ -811,18 +812,26 @@ func (r *Room) cleanup() {
r.LocalParticipant.cleanup()
}

func (r *Room) setSid(sid string, allowEmpty bool) {
// setSid records the room's session ID and unblocks SID(). Once the ID is known, a
// different non-empty ID replaces it and reports changed, so callers can notify
// OnRoomSIDChanged when the server re-keys the session the room belongs to.
func (r *Room) setSid(sid string, allowEmpty bool) (changed bool) {
r.lock.Lock()
if sid != "" || allowEmpty {
select {
case <-r.sidReady:
// already closed
default:
defer r.lock.Unlock()

select {
case <-r.sidReady:
if sid != "" && sid != r.sid {
changed = r.sid != ""
r.sid = sid
}
default:
if sid != "" || allowEmpty {
r.sid = sid
close(r.sidReady)
}
}
r.lock.Unlock()
return changed
}

// Simulate triggers various test scenarios for debugging and testing purposes.
Expand Down Expand Up @@ -1269,7 +1278,9 @@ func (r *Room) OnRoomUpdate(room *livekit.Room) {
r.activeRecording = room.ActiveRecording
}
r.lock.Unlock()
r.setSid(room.Sid, false)
if r.setSid(room.Sid, false) {
go r.callback.OnRoomSIDChanged(room.Sid)
}
if metadataChanged {
go r.callback.OnRoomMetadataChanged(room.Metadata)
}
Expand All @@ -1280,13 +1291,12 @@ func (r *Room) OnRoomUpdate(room *livekit.Room) {

func (r *Room) OnRoomMoved(moved *livekit.RoomMovedResponse) {
r.log.Infow("room moved", "newRoom", moved.Room.Name)
r.OnRoomUpdate(moved.Room)

// setSid is one-shot; update name/sid directly so the getters report the destination room.
// set the name first so OnRoomSIDChanged observes the destination room's name
r.lock.Lock()
r.name = moved.Room.Name
r.sid = moved.Room.Sid
r.lock.Unlock()
r.OnRoomUpdate(moved.Room)

for _, rp := range r.GetRemoteParticipants() {
r.OnParticipantDisconnect(rp, livekit.DisconnectReason_MIGRATION)
Expand Down
54 changes: 54 additions & 0 deletions room_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,57 @@ func TestOnRoomUpdateDeliversLateSID(t *testing.T) {
return room.SID() == "RM_late"
}, time.Second, 10*time.Millisecond, "SID() never returned the SID delivered via OnRoomUpdate")
}

func TestOnRoomUpdateReportsSIDChange(t *testing.T) {
changed := make(chan string, 4)
room := NewRoom(&RoomCallback{
OnRoomSIDChanged: func(sid string) { changed <- sid },
})

room.OnRoomUpdate(&livekit.Room{Sid: "RM_first"})
require.Equal(t, "RM_first", room.SID())

// the same ID or an empty one is not a change
room.OnRoomUpdate(&livekit.Room{Sid: "RM_first"})
room.OnRoomUpdate(&livekit.Room{})
require.Equal(t, "RM_first", room.SID())

room.OnRoomUpdate(&livekit.Room{Sid: "RM_second"})
require.Equal(t, "RM_second", room.SID())

select {
case sid := <-changed:
require.Equal(t, "RM_second", sid)
case <-time.After(time.Second):
t.Fatal("OnRoomSIDChanged not called")
}
select {
case sid := <-changed:
t.Fatalf("unexpected OnRoomSIDChanged(%q)", sid)
case <-time.After(50 * time.Millisecond):
}
}

func TestOnRoomMovedReportsSIDChangeWithNewName(t *testing.T) {
names := make(chan string, 1)
var room *Room
room = NewRoom(&RoomCallback{
OnRoomSIDChanged: func(string) { names <- room.Name() },
})
room.LocalParticipant.updateInfo(&livekit.ParticipantInfo{Sid: "local", Identity: "local-identity"})
room.name = "old-room"
room.setSid("RM_old", false)

room.OnRoomMoved(&livekit.RoomMovedResponse{
Room: &livekit.Room{Name: "new-room", Sid: "RM_new"},
Participant: &livekit.ParticipantInfo{Sid: "local", Identity: "local-identity"},
Token: "token",
})

select {
case name := <-names:
require.Equal(t, "new-room", name)
case <-time.After(time.Second):
t.Fatal("OnRoomSIDChanged not called")
}
}
Loading