Signatur
Beschreibung
Die Methode isochronousTransferOut() der WebUSB-API überträgt Daten zum Gerät, und zwar über einen isochronen OUT-Endpunkt. Isochrone Übertragungen haben eine feste Bandbreite und einen festen Zeitrahmen. Dafür gibt es keine Wiederholung bei Fehlern. Sie eignen sich für Datenströme, bei denen der Zeitpunkt wichtiger ist als eine fehlerfreie Zustellung, etwa Audioausgabe über USB-Soundkarten, DACs oder Mess- und Steuergeräte mit festem Takt.
Der Puffer data wird anhand des Arrays packetLengths in einzelne Pakete aufgeteilt: Das erste Paket enthält die ersten packetLengths[0] Bytes, das zweite die nächsten packetLengths[1] Bytes und so weiter. Jedes Paket wird in einem eigenen USB-Frame bzw. Microframe gesendet. Das Ergebnis enthält im Array packets für jedes Paket ein USBIsochronousOutTransferPacket mit bytesWritten und status.
Bevor du die Methode aufrufst, muss das Gerät geöffnet sein (open()), eine Konfiguration gewählt sein (selectConfiguration()) und die Schnittstelle beansprucht sein (claimInterface()). Isochrone Endpunkte liegen meist in einer alternativen Einstellung der Schnittstelle, weil die Standardeinstellung keine Bandbreite reserviert. Deshalb ist in der Regel zusätzlich selectAlternateInterface() nötig.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $endpointNumber Pflicht | number | Nummer des isochronen OUT-Endpunkts (ohne Richtungsbit, also z. B. 1 statt 0x01). Der Endpunkt muss zu einer beanspruchten Schnittstelle gehören. |
|
| $data Pflicht | ArrayBuffer | TypedArray | DataView | Die zu sendenden Daten als BufferSource. Sie werden in der Reihenfolge von packetLengths auf die Pakete aufgeteilt. |
|
| $packetLengths Pflicht | number[] | Array mit der Länge jedes Pakets in Bytes. Ein einzelner Wert darf die maximale Paketgröße des Endpunkts (packetSize) nicht überschreiten. Die Summe aller Werte muss zur Länge von data passen. |
Rückgabewert
USBIsochronousOutTransferResult erfüllt wird. Dessen Eigenschaft packets ist ein Array von USBIsochronousOutTransferPacket-Objekten mit bytesWritten (gesendete Bytes) und status ("ok" oder "stall"). Das Promise wird mit einer DOMException abgelehnt, wenn das Gerät nicht geöffnet ist, die Schnittstelle nicht beansprucht ist, der Endpunkt nicht existiert oder die Übertragung fehlschlägt.Beispiele
Gerät vorbereiten und einen Audioblock senden
// Muss in einem Klick-Handler laufen, weil requestDevice() eine Nutzeraktion verlangt
const button = document.querySelector('#connect');
button.addEventListener('click', async () => {
const device = await navigator.usb.requestDevice({
filters: [{ classCode: 0x01 }] // USB-Audio
});
await device.open();
if (device.configuration === null) {
await device.selectConfiguration(1);
}
await device.claimInterface(1);
// Alternative Einstellung 1 reserviert die Bandbreite für den isochronen Endpunkt
await device.selectAlternateInterface(1, 1);
// 8 Pakete zu je 192 Bytes (48 kHz, 16 Bit, Stereo, 1 ms pro Paket)
const packetSize = 192;
const packetCount = 8;
const data = new Uint8Array(packetSize * packetCount); // Stille
const packetLengths = new Array(packetCount).fill(packetSize);
const result = await device.isochronousTransferOut(1, data, packetLengths);
console.log(`${result.packets.length} Pakete gesendet`);
});
Paketstatus prüfen und gesendete Bytes zählen
const sendBlock = async (device, endpoint, samples, packetSize) => {
const packetCount = Math.ceil(samples.byteLength / packetSize);
const packetLengths = Array.from({ length: packetCount }, (_, i) =>
Math.min(packetSize, samples.byteLength - i * packetSize)
);
const { packets } = await device.isochronousTransferOut(endpoint, samples, packetLengths);
const written = packets.reduce((sum, p) => sum + p.bytesWritten, 0);
const stalled = packets.filter((p) => p.status === 'stall').length;
if (stalled > 0) {
console.warn(`${stalled} Paket(e) mit Stall – Endpunkt wird zurückgesetzt`);
await device.clearHalt('out', endpoint);
}
console.log(`Gesendet: ${written} von ${samples.byteLength} Bytes`);
return written;
};
Kontinuierlicher Datenstrom mit mehreren Übertragungen gleichzeitig
// Mehrere Übertragungen gleichzeitig offen halten, damit keine Lücken entstehen
const streamOut = async (device, endpoint, nextBlock, signal) => {
const packetSize = 192;
const packetCount = 10;
const lengths = new Array(packetCount).fill(packetSize);
const pump = async () => {
while (!signal.aborted) {
const block = nextBlock(packetSize * packetCount); // liefert Uint8Array
await device.isochronousTransferOut(endpoint, block, lengths);
}
};
// Drei parallele Pumpen bilden einen einfachen Warteschlangen-Puffer
await Promise.all([pump(), pump(), pump()]);
};
const controller = new AbortController();
// streamOut(device, 1, (n) => new Uint8Array(n), controller.signal);
// später: controller.abort();
// Wichtig · Fallstricke
- Richtung: Anders als die MDN-Kurzbeschreibung vermuten lässt, sendet die Methode Daten an das Gerät (Host → Gerät). Zum Empfangen dient
isochronousTransferIn(). - Keine Zustellgarantie: Isochrone Pakete werden bei Fehlern nicht wiederholt. Prüfe
statusundbytesWrittenjedes Pakets einzeln. Ein Promise, das erfüllt wird, bedeutet nicht, dass alle Daten angekommen sind. - Alternative Einstellung: Ohne
selectAlternateInterface()mit einer Einstellung, die Bandbreite reserviert, schlägt die Übertragung meist fehl oder liefert keine Daten. - Paketgröße: Ein Wert in
packetLengths, der größer ist alsendpoint.packetSize, führt zu einem Fehler oder zu abgeschnittenen Paketen. - Kontinuität: Für lückenlose Datenströme solltest du mehrere Übertragungen gleichzeitig offen halten. Einzelne, nacheinander abgewartete Aufrufe erzeugen Aussetzer.
- Kompatibilität und Sicherheit: WebUSB gibt es nur in Chromium-Browsern (Chrome, Edge, Opera, auf Desktop und Android). Firefox und Safari unterstützen es nicht. Die API braucht einen sicheren Kontext (HTTPS), eine Freigabe durch den Nutzer über
navigator.usb.requestDevice()und die Permissions Policyusb. Geräteklassen, die das Betriebssystem schützt (z. B. HID oder Massenspeicher), sind gesperrt. Unter Windows kann für isochrone Übertragungen ein WinUSB-Treiber nötig sein. - Prüfe die Unterstützung mit
'usb' in navigator.