Skip to content

Conversation

1egoman
Copy link
Contributor

@1egoman 1egoman commented Aug 4, 2025

It seems initially like modeling a room connection with a useEffect(() => { room.connect(); return () => room.disconnect(); }, [...]) would be natural and work well, however if dependencies in that useEffect change rapidly, then the room can thrash back and forth between connected and disconnected. Because room.disconnect() is async, this sometimes results in connects and disconnects happening at the same time, which can cause edge cases in the SDK, redulting in sometimes very weird errors due to state from past connection attempts being considered as current.

There's some thinking being done to address this at the client-sdk-js level but for now, introduce a hook folks can use to at least stem the bleeding in the short term a bit. Once the issue is fixed in client-sdk-js then this hook can be updated to just use a useEffect again.

Note that this hook inherently must make a tradeoff - the existing room.connect() / room.disconnect() logic only wraps part of each operation in a mutex, meaning that operations are supposed to be able to overlap to try to keep performance up at the expense of reliability. This hook takes the other side of that tradeoff, resulting in slower but much more predictable behavior if connect()s and disconnect()s occur rapidly.

Usage example: livekit-examples/agent-starter-react#225

It seems initially like modelling a room connection with a `useEffect(()
=> { room.connect(); return () => room.disconnect(); }, [...])` would be
natural and work well, however if dependencies in that `useEffect` change
rapidly, then the room can thrash back and forth between connected and
disconnected, and because room.disconnect() is async, sometimes
resulting in connects and disconnects happening at the same time.

There's some thinking being done to address this at the client-sdk-js
level but for now, introduce a hook folks can use to at least stem the
bleeding a bit. Once the issue is fixed in `client-sdk-js` then this
hook can be updated to just use a `useEffect` again.
Copy link
Contributor

github-actions bot commented Aug 4, 2025

size-limit report 📦

Path Size
LiveKitRoom only 6 KB (0%)
LiveKitRoom with VideoConference 30.59 KB (0%)
All exports 38.25 KB (+0.31% 🔺)

Copy link

changeset-bot bot commented Aug 4, 2025

⚠️ No Changeset found

Latest commit: dce6f2a

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@1egoman 1egoman requested review from lukasIO and bcherry August 4, 2025 19:56
try {
await Promise.all([
room.localParticipant.setMicrophoneEnabled(
true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this limits the usage of this hook to scenarios where users connect to rooms with their mic (and only their mic) enabled 🤔

Copy link
Contributor Author

@1egoman 1egoman Aug 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, you are correct, but this doesn't seem bad to me / was intentional.

I suppose maybe it could be nice to be able to configure whether this setMicrophoneEnabled runs here or not, to enable / disable the audio buffering behavior before connection? But besides that, is there a scenario where a user would want to connect to a room with something else like video enabled before room.connect(...) runs?

connectDisconnectLock.lock().then(async (unlock) => {
if (connected) {
setStatus('connecting');
const connectionDetails = await options.getConnectionDetails();
Copy link
Contributor

@lukasIO lukasIO Aug 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we employ this pattern we have to think about what happens if retrieving connection details here fails. E.g. is a user expected to flip connected to false and back to true on an error?

Also wondering if decoupling the two (connection and connectionDetails) makes more sense, as it can speed up the actual connection if connection Details retrieval happens in advance (e.g. like prefetch before you actually click)

});
}, [connected]);

return { room, status };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

returning the room here might lead to patterns that we don't really want to encourage, i.e. trying to call methods on the room itself again.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I had figured that was kinda the whole point, I'm not too well versed with this package yet. It sounds like the intention maybe is that the room would always be in the RoomContext and that is how other operations should be performed on it, including imperative updates?

@1egoman
Copy link
Contributor Author

1egoman commented Aug 5, 2025

Digging around, I actually discovered something that already exists which pretty closely matches what I think I was aiming to create here: https://github.com/livekit/components-js/blob/main/packages/react/src/hooks/useLiveKitRoom.ts and also https://github.com/livekit/components-js/blob/main/packages/react/src/components/LiveKitRoom.tsx. It's probably on me for missing this, it's pretty clearly called out in the docs!

I think given this discovery, I'm going to close this pull request and migrate the connection behavior from here into this pre-existing useLiveKitRoom hook / LiveKitRoom component.

@1egoman 1egoman closed this Aug 5, 2025
1egoman added a commit that referenced this pull request Aug 5, 2025
…nnect in series

Context around why this is important: #1197
1egoman added a commit that referenced this pull request Aug 5, 2025
…nnect in series

Context around why this is important: #1197
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants