| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- <!doctype html>
- <html lang="en">
- <head>
- <meta charset="utf-8">
- <title>Audio Player Controls — Arozcast Example</title>
- <script src="../arozcast.js"></script>
- <style>
- body { background:#111; color:#ddd; font-family:sans-serif; padding:24px; max-width:480px; }
- h2 { margin:0 0 6px; }
- p { margin:0 0 14px; color:#888; }
- code { color:#aaa; background:#222; padding:1px 5px; border-radius:3px; }
- input, button { background:#222; color:#ddd; border:1px solid #444; border-radius:4px; padding:5px 10px; }
- button { cursor:pointer; }
- button:hover { background:#333; }
- hr { border:none; border-top:1px solid #333; margin:16px 0; }
- #bar { background:#333; height:8px; border-radius:4px; cursor:pointer; margin:10px 0 4px; }
- #fill { background:#aaa; height:100%; border-radius:4px; width:0; pointer-events:none; }
- #time { color:#888; font-size:13px; }
- #controls { display:none; }
- #controls button { margin:0 4px 8px 0; }
- #ended-msg { color:#888; font-size:13px; display:none; }
- </style>
- </head>
- <body>
- <h2>Audio Player Controls</h2>
- <p>
- Demonstrates <code>seek()</code>, mute toggle, <code>isConnected()</code>,
- repeat modes, and the <code>ended</code> event.<br>
- Place your audio at <code>user:/example.mp3</code>.
- </p>
- <p>
- Room code:
- <input id="code" maxlength="4" size="5" placeholder="1234">
- <button onclick="doConnect()">Connect</button>
- </p>
- <p id="status">Not connected</p>
- <div id="controls">
- <!-- Transport -->
- <button onclick="cast.play()">Play</button>
- <button onclick="cast.pause()">Pause</button>
- <button onclick="doDisconnect()">Disconnect</button>
- <hr>
- <!-- Progress bar — click to seek(time) to that position -->
- <div id="bar" onclick="onSeekBarClick(event)">
- <div id="fill"></div>
- </div>
- <span id="time">0:00 / 0:00</span>
- <hr>
- <!-- Volume slider + mute toggle -->
- Volume: <input type="range" id="vol" min="0" max="100" value="80"
- oninput="onVolumeChange()">
- <button id="mute-btn" onclick="toggleMute()">Mute</button>
- <hr>
- <!-- Repeat — cycles none → all → one, synced via setRepeat() -->
- <button id="repeat-btn" onclick="cycleRepeat()">Repeat: off</button>
- <p id="ended-msg">⏹ Track finished — this is where you would load the next track.</p>
- <hr>
- <!-- cast.code and cast.connected readable properties -->
- Room: <span id="room-code">—</span> |
- Connected: <span id="connected-state">false</span>
- </div>
- <script>
- var _s = document.querySelector('script[src*="arozcast.js"]').src;
- var ao_root = _s.slice(0, _s.indexOf('Arozcast/arozcast.js'));
- var FILE = 'user:/example.mp3';
- var muted = false;
- var repeatMode = 'none'; // 'none' | 'all' | 'one'
- var duration = 0;
- var currTime = 0;
- var cast = new ArozCast({ aoRoot: ao_root });
- // ── Events ─────────────────────────────────────────────────────────────────
- cast.on('connect', function(e) {
- status('Connected to room ' + e.code);
- document.getElementById('controls').style.display = 'block';
- document.getElementById('ended-msg').style.display = 'none';
- refreshProps();
- cast.load({
- name: 'example.mp3', type: 'audio',
- src: ao_root + 'media?file=' + encodeURIComponent(FILE),
- filepath: FILE,
- });
- cast.setVolume(+document.getElementById('vol').value, muted);
- cast.setRepeat(repeatMode); // re-sync repeat on every connect / reconnect
- cast.play();
- });
- cast.on('disconnect', function() { status('Connection lost — reconnecting…'); refreshProps(); });
- cast.on('reconnecting', function(e) { status('Reconnecting, attempt ' + e.attempt + '…'); });
- cast.on('giveup', function() { status('Could not reconnect'); refreshProps(); });
- // status event → drive the seek bar and time display
- cast.on('status', function(s) {
- duration = s.duration;
- currTime = s.currentTime;
- updateBar();
- refreshProps();
- });
- // ended event — fired when the track finishes naturally.
- // Not fired when repeat === 'one' (receiver loops natively, no ended event).
- // For repeat === 'all', this is where you would call cast.load() with the next track.
- cast.on('ended', function() {
- document.getElementById('ended-msg').style.display = '';
- });
- // ── Seek bar ────────────────────────────────────────────────────────────────
- function onSeekBarClick(e) {
- // isConnected() is checked explicitly before sending any command
- if (!cast.isConnected()) return;
- var t = (e.offsetX / e.currentTarget.offsetWidth) * (duration || 0);
- cast.seek(t); // seek(time) — absolute seek in seconds
- currTime = t; // optimistic update
- updateBar();
- }
- function updateBar() {
- var pct = duration ? Math.min(currTime / duration * 100, 100) : 0;
- document.getElementById('fill').style.width = pct + '%';
- document.getElementById('time').textContent = fmt(currTime) + ' / ' + fmt(duration);
- }
- // ── Volume / mute ───────────────────────────────────────────────────────────
- function onVolumeChange() {
- if (!cast.isConnected()) return;
- cast.setVolume(+document.getElementById('vol').value, muted);
- }
- function toggleMute() {
- muted = !muted;
- document.getElementById('mute-btn').textContent = muted ? 'Unmute' : 'Mute';
- // setVolume(level, true) mutes; setVolume(level, false) unmutes
- cast.setVolume(+document.getElementById('vol').value, muted);
- }
- // ── Repeat ──────────────────────────────────────────────────────────────────
- function cycleRepeat() {
- var modes = ['none', 'all', 'one'];
- repeatMode = modes[(modes.indexOf(repeatMode) + 1) % modes.length];
- document.getElementById('repeat-btn').textContent = 'Repeat: ' + repeatMode;
- cast.setRepeat(repeatMode);
- }
- // ── Connect / disconnect ───────────────────────────────────────────────────
- function doConnect() {
- var code = document.getElementById('code').value.trim();
- if (!/^\d{4}$/.test(code)) { alert('Enter a 4-digit code'); return; }
- status('Checking room…');
- cast.ping(code).then(function(ok) {
- if (!ok) { status('Room not found — is Arozcast open?'); return; }
- return cast.connect(code);
- }).catch(function(err) { status('Error: ' + err.message); });
- }
- function doDisconnect() {
- cast.disconnect();
- status('Disconnected');
- document.getElementById('controls').style.display = 'none';
- duration = currTime = 0;
- refreshProps();
- }
- // ── Helpers ────────────────────────────────────────────────────────────────
- function refreshProps() {
- document.getElementById('room-code').textContent = cast.code || '—';
- document.getElementById('connected-state').textContent = cast.connected ? 'true' : 'false';
- }
- function status(msg) { document.getElementById('status').textContent = msg; }
- function fmt(s) {
- s = Math.floor(s || 0);
- return Math.floor(s / 60) + ':' + ('0' + s % 60).slice(-2);
- }
- </script>
- </body>
- </html>
|