상세 컨텐츠

본문 제목

화상채팅 / 실시간화상회의/ 온라인수업 ... webRtc 로 직접 만들어보자 실제 샘플코드 작성하기 (2)

카테고리 없음

by 동해둘리 2020. 9. 6. 10:45

본문

반응형

화상채팅/ 화상회의 샘플코드 작성

 

지난 포스팅에서 설명했듯이 peer to peer 통신을 통해 화상/음성을 주고받을 수 있는 기술인 webRtc를 이용하여 실제 코드를 만들어 보겠습니다. 

 

doolyit.tistory.com/208

 

화상채팅 / 실시간화상회의/ 온라인수업 ... webRtc 로 직접 만들어보자 ZOOM 대체 (1)

화상채팅 / 실시간화상회의 솔루션 코로나 여파로 화상채팅/ 화상회의 솔루션을 이용한 온라인 수업을 실시하는 학교와 기관이 늘어나고 있습니다. 줌(ZOOM) 을 이용하거나 구글미트(Google meet) 등

doolyit.tistory.com

 

 

 

 

접속화면을 위한 HTML 

 

아래 코드를 실행시키면 좌측에는 본인, 우측에는 상대방이 표시됩니다. Call 버튼을 클릭하게 되면 상대방에서 접속요청을 보내게 되고, 요청을 받은 상대방 측에서는 자신의 peer 주소를 보내주어 통신을 하게됩니다.

webRTC

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<html>
  <head>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" type="text/css" href="css/style.css">
  </head>
  <body onload="showMyFace()">
    <video id="yourVideo" autoplay muted playsinline></video>
    <video id="friendsVideo" autoplay playsinline></video>
    <br />
    <button onclick="showFriendsFace()" type="button" class="btn btn-primary btn-lg"><span class="glyphicon glyphicon-facetime-video" aria-hidden="true"></span> Call</button>
    <script src="https://www.gstatic.com/firebasejs/4.9.0/firebase.js"></script>
  </body>
</html>
 
cs

 

 

 

 

 

 

Firebase 실시간 데이터베이스 설정

 

아래의 config 는 Firebase Realtime Database 를 생성한 후에 Firebase 에서 제공하는 세팅값을 입력하는 부분입니다. Firebase 에 접속하여 데이터베이스를 생성하게 되면 얻을 수 있는 설정값입니다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<script language = "javascript">
//Create an account on Firebase, and use the credentials they give you in place of the following
var config = {
  apiKey: "AIeaS7AvL9f2MvHwVcghtVbGWtOk8AGcRmw6-Rqc",
  authDomain: "webrtc-f0d24.firebaseapp.com",
  databaseURL: "https://webrtc-f0d24.firebaseio.com",
  projectId: "webrtc-f0d24",
  storageBucket: "webrtc-f0d24.appspot.com",
  messagingSenderId: "876347981221",
};
 
 
firebase.initializeApp(config);
 
var database = firebase.database().ref();
 
</script>
cs

 

 

 

 

 

 

turn 서버 설정 및 PeerConnection 설정

아래 코드의 var servers 에 세팅된 값은 공개 turn 서버의 주소를 사용한 코드입니다.

https://gist.github.com/sagivo/3a4b2f2c7ac6e1b5267c2f1f59ac6c6b 이 주소에 접속하면 공개서버를 다수 확인할 수 있습니다. RtcPeerConnection 함수를 이용하여 peer  커넥션을 위한 객체를 생성하게 됩니다 

 

 

1
2
3
4
5
6
7
8
9
10
11
<script language = "javascript">
 
var yourVideo = document.getElementById("yourVideo");
var friendsVideo = document.getElementById("friendsVideo");
var yourId = Math.floor(Math.random()*1000000000);
var servers = {"urls": ["turn:13.250.13.83:3478?transport=udp"],"username""YzYNCouZM1mhqhmseWk6","credential""YzYNCouZM1mhqhmseWk6"}
var pc = new RTCPeerConnection(servers);
pc.onicecandidate = (event => event.candidate?sendMessage(yourId, JSON.stringify({'ice'event.candidate})):console.log("Sent All Ice") );
pc.onaddstream = (event => friendsVideo.srcObject = event.stream);
 
</script>
cs

 

 

 

 

 

메시지 전송/수신 부분

sendMessage 와 readmessage 함수는 peer 간에 서로 메시지를 주고 받기 위해 사용하는 함수 입니다. Firebase 연결을 통해 생성한 database 객체는 child_added 이벤트가 발생하면 readMessage()를 호출하게 됩니다. readMessage() 함수에서는 자신이 보낸 메시지인지 상대가 보낸 메시지인지를 구분하여 적절한 처리를 하게됩니다. 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<script language = "javascript">
 
function sendMessage(senderId, data) {
    var msg = database.push({ sender: senderId, message: data });
    msg.remove();
}
 
function readMessage(data) {
    var msg = JSON.parse(data.val().message);
    var sender = data.val().sender;
    if (sender != yourId) {
        if (msg.ice != undefined)
            pc.addIceCandidate(new RTCIceCandidate(msg.ice));
        else if (msg.sdp.type == "offer")
            pc.setRemoteDescription(new RTCSessionDescription(msg.sdp))
              .then(() => pc.createAnswer())
              .then(answer => pc.setLocalDescription(answer))
              .then(() => sendMessage(yourId, JSON.stringify({'sdp': pc.localDescription})));
        else if (msg.sdp.type == "answer")
            pc.setRemoteDescription(new RTCSessionDescription(msg.sdp));
    }
};
 
database.on('child_added', readMessage);
</script>
cs

 

 

 

 

화면 로드시 showMyFace() 가 호출되어 getUserMedia()함수를 통해 자신의 영상정보를 읽어와서 뿌려주게 됩니다. Call 버튼을 클릭하게 되면 show FriendsFace()가 호출되어 sendMessage()함수를 통해 상대방에게 메시지를 보내게 됩니다. 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
<script language = "javascript">
database.on('child_added', readMessage);
function showMyFace() {
  navigator.mediaDevices.getUserMedia({audio:true, video:true})
    .then(stream => yourVideo.srcObject = stream)
    .then(stream => pc.addStream(stream));
}
function showFriendsFace() {
  pc.createOffer()
    .then(offer => pc.setLocalDescription(offer) )
    .then(() => sendMessage(yourId, JSON.stringify({'sdp': pc.localDescription})) );
}    
</script>
cs

 

 

 

 

 

 

 

전체 코드 보기

 

코드가 그리 길지 않아서 css 와 javascript 코드를 모두 한페이지에 넣어두었습니다. 코드 중에서 config 값은 자신의 Firebase config 값으로 변경해야 동작하게 됩니다. 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<html>
  <head>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" type="text/css" href="css/style.css">
    <meta name="apple-mobile-web-app-capable" content="yes">
  </head>
  <body onload="showMyFace()">
    <style>
      video {
        background-color: #ddd;
        border-radius: 7px;
        margin: 10px 0px 0px 10px;
        width: 320px;
        height: 240px;
      }
      button {
        margin: 5px 0px 0px 10px !important;
        width: 654px;
      }      
    </style>
    <video id="yourVideo" autoplay muted playsinline></video>
    <video id="friendsVideo" autoplay muted playsinline></video>
    <br />
    <button onclick="showFriendsFace()" type="button" class="btn btn-primary btn-lg"><span class="glyphicon glyphicon-facetime-video" aria-hidden="true"></span> Call</button>
    <script src="https://www.gstatic.com/firebasejs/4.9.0/firebase.js"></script>
  </body>
 
<script language = "javascript">
//Create an account on Firebase, and use the credentials they give you in place of the following
var config = {
  apiKey: "AIeaS7AvL9f2MvHwVcghtVbGWtOk8AGcRmw6-Rqc",
  authDomain: "webrtc-f0d24.firebaseapp.com",
  databaseURL: "https://webrtc-f0d24.firebaseio.com",
  projectId: "webrtc-f0d24",
  storageBucket: "webrtc-f0d24.appspot.com",
  messagingSenderId: "876347981221",
};
 
 
firebase.initializeApp(config);
 
var database = firebase.database().ref();
var yourVideo = document.getElementById("yourVideo");
var friendsVideo = document.getElementById("friendsVideo");
var yourId = Math.floor(Math.random()*1000000000);
//Create an account on Viagenie (http://numb.viagenie.ca/), and replace {'urls': 'turn:numb.viagenie.ca','credential': 'websitebeaver','username': 'websitebeaver@email.com'} with the information from your account
 
 
//var servers = {'iceServers': [{'urls': 'stun:stun.services.mozilla.com'}, {'urls': 'stun:stun.l.google.com:19302'}, {'urls': 'turn:numb.viagenie.ca','credential': 'beaver','username': 'webrtc.websitebeaver@gmail.com'}]};
//var servers = {'iceServers': [{'urls': 'turn:13.250.13.83:3478?transport=udp','YzYNCouZM1mhqhmseWk6': 'beaver','YzYNCouZM1mhqhmseWk6': 'webrtc.websitebeaver@gmail.com'}]};
 
// 아래 서버정보는 https://gist.github.com/sagivo/3a4b2f2c7ac6e1b5267c2f1f59ac6c6b  에서 참고했음
var servers = {"urls": ["turn:13.250.13.83:3478?transport=udp"],"username""YzYNCouZM1mhqhmseWk6","credential""YzYNCouZM1mhqhmseWk6"}
var pc = new RTCPeerConnection(servers);
pc.onicecandidate = (event => event.candidate?sendMessage(yourId, JSON.stringify({'ice'event.candidate})):console.log("Sent All Ice") );
pc.onaddstream = (event => friendsVideo.srcObject = event.stream);
 
function sendMessage(senderId, data) {
    var msg = database.push({ sender: senderId, message: data });
    msg.remove();
}
 
function readMessage(data) {
    var msg = JSON.parse(data.val().message);
    var sender = data.val().sender;
    if (sender != yourId) {
        if (msg.ice != undefined)
            pc.addIceCandidate(new RTCIceCandidate(msg.ice));
        else if (msg.sdp.type == "offer")
            pc.setRemoteDescription(new RTCSessionDescription(msg.sdp))
              .then(() => pc.createAnswer())
              .then(answer => pc.setLocalDescription(answer))
              .then(() => sendMessage(yourId, JSON.stringify({'sdp': pc.localDescription})));
        else if (msg.sdp.type == "answer")
            pc.setRemoteDescription(new RTCSessionDescription(msg.sdp));
    }
};
 
database.on('child_added', readMessage);
 
function showMyFace() {
  navigator.mediaDevices.getUserMedia({audio:true, video:true})
    .then(stream => yourVideo.srcObject = stream)
    .then(stream => pc.addStream(stream));
}
 
function showFriendsFace() {
  pc.createOffer()
    .then(offer => pc.setLocalDescription(offer) )
    .then(() => sendMessage(yourId, JSON.stringify({'sdp': pc.localDescription})) );
}    
  </script>
</html>
 
cs

 

 

 

 

참고 사이트 

 

websitebeaver.com/insanely-simple-webrtc-video-chat-using-firebase-with-codepen-demo#demo

 

Insanely Simple WebRTC Video Chat Using Firebase (With Codepen Demo)

In this tutorial, you’ll learn how to build a simple video chat using WebRTC. You can view the demo above to see the video chat in action. Just replace the Firebase credentials in the CodePen, open this web page on another computer, and press call on eit

websitebeaver.com

 

반응형

댓글 영역