Signatur
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: einDataViewauf den gesamten Empfangspuffer (odernull).packets: ein Array ausUSBIsochronousInTransferPacket-Objekten. Jedes Objekt hat eine eigenedata-Sicht (DataView) und einenstatus("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
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`);
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);
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));
// 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 mitclearHalt()zurücksetzen. - Lücken im Puffer:
result.dataenthält die Pakete an den Offsets, die sich aus den angefordertenpacketLengthsergeben. Kürzere Pakete hinterlassen ungenutzte Bytes. Lesen Sie die Daten deshalb überpackets[i].dataund 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.