diff --git a/resources/js/candidate-room.js b/resources/js/candidate-room.js index 6a89667..39e93d5 100644 --- a/resources/js/candidate-room.js +++ b/resources/js/candidate-room.js @@ -602,14 +602,18 @@ export function getCandidatePeerId() { : ('cand_' + interviewId); } -export async function initCandidatePeer() { +export async function initCandidatePeer(force = false) { const interviewId = document.body.dataset.interviewId; const candName = document.body.dataset.candidateName || 'Candidate'; if (!interviewId || typeof window.Peer === 'undefined') return; + if (!force && candidatePeerInstance && !candidatePeerInstance.destroyed && candidatePeerInstance.open) { + return candidatePeerInstance; + } + const iceServers = await initMeteredIceServers(); const peerId = getCandidatePeerId(); - if (candidatePeerInstance) { + if (candidatePeerInstance && !candidatePeerInstance.destroyed) { try { candidatePeerInstance.destroy(); } catch(e) {} } @@ -750,7 +754,18 @@ export function sendCandidatePeerHeartbeat(action = 'heartbeat') { const isMicOn = isTrueVal(p.mic_on); const isCamOn = isTrueVal(p.cam_on); - addOrUpdateCandidateInterviewerTile(p.peer_id, existingStream, nameLabel, isMicOn, isCamOn); + if (!existingStream && candidateLocalStream && candidatePeerInstance && candidatePeerInstance.open && !p.peer_id.startsWith('cand_')) { + try { + const outCall = candidatePeerInstance.call(p.peer_id, candidateLocalStream); + if (outCall) { + outCall.on('stream', remoteStream => { + addOrUpdateCandidateInterviewerTile(p.peer_id, remoteStream, nameLabel, isMicOn, isCamOn); + }); + } + } catch(e) {} + } else { + addOrUpdateCandidateInterviewerTile(p.peer_id, existingStream, nameLabel, isMicOn, isCamOn); + } } }); } diff --git a/resources/js/interview-call.js b/resources/js/interview-call.js index 933d490..c16b00b 100644 --- a/resources/js/interview-call.js +++ b/resources/js/interview-call.js @@ -781,7 +781,20 @@ export function pollReviewData() { const isMicOn = isTrueVal(p.mic_on); const isCamOn = isTrueVal(p.cam_on); - if (p.peer_id.startsWith('interviewer_')) { + const isCandPeer = p.role === 'candidate' || (p.peer_id && (p.peer_id === candPeerId || (p.peer_id.startsWith('cand_') && !p.peer_id.startsWith('cand_screen_')))); + if (isCandPeer) { + if (interviewerLocalStream && interviewerPeer && interviewerPeer.open && !candidateStreamConnected) { + try { + const outCall = interviewerPeer.call(p.peer_id, interviewerLocalStream); + if (outCall) { + outCall.on('stream', remoteStream => { + if (candVid) safePlayMediaStream(candVid, remoteStream); + updateCandidateStatusIcons(isMicOn, isCamOn, true); + }); + } + } catch(e) {} + } + } else if (p.peer_id.startsWith('interviewer_')) { if (interviewerLocalStream && interviewerPeer && interviewerPeer.open) { if (!panelistMeshTiles.has(p.peer_id)) { try { @@ -1321,6 +1334,17 @@ export function safePlayMediaStream(videoElem, stream, isSelf = false) { videoElem.onloadedmetadata = () => { videoElem.play().catch(() => {}); }; + if (!isSelf) { + videoElem.muted = true; + videoElem.play().catch(() => {}); + const unmuteHandler = () => { + videoElem.muted = false; + videoElem.play().catch(() => {}); + }; + window.addEventListener('click', unmuteHandler, { once: true }); + window.addEventListener('keydown', unmuteHandler, { once: true }); + window.addEventListener('touchstart', unmuteHandler, { once: true }); + } } }); }