Signatur
Beschreibung
Das Interface USBIsochronousOutTransferPacket gehört zur WebUSB API. Bei einer isochronen Übertragung werden Daten in feste Zeitfenster aufgeteilt, zum Beispiel für Audio- oder Videostreams an ein USB-Gerät. Ruft man USBDevice.isochronousTransferOut(endpointNumber, data, packetLengths) auf, wird der Puffer data anhand der Längen in packetLengths in einzelne Pakete zerlegt. Für jedes Paket liefert das USBIsochronousOutTransferResult in seinem Array packets ein eigenes USBIsochronousOutTransferPacket.
Jedes Paket-Objekt hat zwei schreibgeschützte Eigenschaften:
bytesWritten(number): die Anzahl der Bytes, die in diesem Paket tatsächlich an das Gerät gesendet wurden.status(string): der Status des Pakets, entweder"ok"(erfolgreich) oder"stall"(der Endpunkt hat einen Stall gemeldet).
Im Gegensatz zu Bulk- oder Interrupt-Übertragungen gibt es bei isochronen Übertragungen keine automatische Wiederholung. Deshalb sollte man jedes Paket einzeln prüfen: Einzelne Pakete können fehlschlagen oder unvollständig sein, obwohl das Promise erfolgreich erfüllt wird. Den Konstruktor braucht man in der Praxis vor allem, um Ergebnisse in Tests oder Polyfills nachzubilden.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $status Pflicht | "ok" | "stall" | Nur beim Konstruktor: Status des Pakets. Wird als Eigenschaft status übernommen. |
|
| $bytesWritten | number | 0 | Nur beim Konstruktor: Anzahl der gesendeten Bytes. Wird als Eigenschaft bytesWritten übernommen. |
Rückgabewert
bytesWritten und status. Der Browser erzeugt es normalerweise selbst als Element von USBIsochronousOutTransferResult.packets.Beispiele
Paket-Objekt direkt erzeugen (z. B. für Tests)
// Ergebnis eines Pakets nachbilden, etwa für einen Mock von USBDevice
const packet = new USBIsochronousOutTransferPacket('ok', 192);
console.log(packet.status, packet.bytesWritten);
const stalled = new USBIsochronousOutTransferPacket('stall');
console.log(stalled.status, stalled.bytesWritten);
Audio-Frames isochron senden und jedes Paket prüfen
const sendAudioFrames = async (device, endpointNumber, samples) => {
const packetSize = 192; // z. B. 48 kHz, 16 Bit, Stereo, 1 ms
const packetCount = Math.ceil(samples.byteLength / packetSize);
const packetLengths = Array.from({ length: packetCount }, (_, i) =>
Math.min(packetSize, samples.byteLength - i * packetSize)
);
const result = await device.isochronousTransferOut(
endpointNumber,
samples,
packetLengths
);
result.packets.forEach((packet, i) => {
if (packet.status !== 'ok') {
console.warn(`Paket ${i}: Status ${packet.status}`);
} else if (packet.bytesWritten < packetLengths[i]) {
console.warn(`Paket ${i}: nur ${packet.bytesWritten}/${packetLengths[i]} Bytes`);
}
});
return result.packets.reduce((sum, p) => sum + p.bytesWritten, 0);
};
// Nutzung (nach navigator.usb.requestDevice() und device.open()):
// const total = await sendAudioFrames(device, 1, new Uint8Array(1920));
// console.log(`Gesendet: ${total} Bytes`);
Statistik über erfolgreiche und fehlerhafte Pakete
const summarize = (packets) => {
const ok = packets.filter((p) => p.status === 'ok').length;
const stalls = packets.length - ok;
const bytes = packets.reduce((sum, p) => sum + p.bytesWritten, 0);
return { ok, stalls, bytes };
};
const packets = [
new USBIsochronousOutTransferPacket('ok', 64),
new USBIsochronousOutTransferPacket('ok', 64),
new USBIsochronousOutTransferPacket('stall', 0)
];
console.log(summarize(packets));
// Wichtig · Fallstricke
Browser-Kompatibilität: WebUSB gibt es nur in Chromium-Browsern (Chrome, Edge, Opera) auf dem Desktop und unter Android. Firefox und Safari unterstützen die API nicht. Die API ist nur in sicheren Kontexten (HTTPS) verfügbar und kann per Permissions-Policy usb gesperrt sein. Prüfe die Verfügbarkeit vorher mit 'usb' in navigator.
Fallstricke:
- Das Promise von
isochronousTransferOut()wird auch dann erfüllt, wenn einzelne Pakete"stall"melden. Werte darum immer jedes Paket inpacketsaus. - Isochrone Übertragungen wiederholen verlorene Daten nicht. Bei Echtzeit-Streams musst du fehlende Pakete gegebenenfalls selbst ausgleichen.
- Die Summe von
packetLengthsmuss zur Größe des Datenpuffers passen. Außerdem muss das Interface mit dem isochronen Endpunkt vorher mitclaimInterface()reserviert und die passende Alternate Setting mitselectAlternateInterface()gewählt worden sein. - Viele Geräteklassen (z. B. USB-Audio) werden vom Betriebssystem beansprucht und sind über WebUSB nicht erreichbar.