Resenha - Adicione Salas de Vídeo e Voz estilo Discord à sua Comunidade 🎙

Parece que no celular só é possível criar salas, mas ao clicar diretamente em uma sala já criada, não é possível entrar. No entanto, ao acessar diretamente /resenha/r/topic, é possível abri-la. Isso é um bug?

Funciona perfeitamente no meu celular. Você atualizou sua instância do Discourse esta semana?

Plugins experimentais exigem atualizações frequentes

5 curtidas

Muitas atualizações este mês, mas a principal é o suporte opcional e por sala para SFU via LiveKit.

O WebRTC P2P completo continua sendo o transporte principal e padrão suportado, mas o SFU agora também é suportado para pessoas que precisam de centenas de participantes em uma única sala.

Tambés fizemos muitas melhorias, como seletores de dispositivos de áudio e vídeo nos controles de sala e widget, salas do Resenha mencionáveis via auto-complete com # em chats e posts, opções de layout de sala e muito mais.

15 curtidas

Obrigado por isso, a SFU era realmente a peça que faltava. Foi o que originalmente me levou a manter um fork separado; com o suporte upstream, posso aposentar o fork e acompanhar o resenha diretamente.

Eu estava esperando para perguntar sobre o LiveKit porque não sabia se você queria seguir nessa direção. Agora que você já tem: está aberto a PRs para recursos e melhorias menores?

4 curtidas

@Falco Ei, encontrei alguns problemas reproduzíveis enquanto testava a versão atualizada do resenha. Compartilhando as descobertas + os patches que estou usando localmente, caso sejam úteis upstream.

1. A UI de Admin descarta silenciosamente room_type; os quartos de estágio nunca conseguem manter o tipo
app/controllers/resenha/admin_rooms_controller.rb:65 (room_params) omite :room_type da lista de permissões, e admin_room_serializer.rb nunca o serializa.

Toda atribuição de estágio feita através da UI de admin é descartada; os quartos são criados como abertos e “regridem” para abertos em qualquer edição posterior de admin. Confirmado via logs de produção; o controller voltado ao usuário permite, apenas o caminho de admin o perdeu.

# admin_rooms_controller.rb — adicione :room_type à lista de permissões, então:
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 para que o formulário inicialize corretamente

2. room_type inválido cai silenciosamente para aberto
app/controllers/resenha/rooms_controller.rb:575ROOM_TYPES[...] || ROOM_TYPE_OPEN.

Qualquer room_type malformado/obsoleto em uma edição de quarto válida silenciosamente transforma um quarto de estágio em aberto. Um 400 torna visível o chamador mal-comportado em vez de corromper o quarto.

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 ressuscita um usuário que acabou de sair (presença fantasma)
rooms_controller.rb:234 (heartbeat) re-adiciona presença incondicionalmente, então um heartbeat em voo quando leave (:220) processa chega em segundo lugar e re-cria o usuário que partiu.
O fantasma persiste até a reaplicação do TTL, que não faz broadcast — os clientes o mostram “no quarto” por até um minuto.

Reproduzido em dispositivo; kick tem a exposição idêntica.

# ParticipantTracker: lápide de 15s
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. Webhook participant_left obsoleto faz kick fantasma em uma sessão nova
livekit_webhooks_controller.rb:37/57 — partidas são combinadas apenas pela identidade do usuário.
Em uma desconexão/reconexão rápida, o participant_left da sessão substituída chega atrasado e expira a presença da nova sessão (usuário “expulso” ~3s após reconectar, de volta ~15s depois).
Reproduzido em dispositivo; a heurística gone_at não consegue distinguir as sessões quando a reconexão antecede a desconexão da sessão antiga.

# participant_joined → registre o SID vivo
Resenha::ParticipantTracker.set_livekit_sid(room.id, user_id, event.dig("participant", "sid"))
# expire_participant → pule a partida de uma sessão substituída
known = Resenha::ParticipantTracker.livekit_sid(room.id, user_id)
return if sid.present? && known.present? && sid != known

5. DeleteRoom 404 após a última saída inunda os logs
lib/resenha/livekit/room_service_client.rb:84 alerta em qualquer não-200.
O SFU fecha automaticamente um quarto no momento em que fica vazio, então o DeleteRoom da última saída rotineiramente compete com ele — “quarto solicitado não existe” é o estado final desejado, não uma falha.
Ele cai no Logster em toda última saída.

elsif method == "DeleteRoom" && response.status == 404
  Rails.logger.debug("[resenha-livekit] DeleteRoom no-op para quarto #{room.id}: já foi embora")
  true

Posso enviar um pull request se você desejar.

Como disse anteriormente, não conheço sua direção em detalhes, mas você pode dar uma olhada na minha, já que fiz um post aqui → Discourse Desktop Mac App - #10 by nicolsdennis

2 curtidas

Isso seria absolutamente brilhante — faria sentido integrá-lo ao mecanismo de transmissão ao vivo, que forneceria o canal de chat associado como parte de uma experiência integrada e elegante

4 curtidas

Oi, ao alterar o nome do quarto, o slug não é atualizado. Além disso, não consigo excluir quartos — recebo um erro do servidor.

Também seria legal poder alterar visualmente a ordem dos quartos e como eles aparecem.

Obrigado pelo relatório detalhado, acabei de mesclar um PR para isso:

6 curtidas

Tenho algumas pequenas questões de UI/UX relacionadas aos salas de voz privadas:

1. O micro-ícone de privado/trancado é muito pequeno.

É ótimo que tenhamos um ícone indicando o status de privacidade de uma sala; infelizmente, ele é muito pequeno e se sobrepõe demais ao ícone. Além disso, é inconsistente com o restante da barra lateral:

image   image

2. A lista de participantes é difícil de encontrar

Você só pode acessar a lista de participantes em uma sala de voz privada a partir da própria chamada.

Isso não é muito intuitivo. Eu esperava poder modificar os participantes/convidados pelas configurações disponíveis quando a sala de voz está inativa. muitas configurações disponíveis quando está inativa (incluindo pública versus privada, número máximo de participantes, etc.), apenas não a lista real de participantes.

3 curtidas

Corrigi ambos os problemas, obrigado pelo relatório, @nathank!

2 curtidas

Me pergunto se é possível vincular um quarto específico por meio de links href? Gostaria de adicionar um atalho para uma única sala de teste para simplificar nossa UX.

Sim, agora é possível neste formato

https://discourse-on-a-pi5.falco.dev/resenha/r/watercooler

4 curtidas

Vale a pena destacar também as melhorias recentes:

Suporte a STUN/TURN privado via autenticação do coturn

Isso permite manter sua instância do coturn restrita a você, e é muito fácil de configurar com um segredo compartilhado entre o Discourse e o Coturn.

Suporte à gravação de sessões ao usar o LiveKit

Tudo pela interface de chamada, um clique para iniciar a gravação, um clique para parar.

Suporte a sinalizadores para participantes da chamada

Embora o sinalizador não tenha contexto, os usuários podem fornecê-lo por meio da área de texto

Menu de clique direito nos blocos de vídeo

Fácil de ajustar o volume de um participante, ou expulsar, etc.

Opção de qualidade mais alta para voz, vídeo e compartilhamento de tela

Minha funcionalidade favorita da semana, isso permite que os usuários optem por limites de taxa de bits muito mais altos e obtenham áudio/vídeo muito melhor.

6 curtidas

Muito melhor!!! Obrigado por ouvir (e agir)!!

image

2 curtidas

Isso é um problema da minha instância ou provavelmente algo que deve ser investigado? Estou recebendo o erro 500 ao tentar remover salas de voz no painel de administração:

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".
1 curtida

Obrigado pelo relatório, a correção foi mesclada

2 curtidas

Obrigado por esta correção ultra-rápida; funcionou conforme o esperado.

Apenas uma pequena observação, em seguimento: alterar o nome padrão do quarto não atualizou o caminho /resenha/r/watercooler, mas agora consegui remover o quarto padrão anterior e adicionar um novo.

1 curtida

Agora tornei o slug explicitamente editável, então ele funciona como as categorias

6 curtidas

Você também pode adicionar alguns parâmetros de URL para abrir de uma maneira específica:

https://discourse-on-a-pi5.falco.dev/resenha/r/watercooler?join, apenas entra na sala, sem botão de clique para entrar

https://discourse-on-a-pi5.falco.dev/resenha/r/watercooler?join&widget (adicionado no início desta semana), abre e entra no modo widget

https://discourse-on-a-pi5.falco.dev/resenha/r/watercooler?join&chat abre no modo de chat

2 curtidas