Start · Sprachen · JavaScript · Referenz · RTCEncodedAudioFrame.timestamp

RTCEncodedAudioFrame.timestamp

Eigenschaft

Nur lesbare Eigenschaft, die den Zeitstempel des Abtastbeginns eines kodierten Audio-Frames liefert; entspricht dem RTP-Zeitstempel des Frames.

seit JavaScript WebRTC Encoded Transform – Chromium 86+ (Insertabl deprecated seit ja Kategorie: webapi

Signatur

get RTCEncodedAudioFrame.timestamp

Beschreibung

Die Eigenschaft timestamp eines RTCEncodedAudioFrame gibt an, wann die Abtastung (Sampling) des Audio-Frames begann. Der Wert entspricht dem RTP-Zeitstempel nach RFC 3550, also dem Abtastzeitpunkt des ersten Oktetts im RTP-Paket. Er wird in Einheiten der Medien-Taktrate gezählt (bei Opus typischerweise 48 000 Hz) und nicht in Millisekunden der Wanduhr.

Verwenden kannst du die Eigenschaft innerhalb einer WebRTC Encoded Transform, also überall dort, wo du kodierte Frames zwischen Encoder und Paketierer (Sender) bzw. zwischen Depaketierer und Decoder (Empfänger) abfängst, z. B. über RTCRtpScriptTransform in einem Worker. Typische Einsatzfälle sind das Sortieren oder Synchronisieren von Frames, das Erkennen von Lücken (verlorene Pakete), das Messen der Frame-Dauer sowie das Protokollieren oder Debuggen von Audio-Pipelines, etwa bei Ende-zu-Ende-Verschlüsselung.

Die Eigenschaft ist schreibgeschützt. Die Spezifikation hat den Wert inzwischen in die Metadaten verlagert: Neuer Code sollte frame.getMetadata().rtpTimestamp verwenden und timestamp höchstens als Rückfalllösung für ältere Browser lesen.

Rückgabewert

Typ
number
Beschreibung
Eine nicht negative Ganzzahl (vorzeichenloser 32-Bit-Wert) mit dem RTP-Zeitstempel des Frames, also dem Abtastbeginn in Einheiten der Taktrate des Codecs.

Beispiele

Zeitstempel im Worker mit RTCRtpScriptTransform protokollieren

// worker.js
onrtctransform = (event) => {
  const { readable, writable } = event.transformer;

  const logger = new TransformStream({
    transform(frame, controller) {
      // Neuere Browser: Metadaten bevorzugen, sonst auf timestamp zurückfallen
      const ts = frame.getMetadata?.().rtpTimestamp ?? frame.timestamp;
      console.log(`Audio-Frame: RTP-Zeitstempel ${ts}, ${frame.data.byteLength} Byte`);
      controller.enqueue(frame);
    }
  });

  readable.pipeThrough(logger).pipeTo(writable);
};

// main.js
const worker = new Worker('worker.js');
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const pc = new RTCPeerConnection();
const sender = pc.addTrack(stream.getAudioTracks()[0], stream);
sender.transform = new RTCRtpScriptTransform(worker, { side: 'send' });
Audio-Frame: RTP-Zeitstempel 3141592653, 87 Byte Audio-Frame: RTP-Zeitstempel 3141593613, 91 Byte

Frame-Dauer und Lücken auf der Empfangsseite erkennen

// worker.js – Empfangsseite
const CLOCK_RATE = 48000; // Opus
let lastTs = null;

onrtctransform = (event) => {
  const { readable, writable } = event.transformer;

  readable.pipeThrough(new TransformStream({
    transform(frame, controller) {
      const ts = frame.timestamp;
      if (lastTs !== null) {
        // Differenz modulo 2^32 berechnen (Überlauf berücksichtigen)
        const delta = (ts - lastTs + 2 ** 32) % 2 ** 32;
        const ms = (delta / CLOCK_RATE) * 1000;
        if (ms > 20) console.warn(`Lücke erkannt: ${ms.toFixed(1)} ms`);
      }
      lastTs = ts;
      controller.enqueue(frame);
    }
  })).pipeTo(writable);
};

// main.js
pc.ontrack = ({ receiver }) => {
  receiver.transform = new RTCRtpScriptTransform(worker, { side: 'receive' });
};
Lücke erkannt: 60.0 ms

Legacy-API in Chromium (createEncodedStreams)

// Nur Chromium, PeerConnection mit encodedInsertableStreams erzeugen
const pc = new RTCPeerConnection({ encodedInsertableStreams: true });
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const sender = pc.addTrack(stream.getAudioTracks()[0], stream);

const { readable, writable } = sender.createEncodedStreams();
readable.pipeThrough(new TransformStream({
  transform(frame, controller) {
    console.log('timestamp:', frame.timestamp);
    controller.enqueue(frame);
  }
})).pipeTo(writable);
timestamp: 1234567890

// Wichtig · Fallstricke

  • Veraltet: Die Spezifikation führt den Wert inzwischen als rtpTimestamp in RTCEncodedAudioFrame.getMetadata(). Verwende timestamp nur als Rückfall und prüfe per Feature-Erkennung.
  • Einheit: Der Wert ist kein Wanduhr- oder performance.now()-Zeitstempel, sondern zählt in Takten der Codec-Taktrate. Zum Umrechnen in Millisekunden musst du durch die Taktrate teilen (z. B. 48 000 bei Opus).
  • Überlauf: RTP-Zeitstempel sind 32-Bit-Werte, die überlaufen und bei einem zufälligen Wert starten. Differenzen deshalb immer modulo 232 berechnen.
  • Kompatibilität: Chromium unterstützt die ältere API createEncodedStreams() (mit encodedInsertableStreams: true) und neuere Versionen auch RTCRtpScriptTransform; Firefox und Safari nur RTCRtpScriptTransform. Die Frames sind ausschließlich innerhalb dieser Transform-Pipelines verfügbar, nicht über andere Media-APIs.
  • Die Frames müssen mit controller.enqueue() weitergereicht werden, sonst bricht der Audiostrom ab.