Start · Sprachen · JavaScript · Referenz · USBIsochronousInTransferResult

USBIsochronousInTransferResult

Schnittstelle

Enthält das Ergebnis von <code>USBDevice.isochronousTransferIn()</code>: die empfangenen Rohdaten und den Status jedes einzelnen isochronen Pakets.

seit JavaScript Chromium 61+ (Chrome, Edge, Opera); experimentell, Kategorie: webapi

Signatur

interface USBIsochronousInTransferResult

Beschreibung

Das Interface USBIsochronousInTransferResult gehört zur WebUSB API. Ein Objekt dieses Typs erhalten Sie, wenn das von USBDevice.prototype.isochronousTransferIn() zurückgegebene Promise erfüllt wird. Es beschreibt eine isochrone Eingangsübertragung vom Gerät zum Host. Solche Übertragungen kommen bei zeitkritischen Datenströmen zum Einsatz, etwa bei Audio-Interfaces, Webcams oder Messgeräten mit festen Abtastraten.

Isochrone Übertragungen garantieren eine feste Bandbreite, aber keine Zustellung. Fehlerhafte Pakete werden nicht erneut gesendet. Deshalb liefert das Ergebnis neben den Gesamtdaten auch für jedes angeforderte Paket einen eigenen Status. Das Interface hat zwei schreibgeschützte Eigenschaften:

  • data: ein DataView auf den gesamten Empfangspuffer (oder null).
  • packets: ein Array aus USBIsochronousInTransferPacket-Objekten. Jedes Objekt hat eine eigene data-Sicht (DataView) und einen status ("ok", "stall" oder "babble").

Werten Sie die Daten in der Praxis paketweise über packets aus. Die Pakete können kürzer sein als angefordert, und im gemeinsamen Puffer data können dadurch Lücken entstehen. Den Konstruktor brauchen Sie normalerweise nur für Tests und Mocks, denn der Browser erzeugt die Objekte selbst.

Parameter

Name Typ Default Beschreibung
$packets Pflicht USBIsochronousInTransferPacket[] Nur für den Konstruktor new USBIsochronousInTransferResult(packets, data): Array der Einzelpaket-Ergebnisse.
$data DataView null Nur für den Konstruktor: DataView auf den Puffer mit allen empfangenen Daten.

Rückgabewert

Typ
USBIsochronousInTransferResult
Beschreibung
Ein Objekt mit den schreibgeschützten Eigenschaften data (DataView | null) und packets (USBIsochronousInTransferPacket[]).

Beispiele

Isochrone Audio-Daten empfangen und paketweise auswerten

const [device] = await navigator.usb.getDevices();
await device.open();
await device.selectConfiguration(1);
await device.claimInterface(1);
// Alternate Setting mit isochronem Endpunkt aktivieren
await device.selectAlternateInterface(1, 1);

// 8 Pakete zu je 192 Byte von Endpunkt 1 anfordern
const packetLengths = new Array(8).fill(192);
const result = await device.isochronousTransferIn(1, packetLengths);

let bytesOk = 0;
result.packets.forEach((packet, i) => {
  if (packet.status === 'ok') {
    bytesOk += packet.data.byteLength;
  } else {
    console.warn(`Paket ${i}: ${packet.status}`);
  }
});
console.log(`Empfangen: ${bytesOk} Byte in ${result.packets.length} Paketen`);
Empfangen: 1536 Byte in 8 Paketen

16-Bit-PCM-Samples aus gültigen Paketen extrahieren

const extractSamples = (result) => {
  const samples = [];
  for (const { status, data } of result.packets) {
    if (status !== 'ok') continue; // fehlerhafte Pakete überspringen
    for (let offset = 0; offset + 1 < data.byteLength; offset += 2) {
      samples.push(data.getInt16(offset, true)); // Little Endian
    }
  }
  return Int16Array.from(samples);
};

const result = await device.isochronousTransferIn(1, [192, 192, 192, 192]);
const pcm = extractSamples(result);
console.log(pcm.length);
384

Ergebnis per Konstruktor für Unit-Tests erzeugen

const buffer = new ArrayBuffer(8);
const view = new DataView(buffer);
view.setUint32(0, 0xCAFEBABE);

const packets = [
  new USBIsochronousInTransferPacket('ok', new DataView(buffer, 0, 4)),
  new USBIsochronousInTransferPacket('babble', new DataView(buffer, 4, 0))
];
const fake = new USBIsochronousInTransferResult(packets, view);

console.log(fake.packets.map((p) => p.status));
console.log(fake.packets[0].data.getUint32(0).toString(16));
["ok", "babble"] cafebabe

// Wichtig · Fallstricke

  • Browser-Unterstützung: WebUSB gibt es nur in Chromium-basierten Browsern (Chrome, Edge, Opera). Firefox und Safari unterstützen die API nicht. Prüfen Sie die Verfügbarkeit vorher mit 'usb' in navigator.
  • Die API funktioniert nur in einem sicheren Kontext (HTTPS). Der erste Gerätezugriff braucht eine Nutzeraktion über navigator.usb.requestDevice(). Außerdem kann eine Permissions Policy (usb) den Zugriff in iframes sperren.
  • Keine Zustellgarantie: Prüfen Sie immer packet.status. "babble" heißt, das Gerät hat mehr Daten gesendet als erwartet. "stall" bedeutet einen Endpunkt-Fehler. Isochrone Endpunkte lassen sich nicht wie Bulk-Endpunkte mit clearHalt() zurücksetzen.
  • Lücken im Puffer: result.data enthält die Pakete an den Offsets, die sich aus den angeforderten packetLengths ergeben. Kürzere Pakete hinterlassen ungenutzte Bytes. Lesen Sie die Daten deshalb über packets[i].data und nicht direkt als zusammenhängenden Strom.
  • Viele Geräte stellen isochrone Endpunkte nur in einem Alternate Setting bereit. Ohne selectAlternateInterface() wird die Übertragung mit einem Fehler abgelehnt.
  • Für einen durchgehenden Datenstrom sollten mehrere Übertragungen gleichzeitig laufen. Wenn Sie jede Übertragung einzeln abwarten, entstehen Lücken im Stream.