Web MIDI API:权限与设备隐私
围绕用户激活、权限、端口变化、受限消息、最小元数据和可靠回退设计 Web MIDI。
BotBrowser Team
当受控浏览器暴露 navigator.requestMIDIAccess() 并由明确操作发起请求时,BotBrowser 可用于测试经过授权的 Web MIDI 流程。它不能制造物理乐器、替用户选择端口、绕过浏览器授予权限,也不能把端口名称变成所有权证明。可靠的契约是可见工作流:请求、显示结果、校验每条消息、协调端口变化,并在浏览器或硬件不可用时保留无 MIDI 路径。
TL;DR
获得浏览器权限后,Web MIDI 可以访问输入和输出端口,但不会提供无限制的硬件清单或稳定的乐器身份。检测 navigator.requestMIDIAccess,从明确控件调用,只请求必要能力,把 MIDIAccess 当作会变化的实时视图。监听 statechange,校验 MIDIMessageEvent.data,端口消失时释放监听器。
W3C Web MIDI 规范定义了 MIDIAccess、输入输出端口、状态变化、消息事件和可选的 System Exclusive。MDN指出支持范围有限。BotBrowser 可以记录浏览器可见的权限和端口状态,但不能证明物理乐器存在、属于某人或产生了声音。
内容导航
权限是能力边界
navigator.requestMIDIAccess() 请求的是浏览器管理的能力,而不是打开所有 USB 设备。安全上下文、用户激活、权限和平台支持都可能成为条件。Promise 返回 MIDIAccess 只表示浏览器暴露了能力表面,不表示存在连接端口或某人已获授权。
请求最小范围。普通音符和控制消息可使用 { sysex: false }。System Exclusive 可能包含厂商命令和较大的不透明序列,需要单独的产品决定和说明。不要因为库支持 sysex: true 就自动开启。Web USB:设备访问与隐私边界体现同一原则:权限不是设备清单。
端口名称、厂商和版本可用于当前会话的选择器,却不是所有权证明或稳定身份。只在任务需要时保存 granted、denied、unsupported 或 no-port,不要把这些结果与网络、屏幕和 profile 组合成长久标签。
从用户操作请求访问
在使用时检测能力。没有 API 时可以禁用“连接 MIDI”按钮;用户点击或按键后再请求,不要在加载、定时器或后台网络回调中自动弹出选择器。
async function connectMidi() {
if (!window.isSecureContext || !navigator.requestMIDIAccess) {
return showMidiState('unsupported');
}
setMidiState('requesting');
try {
const access = await navigator.requestMIDIAccess({ sysex: false });
attachMidiAccess(access);
renderPorts(access);
} catch (error) {
setMidiState(classifyMidiError(error));
showMidiFallback();
}
}
connectButton.addEventListener('click', connectMidi);
requesting 可以防止重复选择并提供可访问状态。失败时只记录页面能知道的 NotAllowedError、不支持或本地超时,不要说某个命名设备拒绝了访问。恢复控件,提供新的可见重试。Web Bluetooth:权限与设备隐私展示了相似选择器,但同样应区分 API 存在、浏览器授予访问和当前有可用设备。
把端口视为变化中的会话
MIDIAccess.inputs 和 MIDIAccess.outputs 是当前暴露端口的 map。设备插入、移除或重配置时会触发 statechange;每次事件都重新绘制完整 map,不要把旧行追加到新列表。
function attachMidiAccess(access) {
access.onstatechange = event => {
const port = event.port;
renderPorts(access);
if (port.state === 'disconnected') detachInput(port.id);
if (port.state === 'connected' && port.type === 'input') attachInput(port);
};
for (const input of access.inputs.values()) attachInput(input);
for (const output of access.outputs.values()) renderOutput(output);
}
使用前检查 port.state 和 port.connection,捕获发送失败。输入断开时删除监听器并清除关联状态。port.id 只应作为短期会话键,不能写进长期 profile 或指纹。send() 也不能证明乐器产生了声音或其他应用收到了消息。输出端口必须由用户明确选择,不要因为名称相似而静默切换。
在消息进入应用状态前限制它
MIDIMessageEvent.data 是不可信字节序列。更新状态前校验长度、状态字节、通道和数据范围。应用允许的白名单可以小于完整 MIDI 协议。
const MAX_MIDI_BYTES = 3;
const allowedStatus = new Set([0x80, 0x90, 0xb0, 0xe0]);
function acceptMidiMessage(event) {
const bytes = [...event.data];
if (bytes.length < 2 || bytes.length > MAX_MIDI_BYTES) return;
const status = bytes[0] & 0xf0;
if (!allowedStatus.has(status) || bytes.slice(1).some(byte => byte > 0x7f)) return;
updateMusicState({ status, channel: bytes[0] & 0x0f, data: bytes.slice(1) });
}
示例故意忽略 System Exclusive、realtime 和系统消息。启用它们应是有大小限制和厂商文档的独立协议变更。不要默认记录全部字节,也不要把字节序列当作设备身份。对高频事件限流,只在用户明确开启诊断时保留短时原始捕获。
最小化元数据并保留回退
虚拟键盘、文件导入、快捷键或乐谱视图可以在没有 MIDI 时保留任务。页面应说明浏览器没有暴露可用端口,不要假装正在控制乐器。把音乐模型与 MIDI 适配器分开:断开后仍可编辑,新端口出现后要求明确选择。
短记录可以包含支持结果、权限、端口类型和状态、本地标签、接收消息计数及时间。无需保存完整厂商字符串、端口清单、原始字节或无关浏览器属性。端口名可能暴露设备型号或工作室环境,应定义用途和保存期限。
使用决策表
| 观察结果 | 安全动作 | 不应声称 |
|---|---|---|
| API 缺失或上下文不安全 | 保留虚拟键盘或文件路径 | 浏览器普遍支持 |
| 权限被拒绝 | 解释并保留任务 | 某个命名设备拒绝 |
| 已授权但无端口 | 显示设置提示和回退 | 不存在物理乐器 |
| 输入端口连接 | 安装校验监听器 | 端口属于某人 |
| 输出端口连接 | 发送前要求明确选择 | 已产生或听到声音 |
statechange 断开 | 删除监听器并标记离线 | 一定会自动回来 |
| MIDI 字节无效 | 丢弃并分类 | 发送者身份已知 |
| 请求 SysEx | 要求单独决定 | 默认数据无害 |
用 BotBrowser 测试可见行为
BotBrowser 受控上下文可以运行确定性连接按钮、合成回退、受限校验器和可见端口记录。记录 API 是否存在、权限结果、端口数量、statechange 事件和回退可见性。unsupported、permission-denied、no-port 都是有效结果,只要不声称播放了声音。BotBrowser 高级功能文档不保证 runner 上有 MIDI 设备。
{
"api": "requestMIDIAccess",
"permission": "unknown",
"ports": { "inputs": 0, "outputs": 0 },
"states": ["fallback"],
"messagesAccepted": 0,
"rawBytesRetained": false,
"physicalInstrument": "not-asserted"
}
每次只改变一个变量重复 fixture:浏览器版本、安全上下文、权限结果、端口连接或消息类型。比较第一次可见差异,不要将单次结果扩大成所有系统和驱动的承诺。
结论
Web MIDI 是受权限控制且会变化的浏览器能力。从可见操作发起,使用最小范围,显示实时端口 map,校验每条消息,断开时释放监听器。BotBrowser 可以在授权受控上下文中重放这些可见分支;它不能制造乐器、绕过权限、保证端口或从 MIDI 元数据推断所有权。
公开来源
延伸阅读
本文属于指南: Web 平台能力面:一致性复核地图