It seems that on the mobile app, you can only create rooms but cannot directly enter already created rooms by clicking on them. However, if you directly access /resenha/r/topic, it works. Is this a bug?
Works just fine for me on my phone, have you updated your Discourse instance this week?
Experimental plugins require frequent updates
Lots of updates this month, but the main one is optional and per-room support for SFU via LiveKit.
Full P2P WebRTC is still the main and default supported transport, but SFU is now also supported for people who need to support hundreds of participants in a single room.
We’ve also made lots of improvements, like Audio and Video device pickers on room and widget controls, made Resenha rooms mentionable via # auto complete on chat and posts, room layout options, and more.
Thanks for this, the SFU was the real missing piece. It’s what originally pushed me into maintaining a separate fork; with it supported upstream I can retire the fork and track resenha directly.
I’d held off asking about LiveKit because I didn’t know if you wanted to go that direction. Now that you have: are you open to PRs for features and small improvements?
@Falco Hey I’ve hit a few reproducible issues while testing the updated resenha. Sharing findings + the patches I’m running locally, in case they’re useful upstream.
1. Admin UI silently discards room_type stage rooms can never stick
app/controllers/resenha/admin_rooms_controller.rb:65 (room_params) omits :room_type from the permit list, and admin_room_serializer.rb never serializes it.
Every stage assignment made through the admin UI is dropped, rooms create as open and “revert” to open on any later admin edit. Confirmed via production logs; the user-facing controller permits it, only the admin path lost it.
# admin_rooms_controller.rb — add :room_type to the permit list, then:
if permitted.key?(:room_type)
value = Resenha::Room::ROOM_TYPES[permitted[:room_type].to_s]
raise Discourse::InvalidParameters.new(:room_type) if value.nil?
permitted[:room_type] = value
end
# admin_room_serializer.rb — serialize room_type so the form initializes correctly
2. Invalid room_type silently falls back to open
app/controllers/resenha/rooms_controller.rb:575 — ROOM_TYPES[...] || ROOM_TYPE_OPEN.
Any malformed/stale room_type in an otherwise-valid room edit quietly flips a stage room to open. A 400 makes the misbehaving caller visible instead of corrupting the room.
value = Resenha::Room::ROOM_TYPES[permitted[:room_type].to_s]
raise Discourse::InvalidParameters.new(:room_type) if value.nil?
permitted[:room_type] = value
3. Heartbeat resurrects a user who just left (ghost presence)
rooms_controller.rb:234 (heartbeat) unconditionally re-adds presence, so a heartbeat in flight when leave (:220) processes lands second and re-creates the departed user.
The ghost persists until the TTL reap, which doesn’t broadcast — clients show them “in the room” for up to a minute.
Reproduced on device; kick has the identical exposure.
# ParticipantTracker: 15s tombstone
def mark_left(room_id, user_id) = redis.setex(left_key(room_id, user_id), 15, "1")
def recently_left?(room_id, user_id) = redis.exists?(left_key(room_id, user_id))
# leave/kick → mark_left; join/livekit_token → clear_left; heartbeat:
return head :no_content if Resenha::ParticipantTracker.recently_left?(@room.id, current_user.id)
4. Stale participant_left webhook phantom-kicks a fresh session
livekit_webhooks_controller.rb:37/57 — departures are matched by user identity alone.
On a quick disconnect/rejoin, the superseded session’s participant_left arrives late and expires the new session’s presence (user “kicked” ~3s after rejoining, back ~15s later).
Reproduced on device; the gone_at heuristic can’t distinguish the sessions when the rejoin predates the old session’s disconnect.
# participant_joined → record the live SID
Resenha::ParticipantTracker.set_livekit_sid(room.id, user_id, event.dig("participant", "sid"))
# expire_participant → skip a superseded session's departure
known = Resenha::ParticipantTracker.livekit_sid(room.id, user_id)
return if sid.present? && known.present? && sid != known
5. DeleteRoom 404 after the last leave floods the logs
lib/resenha/livekit/room_service_client.rb:84 warns on any non-200.
The SFU auto-closes a room the moment it empties, so the last leave’s DeleteRoom routinely races it — “requested room does not exist” is the desired end state, not a fault.
It lands in Logster on every last-leave.
elsif method == "DeleteRoom" && response.status == 404
Rails.logger.debug("[resenha-livekit] DeleteRoom no-op for room #{room.id}: already gone")
true
I can send a pull request if you wish.
As I said in previous I don’t know your direction in full, but you can have a look at mines as I’ve made a post here → Discourse Desktop Mac App - #10 by nicolsdennis
This would be absolutely brilliant - it would make sense to make it hook into the Livestream mechanism, which would provide the associated chat channel as part of a beautiful integrated experience
Hi, when changing the name of the room, it doesn’t update the slug. Also, it doesn’t let me delete rooms – I get server error.
It would also be nice to be able to visually change the order of the rooms and how they appear.
Thanks for the detailed report, just a merged a PR for those:
I’ve got a couple of minor UI/UX things related to private voice rooms:
1. The private / lock micro-icon is too small.
Great that we have an icon indicating the privacy status of a room; unfortunately it
is too small, and overlaps the icon a lot. And is inconsitent with the rest of the sidebar:
![]()
2. The participant list is hard to find
You can only get to the participant list in a private voiceroom from within the call itself.
This isn’t super-intuitive. I expect to be able to modify the participants / invitees from the settings available when the voiceroom is inactive as well. There are plently of settings available when it is inactive (including public vs private, max participants, etc), just not the actual participant list.
I have made fixes for both of those, thanks for the report @nathank!
I wonder if it is possible to link a specific room from href links? Want to add a shortcut to a single test room to simplify our UX.
Yeah, it is now possible in this format
Also worth highlighting recent improvements:
Support for private STUN/TURN via coturn auth
This allows you to keep your coturn instance restricted to you, and it’s very easy to configure with a shared secret between Discourse and Coturn.
Support for session recording when using LiveKit
All via the call UI, single click to start recording, single click to stop.
Flag support for call participants
While the flag will lack context, users can provide it via the text area
Right click menu on the video tiles
Easy to adjust volume of a peer, or kick, etc.
Opt-in higher quality for voice, video and screen sharing
My favorite feature of the week, this allows users to opt into much higher bitrate limits, and get much better audio / video.
Is it my instance or probably something to look into? I’m recieving error 500 when trying to remove voice rooms from admin panel:
ActiveRecord::InvalidForeignKey (PG::ForeignKeyViolation: ERROR: update or delete on table "resenha_rooms" violates foreign key constraint "fk_rails_ID" on table "resenha_sessions" DETAIL: Key (id)=(1) is still referenced from table "resenha_sessions".
Thanks for the report, fix is merged
Thanks for this ultra-fast fix; it worked as expected.
Just a little note, following up: changing the default room name did not update the path /resenha/r/watercooler, but I was now able to remove the previous default room and add a fresh one.

