Files
mumh5/test/share-signal.test.ts
T
kibiandClaude Opus 5.5 0cce3c97c2 Add screen sharing between mumh5 users (picture only)
- Signals travel as Mumble plugin data (compressed, chunked under Murmur's
  1000 byte limit); the picture goes directly to each viewer over WebRTC
- Toolbar button with a source picker in the desktop app, an indicator next to
  people who share, click to watch, a view above the chat with full screen
- Late joiners learn about running streams; moving, stopping or disconnecting
  ends them for viewers
- A note about IP addresses before the first use, optional STUN server setting
- Unit tests for the signal codec and an E2E with two app instances

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 20:58:33 +02:00

43 lines
2.1 KiB
TypeScript

import { test } from 'node:test';
import assert from 'node:assert/strict';
import { SHARE, encodeShare, ShareAssembler } from '../src/core/share-signal.ts';
test('bare signals are one byte', async () => {
const packets = await encodeShare(SHARE.on);
assert.deepEqual(packets, [new Uint8Array([SHARE.on])]);
assert.deepEqual(await new ShareAssembler().push(1, packets[0]), { type: SHARE.on });
});
test('session descriptions survive chunking, in any order', async () => {
// Random-looking text compresses badly, forcing several chunks
const sdp = Array.from({ length: 400 }, (_, i) => `a=candidate:${(i * 2654435761 >>> 0).toString(36)} 1 udp ${i} 2001:db8::${i} typ host`).join('\r\n');
const packets = await encodeShare(SHARE.offer, sdp);
assert.ok(packets.length > 1, 'needs more than one packet');
// Murmur drops plugin data over 1000 bytes
assert.ok(packets.every(p => p.length <= 1000));
const assembler = new ShareAssembler();
let result = null;
for (const p of [...packets].reverse()) result = await assembler.push(7, p);
assert.deepEqual(result, { type: SHARE.offer, text: sdp });
});
test('chunks from different senders do not mix', async () => {
const a = await encodeShare(SHARE.answer, Array.from({ length: 400 }, (_, i) => (i * 40503 * 2654435761 >>> 0).toString(36)).join(' '));
assert.ok(a.length > 1);
const assembler = new ShareAssembler();
assert.equal(await assembler.push(1, a[0]), null);
for (const p of a.slice(1)) assert.equal(await assembler.push(2, p), null);
let result = null;
for (const p of a.slice(1)) result = await assembler.push(1, p);
assert.equal(result?.type, SHARE.answer);
});
test('garbage is ignored', async () => {
const assembler = new ShareAssembler();
assert.equal(await assembler.push(1, new Uint8Array([99])), null);
assert.equal(await assembler.push(1, new Uint8Array([SHARE.offer, 1])), null);
assert.equal(await assembler.push(1, new Uint8Array([SHARE.offer, 1, 5, 2, 1, 2, 3])), null);
// A complete transfer that is not valid compressed data
assert.equal(await assembler.push(1, new Uint8Array([SHARE.offer, 1, 0, 1, 255, 255, 255, 255])), null);
});