<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>WebRTC Receiver</title>
<script src="https://js.pusher.com/7.0/pusher.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/laravel-echo/dist/echo.iife.min.js"></script>
</head>
<body>
<video id="remoteVideo" playsinline autoplay></video>
<script>
const remoteVideo = document.getElementById('remoteVideo');
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'ключ',
cluster: 'eu',
encrypted: true
});
const channel = window.Echo.channel('webrtc-channel');
let pc;
let pendingCandidates = [];
channel.listen('.webrtc-signal', async event => {
if (event.type === 'offer') {
pc = createPeerConnection();
const remoteDesc = new RTCSessionDescription(event.data);
await pc.setRemoteDescription(remoteDesc);
const answer = await pc.createAnswer();
await pc.setLocalDescription(answer);
sendSignal('answer', pc.localDescription);
// Обработка всех отложенных ICE кандидатов
pendingCandidates.forEach(async candidate => {
await pc.addIceCandidate(candidate);
});
pendingCandidates = [];
} else if (event.type === 'candidate') {
const candidate = new RTCIceCandidate(event.data);
if (pc && pc.remoteDescription) {
await pc.addIceCandidate(candidate);
} else {
pendingCandidates.push(candidate);
}
}
});
function createPeerConnection() {
const pc = new RTCPeerConnection({
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' }
]
});
pc.onicecandidate = event => {
if (event.candidate) {
sendSignal('candidate', event.candidate);
}
};
pc.ontrack = event => {
remoteVideo.srcObject = event.streams[0];
};
return pc;
}
async function sendSignal(type, data) {
// Добавление новой строки к SDP
if (data.sdp) {
data.sdp += '\n';
}
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
const response = await fetch('/send-signal', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': csrfToken
},
body: JSON.stringify({ type, data })
});
const result = await response.json();
console.log(result);
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>WebRTC Sender</title>
<script src="https://js.pusher.com/7.0/pusher.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/laravel-echo/dist/echo.iife.min.js"></script>
</head>
<body>
<video id="localVideo" playsinline autoplay muted></video>
<button id="startButton">Start Stream</button>
<button id="hangupButton" disabled>Hang Up</button>
<script>
const startButton = document.getElementById('startButton');
const hangupButton = document.getElementById('hangupButton');
const localVideo = document.getElementById('localVideo');
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'ключ',
cluster: 'eu',
encrypted: true
});
const channel = window.Echo.channel('webrtc-channel');
let localStream;
let pc;
let pendingCandidates = [];
startButton.onclick = async () => {
localStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
localVideo.srcObject = localStream;
pc = createPeerConnection();
localStream.getTracks().forEach(track => pc.addTrack(track, localStream));
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
sendSignal('offer', pc.localDescription);
startButton.disabled = true;
hangupButton.disabled = false;
};
hangupButton.onclick = () => {
pc.close();
pc = null;
localStream.getTracks().forEach(track => track.stop());
localVideo.srcObject = null;
startButton.disabled = false;
hangupButton.disabled = true;
};
channel.listen('.webrtc-signal', async event => {
if (event.type === 'answer') {
const remoteDesc = new RTCSessionDescription(event.data);
await pc.setRemoteDescription(remoteDesc);
// Обработка всех отложенных ICE кандидатов
pendingCandidates.forEach(async candidate => {
await pc.addIceCandidate(candidate);
});
pendingCandidates = [];
} else if (event.type === 'candidate') {
const candidate = new RTCIceCandidate(event.data);
if (pc.remoteDescription) {
await pc.addIceCandidate(candidate);
} else {
pendingCandidates.push(candidate);
}
}
});
function createPeerConnection() {
const pc = new RTCPeerConnection({
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' }
]
});
pc.onicecandidate = event => {
if (event.candidate) {
sendSignal('candidate', event.candidate);
}
};
return pc;
}
async function sendSignal(type, data) {
// Добавление новой строки к SDP
if (data.sdp) {
data.sdp += '\n';
}
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
const response = await fetch('/send-signal', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': csrfToken
},
body: JSON.stringify({ type, data })
});
const result = await response.json();
console.log(result);
}
</script>
</body>
</html>