Intermittent audio cut in SCORM packages – possible rlplayer.js trigger

Whenever I use the text-to-speech feature, the generated audio is automatically configured with an entrance effect (“Appear”) and an exit effect (“Disappear”). Could you explain why this happens?

We have recently created several training SCORM packages using ActivePresenter 10.x. Occasionally, colleagues who view these packages report that on some slides the audio stops unexpectedly about 0.5 to 1 second before the slide actually ends. From our analysis, it looks like an event in rlplayer.js may be triggering this stop/pause.

We also noticed a difference when we enable the option “Show to the end of the slide” for the audio: in that case, the “Disappear” effect is no longer applied, and the audio seems to play through more reliably. Could you clarify what changes internally when using this option, and how it interacts with entrance/exit effects?

Finally, have you heard of similar reports from other users? The main challenge is that the issue appears randomly, making it difficult for us to reproduce consistently.

Hi,

In ActivePresenter, audio generated by the Text-to-Speech feature is treated as an object with a defined duration on the timeline. To manage this, the software automatically applies “Appear” and “Disappear” effects to control when the audio starts and ends. This is by design and helps synchronize the audio with other slide elements.

When the option “Show to the end of the slide” is enabled, the audio duration is extended to match the slide length and the exit effect is disabled. As a result, the “Disappear” effect is removed, allowing the audio to play until the slide ends. This helps reduce the risk of the player stopping the audio early due to timing or synchronization issues.

We have received occasional reports of similar behavior, especially in HTML5/SCORM output, where browser timing and player events can affect playback. As a workaround, we recommend enabling “Show to the end of the slide” or slightly extending the audio object on the timeline for more reliable playback.

Regards,

The reason why I am asking is this:

I have generated a test AP 10.x project with 2 times and an audio saying “This is a test”. One I generated with “Show to the end of the slide” Audio #1 the other in standard mode with usual entrance and exit effect as Audio #2.

Then I wrote a chrome debug script that is printing a web browser SCORM log to the chrome debug console and let it analyse this with chatGPT afterwads. It says:

What exactly is happening?

  • Audio #1 (res_10000.m4a) plays all the way to the end and finishes cleanly:
    t=2.427, left=0.000, then pause + ended.

  • Audio #2 (res_10001.m4a) is started before Audio #1 finishes (the overlap is visible in the log).

  • Audio #2 is then actively stopped:
    🚨 CUT DETECTED … left=0.609
    Immediately afterwards you see ⏸️ pause() called …
    And the stack trace points to rlplayer.js (i.Hc and i.js) → meaning the player triggers the pause, not the browser.


Important: Is Audio #2 being removed?

No. Your additional checks show:
post-CUT check +0ms/+80ms/+250ms: isConnected=true

This means: Audio #2 remains in the DOM, but it is paused by the player.

Here is the log by the way

[11:21:11] :white_check_mark: Overlay active on https://lms.hilscher.local:445/pluginfile.php/900/mod_scorm/content/5/HTML5/index.html (frame=child sameOriginTop=true)
VM184:62 [11:21:11] —————————————————————————————
VM184:62 [11:21:11] :white_check_mark: API_1484_11 found via parent^1 (hooked=true)
VM184:62 [11:21:11] —————————————————————————————
VM184:62 [11:21:11] :white_check_mark: fetch hook installed (ALL).
VM184:62 [11:21:11] :white_check_mark: XHR hook installed (ALL).
VM184:62 [11:21:11] —————————————————————————————
VM184:62 [11:21:11] :white_check_mark: DOM removal hooks installed (removeChild/replaceChild/remove).
VM184:62 [11:21:11] :white_check_mark: Media property setter hooks installed (src/currentTime/etc).
VM184:62 [11:21:11] :white_check_mark: Media element hook active. Found: 0
VM184:62 [11:21:11] :white_check_mark: pause()/play() stack hook active (+ cut detect + media lifecycle).
VM184:62 [11:21:11] —————————————————————————————
VM184:62 [11:21:11] :white_check_mark: AudioContext hook installed (best effect after reload).
VM184:62 [11:21:11] —————————————————————————————
VM184:62 [11:21:11] :white_check_mark: Global error hooks installed.
VM184:62 [11:21:11] —————————————————————————————
VM184:62 [11:21:11] :white_check_mark: Ready. Watch for: :police_car_light: CUT DETECTED (auto-dump), :compass: nav signals, :brick: near-CUT DOM change, :wastebasket: removals, :clapper_board: waiting/stalled/error, :repeat_button: src/currentTime changes, :eye: visibility, :window: focus/blur.
VM184:62 [11:21:23] :pushpin: SCORM SetValue cmi.suspend_data “{“info”:{“slides”:[{},{}],“slideIds”:[77,75],“fbs”:,“randomMap”:{},“vars”:{“apScoreSubtract”:0},“index”:1,“ts”:0,“elapsedTime”:10057,“maxVisitedIdx”:1,“maxVisitedTs”:8090},“map”:{},“nextIdx”:0}”
↳ at obj. [as SetValue] (:232:20) | at doSetValue (https://lms.hilscher.local:445/pluginfile.php/900/mod_scorm/content/5/HTML5/player/APIWrapper.js:223:24)
VM184:62 [11:21:23] :pushpin: SCORM Commit “”
↳ at obj. [as Commit] (:232:20) | at doCommit (https://lms.hilscher.local:445/pluginfile.php/900/mod_scorm/content/5/HTML5/player/APIWrapper.js:253:24)
VM184:62 [11:21:23] :window: window blur
VM184:62 [11:21:23] :plus: media added: audio:res_10000.m4a
VM184:62 [11:21:23] :plus: media added: audio:res_10001.m4a
9XHR finished loading: POST “”.
VM184:62 [11:21:23] :clapper_board: play src=audio:res_10000.m4a t=0.000 dur=2.427 left=2.427 paused=false ended=false rs=4 ns=1 vis=visible
VM184:62 [11:21:23] :clapper_board: playing src=audio:res_10000.m4a t=0.000 dur=2.427 left=2.427 paused=false ended=false rs=4 ns=1 vis=visible
VM184:62 [11:21:24] :clapper_board: timeupdate src=audio:res_10000.m4a t=0.099 dur=2.427 left=2.328 paused=false ended=false rs=4 ns=1 vis=visible
VM184:62 [11:21:24] :white_check_mark: Media element hook active. Found: 2
VM184:62 [11:21:24] :clapper_board: timeupdate src=audio:res_10000.m4a t=0.362 dur=2.427 left=2.065 paused=false ended=false rs=4 ns=1 vis=visible
VM184:62 [11:21:24] :clapper_board: timeupdate src=audio:res_10000.m4a t=0.622 dur=2.427 left=1.805 paused=false ended=false rs=4 ns=1 vis=visible
VM184:62 [11:21:24] :clapper_board: timeupdate src=audio:res_10000.m4a t=0.895 dur=2.427 left=1.532 paused=false ended=false rs=4 ns=1 vis=visible
VM184:62 [11:21:25] :clapper_board: timeupdate src=audio:res_10000.m4a t=1.164 dur=2.427 left=1.263 paused=false ended=false rs=4 ns=1 vis=visible
VM184:62 [11:21:25] :white_check_mark: Media element hook active. Found: 2
VM184:62 [11:21:25] :play_button: play() called on audio:res_10001.m4a
↳ at el.play (:470:20) | at i.js (https://lms.hilscher.local:445/pluginfile.php/900/mod_scorm/content/5/HTML5/player/rlplayer.js:101:259649) | at Object.set (https://lms.hilscher.local:445/pluginfile.php/900/mod_scorm/content/5/HTML5/player/rlplayer.js:101:357898) | at i.toTarget (https://lms.hilscher.local:445/pluginfile.php/900/mod_scorm/content/5/HTML5/player/rlplayer.js:101:367465) | at i.apply (https://lms.hilscher.local:445/pluginfile.php/900/mod_scorm/content/5/HTML5/player/rlplayer.js:101:367383)
VM184:62 [11:21:25] :clapper_board: play src=audio:res_10001.m4a t=0.000 dur=1.939 left=1.939 paused=false ended=false rs=4 ns=1 vis=visible
VM184:62 [11:21:25] :clapper_board: playing src=audio:res_10001.m4a t=0.000 dur=1.939 left=1.939 paused=false ended=false rs=4 ns=1 vis=visible
VM184:62 [11:21:25] :clapper_board: timeupdate src=audio:res_10000.m4a t=1.425 dur=2.427 left=1.002 paused=false ended=false rs=4 ns=1 vis=visible
VM184:62 [11:21:25] :clapper_board: timeupdate src=audio:res_10001.m4a t=0.171 dur=1.939 left=1.768 paused=false ended=false rs=4 ns=1 vis=visible
VM184:62 [11:21:25] :clapper_board: timeupdate src=audio:res_10000.m4a t=1.688 dur=2.427 left=0.739 paused=false ended=false rs=4 ns=1 vis=visible
VM184:62 [11:21:25] :clapper_board: timeupdate src=audio:res_10001.m4a t=0.426 dur=1.939 left=1.513 paused=false ended=false rs=4 ns=1 vis=visible
VM184:62 [11:21:26] :clapper_board: timeupdate src=audio:res_10000.m4a t=1.957 dur=2.427 left=0.470 paused=false ended=false rs=4 ns=1 vis=visible
VM184:62 [11:21:26] :clapper_board: timeupdate src=audio:res_10001.m4a t=0.688 dur=1.939 left=1.251 paused=false ended=false rs=4 ns=1 vis=visible
VM184:62 [11:21:26] :white_check_mark: Media element hook active. Found: 2
VM184:62 [11:21:26] :clapper_board: timeupdate src=audio:res_10000.m4a t=2.215 dur=2.427 left=0.212 paused=false ended=false rs=4 ns=1 vis=visible
VM184:62 [11:21:26] :clapper_board: timeupdate src=audio:res_10001.m4a t=0.959 dur=1.939 left=0.980 paused=false ended=false rs=4 ns=1 vis=visible
VM184:62 [11:21:26] :clapper_board: timeupdate src=audio:res_10000.m4a t=2.427 dur=2.427 left=0.000 paused=true ended=true rs=4 ns=1 vis=visible
VM184:62 [11:21:26] :clapper_board: pause src=audio:res_10000.m4a t=2.427 dur=2.427 left=0.000 paused=true ended=true rs=4 ns=1 vis=visible
VM184:62 [11:21:26] :clapper_board: ended src=audio:res_10000.m4a t=2.427 dur=2.427 left=0.000 paused=true ended=true rs=4 ns=1 vis=visible
VM184:62 [11:21:26] :clapper_board: timeupdate src=audio:res_10001.m4a t=1.226 dur=1.939 left=0.713 paused=false ended=false rs=4 ns=1 vis=visible
VM184:62 [11:21:26] :police_car_light: CUT DETECTED src=audio:res_10001.m4a t=1.330 dur=1.939 left=0.609 rs=4 ns=1 vis=visible
VM184:62 [11:21:26] :megaphone: ACTIVE MEDIA DUMP (after CUT audio:res_10001.m4a) count=2
VM184:62 [11:21:26] • audio:res_10000.m4a t=2.427 dur=2.427 left=0.000 paused=true ended=true rs=4 ns=1 conn=true muted=false vol=1 rate=1
VM184:62 [11:21:26] • audio:res_10001.m4a t=1.330 dur=1.939 left=0.609 paused=false ended=false rs=4 ns=1 conn=true muted=false vol=1 rate=1
VM184:62 [11:21:26] :pause_button: pause() called src=audio:res_10001.m4a t=1.330 dur=1.939 left=0.609 paused=false ended=false rs=4 ns=1 vis=visible
↳ at el.pause (:479:20) | at i.Hc (https://lms.hilscher.local:445/pluginfile.php/900/mod_scorm/content/5/HTML5/player/rlplayer.js:101:263289) | at Object.set (https://lms.hilscher.local:445/pluginfile.php/900/mod_scorm/content/5/HTML5/player/rlplayer.js:101:355472) | at i.toTarget (https://lms.hilscher.local:445/pluginfile.php/900/mod_scorm/content/5/HTML5/player/rlplayer.js:101:367465) | at i.apply (https://lms.hilscher.local:445/pluginfile.php/900/mod_scorm/content/5/HTML5/player/rlplayer.js:101:367383) | at i.Yp (https://lms.hilscher.local:445/pluginfile.php/900/mod_scorm/content/5/HTML5/player/rlplayer.js:101:379033) | at i.update (https://lms.hilscher.local:445/pluginfile.php/900/mod_scorm/content/5/HTML5/player/rlplayer.js:101:378181)
VM184:62 [11:21:26] :police_car_light: CUT DETECTED src=audio:res_10001.m4a t=1.332 dur=1.939 left=0.607 rs=4 ns=1 vis=visible
VM184:62 [11:21:26] :megaphone: ACTIVE MEDIA DUMP (after CUT audio:res_10001.m4a) count=2
VM184:62 [11:21:26] • audio:res_10000.m4a t=2.427 dur=2.427 left=0.000 paused=true ended=true rs=4 ns=1 conn=true muted=false vol=1 rate=1
VM184:62 [11:21:26] • audio:res_10001.m4a t=1.332 dur=1.939 left=0.607 paused=true ended=false rs=4 ns=1 conn=true muted=false vol=1 rate=1
VM184:62 [11:21:26] :pause_button: pause() called src=audio:res_10001.m4a t=1.332 dur=1.939 left=0.607 paused=true ended=false rs=4 ns=1 vis=visible
↳ at el.pause (:479:20) | at i.js (https://lms.hilscher.local:445/pluginfile.php/900/mod_scorm/content/5/HTML5/player/rlplayer.js:101:259599) | at Object.set (https://lms.hilscher.local:445/pluginfile.php/900/mod_scorm/content/5/HTML5/player/rlplayer.js:101:357898) | at i.toTarget (https://lms.hilscher.local:445/pluginfile.php/900/mod_scorm/content/5/HTML5/player/rlplayer.js:101:367465) | at i.apply (https://lms.hilscher.local:445/pluginfile.php/900/mod_scorm/content/5/HTML5/player/rlplayer.js:101:367383) | at i.Yp (https://lms.hilscher.local:445/pluginfile.php/900/mod_scorm/content/5/HTML5/player/rlplayer.js:101:379033) | at i.update (https://lms.hilscher.local:445/pluginfile.php/900/mod_scorm/content/5/HTML5/player/rlplayer.js:101:378181)
VM184:62 [11:21:26] :brick: near-CUT DOM change: node delta added=10 removed=10
VM184:62 [11:21:26] :test_tube: post-CUT check +0ms: audio:res_10001.m4a isConnected=true
VM184:62 [11:21:26] :clapper_board: timeupdate src=audio:res_10001.m4a t=1.332 dur=1.939 left=0.607 paused=true ended=false rs=4 ns=1 vis=visible
VM184:62 [11:21:26] :clapper_board: pause src=audio:res_10001.m4a t=1.332 dur=1.939 left=0.607 paused=true ended=false rs=4 ns=1 vis=visible
VM184:62 [11:21:26] :test_tube: post-CUT check +0ms: audio:res_10001.m4a isConnected=true
2VM184:62 [11:21:26] :test_tube: post-CUT check +80ms: audio:res_10001.m4a isConnected=true
2VM184:62 [11:21:27] :test_tube: post-CUT check +250ms: audio:res_10001.m4a isConnected=true
VM184:62 [11:21:27] :pushpin: SCORM SetValue cmi.score.min 0
↳ at obj. [as SetValue] (:232:20) | at doSetValue (https://lms.hilscher.local:445/pluginfile.php/900/mod_scorm/content/5/HTML5/player/APIWrapper.js:223:24)
VM184:62 [11:21:27] :pushpin: SCORM SetValue cmi.score.scaled 0
↳ at obj. [as SetValue] (:232:20) | at doSetValue (https://lms.hilscher.local:445/pluginfile.php/900/mod_scorm/content/5/HTML5/player/APIWrapper.js:223:24)
VM184:62 [11:21:27] :pushpin: SCORM SetValue cmi.score.max 0
↳ at obj. [as SetValue] (:232:20) | at doSetValue (https://lms.hilscher.local:445/pluginfile.php/900/mod_scorm/content/5/HTML5/player/APIWrapper.js:223:24)
VM184:62 [11:21:27] :pushpin: SCORM SetValue cmi.score.raw 0
↳ at obj. [as SetValue] (:232:20) | at doSetValue (https://lms.hilscher.local:445/pluginfile.php/900/mod_scorm/content/5/HTML5/player/APIWrapper.js:223:24)
VM184:62 [11:21:27] :pushpin: SCORM SetValue cmi.success_status “passed”
↳ at obj. [as SetValue] (:232:20) | at doSetValue (https://lms.hilscher.local:445/pluginfile.php/900/mod_scorm/content/5/HTML5/player/APIWrapper.js:223:24)
VM184:62 [11:21:27] :pushpin: SCORM SetValue cmi.completion_status “completed”
↳ at obj. [as SetValue] (:232:20) | at doSetValue (https://lms.hilscher.local:445/pluginfile.php/900/mod_scorm/content/5/HTML5/player/APIWrapper.js:223:24)
VM184:62 [11:21:27] :pushpin: SCORM SetValue cmi.exit “normal”
↳ at obj. [as SetValue] (:232:20) | at doSetValue (https://lms.hilscher.local:445/pluginfile.php/900/mod_scorm/content/5/HTML5/player/APIWrapper.js:223:24)
VM184:62 [11:21:27] :pushpin: SCORM SetValue cmi.session_time “PT0H0M14S”
↳ at obj. [as SetValue] (:232:20) | at doSetValue (https://lms.hilscher.local:445/pluginfile.php/900/mod_scorm/content/5/HTML5/player/APIWrapper.js:223:24)
VM184:62 [11:21:27] :pushpin: SCORM Commit “”
↳ at obj. [as Commit] (:232:20) | at doCommit (https://lms.hilscher.local:445/pluginfile.php/900/mod_scorm/content/5/HTML5/player/APIWrapper.js:253:24)
rlplayer.js:101 [Violation] ‘requestAnimationFrame’ handler took 83ms
VM184:62 [11:21:27] :brick: near-CUT DOM change: node delta added=9 removed=9
VM184:62 [11:21:27] :white_check_mark: Media element hook active. Found: 2
VM184:62 [11:21:28] :window: window blur
VM184:62 [11:21:28] :eye: visibilitychange → hidden

Hi,

In the default mode, narration audio is auto-played and synchronized with the slide timeline. When an exit effect (“Disappear”) is present, the HTML5 player explicitly calls pause() on the audio at the scheduled end time of the audio object. So your log analysis and stack trace interpretation are correct.

Because timeline synchronization in HTML5/JavaScript is not perfectly precise, this stop event can occasionally fire slightly early, which may cut off a small portion of the audio at the end.

As a temporary workaround, we recommend extending the audio end time (or slide duration) slightly to avoid relying on the exit timing event.

Regards,

Ok, understood.

Would you say, that using the “Show to the end of the slide” function on narration audio would do the same effect?

The reason why I am asking is, that just clicking on our multiple audio tracks on the main timeline all at once and the check the box “Show to the end of the slide” for all at a time is much easier that to extend the audio end time.

Regards

Armin

Yes, using “Show to the end of the slide” on narration audio effectively achieves the same result.

Selecting multiple audio tracks and enabling this option in bulk is a perfectly valid and easier workaround compared to manually extending each audio end time.

Regards,