@@ -8,6 +8,8 @@ const master = {
8
8
localStream : null ,
9
9
remoteStreams : [ ] ,
10
10
peerConnectionStatsInterval : null ,
11
+ kinesisVideoSignalingChannelsClient : null ,
12
+ pendingIceCandidateByClientId : { } ,
11
13
} ;
12
14
13
15
async function startMaster ( localView , remoteView , formValues , onStatsReport , onRemoteDataMessage ) {
@@ -63,48 +65,24 @@ async function startMaster(localView, remoteView, formValues, onStatsReport, onR
63
65
systemClockOffset : kinesisVideoClient . config . systemClockOffset ,
64
66
} ) ;
65
67
66
- // Get ICE server configuration
67
- const kinesisVideoSignalingChannelsClient = new AWS . KinesisVideoSignalingChannels ( {
68
+ // Create client for calling getIceServerConfig
69
+ master . kinesisVideoSignalingChannelsClient = new AWS . KinesisVideoSignalingChannels ( {
68
70
region : formValues . region ,
69
71
accessKeyId : formValues . accessKeyId ,
70
72
secretAccessKey : formValues . secretAccessKey ,
71
73
sessionToken : formValues . sessionToken ,
72
74
endpoint : endpointsByProtocol . HTTPS ,
73
75
correctClockSkew : true ,
74
76
} ) ;
75
- const getIceServerConfigResponse = await kinesisVideoSignalingChannelsClient
76
- . getIceServerConfig ( {
77
- ChannelARN : channelARN ,
78
- } )
79
- . promise ( ) ;
80
- const iceServers = [ ] ;
81
- if ( ! formValues . natTraversalDisabled && ! formValues . forceTURN ) {
82
- iceServers . push ( { urls : `stun:stun.kinesisvideo.${ formValues . region } .amazonaws.com:443` } ) ;
83
- }
84
- if ( ! formValues . natTraversalDisabled ) {
85
- getIceServerConfigResponse . IceServerList . forEach ( iceServer =>
86
- iceServers . push ( {
87
- urls : iceServer . Uris ,
88
- username : iceServer . Username ,
89
- credential : iceServer . Password ,
90
- } ) ,
91
- ) ;
92
- }
93
- console . log ( '[MASTER] ICE servers: ' , iceServers ) ;
94
-
95
- const configuration = {
96
- iceServers,
97
- iceTransportPolicy : formValues . forceTURN ? 'relay' : 'all' ,
98
- } ;
99
77
100
78
const resolution = formValues . widescreen ? { width : { ideal : 1280 } , height : { ideal : 720 } } : { width : { ideal : 640 } , height : { ideal : 480 } } ;
101
79
const constraints = {
102
80
video : formValues . sendVideo ? resolution : false ,
103
81
audio : formValues . sendAudio ,
104
82
} ;
105
83
106
- // Get a stream from the webcam and display it in the local view.
107
- // If no video/audio needed, no need to request for the sources.
84
+ // Get a stream from the webcam and display it in the local view.
85
+ // If no video/audio needed, no need to request for the sources.
108
86
// Otherwise, the browser will throw an error saying that either video or audio has to be enabled.
109
87
if ( formValues . sendVideo || formValues . sendAudio ) {
110
88
try {
@@ -122,6 +100,35 @@ async function startMaster(localView, remoteView, formValues, onStatsReport, onR
122
100
master . signalingClient . on ( 'sdpOffer' , async ( offer , remoteClientId ) => {
123
101
console . log ( '[MASTER] Received SDP offer from client: ' + remoteClientId ) ;
124
102
103
+ // Get ICE server configuration.
104
+ const getIceServerConfigResponse = await master . kinesisVideoSignalingChannelsClient
105
+ . getIceServerConfig ( {
106
+ ChannelARN : channelARN ,
107
+ } )
108
+ . promise ( ) ;
109
+
110
+ const iceServers = [ ] ;
111
+
112
+ if ( ! formValues . natTraversalDisabled && ! formValues . forceTURN ) {
113
+ iceServers . push ( { urls : `stun:stun.kinesisvideo.${ formValues . region } .amazonaws.com:443` } ) ;
114
+ }
115
+ if ( ! formValues . natTraversalDisabled ) {
116
+ getIceServerConfigResponse . IceServerList . forEach ( iceServer =>
117
+ iceServers . push ( {
118
+ urls : iceServer . Uris ,
119
+ username : iceServer . Username ,
120
+ credential : iceServer . Password ,
121
+ } ) ,
122
+ ) ;
123
+ }
124
+
125
+ console . log ( '[MASTER] ICE servers: ' , iceServers ) ;
126
+
127
+ const configuration = {
128
+ iceServers,
129
+ iceTransportPolicy : formValues . forceTURN ? 'relay' : 'all' ,
130
+ } ;
131
+
125
132
// Create a new peer connection using the offer from the given client
126
133
const peerConnection = new RTCPeerConnection ( configuration ) ;
127
134
master . peerConnectionByClientId [ remoteClientId ] = peerConnection ;
@@ -174,6 +181,11 @@ async function startMaster(localView, remoteView, formValues, onStatsReport, onR
174
181
}
175
182
await peerConnection . setRemoteDescription ( offer ) ;
176
183
184
+ // Submit ice candidates after remote description has been set.
185
+ if ( master . pendingIceCandidateByClientId [ remoteClientId ] ) {
186
+ master . pendingIceCandidateByClientId [ remoteClientId ] . forEach ( iceCandidate => peerConnection . addIceCandidate ( iceCandidate ) ) ;
187
+ }
188
+
177
189
// Create an SDP answer to send back to the client
178
190
console . log ( '[MASTER] Creating SDP answer for client: ' + remoteClientId ) ;
179
191
await peerConnection . setLocalDescription (
@@ -196,7 +208,17 @@ async function startMaster(localView, remoteView, formValues, onStatsReport, onR
196
208
197
209
// Add the ICE candidate received from the client to the peer connection
198
210
const peerConnection = master . peerConnectionByClientId [ remoteClientId ] ;
199
- peerConnection . addIceCandidate ( candidate ) ;
211
+
212
+ // Can not deliver ice candidate until remote description has been set.
213
+ // Therefore store ice candidate if peerConnection is not ready.
214
+ if ( peerConnection && peerConnection . remoteDescription ) {
215
+ peerConnection . addIceCandidate ( candidate ) ;
216
+ } else {
217
+ if ( ! master . pendingIceCandidateByClientId [ remoteClientId ] ) {
218
+ master . pendingIceCandidateByClientId [ remoteClientId ] = [ ] ;
219
+ }
220
+ master . pendingIceCandidateByClientId [ remoteClientId ] . push ( candidate ) ;
221
+ }
200
222
} ) ;
201
223
202
224
master . signalingClient . on ( 'close' , ( ) => {
0 commit comments