Initial commit: mumh5, a modern Mumble client
Electron desktop app with a Svelte 5 interface for any Mumble server. - Mumble protocol core: TLS, handshake, channels, users, text, plugin data, client-side pacing of Murmur's rate limits - Voice: WebCodecs Opus over the TCP tunnel, voice activity, push to talk, always-on, devices, per-user volume and local mute - Several servers at once, voice on one; server rail with icons and ordering - Chat: channels, direct messages, side chat, file sharing through f0ckm, inline images without it, click-to-play YouTube - Profiles with rich descriptions, registration, rename, nicknames, connection information and moderation menus - Identity wizard, multiple identities, PKCS#12 import/export, desktop Mumble certificate import, certificate pinning and viewer - Tray icon with voice state - Unit, server and end-to-end tests against a real Murmur Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { writeVarint, readVarint, encodeVoice, decodeVoice, relayAsServer } from '../src/core/voice-packet.ts';
|
||||
|
||||
test('Mumble varints round trip at every size boundary', () => {
|
||||
for (const v of [0, 1, 0x7f, 0x80, 0x3fff, 0x4000, 0x1fffff, 0x200000, 0xfffffff, 0x10000000, 0xffffffff, 0x100000000, 2 ** 40 + 5]) {
|
||||
const out: number[] = [];
|
||||
writeVarint(out, v);
|
||||
assert.deepEqual(readVarint(new Uint8Array(out), 0), [v, out.length], `value ${v}`);
|
||||
}
|
||||
const small: number[] = [];
|
||||
writeVarint(small, 300);
|
||||
assert.deepEqual(small, [0x81, 0x2c], 'matches PacketDataStream encoding');
|
||||
});
|
||||
|
||||
for (const protobuf of [false, true]) {
|
||||
test(`${protobuf ? 'protobuf' : 'legacy'} voice packets survive a server relay`, () => {
|
||||
const opus = new Uint8Array([0xfc, 1, 2, 3, 250]);
|
||||
for (const last of [false, true]) {
|
||||
const sent = encodeVoice({ target: 0, frame: 1234, opus, last }, protobuf);
|
||||
const got = decodeVoice(relayAsServer(sent, 42, protobuf));
|
||||
assert.deepEqual(got, { session: 42, target: 0, frame: 1234, opus, last });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
test('legacy header layout: opus type, terminator bit in the size field', () => {
|
||||
const p = encodeVoice({ target: 3, frame: 5, opus: new Uint8Array(10), last: true }, false);
|
||||
assert.equal(p[0], (4 << 5) | 3);
|
||||
assert.equal(p[1], 5);
|
||||
assert.deepEqual([p[2], p[3]], [0x80 | 0x20, 10], 'size 10 | 0x2000 as a 2-byte varint');
|
||||
});
|
||||
|
||||
test('non-audio packets are ignored', () => {
|
||||
assert.equal(decodeVoice(new Uint8Array([1, 2, 3])), null, 'protobuf ping');
|
||||
assert.equal(decodeVoice(new Uint8Array([0x20, 5])), null, 'legacy ping');
|
||||
assert.equal(decodeVoice(new Uint8Array([0x80, 1])), null, 'truncated');
|
||||
});
|
||||
Reference in New Issue
Block a user