idnits 2.17.1 draft-ietf-rtcweb-jsep-00.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 (March 3, 2012) is 4437 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 647, but not defined == Unused Reference: 'RFC3264' is defined on line 1215, but no explicit reference was found in the text == Unused Reference: 'RFC4566' is defined on line 1218, but no explicit reference was found in the text == Unused Reference: 'RFC5245' is defined on line 1227, 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 Intended status: Standards Track C. Jennings 5 Expires: September 4, 2012 Cisco Systems, Inc. 6 March 3, 2012 8 Javascript Session Establishment Protocol 9 draft-ietf-rtcweb-jsep-00 11 Abstract 13 This document proposes a mechanism for allowing a Javascript 14 application to fully control the signaling plane of a multimedia 15 session, and discusses how this would work with existing signaling 16 protocols. 18 This document is an input document for discussion. It should be 19 discussed in the RTCWEB WG list, rtcweb@ietf.org. 21 Status of this Memo 23 This Internet-Draft is submitted in full conformance with the 24 provisions of BCP 78 and BCP 79. 26 Internet-Drafts are working documents of the Internet Engineering 27 Task Force (IETF). Note that other groups may also distribute 28 working documents as Internet-Drafts. The list of current Internet- 29 Drafts is at http://datatracker.ietf.org/drafts/current/. 31 Internet-Drafts are draft documents valid for a maximum of six months 32 and may be updated, replaced, or obsoleted by other documents at any 33 time. It is inappropriate to use Internet-Drafts as reference 34 material or to cite them other than as "work in progress." 36 This Internet-Draft will expire on July 26, 2012. 38 Copyright Notice 40 Copyright (c) 2012 IETF Trust and the persons identified as the 41 document authors. All rights reserved. 43 This document is subject to BCP 78 and the IETF Trust's Legal 44 Provisions Relating to IETF Documents 45 (http://trustee.ietf.org/license-info) in effect on the date of 46 publication of this document. Please review these documents 47 carefully, as they describe your rights and restrictions with respect 48 to this document. Code Components extracted from this document must 49 include Simplified BSD License text as described in Section 4.e of 50 the Trust Legal Provisions and are provided without warranty as 51 described in the Simplified BSD License. 53 Table of Contents 55 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 4 56 Terminology . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 57 2. JSEP Approach . . . . . . . . . . . . . . . . . . . . . . . . . 5 58 3. Other Approaches Considered . . . . . . . . . . . . . . . . . . 6 59 4. Semantics and Syntax . . . . . . . . . . . . . . . . . . . . . 7 60 4.1. Signaling Model . . . . . . . . . . . . . . . . . . . . . . 7 61 4.2. Session Descriptions . . . . . . . . . . . . . . . . . . . 7 62 4.3. Session Description Format . . . . . . . . . . . . . . . . 8 63 4.4. Separation of Signaling and ICE State Machines . . . . . . 9 64 4.5. ICE Candidate Trickling . . . . . . . . . . . . . . . . . . 9 65 4.6. ICE Candidate Format . . . . . . . . . . . . . . . . . . . 10 66 5. Media Setup Overview . . . . . . . . . . . . . . . . . . . . . 10 67 5.1. Initiating the Session . . . . . . . . . . . . . . . . . . 10 68 5.1.1. Generating An Offer . . . . . . . . . . . . . . . . . . 11 69 5.1.2. Applying the Offer . . . . . . . . . . . . . . . . . . 11 70 5.1.3. Initiating ICE . . . . . . . . . . . . . . . . . . . . 11 71 5.1.4. Serializing the Offer and Candidates . . . . . . . . . 11 72 5.2. Receiving the Session . . . . . . . . . . . . . . . . . . . 12 73 5.2.1. Receiving the Offer . . . . . . . . . . . . . . . . . . 12 74 5.2.2. Initiating ICE . . . . . . . . . . . . . . . . . . . . 12 75 5.2.3. Handling ICE Messages . . . . . . . . . . . . . . . . . 12 76 5.2.4. Generating the Answer . . . . . . . . . . . . . . . . . 12 77 5.2.5. Applying the Answer . . . . . . . . . . . . . . . . . . 13 78 5.2.6. Serializing the Answer . . . . . . . . . . . . . . . . 13 79 5.3. Completing the Session . . . . . . . . . . . . . . . . . . 13 80 5.3.1. Receiving the Answer . . . . . . . . . . . . . . . . . 13 81 5.4. Updates to the Session . . . . . . . . . . . . . . . . . . 13 82 6. Proposed WebRTC API changes . . . . . . . . . . . . . . . . . . 14 83 6.1. PeerConnection API . . . . . . . . . . . . . . . . . . . . 14 84 6.1.1 MediaHints . . . . . . . . . . . . . . . . . . . . . . . 15 85 6.1.2 createOffer . . . . . . . . . . . . . . . . . . . . . . 16 86 6.1.3 createAnswer . . . . . . . . . . . . . . . . . . . . . . 16 87 6.1.4 SDP_OFFER, SDP_PRANSWER, and SDP_ANSWER . . . . . . . . 17 88 6.1.5 setLocalDescription . . . . . . . . . . . . . . . . . . 17 89 6.1.6 setRemoteDescription . . . . . . . . . . . . . . . . . . 18 90 6.1.7 localDescription . . . . . . . . . . . . . . . . . . . . 18 91 6.1.8 remoteDescription . . . . . . . . . . . . . . . . . . . 18 92 6.1.9 IceOptions . . . . . . . . . . . . . . . . . . . . . . . 19 93 6.1.10 startIce . . . . . . . . . . . . . . . . . . . . . . . 19 94 6.1.11 processIceMessage . . . . . . . . . . . . . . . . . . . 19 95 7. Example API Flows . . . . . . . . . . . . . . . . . . . . . . . 20 96 7.1. Call using ROAP . . . . . . . . . . . . . . . . . . . . . . 20 97 7.2. Call using XMPP . . . . . . . . . . . . . . . . . . . . . . 20 98 7.3. Adding video to a call, using XMPP . . . . . . . . . . . . 22 99 7.4. Simultaneous add of video streams, using XMPP . . . . . . . 22 100 7.5. Call using SIP . . . . . . . . . . . . . . . . . . . . . . 23 101 7.6. Handling early media (e.g. 1-800-FEDEX), using SIP . . . . 24 102 8. Example Application . . . . . . . . . . . . . . . . . . . . . . 24 103 9. Security Considerations . . . . . . . . . . . . . . . . . . . . 26 104 10. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 26 105 11. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 26 106 12. References . . . . . . . . . . . . . . . . . . . . . . . . . . 26 107 12.1. Normative References . . . . . . . . . . . . . . . . . . . 26 108 12.2. Informative References . . . . . . . . . . . . . . . . . . 27 109 Appendix A. Open Issues . . . . . . . . . . . . . . . . . . . . . 27 110 Appendix B. Change log . . . . . . . . . . . . . . . . . . . . . . 27 111 Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 27 113 1. Introduction 115 The general thinking behind WebRTC call setup has been to fully 116 specify and control the media plane, but to leave the signaling plane 117 up to the application as much as possible. The rationale is that 118 different applications may prefer to use different protocols, such as 119 the existing SIP or Jingle call signaling protocols, or something 120 custom to the particular application, perhaps for a novel use case. 121 In this approach, the key information that needs to be exchanged is 122 the multimedia session description, which specifies the necessary 123 transport and media configuration information necessary to establish 124 the media plane. 126 The original spec for WebRTC attempted to implement this protocol- 127 agnostic signaling by providing a mechanism to exchange session 128 descriptions in the form of SDP blobs. Upon starting a session, the 129 browser would generate a SDP blob, which would be passed to the 130 application for transport over its preferred signaling protocol. On 131 the remote side, this blob would be passed into the browser from the 132 application, and the browser would then generate a blob of its own in 133 response. Upon transmission back to the initiator, this blob would be 134 plugged into their browser, and the handshake would be complete. 136 Experimentation with this mechanism turned up several shortcomings, 137 which generally stemmed from there being insufficient context at the 138 browser to fully determine the meaning of a SDP blob. For example, 139 determining whether a blob is an offer or an answer, or 140 differentiating a new offer from a retransmit. 142 The ROAP proposal, specified in http://tools.ietf.org/html/draft- 143 jennings-rtcweb-signaling-01, attempted to resolve these issues by 144 providing additional structure in the messaging - in essence, to 145 create a generic signaling protocol that specifies how the browser 146 signaling state machine should operate. However, even though the 147 protocol is abstracted, the state machine forces a least-common- 148 denominator approach on the signaling interactions. For example, in 149 Jingle, the call initiator can provide additional ICE candidates even 150 after the initial offer has been sent, which allows the offer to be 151 sent immediately for quicker call startup. However, in the browser 152 state machine, there is no notion of sending an updated offer before 153 the initial offer has been responded to, rendering this functionality 154 impossible. 156 While specific concerns like this could be addressed by modifying the 157 generic protocol, others would likely be discovered later. The main 158 reason this mechanism is inflexible is because it embeds a signaling 159 state machine within the browser. Since the browser generates the 160 session descriptions on its own, and fully controls the possible 161 states and advancement of the signaling state machine, modification 162 of the session descriptions or use of alternate state machines 163 becomes difficult or impossible. 165 The browser environment also has its own challenges that cause 166 problems for an embedded signaling state machine. One of these is 167 that the user may reload the web page at any time. If this happens, 168 and the state machine is being run at a server, the server can simply 169 push the current state back down to the page and resume the call 170 where it left off. If instead the state machine is run at the browser 171 end, and is instantiated within, for example, the PeerConnection 172 object, that state machine will be reinitialized when the page is 173 reloaded and the JavaScript re-executed. This actually complicates 174 the design of any interoperability service, as all cases where an 175 offer or answer has already been generated but is now "forgotten" 176 must now be handled by trying to move the client state machine 177 forward to the same state it had been in previously in order to match 178 what has already been delivered to and/or answered by the far side, 179 or handled by ensuring that aborts are cleanly handled from every 180 state and the negotiation rapidly restarted. 182 Terminology 184 The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 185 "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this 186 document are to be interpreted as described in RFC 2119 [RFC2119]. 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 offered 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 546 Once the recipient has decided to accept the session, it generates an 547 answer session description. This process performs the appropriate 548 intersection of codecs and other parameters to generate the correct 549 answer. As with the offer, MediaHints can be provided to influence 550 the answer that is generated, and/or the application can post-process 551 the answer manually. 553 AnswererJS->AnswererUA: pc.createAnswer(offer, null); 555 5.2.5. Applying the Answer 557 The recipient then instructs the PeerConnection to use the answer as 558 its local description for this session, i.e. what codecs it will use 559 to receive media, etc. It also marks the description as an answer, 560 which tells the UA that these parameters are final. This causes the 561 PeerConnection to move to the ACTIVE state, and transmission of media 562 by the answerer to start. 564 AnswererJS->AnswererUA: pc.setLocalDescription(SDP_ANSWER, answer); 565 AnswererUA->OffererUA: 567 5.2.6. Serializing the Answer 569 As with the offer, the answer (with or without candidates) is now 570 converted to the desired signaling format and sent to the initiator. 572 5.3. Completing the Session 574 5.3.1. Receiving the Answer 576 The initiator converts the answer from the signaling protocol and 577 applies it as the remote description, marking it as an answer. This 578 causes the PeerConnection to move to the ACTIVE state, and 579 transmission of media by the offerer to start. 581 OffererJS->OffererUA: pc.setRemoteDescription(SDP_ANSWER, answer); 582 OffererUA->AnswererUA: 584 5.4. Updates to the Session 586 Updates to the session are handled with a new offer/answer exchange. 587 However, since media will already be flowing at this point, the new 588 offerer needs to support both its old session description as well as 589 the new one it has offered, until the change is accepted by the 590 remote side. 592 Note also that in an update scenario, the roles may be reversed, i.e. 593 the update offerer can be different than the original offerer. 595 6. Proposed WebRTC API changes 597 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; 644 [-] const unsigned short SDP_IDLE = 0x1000; 645 [-] const unsigned short SDP_WAITING = 0x2000; 646 [-] const unsigned short SDP_GLARE = 0x3000; 647 [-] readonly attribute unsigned short sdpState; 648 void addStream (MediaStream stream, MediaStreamHints hints); 649 void removeStream (MediaStream stream); 650 readonly attribute MediaStream[] localStreams; 651 readonly attribute MediaStream[] remoteStreams; 652 void close (); 653 [ rest of interface omitted ] 654 }; 656 [Constructor (in DOMString sdp)] 657 interface SessionDescription { 658 // adds the specified candidate to the description 659 void addCandidate(IceCandidate candidate); 660 // serializes the description to SDP 661 DOMString toSdp(); 662 }; 664 [Constructor (in DOMString label, in DOMString candidateLine)] 665 interface IceCandidate { 666 // the m= line this candidate is associated with 667 readonly DOMString label; 668 // creates a SDP-ized form of this candidate 669 DOMString toSdp(); 670 }; 672 6.1.1 MediaHints 674 MediaHints is an object that can be passed into createOffer or 675 createAnswer to affect the type of offer/answer that is generated. 677 The following properties can be set on MediaHints: 679 has_audio: boolean 681 Indicates whether we want to receive audio; defaults to true if we 682 have audio streams, else false 684 has_video: boolean 686 Indicates whether we want to receive video; defaults to true if we 687 have video streams, else false 689 As an example, MediaHints could be used to create a session that 690 transmits only audio, but is able to receive video from the remote 691 side, by forcing the inclusion of a m=video line even when no video 692 sources are provided. 694 6.1.2 createOffer 696 The createOffer method generates a blob of SDP that contains a RFC 697 3264 offer with the supported configurations for the session, 698 including descriptions of the local MediaStreams attached to this 699 PeerConnection, the codec/RTP/RTCP options supported by this 700 implementation, and any candidates that have been gathered by the ICE 701 Agent. The |hints| parameter may be supplied to provide additional 702 control over the generated offer. 704 As an offer, the generated SDP will contain the full set of 705 capabilities supported by the session (as opposed to an answer, which 706 will include only a specific negotiated subset to use); for each SDP 707 line, the generation of the SDP must follow the appropriate process 708 for generating an offer. In the event createOffer is called after the 709 session is established, createOffer will generate an offer that is 710 compatible with the current session, incorporating any changes that 711 have been made to the session since the last complete offer-answer 712 exchange, such as addition or removal of streams. If no changes have 713 been made, the offer will be identical to the current local 714 description. 716 Session descriptions generated by createOffer must be immediately 717 usable by setLocalDescription; if a system has limited resources 718 (e.g. a finite number of decoders), createOffer should return an 719 offer that reflects the current state of the system, so that 720 setLocalDescription will succeed when it attempts to acquire those 721 resources. 723 Calling this method does not change the state of the PeerConnection; 724 its use is not required. 726 A TBD exception is thrown if the |hints| parameter is malformed. 728 6.1.3 createAnswer 730 The createAnswer method generates a blob of SDP that contains a RFC 731 3264 SDP answer with the supported configuration for the session that 732 is compatible with the parameters supplied in |offer|. Like 733 createOffer, the returned blob contains descriptions of the local 734 MediaStreams attached to this PeerConnection, the codec/RTP/RTCP 735 options negotiated for this session, and any candidates that have 736 been gathered by the ICE Agent. The |hints| parameter may be supplied 737 to provide additional control over the generated answer. 739 As an answer, the generated SDP will contain a specific configuration 740 that specifies how the media plane should be established. For each 741 SDP line, the generation of the SDP must follow the appropriate 742 process for generating an answer. 744 Session descriptions generated by createAnswer must be immediately 745 usable by setLocalDescription; like createOffer, the returned 746 description should reflect the current state of the system. 748 Calling this method does not change the state of the PeerConnection; 749 its use is not required. 751 A TBD exception is thrown if the |hints| parameter is malformed, or 752 the |offer| parameter is missing or malformed. 754 6.1.4 SDP_OFFER, SDP_PRANSWER, and SDP_ANSWER 756 The SDP_XXXX enums serve as arguments to setLocalDescription and 757 setRemoteDescription. They provide information as to how the 758 |description| parameter should be parsed, and how the media state 759 should be changed. 761 SDP_OFFER indicates that a description should be parsed as an offer; 762 said description may include many possible media configurations. A 763 description used as a SDP_OFFER may be applied anytime the 764 PeerConnection is in a stable state, or as an update to a previously 765 sent but unanswered SDP_OFFER. 767 SDP_PRANSWER indicates that a description should be parsed as an 768 answer, but not a final answer, and so should not result in the 769 starting of media transmission. A description used as a SDP_PRANSWER 770 may be applied as a response to a SDP_OFFER, or an update to a 771 previously sent SDP_PRANSWER. 773 SDP_ANSWER indicates that a description should be parsed as an 774 answer, and the offer-answer exchange should be considered complete. 775 A description used as a SDP_ANSWER may be applied as a response to a 776 SDP_OFFER, or an update to a previously send SDP_PRANSWER. 778 6.1.5 setLocalDescription 780 The setLocalDescription method instructs the PeerConnection to apply 781 the supplied SDP blob as its local configuration. The |type| 782 parameter indicates whether the blob should be processed as an offer 783 (SDP_OFFER), provisional answer (SDP_PRANSWER), or final answer 784 (SDP_ANSWER); offers and answers are checked differently, using the 785 various rules that exist for each SDP line. 787 This API changes the local media state; among other things, it sets 788 up local resources for receiving and decoding media. In order to 789 successfully handle scenarios where the application wants to offer to 790 change from one media format to a different, incompatible format, the 791 PeerConnection must be able to simultaneously support use of both the 792 old and new local descriptions (e.g. support codecs that exist in 793 both descriptions) until a final answer is received, at which point 794 the PeerConnection can fully adopt the new local description, or roll 795 back to the old description if the remote side denied the change. 797 Changes to the state of media transmission will only occur when a 798 final answer is successfully applied. 800 A TBD exception is thrown if |description| is invalid. A TBD 801 exception is thrown if there are insufficient local resources to 802 apply |description|. 804 6.1.6 setRemoteDescription 806 The setRemoteDescription method instructs the PeerConnection to apply 807 the supplied SDP blob as the desired remote configuration. As in 808 setLocalDescription, the |type| parameter indicates how the blob 809 should be processed. 811 This API changes the local media state; among other things, it sets 812 up local resources for sending and encoding media. 814 Changes to the state of media transmission will only occur when a 815 final answer is successfully applied. 817 A TBD exception is thrown if |description| is invalid. A TBD 818 exception is thrown if there are insufficient local resources to 819 apply |description|. 821 6.1.7 localDescription 823 The localDescription method returns a copy of the current local 824 configuration, i.e. what was most recently passed to 825 setLocalDescription, plus any local candidates that have been 826 generated by the ICE Agent. 828 A null object will be returned if the local description has not yet 829 been established. 831 6.1.8 remoteDescription 833 The remoteDescription method returns a copy of the current remote 834 configuration, i.e. what was most recently passed to 835 setRemoteDescription, plus any remote candidates that have been 836 supplied via processIceMessage. 838 A null object will be returned if the remote description has not yet 839 been established. 841 6.1.9 IceOptions 843 IceOptions is an object that can be passed into startIce to restrict 844 the candidates that are provided to the application and used for 845 connectivity checks. This can be useful if the application wants to 846 only use TURN candidates for privacy reasons, or only local + STUN 847 candidates for cost reasons. 849 The following properties can be set on IceOptions: 851 use_candidates: "all", "no_relay", "only_relay" 853 Indicates what types of local candidates should be used; defaults 854 to "all" 856 6.1.10 startIce 858 The startIce method starts or updates the ICE Agent process of 859 gathering local candidates and pinging remote candidates. The 860 |options| argument can be used to restrict which types of local 861 candidates are provided to the application and used for pinging; this 862 can be used to limit the use of TURN candidates by a callee to avoid 863 leaking location information prior to the call being accepted. 865 This call may result in a change to the state of the ICE Agent, and 866 may result in a change to media state if it results in connectivity 867 being established. 869 A TBD exception will be thrown if |options| is malformed. 871 6.1.11 processIceMessage 873 The processIceMessage method provides a remote candidate to the ICE 874 Agent, which will be added to the remote description. If startIce has 875 been called, connectivity checks will be sent to the new candidates. 877 This call will result in a change to the state of the ICE Agent, and 878 may result in a change to media state if it results in connectivity 879 being established. 881 A TBD exception will be thrown if |candidate| is missing or 882 malformed. 884 7. Example API Flows 886 Below are several sample flows for the new PeerConnection and library 887 APIs, demonstrating when the various APIs are called in different 888 situations and with various transport protocols. 890 7.1. Call using ROAP 892 This example demonstrates a ROAP call, without the use of trickle 893 candidates. 895 // Call is initiated toward Answerer 896 OffererJS->OffererUA: pc = new PeerConnection(); 897 OffererJS->OffererUA: pc.addStream(localStream, null); 898 OffererJS->OffererUA: pc.startIce(); 899 OffererUA->OffererJS: iceCallback(candidate, false); 900 OffererJS->OffererUA: offer = pc.createOffer(null); 901 OffererJS->OffererUA: pc.setLocalDescription(SDP_OFFER, offer.toSdp()); 902 OffererJS->AnswererJS: {"type":"OFFER", "sdp":""} 904 // OFFER arrives at Answerer 905 AnswererJS->AnswererUA: pc = new PeerConnection(); 906 AnswererJS->AnswererUA: pc.setRemoteDescription(SDP_OFFER, msg.sdp); 907 AnswererUA->AnswererJS: onaddstream(remoteStream); 908 AnswererJS->AnswererUA: pc.startIce(); 909 AnswererUA->OffererUA: iceCallback(candidate, false); 911 // Answerer accepts call 912 AnswererJS->AnswererUA: peer.addStream(localStream, null); 913 AnswererJS->AnswererUA: answer = peer.createAnswer(msg.offer, null); 914 AnswererJS->AnswererUA: peer.setLocalDescription(SDP_ANSWER, answer); 915 AnswererJS->OffererJS: {"type":"ANSWER","sdp":""} 917 // ANSWER arrives at Offerer 918 OffererJS->OffererUA: peer.setRemoteDescription(ANSWER, answer); 919 OffererUA->OffererJS: onaddstream(remoteStream); 921 // ICE Completes (at Answerer) 922 AnswererUA->AnswererJS: onopen(); 923 AnswererUA->OffererUA: Media 925 // ICE Completes (at Offerer) 926 OffererUA->OffererJS: onopen(); 927 OffererJS->AnswererJS: {"type":"OK" } 928 OffererUA->AnswererUA: Media 930 7.2. Call using XMPP 931 This example demonstrates an XMPP call, making use of trickle 932 candidates. 934 // Call is initiated toward Answerer 935 OffererJS->OffererUA: pc = new PeerConnection(); 936 OffererJS->OffererUA: pc.addStream(localStream, null); 937 OffererJS->OffererUA: offer = pc.createOffer(null); 938 OffererJS->OffererUA: pc.setLocalDescription(SDP_OFFER, offer); 939 OffererJS: xmpp = createSessionInitiate(offer); 940 OffererJS->AnswererJS: 942 OffererJS->OffererUA: pc.startIce(); 943 OffererUA->OffererJS: iceCallback(cand); 944 OffererJS: createTransportInfo(cand, ...); 945 OffererJS->AnswererJS: 947 // session-initiate arrives at Answerer 948 AnswererJS->AnswererUA: pc = new PeerConnection(); 949 AnswererJS: offer = parseSessionInitiate(xmpp); 950 AnswererJS->AnswererUA: pc.setRemoteDescription(SDP_OFFER, offer); 951 AnswererUA->AnswererJS: onaddstream(remoteStream); 953 // transport-infos arrive at Answerer 954 AnswererJS->AnswererUA: candidates = parseTransportInfo(xmpp); 955 AnswererJS->AnswererUA: pc.processIceMessage(candidates); 956 AnswererJS->AnswererUA: pc.startIce(); 957 AnswererUA->AnswererJS: iceCallback(cand, ...) 958 AnswererJS: createTransportInfo(cand); 959 AnswererJS->OffererJS: 961 // transport-infos arrive at Offerer 962 OffererJS->OffererUA: candidates = parseTransportInfo(xmpp); 963 OffererJS->OffererUA: pc.processIceMessage(candidates); 965 // Answerer accepts call 966 AnswererJS->AnswererUA: peer.addStream(localStream, null); 967 AnswererJS->AnswererUA: answer = peer.createAnswer(offer, null); 968 AnswererJS: xmpp = createSessionAccept(answer); 969 AnswererJS->AnswererUA: pc.setLocalDescription(SDP_ANSWER, answer); 970 AnswererJS->OffererJS: 972 // session-accept arrives at Offerer 973 OffererJS: answer = parseSessionAccept(xmpp); 974 OffererJS->OffererUA: peer.setRemoteDescription(ANSWER, answer); 975 OffererUA->OffererJS: onaddstream(remoteStream); 977 // ICE Completes (at Answerer) 978 AnswererUA->AnswererJS: onopen(); 979 AnswererUA->OffererUA: Media 981 // ICE Completes (at Offerer) 982 OffererUA->OffererJS: onopen(); 983 OffererUA->AnswererUA: Media 985 7.3. Adding video to a call, using XMPP 987 This example demonstrates an XMPP call, where the XMPP content-add 988 mechanism is used to add video media to an existing session. For 989 simplicity, candidate exchange is not shown. 991 Note that the offerer for the change to the session may be different 992 than the original call offerer. 994 // Offerer adds video stream 995 OffererJS->OffererUA: pc.addStream(videoStream) 996 OffererJS->OffererUA: offer = pc.createOffer(null); 997 OffererJS: xmpp = createContentAdd(offer); 998 OffererJS->OffererUA: pc.setLocalDescription(SDP_OFFER, offer); 999 OffererJS->AnswererJS: 1001 // content-add arrives at Answerer 1002 AnswererJS: offer = parseContentAdd(xmpp); 1003 AnswererJS->AnswererUA: pc.setRemoteDescription(SDP_OFFER, offer); 1004 AnswererJS->AnswererUA: answer = pc.createAnswer(offer, null); 1005 AnswererJS->AnswererUA: pc.setLocalDescription(SDP_ANSWER, answer); 1006 AnswererJS: xmpp = createContentAccept(answer); 1007 AnswererJS->OffererJS: 1009 // content-accept arrives at Offerer 1010 OffererJS: answer = parseContentAccept(xmpp); 1011 OffererJS->OffererUA: pc.setRemoteDescription(SDP_ANSWER, answer); 1013 7.4. Simultaneous add of video streams, using XMPP 1015 This example demonstrates an XMPP call, where new video sources are 1016 added at the same time to a call that already has video; since adding 1017 these sources only affects one side of the call, there is no 1018 conflict. The XMPP description-info mechanism is used to indicate the 1019 new sources to the remote side. 1021 // Offerer and "Answerer" add video streams at the same time 1022 OffererJS->OffererUA: pc.addStream(offererVideoStream2) 1023 OffererJS->OffererUA: offer = pc.createOffer(null); 1024 OffererJS: xmpp = createDescriptionInfo(offer); 1025 OffererJS->OffererUA: pc.setLocalDescription(SDP_OFFER, offer); 1026 OffererJS->AnswererJS: 1028 AnswererJS->AnswererUA: pc.addStream(answererVideoStream2) 1029 AnswererJS->AnswererUA: offer = pc.createOffer(null); 1030 AnswererJS: xmpp = createDescriptionInfo(offer); 1031 AnswererJS->AnswererUA: pc.setLocalDescription(SDP_OFFER, offer); 1032 AnswererJS->OffererJS: 1034 // description-info arrives at "Answerer", and is acked 1035 AnswererJS: offer = parseDescriptionInfo(xmpp); 1036 AnswererJS->OffererJS: // ack 1042 // ack arrives at Offerer; remote offer is used as an answer 1043 OffererJS->OffererUA: pc.setRemoteDescription(SDP_ANSWER, offer); 1045 // ack arrives at "Answerer"; remote offer is used as an answer 1046 AnswererJS->AnswererUA: pc.setRemoteDescription(SDP_ANSWER, offer); 1048 7.5. Call using SIP 1050 This example demonstrates a simple SIP call (e.g. where the client 1051 talks to a SIP proxy over WebSockets). 1053 // Call is initiated toward Answerer 1054 OffererJS->OffererUA: pc = new PeerConnection(); 1055 OffererJS->OffererUA: pc.addStream(localStream, null); 1056 OffererJS->OffererUA: pc.startIce(); 1057 OffererUA->OffererJS: iceCallback(candidate, false); 1058 OffererJS->OffererUA: offer = pc.createOffer(null); 1059 OffererJS->OffererUA: pc.setLocalDescription(SDP_OFFER, offer); 1060 OffererJS: sip = createInvite(offer);- 1061 OffererJS->AnswererJS: SIP INVITE w/ SDP 1063 // INVITE arrives at Answerer 1064 AnswererJS->AnswererUA: pc = new PeerConnection(); 1065 AnswererJS: offer = parseInvite(sip); 1066 AnswererJS->AnswererUA: pc.setRemoteDescription(SDP_OFFER, offer); 1067 AnswererUA->AnswererJS: onaddstream(remoteStream); 1068 AnswererJS->AnswererUA: pc.startIce(); 1069 AnswererUA->OffererUA: iceCallback(candidate, false); 1071 // Answerer accepts call 1072 AnswererJS->AnswererUA: peer.addStream(localStream, null); 1073 AnswererJS->AnswererUA: answer = peer.createAnswer(offer, null); 1074 AnswererJS: sip = createResponse(200, answer); 1075 AnswererJS->AnswererUA: peer.setLocalDescription(SDP_ANSWER, answer); 1076 AnswererJS->OffererJS: 200 OK w/ SDP 1078 // 200 OK arrives at Offerer 1079 OffererJS: answer = parseResponse(sip); 1080 OffererJS->OffererUA: peer.setRemoteDescription(ANSWER, answer); 1081 OffererUA->OffererJS: onaddstream(remoteStream); 1082 OffererJS->AnswererJS: ACK 1084 // ICE Completes (at Answerer) 1085 AnswererUA->AnswererJS: onopen(); 1086 AnswererUA->OffererUA: Media 1088 // ICE Completes (at Offerer) 1089 OffererUA->OffererJS: onopen(); 1090 OffererUA->AnswererUA: Media 1092 7.6. Handling early media (e.g. 1-800-FEDEX), using SIP 1094 This example demonstrates how early media could be handled; for 1095 simplicity, only the offerer side of the call is shown. 1097 // Call is initiated toward Answerer 1098 OffererJS->OffererUA: pc = new PeerConnection(); 1099 OffererJS->OffererUA: pc.addStream(localStream, null); 1100 OffererJS->OffererUA: pc.startIce(); 1101 OffererUA->OffererJS: iceCallback(candidate, false); 1102 OffererJS->OffererUA: offer = pc.createOffer(null); 1103 OffererJS->OffererUA: pc.setLocalDescription(SDP_OFFER, offer); 1104 OffererJS: sip = createInvite(offer); 1105 OffererJS->AnswererJS: SIP INVITE w/ SDP 1107 // 180 Ringing is received by offerer, w/ SDP 1108 OffererJS: answer = parseResponse(sip); 1109 OffererJS->OffererUA: pc.setRemoteDescription(SDP_PRANSWER, answer); 1110 OffererUA->OffererJS: onaddstream(remoteStream); 1112 // ICE Completes (at Offerer) 1113 OffererUA->OffererJS: onopen(); 1114 OffererUA->AnswererUA: Media 1116 // 200 OK arrives at Offerer 1117 OffererJS: answer = parseResponse(sip); 1118 OffererJS->OffererUA: pc.setRemoteDescription(SDP_ANSWER, answer); 1119 OffererJS->AnswererJS: ACK 1121 8. Example Application 1122 The following example demonstrates a simple video calling 1123 application, roughly corresponding to the flow in Example 7.1. 1125 var signalingChannel = createSignalingChannel(); 1126 var pc = null; 1127 var hasCandidates = false; 1129 function start(isCaller) { 1130 // create a PeerConnection and hook up the IceCallback 1131 pc = new webkitPeerConnection( 1132 "", function (candidate, moreToFollow) { 1133 if (!moreToFollow) { 1134 hasCandidates = true; 1135 maybeSignal(isCaller); 1136 } 1137 }); 1139 // get the local stream and show it in the local video element 1140 navigator.webkitGetUserMedia( 1141 {"audio": true, "video": true}, function (localStream) { 1142 selfView.src = webkitURL.createObjectURL(localStream); 1143 pc.addStream(localStream); 1144 maybeSignal(isCaller); 1145 } 1147 // once remote stream arrives, show it in the remote video element 1148 pc.onaddstream = function(evt) { 1149 remoteView.src = webkitURL.createObjectURL(evt.stream); 1150 }; 1152 // if we're the caller, create and install our offer, 1153 // and start candidate generation 1154 if (isCaller) { 1155 offer = pc.createOffer(null); 1156 pc.setLocalDescription(SDP_OFFER, offer); 1157 pc.startIce(); 1158 } 1159 } 1161 function maybeSignal(isCaller) { 1162 // only signal once we have a local stream and local candidates 1163 if (localStreams.size() == 0 || !hasCandidates) return; 1164 if (isCaller) { 1165 offer = pc.localDescription; 1166 signalingChannel.send( 1167 JSON.stringify({ "type": "offer", "sdp": offer })); 1168 } else { 1169 // if we're the callee, generate, apply, and send the answer 1170 answer = pc.createAnswer(pc.remoteDescription, null); 1171 pc.setLocalDescription(SDP_ANSWER, answer); 1172 signalingChannel.send( 1173 JSON.stringify({ "type": "answer", "sdp": answer })); 1174 } 1175 } 1177 signalingChannel.onmessage = function(evt) { 1178 var msg = JSON.parse(evt.data); 1179 if (msg.type == "offer") { 1180 // create the PeerConnection 1181 start(false); 1182 // feed the received offer into the PeerConnection and 1183 // start candidate generation 1184 pc.setRemoteDescription(PeerConnection.SDP_OFFER, msg.sdp); 1185 pc.startIce(); 1186 } else if (msg.type == "answer") { 1187 // feed the answer into the PeerConnection to complete setup 1188 pc.setRemoteDescription(PeerConnection.SDP_ANSWER, msg.sdp); 1189 } 1191 9. Security Considerations 1193 TODO 1195 10. IANA Considerations 1197 This document requires no actions from IANA. 1199 11. Acknowledgements 1201 Harald Alvestrand, Dan Burnett, Neil Stratford, Eric Rescorla, and 1202 Anant Narayanan all provided valuable feedback on this proposal. 1203 Matthew Kaufman provided the observation that keeping state out of 1204 the browser allows a call to continue even if the page is reloaded. 1205 Adam Bergvist provided a code example that served as the basis for 1206 the example in Section 8. 1208 12. References 1210 12.1. Normative References 1212 [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate 1213 Requirement Levels", BCP 14, RFC 2119, March 1997. 1215 [RFC3264] Rosenberg, J. and H. Schulzrinne, "An Offer/Answer Model 1216 with Session Description Protocol (SDP)", RFC 3264, June 2002. 1218 [RFC4566] Handley, M., Jacobson, V., and C. Perkins, "SDP: Session 1219 Description Protocol", RFC 4566, July 2006. 1221 12.2. Informative References 1223 [RFC4568] Andreasen, F., Baugher, M., and D. Wing, "Session 1224 Description Protocol (SDP) Security Descriptions for Media Streams", 1225 RFC 4568, July 2006. 1227 [RFC5245] Rosenberg, J., "Interactive Connectivity Establishment 1228 (ICE): A Protocol for Network Address Translator (NAT) Traversal for 1229 Offer/Answer Protocols", RFC 5245, April 2010. 1231 [webrtc-api] Bergkvist, Burnett, Jennings, Narayanan, "WebRTC 1.0: 1232 Real-time Communication Between Browsers", October 2011. 1234 Available at http://dev.w3.org/2011/webrtc/editor/webrtc.html 1236 Appendix A. Open Issues 1238 - Determine list of exceptions that can be thrown by each method. 1239 Leaning toward something like a PCException, a la 1240 https://developer.mozilla.org/en/IndexedDB/IDBDatabaseException 1242 - Need callback to indicate that the transport is down, e.g. 1243 ICE_DISCONNECTED or ondisconnected(). 1245 Appendix B. Change log 1247 00: Migrated from draft-uberti-rtcweb-jsep-02. 1249 Authors' Addresses 1251 Justin Uberti 1252 Google 1253 5 Cambridge Center 1254 Cambridge, MA 02142 1256 Email: justin@uberti.name 1258 Cullen Jennings 1259 Cisco 1260 170 West Tasman Drive 1261 San Jose, CA 95134 1262 USA 1264 Email: fluffy@cisco.com