Signatur
Beschreibung
Ein USB-Interface kann mehrere alternative Einstellungen (Alternate Settings) haben. Jede davon hat eigene Endpunkte, zum Beispiel mit anderer Paketgröße, anderer Bandbreite oder einer anderen Übertragungsart. Typische Fälle sind Audio- und Video-Geräte: Einstellung 0 hat meist gar keine Endpunkte und belegt dadurch keine Bandbreite, erst eine höhere Einstellung schaltet die isochronen Datenströme frei. Mit selectAlternateInterface() sendet der Browser den Standard-Befehl SET_INTERFACE an das Gerät.
Die Methode lässt sich nur aufrufen, wenn das Gerät mit open() geöffnet wurde, mit selectConfiguration() eine Konfiguration aktiv ist und das Interface mit claimInterface() beansprucht wurde. Danach enthält USBInterface.alternate die neu gewählte Einstellung. Über deren endpoints sieht man, welche Endpunktnummern man für transferIn(), transferOut() oder isochronousTransferIn() verwenden kann.
Welche Einstellungen es gibt, steht in USBInterface.alternates. Jeder Eintrag ist ein USBAlternateInterface mit alternateSetting, interfaceClass, interfaceSubclass, interfaceProtocol und endpoints.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $interfaceNumber Pflicht | number | Nummer des Interfaces (USBInterface.interfaceNumber) in der aktiven Konfiguration. Das Interface muss vorher mit claimInterface() beansprucht worden sein. |
|
| $alternateSetting Pflicht | number | Nummer der gewünschten alternativen Einstellung (USBAlternateInterface.alternateSetting). |
Rückgabewert
NotFoundError, wenn es das Interface oder die Einstellung nicht gibt, mit InvalidStateError, wenn das Gerät nicht geöffnet oder das Interface nicht beansprucht ist, oder mit NetworkError, wenn die Übertragung fehlschlägt.Beispiele
Grundablauf: öffnen, beanspruchen, Einstellung wählen
const connect = async () => {
const device = await navigator.usb.requestDevice({
filters: [{ vendorId: 0x2341 }]
});
await device.open();
if (device.configuration === null) {
await device.selectConfiguration(1);
}
await device.claimInterface(0);
// Alternative Einstellung 1 für Interface 0 aktivieren
await device.selectAlternateInterface(0, 1);
const iface = device.configuration.interfaces.find(i => i.interfaceNumber === 0);
console.log('Aktive Einstellung:', iface.alternate.alternateSetting);
return device;
};
// Muss durch eine Nutzeraktion ausgelöst werden
document.querySelector('#connect').addEventListener('click', connect);
Passende Einstellung anhand der Endpunkte suchen
const selectIsochronousSetting = async (device, interfaceNumber) => {
const iface = device.configuration.interfaces
.find(i => i.interfaceNumber === interfaceNumber);
// Erste Einstellung mit isochronem IN-Endpunkt suchen
const alt = iface.alternates.find(a =>
a.endpoints.some(ep => ep.type === 'isochronous' && ep.direction === 'in')
);
if (!alt) throw new Error('Keine isochrone Einstellung vorhanden');
await device.claimInterface(interfaceNumber);
await device.selectAlternateInterface(interfaceNumber, alt.alternateSetting);
const ep = alt.endpoints.find(e => e.direction === 'in');
console.log(`Einstellung ${alt.alternateSetting}, Endpunkt ${ep.endpointNumber}, ${ep.packetSize} Byte`);
return ep;
};
Fehlerbehandlung und Zurückschalten auf Einstellung 0
const stopStream = async (device, interfaceNumber) => {
try {
// Einstellung 0 gibt die reservierte Bandbreite wieder frei
await device.selectAlternateInterface(interfaceNumber, 0);
await device.releaseInterface(interfaceNumber);
console.log('Stream gestoppt');
} catch (err) {
if (err.name === 'NotFoundError') {
console.error('Interface oder Einstellung existiert nicht');
} else if (err.name === 'InvalidStateError') {
console.error('Gerät nicht geöffnet oder Interface nicht beansprucht');
} else {
console.error('USB-Fehler:', err);
}
}
};
// Wichtig · Fallstricke
- Browserunterstützung: WebUSB gibt es nur in Chromium-basierten Browsern (Chrome, Edge, Opera). Firefox und Safari unterstützen die API nicht. Vor der Nutzung mit
'usb' in navigatorprüfen. - Sicherer Kontext: Die API funktioniert nur über HTTPS (oder
localhost). In iframes muss die Permissions Policyusberlaubt sein. - Reihenfolge: Wer die Methode vor
claimInterface()aufruft, bekommt einenInvalidStateError. Nach dem Umschalten können sich die Endpunkte ändern, deshalb die Endpunktnummern immer ausiface.alternate.endpointsneu lesen. - Geschützte Klassen: Interfaces geschützter Klassen wie HID, Massenspeicher, Audio oder Video beansprucht in der Regel schon der Betriebssystem-Treiber.
claimInterface()schlägt dann fehl, und damit auch das Umschalten. - Laufende Übertragungen auf den Endpunkten der alten Einstellung werden durch das Umschalten abgebrochen.
- Unter Windows braucht das Gerät passende Treiber (z. B. WinUSB), sonst schlägt der Zugriff fehl.