Test3devmerge - #278
Merged
Merged
Conversation
Run document upload handling asynchronously after meeting creation for improved API response time.
Replaces grails-async task {} with a dedicated fixed-size
executor owned by PresentationService. grails-async's default factory
is an unbounded thread pool with no supervision, and exceptions raised
inside the task closure are silently swallowed instead of surfacing
anywhere. submitPresentationTask() logs any escaping failure with
meeting/source context and caps concurrency via the existing
numConversionThreads-style property pattern (numPresentationDownloadThreads,
default 5), removing the grails-async dependency entirely.
Also drops the now-unreachable invalid() call inside
downloadAndProcessDocument's UnsupportedEncodingException handler,
since that method runs off the request thread and can no longer render
a response.
Updates docs for the async create/insertDocument semantics and the new
numPresentationDownloadThreads property.
…async tasks Review follow-up: filename derivation/validation moves out of downloadAndProcessDocument into resolvePresentationFilename(), which runs on the request thread before submitPresentationTask at all three submit sites (default presentation, URL documents, raw-bytes documents). Invalid filenames are rejected synchronously with an error log and no task is spawned. This also closes two gaps: URLDecoder.decode's IllegalArgumentException (malformed percent-encoding) is now caught — unlike UnsupportedEncodingException it is actually reachable — and the raw-bytes path, whose internal name validation result was silently discarded (pres stays null so processUploadedFile never runs and the failure never reaches the meeting), now rejects invalid names before a task exists at all.
- Replace Executors.newFixedThreadPool (unbounded queue) with a ThreadPoolExecutor backed by a bounded queue (threads x 20) and an AbortPolicy. submitPresentationTask now catches RejectedExecutionException, logs it with meeting/source context and returns false, so a burst of create/insertDocument calls can no longer grow the queue until the heap is exhausted. - uploadDocuments defers task submission until every filename is validated. insertDocument now returns a FAILED response when a document is rejected for an invalid filename instead of reporting SUCCESS for a skipped document. create still skips invalid documents and creates the meeting with the valid ones. - resolvePresentationFilename derives the name from the URL path only, dropping any query string or fragment (e.g. presigned S3 links) before decoding, mirroring Util.extractFilenameFromUrl. The download still uses the full URL. - docs: describe the bounded queue/rejection behavior and drop the shell prompt marker (MD014).
The create handler now calls uploadDocuments before respondWithConference, so an unexpected exception in the synchronous upload-handling path would skip the response and return a 500 for a meeting that was actually created. Wrap that call in try/catch: log the failure and still respond with success, consistent with async download/processing failures being non-fatal to the API response. Clamp the download pool size to at least 1. numDownloadThreads is injected as a String, so a configured "0" is truthy and slips past the Elvis default; 0 or a negative value makes the ThreadPoolExecutor constructor throw and fails bean initialization at startup. Document that a presentation task rejected because the pool is saturated is not uploaded and is not reflected in the create/insertDocument response, only logged.
refactor(bbb-web): process pre-uploaded slides async on a bounded pool
…gbluebutton#25439) * Translate en.json in it_IT 100% translated source file: 'en.json' on 'it_IT'. * Translate en.json in zh_TW 100% translated source file: 'en.json' on 'zh_TW'. * Translate en.json in ja 100% translated source file: 'en.json' on 'ja'. --------- Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
…npm_and_yarn/docs/postcss-8.5.23 build(deps): bump postcss from 8.5.15 to 8.5.23 in /docs
…25522) Bumps [body-parser](https://github.com/expressjs/body-parser) from 2.2.1 to 2.3.0. - [Release notes](https://github.com/expressjs/body-parser/releases) - [Changelog](https://github.com/expressjs/body-parser/blob/master/HISTORY.md) - [Commits](expressjs/body-parser@v2.2.1...v2.3.0) --- updated-dependencies: - dependency-name: body-parser dependency-version: 2.3.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…on#25520) Bumps [shell-quote](https://github.com/ljharb/shell-quote) from 1.8.4 to 1.10.0. - [Changelog](https://github.com/ljharb/shell-quote/blob/main/CHANGELOG.md) - [Commits](ljharb/shell-quote@v1.8.4...v1.10.0) --- updated-dependencies: - dependency-name: shell-quote dependency-version: 1.10.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…bigbluebutton#25514) Move getJoinUrl out of the integration API listing into a new "Internal API calls" section, and document the other session-token authenticated, client-only endpoints alongside it: stuns, signOut and learningDashboard. These endpoints are authenticated with a per-user sessionToken issued by /join rather than a shared-secret checksum, and are only reachable by the BigBlueButton HTML5 client -- not by integrations (Greenlight, Moodle) or load balancers (Scalelite, b3scale), which never see the session token. The new section makes that boundary explicit and warns integrators not to build on these endpoints. All four endpoints are routed for both GET and POST (per UrlMappings and confirmed against a running server), so getJoinUrl is labelled accordingly. Addresses bigbluebutton#24212. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
AudioFloorManager's FloorState.talkingStateChanges has no actual usage. Drop the field and the consequently stale cleanupOldState.
AudioFloorManager is an akka-apps-wide singleton, which may cause collisions when handling audio floor events. Turn AudioFloorManager into a per-meeting class held by LiveMeeting, so floor grants, releases, CDs and pending queues are meeting-scoped and releases always resolve in the holder's own meeting, and tear it down from a MeetingActor postStop hook, which covers every termination path.
There are a few issues regarding floor grant scheduling vs cooldown handling: - Each pending floor grant runs off its own timer on a manually managed scheduler thread. A grant that fires inside the cooldown period is rejected and never re-scheduled, and new scheduling is blocked if the user keeps talking - so two users starting to talk within the cooldown of each other leave the second one starved of the floor until they stop and restart talking. - Timers that are not the head of the grant queue are no-ops, which leaves orphaned queue entries that can block actual floor grants tha come in later. - The timer task mutates VoiceUsers and emits floor events decoupled from the meeting actor's lifecycle - which races meeting events and is just weird Replace the per-queued grant timers with a single re-scheduled grant dispatch that always evaluates the queue head at the earliest instant a grant can succeed (talking deadline or cooldown expiry, whichever is later) and re-runs on every queue or floor-state change. This includes the rewrite of the scheduler to use Pekko's scheduleOnce via an internal DispatchFloorGrantsInternalMsg to the meeting actor, handled in like the other internal meeting timers, so all floor state is inside the meeting actor lifecycle.
When a floor holder leaves, the release itself starts a cooldown that defers the grant to the next pending speaker until after the cooldown elapses. The cooldown exists to space out floor switches only - a release event always should come after the cooldown already acted. Enforce cooldowns on grants only, so a pending speaker is promoted as soon as their talking deadline allows.
speakingStartTimes entries are removed only by explicit stop-talking or left-voice events. A user whose events are lost (disconnect, ...) leaves an entry behind until meeting end. Two obvious issues: queue buildup and floor grant block for the affected user. Prune speaking state entries older than five minutes, dropping matching pending grants with them. TTL may be tweaked later based on observation.
…defaults Align fallback config values for voiceConf.floorControl and minTalkingDuration with the default application.conf values.
The grant dispatch dequeues the pending item before granting it, so a grant attempt that fails to execute drops the speaker from the queue and the re-scheduled dispatch retries the next queued speaker instead. Dequeue only after the grant went through; a half-granted holder is still dequeued by the dispatch's stale cleanup routine on retry.
feat: New useTimer hook
…oors-fixes Backport: "fix(audio): assorted fixes and improvements to LiveKit's floor manager"
…hat messages hook (it remains static throughout the meeting) (bigbluebutton#25539)
fix: MeetingActor analytics discards VoiceUserState.callerName, logs ERROR after user leaves
Especially under reconnects, BBB <-> LiveKit state can drift apart. This is both due to them being two separate systems, but also due to the fact that akka-apps itself makes VoiceUsers (which is the basic media participant unit in BBB) just _very loosely coupled_ to the Users2x model of users. This may cause a few issues, such as a client being marked as out of audio after a reconnect with no way to recover it - even though it got back its media session. Introduce a voice user reconciler that centralizes VoiceUsers <-> Users2x state reconciliation and makes it easier to reason about the state of a voice user in BBB and propagate it to LiveKit. In addition to centralizing something that was spread across akka, this also introduces a new concept of "fencing" a voice user: keeping it alive, for a time, with a downgraded permission state when it is no longer associated with a meeting user. Fencing makes the reconnection process smoother (no VoiceUser teardown, just permission up/downgrade) and more robust (permissions adhere to state being consistent across Users2x and VoiceUsers). Fencing, when applicable, is done at: the voice conf join (if orphaned), and MeetingActor's periodic user audit. For LiveKit, bbb-webrtc-sfu acts on media permission up/down grades as well as voice user ejections. For mediasoup/FreeSWITCH, it acts on ejections.
v2.24.0 --- * feat(livekit): handle participant permission updates from akka * feat(livekit): ack participant permission and voice eject outcomes
…ed (bigbluebutton#25535) Viewers joining a session that already had an external video shared got a silent video. Audio only came back if they nudged the BBB volume slider or pressed the reload button in the player toolbar. When the browser blocks autoplay with sound, YouTube's embed does not surface the failure: it mutes itself inside the iframe and plays anyway. The `muted` prop on this side therefore stays false, and react-player only calls unmute() when that prop *changes*, so nothing ever undoes the mute. Chrome gates unmuted autoplay on user activation or the per-profile Media Engagement Index, which is why this is invisible on an established profile and reproduces in incognito, on a fresh profile, or for a first-time participant. Both known workarounds line up with the mechanism exactly: changeVolume calls unMute directly, and the reload button remounts the iframe close enough to a click to inherit its transient activation. The existing autoplay warning cannot cover this. It triggers on `reactPlayerPlaying !== playing`, and muted playback is still playback, so the condition is never met and the client believes everything is fine. The 2.x detector had the same blind spot by design: it fired only when the player became ready without ever playing, which assumed a blocked autoplay meant no playback at all. That is no longer the failure mode. Reconcile the provider's real muted state against the UI's on the first play and on subsequent progress ticks, and unmute when the two diverge: - Read the muted flag from the provider rather than from component state, since detecting where the two disagree is the whole point. isMuted() for YouTube, getMuted() for Vimeo and Twitch, .muted for HTML5 media playback. - Disarm without acting when the provider reports unmuted, or reports nothing at all, so a viewer who mutes through the provider's own controls is not overridden a tick later. - Unmute immediately when the document already has user activation. That covers effectively every real join and avoids making the viewer click for their audio. - Always also arm a one-shot pointerup/keydown listener that unmutes synchronously inside the handler. That is the only moment the browser is guaranteed to honour an unmute rather than answering it by pausing the media, so it is what actually guarantees recovery. Both event types are activation triggers, so keyboard-only viewers are covered too. - One automatic attempt plus one gesture-anchored attempt means the recovery can never ping-pong with the viewer-side auto-resume in handleOnStop, so there is no retry budget to tune. - Disarm before the await rather than after, so an onPlay and a progress tick in flight together cannot both clear the guard and run the recovery twice. - Re-arm per player mount in handleOnStart, before its first await, since react-player invokes onStart then onPlay synchronously and the async tail would otherwise undo that attempt's result. Release the gesture listener when it fires, on unmount, and on remount. Volume needs no extra plumbing: the player mounts unmuted, so react-player has already applied the stored volume by the time the unmute lands. Verified manually in an incognito window against a live server, which is the only place the behaviour reproduces. Headless Chromium's autoplay policy does not match a real profile, so an E2E test here would be either vacuous or flaky.
…x-lk-reconciliation [3.0] refactor(audio): better BBB<->LiveKit state reconciliation on reconnects, bbb-webrtc-sfu@v2.24.0- bigbluebutton#25550
* docs: iteration doc sync for 3.0.33 Covers documentation-worthy changes on v3.0.x-release since the v3.0.32 tag that were not yet reflected in the docs: - new-features.md: Panopto external video player; the new public.whiteboard.slideSwapDecodeTimeoutMs client setting; corrected the html5PluginSdkVersion line to 0.0.104; tagged maxSharedNotesInitialContentUrlPayloadSize with 3.0.33 and added numPresentationDownloadThreads to the bbb-web properties ledger. - create.tsx: "(added 3.0.33)" on sharedNotesInitialContentMarkdown and sharedNotesInitialContentMarkdownUrl. - api.md: the three shared-notes initial-content create parameters added to the "Updated in 3.0" list, tagged with the point release that shipped them. - plugins.md: useTimer hook (plugin SDK 0.0.104) and the new senderRole field on useLoadedChatMessages. - faq.md: external video line now mentions Panopto.
…on#25563) Bumps [ip-address](https://github.com/beaugunderson/ip-address) from 10.2.0 to 10.4.0. - [Release notes](https://github.com/beaugunderson/ip-address/releases) - [Commits](beaugunderson/ip-address@v10.2.0...v10.4.0) --- updated-dependencies: - dependency-name: ip-address dependency-version: 10.4.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…n#25569) Bumps [fast-uri](https://github.com/fastify/fast-uri) from 3.1.4 to 3.1.5. - [Release notes](https://github.com/fastify/fast-uri/releases) - [Commits](fastify/fast-uri@v3.1.4...v3.1.5) --- updated-dependencies: - dependency-name: fast-uri dependency-version: 3.1.5 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…tton#25572) Bumps [fast-uri](https://github.com/fastify/fast-uri) from 3.1.2 to 3.1.5. - [Release notes](https://github.com/fastify/fast-uri/releases) - [Commits](fastify/fast-uri@v3.1.2...v3.1.5) --- updated-dependencies: - dependency-name: fast-uri dependency-version: 3.1.5 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…n#25556) Bumps [sanitize-html](https://github.com/apostrophecms/apostrophe/tree/HEAD/packages/sanitize-html) from 2.17.4 to 2.17.5. - [Changelog](https://github.com/apostrophecms/apostrophe/blob/main/packages/sanitize-html/CHANGELOG.md) - [Commits](https://github.com/apostrophecms/apostrophe/commits/sanitize-html@2.17.5/packages/sanitize-html) --- updated-dependencies: - dependency-name: sanitize-html dependency-version: 2.17.5 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…bluebutton#25573) Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 1.1.13 to 1.1.18. - [Release notes](https://github.com/juliangruber/brace-expansion/releases) - [Commits](juliangruber/brace-expansion@v1.1.13...v1.1.18) --- updated-dependencies: - dependency-name: brace-expansion dependency-version: 1.1.18 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
🚨 Automated tests failed |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Closes Issue(s)
Closes #
Motivation
How to test
More