Skip to content

Commit 04a3f39

Browse files
authored
fix(react-client): await pending addTrack to fix track ops race (#527)
## Description `getCurrentTrackId` now awaits the in-flight `addTrack` promise before returning, so callers always see the resolved remote track id once the track is registered. - Add `connectionPromiseRef` storing the active `addTrack` job - Make `getCurrentTrackId` async and await pending job - Update callers (`replaceTrack`, `refreshStreamedTrack`, `toggleMute`, `toggleDevice`) to await the new async signature - Await `pauseStreaming` in `toggleDevice` ## Motivation and Context `startStreaming` set `currentTrackIdRef.current` only after `addTrack` resolved. If the user invoked `toggleMute`, `replaceTrack`, or `toggleDevice` during that window, `getCurrentTrackId` returned `null` and the operation silently no-op'd (mute toggles ignored, replace skipped). Awaiting the pending promise removes the race. ## Documentation impact - [ ] Documentation update required - [ ] Documentation updated [in another PR](_) - [x] No documentation update required ## Types of changes - [x] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
1 parent bb70155 commit 04a3f39

1 file changed

Lines changed: 12 additions & 7 deletions

File tree

packages/react-client/src/hooks/internal/useTrackManager.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export const useTrackManager = ({
2727
logger,
2828
}: TrackManagerConfig): TrackManager => {
2929
const currentTrackIdRef = useRef<string | null>(null);
30+
const connectionPromiseRef = useRef<Promise<string> | null>(null);
3031

3132
const {
3233
startDevice,
@@ -43,7 +44,10 @@ export const useTrackManager = ({
4344
// every time it changes.
4445
const getDeviceTrack = useCurrentCallback(() => deviceTrack);
4546

46-
const getCurrentTrackId = (): string | null => {
47+
const getCurrentTrackId = async (): Promise<string | null> => {
48+
if (connectionPromiseRef.current) {
49+
await connectionPromiseRef.current;
50+
}
4751
const refTrackId = currentTrackIdRef.current;
4852
if (!refTrackId) return null;
4953
const currentTrack = getRemoteOrLocalTrack(tsClient, refTrackId);
@@ -57,7 +61,7 @@ export const useTrackManager = ({
5761
const [newTrack, error] = result;
5862
if (error) return error;
5963

60-
const currentTrackId = getCurrentTrackId();
64+
const currentTrackId = await getCurrentTrackId();
6165
if (!currentTrackId) return;
6266

6367
await tsClient.replaceTrack(currentTrackId, newTrack);
@@ -66,7 +70,7 @@ export const useTrackManager = ({
6670
const setTrackMiddleware = useCurrentCallback(async (middleware: TrackMiddleware) => {
6771
const processedTrack = await applyMiddleware(middleware);
6872

69-
const currentTrackId = getCurrentTrackId();
73+
const currentTrackId = await getCurrentTrackId();
7074
if (!currentTrackId) return;
7175

7276
await tsClient.replaceTrack(currentTrackId, processedTrack);
@@ -90,8 +94,9 @@ export const useTrackManager = ({
9094
const [maxBandwidth, simulcastConfig] = getConfigAndBandwidthFromProps(props.sentQualities, bandwidthLimits);
9195

9296
try {
93-
const remoteTrackId = await tsClient.addTrack(track, trackMetadata, simulcastConfig, maxBandwidth);
94-
97+
const addTrackJob = tsClient.addTrack(track, trackMetadata, simulcastConfig, maxBandwidth);
98+
connectionPromiseRef.current = addTrackJob;
99+
const remoteTrackId = await addTrackJob;
95100
currentTrackIdRef.current = remoteTrackId;
96101
} catch (err) {
97102
if (err instanceof TrackTypeError) {
@@ -119,7 +124,7 @@ export const useTrackManager = ({
119124
* @see {@link TrackManager#toggleMute} for more details.
120125
*/
121126
const toggleMute = useCurrentCallback(async () => {
122-
const currentTrackId = getCurrentTrackId();
127+
const currentTrackId = await getCurrentTrackId();
123128
const isTrackCurrentlyEnabled = Boolean(deviceTrack?.enabled);
124129
if (!currentTrackId) {
125130
logger.warn("Toggling mute is only possible while connected to a room.");
@@ -139,7 +144,7 @@ export const useTrackManager = ({
139144
* @see {@link TrackManager#toggleDevice} for more details.
140145
*/
141146
const toggleDevice = useCurrentCallback(async () => {
142-
const currentTrackId = getCurrentTrackId();
147+
const currentTrackId = await getCurrentTrackId();
143148
if (deviceTrack) {
144149
stopDevice();
145150
if (currentTrackId) {

0 commit comments

Comments
 (0)