모든 방법은 아래 글을 보고 참고했습니다. step-05 사용
turn 임대서버를 사용했음에도 본테스트는 안됨
내부네트워크에서만 작동함
https://codelabs.developers.google.com/codelabs/webrtc-web/#7
Real time communication with WebRTC | Google Codelabs
Learn how to stream media and data between two browsers. Get to grips with the core APIs and technologies of WebRTC. Capture and manipulate images using getUserMedia, CSS, and the canvas element. Set up a peer connection and exchange data directly between
codelabs.developers.google.com
설치서버
[codetest@servera131 step-05]$ pwd
/home/codetest/base/webrtc-web/step-05
서버 실행
[codetest@servera131 step-05]$ node server_ssl.js
브라우져 접속
https://codetest.coforward.com:8443/
전체소스
vi package.json
{
"name": "webrtc-codelab",
"version": "0.0.1",
"description": "WebRTC codelab",
"dependencies": {
"node-static": "^0.7.10",
"socket.io": "^2.0.4",
"express": "^4.17.1",
"ejs": "^3.1.3",
"nodemon": "^2.0.4",
"peer": "^0.5.3",
"uuid": "^8.3.0"
}
}
$ npm install
vi server_ssl.js
'use strict';
const fs = require('fs');
var os = require('os');
var nodeStatic = require('node-static');
var http = require('http');
var socketIO = require('socket.io');
const https = require('https');
// Certificate 인증서 경로
const privateKey = fs.readFileSync('/etc/httpd/ssl/codetest.coforward.com_2022.key', 'utf8');
const certificate = fs.readFileSync('/etc/httpd/ssl/codetest.coforward.com_2022.crt', 'utf8');
const credentials = {
key: privateKey,
cert: certificate,
};
var fileServer = new(nodeStatic.Server)();
var app = https.createServer(credentials, function(req, res) {
fileServer.serve(req, res);
//res.writeHead(200);
//res.end('hello world\n');
}).listen(8443);
//var io = socketIO.listen(app);
const io = require("socket.io")(app, {
cors: {
origin: '*'
}
});
io.sockets.on('connection', function(socket) {
// convenience function to log server messages on the client
function log() {
var array = ['Message from server:'];
array.push.apply(array, arguments);
socket.emit('log', array);
}
socket.on('message', function(message) {
log('Client said: ', message);
// for a real app, would be room-only (not broadcast)
socket.broadcast.emit('message', message);
});
socket.on('create or join', function(room) {
log('Received request to create or join room ' + room);
var clientsInRoom = io.sockets.adapter.rooms[room];
var numClients = clientsInRoom ? Object.keys(clientsInRoom.sockets).length : 0;
log('Room ' + room + ' now has ' + numClients + ' client(s)');
if (numClients === 0) {
socket.join(room);
log('Client ID ' + socket.id + ' created room ' + room);
socket.emit('created', room, socket.id);
} else if (numClients === 1) {
log('Client ID ' + socket.id + ' joined room ' + room);
io.sockets.in(room).emit('join', room);
socket.join(room);
socket.emit('joined', room, socket.id);
io.sockets.in(room).emit('ready');
} else { // max two clients
socket.emit('full', room);
}
});
socket.on('ipaddr', function() {
var ifaces = os.networkInterfaces();
for (var dev in ifaces) {
ifaces[dev].forEach(function(details) {
if (details.family === 'IPv4' && details.address !== '127.0.0.1') {
socket.emit('ipaddr', details.address);
}
});
}
});
});
vi js/main.js
'use strict';
var isChannelReady = false;
var isInitiator = false;
var isStarted = false;
var localStream;
var pc;
var remoteStream;
var turnReady;
var pcConfig = {
'iceServers': [{
'urls': 'stun:stun.l.google.com:19302'
}]
/*
iceServers: [
{
urls: "stun:relay.metered.ca:80",
},
{
urls: "turn:relay.metered.ca:80",
username: "f75c5c089422654fc7c61437",
credential: "dkLa3Am6b79Sizb9",
},
{
urls: "turn:relay.metered.ca:443",
username: "f75c5c089422654fc7c61437",
credential: "dkLa3Am6b79Sizb9",
},
{
urls: "turn:relay.metered.ca:443?transport=tcp",
username: "f75c5c089422654fc7c61437",
credential: "dkLa3Am6b79Sizb9",
},
],
*/
};
// Set up audio and video regardless of what devices are present.
var sdpConstraints = {
offerToReceiveAudio: true,
offerToReceiveVideo: true
};
/////////////////////////////////////////////
var room = 'foo';
// Could prompt for room name:
// room = prompt('Enter room name:');
var socket = io.connect();
if (room !== '') {
socket.emit('create or join', room);
console.log('Attempted to create or join room', room);
}
socket.on('created', function(room) {
console.log('Created room ' + room);
isInitiator = true;
});
socket.on('full', function(room) {
console.log('Room ' + room + ' is full');
});
socket.on('join', function (room){
console.log('Another peer made a request to join room ' + room);
console.log('This peer is the initiator of room ' + room + '!');
isChannelReady = true;
});
socket.on('joined', function(room) {
console.log('joined: ' + room);
isChannelReady = true;
});
socket.on('log', function(array) {
console.log.apply(console, array);
});
////////////////////////////////////////////////
function sendMessage(message) {
console.log('Client sending message: ', message);
socket.emit('message', message);
}
// This client receives a message
socket.on('message', function(message) {
console.log('Client received message:', message);
if (message === 'got user media') {
maybeStart();
} else if (message.type === 'offer') {
if (!isInitiator && !isStarted) {
maybeStart();
}
pc.setRemoteDescription(new RTCSessionDescription(message));
doAnswer();
} else if (message.type === 'answer' && isStarted) {
pc.setRemoteDescription(new RTCSessionDescription(message));
} else if (message.type === 'candidate' && isStarted) {
var candidate = new RTCIceCandidate({
sdpMLineIndex: message.label,
candidate: message.candidate
});
pc.addIceCandidate(candidate);
} else if (message === 'bye' && isStarted) {
handleRemoteHangup();
}
});
////////////////////////////////////////////////////
var localVideo = document.querySelector('#localVideo');
var remoteVideo = document.querySelector('#remoteVideo');
navigator.mediaDevices.getUserMedia({
audio: false,
video: true
})
.then(gotStream)
.catch(function(e) {
alert('getUserMedia() error: ' + e.name);
});
function gotStream(stream) {
console.log('Adding local stream.');
localStream = stream;
localVideo.srcObject = stream;
sendMessage('got user media');
if (isInitiator) {
maybeStart();
}
}
var constraints = {
video: true
};
console.log('Getting user media with constraints', constraints);
if (location.hostname !== 'localhost') {
console.log('>>>> relay.metered.ca');
requestTurn(
//'https://computeengineondemand.appspot.com/turn?username=41784574&key=4080218913'
'https://relay.metered.ca/?username=f75c5c089422654fc7c61437&credential=dkLa3Am6b79Sizb9'
);
}
function maybeStart() {
console.log('>>>>>>> maybeStart() ', isStarted, localStream, isChannelReady);
if (!isStarted && typeof localStream !== 'undefined' && isChannelReady) {
console.log('>>>>>> creating peer connection');
createPeerConnection();
pc.addStream(localStream);
isStarted = true;
console.log('isInitiator', isInitiator);
if (isInitiator) {
doCall();
}
}
}
window.onbeforeunload = function() {
sendMessage('bye');
};
/////////////////////////////////////////////////////////
function createPeerConnection() {
try {
pc = new RTCPeerConnection(null);
pc.onicecandidate = handleIceCandidate;
pc.onaddstream = handleRemoteStreamAdded;
pc.onremovestream = handleRemoteStreamRemoved;
console.log('Created RTCPeerConnnection');
} catch (e) {
console.log('Failed to create PeerConnection, exception: ' + e.message);
alert('Cannot create RTCPeerConnection object.');
return;
}
}
function handleIceCandidate(event) {
console.log('icecandidate event: ', event);
if (event.candidate) {
sendMessage({
type: 'candidate',
label: event.candidate.sdpMLineIndex,
id: event.candidate.sdpMid,
candidate: event.candidate.candidate
});
} else {
console.log('End of candidates.');
}
}
function handleCreateOfferError(event) {
console.log('createOffer() error: ', event);
}
function doCall() {
console.log('Sending offer to peer');
pc.createOffer(setLocalAndSendMessage, handleCreateOfferError);
}
function doAnswer() {
console.log('Sending answer to peer.');
pc.createAnswer().then(
setLocalAndSendMessage,
onCreateSessionDescriptionError
);
}
function setLocalAndSendMessage(sessionDescription) {
pc.setLocalDescription(sessionDescription);
console.log('setLocalAndSendMessage sending message', sessionDescription);
sendMessage(sessionDescription);
}
function onCreateSessionDescriptionError(error) {
trace('Failed to create session description: ' + error.toString());
}
function requestTurn(turnURL) {
var turnExists = false;
for (var i in pcConfig.iceServers) {
if (pcConfig.iceServers[i].urls.substr(0, 5) === 'turn:') {
turnExists = true;
turnReady = true;
break;
}
}
if (!turnExists) {
console.log('Getting TURN server from ', turnURL);
// No TURN server. Get one from computeengineondemand.appspot.com:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
console.log('>>>>>>:'+xhr.status);
if (xhr.readyState === 4 && xhr.status === 200) {
var turnServer = JSON.parse(xhr.responseText);
console.log('Got TURN server: ', turnServer);
pcConfig.iceServers.push({
'urls': 'turn:' + turnServer.username + '@' + turnServer.turn,
'credential': turnServer.password
});
turnReady = true;
}
};
xhr.open('GET', turnURL, true);
xhr.send();
}
}
function handleRemoteStreamAdded(event) {
console.log('Remote stream added.');
remoteStream = event.stream;
remoteVideo.srcObject = remoteStream;
}
function handleRemoteStreamRemoved(event) {
console.log('Remote stream removed. Event: ', event);
}
function hangup() {
console.log('Hanging up.');
stop();
sendMessage('bye');
}
function handleRemoteHangup() {
console.log('Session terminated.');
stop();
isInitiator = false;
}
function stop() {
isStarted = false;
pc.close();
pc = null;
}
'프로그래밍 > Js' 카테고리의 다른 글
크롬 비활성화된 탭 네트워크(웹소켓) 끊어지는 현상 Intensive Wake Up Throttling (0) | 2023.03.07 |
---|---|
안드로이드 웹뷰와 웹워커 브릿지 (android + webview + webworker bridge example) 샘플 (0) | 2023.02.28 |
방법1 WebRTC Socket.io + Node.js + turn 임대 서버 이용방법 (1차완료) (0) | 2023.02.22 |
webRTC 카메라/오디오 권한 획득 기본 샘플 (0) | 2023.02.21 |
webRTC 이용하여 비디오 채팅 방법 with Node.js + Socket.io (0) | 2023.02.21 |