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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
|
---
title: L’essentiel du WebRTC
slug: Web/Guide/API/WebRTC/WebRTC_basics
tags:
- WebRTC
translation_of: Web/API/WebRTC_API/Signaling_and_video_calling
translation_of_original: Web/API/WebRTC_API/WebRTC_basics
---
<div class="summary">
<p>Maintenant que vous comprenez l'<a href="/fr/docs/Web/Guide/API/WebRTC/WebRTC_architecture" title="Introduction à l'architecture WebRTC">architecture WebRTC</a>, vous pouvez passer à cet article, qui vous emmène à travers la création d'une application RTC multi-navigateurs.A la fin de cet article vous devriez pouvoir créer un canal de données et de médias pair à pair qui fonctionne</p>
</div>
<h2 id="Contenu_semi-ancien_à_partir_de_RTCPeerConnection">Contenu semi-ancien, à partir de RTCPeerConnection</h2>
<p>Les informations ci-dessous proviennent de RTCPeerConnection; elles pourraient rester ici, comme aller ailleurs. Mais elles ne font pas partie de cette page. Alors pendant que je trie cette page, elles seront ici, jusqu'à ce que je sache où elles appartiennent pour de vrai.</p>
<h2 id="Usage_basique">Usage basique</h2>
<p>l'utilisation de RTCPeerConnection implique la négociation d'une connexion entre votre machine et une machine distante,et ce, en générant {{interwiki("wikipedia", "Session Description Protocol")}} a échanger entre les deux. L'appelant commence le processus en envoyant une offre à l'appareil distant, qui répond par l'acceptation ou le rejet de la demande de connexion.</p>
<p>Les deux parties (l'appelant et l'appelé) doivent mettre en place leurs propres instances de RTCPeerConnection pour représenter leurs extrémités de la connexion peer-to-peer:</p>
<pre class="notranslate"><code>var pc = new RTCPeerConnection();
pc.onaddstream = function(obj) {
var vid = document.createElement("video");
document.appendChild(vid);
vid.srcObject = obj.stream;
}
// Helper functions
function endCall() {
var videos = document.getElementsByTagName("video");
for (var i = 0; i < videos.length; i++) {
videos[i].pause();
}
pc.close();
}
function error(err) {
endCall();
}</code></pre>
<p><strong>Initialiser un appel</strong></p>
<p>l'appelant doit utiliser {{domxref("navigator.getUserMedia()")}} pour obtenir un flux vidéo, puis ajouter ce flux à l'instance de RTCPeerConnection. Une fois que cela a été fait, il doit appeler {{domxref("RTCPeerConnection.createOffer()")}} pour créer une offre,puis la configurer et l'envoyer a un serveur faisant office d'intermediaire.</p>
<pre class="notranslate"><code>// recuperer la liste des "amis" a partir du serveur
// l'utilisateur selectionne un amis avec qui lancer la connection
navigator.getUserMedia({video: true}, function(stream) {
// l'ajout d'un stream locale ne declanche pas onaddstream,
// donc il faut l'appeler manuellement.
pc.onaddstream = e => video.src = URL.createObjectURL(e.stream);
pc.addStream(stream);
pc.createOffer(function(offer) {
pc.setLocalDescription(offer, function() {
// envoi de l'offre au serveur qui se charge de la transmettre a "l'ami" choisit precedemment.
}, error);
}, error);
});</code></pre>
<p><strong>Répondre à un appel</strong></p>
<p>sur l'autre machine, l'ami recevra l'offre à partir du serveur en utilisant le protocole approprié (définit par le serveur). Une fois que l'offre arrive,{{domxref("navigator.getUserMedia()")}} est une fois de plus appelée pour créer le second flux, qui est ajouté à la RTCPeerConnection. Un objet {{domxref("RTCSessionDescription")}} est créé, et mis en place comme la description du distant en appelant {{domxref("RTCPeerConnection.setRemoteDescription()")}}.</p>
<p>Ensuite, une réponse est créée en utilisant {{domxref("RTCPeerConnection.createAnswer()")}} et renvoyé au serveur, qui la transmet à l'appelant.</p>
<pre class="notranslate"><code>var offer = getOfferFromFriend();
navigator.getUserMedia({video: true}, function(stream) {
pc.onaddstream = e => video.src = URL.createObjectURL(e.stream);
pc.addStream(stream);
pc.setRemoteDescription(new RTCSessionDescription(offer), function() {
pc.createAnswer(function(answer) {
pc.setLocalDescription(answer, function() {
// envoi de la réponse au serveur qui la transmettra a l'appelant
}, error);
}, error);
}, error);
});</code></pre>
<p><strong>Gestion de la réponse</strong></p>
<p>retour a la première machine, qui recois la reponse. une fois cette dernière arrivée,l'appelant utilise {{domxref("RTCPeerConnection.setRemoteDescription()")}} pour définir la réponse comme la description de l'autre l'extrémité de la connexion. </p>
<pre class="notranslate"><code>// pc a été déclaré </code>précédemment<code>, lors de l'envoi de l'offre.
var offer = getResponseFromFriend();
pc.setRemoteDescription(new RTCSessionDescription(offer), function() { }, error);</code></pre>
<h2 id="Ancien_contenu_en_approche!">Ancien contenu en approche!</h2>
<p>Tout ce qui est en dessous de ce point est potentiellement obsolète. Il est toujours là en attente d'examen et d'intégration possible dans d'autres parties de la documentation où il serait encore valides.</p>
<div class="note">
<p>Ne pas utiliser les examples de cette page. Voir l'article <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Signaling_and_video_calling">signalisation et appel vidéo</a> ,pour des example mis a jour sur l'utilisation des medias WebRTC.</p>
</div>
<h2 id="Note">Note</h2>
<p>Cette page contient des informations périmées selon <a href="http://stackoverflow.com/a/25065359/3760500">http://stackoverflow.com/a/25065359/3760500</a></p>
<blockquote>
<p>Peu importe ce que la page de MDN indique, RTPDataChannels est très désuet (faites connaître l'URL). Firefox et Chrome supportent les spec DataChannels maintenant. Idem pour DTLSSRTPKeyAgreement je pense.</p>
</blockquote>
<h2 id="Shims_Bibliothèque_d’interception_d’API">Shims (Bibliothèque d’interception d’API)</h2>
<p>Comme vous pouvez l'imaginer, avec une API aussi jeune, vous devez utiliser les préfixes de navigateur et les positionner dans des variables communes.</p>
<pre class="brush: js notranslate">var PeerConnection = window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
var IceCandidate = window.mozRTCIceCandidate || window.RTCIceCandidate;
var SessionDescription = window.mozRTCSessionDescription || window.RTCSessionDescription;
navigator.getUserMedia = navigator.getUserMedia || navigator.mozGetUserMedia || navigator.webkitGetUserMedia;</pre>
<h2 id="PeerConnection">PeerConnection</h2>
<p>C'est le point de départ pour créer une connexion avec un pair. Il accepte des options de configuration sur les serveurs ICE à utiliser pour établir une connexion.</p>
<pre class="brush: js notranslate">var pc = new PeerConnection(configuration, options);</pre>
<h3 id="RTCConfiguration"><strong><code>RTCConfiguration</code></strong></h3>
<p>L'objet {{domxref("RTCConfiguration")}} contient l’information sur les serveurs TURN et/ou STUN à utiliser pour ICE. Ceci est requis pour s'assurer que la plupart des utilisateurs peuvent en fait créer une connexion en évitant les restrictions du NAT et du pare-feu.</p>
<pre class="brush: js notranslate">var configuration = {
iceServers: [
{url: "stun:23.21.150.121"},
{url: "stun:stun.l.google.com:19302"},
{url: "turn:numb.viagenie.ca", credential: "webrtcdemo", username: "louis%40mozilla.com"}
]
}</pre>
<p>Google met à disposition un <a href="https://code.google.com/p/natvpn/source/browse/trunk/stun_server_list">serveur STUN public</a> que nous pouvons utiliser. J'ai également créé un compte chez http://numb.viagenie.ca/ pour un accès gratuit à un serveur TURN. Vous pouvez faire la même chose et les remplacer par vos propres informations d'identification.</p>
<h3 id="options_Cf._Note_avant"><strong><code>options</code></strong> (Cf. "Note" avant)</h3>
<p>Selon le type de connexion, vous devez passer des options.</p>
<pre class="brush: js notranslate" lang="javascript">var options = {
optional: [
{DtlsSrtpKeyAgreement: true},
{RtpDataChannels: true}
]
}</pre>
<p><code>DtlsSrtpKeyAgreement</code> est exigé pour Chrome et Firefox pour interagir.</p>
<p><code>RtpDataChannels</code> est nécessaire si nous voulons utiliser l'API DataChannels sur Firefox.</p>
<h2 id="ICECandidate">ICECandidate</h2>
<p>Après avoir créé la connexion et en passant par les serveurs STUN et TURN disponibles, un événement sera déclenché une fois que le framework ICE aura trouvé certains « candidats » qui permettront de vous connecter avec un pair. Ceci est reconnu comme étant un candidat ICE et exécute une fonction de rappel sur PeerConnection#onicecandidate.</p>
<pre class="brush: js notranslate" lang="javascript">pc.onicecandidate = function (e) {
// candidate exists in e.candidate
if (e.candidate == null) { return }
send("icecandidate", JSON.stringify(e.candidate));
pc.onicecandidate = null;
};</pre>
<p>Lorsque le rappel est exécuté, nous devons utiliser le canal de signal pour envoyer le Candidat au pair. Sur Chrome, on trouve habituellement plusieurs candidats ICE, nous n’en avons besoin que d'un seul donc j'en envoie généralement une puis supprimer le descripteur. Firefox inclut le Candidat dans l'Offre SDP.</p>
<h2 id="Canal_de_Signal">Canal de Signal</h2>
<p>Maintenant que nous avons un candidat ICE, nous devons l’envoyer à nos pairs afin qu'ils sachent comment se connecter avec nous. Toutefois, cela nous laisse face à une problématique de l’œuf et de la poule; Nous voulons que PeerConnection envoie des données à un pair, mais avant cela, nous devons lui envoyer des métadonnées…</p>
<p>C'est là qu'intervient le canal de signal. C'est n'importe quel mode de transport de données qui permet aux deux pairs d’échanger des informations. Dans cet article, nous allons utiliser <a href="http://firebase.com">FireBase</a> parce que c'est incroyablement facile à installer et ne nécessite aucun hébergement ou code serveur.</p>
<p>Pour l'instant imaginez seulement que deux méthodes existent: <code>send()</code> va prendre une clé et lui affecter des données et <code>recv()</code> appelle un descripteur lorsqu'une clé a une valeur.</p>
<p>La structure de la base de données ressemble à ceci :</p>
<pre class="brush: js notranslate" lang="json">{
"": {
"candidate:": …
"offer": …
"answer": …
}
}</pre>
<p>Les connexions sont divisées par un <code>roomId</code> et stockeront 4 éléments d'information, le candidat ICE de l'auteur de l'offre, le candidat ICE du répondeur, l'offre SDP et la réponse SDP.</p>
<h2 id="Offre">Offre</h2>
<p>Une offre SDP (Session Description Protocol) et le méta données qui décrit aux autres pairs le format attendu(video, formats, codecs, cryptage, résolution, taille, etc etc).</p>
<p>Un échange nécessite une offre d'un pair, alors l'autre pair doit recevoir l'offre et offrir en retour une réponse.</p>
<pre class="brush: js notranslate" lang="javascript">pc.createOffer(function (offer) {
pc.setLocalDescription(offer);
send("offer", JSON.stringify(offer));
}, errorHandler, constraints);</pre>
<h3 id="errorHandler"><strong><code>errorHandler</code></strong></h3>
<p>S'il y avait un problème lors de la génération d’une offre, cette méthode sera exécutée avec les détails de l'erreur comme premier argument.</p>
<pre class="brush: js notranslate" lang="javascript">var errorHandler = function (err) {
console.error(err);
};</pre>
<h3 id="constraints"><strong><code>constraints</code></strong></h3>
<p>Options pour l'offre SDP.</p>
<pre class="brush: js notranslate" lang="javascript">var constraints = {
mandatory: {
OfferToReceiveAudio: true,
OfferToReceiveVideo: true
}
};</pre>
<p><code>OfferToReceiveAudio/Video</code> Dit aux autres pair que vous désirez recevoir de la vidéo ou de l'audio de leur part. Ce n'est pas nécessaire pour DataChannels.</p>
<p>Une fois que l'offre a été générée nous devons définir le SDP local à la nouvelle offre et l’envoyer par le canal de signal aux autres pairs et attendre leur réponse SDP.</p>
<h2 id="Réponse">Réponse</h2>
<p>Une réponse SDP est comme une offre, mais est une réponse ; un peu comme répondre au téléphone. Nous pouvons seulement émettre une réponse qu’après avoir reçu une offre.</p>
<pre class="brush: js notranslate" lang="javascript">recv("offer", function (offer) {
offer = new SessionDescription(JSON.parse(offer))
pc.setRemoteDescription(offer);
pc.createAnswer(function (answer) {
pc.setLocalDescription(answer);
send("answer", JSON.stringify(answer));
}, errorHandler, constraints);
});</pre>
<h2 id="DataChannel">DataChannel</h2>
<p>J'expliquerai d'abord comment utiliser PeerConnection pour l'API DataChannels et le transfert de données arbitraires entre des pairs.</p>
<p><em>Note: Au moment de l’écriture de cet article, l'interopérabilité entre Chrome et Firefox n'est pas possible avec DataChannels. Chrome prend en charge un protocole similaire mais privé et soutiendra le protocole standard bientôt.</em></p>
<pre class="brush: js notranslate" lang="javascript">var channel = pc.createDataChannel(channelName, channelOptions);</pre>
<p>L'auteur de l'offre doit être le pair qui crée le canal. Le répondeur recevra le canal dans le rappel (callback) <code>ondatachannel</code> dans le PeerConnection. Vous devez appeler <code>createDataChannel()</code> une fois avant de créer l'offre.</p>
<h3 id="channelName"><strong><code>channelName</code></strong></h3>
<p>Il s'agit d'une chaîne qui agit comme une étiquette pour le nom de votre canal. <em>AVERTISSEMENT : Assurez-vous que votre nom de canal n'a pas d'espaces ou Chrome va échouer sur <code>createAnswer()</code>.</em></p>
<h3 id="channelOptions"><strong><code>channelOptions</code></strong></h3>
<pre class="brush: js notranslate" lang="javascript">var channelOptions = {};</pre>
<p>Ces options ne sont pas bien supportées sur Chrome donc vous pouvez laisser ça vide pour l'instant. Vérifiez le <a href="http://dev.w3.org/2011/webrtc/editor/webrtc.html#attributes-7">RFC</a> pour plus d'informations sur les options.</p>
<h3 id="Méthodes_et_événements_de_canal">Méthodes et événements de canal</h3>
<h4 id="onopen"><strong><code>onopen</code></strong></h4>
<p>Exécuté lorsque la connexion est établie.</p>
<h4 id="onerror"><strong><code>onerror</code></strong></h4>
<p>Exécuté s'il y a une erreur de création de la connexion. Le premier argument est un objet d'erreur.</p>
<pre class="brush: js notranslate" lang="javascript">channel.onerror = function (err) {
console.error("Channel Error:", err);
};</pre>
<h4 id="onmessage"><strong><code>onmessage</code></strong></h4>
<pre class="brush: js notranslate" lang="javascript">channel.onmessage = function (e) {
console.log("Got message:", e.data);
}</pre>
<p>Le cœur de la connexion. Lorsque vous recevez un message, cette méthode s’exécute. Le premier argument est un objet d'événement qui contient les données, heure de réception et autres informations.</p>
<h4 id="onclose"><strong><code>onclose</code></strong></h4>
<p>Exécuté si l'autre pair ferme la connexion.</p>
<h3 id="Lier_les_événements"><strong>Lier les événements</strong></h3>
<p>Si vous êtes le créateur du canal(l'auteur de l'offre), vous pouvez lier des événements directement à la DataChannel que vous avez créé avec <code>createChannel</code>. Si vous êtes l'auteur de la réponse, vous devez utiliser le callback <code>ondatachannel</code> dans le PeerConnection afin d'accéder au même canal.</p>
<pre class="brush: js notranslate" lang="javascript">pc.ondatachannel = function (e) {
e.channel.onmessage = function () { … };
};</pre>
<p>Le canal est disponible dans l’objet événement passé dans le descripteur en tant que <code>e.channel</code>.</p>
<h4 id="send"><strong><code>send()</code></strong></h4>
<pre class="brush: js notranslate" lang="javascript">channel.send("Hi Peer!");</pre>
<p>Cette méthode vous permet d'envoyer des données directement au pair! Incroyable. Vous devez envoyer un String, Blob, ArrayBuffer ou ArrayBufferView, alors assurez-vous de "stringifier" les objets.</p>
<h4 id="close"><strong><code>close()</code></strong></h4>
<p>Ferme le canal une fois que la connexion doit se terminer. Il est recommandé de le faire sur l’ unload de la page.</p>
<h2 id="Media">Media</h2>
<p>Maintenant nous allons couvrir la transmission de médias tels que l'audio ou la vidéo. Pour afficher la vidéo et l'audio, vous devez inclure un tag <code><video></code> dans le document avec l'attribut <code>autoplay</code>.</p>
<h3 id="Obtenir_les_médias_de_lutilisateur">Obtenir les médias de l'utilisateur</h3>
<pre class="brush: js notranslate"><video id="preview" autoplay></video>
var video = document.getElementById("preview");
navigator.getUserMedia(mediaOptions, function (stream) {
video.src = URL.createObjectURL(stream);
}, errorHandler);</pre>
<p><strong><code>mediaOptions</code></strong></p>
<p>Les contraintes sur les types de médias que vous souhaitez renvoyer de l'utilisateur.</p>
<pre class="brush: js notranslate" lang="javascript">var mediaOptions = {
video: true,
audio: true
};</pre>
<p>Si vous voulez juste une conversation audio, supprimez la clé <code>video</code>.</p>
<h4 id="errorHandler_2"><strong><code>errorHandler</code></strong></h4>
<p>Exécuté s'il y a une erreur retournée par le support demandé.</p>
<h3 id="Événements_Médias_et_Méthodes">Événements Médias et Méthodes</h3>
<h4 id="addStream"><strong><code>addStream</code></strong></h4>
<p>Ajoute le flux de <code>getUserMedia</code> au PeerConnection.</p>
<pre class="brush: js notranslate" lang="javascript">pc.addStream(stream);</pre>
<h4 id="onaddstream"><strong><code>onaddstream</code></strong></h4>
<pre class="brush: js notranslate"><video id="otherPeer" autoplay></video>
var otherPeer = document.getElementById("otherPeer");
pc.onaddstream = function (e) {
otherPeer.src = URL.createObjectURL(e.stream);
};</pre>
<p>Exécuté lorsque la connexion a été mise en place et que l'autre pair a ajouté le flux de données pour la connexion avec <code>addStream</code>. Vous avez besoin d'un autre tag <code><video></code> pour afficher les médias de l'autre pair.</p>
<p>Le premier argument est un objet d'événement avec les flux de média de l'autre pair.</p>
<h2 id="Afficher_la_Source">Afficher la Source</h2>
<p>Vous pouvez voir la source développée à partir de tous les extraits de code de cet article à <a href="http://github.com/louisstow/WebRTC">mon repo WebRTC</a>.</p>
<ul>
<li>
<p><strong>Exemple de DataChannels :</strong> <a href="https://github.com/louisstow/WebRTC/blob/master/datachannels.html">code</a>, <a href="http://louisstow.github.io/WebRTC/datachannels.html">demo</a></p>
</li>
<li>
<p><strong>Exemple de média :</strong> <a href="https://github.com/louisstow/WebRTC/blob/master/media.html">code</a>, <a href="http://louisstow.github.io/WebRTC/media.html">demo</a></p>
</li>
</ul>
|