Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion react/features/base/app/components/BaseApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { compose, createStore } from 'redux';
import Thunk from 'redux-thunk';

import { IStore } from '../../../app/types';
import { registerRecordingAudioFiles } from '../../../recording/functions';
import i18next from '../../i18n/i18next';
import MiddlewareRegistry from '../../redux/MiddlewareRegistry';
import PersistenceRegistry from '../../redux/PersistenceRegistry';
Expand Down Expand Up @@ -143,7 +144,17 @@ export default class BaseApp<P> extends Component<P, IState> {
*
* @returns {void}
*/
_extraInit() {
async _extraInit() {
// Register sounds early to prevent timing issues
if (this.state.store) {
console.log('BaseApp._extraInit: Registering recording sounds early');
registerRecordingAudioFiles(this.state.store.dispatch);

// Give Redux a chance to process the registration actions
await new Promise(resolve => setTimeout(resolve, 10));
} else {
console.log('BaseApp._extraInit: Store not available yet');
}
// To be implemented by subclass.
}

Expand Down
79 changes: 79 additions & 0 deletions react/features/base/sounds/middleware.any.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,96 @@ function _playSound({ getState }: IStore, soundId: string) {
const sounds = getState()['features/base/sounds'];
const sound = sounds.get(soundId);

// Debug logging for recording sounds
if (soundId.includes('RECORDING') || soundId.includes('STREAMING')) {
logger.info('_playSound debug:', {
soundId,
soundExists: !!sound,
hasAudioElement: !!sound?.audioElement,
soundsSize: sounds.size,
allSoundIds: Array.from(sounds.keys())
});
}

if (sound) {
if (sound.audioElement) {
sound.audioElement.play();
} else {
logger.warn(`PLAY_SOUND: sound not loaded yet for id: ${soundId}`);

// For recording sounds, keep retrying until audio element is loaded
if (soundId.includes('RECORDING') || soundId.includes('STREAMING')) {
_retryPlaySound(getState, soundId, 1);
}
}
} else {
logger.warn(`PLAY_SOUND: no sound found for id: ${soundId}`);
// For recording sounds, retry until found and loaded
if (soundId.includes('RECORDING') || soundId.includes('STREAMING')) {
setTimeout(() => {
const retrySounds = getState()['features/base/sounds'];
const retrySound = retrySounds.get(soundId);

logger.info('_playSound retry debug (not found):', {
soundId,
retrySoundExists: !!retrySound,
hasAudioElement: !!retrySound?.audioElement
});
if (retrySound?.audioElement) {
retrySound.audioElement.play();
} else {
// Try one more time with an even longer delay
setTimeout(() => {
const finalRetrySounds = getState()['features/base/sounds'];
const finalRetrySound = finalRetrySounds.get(soundId);

if (finalRetrySound?.audioElement) {
finalRetrySound.audioElement.play();
}
}, 3000);
}
}, 2000); // Even longer delay for sounds that weren't found
}
}
}

/**
* Retries playing a sound with exponential backoff until it's loaded.
*
* @param {Function} getState - Redux getState function.
* @param {string} soundId - The sound ID to retry.
* @param {number} attempt - Current attempt number.
* @private
* @returns {void}
*/
function _retryPlaySound(getState: IStore['getState'], soundId: string, attempt: number) {
const maxAttempts = 10; // Maximum 10 attempts
const baseDelay = 500; // Start with 500ms
const delay = Math.min(baseDelay * Math.pow(2, attempt - 1), 5000); // Exponential backoff, max 5s

setTimeout(() => {
const sounds = getState()['features/base/sounds'];
const sound = sounds.get(soundId);

logger.info(`_playSound retry attempt ${attempt}:`, {
soundId,
soundExists: !!sound,
hasAudioElement: !!sound?.audioElement,
delay
});

if (sound?.audioElement) {
// Success! Audio element is loaded
sound.audioElement.play();
} else if (attempt < maxAttempts) {
// Try again
_retryPlaySound(getState, soundId, attempt + 1);
} else {
logger.warn(`Failed to load audio element for ${soundId} after ${maxAttempts} attempts`);
}
}, delay);
}

/**
* Stop sound from audio element registered in the Redux store.
*
Expand Down