cduss commited on
Commit
5a069c2
·
1 Parent(s): c521401

test latency

Browse files
Files changed (2) hide show
  1. index.html +67 -2
  2. style.css +16 -0
index.html CHANGED
@@ -41,7 +41,7 @@
41
  <div class="app-container">
42
  <!-- Video -->
43
  <div class="video-container">
44
- <video id="remoteVideo" autoplay playsinline></video>
45
 
46
  <div class="video-overlay-top">
47
  <div class="connection-badge">
@@ -49,6 +49,9 @@
49
  <span id="statusText">Disconnected</span>
50
  </div>
51
  <div class="robot-name" id="robotName"></div>
 
 
 
52
  </div>
53
 
54
  <div class="video-overlay-bottom">
@@ -159,13 +162,14 @@
159
  </div>
160
 
161
  <script type="module">
162
- import { ReachyMini } from "https://cdn.jsdelivr.net/gh/pollen-robotics/reachy_mini@develop/js/reachy-mini.js";
163
 
164
  const robot = new ReachyMini();
165
 
166
  let selectedRobotId = null;
167
  let headSlidersActive = false;
168
  let detachVideo = null;
 
169
 
170
  // Export functions for inline onclick handlers
171
  window.loginToHuggingFace = () => robot.login();
@@ -214,6 +218,7 @@
214
  updateStatus('connected', 'Connected');
215
  enableControls(true);
216
  document.getElementById('robotSelector').classList.add('hidden');
 
217
  });
218
 
219
  robot.addEventListener('sessionStopped', () => {
@@ -223,6 +228,7 @@
223
  enableControls(false);
224
  updateStatus('connected', 'Connected');
225
  updateMicButton();
 
226
  });
227
 
228
  robot.addEventListener('state', (e) => updateStateDisplay(e.detail));
@@ -289,6 +295,65 @@
289
  }
290
  }
291
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
292
  // ===================== Session =====================
293
  async function startStream() {
294
  if (!selectedRobotId) return;
 
41
  <div class="app-container">
42
  <!-- Video -->
43
  <div class="video-container">
44
+ <video id="remoteVideo" autoplay playsinline muted></video>
45
 
46
  <div class="video-overlay-top">
47
  <div class="connection-badge">
 
49
  <span id="statusText">Disconnected</span>
50
  </div>
51
  <div class="robot-name" id="robotName"></div>
52
+ <div class="latency-badge hidden" id="latencyBadge">
53
+ <span id="latencyValue">--</span>
54
+ </div>
55
  </div>
56
 
57
  <div class="video-overlay-bottom">
 
162
  </div>
163
 
164
  <script type="module">
165
+ import { ReachyMini } from "https://cdn.jsdelivr.net/gh/pollen-robotics/reachy_mini@invest-latency/js/reachy-mini.js";
166
 
167
  const robot = new ReachyMini();
168
 
169
  let selectedRobotId = null;
170
  let headSlidersActive = false;
171
  let detachVideo = null;
172
+ let latencyIntervalId = null;
173
 
174
  // Export functions for inline onclick handlers
175
  window.loginToHuggingFace = () => robot.login();
 
218
  updateStatus('connected', 'Connected');
219
  enableControls(true);
220
  document.getElementById('robotSelector').classList.add('hidden');
221
+ startLatencyDisplay();
222
  });
223
 
224
  robot.addEventListener('sessionStopped', () => {
 
228
  enableControls(false);
229
  updateStatus('connected', 'Connected');
230
  updateMicButton();
231
+ stopLatencyDisplay();
232
  });
233
 
234
  robot.addEventListener('state', (e) => updateStateDisplay(e.detail));
 
295
  }
296
  }
297
 
298
+ // ===================== Latency =====================
299
+ function startLatencyDisplay() {
300
+ const badge = document.getElementById('latencyBadge');
301
+ const label = document.getElementById('latencyValue');
302
+ badge.classList.remove('hidden');
303
+
304
+ latencyIntervalId = setInterval(async () => {
305
+ const video = document.getElementById('remoteVideo');
306
+ let bufLagMs = null;
307
+ let rttMs = null;
308
+ let jitterMs = null;
309
+
310
+ // Buffer lag (how far behind live edge)
311
+ if (video && video.buffered && video.buffered.length > 0) {
312
+ const end = video.buffered.end(video.buffered.length - 1);
313
+ bufLagMs = Math.round((end - video.currentTime) * 1000);
314
+ }
315
+
316
+ // WebRTC stats: RTT + jitter buffer delay
317
+ if (robot._pc) {
318
+ try {
319
+ const stats = await robot._pc.getStats();
320
+ stats.forEach(report => {
321
+ if (report.type === 'candidate-pair' && report.currentRoundTripTime != null) {
322
+ rttMs = Math.round(report.currentRoundTripTime * 1000);
323
+ }
324
+ if (report.type === 'inbound-rtp' && report.kind === 'video') {
325
+ if (report.jitterBufferDelay != null && report.jitterBufferEmittedCount > 0) {
326
+ jitterMs = Math.round((report.jitterBufferDelay / report.jitterBufferEmittedCount) * 1000);
327
+ }
328
+ }
329
+ });
330
+ } catch (_) { /* no stats yet */ }
331
+ }
332
+
333
+ // Display
334
+ const parts = [];
335
+ if (bufLagMs != null) parts.push(`buf ${bufLagMs}ms`);
336
+ if (rttMs != null) parts.push(`rtt ${rttMs}ms`);
337
+ if (jitterMs != null) parts.push(`jit ${jitterMs}ms`);
338
+ label.textContent = parts.length ? parts.join(' · ') : '--';
339
+
340
+ // Color based on buffer lag
341
+ badge.classList.remove('good', 'ok', 'bad');
342
+ if (bufLagMs != null) {
343
+ if (bufLagMs < 200) badge.classList.add('good');
344
+ else if (bufLagMs < 500) badge.classList.add('ok');
345
+ else badge.classList.add('bad');
346
+ }
347
+ }, 1000);
348
+ }
349
+
350
+ function stopLatencyDisplay() {
351
+ if (latencyIntervalId) { clearInterval(latencyIntervalId); latencyIntervalId = null; }
352
+ const badge = document.getElementById('latencyBadge');
353
+ badge.classList.add('hidden');
354
+ badge.classList.remove('good', 'ok', 'bad');
355
+ }
356
+
357
  // ===================== Session =====================
358
  async function startStream() {
359
  if (!selectedRobotId) return;
style.css CHANGED
@@ -132,6 +132,22 @@ video {
132
  font-size: 0.8em;
133
  }
134
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
  .status-indicator {
136
  width: 8px;
137
  height: 8px;
 
132
  font-size: 0.8em;
133
  }
134
 
135
+ .latency-badge {
136
+ display: flex;
137
+ align-items: center;
138
+ background: rgba(0,0,0,0.5);
139
+ padding: 4px 10px;
140
+ border-radius: 12px;
141
+ font-size: 0.75em;
142
+ font-variant-numeric: tabular-nums;
143
+ color: var(--text-secondary);
144
+ font-family: 'Inter', monospace;
145
+ }
146
+
147
+ .latency-badge.good { color: var(--success); }
148
+ .latency-badge.ok { color: var(--warning); }
149
+ .latency-badge.bad { color: var(--danger); }
150
+
151
  .status-indicator {
152
  width: 8px;
153
  height: 8px;