Signatur
Beschreibung
USBIsochronousOutTransferResult gehört zur WebUSB-API. Ein Objekt dieses Typs erhalten Sie, wenn das von USBDevice.isochronousTransferOut(endpointNumber, data, packetLengths) zurückgegebene Promise erfüllt wird. Isochrone Übertragungen nutzt man für zeitkritische Datenströme mit fester Bandbreite, etwa Audio- oder Videodaten an USB-Soundkarten, DACs oder Kameras. Bei dieser Übertragungsart ist die Einhaltung des Zeitplans wichtiger als eine garantierte Zustellung.
Das Interface hat nur eine Eigenschaft: packets. Sie ist ein schreibgeschütztes Array aus USBIsochronousOutTransferPacket-Objekten. Für jeden Eintrag in packetLengths gibt es darin genau ein Paket. Jedes Paket hat folgende Eigenschaften:
bytesWritten: die Anzahl der Bytes, die tatsächlich an das Gerät gesendet wurden.status:"ok"bei Erfolg oder"stall", wenn der Endpunkt blockiert hat (Stall).
Weil isochrone Übertragungen keine Wiederholung bei Fehlern kennen, sollten Sie nach jedem Transfer die Pakete einzeln prüfen. Anders als bei transferOut() gibt es kein Gesamtergebnis. Ob einzelne Pakete fehlgeschlagen sind, erfahren Sie nur über den Status des jeweiligen Pakets.
Über den Konstruktor new USBIsochronousOutTransferResult(packets) können Sie Ergebnisobjekte auch selbst erzeugen. Das ist vor allem für Tests und Mocks nützlich.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $packets Pflicht | USBIsochronousOutTransferPacket[] | Nur beim Konstruktor: ein Array von USBIsochronousOutTransferPacket-Objekten, die das Ergebnisobjekt enthalten soll. |
Rückgabewert
packets (Array von USBIsochronousOutTransferPacket). Jedes Paket hat die Eigenschaften bytesWritten (number) und status ("ok" | "stall").Beispiele
Audiodaten isochron senden und Pakete auswerten
// Muss durch eine Nutzeraktion ausgelöst werden (z. B. Klick)
const sendAudioFrame = async () => {
const [device] = await navigator.usb.getDevices();
await device.open();
await device.selectConfiguration(1);
await device.claimInterface(1);
await device.selectAlternateInterface(1, 1); // Alternate-Setting mit Bandbreite
const packetLengths = [192, 192, 192, 192]; // 4 Pakete à 192 Byte
const data = new Uint8Array(packetLengths.reduce((a, b) => a + b, 0));
const result = await device.isochronousTransferOut(1, data, packetLengths);
result.packets.forEach((packet, i) => {
console.log(`Paket ${i}: ${packet.status}, ${packet.bytesWritten} Byte`);
});
};
document.querySelector('#play').addEventListener('click', sendAudioFrame);
Übertragungsstatistik aus dem Ergebnis berechnen
const summarize = (result) => {
const total = result.packets.reduce((sum, p) => sum + p.bytesWritten, 0);
const stalled = result.packets.filter((p) => p.status === 'stall').length;
return { pakete: result.packets.length, bytes: total, stalls: stalled };
};
// Innerhalb einer async-Funktion:
// const result = await device.isochronousTransferOut(1, data, packetLengths);
// console.log(summarize(result));
Ergebnisobjekt für Unit-Tests selbst erzeugen
const packets = [
new USBIsochronousOutTransferPacket('ok', 192),
new USBIsochronousOutTransferPacket('stall', 0)
];
const fakeResult = new USBIsochronousOutTransferResult(packets);
console.log(fakeResult.packets.length);
console.log(fakeResult.packets[1].status);
Nach einem Stall den Endpunkt zurücksetzen
const sendWithRecovery = async (device, endpoint, data, lengths) => {
const result = await device.isochronousTransferOut(endpoint, data, lengths);
if (result.packets.some((p) => p.status === 'stall')) {
console.warn('Stall erkannt – Endpunkt wird zurückgesetzt');
await device.clearHalt('out', endpoint);
}
return result;
};
// Wichtig · Fallstricke
- Kompatibilität: WebUSB ist experimentell. Die API gibt es nur in Chromium-basierten Browsern (Chrome, Edge, Opera) auf dem Desktop und unter Android. Firefox und Safari unterstützen sie nicht. Prüfen Sie die Verfügbarkeit mit
'usb' in navigator. - Sicherer Kontext: WebUSB funktioniert nur über HTTPS oder
localhost. Der Zugriff auf ein Gerät setzt voraus, dass der Nutzer es vorher übernavigator.usb.requestDevice()ausgewählt hat. Dieser Aufruf muss durch eine Nutzeraktion ausgelöst werden. Die Berechtigungsrichtlinieusbkann WebUSB in iframes sperren. - Kein Fehler bei Paketverlust: Das Promise wird auch dann erfüllt, wenn einzelne Pakete mit
"stall"enden. Prüfen Sie deshalb immer jedes Paket inpacketseinzeln. - Die Summe aller Werte in
packetLengthsmuss genau der Länge vondataentsprechen. Sonst wird das Promise mit einem Fehler abgelehnt. - Isochrone Endpunkte sind oft erst nach
selectAlternateInterface()aktiv, weil das Standard-Setting (0) meist keine Bandbreite reserviert. - Manche Geräteklassen, z. B. USB-Audio, beansprucht das Betriebssystem selbst. Solche Interfaces lassen sich dann nicht über
claimInterface()belegen.