1
+ 'use strict' ;
2
+
3
+ ( function ( ) {
4
+ const mediaStreamConstraints = {
5
+ video : true ,
6
+ } ;
7
+
8
+ const offerOptions = {
9
+ offerToReceiveVideo : 1 ,
10
+ } ;
11
+
12
+ const localVideo = document . getElementById ( 'localVideo' ) ;
13
+ const remoteVideo = document . getElementById ( 'remoteVideo' ) ;
14
+ const startButton = document . getElementById ( 'startButton' ) ;
15
+ const callButton = document . getElementById ( 'callButton' ) ;
16
+ const hangupButton = document . getElementById ( 'hangupButton' ) ;
17
+
18
+ callButton . disabled = true ;
19
+ hangupButton . disabled = true ;
20
+
21
+ startButton . addEventListener ( 'click' , startAction ) ;
22
+ callButton . addEventListener ( 'click' , callAction ) ;
23
+ hangupButton . addEventListener ( 'click' , hangupAction ) ;
24
+
25
+ let localStream ;
26
+ let remoteStream ;
27
+
28
+ let localPeerConnection ;
29
+ let remotePeerConnection ;
30
+
31
+ function trace ( text ) {
32
+ text = text . trim ( ) ;
33
+ const now = ( window . performance . now ( ) / 1000 ) . toFixed ( 3 ) ;
34
+
35
+ console . log ( now , text ) ;
36
+ }
37
+
38
+ function gotLocalMediaStream ( mediaStream ) {
39
+ localVideo . srcObject = mediaStream ;
40
+ localStream = mediaStream ;
41
+ trace ( 'Received local stream.' ) ;
42
+ callButton . disabled = false ;
43
+ }
44
+
45
+ function gotRemoteMediaStream ( event ) {
46
+ const mediaStream = event . stream ;
47
+ remoteVideo . srcObject = mediaStream ;
48
+ remoteStream = mediaStream ;
49
+ trace ( 'Remote peer connection received remote stream.' ) ;
50
+ }
51
+
52
+ function handleLocalMediaStreamError ( error ) {
53
+ trace ( `navigator.mediaDevices.getUserMedia error: ${ error . toString ( ) } .` ) ;
54
+ }
55
+
56
+ function handleConnection ( event ) {
57
+ const peerConnection = event . target ;
58
+ const iceCandidate = event . candiate ;
59
+
60
+ if ( iceCandidate ) {
61
+ const newIceCandidate = new RTCIceCandidate ( iceCandidate ) ;
62
+ const otherPeer = getOtherPeer ( peerConnection ) ;
63
+
64
+ otherPeer . addIceCandidate ( newIceCandidate )
65
+ . then ( ( ) => handleConnectionSuccess ( peerConnection ) )
66
+ . catch ( error => handleConnectionFailure ( peerConnection , error ) ) ;
67
+
68
+ trace ( `${ getPeerName ( peerConnection ) } ICE candidate:\n${ iceCandidate . candidate } .` ) ;
69
+ }
70
+ }
71
+
72
+ function handleConnectionChange ( event ) {
73
+ const peerConnection = event . target ;
74
+ console . log ( 'ICE state change event: ' , event ) ;
75
+ trace ( `${ getPeerName ( peerConnection ) } ICE state: ${ peerConnection . iceConnectionState } .` ) ;
76
+ }
77
+
78
+ function handleConnectionSuccess ( peerConnection ) {
79
+ trace ( `${ getPeerName ( peerConnection ) } addIceCandidate success.` ) ;
80
+ }
81
+
82
+ function handleConnectionFailure ( peerConnection , error ) {
83
+ trace ( `${ getPeerName ( peerConnection ) } failed to add ICE Candidate:\n${ error . toString ( ) } .` ) ;
84
+ }
85
+
86
+ function createdOffer ( description ) {
87
+ trace ( `Offer from localPeerConnection:\n${ description . sdp } ` ) ;
88
+
89
+ trace ( 'localPeerConnection setLocalDescription start.' ) ;
90
+ localPeerConnection . setLocalDescription ( description )
91
+ . then ( ( ) => setLocalDescriptionSuccess ( localPeerConnection ) )
92
+ . catch ( setSessionDescriptionError ) ;
93
+
94
+ trace ( 'remotePeerConnection setRemoteDescription start.' ) ;
95
+ remotePeerConnection . setRemoteDescription ( description )
96
+ . then ( ( ) => setRemoteDescriptionSuccess ( remotePeerConnection ) )
97
+ . catch ( setSessionDescriptionError ) ;
98
+
99
+ trace ( 'remotePeerConnection createAnswer start.' ) ;
100
+ remotePeerConnection . createAnswer ( )
101
+ . then ( createdAnswer )
102
+ . catch ( setSessionDescriptionError ) ;
103
+ }
104
+
105
+ function createdAnswer ( description ) {
106
+ trace ( `Answer from remotePeerConnection:\n${ description . sdp } .` ) ;
107
+
108
+ trace ( 'remotePeerConnection setLocalDescription start.' ) ;
109
+ remotePeerConnection . setLocalDescription ( description )
110
+ . then ( ( ) => setLocalDescriptionSuccess ( remotePeerConnection ) )
111
+ . catch ( setSessionDescriptionError ) ;
112
+
113
+ trace ( 'localPeerConnection setRemoteDescription start.' ) ;
114
+ localPeerConnection . setRemoteDescription ( description )
115
+ . then ( ( ) => setRemoteDescriptionSuccess ( localPeerConnection ) )
116
+ . catch ( setSessionDescriptionError ) ;
117
+ }
118
+
119
+ function setDescriptionSuccess ( peerConnection , functionName ) {
120
+ const peerName = getPeerName ( peerConnection ) ;
121
+ trace ( `${ peerName } ${ functionName } complete.` ) ;
122
+ }
123
+
124
+ function setLocalDescriptionSuccess ( peerConnection ) {
125
+ setDescriptionSuccess ( peerConnection , 'setLocalDescription' ) ;
126
+ }
127
+
128
+ function setRemoteDescriptionSuccess ( peerConnection ) {
129
+ setDescriptionSuccess ( peerConnection , 'setRemoteDescription' ) ;
130
+ }
131
+
132
+ function setSessionDescriptionError ( error ) {
133
+ trace ( `Failed to create session description: ${ error . toString ( ) } .` ) ;
134
+ }
135
+
136
+ function getOtherPeer ( peerConnection ) {
137
+ return ( peerConnection === localPeerConnection ) ?
138
+ remotePeerConnection : localPeerConnection ;
139
+ }
140
+
141
+ function getPeerName ( peerConnection ) {
142
+ return ( peerConnection === localPeerConnection ) ?
143
+ 'localPeerConnection' : 'remotePeerConnection' ;
144
+ }
145
+
146
+ function startAction ( e ) {
147
+ startButton . disabled = true ;
148
+ navigator . mediaDevices . getUserMedia ( mediaStreamConstraints )
149
+ . then ( gotLocalMediaStream )
150
+ . catch ( handleLocalMediaStreamError ) ;
151
+ trace ( 'Requesting local stream.' ) ;
152
+ }
153
+
154
+ function callAction ( e ) {
155
+ callButton . disabled = true ;
156
+ hangupButton . disabled = false ;
157
+
158
+ trace ( 'Start calling.' ) ;
159
+
160
+ const videoTracks = localStream . getVideoTracks ( ) ;
161
+ const audioTracks = localStream . getAudioTracks ( ) ;
162
+ if ( videoTracks . length > 0 ) {
163
+ trace ( `Using video device: ${ videoTracks [ 0 ] . label } .` ) ;
164
+ }
165
+ if ( audioTracks . length > 0 ) {
166
+ trace ( `Using audio device: ${ audioTracks [ 0 ] . label } .` ) ;
167
+ }
168
+
169
+ const servers = null ;
170
+
171
+ localPeerConnection = new RTCPeerConnection ( servers ) ;
172
+ trace ( 'Created local peer connection object localPeerConnection.' ) ;
173
+
174
+ localPeerConnection . addEventListener ( 'icecandidate' , handleConnection ) ;
175
+ localPeerConnection . addEventListener (
176
+ 'iceconnectionstatechange' , handleConnectionChange
177
+ ) ;
178
+
179
+ remotePeerConnection = new RTCPeerConnection ( servers ) ;
180
+ trace ( 'Created remote peer connection object remotePeerConnection.' ) ;
181
+
182
+ remotePeerConnection . addEventListener ( 'icecandidate' , handleConnection ) ;
183
+ remotePeerConnection . addEventListener (
184
+ 'iceconnectionstatechange' , handleConnectionChange
185
+ ) ;
186
+ remotePeerConnection . addEventListener ( 'addstream' , gotRemoteMediaStream ) ;
187
+
188
+ localPeerConnection . addStream ( localStream ) ;
189
+ trace ( 'Added local stream to localPeerConnection.' ) ;
190
+
191
+ trace ( 'localPeerConnection createOffer start.' ) ;
192
+ localPeerConnection . createOffer ( offerOptions )
193
+ . then ( createdOffer )
194
+ . catch ( setSessionDescriptionError ) ;
195
+ }
196
+
197
+ function hangupAction ( e ) {
198
+ localPeerConnection . close ( ) ;
199
+ localPeerConnection = null ;
200
+
201
+ remotePeerConnection . close ( ) ;
202
+ remotePeerConnection = null ;
203
+
204
+ hangupButton . disabled = true ;
205
+ callButton . disabled = false ;
206
+ trace ( 'Ending call.' ) ;
207
+ }
208
+ } ) ( ) ;
0 commit comments