Skip to content

Commit da9e217

Browse files
committed
feat: surface viewer RTT in the PopcornHost embed SDK (requestRtt + rtt event)
1 parent 7d8cdef commit da9e217

2 files changed

Lines changed: 29 additions & 1 deletion

File tree

images/minimal-vnc-desktop/host/popcorn-host.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -700,6 +700,7 @@
700700
case 'POPCORN_KBD_STATE': emit('kbdstate', d); break;
701701
case 'POPCORN_INPUT_DRIFT': emit('inputdrift', d); break;
702702
case 'POPCORN_INTERACTION': emit('interaction', d); break;
703+
case 'POPCORN_RTT': emit('rtt', d); break;
703704
case 'POPCORN_KBD_HEALTH': emit('health', d); break;
704705
// Framebuffer vs CSS vs device-pixel geometry (viewer.js traceScale).
705706
// The one place a "the stream looks blurry" report becomes a number, and
@@ -846,7 +847,7 @@
846847
}
847848

848849
return {
849-
/** Subscribe to viewer events: hello|viewport|connect|frame|disconnect|error|kbdstate|inputdrift|interaction|health|scale|layout */
850+
/** Subscribe to viewer events: hello|viewport|connect|frame|disconnect|error|kbdstate|inputdrift|interaction|health|scale|layout|rtt */
850851
on: function (name, fn) {
851852
(listeners[name] || (listeners[name] = [])).push(fn);
852853
return this;
@@ -862,6 +863,14 @@
862863
toggleMagnify: function () { post('POPCORN_TOGGLE_MAGNIFY', null); },
863864
/** Drive the viewer's keyboard toggle from your own button. */
864865
toggleKeyboard: function () { post('POPCORN_TOGGLE_KBD', null); },
866+
/**
867+
* Ask for the viewer's measured tunnel round trip; the answer arrives as
868+
* .on('rtt', ({rttMs, avgMs, samples}) => ...). rttMs is the latest
869+
* viewer<->pod sample (null before the first pong), avgMs the smoothed
870+
* link latency. A postMessage ping from this page could only time the
871+
* in-device hop, so the viewer's own measurement is the one that matters.
872+
*/
873+
requestRtt: function () { post('POPCORN_RTT_REQUEST', null); },
865874
/**
866875
* Paste text into the focused remote field. Read the clipboard HERE, in the
867876
* gesture handler of your own button: clipboard permission in a nested

images/minimal-vnc-desktop/kbd/test/host-rtt.test.mjs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
installGlobals, freshViewer, fireHostMessage, parentMessages, advanceClock,
1111
} from './stub-dom.mjs';
1212
import { createMockRfb } from './mock-rfb.mjs';
13+
import { makeHostWindow } from './host-stub.mjs';
1314

1415
installGlobals('ios', { embedded: true, search: '?parentOrigin=https://portal.test' });
1516

@@ -52,3 +53,21 @@ test('the RTT read obeys the fail-closed inbound gate (wrong origin ignored)', a
5253
fireHostMessage({ type: 'POPCORN_RTT_REQUEST' }, { origin: 'https://evil.example' });
5354
assert.equal(lastRttMsg(), null, 'request from a non-configured origin is dropped');
5455
});
56+
57+
// ---- host side (PopcornHost SDK) ----------------------------------------
58+
59+
test('PopcornHost.requestRtt posts the request and surfaces the reply as .on(\'rtt\')', async () => {
60+
const h = makeHostWindow({ top: true, iframeStyle: { position: 'fixed' },
61+
iframeRect: { left: 0, top: 0, width: 411, height: 732 } });
62+
const host = h.PopcornHost.attach(h.iframe, { childOrigin: 'https://pod.test' });
63+
64+
const got = [];
65+
host.on('rtt', (d) => got.push(d));
66+
host.requestRtt();
67+
assert.ok(h.posted.some((m) => m.type === 'POPCORN_RTT_REQUEST'), 'request posted to the frame');
68+
69+
h.fromChild({ type: 'POPCORN_RTT', rttMs: 86, avgMs: 92, samples: 41 });
70+
assert.equal(got.length, 1, 'rtt event emitted');
71+
assert.equal(got[0].rttMs, 86);
72+
assert.equal(got[0].samples, 41);
73+
});

0 commit comments

Comments
 (0)