parent
ac0570b82c
commit
4358d49b48
3 changed files with 75 additions and 3 deletions
|
|
@ -1003,6 +1003,29 @@ function ensurePeerConnection(peerId) {
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pc.oniceconnectionstatechange = async () => {
|
||||||
|
const iceState = pc.iceConnectionState;
|
||||||
|
console.debug(`voice ice state (${peerId}):`, iceState);
|
||||||
|
if (iceState !== "failed" || pc.restartingIce) return;
|
||||||
|
pc.restartingIce = true;
|
||||||
|
try {
|
||||||
|
const offer = await pc.createOffer({ iceRestart: true });
|
||||||
|
await pc.setLocalDescription(offer);
|
||||||
|
if (state.voice.ws && state.voice.ws.readyState === WebSocket.OPEN) {
|
||||||
|
state.voice.ws.send(JSON.stringify({
|
||||||
|
type: "signal",
|
||||||
|
to_user_id: peerId,
|
||||||
|
kind: "offer",
|
||||||
|
data: pc.localDescription,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.warn("ICE restart failed", err);
|
||||||
|
} finally {
|
||||||
|
pc.restartingIce = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
pc.ontrack = (event) => {
|
pc.ontrack = (event) => {
|
||||||
const stream = event.streams[0];
|
const stream = event.streams[0];
|
||||||
if (event.track.kind === "audio") {
|
if (event.track.kind === "audio") {
|
||||||
|
|
@ -1014,7 +1037,20 @@ function ensurePeerConnection(peerId) {
|
||||||
audio.playsInline = true;
|
audio.playsInline = true;
|
||||||
document.body.appendChild(audio);
|
document.body.appendChild(audio);
|
||||||
}
|
}
|
||||||
audio.srcObject = stream;
|
audio.muted = false;
|
||||||
|
audio.volume = 1;
|
||||||
|
audio.srcObject = new MediaStream([event.track]);
|
||||||
|
const tryPlay = () => {
|
||||||
|
const playPromise = audio.play();
|
||||||
|
if (playPromise && typeof playPromise.catch === "function") {
|
||||||
|
playPromise.catch((err) => {
|
||||||
|
console.warn(`remote audio playback blocked for ${peerId}`, err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
audio.onloadedmetadata = tryPlay;
|
||||||
|
audio.oncanplay = tryPlay;
|
||||||
|
tryPlay();
|
||||||
} else if (event.track.kind === "video") {
|
} else if (event.track.kind === "video") {
|
||||||
const peer = state.members.find(m => m.id === peerId) || { display_name: "Unknown" };
|
const peer = state.members.find(m => m.id === peerId) || { display_name: "Unknown" };
|
||||||
renderVideo(peerId, peer.display_name, stream, event.track.id);
|
renderVideo(peerId, peer.display_name, stream, event.track.id);
|
||||||
|
|
|
||||||
|
|
@ -943,6 +943,29 @@ function ensurePeerConnection(peerId) {
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pc.oniceconnectionstatechange = async () => {
|
||||||
|
const iceState = pc.iceConnectionState;
|
||||||
|
console.debug(`voice ice state (${peerId}):`, iceState);
|
||||||
|
if (iceState !== "failed" || pc.restartingIce) return;
|
||||||
|
pc.restartingIce = true;
|
||||||
|
try {
|
||||||
|
const offer = await pc.createOffer({ iceRestart: true });
|
||||||
|
await pc.setLocalDescription(offer);
|
||||||
|
if (state.voice.ws && state.voice.ws.readyState === WebSocket.OPEN) {
|
||||||
|
state.voice.ws.send(JSON.stringify({
|
||||||
|
type: "signal",
|
||||||
|
to_user_id: peerId,
|
||||||
|
kind: "offer",
|
||||||
|
data: pc.localDescription,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.warn("ICE restart failed", err);
|
||||||
|
} finally {
|
||||||
|
pc.restartingIce = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
pc.ontrack = (event) => {
|
pc.ontrack = (event) => {
|
||||||
const stream = event.streams[0];
|
const stream = event.streams[0];
|
||||||
if (event.track.kind === "audio") {
|
if (event.track.kind === "audio") {
|
||||||
|
|
@ -954,7 +977,20 @@ function ensurePeerConnection(peerId) {
|
||||||
audio.playsInline = true;
|
audio.playsInline = true;
|
||||||
document.body.appendChild(audio);
|
document.body.appendChild(audio);
|
||||||
}
|
}
|
||||||
audio.srcObject = stream;
|
audio.muted = false;
|
||||||
|
audio.volume = 1;
|
||||||
|
audio.srcObject = new MediaStream([event.track]);
|
||||||
|
const tryPlay = () => {
|
||||||
|
const playPromise = audio.play();
|
||||||
|
if (playPromise && typeof playPromise.catch === "function") {
|
||||||
|
playPromise.catch((err) => {
|
||||||
|
console.warn(`remote audio playback blocked for ${peerId}`, err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
audio.onloadedmetadata = tryPlay;
|
||||||
|
audio.oncanplay = tryPlay;
|
||||||
|
tryPlay();
|
||||||
} else if (event.track.kind === "video") {
|
} else if (event.track.kind === "video") {
|
||||||
const peer = state.members.find(m => m.id === peerId) || { display_name: "Unknown" };
|
const peer = state.members.find(m => m.id === peerId) || { display_name: "Unknown" };
|
||||||
renderVideo(peerId, peer.display_name, stream, event.track.id);
|
renderVideo(peerId, peer.display_name, stream, event.track.id);
|
||||||
|
|
|
||||||
|
|
@ -265,7 +265,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/static/app.js?v=20260225-voice-dfn-localassets-1" defer></script>
|
<script src="/static/app.js?v=20260225-voice-audiofix-1" defer></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue