idnits 2.17.1 draft-uberti-rtcweb-jsep-02.txt: Checking boilerplate required by RFC 5378 and the IETF Trust (see https://trustee.ietf.org/license-info): ---------------------------------------------------------------------------- No issues found here. Checking nits according to https://www.ietf.org/id-info/1id-guidelines.txt: ---------------------------------------------------------------------------- No issues found here. Checking nits according to https://www.ietf.org/id-info/checklist : ---------------------------------------------------------------------------- ** There are 2 instances of too long lines in the document, the longest one being 4 characters in excess of 72. == There are 1 instance of lines with non-RFC6890-compliant IPv4 addresses in the document. If these are example addresses, they should be changed. Miscellaneous warnings: ---------------------------------------------------------------------------- == The copyright year in the IETF Trust and authors Copyright Line does not match the current year == The document doesn't use any RFC 2119 keywords, yet seems to have RFC 2119 boilerplate text. -- The document date (February 16, 2012) is 4446 days in the past. Is this intentional? Checking references for intended status: Proposed Standard ---------------------------------------------------------------------------- (See RFCs 3967 and 4897 for information about using normative references to lower-maturity documents in RFCs) == Missing Reference: '-' is mentioned on line 646, but not defined == Unused Reference: 'RFC3264' is defined on line 1223, but no explicit reference was found in the text == Unused Reference: 'RFC4566' is defined on line 1226, but no explicit reference was found in the text == Unused Reference: 'RFC5245' is defined on line 1235, but no explicit reference was found in the text ** Obsolete normative reference: RFC 4566 (Obsoleted by RFC 8866) -- Obsolete informational reference (is this intentional?): RFC 5245 (Obsoleted by RFC 8445, RFC 8839) Summary: 2 errors (**), 0 flaws (~~), 7 warnings (==), 2 comments (--). Run idnits with the --verbose option for more detailed information about the items above. -------------------------------------------------------------------------------- 2 Network Working Group J. Uberti 3 Internet-Draft Google 4 Network Working Group C. Jennings 5 Internet-Draft Cisco Systems, Inc. 6 Intended status: Standards Track February 16, 2012 7 Expires: August 19, 2012 9 Javascript Session Establishment Protocol 10 draft-uberti-rtcweb-jsep-02 12 Abstract 14 This document proposes a mechanism for allowing a Javascript 15 application to fully control the signaling plane of a multimedia 16 session, and discusses how this would work with existing signaling 17 protocols. 19 This document is an input document for discussion. It should be 20 discussed in the RTCWEB WG list, rtcweb@ietf.org. 22 Requirements Language 24 The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 25 "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this 26 document are to be interpreted as described in RFC 2119 [RFC2119]. 28 Status of this Memo 30 This Internet-Draft is submitted in full conformance with the 31 provisions of BCP 78 and BCP 79. 33 Internet-Drafts are working documents of the Internet Engineering 34 Task Force (IETF). Note that other groups may also distribute 35 working documents as Internet-Drafts. The list of current Internet- 36 Drafts is at http://datatracker.ietf.org/drafts/current/. 38 Internet-Drafts are draft documents valid for a maximum of six months 39 and may be updated, replaced, or obsoleted by other documents at any 40 time. It is inappropriate to use Internet-Drafts as reference 41 material or to cite them other than as "work in progress." 43 This Internet-Draft will expire on July 26, 2012. 45 Copyright Notice 47 Copyright (c) 2012 IETF Trust and the persons identified as the 48 document authors. All rights reserved. 50 This document is subject to BCP 78 and the IETF Trust's Legal 51 Provisions Relating to IETF Documents 52 (http://trustee.ietf.org/license-info) in effect on the date of 53 publication of this document. Please review these documents 54 carefully, as they describe your rights and restrictions with respect 55 to this document. Code Components extracted from this document must 56 include Simplified BSD License text as described in Section 4.e of 57 the Trust Legal Provisions and are provided without warranty as 58 described in the Simplified BSD License. 60 Table of Contents 62 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 4 63 2. JSEP Approach . . . . . . . . . . . . . . . . . . . . . . . . . 5 64 3. Other Approaches Considered . . . . . . . . . . . . . . . . . . 6 65 4. Semantics and Syntax . . . . . . . . . . . . . . . . . . . . . 7 66 4.1. Signaling Model . . . . . . . . . . . . . . . . . . . . . . 7 67 4.2. Session Descriptions . . . . . . . . . . . . . . . . . . . 7 68 4.3. Session Description Format . . . . . . . . . . . . . . . . 8 69 4.4. Separation of Signaling and ICE State Machines . . . . . . 9 70 4.5. ICE Candidate Trickling . . . . . . . . . . . . . . . . . . 9 71 4.6. ICE Candidate Format . . . . . . . . . . . . . . . . . . . 10 72 5. Media Setup Overview . . . . . . . . . . . . . . . . . . . . . 10 73 5.1. Initiating the Session . . . . . . . . . . . . . . . . . . 10 74 5.1.1. Generating An Offer . . . . . . . . . . . . . . . . . . 10 75 5.1.2. Applying the Offer . . . . . . . . . . . . . . . . . . 11 76 5.1.3. Initiating ICE . . . . . . . . . . . . . . . . . . . . 11 77 5.1.4. Serializing the Offer and Candidates . . . . . . . . . 11 78 5.2. Receiving the Session . . . . . . . . . . . . . . . . . . . 12 79 5.2.1. Receiving the Offer . . . . . . . . . . . . . . . . . . 12 80 5.2.2. Initiating ICE . . . . . . . . . . . . . . . . . . . . 12 81 5.2.3. Handling ICE Messages . . . . . . . . . . . . . . . . . 12 82 5.2.4. Generating the Answer . . . . . . . . . . . . . . . . . 12 83 5.2.5. Applying the Answer . . . . . . . . . . . . . . . . . . 13 84 5.2.6. Serializing the Answer . . . . . . . . . . . . . . . . 13 85 5.3. Completing the Session . . . . . . . . . . . . . . . . . . 13 86 5.3.1. Receiving the Answer . . . . . . . . . . . . . . . . . 13 87 5.4. Updates to the Session . . . . . . . . . . . . . . . . . . 13 88 6. Proposed WebRTC API changes . . . . . . . . . . . . . . . . . . 13 89 6.1. PeerConnection API . . . . . . . . . . . . . . . . . . . . 13 90 6.1.1 MediaHints . . . . . . . . . . . . . . . . . . . . . . . 15 91 6.1.2 createOffer . . . . . . . . . . . . . . . . . . . . . . 15 92 6.1.3 createAnswer . . . . . . . . . . . . . . . . . . . . . . 16 93 6.1.4 SDP_OFFER, SDP_PRANSWER, and SDP_ANSWER . . . . . . . . 17 94 6.1.5 setLocalDescription . . . . . . . . . . . . . . . . . . 17 95 6.1.6 setRemoteDescription . . . . . . . . . . . . . . . . . . 18 96 6.1.7 localDescription . . . . . . . . . . . . . . . . . . . . 18 97 6.1.8 remoteDescription . . . . . . . . . . . . . . . . . . . 19 98 6.1.9 IceOptions . . . . . . . . . . . . . . . . . . . . . . . 19 99 6.1.10 startIce . . . . . . . . . . . . . . . . . . . . . . . 19 100 6.1.11 processIceMessage . . . . . . . . . . . . . . . . . . . 19 101 7. Example API Flows . . . . . . . . . . . . . . . . . . . . . . . 20 102 7.1. Call using ROAP . . . . . . . . . . . . . . . . . . . . . . 20 103 7.2. Call using XMPP . . . . . . . . . . . . . . . . . . . . . . 21 104 7.3. Adding video to a call, using XMPP . . . . . . . . . . . . 22 105 7.4. Simultaneous add of video streams, using XMPP . . . . . . . 22 106 7.5. Call using SIP . . . . . . . . . . . . . . . . . . . . . . 23 107 7.6. Handling early media (e.g. 1-800-FEDEX), using SIP . . . . 24 108 8. Example Application . . . . . . . . . . . . . . . . . . . . . . 25 109 9. Security Considerations . . . . . . . . . . . . . . . . . . . . 26 110 10. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 26 111 11. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 26 112 12. References . . . . . . . . . . . . . . . . . . . . . . . . . . 26 113 12.1. Normative References . . . . . . . . . . . . . . . . . . . 26 114 12.2. Informative References . . . . . . . . . . . . . . . . . . 27 115 Appendix A. Open Issues . . . . . . . . . . . . . . . . . . . . . 27 116 Appendix B. Change log . . . . . . . . . . . . . . . . . . . . . . 27 117 Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 27 119 1. Introduction 121 The general thinking behind WebRTC call setup has been to fully 122 specify and control the media plane, but to leave the signaling plane 123 up to the application as much as possible. The rationale is that 124 different applications may prefer to use different protocols, such as 125 the existing SIP or Jingle call signaling protocols, or something 126 custom to the particular application, perhaps for a novel use case. 127 In this approach, the key information that needs to be exchanged is 128 the multimedia session description, which specifies the necessary 129 transport and media configuration information necessary to establish 130 the media plane. 132 The original spec for WebRTC attempted to implement this protocol- 133 agnostic signaling by providing a mechanism to exchange session 134 descriptions in the form of SDP blobs. Upon starting a session, the 135 browser would generate a SDP blob, which would be passed to the 136 application for transport over its preferred signaling protocol. On 137 the remote side, this blob would be passed into the browser from the 138 application, and the browser would then generate a blob of its own in 139 response. Upon transmission back to the initiator, this blob would be 140 plugged into their browser, and the handshake would be complete. 142 Experimentation with this mechanism turned up several shortcomings, 143 which generally stemmed from there being insufficient context at the 144 browser to fully determine the meaning of a SDP blob. For example, 145 determining whether a blob is an offer or an answer, or 146 differentiating a new offer from a retransmit. 148 The ROAP proposal, specified in http://tools.ietf.org/html/draft- 149 jennings-rtcweb-signaling-01, attempted to resolve these issues by 150 providing additional structure in the messaging - in essence, to 151 create a generic signaling protocol that specifies how the browser 152 signaling state machine should operate. However, even though the 153 protocol is abstracted, the state machine forces a least-common- 154 denominator approach on the signaling interactions. For example, in 155 Jingle, the call initiator can provide additional ICE candidates even 156 after the initial offer has been sent, which allows the offer to be 157 sent immediately for quicker call startup. However, in the browser 158 state machine, there is no notion of sending an updated offer before 159 the initial offer has been responded to, rendering this functionality 160 impossible. 162 While specific concerns like this could be addressed by modifying the 163 generic protocol, others would likely be discovered later. The main 164 reason this mechanism is inflexible is because it embeds a signaling 165 state machine within the browser. Since the browser generates the 166 session descriptions on its own, and fully controls the possible 167 states and advancement of the signaling state machine, modification 168 of the session descriptions or use of alternate state machines 169 becomes difficult or impossible. 171 The browser environment also has its own challenges that cause 172 problems for an embedded signaling state machine. One of these is 173 that the user may reload the web page at any time. If this happens, 174 and the state machine is being run at a server, the server can simply 175 push the current state back down to the page and resume the call 176 where it left off. If instead the state machine is run at the browser 177 end, and is instantiated within, for example, the PeerConnection 178 object, that state machine will be reinitialized when the page is 179 reloaded and the JavaScript re-executed. This actually complicates 180 the design of any interoperability service, as all cases where an 181 offer or answer has already been generated but is now "forgotten" 182 must now be handled by trying to move the client state machine 183 forward to the same state it had been in previously in order to match 184 what has already been delivered to and/or answered by the far side, 185 or handled by ensuring that aborts are cleanly handled from every 186 state and the negotiation rapidly restarted. 188 2. JSEP Approach 190 To resolve these issues, this document proposes the Javascript 191 Session Establishment Protocol (JSEP) that pulls the signaling state 192 machine out of the browser and into Javascript. This mechanism 193 effectively removes the browser almost completely from the core 194 signaling flow; the only interface needed is a way for the 195 application to pass in the local and remote session descriptions 196 negotiated by whatever signaling mechanism is used, and a way to 197 interact with the ICE state machine. 199 JSEP's handling of session descriptions is simple and 200 straightforward. Whenever an offer/answer exchange is needed, the 201 initiating side creates an offer by calling a createOffer() API on 202 PeerConnection. The application can do massaging of that offer, if it 203 wants to, and then uses it to set up its local config via a 204 setLocalDescription() API. The offer is then sent off to the remote 205 side over its preferred signaling mechanism (e.g. WebSockets); upon 206 receipt of that offer, the remote party installs it using a 207 setRemoteDescription() API. 209 When the call is accepted, the callee uses a createAnswer() API to 210 generate an appropriate answer, applies it using 211 setLocalDescription(), and sends the answer back to the initiator 212 over the signaling channel. When the offerer gets that answer, it 213 installs it using setRemoteDescription(), and initial setup is 214 complete. This process can be repeated for additional offer/answer 215 exchanges. 217 Regarding ICE, in this approach we decouple the ICE state machine 218 from the overall signaling state machine; the ICE state machine must 219 remain in the browser, given that only the browser has the necessary 220 knowledge of candidates and other transport info. While transport has 221 typically been lumped in with session descriptions, performing this 222 separation it provides additional flexibility. In protocols that 223 decouple session descriptions from transport, such as Jingle, the 224 transport information can be sent separately; in protocols that 225 don't, such as SIP, the information can be easily aggregated and 226 recombined. Sending transport information separately can allow for 227 faster ICE and DTLS startup, since the necessary roundtrips can occur 228 while waiting for the remote side to accept the session. 230 The JSEP approach does come with a minor downside. As the application 231 now is responsible for driving the signaling state machine, slightly 232 more application code is necessary to perform call setup; the 233 application must call the right APIs at the right times, and convert 234 the session desciptions and ICE information into the defined messages 235 of its chosen signaling protocol, instead of simply forwarding the 236 messages emitted from the browser. 238 One way to mitigate this is to provide a Javascript library that 239 hides this complexity from the developer, which would implement the 240 state machine and serialization of the desired signaling protocol. 241 For example, this library could convert easily adapt the JSEP API 242 into the exact ROAP API, thereby implementing the ROAP signaling 243 protocol. Such a library could of course also implement other popular 244 signaling protocols, including SIP or Jingle. In this fashion we can 245 enable greater control for the experienced developer without forcing 246 any additional complexity on the novice developer. 248 3. Other Approaches Considered 250 Another approach that was considered for JSEP was to move the 251 mechanism for generating offers and answers out of the browser as 252 well. This approach would add a getCapabilities API which would 253 provide the application with the information it needed in order to 254 generate session descriptions. This increases the amount of work that 255 the application needs to do; it needs to know how to generate session 256 descriptions from capabilities, and especially how to generate the 257 correct answer from an arbitrary offer and available capabilities. 258 While this could certainly be addressed by using a library like the 259 one mentioned above, some experimentation also indicates that coming 260 up with a sufficiently complete getCapabilities API is a nontrivial 261 undertaking. Nevertheless, if we wanted to go down this road, JSEP 262 makes it significantly easier; if a getCapabilities API is added in 263 the future, the application can generate session descriptions 264 accordingly and pass those to the 265 setLocalDescription/setRemoteDescription APIs added by JSEP. (Even 266 with JSEP, an application could still perform its own browser 267 fingerprinting and generate approximate session descriptions as a 268 result.) 270 Note also that while JSEP transfers more control to Javascript, it is 271 not intended to be an example of a "low-level" API. The general 272 argument against a low-level API is that there are too many necessary 273 API points, and they can be called in any order, leading to something 274 that is hard to specify and test. In the approach proposed here, 275 control is performed via session descriptions; this requires only a 276 few APIs to handle these descriptions, and they are evaluated in a 277 specific fashion, which reduces the number of possible states and 278 interactions. 280 4. Semantics and Syntax 282 4.1. Signaling Model 284 JSEP does not specify a particular signaling model or state machine, 285 other than the generic need to exchange RFC 3264 offers and answers 286 in order for both sides of the session to know how to conduct the 287 session. JSEP provides mechanisms to create offers and answers, as 288 well as to apply them to a PeerConnection. However, the actual 289 mechanism by which these offers and answers are communicated to the 290 remote side, including addressing, retransmission, forking, and glare 291 handling, is left entirely up to the application. 293 4.2. Session Descriptions 295 In order to establish the media plane, PeerConnection needs specific 296 parameters to indicate what to transmit to the remote side, as well 297 as how to handle the media that is received. These parameters are 298 determined by the exchange of session descriptions in offers and 299 answers, and there are certain details to this process that must be 300 handled in the JSEP APIs. 302 Whether a session description was sent or received affects the 303 meaning of that description. For example, the list of codecs sent to 304 a remote party indicates what the local side is willing to decode, 305 and what the remote party should send. Not all parameters follow this 306 rule; the SRTP parameters [RFC4568] sent to a remote party indicate 307 what the local side will use to encrypt, and thereby how the remote 308 party should expect to receive. 310 In addition, various RFCs put different conditions on the format of 311 offers versus answers. For example, a offer may propose multiple SRTP 312 configurations, but an answer may only contain a single SRTP 313 configuration. 315 Lastly, while the exact media parameters are only known only after a 316 offer and an answer have been exchanged, it is possible for the 317 offerer to receive media after they have sent an offer and before 318 they have received an answer. To properly process incoming media in 319 this case, the offerer's media handler must be aware of the details 320 of the offerer before the answer arrives. 322 Therefore, in order to handle session descriptions properly, 323 PeerConnection needs: 325 1. To know if a session description pertains to the local or 326 remote side. 328 2. To know if a session description is an offer or an answer. 330 3. To allow the offer to be specified independently of the answer. 332 JSEP addresses this by adding both a setLocalDescription and a 333 setRemoteDescription method, and both these methods take as a first 334 parameter either the value SDP_OFFER, SDP_PRANSWER (for a non-final 335 answer) or SDP_ANSWER (for a final answer). This satisfies the 336 requirements listed above for both the offerer, who first calls 337 setLocalDescription(SDP_OFFER, sdp) and then later 338 setRemoteDescription(SDP_ANSWER, sdp), as well as for the answerer, 339 who first calls setRemoteDescription(SDP_OFFER, sdp) and then later 340 setLocalDescription(SDP_ANSWER, sdp). 342 While it could be possible to implicitly determine the value of the 343 offer/answer argument inside of PeerConnection, requiring it to be 344 specified explicitly seems substantially more robust, allowing 345 invalid combinations (i.e. an answer before an offer) to generate an 346 appropriate error. 348 4.3. Session Description Format 350 In the current WebRTC specification, session descriptions are 351 formatted as SDP messages. While this format is not optimal for 352 manipulation from Javascript, it is widely accepted, and frequently 353 updated with new features. Any alternate encoding of session 354 descriptions would have to keep pace with the changes to SDP, at 355 least until the time that this new encoding eclipsed SDP in 356 popularity. As a result, JSEP continues to use SDP as the internal 357 representation for its session descriptions. 359 However, to simplify Javascript processing, and provide for future 360 flexibility, the SDP syntax is encapsulated within a 361 SessionDescription object, which can be constructed from SDP, and be 362 serialized out to SDP. If we were able to agree on a JSON format for 363 session descriptions, we could easily enable this object to 364 generate/expect JSON. 366 Other methods may be added to SessionDescription in the future to 367 simplify handling of SessionDescriptions from Javascript. 369 4.4. Separation of Signaling and ICE State Machines 371 Previously, PeerConnection operated two state machines, referred to 372 in the spec as an "ICE Agent", which handles the establishment of 373 peer-to-peer connectivity, and an "SDP Agent", which handles the 374 state of the offer-answer signaling. The states of these state 375 machines were exposed through the iceState and sdpState attributes on 376 PeerConnection, with an additional readyState attribute that 377 reflected the high-level state of the PeerConnection. 379 JSEP does away with the SDP Agent within the browser; this 380 functionality is now controlled directly by the application, which 381 uses the setLocalDescription and setRemoteDescription APIs to tell 382 PeerConnection what SDP has been negotiated. The ICE Agent remains in 383 the browser, as it still needs to perform gathering of candidates, 384 connectivity checking, and related ICE functionality. 386 The net effect of this is that sdpState goes away, and 387 processSignalingMessage becomes processIceMessage, which now 388 specifically handles incoming ICE candidates. To allow the 389 application to control exactly when it wants to start ICE negotiation 390 (e.g. either on receipt of the call, or only after accepting the 391 call), a startIce method has been added. 393 4.5. ICE Candidate Trickling 395 Candidate trickling is a technique through which a caller may 396 incrementally provide candidates to the callee after the initial 397 offer has been dispatched. This allows the callee to begin acting 398 upon the call and setting up the ICE (and perhaps DTLS) connections 399 immediately, without having to wait for the caller to allocate all 400 possible candidates, resulting in faster call startup in many cases. 402 JSEP supports optional candidate trickling by providing APIs that 403 provide control and feedback on the ICE candidate gathering process. 404 Applications that support candidate trickling can send the initial 405 offer immediately and send individual candidates when they get a 406 callback with a new candidate; applications that do not support this 407 feature can simply wait for the callback that indicates gathering is 408 complete, and simply create and send their offer, with all the 409 candidates, at this time. 411 To be clear, aplications that do not make use of candidate tricking 412 can ignore processIceMessage entirely, and use IceCallback solely to 413 indicate when candidate gathering is complete. 415 4.6. ICE Candidate Format 417 As with session descriptions, we choose to provide an IceCandidate 418 object that provides some abstraction, but can be easily converted 419 to/from SDP a=candidate lines. 421 The IceCandidate object has a field to indicate which m= line it 422 should be associated with, and a method to convert to a SDP 423 representation, ex: 425 a=candidate:1 1 UDP 1694498815 66.77.88.99 10000 typ host 427 Currently, a=candidate lines are the only thing that are contained 428 within IceCandidate, as this is the only information that is needed 429 that is not present in the initial offer (i.e. for trickle 430 candidates). 432 5. Media Setup Overview 434 The example here shows a typical call setup using the JSEP model. We 435 assume the following architecture in this example, where UA is 436 synonymous with "browser", and JS is synonymous with "web 437 application": 439 OffererUA <-> OffererJS <-> WebServer <-> AnswererJS <-> AnswererUA 441 5.1. Initiating the Session 443 The initiator creates a PeerConnection, installs its IceCallback, and 444 adds the desired MediaStreams (presumably obtained via getUserMedia). 445 The PeerConnection is in the NEW state. 447 OffererJS->OffererUA: var pc = new PeerConnection(config, iceCb); 448 OffererJS->OffererUA: pc.addStream(stream); 450 5.1.1. Generating An Offer 452 The initiator then creates a session description to offer to the 453 callee. This description includes the codecs and other necessary 454 session parameters, as well as information about each of the streams 455 that has been added (e.g. SSRC, CNAME, etc.) The created description 456 includes all parameters that the offerer's UA supports; if the 457 initiator wants to influence the created offer, they can pass in a 458 MediaHints object to createOffer that allows for customization (e.g. 459 if the initiator wants to receive but not send video). The initiator 460 can also directly manipulate the created session description as well, 461 perhaps if it wants to change the priority of the offerered codecs. 463 OffererJS->OffererUA: var offer = pc.createOffer(null); 465 5.1.2. Applying the Offer 467 The initiator then instructs the PeerConnection to use this offer as 468 the local description for this session, i.e. what codecs it will use 469 for received media, what SRTP keys it will use for sending media (if 470 using SDES), etc. In order that the UA handle the description 471 properly, the initiator marks it as an offer when calling 472 setLocalDescription; this indicates to the UA that multiple 473 capabilities have been offered, but this set may be pared back later, 474 when the answer arrives. 476 Since the local user agent must be prepared to receive media upon 477 applying the offer, this operation will cause local decoder resources 478 to be allocated, based on the codecs indicated in the offer. 480 OffererJS->OffererUA: pc.setLocalDescription(SDP_OFFER, offer); 482 5.1.3. Initiating ICE 484 The initiator can now start the ICE process of candidate generation 485 and connectivity checking. This results in callbacks to the 486 application's IceCallback. Candidates are provided to the IceCallback 487 as they are allocated, with the |moreToFollow| argument set to true 488 if there are still allocations pending; when the last allocation 489 completes or times out, this callback will be invoked with 490 |moreToFollow| set to false. 492 OffererJS->OffererUA: pc.startIce(); 493 OffererUA->OffererJS: iceCallback(candidate, ...); 495 5.1.4. Serializing the Offer and Candidates 497 At this point, the offerer is ready to send its offer to the callee 498 using its preferred signaling protocol. Depending on the protocol, it 499 can either send the initial session description first, and then 500 "trickle" the ICE candidates as they are given to the application, or 501 it can wait for all the ICE candidates to be collected, and then send 502 the offer and list of candidates all at once. 504 5.2. Receiving the Session 506 Through the chosen signaling protocol, the recipient is notified of 507 an incoming session request. It creates a PeerConnection, and 508 installs its own IceCallback. 510 AnswererJS->AnswererUA: var pc = new PeerConnection(config, iceCb); 512 5.2.1. Receiving the Offer 514 The recipient converts the received offer from its signaling protocol 515 into SDP format, and supplies it to its PeerConnection, again marking 516 it as an offer. As a remote description, the offer indicates what 517 codecs the remote side wants to use for receiving, as well as what 518 SRTP keys it will use for sending. The setting of the remote 519 description causes callbacks to be issued, informing the application 520 of what kinds of streams are present in the offer. 522 This step will also cause encoder resources to be allocated, based on 523 the codecs specified in |offer|. 525 AnswererJS->AnswererUA: pc.setRemoteDescription(SDP_OFFER, offer); 526 AnswererUA->AnswererJS: onAddStream(stream); 528 5.2.2. Initiating ICE 530 The recipient then starts its own ICE state machine, to allow 531 connectivity to be established as quickly as possible. 533 AnswererJS->AnswererUA: pc.startIce(); 534 AnswererUA->AnswererJS: iceCallback(candidate, ...); 536 5.2.3. Handling ICE Messages 538 If ICE candidates from the remote site were included in the offer, 539 the ICE Agent will automatically start trying to use them. Otherwise, 540 if ICE candidates are sent separately, they are passed into the 541 PeerConnection when they arrive. 543 AnswererJS->AnswererUA: pc.processIceMessage(candidate); 545 5.2.4. Generating the Answer 547 Once the recipient has decided to accept the session, it generates an 548 answer session description. This process performs the appropriate 549 intersection of codecs and other parameters to generate the correct 550 answer. As with the offer, MediaHints can be provided to influence 551 the answer that is generated, and/or the application can post-process 552 the answer manually. 554 AnswererJS->AnswererUA: pc.createAnswer(offer, null); 556 5.2.5. Applying the Answer 558 The recipient then instructs the PeerConnection to use the answer as 559 its local description for this session, i.e. what codecs it will use 560 to receive media, etc. It also marks the description as an answer, 561 which tells the UA that these parameters are final. This causes the 562 PeerConnection to move to the ACTIVE state, and transmission of media 563 by the answerer to start. 565 AnswererJS->AnswererUA: pc.setLocalDescription(SDP_ANSWER, answer); 566 AnswererUA->OffererUA: 568 5.2.6. Serializing the Answer 570 As with the offer, the answer (with or without candidates) is now 571 converted to the desired signaling format and sent to the initiator. 573 5.3. Completing the Session 575 5.3.1. Receiving the Answer 577 The initiator converts the answer from the signaling protocol and 578 applies it as the remote description, marking it as an answer. This 579 causes the PeerConnection to move to the ACTIVE state, and 580 transmission of media by the offerer to start. 582 OffererJS->OffererUA: pc.setRemoteDescription(SDP_ANSWER, answer); 583 OffererUA->AnswererUA: 585 5.4. Updates to the Session 587 Updates to the session are handled with a new offer/answer exchange. 588 However, since media will already be flowing at this point, the new 589 offerer needs to support both its old session description as well as 590 the new one it has offered, until the change is accepted by the 591 remote side. 593 Note also that in an update scenario, the roles may be reversed, i.e. 594 the update offerer can be different than the original offerer. 596 6. Proposed WebRTC API changes 598 6.1. PeerConnection API 599 The text below indicates the recommended changes to the 600 PeerConnection API to implement the JSEP functionality. Methods 601 marked with a [+] are new/proposed; methods marked with a [-] have 602 been removed in this proposal. 604 [Constructor (in DOMString configuration, in IceCallback iceCb)] 605 interface PeerConnection { 606 // creates a blob of SDP to be provided as an offer. 607 [+] SessionDescription createOffer (MediaHints hints); 608 // creates a blob of SDP to be provided as an answer. 609 [+] SessionDescription createAnswer (DOMString offer, 610 MediaHints hints); 611 // actions, for setLocalDescription/setRemoteDescription 612 [+] const unsigned short SDP_OFFER = 0x100; 613 [+] const unsigned short SDP_PRANSWER = 0x200; 614 [+] const unsigned short SDP_ANSWER = 0x300; 615 // sets the local session description 616 [+] void setLocalDescription (unsigned short action, 617 SessionDescription desc); 618 // sets the remote session description 619 [+] void setRemoteDescription (unsigned short action, 620 SessionDescription desc); 621 // returns the current local session description 622 [+] readonly SessionDescription localDescription; 623 // returns the current remote session description 624 [+] readonly SessionDescription remoteDescription; 625 [-] void processSignalingMessage (DOMString message); 626 const unsigned short NEW = 0; // initial state 627 [+] const unsigned short OPENING = 1; // local or remote desc set 628 const unsigned short ACTIVE = 2; // local and remote desc set 629 const unsigned short CLOSED = 3; // ended state 630 readonly attribute unsigned short readyState; 631 // starts ICE connection/handshaking 632 [+] void startIce (optional IceOptions options); 633 // processes received ICE information 634 [+] void processIceMessage (IceCandidate candidate); 635 const unsigned short ICE_GATHERING = 0x100; 636 const unsigned short ICE_WAITING = 0x200; 637 const unsigned short ICE_CHECKING = 0x300; 638 const unsigned short ICE_CONNECTED = 0x400; 639 const unsigned short ICE_COMPLETED = 0x500; 640 const unsigned short ICE_FAILED = 0x600; 641 const unsigned short ICE_CLOSED = 0x700; 642 readonly attribute unsigned short iceState; 643 [-] const unsigned short SDP_IDLE = 0x1000; 644 [-] const unsigned short SDP_WAITING = 0x2000; 645 [-] const unsigned short SDP_GLARE = 0x3000; 646 [-] readonly attribute unsigned short sdpState; 647 void addStream (MediaStream stream, MediaStreamHints hints); 648 void removeStream (MediaStream stream); 649 readonly attribute MediaStream[] localStreams; 650 readonly attribute MediaStream[] remoteStreams; 651 void close (); 652 [ rest of interface omitted ] 653 }; 655 [Constructor (in DOMString sdp)] 656 interface SessionDescription { 657 // adds the specified candidate to the description 658 void addCandidate(IceCandidate candidate); 659 // serializes the description to SDP 660 DOMString toSdp(); 661 }; 663 [Constructor (in DOMString label, in DOMString candidateLine)] 664 interface IceCandidate { 665 // the m= line this candidate is associated with 666 readonly DOMString label; 667 // creates a SDP-ized form of this candidate 668 DOMString toSdp(); 669 }; 671 6.1.1 MediaHints 673 MediaHints is an object that can be passed into createOffer or 674 createAnswer to affect the type of offer/answer that is generated. 676 The following properties can be set on MediaHints: 678 has_audio: boolean 680 Indicates whether we want to receive audio; defaults to true if we 681 have audio streams, else false 683 has_video: boolean 685 Indicates whether we want to receive video; defaults to true if we 686 have video streams, else false 688 As an example, MediaHints could be used to create a session that 689 transmits only audio, but is able to receive video from the remote 690 side, by forcing the inclusion of a m=video line even when no video 691 sources are provided. 693 6.1.2 createOffer 694 The createOffer method generates a blob of SDP that contains a RFC 695 3264 offer with the supported configurations for the session, 696 including descriptions of the local MediaStreams attached to this 697 PeerConnection, the codec/RTP/RTCP options supported by this 698 implementation, and any candidates that have been gathered by the ICE 699 Agent. The |hints| parameter may be supplied to provide additional 700 control over the generated offer. 702 As an offer, the generated SDP will contain the full set of 703 capabilities supported by the session (as opposed to an answer, which 704 will include only a specific negotiated subset to use); for each SDP 705 line, the generation of the SDP must follow the appropriate process 706 for generating an offer. In the event createOffer is called after the 707 session is established, createOffer will generate an offer that is 708 compatible with the current session, incorporating any changes that 709 have been made to the session since the last complete offer-answer 710 exchange, such as addition or removal of streams. If no changes have 711 been made, the offer will be identical to the current local 712 description. 714 Session descriptions generated by createOffer must be immediately 715 usable by setLocalDescription; if a system has limited resources 716 (e.g. a finite number of decoders), createOffer should return an 717 offer that reflects the current state of the system, so that 718 setLocalDescription will succeed when it attempts to acquire those 719 resources. 721 Session descriptions generated by createOffer must be immediately 722 usable by setLocalDescription; if a system has limited resources 723 (e.g. a finite number of decoders), createOffer should return an 724 offer that reflects the current state of the system, so that 725 setLocalDescription will succeed when it attempts to acquire those 726 resources. 728 Calling this method does not change the state of the PeerConnection; 729 its use is not required. 731 A TBD exception is thrown if the |hints| parameter is malformed. 733 6.1.3 createAnswer 735 The createAnswer method generates a blob of SDP that contains a RFC 736 3264 SDP answer with the supported configuration for the session that 737 is compatible with the parameters supplied in |offer|. Like 738 createOffer, the returned blob contains descriptions of the local 739 MediaStreams attached to this PeerConnection, the codec/RTP/RTCP 740 options negotiated for this session, and any candidates that have 741 been gathered by the ICE Agent. The |hints| parameter may be supplied 742 to provide additional control over the generated answer. 744 As an answer, the generated SDP will contain a specific configuration 745 that specifies how the media plane should be established. For each 746 SDP line, the generation of the SDP must follow the appropriate 747 process for generating an answer. 749 Session descriptions generated by createAnswer must be immediately 750 usable by setRemoteDescription; like createOffer, the returned 751 description should reflect the current state of the system. 753 Session descriptions generated by createAnswer must be immediately 754 usable by setRemoteDescription; like createOffer, the returned 755 description should reflect the current state of the system. 757 Calling this method does not change the state of the PeerConnection; 758 its use is not required. 760 A TBD exception is thrown if the |hints| parameter is malformed, or 761 the |offer| parameter is missing or malformed. 763 6.1.4 SDP_OFFER, SDP_PRANSWER, and SDP_ANSWER 765 The SDP_XXXX enums serve as arguments to setLocalDescription and 766 setRemoteDescription. They provide information as to how the 767 |description| parameter should be parsed, and how the media state 768 should be changed. 770 SDP_OFFER indicates that a description should be parsed as an offer; 771 said description may include many possible media configurations. A 772 description used as a SDP_OFFER may be applied anytime the 773 PeerConnection is in a stable state, or as an update to a previously 774 sent but unanswered SDP_OFFER. 776 SDP_PRANSWER indicates that a description should be parsed as an 777 answer, but not a final answer, and so should not result in the 778 starting of media transmission. A description used as a SDP_PRANSWER 779 may be applied as a response to a SDP_OFFER, or an update to a 780 previously sent SDP_PRANSWER. 782 SDP_ANSWER indicates that a description should be parsed as an 783 answer, and the offer-answer exchange should be considered complete. 784 A description used as a SDP_ANSWER may be applied as a response to a 785 SDP_OFFER, or an update to a previously send SDP_PRANSWER. 787 6.1.5 setLocalDescription 789 The setLocalDescription method instructs the PeerConnection to apply 790 the supplied SDP blob as its local configuration. The |type| 791 parameter indicates whether the blob should be processed as an offer 792 (SDP_OFFER), provisional answer (SDP_PRANSWER), or final answer 793 (SDP_ANSWER); offers and answers are checked differently, using the 794 various rules that exist for each SDP line. 796 This API changes the local media state; among other things, it sets 797 up local resources for receiving and decoding media. In order to 798 successfully handle scenarios where the application wants to offer to 799 change from one media format to a different, incompatible format, the 800 PeerConnection must be able to simultaneously support use of both the 801 old and new local descriptions (e.g. support codecs that exist in 802 both descriptions) until a final answer is received, at which point 803 the PeerConnection can fully adopt the new local description, or roll 804 back to the old description if the remote side denied the change. 806 Changes to the state of media transmission will only occur when a 807 final answer is successfully applied. 809 A TBD exception is thrown if |description| is invalid. A TBD 810 exception is thrown if there are insufficient local resources to 811 apply |description|. 813 6.1.6 setRemoteDescription 815 The setRemoteDescription method instructs the PeerConnection to apply 816 the supplied SDP blob as the desired remote configuration. As in 817 setLocalDescription, the |type| parameter indicates how the blob 818 should be processed. 820 This API changes the local media state; among other things, it sets 821 up local resources for sending and encoding media. 823 Changes to the state of media transmission will only occur when a 824 final answer is successfully applied. 826 A TBD exception is thrown if |description| is invalid. A TBD 827 exception is thrown if there are insufficient local resources to 828 apply |description|. 830 6.1.7 localDescription 832 The localDescription method returns a copy of the current local 833 configuration, i.e. what was most recently passed to 834 setLocalDescription, plus any local candidates that have been 835 generated by the ICE Agent. 837 A null object will be returned if the local description has not yet 838 been established. 840 6.1.8 remoteDescription 842 The remoteDescription method returns a copy of the current remote 843 configuration, i.e. what was most recently passed to 844 setRemoteDescription, plus any remote candidates that have been 845 supplied via processIceMessage. 847 A null object will be returned if the remote description has not yet 848 been established. 850 6.1.9 IceOptions 852 IceOptions is an object that can be passed into startIce to restrict 853 the candidates that are provided to the application and used for 854 connectivity checks. This can be useful if the application wants to 855 only use TURN candidates for privacy reasons, or only local + STUN 856 candidates for cost reasons. 858 The following properties can be set on IceOptions: 860 use_candidates: "all", "no_relay", "only_relay" 862 Indicates what types of local candidates should be used; defaults 863 to "all" 865 6.1.10 startIce 867 The startIce method starts or updates the ICE Agent process of 868 gathering local candidates and pinging remote candidates. The 869 |options| argument can be used to restrict which types of local 870 candidates are provided to the application and used for pinging; this 871 can be used to limit the use of TURN candidates by a callee to avoid 872 leaking location information prior to the call being accepted. 874 This call may result in a change to the state of the ICE Agent, and 875 may result in a change to media state if it results in connectivity 876 being established. 878 A TBD exception will be thrown if |options| is malformed. 880 6.1.11 processIceMessage 882 The processIceMessage method provides a remote candidate to the ICE 883 Agent, which will be added to the remote description. If startIce has 884 been called, connectivity checks will be sent to the new candidates. 886 This call will result in a change to the state of the ICE Agent, and 887 may result in a change to media state if it results in connectivity 888 being established. 890 A TBD exception will be thrown if |candidate| is missing or 891 malformed. 893 7. Example API Flows 895 Below are several sample flows for the new PeerConnection and library 896 APIs, demonstrating when the various APIs are called in different 897 situations and with various transport protocols. 899 7.1. Call using ROAP 901 This example demonstrates a ROAP call, without the use of trickle 902 candidates. 904 // Call is initiated toward Answerer 905 OffererJS->OffererUA: pc = new PeerConnection(); 906 OffererJS->OffererUA: pc.addStream(localStream, null); 907 OffererJS->OffererUA: pc.startIce(); 908 OffererUA->OffererJS: iceCallback(candidate, false); 909 OffererJS->OffererUA: offer = pc.createOffer(null); 910 OffererJS->OffererUA: pc.setLocalDescription(SDP_OFFER, offer.toSdp()); 911 OffererJS->AnswererJS: {"type":"OFFER", "sdp":""} 913 // OFFER arrives at Answerer 914 AnswererJS->AnswererUA: pc = new PeerConnection(); 915 AnswererJS->AnswererUA: pc.setRemoteDescription(SDP_OFFER, msg.sdp); 916 AnswererUA->AnswererJS: onaddstream(remoteStream); 917 AnswererJS->AnswererUA: pc.startIce(); 918 AnswererUA->OffererUA: iceCallback(candidate, false); 920 // Answerer accepts call 921 AnswererJS->AnswererUA: peer.addStream(localStream, null); 922 AnswererJS->AnswererUA: answer = peer.createAnswer(msg.offer, null); 923 AnswererJS->AnswererUA: peer.setLocalDescription(SDP_ANSWER, answer); 924 AnswererJS->OffererJS: {"type":"ANSWER","sdp":""} 926 // ANSWER arrives at Offerer 927 OffererJS->OffererUA: peer.setRemoteDescription(ANSWER, answer); 928 OffererUA->OffererJS: onaddstream(remoteStream); 930 // ICE Completes (at Answerer) 931 AnswererUA->AnswererJS: onopen(); 932 AnswererUA->OffererUA: Media 933 // ICE Completes (at Offerer) 934 OffererUA->OffererJS: onopen(); 935 OffererJS->AnswererJS: {"type":"OK" } 936 OffererUA->AnswererUA: Media 938 7.2. Call using XMPP 940 This example demonstrates an XMPP call, making use of trickle 941 candidates. 943 // Call is initiated toward Answerer 944 OffererJS->OffererUA: pc = new PeerConnection(); 945 OffererJS->OffererUA: pc.addStream(localStream, null); 946 OffererJS->OffererUA: offer = pc.createOffer(null); 947 OffererJS->OffererUA: pc.setLocalDescription(SDP_OFFER, offer); 948 OffererJS: xmpp = createSessionInitiate(offer); 949 OffererJS->AnswererJS: 951 OffererJS->OffererUA: pc.startIce(); 952 OffererUA->OffererJS: iceCallback(cand); 953 OffererJS: createTransportInfo(cand, ...); 954 OffererJS->AnswererJS: 956 // session-initiate arrives at Answerer 957 AnswererJS->AnswererUA: pc = new PeerConnection(); 958 AnswererJS: offer = parseSessionInitiate(xmpp); 959 AnswererJS->AnswererUA: pc.setRemoteDescription(SDP_OFFER, offer); 960 AnswererUA->AnswererJS: onaddstream(remoteStream); 962 // transport-infos arrive at Answerer 963 AnswererJS->AnswererUA: candidates = parseTransportInfo(xmpp); 964 AnswererJS->AnswererUA: pc.processIceMessage(candidates); 965 AnswererJS->AnswererUA: pc.startIce(); 966 AnswererUA->AnswererJS: iceCallback(cand, ...) 967 AnswererJS: createTransportInfo(cand); 968 AnswererJS->OffererJS: 970 // transport-infos arrive at Offerer 971 OffererJS->OffererUA: candidates = parseTransportInfo(xmpp); 972 OffererJS->OffererUA: pc.processIceMessage(candidates); 974 // Answerer accepts call 975 AnswererJS->AnswererUA: peer.addStream(localStream, null); 976 AnswererJS->AnswererUA: answer = peer.createAnswer(offer, null); 977 AnswererJS: xmpp = createSessionAccept(answer); 978 AnswererJS->AnswererUA: pc.setLocalDescription(SDP_ANSWER, answer); 979 AnswererJS->OffererJS: 980 // session-accept arrives at Offerer 981 OffererJS: answer = parseSessionAccept(xmpp); 982 OffererJS->OffererUA: peer.setRemoteDescription(ANSWER, answer); 983 OffererUA->OffererJS: onaddstream(remoteStream); 985 // ICE Completes (at Answerer) 986 AnswererUA->AnswererJS: onopen(); 987 AnswererUA->OffererUA: Media 989 // ICE Completes (at Offerer) 990 OffererUA->OffererJS: onopen(); 991 OffererUA->AnswererUA: Media 993 7.3. Adding video to a call, using XMPP 995 This example demonstrates an XMPP call, where the XMPP content-add 996 mechanism is used to add video media to an existing session. For 997 simplicity, candidate exchange is not shown. 999 Note that the offerer for the change to the session may be different 1000 than the original call offerer. 1002 // Offerer adds video stream 1003 OffererJS->OffererUA: pc.addStream(videoStream) 1004 OffererJS->OffererUA: offer = pc.createOffer(null); 1005 OffererJS: xmpp = createContentAdd(offer); 1006 OffererJS->OffererUA: pc.setLocalDescription(SDP_OFFER, offer); 1007 OffererJS->AnswererJS: 1009 // content-add arrives at Answerer 1010 AnswererJS: offer = parseContentAdd(xmpp); 1011 AnswererJS->AnswererUA: pc.setRemoteDescription(SDP_OFFER, offer); 1012 AnswererJS->AnswererUA: answer = pc.createAnswer(offer, null); 1013 AnswererJS->AnswererUA: pc.setLocalDescription(SDP_ANSWER, answer); 1014 AnswererJS: xmpp = createContentAccept(answer); 1015 AnswererJS->OffererJS: 1017 // content-accept arrives at Offerer 1018 OffererJS: answer = parseContentAccept(xmpp); 1019 OffererJS->OffererUA: pc.setRemoteDescription(SDP_ANSWER, answer); 1021 7.4. Simultaneous add of video streams, using XMPP 1023 This example demonstrates an XMPP call, where new video sources are 1024 added at the same time to a call that already has video; since adding 1025 these sources only affects one side of the call, there is no 1026 conflict. The XMPP description-info mechanism is used to indicate the 1027 new sources to the remote side. 1029 // Offerer and "Answerer" add video streams at the same time 1030 OffererJS->OffererUA: pc.addStream(offererVideoStream2) 1031 OffererJS->OffererUA: offer = pc.createOffer(null); 1032 OffererJS: xmpp = createDescriptionInfo(offer); 1033 OffererJS->OffererUA: pc.setLocalDescription(SDP_OFFER, offer); 1034 OffererJS->AnswererJS: 1036 AnswererJS->AnswererUA: pc.addStream(answererVideoStream2) 1037 AnswererJS->AnswererUA: offer = pc.createOffer(null); 1038 AnswererJS: xmpp = createDescriptionInfo(offer); 1039 AnswererJS->AnswererUA: pc.setLocalDescription(SDP_OFFER, offer); 1040 AnswererJS->OffererJS: 1042 // description-info arrives at "Answerer", and is acked 1043 AnswererJS: offer = parseDescriptionInfo(xmpp); 1044 AnswererJS->OffererJS: // ack 1050 // ack arrives at Offerer; remote offer is used as an answer 1051 OffererJS->OffererUA: pc.setRemoteDescription(SDP_ANSWER, offer); 1053 // ack arrives at "Answerer"; remote offer is used as an answer 1054 AnswererJS->AnswererUA: pc.setRemoteDescription(SDP_ANSWER, offer); 1056 7.5. Call using SIP 1058 This example demonstrates a simple SIP call (e.g. where the client 1059 talks to a SIP proxy over WebSockets). 1061 // Call is initiated toward Answerer 1062 OffererJS->OffererUA: pc = new PeerConnection(); 1063 OffererJS->OffererUA: pc.addStream(localStream, null); 1064 OffererJS->OffererUA: pc.startIce(); 1065 OffererUA->OffererJS: iceCallback(candidate, false); 1066 OffererJS->OffererUA: offer = pc.createOffer(null); 1067 OffererJS->OffererUA: pc.setLocalDescription(SDP_OFFER, offer); 1068 OffererJS: sip = createInvite(offer);- 1069 OffererJS->AnswererJS: SIP INVITE w/ SDP 1071 // INVITE arrives at Answerer 1072 AnswererJS->AnswererUA: pc = new PeerConnection(); 1073 AnswererJS: offer = parseInvite(sip); 1074 AnswererJS->AnswererUA: pc.setRemoteDescription(SDP_OFFER, offer); 1075 AnswererUA->AnswererJS: onaddstream(remoteStream); 1076 AnswererJS->AnswererUA: pc.startIce(); 1077 AnswererUA->OffererUA: iceCallback(candidate, false); 1079 // Answerer accepts call 1080 AnswererJS->AnswererUA: peer.addStream(localStream, null); 1081 AnswererJS->AnswererUA: answer = peer.createAnswer(offer, null); 1082 AnswererJS: sip = createResponse(200, answer); 1083 AnswererJS->AnswererUA: peer.setLocalDescription(SDP_ANSWER, answer); 1084 AnswererJS->OffererJS: 200 OK w/ SDP 1086 // 200 OK arrives at Offerer 1087 OffererJS: answer = parseResponse(sip); 1088 OffererJS->OffererUA: peer.setRemoteDescription(ANSWER, answer); 1089 OffererUA->OffererJS: onaddstream(remoteStream); 1090 OffererJS->AnswererJS: ACK 1092 // ICE Completes (at Answerer) 1093 AnswererUA->AnswererJS: onopen(); 1094 AnswererUA->OffererUA: Media 1096 // ICE Completes (at Offerer) 1097 OffererUA->OffererJS: onopen(); 1098 OffererUA->AnswererUA: Media 1100 7.6. Handling early media (e.g. 1-800-FEDEX), using SIP 1102 This example demonstrates how early media could be handled; for 1103 simplicity, only the offerer side of the call is shown. 1105 // Call is initiated toward Answerer 1106 OffererJS->OffererUA: pc = new PeerConnection(); 1107 OffererJS->OffererUA: pc.addStream(localStream, null); 1108 OffererJS->OffererUA: pc.startIce(); 1109 OffererUA->OffererJS: iceCallback(candidate, false); 1110 OffererJS->OffererUA: offer = pc.createOffer(null); 1111 OffererJS->OffererUA: pc.setLocalDescription(SDP_OFFER, offer); 1112 OffererJS: sip = createInvite(offer); 1113 OffererJS->AnswererJS: SIP INVITE w/ SDP 1115 // 180 Ringing is received by offerer, w/ SDP 1116 OffererJS: answer = parseResponse(sip); 1117 OffererJS->OffererUA: pc.setRemoteDescription(SDP_PRANSWER, answer); 1118 OffererUA->OffererJS: onaddstream(remoteStream); 1120 // ICE Completes (at Offerer) 1121 OffererUA->OffererJS: onopen(); 1122 OffererUA->AnswererUA: Media 1123 // 200 OK arrives at Offerer 1124 OffererJS: answer = parseResponse(sip); 1125 OffererJS->OffererUA: pc.setRemoteDescription(SDP_ANSWER, answer); 1126 OffererJS->AnswererJS: ACK 1128 8. Example Application 1130 The following example demonstrates a simple video calling 1131 application, roughly corresponding to the flow in Example 7.1. 1133 var signalingChannel = createSignalingChannel(); 1134 var pc = null; 1135 var hasCandidates = false; 1137 function start(isCaller) { 1138 // create a PeerConnection and hook up the IceCallback 1139 pc = new webkitPeerConnection( 1140 "", function (candidate, moreToFollow) { 1141 if (!moreToFollow) { 1142 hasCandidates = true; 1143 maybeSignal(isCaller); 1144 } 1145 }); 1147 // get the local stream and show it in the local video element 1148 navigator.webkitGetUserMedia( 1149 {"audio": true, "video": true}, function (localStream) { 1150 selfView.src = webkitURL.createObjectURL(localStream); 1151 pc.addStream(localStream); 1152 maybeSignal(isCaller); 1153 } 1155 // once remote stream arrives, show it in the remote video element 1156 pc.onaddstream = function(evt) { 1157 remoteView.src = webkitURL.createObjectURL(evt.stream); 1158 }; 1160 // if we're the caller, create and install our offer, 1161 // and start candidate generation 1162 if (isCaller) { 1163 offer = pc.createOffer(null); 1164 pc.setLocalDescription(SDP_OFFER, offer); 1165 pc.startIce(); 1166 } 1167 } 1169 function maybeSignal(isCaller) { 1170 // only signal once we have a local stream and local candidates 1171 if (localStreams.size() == 0 || !hasCandidates) return; 1172 if (isCaller) { 1173 offer = pc.localDescription; 1174 signalingChannel.send( 1175 JSON.stringify({ "type": "offer", "sdp": offer })); 1176 } else { 1177 // if we're the callee, generate, apply, and send the answer 1178 answer = pc.createAnswer(pc.remoteDescription, null); 1179 pc.setLocalDescription(SDP_ANSWER, answer); 1180 signalingChannel.send( 1181 JSON.stringify({ "type": "answer", "sdp": answer })); 1182 } 1183 } 1185 signalingChannel.onmessage = function(evt) { 1186 var msg = JSON.parse(evt.data); 1187 if (msg.type == "offer") { 1188 // create the PeerConnection 1189 start(false); 1190 // feed the received offer into the PeerConnection and 1191 // start candidate generation 1192 pc.setRemoteDescription(PeerConnection.SDP_OFFER, msg.sdp); 1193 pc.startIce(); 1194 } else if (msg.type == "answer") { 1195 // feed the answer into the PeerConnection to complete setup 1196 pc.setRemoteDescription(PeerConnection.SDP_ANSWER, msg.sdp); 1197 } 1199 9. Security Considerations 1201 TODO 1203 10. IANA Considerations 1205 This document requires no actions from IANA. 1207 11. Acknowledgements 1209 Harald Alvestrand, Dan Burnett, Neil Stratford, Eric Rescorla, and 1210 Anant Narayanan all provided valuable feedback on this proposal. 1211 Matthew Kaufman provided the observation that keeping state out of 1212 the browser allows a call to continue even if the page is reloaded. 1213 Adam Bergvist provided a code example that served as the basis for 1214 the example in Section 8. 1216 12. References 1218 12.1. Normative References 1220 [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate 1221 Requirement Levels", BCP 14, RFC 2119, March 1997. 1223 [RFC3264] Rosenberg, J. and H. Schulzrinne, "An Offer/Answer Model 1224 with Session Description Protocol (SDP)", RFC 3264, June 2002. 1226 [RFC4566] Handley, M., Jacobson, V., and C. Perkins, "SDP: Session 1227 Description Protocol", RFC 4566, July 2006. 1229 12.2. Informative References 1231 [RFC4568] Andreasen, F., Baugher, M., and D. Wing, "Session 1232 Description Protocol (SDP) Security Descriptions for Media Streams", 1233 RFC 4568, July 2006. 1235 [RFC5245] Rosenberg, J., "Interactive Connectivity Establishment 1236 (ICE): A Protocol for Network Address Translator (NAT) Traversal for 1237 Offer/Answer Protocols", RFC 5245, April 2010. 1239 [webrtc-api] Bergkvist, Burnett, Jennings, Narayanan, "WebRTC 1.0: 1240 Real-time Communication Between Browsers", October 2011. 1242 Available at http://dev.w3.org/2011/webrtc/editor/webrtc.html 1244 Appendix A. Open Issues 1246 - Determine list of exceptions that can be thrown by each method. 1247 Leaning toward something like a PCException, a la 1248 https://developer.mozilla.org/en/IndexedDB/IDBDatabaseException 1250 - Need callback to indicate that the transport is down, e.g. 1251 ICE_DISCONNECTED or ondisconnected(). 1253 Appendix B. Change log 1255 02: Updates based on additional feedback: clarified handling of 1256 createOffer/Answer and setLocal/RemoteDescription; fixed bug in 1257 sample app. 1258 01: Updates based on IETF 82.5 feedback: simpler handing of SDP and 1259 candidates, connect()->startIce(), added more specifics on APIs, 1260 more examples, full sample application. 1261 00: Initial version; includes some improvements from W3C mailing list 1262 feedback. 1264 Authors' Addresses 1266 Justin Uberti 1267 Google 1268 5 Cambridge Center 1269 Cambridge, MA 02142 1271 Email: justin@uberti.name 1273 Cullen Jennings 1274 Cisco 1275 170 West Tasman Drive 1276 San Jose, CA 95134 1277 USA 1279 Email: fluffy@cisco.com