diff --git a/ts/components/GlobalAudioContext.tsx b/ts/components/GlobalAudioContext.tsx index dac1438a17..06f46ce5b5 100644 --- a/ts/components/GlobalAudioContext.tsx +++ b/ts/components/GlobalAudioContext.tsx @@ -21,6 +21,8 @@ export type GlobalAudioProps = { children?: React.ReactNode | React.ReactChildren; }; +const audioContext = new AudioContext(); + /** * A global context that holds Audio, AudioContext, LRU instances that are used * inside the conversation by ts/components/conversation/MessageAudio.tsx @@ -29,45 +31,33 @@ export const GlobalAudioProvider: React.FC = ({ conversationId, children, }) => { - const audio = React.useMemo(() => { - window.log.info( - 'GlobalAudioProvider: re-generating audio for', - conversationId - ); - return new Audio(); - }, [conversationId]); + const audio = React.useRef(null); + const waveformCache = React.useRef(null); - // NOTE: the number of active audio contexts is limited per tab/window - // See: https://developer.mozilla.org/en-US/docs/Web/API/AudioContext/AudioContext#google_chrome - const audioContext = React.useMemo(() => { - window.log.info('Instantiating new audio context'); - return new AudioContext(); - }, []); - - const waveformCache: WaveformCache = React.useMemo(() => { - return new LRU({ + // NOTE: We don't want to construct these values on every re-render hence + // the constructor calls have to be guarded by `if`s. + if (!audio.current) { + audio.current = new Audio(); + } + if (!waveformCache.current) { + waveformCache.current = new LRU({ max: MAX_WAVEFORM_COUNT, }); - }, []); + } // When moving between conversations - stop audio React.useEffect(() => { return () => { - audio.pause(); + if (audio.current) { + audio.current.pause(); + } }; - }, [audio, conversationId]); - - React.useEffect(() => { - return () => { - window.log.info('Closing old audio context'); - audioContext.close(); - }; - }, [audioContext]); + }, [conversationId]); const value = { - audio, + audio: audio.current, audioContext, - waveformCache, + waveformCache: waveformCache.current, }; return ( diff --git a/ts/util/lint/exceptions.json b/ts/util/lint/exceptions.json index ce63189e08..8ac070eee2 100644 --- a/ts/util/lint/exceptions.json +++ b/ts/util/lint/exceptions.json @@ -11903,6 +11903,14 @@ "reasonCategory": "falseMatch", "updated": "2018-09-19T18:06:35.446Z" }, + { + "rule": "jQuery-wrap(", + "path": "node_modules/pino/browser.js", + "line": " wrap(opts, logger, level)", + "lineNumber": 181, + "reasonCategory": "falseMatch", + "updated": "2021-03-09T20:56:35.403Z" + }, { "rule": "jQuery-$(", "path": "node_modules/popper.js/dist/esm/popper.min.js", @@ -14696,6 +14704,24 @@ "updated": "2020-11-11T21:56:04.179Z", "reasonDetail": "Needed to render the remote video element." }, + { + "rule": "React-useRef", + "path": "ts/components/GlobalAudioContext.js", + "line": " const audio = React.useRef(null);", + "lineNumber": 38, + "reasonCategory": "usageTrusted", + "updated": "2021-03-11T17:20:05.355Z", + "reasonDetail": "Need this to avoid re-creating Audio on every re-render" + }, + { + "rule": "React-useRef", + "path": "ts/components/GlobalAudioContext.js", + "line": " const waveformCache = React.useRef(null);", + "lineNumber": 39, + "reasonCategory": "usageTrusted", + "updated": "2021-03-11T17:20:05.355Z", + "reasonDetail": "Need this to avoid re-creating WaveformCache on every re-render" + }, { "rule": "React-useRef", "path": "ts/components/GroupCallOverflowArea.js", @@ -15444,13 +15470,5 @@ "reasonCategory": "usageTrusted", "updated": "2021-01-08T15:46:32.143Z", "reasonDetail": "Doesn't manipulate the DOM. This is just a function." - }, - { - "rule": "jQuery-wrap(", - "path": "node_modules/pino/browser.js", - "line": " wrap(opts, logger, level)", - "lineNumber": 181, - "reasonCategory": "falseMatch", - "updated": "2021-03-09T20:56:35.403Z" } -] +] \ No newline at end of file