Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

roomOptions changes are not applied to room #730

Open
mpnri opened this issue Dec 6, 2023 · 6 comments
Open

roomOptions changes are not applied to room #730

mpnri opened this issue Dec 6, 2023 · 6 comments

Comments

@mpnri
Copy link
Contributor

mpnri commented Dec 6, 2023

Select which package(s) are affected

@livekit/components-react

Describe the bug

In a running meet, if we want to make changes in the room options at the moment (such as changing the codec or changing the audio and video bitrate by using remote configs), those changes will not be applied. I searched through previous PRs and found that the following change in the useEffect dependencies in the useLiveKitRoom hook caused this to happen:
The PR link

image

Describe the proposed solution

I think reverting this change can fix the problem.

Reproduction

Consider this code:

const meetOptions = useMeetOptions(); //* Getting options from server

const { room } = useLiveKitRoom({ ...someRoomOptions, options: meetOptions })

If meetOptions changes due to a server update (or other methods of changing the options), the room will not change.

Logs

No response

System Info

Not needed

Severity

blocking an upgrade

Additional Information

No response

@lukasIO
Copy link
Contributor

lukasIO commented Dec 6, 2023

Could you elaborate a bit on what you'd expect to happen in that case (a reconnect?) and what the use case is for changing options mid-session?

@mpnri
Copy link
Contributor Author

mpnri commented Dec 7, 2023

Sure. Before that change(PR), with each change in room options, a new room with the same url and token was created and the previous room was disconnected. This meant that the user was actually experiencing a state similar to reconnecting. (And if the options were changed before joining the meet, the user would not notice the change at all.)

The benefit of using this(remote configs) is when there are many users using the app or there is a disruption in the Internet network, you can make changes in room options (for example in publishDefaults) without having to deploy a new version of the app to give users a better experience.

@lukasIO
Copy link
Contributor

lukasIO commented Dec 12, 2023

That makes sense. The reason why we did make that change was that we cannot stringify the options object anymore, as the end-to-end encryption options are too complex for that.
The alternative is to make the options object a dependency of a useEffect that sets the room, but this will result in an arguably worse developer experience, as you'd have to wrap your options object in a useState or useMemo.

cc @Ocupe for thoughts on this

@mpnri
Copy link
Contributor Author

mpnri commented Dec 13, 2023

Thanks for clarifying that.
Besides the alternative that you suggested, I have another idea that could be more effective. It might not be the most elegant solution in React 😅, but I think it would work better than JSON.stringify or useState and fix this issue.

In useLivekitRoom:

React.useEffect(() => {
    setRoom(passedRoom ?? new Room(options));
}, [passedRoom, useDeepCompare(options)]);

Definition of useDeepCompare:

type Value = Readonly<unknown>;
export const useDeepCompare = (value: Value): number => {
  const valueRef = React.useRef(value);
  const signalRef = React.useRef<number>(0);

  //* A function like lodash.isEqual or any custom or third party DeepCompare function.
  if (!isEqual(value, valueRef.current)) {
    valueRef.current = value;
    signalRef.current += 1;
  }

  //* return deps signal for `useEffect`
  return signalRef.current;
};

In this solution, whenever a re-render happens, it deep compares the last options and the new options, and if they are not the same, it increments the signalRef and returns it, which causes the useEffect callback to run.

@lukasIO
Copy link
Contributor

lukasIO commented Dec 13, 2023

thanks for the suggestion. I'd like to avoid deep comparing whenever possible as it will run every render cycle of react and that adds up quickly in performance impact.

@mpnri
Copy link
Contributor Author

mpnri commented Dec 13, 2023

Yeah you're right. So It seems there is no other way than putting options directly in the useEffect deps. (But I did some searching and it seems that even lodash.isEqual is about 50% faster than JSON.strigify, and maybe it doesn't have that much of a negative impact on performance)
A benchmark example

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

No branches or pull requests

2 participants