Reputation: 73908
for (const localTrack of localTracks) {
if (localTrack.kind === 'video') {
localParticipant.publishTrack(localTrack, {
priority: 'low',
});
} else {
localParticipant.publishTrack(localTrack, {
priority: 'standard',
});
}
}
I am currently getting an error:
TwilioError: Track name is duplicated
This is because this method is called multiple times (each time a new permission is approved) with the list of all approved tracks.
How do I check if a particular track has been already published?
One would expect that we can inspect the localParticipant
object, e.g.
console.log(
'>>>',
localParticipant.tracks.size,
localParticipant.audioTracks.size,
localParticipant.videoTracks.size
);
but the above produces >>> 0 0 0
and then is followed by "Track name is duplicated" error. So there is some race-condition error.
Upvotes: 1
Views: 334
Reputation: 73908
This was indeed a race condition, and to understand how we got there, we need the full code example:
useEffect(() => {
if (!localParticipant) {
return;
}
for (const localTrack of localTracks) {
if (localTrack.kind === 'video') {
localParticipant.publishTrack(localTrack, {
priority: 'low',
});
} else {
localParticipant.publishTrack(localTrack, {
priority: 'standard',
});
}
}
return () => {
localParticipant.audioTracks.forEach((publication) => {
publication.unpublish();
});
localParticipant.videoTracks.forEach((publication) => {
publication.unpublish();
});
};
}, [localParticipant, localTracks]);
What is happening here is that every time localParticipant
or localTracks
change, we do two things:
Somehow the clean up logic causes the localParticipant.publishTrack
method to go into an error state ("Track name is duplicated") publishTrack
is invoked just after unpublish
.
The fix is to simply move unpublish
logic into a separate hook that does not depend on localTracks
.
useEffect(() => {
if (!localParticipant) {
return;
}
return () => {
localParticipant.audioTracks.forEach((publication) => {
publication.unpublish();
});
localParticipant.videoTracks.forEach((publication) => {
publication.unpublish();
});
};
}, [localParticipant]);
useEffect(() => {
if (!localParticipant) {
return;
}
for (const localTrack of localTracks) {
if (localTrack.kind === 'video') {
localParticipant.publishTrack(localTrack, {
priority: 'low',
});
} else {
localParticipant.publishTrack(localTrack, {
priority: 'standard',
});
}
}
}, [localParticipant, localTracks]);
Note that you need to do this in addition for handling events. The unmount clean-up strategy is used here primarily to enable react hot reloading.
Upvotes: 1