Signatur
Beschreibung
Die schreibgeschützte Eigenschaft sdpMLineIndex eines RTCIceCandidate gibt an, zu welcher Medienbeschreibung (m-Line, also einer Zeile wie m=audio … oder m=video …) im SDP der Kandidat gehört. Die Zählung beginnt bei 0: Die erste m-Line im Angebot bzw. in der Antwort hat den Index 0, die zweite den Index 1 usw.
Der Wert stammt aus dem Feld sdpMLineIndex des Objekts, mit dem der Kandidat erzeugt wurde (new RTCIceCandidate(init)). Wenn der Browser lokale Kandidaten sammelt, befüllt er den Wert selbst, und das Ereignis icecandidate liefert ihn mit. Beim Signaling überträgt man ihn zusammen mit candidate und sdpMid an die Gegenstelle. Dort ordnet RTCPeerConnection.addIceCandidate() den Kandidaten damit dem richtigen Transceiver zu.
Neben dem Index gibt es die Eigenschaft sdpMid, die Media-Stream-Identifikation (Wert des Attributs a=mid:). Sind beide gesetzt, hat sdpMid Vorrang. sdpMLineIndex wird nur ausgewertet, wenn sdpMid null ist. Mindestens eines der beiden Felder muss gesetzt sein, sonst wirft der Konstruktor bzw. addIceCandidate() einen TypeError.
Rückgabewert
null, wenn beim Erzeugen kein Index angegeben wurde.Beispiele
Kandidat erzeugen und Index auslesen
const candidate = new RTCIceCandidate({
candidate: 'candidate:842163049 1 udp 1677729535 203.0.113.5 50000 typ srflx raddr 192.168.1.10 rport 50000',
sdpMid: '0',
sdpMLineIndex: 0
});
console.log(candidate.sdpMLineIndex);
console.log(candidate.sdpMid);
Lokale Kandidaten per Signaling versenden
const pc = new RTCPeerConnection({ iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] });
const ws = new WebSocket('wss://signaling.example.com');
pc.addEventListener('icecandidate', ({ candidate }) => {
if (!candidate) return; // Sammeln abgeschlossen
console.log(`Kandidat für m-Line ${candidate.sdpMLineIndex} (mid=${candidate.sdpMid})`);
ws.send(JSON.stringify({
type: 'candidate',
candidate: candidate.candidate,
sdpMid: candidate.sdpMid,
sdpMLineIndex: candidate.sdpMLineIndex
}));
});
pc.addTransceiver('audio');
pc.addTransceiver('video');
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
Empfangenen Kandidaten robust hinzufügen
const handleRemoteCandidate = async (pc, msg) => {
// Ältere Gegenstellen senden evtl. nur den Index
const init = {
candidate: msg.candidate,
sdpMid: msg.sdpMid ?? null,
sdpMLineIndex: msg.sdpMLineIndex ?? null
};
if (init.sdpMid === null && init.sdpMLineIndex === null) {
console.warn('Kandidat ohne sdpMid/sdpMLineIndex verworfen');
return;
}
try {
await pc.addIceCandidate(init);
} catch (err) {
console.error('addIceCandidate fehlgeschlagen:', err);
}
};
Kandidaten nach Medienspur gruppieren
const byMLine = new Map();
pc.onicecandidate = ({ candidate }) => {
if (!candidate) {
for (const [index, list] of byMLine) {
console.log(`m-Line ${index}: ${list.length} Kandidaten`);
}
return;
}
const key = candidate.sdpMLineIndex ?? 'unbekannt';
if (!byMLine.has(key)) byMLine.set(key, []);
byMLine.get(key).push(candidate.candidate);
};
// Wichtig · Fallstricke
- Schreibgeschützt: Eine Zuweisung wie
candidate.sdpMLineIndex = 1ändert nichts und wirft im Strict Mode einen Fehler. Den Wert setzt man nur über das Init-Objekt des Konstruktors. sdpMidhat Vorrang: Sind beide Werte gesetzt, giltsdpMid. Ein widersprüchlicher Index wird dann ignoriert. Sind beidenull, wirft der Konstruktor bzw.addIceCandidate()einenTypeError.- BUNDLE: Mit
a=group:BUNDLEnutzen alle Medien denselben Transport. Viele Kandidaten gehören dann formal nur zur ersten m-Line (Index0), obwohl sie für alle Spuren gelten. - Serialisierung: Mit
candidate.toJSON()bzw.JSON.stringify(candidate)werdencandidate,sdpMid,sdpMLineIndexundusernameFragmentübernommen. Man kann das Ergebnis also direkt übers Signaling senden. - Kandidat für das Ende des Sammelns: Ein Kandidat mit leerem
candidate-String markiert das Ende der Kandidaten für eine m-Line. Das Ereignisicecandidatemitcandidate === nullmarkiert das Ende für die gesamte Verbindung. - Kompatibilität: Wird in allen aktuellen Browsern unterstützt. Ältere Implementierungen, etwa Chrome vor dem Unified Plan, konnten beim Signaling ausschließlich auf den Index angewiesen sein.