I'm extending the functionality of a timer component to add a beep
sound for the last 3 seconds of the timer. That works fine, the issue is after all is said and done. I'm doing the following:
- Wrapping the timer component on a new functional component
- Initialise the
Audio.Sound()
in the body of the component - Using
useEffect
to load the sound initially - On each timer event I check if I should play the sound and play it using
replayAsync
- On the
useEffect
cleanup I unload the sound object withunloadAsync
A second or so after the last beep has played and I've navigated to the following screen, I get an error which I'll past below in full. It seems there's a seeking operation being called on my sound object by the expo-av library, but my component is no longer there:
[Unhandled promise rejection: Error: Seeking interrupted.]
I've tried the following with no success:
- Make the calls to
loadAsync
andunloadAsync
await calls - Tried to
setOnPlaybakStatusUpdate
to null to try and prevent statusUpdate calls - I've even tried to not unload the soudn via
unloadAsync
My code is:
import React from 'react'
import CountDown from 'react-native-countdown-component'
import { Audio } from 'expo-av'
const BEEP_START = 3
const CountDownBeep = (props) => {
console.log('Sound Created')
const beepSound = new Audio.Sound()
React.useEffect(() => {
async function loadSound() {
console.log("Sound Initialized")
await beepSound.loadAsync(require('../assets/sounds/beep.wav'), {
shouldPlay: false,
isLooping: false,
})
// This is not by design, just one of my attempts to get rid of the error
beepSound.setOnPlaybackStatusUpdate()
}
loadSound()
// Cleanup, tried with async and without
return async () => {
console.log('Sound destroyed')
await beepSound.unloadAsync()
}
})
const countDownTimerChangedHandler = (timeLeft) => {
// This works fine
if (timeLeft <= BEEP_START + 1 && timeLeft > 0) {
console.log('Sound Played:', timeLeft)
beepSound.replayAsync()
}
}
return (
<CountDown
{...props}
onChange={(timeLeft) => countDownTimerChangedHandler(timeLeft)}
/>
)
}
export default CountDownBeep
The functionality is 100%, but after a few ms or a second or two after I navigate away to the next screen I get the following error:
[Unhandled promise rejection: Error: Seeking interrupted.]
- node_modules/react-native/Libraries/BatchedBridge/NativeModules.js:103:50 in promiseMethodWrapper
- node_modules/@unimodules/react-native-adapter/build/NativeModulesProxy.native.js:15:23 in moduleName.methodInfo.name
- node_modules/expo-av/build/Audio/Sound.js:138:24 in replayAsync
- node_modules/expo-av/build/Audio/Sound.js:5:33 in <anonymous>
- node_modules/regenerator-runtime/runtime.js:63:36 in tryCatch
- node_modules/regenerator-runtime/runtime.js:293:29 in invoke
- node_modules/regenerator-runtime/runtime.js:63:36 in tryCatch
- node_modules/regenerator-runtime/runtime.js:154:27 in invoke
- node_modules/regenerator-runtime/runtime.js:189:16 in PromiseImpl$argument_0
- node_modules/promise/setimmediate/core.js:45:6 in tryCallTwo
- node_modules/promise/setimmediate/core.js:200:22 in doResolve
- node_modules/promise/setimmediate/core.js:66:11 in Promise
- node_modules/regenerator-runtime/runtime.js:188:15 in callInvokeWithMethodAndArg
- node_modules/regenerator-runtime/runtime.js:211:38 in enqueue
- node_modules/regenerator-runtime/runtime.js:238:8 in exports.async
- node_modules/expo-av/build/Audio/Sound.js:5:33 in <anonymous>
- node_modules/expo-av/build/Audio/Sound.js:5:33 in <anonymous>
- node_modules/regenerator-runtime/runtime.js:63:36 in tryCatch
- node_modules/regenerator-runtime/runtime.js:293:29 in invoke
- node_modules/regenerator-runtime/runtime.js:63:36 in tryCatch
- node_modules/regenerator-runtime/runtime.js:154:27 in invoke
- node_modules/regenerator-runtime/runtime.js:189:16 in PromiseImpl$argument_0
- node_modules/promise/setimmediate/core.js:45:6 in tryCallTwo
- node_modules/promise/setimmediate/core.js:200:22 in doResolve
- node_modules/promise/setimmediate/core.js:66:11 in Promise
- node_modules/regenerator-runtime/runtime.js:188:15 in callInvokeWithMethodAndArg
- node_modules/regenerator-runtime/runtime.js:211:38 in enqueue
- node_modules/regenerator-runtime/runtime.js:238:8 in exports.async
- node_modules/expo-av/build/Audio/Sound.js:5:33 in <anonymous>
* components/CountDownBeep.js:31:24 in countDownTimerChangedHandler
* components/CountDownBeep.js:39:22 in CountDown.props.onChange
- node_modules/react-native-countdown-component/index.js:115:21 in CountDown#updateTimer
- node_modules/react-native/Libraries/Core/Timers/JSTimers.js:135:14 in _callTimer
- node_modules/react-native/Libraries/Core/Timers/JSTimers.js:387:16 in callTimers
- node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:425:19 in __callFunction
- node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:112:6 in __guard$argument_0
- node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:373:10 in __guard
- node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:111:4 in callFunctionReturnFlushedQueue
* [native code]:null in callFunctionReturnFlushedQueue