endPair/disconnect: WebRTC tamamen kapatılıyor + tiles temizleniyor
sdk/Peer.js — endPair():
- this.rtc?.destroy() eklendi
- Yerel akışlar durur, RTCPeerConnection kapanır
sdk/index.js — sinyal handler'ları:
- end/pair: peer.rtc?.destroy() (alan taraf da kapatır)
- peer/disconnect: peer.rtc?.destroy() (WebSocket kopunca RTC da kapanır)
public/studio/Studio.js:
_clearPeerTiles(peerId):
- data-peer-id dataset'i ile local + remote grid'den tile'ları kaldırır
- Gizli <audio> elemanını srcObject=null + remove() ile temizler
- CSS.escape ile güvenli selector
tile.dataset.peerId: _addLocalTile ve _addRemoteTile her ikisinde eklendi
tile._audioEl: ses tile'larında referans saklanır (clearPeerTiles için)
_watchIncoming: peer.rtc.on('disconnected') → clearPeerTiles + rebuildPeerItems
end/pair handler: clearPeerTiles(from) çağrısı eklendi
peer/disconnect handler: clearPeerTiles(peer.socketId) çağrısı eklendi
_addLocalTile/_addRemoteTile: peerLabel yerine peer objesi alır
go test -race ./... — yeşil
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d468c95adf
commit
5ebd111af0
|
|
@ -62,14 +62,16 @@ export default class Studio {
|
||||||
this._setStatus('online', `${this._peerLabel(peer)} eşleşmesi kuruldu`);
|
this._setStatus('online', `${this._peerLabel(peer)} eşleşmesi kuruldu`);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Eşleşme bitti (karşı taraf koptu veya endPair çağrıldı)
|
// Eşleşme bitti — tiles + RTC (SDK zaten destroy çağırdı, ama tiles Studio'ya ait)
|
||||||
this.mwse.me.on('end/pair', (from) => {
|
this.mwse.me.on('end/pair', (from) => {
|
||||||
|
if (typeof from === 'string') this._clearPeerTiles(from);
|
||||||
this._rebuildPeerItems();
|
this._rebuildPeerItems();
|
||||||
this._setStatus('', `${typeof from === 'string' ? from.slice(-8) : ''} ayrıldı`);
|
this._setStatus('', `${typeof from === 'string' ? from.slice(-8) : ''} ayrıldı`);
|
||||||
});
|
});
|
||||||
|
|
||||||
// WebSocket bağlantısı kopunca (sayfa yenileme, ağ kesilmesi)
|
// WebSocket koptu → RTC da kapandı (SDK destroy çağırdı)
|
||||||
this.mwse.me.on('peer/disconnect', peer => {
|
this.mwse.me.on('peer/disconnect', peer => {
|
||||||
|
this._clearPeerTiles(peer.socketId);
|
||||||
this._rebuildPeerItems();
|
this._rebuildPeerItems();
|
||||||
this._setStatus('error', `${this._peerLabel(peer)} bağlantısı kesildi`);
|
this._setStatus('error', `${this._peerLabel(peer)} bağlantısı kesildi`);
|
||||||
});
|
});
|
||||||
|
|
@ -173,24 +175,29 @@ export default class Studio {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Yerel (gönderilen) akış tile'ı ekle
|
// Yerel (gönderilen) akış tile'ı ekle
|
||||||
_addLocalTile(label, stream, peerLabel) {
|
_addLocalTile(label, stream, peer) {
|
||||||
const hasVideo = stream.getVideoTracks().length > 0;
|
const peerLabel = typeof peer === 'string' ? peer : this._peerLabel(peer);
|
||||||
|
const peerId = peer?.socketId ?? peerLabel;
|
||||||
|
const hasVideo = stream.getVideoTracks().length > 0;
|
||||||
const tile = this._makeTile(
|
const tile = this._makeTile(
|
||||||
label,
|
label,
|
||||||
`→ ${peerLabel}`,
|
`→ ${peerLabel}`,
|
||||||
stream,
|
stream,
|
||||||
hasVideo,
|
hasVideo,
|
||||||
true, // muted (geri besleme yok)
|
true, // muted (geri besleme yok)
|
||||||
() => tile.remove() && this._updatePanelVisibility()
|
() => { tile.remove(); this._updatePanelVisibility(); }
|
||||||
);
|
);
|
||||||
|
tile.dataset.peerId = peerId;
|
||||||
this._localGrid.appendChild(tile);
|
this._localGrid.appendChild(tile);
|
||||||
this._updatePanelVisibility();
|
this._updatePanelVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uzak (gelen) track tile'ı → ses kontrollü
|
// Uzak (gelen) track tile'ı → ses kontrollü
|
||||||
_addRemoteTile(track, streams, peerLabel) {
|
_addRemoteTile(track, streams, peer) {
|
||||||
const isVideo = track.kind === 'video';
|
const peerLabel = typeof peer === 'string' ? peer : this._peerLabel(peer);
|
||||||
const stream = streams?.[0] ?? new MediaStream([track]);
|
const peerId = peer?.socketId ?? peerLabel;
|
||||||
|
const isVideo = track.kind === 'video';
|
||||||
|
const stream = streams?.[0] ?? new MediaStream([track]);
|
||||||
|
|
||||||
const tile = document.createElement('div');
|
const tile = document.createElement('div');
|
||||||
tile.className = `mwse-stream-tile${isVideo ? '' : ' mwse-stream-tile--audio'}`;
|
tile.className = `mwse-stream-tile${isVideo ? '' : ' mwse-stream-tile--audio'}`;
|
||||||
|
|
@ -212,6 +219,8 @@ export default class Studio {
|
||||||
mediaEl.muted = false;
|
mediaEl.muted = false;
|
||||||
mediaEl.srcObject = stream;
|
mediaEl.srcObject = stream;
|
||||||
document.body.appendChild(mediaEl);
|
document.body.appendChild(mediaEl);
|
||||||
|
// tile'a referans ekle ki _clearPeerTiles kapatabilsin
|
||||||
|
tile._audioEl = mediaEl;
|
||||||
|
|
||||||
const icon = document.createElement('div');
|
const icon = document.createElement('div');
|
||||||
icon.className = 'mwse-stream-tile__audio-icon';
|
icon.className = 'mwse-stream-tile__audio-icon';
|
||||||
|
|
@ -258,6 +267,7 @@ export default class Studio {
|
||||||
|
|
||||||
info.append(lbl, peerEl, muteBtn, closeBtn);
|
info.append(lbl, peerEl, muteBtn, closeBtn);
|
||||||
tile.appendChild(info);
|
tile.appendChild(info);
|
||||||
|
tile.dataset.peerId = peerId;
|
||||||
this._remoteGrid.appendChild(tile);
|
this._remoteGrid.appendChild(tile);
|
||||||
this._updatePanelVisibility();
|
this._updatePanelVisibility();
|
||||||
|
|
||||||
|
|
@ -588,7 +598,7 @@ export default class Studio {
|
||||||
const label = dev.label || dev.deviceId.slice(-6);
|
const label = dev.label || dev.deviceId.slice(-6);
|
||||||
if (peer.rtc._streams?.has(label)) peer.rtc.removeStream(label);
|
if (peer.rtc._streams?.has(label)) peer.rtc.removeStream(label);
|
||||||
peer.rtc.addStream(label, stream);
|
peer.rtc.addStream(label, stream);
|
||||||
this._addLocalTile(label, stream, this._peerLabel(peer));
|
this._addLocalTile(label, stream, peer);
|
||||||
this._view.popTo(4); this._pushStreamsColumn(peer);
|
this._view.popTo(4); this._pushStreamsColumn(peer);
|
||||||
} else {
|
} else {
|
||||||
this._previewStream(stream, dev.label || title);
|
this._previewStream(stream, dev.label || title);
|
||||||
|
|
@ -662,7 +672,7 @@ export default class Studio {
|
||||||
|
|
||||||
if (peer.rtc._streams?.has(type)) peer.rtc.removeStream(type);
|
if (peer.rtc._streams?.has(type)) peer.rtc.removeStream(type);
|
||||||
peer.rtc.addStream(type, stream);
|
peer.rtc.addStream(type, stream);
|
||||||
this._addLocalTile(type, stream, this._peerLabel(peer));
|
this._addLocalTile(type, stream, peer);
|
||||||
this._setStatus('online', `${type} → ${this._peerLabel(peer)}`);
|
this._setStatus('online', `${type} → ${this._peerLabel(peer)}`);
|
||||||
this._view.popTo(3);
|
this._view.popTo(3);
|
||||||
this._pushStreamsColumn(peer);
|
this._pushStreamsColumn(peer);
|
||||||
|
|
@ -690,6 +700,21 @@ export default class Studio {
|
||||||
peer.rtc.connect({ polite: this.mwse.me.socketId < peer.socketId });
|
peer.rtc.connect({ polite: this.mwse.me.socketId < peer.socketId });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bir peer'a ait tüm tile'ları temizle (pair bitti veya disconnect)
|
||||||
|
_clearPeerTiles(peerId) {
|
||||||
|
for (const grid of [this._localGrid, this._remoteGrid]) {
|
||||||
|
if (!grid) continue;
|
||||||
|
// dataset.peerId → attribute adı: data-peer-id
|
||||||
|
for (const tile of [...grid.querySelectorAll(`[data-peer-id="${CSS.escape(peerId)}"]`)]) {
|
||||||
|
// Gizli <audio> elemanlarını da kapat
|
||||||
|
const audio = tile._audioEl;
|
||||||
|
if (audio) { audio.srcObject = null; audio.remove(); }
|
||||||
|
tile.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._updatePanelVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
// Gelen track'leri izle → panel'e ekle
|
// Gelen track'leri izle → panel'e ekle
|
||||||
_watchIncoming(peer) {
|
_watchIncoming(peer) {
|
||||||
// RTC başlatılmazsa gelen :rtcpack: sinyalleri receive() içinde _neg=null
|
// RTC başlatılmazsa gelen :rtcpack: sinyalleri receive() içinde _neg=null
|
||||||
|
|
@ -697,9 +722,15 @@ export default class Studio {
|
||||||
this._ensureRTC(peer);
|
this._ensureRTC(peer);
|
||||||
|
|
||||||
peer.rtc.on('track', (track, streams) => {
|
peer.rtc.on('track', (track, streams) => {
|
||||||
this._addRemoteTile(track, streams, this._peerLabel(peer));
|
this._addRemoteTile(track, streams, peer);
|
||||||
this._setStatus('online', `← ${this._peerLabel(peer)} ${track.kind}`);
|
this._setStatus('online', `← ${this._peerLabel(peer)} ${track.kind}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// RTC kapandığında (endPair, peer/disconnect) tile'ları temizle
|
||||||
|
peer.rtc.on('disconnected', () => {
|
||||||
|
this._clearPeerTiles(peer.socketId);
|
||||||
|
this._rebuildPeerItems();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_previewStream(stream, label) {
|
_previewStream(stream, label) {
|
||||||
|
|
|
||||||
|
|
@ -125,6 +125,7 @@ export default class Peer extends MWSEEventTarget {
|
||||||
async endPair() {
|
async endPair() {
|
||||||
await this.mwse.EventPooling.request({ type: 'end/pair', to: this.socketId });
|
await this.mwse.EventPooling.request({ type: 'end/pair', to: this.socketId });
|
||||||
this.mwse.pairs.delete(this.socketId);
|
this.mwse.pairs.delete(this.socketId);
|
||||||
|
this.rtc?.destroy(); // WebRTC bağlantısını kapat, akışları durdur
|
||||||
this.forget();
|
this.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -236,8 +236,8 @@ export default class MWSE {
|
||||||
ep.signal('peer/disconnect', ({ id }) => {
|
ep.signal('peer/disconnect', ({ id }) => {
|
||||||
const peer = this.peer(id, true);
|
const peer = this.peer(id, true);
|
||||||
this.pairs.delete(id);
|
this.pairs.delete(id);
|
||||||
|
peer.rtc?.destroy(); // WebSocket kopunca (sayfa yenileme vb.) RTC da kapat
|
||||||
peer.emit('disconnect');
|
peer.emit('disconnect');
|
||||||
// me üzerinden de yay, Studio dinleyebilsin.
|
|
||||||
this.peer('me').emit('peer/disconnect', peer);
|
this.peer('me').emit('peer/disconnect', peer);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -253,6 +253,7 @@ export default class MWSE {
|
||||||
ep.signal('end/pair', ({ from, info }) => {
|
ep.signal('end/pair', ({ from, info }) => {
|
||||||
const peer = this.peer(from, true);
|
const peer = this.peer(from, true);
|
||||||
this.pairs.delete(from);
|
this.pairs.delete(from);
|
||||||
|
peer.rtc?.destroy(); // karşı taraf endPair çağırdığında da RTC kapat
|
||||||
peer.emit('end/pair', info);
|
peer.emit('end/pair', info);
|
||||||
this.peer('me').emit('end/pair', from, info);
|
this.peer('me').emit('end/pair', from, info);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue