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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
---
title: 'RTCPeerConnection: icecandidate event'
slug: Web/API/RTCPeerConnection/icecandidate_event
translation_of: Web/API/RTCPeerConnection/icecandidate_event
---
<div>{{WebRTCSidebar}}</div>
<p>Событие <strong><code>icecandidate</code></strong> отправляется {{domxref("RTCPeerConnection")}} когда {{domxref("RTCIceCandidate")}} был идентифицирован и добавлен к локальному клиенту (local peer) через вызов {{domxref("RTCPeerConnection.setLocalDescription()")}}. Обработчик события должен передать кандидата удаленному клиенту (remote peer) по каналу сигнализации (signaling channel), чтобы удаленный клиент (remote peer) смог добавить его в свой набор удаленных кандидатов (remote candidates).</p>
<table class="properties">
<tbody>
<tr>
<th scope="row">Всплывает</th>
<td>Нет</td>
</tr>
<tr>
<th scope="row">Отменяемое</th>
<td>Нет</td>
</tr>
<tr>
<th scope="row">Интерфейс</th>
<td>{{DOMxRef("RTCPeerConnectionIceEvent")}}</td>
</tr>
<tr>
<th scope="row">Название обработчика событий</th>
<td>{{DOMxRef("RTCPeerConnection.onicecandidate")}}</td>
</tr>
</tbody>
</table>
<h2 id="Описание">Описание</h2>
<p>Существует три причины, по которым событие <code>icecandidate</code> происходит (fired) у {{domxref("RTCPeerConnection")}}.</p>
<h3 id="Делимся_Sharing_новым_кандидатом">Делимся (Sharing) новым кандидатом</h3>
<p>В основном события <code>icecandidate</code> происходят, чтобы указать, что новый кандидат был построен (gathered). Этого кондидата нужно доставить удаленному клиенту (remote peer) через канал сигнализации (signaling channel), которым управляет ваш код.</p>
<pre class="brush: js notranslate">rtcPeerConnection.onicecandidate = (event) => {
if (event.candidate) {
sendCandidateToRemotePeer(event.candidate)
} else {
/* there are no more candidates coming during this negotiation */
}
}
</pre>
<p>Удаленный клиент (peer), получив кандидата, добавит этого кандидата в свой пул кандидатов, используя вызов {{domxref("RTCPeerConnection.addIceCandidate", "addIceCandidate()")}}, передавая в {{domxref("RTCPeerConnectionIceEvent.candidate", "candidate")}} строку, которую вы передали с помощью сервера сигнализации (signaling server).</p>
<h3 id="Indicating_the_end_of_a_generation_of_candidates">Indicating the end of a generation of candidates</h3>
<p>When an ICE negotiation session runs out of candidates to propose for a given {{domxref("RTCIceTransport")}}, it has completed gathering for a <strong>generation</strong> of candidates. That this has occurred is indicated by an <code>icecandidate</code> event whose {{domxref("RTCPeerConnectionIceEvent.candidate", "candidate")}} string is empty (<code>""</code>).</p>
<p>You should deliver this to the remote peer just like any standard candidate, as described under {{anch("Sharing a new candidate")}} above. This ensures that the remote peer is given the end-of-candidates notification as well. As you see in the code in the previous section, every candidate is sent to the other peer, including any that might have an empty candidate string. Only candidates for which the event's {{domxref("RTCPeerConnectionIceEvent.candidate", "candidate")}} property is <code>null</code> are not forwarded across the signaling connection.</p>
<p>The end-of-candidates indication is described in <a href="https://tools.ietf.org/html/draft-ietf-mmusic-trickle-ice-02#section-9.3">section 9.3 of the Trickle ICE draft specification</a> (note that the section number is subject to change as the specification goes through repeated drafts).</p>
<h3 id="Indicating_that_ICE_gathering_is_complete">Indicating that ICE gathering is complete</h3>
<p>Once all ICE transports have finished gathering candidates and the value of the {{domxref("RTCPeerConnection")}} object's {{domxref("RTCPeerConnection.iceGatheringState", "iceGatheringState")}} has made the transition to <code>complete</code>, an <code>icecandidate</code> event is sent with the value of <code>complete</code> set to <code>null</code>.</p>
<p>This signal exists for backward compatibility purposes and does <em>not</em> need to be delivered onward to the remote peer (which is why the code snippet above checks to see if <code>event.candidate</code> is <code>null</code> prior to sending the candidate along.</p>
<p>If you need to perform any special actions when there are no further candidates expected, you're much better off watching the ICE gathering state by watching for {{domxref("RTCPeerConnection.icegatheringstatechange_event", "icegatheringstatechange")}} events:</p>
<pre class="brush: js notranslate">pc.addEventListener("icegatheringstatechange", ev => {
switch(pc.iceGatheringState) {
case "new":
/* gathering is either just starting or has been reset */
break;
case "gathering":
/* gathering has begun or is ongoing */
break;
case "complete":
/* gathering has ended */
break;
}
});
</pre>
<p>As you can see in this example, the <code>icegatheringstatechange</code> event lets you know when the value of the {{domxref("RTCPeerConnection")}} property {{domxref("RTCPeerConnection.iceGatheringState", "iceGatheringState")}} has been updated. If that value is now <code>complete</code>, you know that ICE gathering has just ended.</p>
<p>This is a more reliable approach than looking at the individual ICE messages for one indicating that the ICE session is finished.</p>
<h2 id="Examples">Examples</h2>
<p>This example creates a simple handler for the <code>icecandidate</code> event that uses a function called <code>sendMessage()</code> to create and send a reply to the remote peer through the signaling server.</p>
<p>First, an example using {{domxref("EventTarget.addEventListener", "addEventListener()")}}:</p>
<pre class="brush: js notranslate">pc.addEventListener("icecandidate", ev => {
if (ev.candidate) {
sendMessage({
type: "new-ice-candidate",
candidate: event.candidate
});
}
}, false);
</pre>
<p>You can also set the {{domxref("RTCPeerConnection.onicecandidate", "onicecandidate")}} event handler property directly:</p>
<pre class="brush: js notranslate">pc.onicecandidate = ev => {
if (ev.candidate) {
sendMessage({
type: "new-ice-candidate",
candidate: event.candidate
});
}
};
</pre>
<h2 id="Specifications">Specifications</h2>
<table class="standard-table">
<tbody>
<tr>
<th scope="col">Specification</th>
<th scope="col">Status</th>
<th scope="col">Comment</th>
</tr>
<tr>
<td>{{ SpecName('WebRTC 1.0', '#event-icecandidate', 'icecandidate') }}</td>
<td>{{Spec2('WebRTC 1.0')}}</td>
<td></td>
</tr>
</tbody>
</table>
<h2 id="Browser_compatibility">Browser compatibility</h2>
<p>{{Compat("api.RTCPeerConnection.icecandidate_event")}}</p>
<h2 id="See_also">See also</h2>
<ul>
<li><a href="/en-US/docs/Web/API/WebRTC_API">WebRTC API</a></li>
<li><a href="/en-US/docs/Web/API/WebRTC_API/Signaling_and_video_calling">Signaling and video calling</a></li>
</ul>
|