diff --git a/public/studio/Studio.js b/public/studio/Studio.js index 1914e8e..89a50c3 100644 --- a/public/studio/Studio.js +++ b/public/studio/Studio.js @@ -62,14 +62,16 @@ export default class Studio { 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) => { + if (typeof from === 'string') this._clearPeerTiles(from); this._rebuildPeerItems(); 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._clearPeerTiles(peer.socketId); this._rebuildPeerItems(); this._setStatus('error', `${this._peerLabel(peer)} bağlantısı kesildi`); }); @@ -173,24 +175,29 @@ export default class Studio { } // Yerel (gönderilen) akış tile'ı ekle - _addLocalTile(label, stream, peerLabel) { - const hasVideo = stream.getVideoTracks().length > 0; + _addLocalTile(label, stream, peer) { + const peerLabel = typeof peer === 'string' ? peer : this._peerLabel(peer); + const peerId = peer?.socketId ?? peerLabel; + const hasVideo = stream.getVideoTracks().length > 0; const tile = this._makeTile( label, `→ ${peerLabel}`, stream, hasVideo, true, // muted (geri besleme yok) - () => tile.remove() && this._updatePanelVisibility() + () => { tile.remove(); this._updatePanelVisibility(); } ); + tile.dataset.peerId = peerId; this._localGrid.appendChild(tile); this._updatePanelVisibility(); } // Uzak (gelen) track tile'ı → ses kontrollü - _addRemoteTile(track, streams, peerLabel) { - const isVideo = track.kind === 'video'; - const stream = streams?.[0] ?? new MediaStream([track]); + _addRemoteTile(track, streams, peer) { + const peerLabel = typeof peer === 'string' ? peer : this._peerLabel(peer); + const peerId = peer?.socketId ?? peerLabel; + const isVideo = track.kind === 'video'; + const stream = streams?.[0] ?? new MediaStream([track]); const tile = document.createElement('div'); tile.className = `mwse-stream-tile${isVideo ? '' : ' mwse-stream-tile--audio'}`; @@ -212,6 +219,8 @@ export default class Studio { mediaEl.muted = false; mediaEl.srcObject = stream; document.body.appendChild(mediaEl); + // tile'a referans ekle ki _clearPeerTiles kapatabilsin + tile._audioEl = mediaEl; const icon = document.createElement('div'); icon.className = 'mwse-stream-tile__audio-icon'; @@ -258,6 +267,7 @@ export default class Studio { info.append(lbl, peerEl, muteBtn, closeBtn); tile.appendChild(info); + tile.dataset.peerId = peerId; this._remoteGrid.appendChild(tile); this._updatePanelVisibility(); @@ -588,7 +598,7 @@ export default class Studio { const label = dev.label || dev.deviceId.slice(-6); if (peer.rtc._streams?.has(label)) peer.rtc.removeStream(label); peer.rtc.addStream(label, stream); - this._addLocalTile(label, stream, this._peerLabel(peer)); + this._addLocalTile(label, stream, peer); this._view.popTo(4); this._pushStreamsColumn(peer); } else { this._previewStream(stream, dev.label || title); @@ -662,7 +672,7 @@ export default class Studio { if (peer.rtc._streams?.has(type)) peer.rtc.removeStream(type); 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._view.popTo(3); this._pushStreamsColumn(peer); @@ -690,6 +700,21 @@ export default class Studio { 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