TheWidlarzGroup / react-native-video

A <Video /> component for react-native
http://thewidlarzgroup.github.io/react-native-video/
MIT License
7.15k stars 2.88k forks source link

[BUG]: AVFoundationErrorDomain on iOS when playing .mp3 file #3551

Open benlumsden2 opened 7 months ago

benlumsden2 commented 7 months ago

Version

v6 (Beta) also happened on v0 (Beta)

What platforms are you having the problem on?

iOS

Architecture

New architecture with interop layer

What happened?

We are receiving numerous Sentry alerts indicating there is an error loading / playing the video.

The error is as follows:

{
  "error": {
    "code": -11800,
    "domain": "AVFoundationErrorDomain",
    "localizedFailureReason": "An unknown error occurred (-66637)",
    "localizedDescription": "The operation could not be completed",
    "localizedRecoverySuggestion": ""
  },
  "target": 6499
}

The error seems to be specific to iOS, regardless of model or iOS version.

It does not happen to everyone, but seems to almost happen randomly

Reproduction

Unable to provide specific steps to reproduce as the exact source of the problem is yet to be found, but this is a sample of the code we use:

interface RecordSilentVideoProps {
    updateTimer: () => void
}

export const SILENT_AUDIO = require(':/sounds/1-minute-of-silence.mp3')
export const BACKGROUND_TIMER_UPDATE_INTERVAL = isAndroid() ? ONE_SEC_MS * 2 : ONE_SEC_MS

/**
* Update the workout timer when the app goes into the background
* using the <Video> component.
*/
const updateTimer = useCallback(() => {
  if (!isInForeground && isCountdownRunning) {
      countdownTimer.updateTime()
  } else if (!isInForeground && !isInactive) {
      updateTimerBackground()
      if (isIOSDevice) {
          refreshLiveActivity()
      }
  }
}, [
  countdownTimer,
  isCountdownRunning,
  isIOSDevice,
  isInForeground,
  isInactive,
  refreshLiveActivity,
  updateTimerBackground,
])

const RecordSilentVideo = ({ updateTimer }: RecordSilentVideoProps) => {
    const videoRef = useRef<VideoRef>(null)

    const handleStateChange = useCallback((state: OnPlaybackStateChangedData) => {
        // if for any reason the video playback stops, force resume it
        if (!state.isPlaying) {
            videoRef.current?.resume()
        }
    }, [])

    const handleError = useCallback((e: OnVideoErrorData) => {
        log.error('ROD: Android Video Error', e)
    }, [])

    const handleUpdateTimer = useCallback(() => {
        updateTimer()
    }, [updateTimer])

    return (
        <Video
            style={{ height: SPACING.s2, width: SPACING.s2 }}
            ref={videoRef}
            source={SILENT_AUDIO}
            repeat
            paused={false}
            rate={1.0}
            controls={false}
            mixWithOthers={MixWithOthersType.MIX}
            disableFocus
            focusable={false}
            disableDisconnectError
            playWhenInactive
            muted
            playInBackground
            preventsDisplaySleepDuringVideoPlayback
            ignoreSilentSwitch={IgnoreSilentSwitchType.IGNORE}
            bufferConfig={{
                minBufferMs: 0,
                maxBufferMs: 0,
                bufferForPlaybackMs: 0,
                bufferForPlaybackAfterRebufferMs: 0,
            }}
            progressUpdateInterval={BACKGROUND_TIMER_UPDATE_INTERVAL}
            onProgress={handleUpdateTimer}
            onPlaybackStateChanged={handleStateChange}
            onError={handleError}
        />
    )
}

export default RecordSilentVideo

The error reported to Sentry is being invoked by handleError.

Any suggestions to find the root of this problem will be much appreciated - thanks in advance!

KrzysztofMoch commented 7 months ago

Hey, I tried to reproduce it, but I was unsuccessful 😐 - I guess without stack trace there is nothing we can do

benlumsden2 commented 6 months ago

We seem to have a couple of error codes commonly coming through: -11819 (mediaServicesWereReset) https://developer.apple.com/documentation/avfoundation/averror/code/mediaserviceswerereset/

-11800 (unknown) https://developer.apple.com/documentation/avfoundation/averror/code/unknown/

This is one of our stack traces. Hopefully it is helpful

{
  "error": {
    "domain": "AVFoundationErrorDomain",
    "localizedFailureReason": "An unknown error occurred (-66637)",
    "localizedDescription": "The operation could not be completed",
    "localizedRecoverySu...
  at customTransport(src/utils/logger.ts:15:27)
  at this._sendToTransport(node_modules/react-native-logs/dist/index.js:141:32)
  at this._log(node_modules/react-native-logs/dist/index.js:115:45)
  at handleError(src/components/RecordSilentVideo/RecordSilentVideo.tsx:29:12)
  at onVideoError(node_modules/react-native-video/src/Video.tsx:284:16)
  at apply(native)
  at invokeGuardedCallbackImpl(node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:22:15)
  at apply(native)
  at invokeGuardedCallback(node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:40:34)
  at apply(native)
  at invokeGuardedCallbackAndCatchFirstError(node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:53:30)
  at executeDispatch(node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:73:42)
  at executeDispatchesAndReleaseTopLevel(node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:1125:24)
  at call(native)
  at forEachAccumulated(node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:361:63)
  at anonymous(node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:1160:25)
  at batchedUpdatesImpl(node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:8457:14)
  at batchedUpdates(node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:1106:30)
  at _receiveRootNodeIDEvent(node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:1137:17)
  at <object>.receiveEvent(node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:1178:28)
  at apply(native)
  at <object>.__callFunction(node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:433:34)
  at anonymous(node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:113:26)
  at <object>.__guard(node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:368:11)
  at <object>.callFunctionReturnFlushedQueue(node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:112:17)
freeboub commented 6 months ago

Without additionnal information, we cannot do anytrhing for this issue... can you provide a sample mp3 url ? did you try with the basic sample included in the repo ?

benlumsden2 commented 6 months ago

Hey, I understand it's a difficult one to debug as we have such limited information on it. It's proven very difficult to test ourselves too, as we are unable to reproduce it too. It only seems to be coming in on a whim with no obvious trend.

We received this error stack trace come through for an Android user, which could also be the same cause for the iOS error?:

{
  "error": {
    "errorStackTrace": "androidx.media3.exoplayer.ExoPlaybackException: MediaCodecAudioRenderer error, index=1, format=Format(null, null, null, audio/mpeg, null, -1, null, [-1, -1, -1.0, null], [1, 8000]), format_supported=YES\n\tat androidx.media3.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:601)\n\tat android.os.Handler.dispatchMessage(Handler.java:102)\n\tat android.os.Looper.loopOnce(Looper.java:233)\n\tat android.os.Looper.loop(Looper.java:344)\n\tat android.os.HandlerThread.run(HandlerThread.java:67)\nCaused by: androidx.media3.exoplayer.audio.AudioSink$InitializationException: AudioTrack init failed 0 Config(8000, 4, 5184) Format(null, null, null, audio/raw, null, -1, null, [-1, -1, -1.0, null], [1, 8000])\n\tat androidx.media3.exoplayer.audio.DefaultAudioSink$Configuration.buildAudioTrack(DefaultAudioSink.java:2109)\n\tat androidx.media3.exoplayer.audio.DefaultAudioSink.buildAudioTrack(DefaultAudioSink.java:1019)\n\tat androidx.media3.exoplayer.audio.DefaultAudioSink.buildAudioTrackWithRetry(DefaultAudioSink.java:997)\n\tat androidx.media3.exoplayer.audio.DefaultAudioSink.initializeAudioTrack(DefaultAudioSink.java:789)\n\tat androidx.media3.exoplayer.audio.DefaultAudioSink.handleBuffer(DefaultAudioSink.java:875)\n\tat androidx.media3.exoplayer.audio.MediaCodecAudioRenderer.processOutputBuffer(MediaCodecAudioRenderer.java:712)\n\tat androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.drainOutputBuffer(MediaCodecRenderer.java:1940)\n\tat androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:816)\n\tat androidx.media3.exoplayer.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:1047)\n\tat androidx.media3.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:522)\n\t... 4 more\n\tSuppressed: androidx.media3.exoplayer.audio.AudioSink$InitializationException: AudioTrack init failed 0 Config(8000, 4, 5184) Format(null, null, null, audio/raw, null, -1, null, [-1, -1, -1.0, null], [1, 8000])\n\t\t... 14 more\n\tCaused by: java.lang.UnsupportedOperationException: Cannot create AudioTrack\n\t\tat android.media.AudioTrack$Builder.build(AudioTrack.java:1308)\n\t\tat androidx.media3.exoplayer.drm.FrameworkMediaDrm$$ExternalSyntheticApiModelOutline0.m(Unknown Source:0)\n\t\tat androidx.media3.exoplayer.audio.DefaultAudioSink$Configuration.createAudioTrackV29(DefaultAudioSink.java:2158)\n\t\tat androidx.media3.exoplayer.audio.DefaultAudioSink$Configuration.createAudioTrack(DefaultAudioSink.java:2136)\n\t\tat androidx.media3.exoplayer.audio.DefaultAudioSink$Configuration.buildAudioTrack(DefaultAudioSink.java:2101)\n\t\t... 13 more\nCaused by: java.lang.UnsupportedOperationException: Cannot create AudioTrack\n\tat android.media.AudioTrack$Builder.build(AudioTrack.java:1308)\n\tat androidx.media3.exoplayer.drm.FrameworkMediaDrm$$ExternalSyntheticApiModelOutline0.m(Unknown Source:0)\n\tat androidx.media3.exoplayer.audio.DefaultAudioSink$Configuration.createAudioTrackV29(DefaultAudioSink.java:2158)\n\tat androidx.media3.exoplayer.audio.DefaultAudioSink$Configuration.createAudioTrack(DefaultAudioSink.java:2136)\n\tat androidx.media3.exoplayer.audio.DefaultAudioSink$Configuration.buildAudioTrack(DefaultAudioSink.java:2101)\n\t... 13 more\n",
    "errorCode": "25001",
    "errorException": "androidx.media3.exoplayer.ExoPlaybackException: MediaCodecAudioRenderer error, index=1, format=Format(null, null, null, audio/mpeg, null, -1, null, [-1, -1, -1.0, null], [1, 8000]), format_supported=YES",
    "errorString": "ExoPlaybackException: ERROR_CODE_AUDIO_TRACK_INIT_FAILED"
  }
}

which looks as if it's attempted to load a .mp3 file as an mpeg.

If there's anything else in that error trace which might be useful, please let me know.

It's just a local file which is loaded (see attached): export const SILENT_AUDIO = require(':/sounds/1-minute-of-silence.mp3')

You can see in the screenshot the file properties.

Screenshot 2024-03-15 at 09 19 32
github-actions[bot] commented 1 week ago

This issue is stale because it has been open for 30 days with no activity. If there won't be any activity in the next 14 days, this issue will be closed automatically.