Start · Sprachen · JavaScript · Referenz · USBAlternateInterface

USBAlternateInterface

Schnittstelle

Beschreibt eine alternative Einstellung (Alternate Setting) einer USB-Schnittstelle, also deren Klasse, Subklasse, Protokoll, Namen und Endpunkte.

seit JavaScript Chrome/Edge 61+, Opera 48+ (nicht in Firefox und S Kategorie: webapi

Signatur

interface USBAlternateInterface

Beschreibung

USBAlternateInterface gehört zur WebUSB API und beschreibt genau eine alternative Einstellung einer USB-Schnittstelle. Laut USB-Spezifikation kann jede Schnittstelle (USBInterface) mehrere solche Einstellungen haben. Sie unterscheiden sich meist in der Anzahl der Endpunkte, der Paketgröße oder der Bandbreite. Ein typisches Beispiel ist eine USB-Audio- oder Videoschnittstelle, deren Einstellung 0 keine Bandbreite belegt, während die Einstellungen 1…n isochrone Endpunkte mit steigender Datenrate anbieten.

Instanzen erzeugt man in der Praxis nicht selbst. Man erhält sie über USBInterface.alternates (alle Einstellungen) oder USBInterface.alternate (die gerade aktive Einstellung). Die Kette sieht so aus: USBDevice.configuration → USBConfiguration.interfaces → USBInterface.alternates → USBAlternateInterface.endpoints.

Alle Eigenschaften sind schreibgeschützt:

  • alternateSetting (number): Nummer dieser Einstellung, also bAlternateSetting aus dem Deskriptor.
  • interfaceClass, interfaceSubclass, interfaceProtocol (number): Klassencodes laut USB-IF, z. B. 0xFF für herstellerspezifisch oder 0x03 für HID.
  • interfaceName (string | null): Name der Schnittstelle aus dem String-Deskriptor, falls das Gerät einen liefert.
  • endpoints (USBEndpoint[]): die Endpunkte dieser Einstellung.

Nützlich ist die Schnittstelle vor allem, um beim Verbinden automatisch die passende Schnittstelle und Einstellung zu finden. Das geht zum Beispiel über die Klasse 0xFF oder über das Vorhandensein bestimmter Bulk-Endpunkte. Danach aktiviert man die Einstellung mit USBDevice.selectAlternateInterface() und nutzt deren Endpunktnummern für transferIn() und transferOut().

Parameter

Name Typ Default Beschreibung
$deviceInterface Pflicht USBInterface Nur beim (selten genutzten) Konstruktor new USBAlternateInterface(deviceInterface, alternateSetting): die Schnittstelle, zu der die Einstellung gehört.
$alternateSetting Pflicht number Nur beim Konstruktor: Nummer der alternativen Einstellung, die beschrieben werden soll. Gibt es sie nicht, wird ein RangeError geworfen.

Rückgabewert

Typ
USBAlternateInterface
Beschreibung
Ein Objekt mit den schreibgeschützten Eigenschaften alternateSetting, interfaceClass, interfaceSubclass, interfaceProtocol, interfaceName und endpoints.

Beispiele

Alle alternativen Einstellungen eines Geräts auflisten

// Muss durch eine Nutzeraktion ausgelöst werden (z. B. Klick)
document.querySelector('#connect').addEventListener('click', async () => {
  const device = await navigator.usb.requestDevice({ filters: [] });
  await device.open();
  if (device.configuration === null) await device.selectConfiguration(1);

  for (const iface of device.configuration.interfaces) {
    for (const alt of iface.alternates) {
      const hex = (n) => '0x' + n.toString(16).padStart(2, '0');
      console.log(
        `Interface ${iface.interfaceNumber} / Alt ${alt.alternateSetting}:`,
        `Klasse ${hex(alt.interfaceClass)}`,
        `Subklasse ${hex(alt.interfaceSubclass)}`,
        `Protokoll ${hex(alt.interfaceProtocol)}`,
        `Name: ${alt.interfaceName ?? '(keiner)'}`,
        `Endpunkte: ${alt.endpoints.length}`
      );
    }
  }
});
Interface 0 / Alt 0: Klasse 0xff Subklasse 0x00 Protokoll 0x00 Name: (keiner) Endpunkte: 2

Herstellerspezifische Schnittstelle mit Bulk-Endpunkten finden und nutzen

const findVendorInterface = (device) => {
  for (const iface of device.configuration.interfaces) {
    for (const alt of iface.alternates) {
      if (alt.interfaceClass !== 0xff) continue;
      const epIn = alt.endpoints.find((e) => e.direction === 'in' && e.type === 'bulk');
      const epOut = alt.endpoints.find((e) => e.direction === 'out' && e.type === 'bulk');
      if (epIn && epOut) return { iface, alt, epIn, epOut };
    }
  }
  return null;
};

const connect = async () => {
  const device = await navigator.usb.requestDevice({ filters: [{ vendorId: 0x2341 }] });
  await device.open();
  if (device.configuration === null) await device.selectConfiguration(1);

  const match = findVendorInterface(device);
  if (!match) throw new Error('Keine passende Schnittstelle gefunden');

  const { iface, alt, epIn, epOut } = match;
  await device.claimInterface(iface.interfaceNumber);
  await device.selectAlternateInterface(iface.interfaceNumber, alt.alternateSetting);

  await device.transferOut(epOut.endpointNumber, new TextEncoder().encode('PING'));
  const result = await device.transferIn(epIn.endpointNumber, 64);
  console.log(new TextDecoder().decode(result.data));
};
PONG

Aktive Einstellung prüfen und Einstellung mit höchster Paketgröße wählen

const selectBestAlternate = async (device, interfaceNumber) => {
  const iface = device.configuration.interfaces
    .find((i) => i.interfaceNumber === interfaceNumber);

  console.log('Aktiv vorher:', iface.alternate.alternateSetting);

  // Einstellung mit der größten maximalen Paketgröße suchen
  const best = iface.alternates.reduce((a, b) => {
    const max = (alt) => Math.max(0, ...alt.endpoints.map((e) => e.packetSize));
    return max(b) > max(a) ? b : a;
  });

  await device.claimInterface(interfaceNumber);
  await device.selectAlternateInterface(interfaceNumber, best.alternateSetting);
  console.log('Aktiv nachher:', iface.alternate.alternateSetting);
};
Aktiv vorher: 0 Aktiv nachher: 3

// Wichtig · Fallstricke

  • Browserunterstützung: WebUSB gibt es nur in Chromium-basierten Browsern (Chrome, Edge, Opera, Chrome für Android). Firefox und Safari unterstützen es nicht. Vorher mit 'usb' in navigator prüfen.
  • Sicherer Kontext: Die API funktioniert nur über HTTPS (oder localhost). requestDevice() braucht eine Nutzeraktion. Über eine Permissions Policy (usb) kann die API in iframes gesperrt sein.
  • Aktivieren nicht vergessen: Das bloße Auslesen eines USBAlternateInterface aktiviert die Einstellung nicht. Dafür braucht es claimInterface() und anschließend selectAlternateInterface(). Erst danach gelten die Endpunkte dieser Einstellung für Übertragungen.
  • interfaceName ist null, wenn das Gerät keinen String-Deskriptor liefert. Den Wert also nie ungeprüft verwenden.
  • Geschützte Klassen: Schnittstellen bestimmter Klassen (z. B. HID 0x03, Massenspeicher 0x08, Audio, Video, Smartcard) blockiert Chrome für WebUSB. claimInterface() schlägt dann mit SecurityError fehl. Für HID ist die WebHID API gedacht.
  • Unter Windows muss für das Gerät meist der WinUSB-Treiber geladen sein. Hat ein Systemtreiber die Schnittstelle schon belegt, schlägt claimInterface() fehl.