Skip to content

Commit c5f43a5

Browse files
author
Sravan S
authored
fix: Race condition in playing audio file (#608)
Race condition occurs when two audio files are requested from backend clear previous player and play only the last arrived file Cleanup - Do not need to fetch audio file if its already in cache Fixes: https://sendbird.atlassian.net/browse/UIKIT-3952
1 parent ca9986a commit c5f43a5

File tree

1 file changed

+41
-17
lines changed

1 file changed

+41
-17
lines changed

src/hooks/VoicePlayer/index.tsx

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -94,19 +94,25 @@ export const VoicePlayerProvider = ({
9494
}
9595

9696
logger.info('VoicePlayer: Start getting audio file.');
97-
new Promise((resolve) => {
97+
new Promise<File>((resolve) => {
98+
voicePlayerDispatcher({
99+
type: INITIALIZE_AUDIO_UNIT,
100+
payload: { groupKey },
101+
});
102+
// audio file passed as a parameter
98103
if (audioFile) {
99-
resolve(audioFile);
100104
logger.info('VoicePlayer: Use the audioFile instance.');
105+
resolve(audioFile);
106+
return;
101107
}
102-
if (audioStorage?.[groupKey]?.audioFile) {
103-
resolve(audioStorage[groupKey].audioFile);
108+
// audio file from the audioStorage
109+
const cachedAudioFile = audioStorage?.[groupKey]?.audioFile;
110+
if (cachedAudioFile) {
104111
logger.info('VoicePlayer: Get from the audioStorage.');
112+
resolve(cachedAudioFile);
113+
return;
105114
}
106-
voicePlayerDispatcher({
107-
type: INITIALIZE_AUDIO_UNIT,
108-
payload: { groupKey },
109-
});
115+
// fetch the audio file from URL
110116
fetch(audioFileUrl)
111117
.then((res) => res.blob())
112118
.then((blob) => {
@@ -118,7 +124,8 @@ export const VoicePlayerProvider = ({
118124
logger.info('VoicePlayer: Get the audioFile from URL.');
119125
});
120126
}).then((audioFile: File) => {
121-
logger.info('VoicePlayer: Succeeded getting audio file.', audioFile);
127+
const voicePlayerRoot = document.getElementById(VOICE_PLAYER_ROOT_ID);
128+
logger.info('VoicePlayer: Succeeded getting audio file.', { audioFile });
122129
const currentAudioUnit = audioStorage[groupKey] || AudioUnitDefaultValue() as AudioStorageUnit;
123130
const audioPlayer = new Audio(URL?.createObjectURL?.(audioFile));
124131
audioPlayer.id = VOICE_PLAYER_AUDIO_ID;
@@ -145,14 +152,31 @@ export const VoicePlayerProvider = ({
145152
payload: { groupKey },
146153
});
147154
};
148-
audioPlayer?.play();
149-
const voicePlayerRoot = document.getElementById(VOICE_PLAYER_ROOT_ID);
150-
voicePlayerRoot.appendChild(audioPlayer);
151-
voicePlayerDispatcher({
152-
type: SET_CURRENT_PLAYER,
153-
payload: { groupKey, audioPlayer },
154-
});
155-
logger.info('VoicePlayer: Succeeded playing audio player.', { groupKey, audioPlayer });
155+
audioPlayer.dataset.sbGroupId = groupKey;
156+
// clean up the previous audio player
157+
try {
158+
voicePlayerRoot?.childNodes.forEach((node) => {
159+
const element = node as HTMLAudioElement;
160+
const thisGroupKey = element.dataset?.sbGroupKey;
161+
if (thisGroupKey !== groupKey) {
162+
element?.pause?.();
163+
voicePlayerDispatcher({
164+
type: ON_VOICE_PLAYER_PAUSE,
165+
payload: { groupKey },
166+
});
167+
voicePlayerRoot.removeChild(element);
168+
logger.info('VoicePlayer: Removed other player.', { element });
169+
}
170+
});
171+
} finally {
172+
audioPlayer?.play();
173+
voicePlayerRoot?.appendChild(audioPlayer);
174+
voicePlayerDispatcher({
175+
type: SET_CURRENT_PLAYER,
176+
payload: { groupKey, audioPlayer },
177+
});
178+
logger.info('VoicePlayer: Succeeded playing audio player.', { groupKey, audioPlayer });
179+
}
156180
});
157181
};
158182

0 commit comments

Comments
 (0)