Quick answer: Godot AudioStreamPlayer finished signal firing when you call stop() manually? The signal is shared - check stream_paused and the playback position before treating it as natural end.

VO cue fires its 'subtitle done' handler the moment the player skips it, because stop() emits finished.

Track the stop call

var manual_stop = false
func _on_finished():
    if manual_stop:
        manual_stop = false
        return
    on_natural_end()

The signal can't tell you why it fired - track the caller's intent.

Or compare playback position

If get_playback_position() is at or beyond stream.get_length(), you ended naturally. Otherwise something stopped you.

Use the AudioStreamPlayback API

For finer control, AudioStreamPlayer.get_stream_playback() exposes a playback object with is_playing() independent of the player's signal flow.

“finished says 'I'm not playing anymore' - that's it. Anything else, you derive.”

Centralize VO/cue completion logic in a coroutine that awaits both the signal and the natural duration, whichever fires first. Easier to debug than chained signal handlers.