diff --git a/pkg/rtc/room.go b/pkg/rtc/room.go index 94e66fac0..e7b4aaece 100644 --- a/pkg/rtc/room.go +++ b/pkg/rtc/room.go @@ -323,6 +323,14 @@ func (r *Room) ToProto() *livekit.Room { return r.protoProxy.Get() } +// ToProtoConsistent returns a room proto with participant counts computed +// directly from the current participants map, bypassing the batched proto +// proxy. Use this when an accurate num_participants is required immediately, +// e.g. for webhook or telemetry events. +func (r *Room) ToProtoConsistent() *livekit.Room { + return r.updateProto() +} + func (r *Room) Name() livekit.RoomName { return livekit.RoomName(r.protoRoom.Name) } @@ -1403,10 +1411,6 @@ func (r *Room) RemoveParticipant( delete(r.participantRequestSources, identity) delete(r.hasPublished, identity) delete(r.agentParticpants, identity) - if !p.Hidden() { - r.protoRoom.NumParticipants-- - } - immediateChange := false if p.IsRecorder() { activeRecording := false diff --git a/pkg/service/roommanager.go b/pkg/service/roommanager.go index 267324959..33bfac448 100644 --- a/pkg/service/roommanager.go +++ b/pkg/service/roommanager.go @@ -569,7 +569,8 @@ func (r *RoomManager) StartSession( persistRoomForParticipantCount(room.ToProto()) clientMeta := &livekit.AnalyticsClientMeta{Region: r.currentNode.Region(), Node: string(r.currentNode.NodeID())} - r.telemetry.ParticipantJoined(ctx, protoRoom, participant.ToProto(), pi.Client, clientMeta, true, participant.TelemetryGuard()) + // Use a consistent room proto so num_participants reflects the newly joined participant + r.telemetry.ParticipantJoined(ctx, room.ToProtoConsistent(), participant.ToProto(), pi.Client, clientMeta, true, participant.TelemetryGuard()) participant.AddOnClose(types.ParticipantCloseKeyNormal, func(p types.LocalParticipant) { participantServerClosers.Close() @@ -577,8 +578,8 @@ func (r *RoomManager) StartSession( pLogger.Errorw("could not delete participant", err) } - // update room store with new numParticipants - proto := room.ToProto() + // use consistent proto so num_participants is accurate for webhook + proto := room.ToProtoConsistent() persistRoomForParticipantCount(proto) r.telemetry.ParticipantLeft(ctx, proto, p.ToProto(), true, participant.TelemetryGuard()) })