Changeset 8681239 in Klonkt for src/assets/js/audio-player.js


Ignore:
Timestamp:
05/07/2026 10:38:43 PM (4 months ago)
Author:
Robin <robin@…>
Branches:
main
Children:
76e9cfd
Parents:
00550c0
Message:

audio v3: robust continuous playback — pause+load reset, error auto-skip, autoplay policy hint

  • loadTrack: pause + audio.load() for a clean reset (prevents state corruption after multiple src changes, root cause of 'stop after 3-4 tracks')
  • play() rejection NotAllowedError -> visual pulse hint on the play button so the user knows 'tap to continue' (iOS autoplay policy)
  • audio.error event: auto-skip to next track, max 3 errors in a row before giving up (anti-infinite-loop)
  • Reset error counter on successful play
  • Cache buster ?v=3 on shell.ejs
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/assets/js/audio-player.js

    r00550c0 r8681239  
    189189    }
    190190    console.log('[pcms-audio] loading', t.title, t.url);
     191    // Schone overgang: pause + reset voorkomt state-corruption van het
     192    // audio-element na meerdere src-changes (bug die continuous playback
     193    // brak na 3-4 tracks). audio.load() forceert reset van internal state.
     194    try { audio.pause(); } catch (e) {}
    191195    audio.src = t.url;
     196    try { audio.load(); } catch (e) {}
    192197    titleEl.textContent  = t.title  || 'Untitled';
    193198    artistEl.textContent = t.artist || '';
     
    214219    const p = audio.play();
    215220    if (p && typeof p.catch === 'function') {
    216       p.catch((err) => console.warn('[pcms-audio] play() rejected', err));
     221      p.catch((err) => {
     222        console.warn('[pcms-audio] play() rejected:', err.name, err.message);
     223        // Browser-autoplay-policy heeft 't gestopt (typisch na 3-4
     224        // automatische plays op iOS Safari, of als tab tijdelijk inactive
     225        // was). Visuele hint dat user op play moet tappen.
     226        if (err && err.name === 'NotAllowedError') {
     227          root.classList.add('audio-needs-tap');
     228          isPlaying = false;
     229          root.classList.remove('is-playing');
     230        }
     231      });
    217232    }
    218233  }
     
    268283  // 5. Audio element events → UI sync
    269284  // ============================================================
    270   audio.addEventListener('play',  () => { isPlaying = true;  root.classList.add('is-playing'); });
     285  // Error-counter voorkomt infinite-loop als ALLE tracks broken zijn.
     286  let consecutiveErrors = 0;
     287
     288  audio.addEventListener('play',  () => {
     289    isPlaying = true;
     290    consecutiveErrors = 0;  // reset bij succesvolle play
     291    root.classList.add('is-playing');
     292    root.classList.remove('audio-needs-tap');  // verstop tap-hint
     293  });
    271294  audio.addEventListener('pause', () => { isPlaying = false; root.classList.remove('is-playing'); });
    272295  audio.addEventListener('ended', next);
     
    274297    const code = audio.error ? audio.error.code : '?';
    275298    console.error('[pcms-audio] playback error', code, audio.src, e);
     299    consecutiveErrors++;
     300    // Bij netwerk/decode-fout: skip naar volgende track ipv stilstaan.
     301    // Max 3 fouten op rij voordat we opgeven (anders infinite loop).
     302    if (consecutiveErrors < 3 && queue.length > 1) {
     303      console.warn('[pcms-audio] auto-skip naar volgende na error', consecutiveErrors);
     304      setTimeout(next, 400);
     305    }
    276306  });
    277   audio.addEventListener('stalled', () => console.warn('[pcms-audio] stalled'));
     307  audio.addEventListener('stalled', () => console.warn('[pcms-audio] stalled at', audio.currentTime));
    278308  audio.addEventListener('volumechange', () => { root.classList.toggle('is-muted', audio.muted || audio.volume === 0); });
    279309  audio.addEventListener('timeupdate', () => {
Note: See TracChangeset for help on using the changeset viewer.