
WebRTC рдПрдХ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд╕рдордп рдСрдбрд┐рдпреЛ / рд╡реАрдбрд┐рдпреЛ рд╕рдВрдЪрд╛рд░ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ (

рдФрд░

)ред
рдЗрд╕ рд╡рд┐рд╖рдп рдореЗрдВ, рдореИрдВ рдЖрдкрдХреЛ рдмрддрд╛рдКрдВрдЧрд╛ рдХрд┐ рд╕рдмрд╕реЗ рд╕рд░рд▓ рд╡реЗрдмрдЖрд░рдЯреАрд╕реА рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдХреИрд╕реЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рдПред
1. getUserMedia - рдореАрдбрд┐рдпрд╛ рдЙрдкрдХрд░рдгреЛрдВ (рдорд╛рдЗрдХреНрд░реЛрдлрд╝реЛрди / рд╡реЗрдмрдХреИрдо) рддрдХ рдкрд╣реБрдВрдЪ
рдХреБрдЫ рднреА рдЬрдЯрд┐рд▓ рдирд╣реАрдВ рд╣реИ, рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЛрдб рдХреА 10 рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рдЖрдк рдмреНрд░рд╛рдЙрдЬрд╝рд░ (
рдбреЗрдореЛ ) рдореЗрдВ рдЦреБрдж рдХреЛ рджреЗрдЦ рдФрд░ рд╕реБрди рд╕рдХрддреЗ рд╣реИрдВред
Index.html рдмрдирд╛рдПрдВ:
<video autoplay></video> <script> navigator.getUserMedia = navigator.getUserMedia || navigator.mozGetUserMedia || navigator.webkitGetUserMedia; navigator.getUserMedia({ audio: true, video: true }, gotStream, streamError); function gotStream(stream) { document.querySelector('video').src = URL.createObjectURL(stream); } function streamError(error) { console.log(error); } </script>
рдЖрдк рд╡реАрдбрд┐рдпреЛ рддрддреНрд╡ рдкрд░
css3 рдлрд╝рд┐рд▓реНрдЯрд░ рд▓рд╛рдЧреВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
рдпрд╣рд╛рдВ рдпрд╣ рдирд┐рд░рд╛рд╢рд╛рдЬрдирдХ рд╣реИ рдХрд┐ WebRTC рд╡рд┐рдХрд╛рд╕ рдХреЗ рдЗрд╕ рдЪрд░рдг рдореЗрдВ рдореИрдВ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдХреЛ рдпрд╣ рдирд╣реАрдВ рдмрддрд╛ рд╕рдХрддрд╛ рдХрд┐ "рдореБрдЭреЗ рдЗрд╕ рд╕рд╛рдЗрдЯ рдкрд░ рднрд░реЛрд╕рд╛ рд╣реИ, рд╣рдореЗрд╢рд╛ рдЗрд╕реЗ рдЕрдкрдиреЗ рдХреИрдорд░рд╛ рдФрд░ рдорд╛рдЗрдХреНрд░реЛрдлрд╝реЛрди рддрдХ рдкрд╣реБрдВрдЪ рджреЗрдВ" рдФрд░ рдЖрдкрдХреЛ рдкреНрд░рддреНрдпреЗрдХ рдкреГрд╖реНрда рдХреЗ рдЦреБрд▓рдиреЗ / рдЕрдкрдбреЗрдЯ рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж рдЕрдиреБрдорддрд┐ рджреЗрдиреЗ рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред
рдЦреИрд░, рдпрд╣ рдпрд╛рдж рд░рдЦрдирд╛ рдЕрддрд┐рд╢реНрдпреЛрдХреНрддрд┐рдкреВрд░реНрдг рдирд╣реАрдВ рд╣реИ рдХрд┐ рдпрджрд┐ рдЖрдкрдиреЗ рдПрдХ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ рдХреИрдорд░реЗ рдХреЛ рдПрдХреНрд╕реЗрд╕ рджрд┐рдпрд╛ рд╣реИ, рддреЛ рджреВрд╕рд░рд╛ рдЬрдм рдЖрдк рдПрдХреНрд╕реЗрд╕ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░реЗрдВрдЧреЗ, рддреЛ PERMISSION_DENIED рдкреНрд░рд╛рдкреНрдд рд╣реЛрдЧрд╛ред
2. рд╕рд┐рдЧреНрдирд▓рд┐рдВрдЧ рд╕рд░реНрд╡рд░
рдпрд╣рд╛рдБ рдореИрдВ "webrtc рдХреА рд╢реБрд░реБрдЖрдд рдХрд░ рд░рд╣рд╛ рд╣реВрдБ" рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХреЗ рдЕрдзрд┐рдХрд╛рдВрд╢ рдХреЛ рддреЛрдбрд╝ рд░рд╣рд╛ рд╣реВрдБ рдХреНрдпреЛрдВрдХрд┐ рд╡реЗ рджреВрд╕рд░реЗ рдЪрд░рдг рдореЗрдВ рдПрдХ рдХреНрд▓рд╛рдЗрдВрдЯ рдкрд░ webRTC рдХреА рдХреНрд╖рдорддрд╛рдУрдВ рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддреЗ рд╣реИрдВ, рдЬреЛ рд╡реНрдпрдХреНрддрд┐рдЧрдд рд░реВрдк рд╕реЗ рдореЗрд░реЗ рд╕реНрдкрд╖реНрдЯреАрдХрд░рдг рдореЗрдВ рднреНрд░рдо рдкреИрджрд╛ рдХрд░рддрд╛ рд╣реИред
рд╕рд┐рдЧреНрдирд▓ рд╕рд░реНрд╡рд░ WebRTC рдлреЛрдХрд▓ рдмрд┐рдВрджреБ рд╣реИ рдЬреЛ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЗ рдмреАрдЪ рд╕рдВрдЪрд╛рд░, рдХрдиреЗрдХреНрд╢рди рдХреЛ рдмрдВрдж рдХрд░рдиреЗ рдФрд░ рдХрдиреЗрдХреНрд╢рди рдФрд░ рддреНрд░реБрдЯрд┐ рд░рд┐рдкреЛрд░реНрдЯрд┐рдВрдЧ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред
рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ рд╕рд┐рдЧреНрдирд▓ рд╕рд░реНрд╡рд░ Node.js + socket.io + рдиреЛрдб-рд╕реНрдЯреИрдЯрд┐рдХ рд╣реИ, рдпрд╣ рдкреЛрд░реНрдЯ 1234 рдкрд░ рд╕реБрдиреЗрдЧрд╛ред
рд╕рд╛рде рд╣реА, рдиреЛрдб-рд╕реНрдЯреЗрдЯрд┐рдХ index.html рджреЗ рд╕рдХрддрд╛ рд╣реИ, рдЬреЛ рд╣рдорд╛рд░реЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдпрдерд╛рд╕рдВрднрд╡ рд╕рд░рд▓ рдмрдирд╛ рджреЗрдЧрд╛ред
рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ, рдЖрд╡рд╢реНрдпрдХ рд╕реНрдерд╛рдкрд┐рдд рдХрд░реЗрдВ:
npm install socket.io npm install node-static
Server.js рдХреЛ рдПрдкреНрд▓реАрдХреЗрд╢рди рдлреЛрд▓реНрдбрд░ рдореЗрдВ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░реЗрдВред рдореИрдВ рд╕рд░реНрд╡рд░ рднрд╛рдЧ рдХреЛ рдЕрд▓рдЧ рдирд╣реАрдВ рдХрд░реВрдВрдЧрд╛, рдпрд╣ рд╕рдордЭрдиреЗ рдореЗрдВ рдХрд╛рдлреА рд╕рд░рд▓ рд╣реИ, рдФрд░ рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдпрд╣ рд╡реЗрдмрдЖрд░рдЯреАрд╕реА рдХрд╛ рдкреНрд░рддреНрдпрдХреНрд╖ рд╣рд┐рд╕реНрд╕рд╛ рдирд╣реАрдВ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдмрд╕ рд╕рд░реНрд╡рд░ рд╢реБрд░реВ рдХрд░реЗрдВ:
node server.js
3. рд╡реЗрдмрдЖрд░рдЯреАрд╕реА
рдЕрдм рд╣рдо рд╕реАрдзреЗ WebRTC рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рд╣реИрдВред рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдХрд╛рдо рдХрд░ рд░рд╣реЗ
index.html рдХреЛ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░реЗрдВ, рдлрд┐рд░ рдореИрдВ рдЗрд╕реЗ рдЯреБрдХрдбрд╝реЛрдВ рдореЗрдВ рдЕрд▓рдЧ рдХрд░ рджреВрдВрдЧрд╛ред
3.0ред рдорд╛рдирдХреЛрдВ рдХреЛ рдЕрднреА рддрдХ рдирд╣реАрдВ рдЕрдкрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЕрдм рд╣рдо рд╡рд┐рднрд┐рдиреНрди рдмреНрд░рд╛рдЙрдЬрд╝рд░реЛрдВ рдХреЗ рд▓рд┐рдП рдЙрдкрд╕рд░реНрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдордЬрдмреВрд░ рд╣реИрдВ:
var PeerConnection = window.mozRTCPeerConnection || window.webkitRTCPeerConnection; var IceCandidate = window.mozRTCIceCandidate || window.RTCIceCandidate; var SessionDescription = window.mozRTCSessionDescription || window.RTCSessionDescription; navigator.getUserMedia = navigator.getUserMedia || navigator.mozGetUserMedia || navigator.webkitGetUserMedia;
3.1ред getUserMedia
navigator.getUserMedia( { audio: true, video: true }, gotStream, function(error) { console.log(error) } ); function gotStream(stream) { document.getElementById("callButton").style.display = 'inline-block'; document.getElementById("localVideo").src = URL.createObjectURL(stream); pc = new PeerConnection(null); pc.addStream(stream); pc.onicecandidate = gotIceCandidate; pc.onaddstream = gotRemoteStream; }
рд╣рдордиреЗ рдкрд╣рд▓реЗ рд╣реА рдкреЛрд╕реНрдЯ рдХреЗ рдЖрд░рдВрдн рдореЗрдВ рдЗрд╕ рд╣рд┐рд╕реНрд╕реЗ рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд┐рдпрд╛, рд╕рд┐рд╡рд╛рдп рдЗрд╕рдХреЗ рдХрд┐ рдЧреЗрдЯрд╕реНрдЯреНрд░реАрдо рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ рд╣рдо рдПрдХ PeerConnection рдмрдирд╛рддреЗ рд╣реИрдВ рдФрд░ рджреЛ рдИрд╡реЗрдВрдЯ рд╣реИрдВрдбрд▓рд░ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ:
onicecandidate
рд╣рдореЗрдВ рдЬрдирд░реЗрдЯ рдХрд┐рдпрд╛ рдЧрдпрд╛ ICE рдХреИрдВрдбрд┐рдбреЗрдЯ рджреЗрддрд╛ рд╣реИ, рдЬрд┐рд╕реЗ рд╣рдо рд╕рд┐рдЧреНрдирд▓ рд╕рд░реНрд╡рд░ рдХреЛ рдкрд╛рд╕ рдХрд░реЗрдВрдЧреЗ, рдЬреЛ рдмрджрд▓реЗ рдореЗрдВ рдЙрдиреНрд╣реЗрдВ onicecandidate
рдХреЛ рдкрд╛рд╕ рдХрд░реЗрдЧрд╛- рдЬрдм рд╣рдо рд╡рд╛рд░реНрддрд╛рдХрд╛рд░ рдХрд╛ рдореАрдбрд┐рдпрд╛ рд╕реНрдЯреНрд░реАрдо рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВ, рддреЛ
onaddstream
рдХреЛ onaddstream
рдЬрд╛рдПрдЧрд╛
3.2ред рдХреЙрд▓ рдСрдлрд░
рдХреЙрд▓ рдСрдлрд░ рдПрдХ WebRTC рд╕рддреНрд░ рдХрд╛ рдЖрд░рдВрдн рд╣реИред рдХреЙрд▓ рдСрдлрд╝рд░ рдФрд░ рдХреЙрд▓ рдЙрддреНрддрд░ (рдЕрдЧрд▓рд╛ рдЪрд░рдг)
рдПрд╕рдбреАрдкреА (рд╕рддреНрд░ рд╡рд┐рд╡рд░рдг рдкреНрд░реЛрдЯреЛрдХреЙрд▓) рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рд╣реИрдВ рдФрд░ рдЧреНрд░рд╛рд╣рдХреЛрдВ рдХреА рдореАрдбрд┐рдпрд╛ рдзрд╛рд░рд╛рдУрдВ рдХреЗ рдкреНрд░рд╛рд░рдВрдн рдХреЗ рдорд╛рдкрджрдВрдбреЛрдВ (рд░рд┐рдЬрд╝реЙрд▓реНрдпреВрд╢рди, рдХреЛрдбреЗрдХ, рдЖрджрд┐) рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
рдорд╣рддреНрд╡рдкреВрд░реНрдг: рдЧреНрд░рд╛рд╣рдХреЛрдВ рдХреЛ рдХреЙрд▓ рдСрдлрд╝рд░ рднреЗрдЬрдиреЗ рдХреЗ рдкрд╣рд▓реЗ рдореАрдбрд┐рдпрд╛ рдЙрдкрдХрд░рдгреЛрдВ рддрдХ рдкрд╣реБрдВрдЪ рдкреНрд░рджрд╛рди рдХрд░рдиреА рдЪрд╛рд╣рд┐рдПред
function createOffer() { pc.createOffer( gotLocalDescription, function(error) { console.log(error) }, { 'mandatory': { 'OfferToReceiveAudio': true, 'OfferToReceiveVideo': true } } ); }
3.3ред рдХреЙрд▓ рдЖрдВрд╕рд░
рдХреЙрд▓ рдкреНрд░рд╕реНрддрд╛рд╡ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рддреБрд░рдВрдд рдмрд╛рдж рдЗрдВрдЯрд░рд▓реЙрдХрд░ рджреНрд╡рд╛рд░рд╛ рдХреЙрд▓ рдЙрддреНрддрд░ рднреЗрдЬрд╛ рдЬрд╛рддрд╛ рд╣реИред рдореИрдВ рдзреНрдпрд╛рди рджреЗрддрд╛ рд╣реВрдВ рдХрд┐
createOffer()
рдФрд░
createAnswer()
рдХрд╛ рдХреЙрд▓рдмреИрдХ рдлрд╝рдВрдХреНрд╢рди рдПрдХ рд╣реА рд╣реИ - gotLocalDescription, рдЕрд░реНрдерд╛рддреНред рдПрдХ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЗ рд▓рд┐рдП
createOffer()
рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд╕рд╛рде рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рдерд╛, рджреВрд╕рд░реЗ рдХреЗ рд▓рд┐рдП
createAnswer()
рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд╕рд╛рдеред
function createAnswer() { pc.createAnswer( gotLocalDescription, function(error) { console.log(error) }, { 'mandatory': { 'OfferToReceiveAudio': true, 'OfferToReceiveVideo': true } } ); }
3.4ред рдЖрдИрд╕реАрдИ рдЙрдореНрдореАрджрд╡рд╛рд░
ICE (рдЗрдВрдЯрд░рдПрдХреНрдЯрд┐рд╡ рдХрдиреЗрдХреНрдЯрд┐рд╡рд┐рдЯреА рдЗрд╕реНрдЯреИрдмреНрд▓рд┐рд╢рдореЗрдВрдЯ) рдХреИрдВрдбрд┐рдбреЗрдЯ рдЧреНрд░рд╛рд╣рдХреЛрдВ рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдХрд╛ рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИ, рдХреНрд▓рд╛рдЗрдВрдЯреНрд╕ рдХреЗ рдмреАрдЪ рдХрд╛ рд░рд╛рд╕реНрддрд╛ рддрдп рдХрд░рддрд╛ рд╣реИ рдЬрд┐рд╕рдХреЗ рд╕рд╛рде рдореАрдбрд┐рдпрд╛ рд╕реНрдЯреНрд░реАрдо рдкреНрд░рд╕рд╛рд░рд┐рдд рд╣реЛрдВрдЧреЗред рд╣рдо рд╕рд┐рдЧреНрдирд▓ рд╕рд░реНрд╡рд░ рдкрд░ рдЙрддреНрдкрдиреНрди ICE рдХреИрдВрдбрд┐рдбреЗрдЯ рдХреЛ рдЕрдЧрд▓реЗ рдЪрд░рдг рдореЗрдВ рд╕рд┐рдЧреНрдирд▓ рд╕рд░реНрд╡рд░ рд╕реЗ рд╕рдВрджреЗрд╢реЛрдВ рдХреЗ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХрд╛ рд╡рд┐рд╡рд░рдг рднреА рднреЗрдЬрддреЗ рд╣реИрдВред
function gotIceCandidate(event){ if (event.candidate) { sendMessage({ type: 'candidate', label: event.candidate.sdpMLineIndex, id: event.candidate.sdpMid, candidate: event.candidate.candidate }); } }
3.5ред рд╕рд┐рдЧреНрдирд▓ рд╕рд░реНрд╡рд░ рд╕реЗ рд╕рдВрджреЗрд╢ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдирд╛
var socket = io.connect('', {port: 1234}); socket.on('message', function (message){ if (message.type === 'offer') { pc.setRemoteDescription(new SessionDescription(message)); createAnswer(); } else if (message.type === 'answer') { pc.setRemoteDescription(new SessionDescription(message)); } else if (message.type === 'candidate') { var candidate = new IceCandidate({sdpMLineIndex: message.label, candidate: message.candidate}); pc.addIceCandidate(candidate); } });
рдХреЛрдб рд╕рд░рд▓ рд╣реИ, рд▓реЗрдХрд┐рди рдореИрдВ рд╕рдордЭрд╛рдКрдВрдЧрд╛:
- рдЬреИрд╕реЗ рд╣реА рд╣рдореЗрдВ Call Offer рдЖрдпрд╛, createAnswer рдХреЛ рдХреЙрд▓ рдХрд░реЗрдВ
- рдХреЙрд▓ рдкреНрд░рд╕реНрддрд╛рд╡ рдФрд░ рдХреЙрд▓ рдЙрддреНрддрд░ рджреЛрдиреЛрдВ рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╕рдордп, рдкреНрд░рд╛рдкреНрдд
setRemoteDescription
рд╕рд╛рде setRemoteDescription
рдХреЛ рдХреЙрд▓ рдХрд░реЗрдВ - ICE рдХреИрдВрдбрд┐рдбреЗрдЯ рдХреЗ рдкреНрд░рд╛рдкреНрдд рд╣реЛрдиреЗ рдкрд░, AddIceCandidate рдкрд░ рдХреЙрд▓ рдХрд░реЗрдВ
3.6ред gotRemoteStream
рдпрджрд┐ рд╕рдм рдХреБрдЫ рдареАрдХ рд░рд╣рд╛, рддреЛ рдЪрд░рдг 3.1 рд╕реЗ
onaddstream
рд╣реИрдВрдбрд▓рд░ рдХреЛ рдмреБрд▓рд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдЬрд┐рд╕рдореЗрдВ рд╡рд╛рд░реНрддрд╛рдХрд╛рд░ рд╕реЗ рдореАрдбрд┐рдпрд╛ рд╕реНрдЯреНрд░реАрдо рд╣реЛрдЧреАред
function gotRemoteStream(event){ document.getElementById("remoteVideo").src = URL.createObjectURL(event.stream); }
рдореИрдВ рдЖрдкрдХреЛ рдпрд╛рдж рджрд┐рд▓рд╛рддрд╛ рд╣реВрдВ рдХрд┐ рдЖрд╡реЗрджрди рдХрд╛ рд╕рдВрдкреВрд░реНрдг рд╕реНрд░реЛрдд рдХреЛрдб
рдпрд╣рд╛рдВ рд▓рд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛
рд╣реИ ред
рд╕рдВрджрд░реНрдн: