1 2 3 4 5 6 7 8 9 10<!doctype html> 11<html 12 lang="en" 13 dir="ltr"> 14 <head> 15 <meta name="google-signin-client-id" content="157101835696-ooapojlodmuabs2do2vuhhnf90bccmoi.apps.googleusercontent.com"><meta name="google-signin-scope" 16 content="profile email"><meta property="og:site_name" content="WebRTC"> 17 <meta property="og:type" content="website"><meta name="theme-color" content="#4285f4"><meta charset="utf-8"> 18 <meta content="IE=Edge" http-equiv="X-UA-Compatible"> 19 <meta name="viewport" content="width=device-width, initial-scale=1"> 20 21 22 <link rel="manifest" href="/_pwa/webrtc/manifest.json" 23 crossorigin="use-credentials"> 24 <link rel="preconnect" href="//www.gstatic.com" crossorigin> 25 <link rel="preconnect" href="//fonts.googleapis.com" crossorigin> 26 <link rel="preconnect" href="//www.google-analytics.com" crossorigin><link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,500,700&display=swap"> 27 <link rel="stylesheet" 28 href="//fonts.googleapis.com/css2?family=Material+Icons&family=Material+Symbols+Outlined&display=block"><link rel="stylesheet" href="https://www.gstatic.com/devrel-devsite/prod/v5be16d8c9f9402e54c2da2ff24cb75c148f5d2bc84c6f8dfc8b9e16ae456160b/webrtc/css/app.css"> 29 30 <link rel="stylesheet" href="https://www.gstatic.com/devrel-devsite/prod/v5be16d8c9f9402e54c2da2ff24cb75c148f5d2bc84c6f8dfc8b9e16ae456160b/webrtc/css/dark-theme.css" disabled> 31 <link rel="shortcut icon" href="https://www.gstatic.com/devrel-devsite/prod/v5be16d8c9f9402e54c2da2ff24cb75c148f5d2bc84c6f8dfc8b9e16ae456160b/webrtc/images/favicon.png"> 32 <link rel="apple-touch-icon" href="https://www.gstatic.com/devrel-devsite/prod/v5be16d8c9f9402e54c2da2ff24cb75c148f5d2bc84c6f8dfc8b9e16ae456160b/webrtc/images/touchicon-180.png"><link rel="canonical" href="https://webrtc.org/getting-started/firebase-rtc-codelab"><link rel="search" type="application/opensearchdescription+xml" 33 title="WebRTC" href="https://webrtc.org/s/opensearch.xml"> 34 <link rel="alternate" hreflang="en" 35 href="https://webrtc.org/getting-started/firebase-rtc-codelab" /><link rel="alternate" hreflang="x-default" href="https://webrtc.org/getting-started/firebase-rtc-codelab" /><link rel="alternate" hreflang="ar" 36 href="https://webrtc.org/getting-started/firebase-rtc-codelab?hl=ar" /><link rel="alternate" hreflang="bn" 37 href="https://webrtc.org/getting-started/firebase-rtc-codelab?hl=bn" /><link rel="alternate" hreflang="zh-Hans" 38 href="https://webrtc.org/getting-started/firebase-rtc-codelab?hl=zh-cn" /><link rel="alternate" hreflang="zh-Hant" 39 href="https://webrtc.org/getting-started/firebase-rtc-codelab?hl=zh-tw" /><link rel="alternate" hreflang="fa" 40 href="https://webrtc.org/getting-started/firebase-rtc-codelab?hl=fa" /><link rel="alternate" hreflang="fr" 41 href="https://webrtc.org/getting-started/firebase-rtc-codelab?hl=fr" /><link rel="alternate" hreflang="de" 42 href="https://webrtc.org/getting-started/firebase-rtc-codelab?hl=de" /><link rel="alternate" hreflang="he" 43 href="https://webrtc.org/getting-started/firebase-rtc-codelab?hl=he" /><link rel="alternate" hreflang="hi" 44 href="https://webrtc.org/getting-started/firebase-rtc-codelab?hl=hi" /><link rel="alternate" hreflang="id" 45 href="https://webrtc.org/getting-started/firebase-rtc-codelab?hl=id" /><link rel="alternate" hreflang="it" 46 href="https://webrtc.org/getting-started/firebase-rtc-codelab?hl=it" /><link rel="alternate" hreflang="ja" 47 href="https://webrtc.org/getting-started/firebase-rtc-codelab?hl=ja" /><link rel="alternate" hreflang="ko" 48 href="https://webrtc.org/getting-started/firebase-rtc-codelab?hl=ko" /><link rel="alternate" hreflang="pl" 49 href="https://webrtc.org/getting-started/firebase-rtc-codelab?hl=pl" /><link rel="alternate" hreflang="pt-BR" 50 href="https://webrtc.org/getting-started/firebase-rtc-codelab?hl=pt-br" /><link rel="alternate" hreflang="ru" 51 href="https://webrtc.org/getting-started/firebase-rtc-codelab?hl=ru" /><link rel="alternate" hreflang="es-419" 52 href="https://webrtc.org/getting-started/firebase-rtc-codelab?hl=es-419" /><link rel="alternate" hreflang="th" 53 href="https://webrtc.org/getting-started/firebase-rtc-codelab?hl=th" /><link rel="alternate" hreflang="tr" 54 href="https://webrtc.org/getting-started/firebase-rtc-codelab?hl=tr" /><link rel="alternate" hreflang="vi" 55 href="https://webrtc.org/getting-started/firebase-rtc-codelab?hl=vi" /><title>Firebase + WebRTC Codelab</title> 56 57<meta property="og:title" content="Firebase + WebRTC Codelab"><meta property="og:url" content="https://webrtc.org/getting-started/firebase-rtc-codelab"><meta property="og:locale" content="en">
57<script type="application/ld+json"> 58 { 59 "@context": "https://schema.org", 60 "@type": "Article", 61 62 "headline": "Firebase + WebRTC Codelab" 63 } 64</script>
64 65 66 67 68 69 70 71 72 </head> 73 <body class="color-scheme--light" 74 template="page" 75 theme="webrtc-theme" 76 type="article" 77 78 appearance 79 80 layout="docs" 81 82 83 84 85 86 display-toc 87 pending> 88 89 <devsite-progress type="indeterminate" id="app-progress"></devsite-progress> 90 91 92 <a href="#main-content" class="skip-link button"> 93 94 Skip to main content 95 </a> 96 <section class="devsite-wrapper"> 97 <devsite-cookie-notification-bar></devsite-cookie-notification-bar> 98 <devsite-header role="banner" keep-tabs-visible> 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122<div class="devsite-header--inner" data-nosnippet> 123 <div class="devsite-top-logo-row-wrapper-wrapper"> 124 <div class="devsite-top-logo-row-wrapper"> 125 <div class="devsite-top-logo-row"> 126 <button type="button" id="devsite-hamburger-menu" 127 class="devsite-header-icon-button button-flat material-icons gc-analytics-event" 128 data-category="Site-Wide Custom Events" 129 data-label="Navigation menu button" 130 visually-hidden 131 aria-label="Open menu"> 132 </button> 133 134<div class="devsite-product-name-wrapper"> 135 136 <a href="/" class="devsite-site-logo-link gc-analytics-event" 137 data-category="Site-Wide Custom Events" data-label="Site logo" track-type="globalNav" 138 track-name="webRTC" track-metadata-position="nav" 139 track-metadata-eventDetail="nav"> 140 141 <picture> 142 143 <source srcset="https://www.gstatic.com/devrel-devsite/prod/v5be16d8c9f9402e54c2da2ff24cb75c148f5d2bc84c6f8dfc8b9e16ae456160b/webrtc/images/lockup-dark-theme.svg" 144 media="(prefers-color-scheme: dark)" 145 class="devsite-dark-theme"> 146 147 <img src="https://www.gstatic.com/devrel-devsite/prod/v5be16d8c9f9402e54c2da2ff24cb75c148f5d2bc84c6f8dfc8b9e16ae456160b/webrtc/images/lockup.svg" class="devsite-site-logo" alt="WebRTC"> 148 </picture> 149 150</a> 151 152 153 154</div> 155 <div class="devsite-top-logo-row-middle"> 156 <div class="devsite-header-upper-tabs"> 157 158 </div> 159 160<devsite-search 161 enable-signin 162 enable-search 163 enable-suggestions 164 enable-query-completion 165 166 enable-search-summaries 167 project-name="WebRTC" 168 tenant-name="WebRTC" 169 170 171 172 173 174 > 175 <form class="devsite-search-form" action="https://webrtc.org/s/results" method="GET"> 176 <div class="devsite-search-container"> 177 <button type="button" 178 search-open 179 class="devsite-search-button devsite-header-icon-button button-flat material-icons" 180 181 aria-label="Open search"></button> 182 <div class="devsite-searchbox"> 183 <input 184 aria-activedescendant="" 185 aria-autocomplete="list" 186 187 aria-label="Search" 188 aria-expanded="false" 189 aria-haspopup="listbox" 190 autocomplete="off" 191 class="devsite-search-field devsite-search-query" 192 name="q" 193 194 placeholder="Search" 195 role="combobox" 196 type="text" 197 value="" 198 > 199 <div class="devsite-search-image material-icons" aria-hidden="true"> 200 201 <svg class="devsite-search-ai-image" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> 202 <g clip-path="url(#clip0_6641_386)"> 203 <path d="M19.6 21L13.3 14.7C12.8 15.1 12.225 15.4167 11.575 15.65C10.925 15.8833 10.2333 16 9.5 16C7.68333 16 6.14167 15.375 4.875 14.125C3.625 12.8583 3 11.3167 3 9.5C3 7.68333 3.625 6.15 4.875 4.9C6.14167 3.63333 7.68333 3 9.5 3C10.0167 3 10.5167 3.05833 11 3.175C11.4833 3.275 11.9417 3.43333 12.375 3.65L10.825 5.2C10.6083 5.13333 10.3917 5.08333 10.175 5.05C9.95833 5.01667 9.73333 5 9.5 5C8.25 5 7.18333 5.44167 6.3 6.325C5.43333 7.19167 5 8.25 5 9.5C5 10.75 5.43333 11.8167 6.3 12.7C7.18333 13.5667 8.25 14 9.5 14C10.6667 14 11.6667 13.625 12.5 12.875C13.35 12.1083 13.8417 11.15 13.975 10H15.975C15.925 10.6333 15.7833 11.2333 15.55 11.8C15.3333 12.3667 15.05 12.8667 14.7 13.3L21 19.6L19.6 21ZM17.5 12C17.5 10.4667 16.9667 9.16667 15.9 8.1C14.8333 7.03333 13.5333 6.5 12 6.5C13.5333 6.5 14.8333 5.96667 15.9 4.9C16.9667 3.83333 17.5 2.53333 17.5 0.999999C17.5 2.53333 18.0333 3.83333 19.1 4.9C20.1667 5.96667 21.4667 6.5 23 6.5C21.4667 6.5 20.1667 7.03333 19.1 8.1C18.0333 9.16667 17.5 10.4667 17.5 12Z" fill="#5F6368"/> 204 </g> 205 <defs> 206 <clipPath id="clip0_6641_386"> 207 <rect width="24" height="24" fill="white"/> 208 </clipPath> 209 </defs> 210 </svg> 211 212 </div> 213 <div class="devsite-search-shortcut-icon-container" aria-hidden="true"> 214 <kbd class="devsite-search-shortcut-icon">/</kbd> 215 </div> 216 </div> 217 </div> 218 </form> 219 <button type="button" 220 search-close 221 class="devsite-search-button devsite-header-icon-button button-flat material-icons" 222 223 aria-label="Close search"></button> 224</devsite-search> 225 226 </div> 227 228 229 230 231 232 233 234 235 236 <devsite-appearance-selector></devsite-appearance-selector> 237 238 239<devsite-language-selector> 240 <ul role="presentation"> 241 242 243 <li role="presentation"> 244 <a role="menuitem" lang="en" 245 >English</a> 246 </li> 247 248 <li role="presentation"> 249 <a role="menuitem" lang="de" 250 >Deutsch</a> 251 </li> 252 253 <li role="presentation"> 254 <a role="menuitem" lang="es" 255 >Español</a> 256 </li> 257 258 <li role="presentation"> 259 <a role="menuitem" lang="es_419" 260 >Español â América Latina</a> 261 </li> 262 263 <li role="presentation"> 264 <a role="menuitem" lang="fr" 265 >Français</a> 266 </li> 267 268 <li role="presentation"> 269 <a role="menuitem" lang="id" 270 >Indonesia</a> 271 </li> 272 273 <li role="presentation"> 274 <a role="menuitem" lang="it" 275 >Italiano</a> 276 </li> 277 278 <li role="presentation"> 279 <a role="menuitem" lang="pl" 280 >Polski</a> 281 </li> 282 283 <li role="presentation"> 284 <a role="menuitem" lang="pt" 285 >Português</a> 286 </li> 287 288 <li role="presentation"> 289 <a role="menuitem" lang="pt_br" 290 >Português â Brasil</a> 291 </li> 292 293 <li role="presentation"> 294 <a role="menuitem" lang="vi" 295 >TiêÌng Việt</a> 296 </li> 297 298 <li role="presentation"> 299 <a role="menuitem" lang="tr" 300 >Türkçe</a> 301 </li> 302 303 <li role="presentation"> 304 <a role="menuitem" lang="ru" 305 >Ð ÑÑÑкий</a> 306 </li> 307 308 <li role="presentation"> 309 <a role="menuitem" lang="he" 310 >×¢×ר×ת</a> 311 </li> 312 313 <li role="presentation"> 314 <a role="menuitem" lang="ar" 315 >Ø§ÙØ¹Ø±Ø¨ÙÙØ©</a> 316 </li> 317 318 <li role="presentation"> 319 <a role="menuitem" lang="fa" 320 >ÙØ§Ø±Ø³Û</a> 321 </li> 322 323 <li role="presentation"> 324 <a role="menuitem" lang="hi" 325 >हिà¤à¤¦à¥</a> 326 </li> 327 328 <li role="presentation"> 329 <a role="menuitem" lang="bn" 330 >বাà¦à¦²à¦¾</a> 331 </li> 332 333 <li role="presentation"> 334 <a role="menuitem" lang="th" 335 >ภาษาà¹à¸à¸¢</a> 336 </li> 337 338 <li role="presentation"> 339 <a role="menuitem" lang="zh_cn" 340 >䏿 â ç®ä½</a> 341 </li> 342 343 <li role="presentation"> 344 <a role="menuitem" lang="zh_tw" 345 >䏿 â ç¹é«</a> 346 </li> 347 348 <li role="presentation"> 349 <a role="menuitem" lang="ja" 350 >æ¥æ¬èª</a> 351 </li> 352 353 <li role="presentation"> 354 <a role="menuitem" lang="ko" 355 >íêµì´</a> 356 </li> 357 358 </ul> 359</devsite-language-selector> 360 361 362 363 364 365 366 367 <devsite-user 368 369 370 371 id="devsite-user"> 372 373
374 <span class="button devsite-top-button" aria-hidden="true" visually-hidden>Sign in</span> 375 376 </devsite-user> 377 378 379 380 </div> 381 </div> 382 </div> 383 384 385 386 <div class="devsite-collapsible-section 387 "> 388 <div class="devsite-header-background"> 389 390 391 392 393 <div class="devsite-doc-set-nav-row"> 394 395 396 397 398 <devsite-tabs class="lower-tabs"> 399 400 <nav class="devsite-tabs-wrapper" aria-label="Lower tabs"> 401 402 403 <tab > 404 405 <a href="https://webrtc.org/" 406 class="devsite-tabs-content gc-analytics-event " 407 track-metadata-eventdetail="https://webrtc.org/" 408 409 track-type="nav" 410 track-metadata-position="nav - home" 411 track-metadata-module="primary nav" 412 413 414 415 data-category="Site-Wide Custom Events" 416 417 data-label="Tab: Home" 418 419 track-name="home" 420 421 > 422 Home 423 424 </a> 425 426 427 </tab> 428 429 430 431 <tab class="devsite-active"> 432 433 <a href="https://webrtc.org/getting-started/overview" 434 class="devsite-tabs-content gc-analytics-event " 435 track-metadata-eventdetail="https://webrtc.org/getting-started/overview" 436 437 track-type="nav" 438 track-metadata-position="nav - guides" 439 track-metadata-module="primary nav" 440 aria-label="Guides, selected" 441 442 443 data-category="Site-Wide Custom Events" 444 445 data-label="Tab: Guides" 446 447 track-name="guides" 448 449 > 450 Guides 451 452 </a> 453 454 455 </tab> 456 457 458 459 <tab > 460 461 <a href="https://webrtc.org/support/overview" 462 class="devsite-tabs-content gc-analytics-event " 463 track-metadata-eventdetail="https://webrtc.org/support/overview" 464 465 track-type="nav" 466 track-metadata-position="nav - support" 467 track-metadata-module="primary nav" 468 469 470 471 data-category="Site-Wide Custom Events" 472 473 data-label="Tab: Support" 474 475 track-name="support" 476 477 > 478 Support 479 480 </a> 481 482 483 </tab> 484 485 486 </nav> 487 488 </devsite-tabs> 489 490 491 492 </div> 493 494 </div> 495 </div> 496 497</div> 498 499 500 501 502</devsite-header> 503 <devsite-book-nav scrollbars > 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527<div class="devsite-book-nav-filter" 528 > 529 <span class="filter-list-icon material-icons" aria-hidden="true"></span> 530 <input type="text" 531 placeholder="Filter" 532 533 aria-label="Type to filter" 534 role="searchbox"> 535 536 <span class="filter-clear-button hidden" 537 data-title="Clear filter" 538 aria-label="Clear filter" 539 role="button" 540 tabindex="0"></span> 541</div> 542 543<nav class="devsite-book-nav devsite-nav nocontent" data-nosnippet 544 aria-label="Side menu"> 545 <div class="devsite-mobile-header"> 546 <button type="button" 547 id="devsite-close-nav" 548 class="devsite-header-icon-button button-flat material-icons gc-analytics-event" 549 data-category="Site-Wide Custom Events" 550 data-label="Close navigation" 551 aria-label="Close navigation"> 552 </button> 553 <div class="devsite-product-name-wrapper"> 554 555 <a href="/" class="devsite-site-logo-link gc-analytics-event" 556 data-category="Site-Wide Custom Events" data-label="Site logo" track-type="globalNav" 557 track-name="webRTC" track-metadata-position="nav" 558 track-metadata-eventDetail="nav"> 559 560 <picture> 561 562 <source srcset="https://www.gstatic.com/devrel-devsite/prod/v5be16d8c9f9402e54c2da2ff24cb75c148f5d2bc84c6f8dfc8b9e16ae456160b/webrtc/images/lockup-dark-theme.svg" 563 media="(prefers-color-scheme: dark)" 564 class="devsite-dark-theme"> 565 566 <img src="https://www.gstatic.com/devrel-devsite/prod/v5be16d8c9f9402e54c2da2ff24cb75c148f5d2bc84c6f8dfc8b9e16ae456160b/webrtc/images/lockup.svg" class="devsite-site-logo" alt="WebRTC"> 567 </picture> 568 569</a> 570 571 572</div> 573 </div> 574 575 <div class="devsite-book-nav-wrapper"> 576 <div class="devsite-mobile-nav-top"> 577 578 <ul class="devsite-nav-list"> 579 580 581<li class="devsite-nav-item"> 582 583 584 <a href="/" 585 586 class="devsite-nav-title gc-analytics-event 587 588 " 589 590 591 592 593 data-category="Site-Wide Custom Events" 594 595 data-label="Tab: Home" 596 597 track-name="home" 598 599 600 data-category="Site-Wide Custom Events" 601 data-label="Responsive Tab: Home" 602 track-type="navMenu" 603 track-metadata-eventDetail="globalMenu" 604 track-metadata-position="nav"> 605 606 <span class="devsite-nav-text" tooltip > 607 Home 608 </span> 609 610 611 </a> 612 613 614</li> 615 616 617 618<li class="devsite-nav-item"> 619 620 621 <a href="/getting-started/overview" 622 623 class="devsite-nav-title gc-analytics-event 624 devsite-nav-has-children 625 devsite-nav-active" 626 627 628 629 630 data-category="Site-Wide Custom Events" 631 632 data-label="Tab: Guides" 633 634 track-name="guides" 635 636 637 data-category="Site-Wide Custom Events" 638 data-label="Responsive Tab: Guides" 639 track-type="navMenu" 640 track-metadata-eventDetail="globalMenu" 641 track-metadata-position="nav"> 642 643 <span class="devsite-nav-text" tooltip > 644 Guides 645 </span> 646 647 <span class="devsite-nav-icon material-icons" data-icon="forward" 648 > 649 </span> 650 651 652 </a> 653 654 655</li> 656 657 658 659<li class="devsite-nav-item"> 660 661 662 <a href="/support/overview" 663 664 class="devsite-nav-title gc-analytics-event 665 devsite-nav-has-children 666 " 667 668 669 670 671 data-category="Site-Wide Custom Events" 672 673 data-label="Tab: Support" 674 675 track-name="support" 676 677 678 data-category="Site-Wide Custom Events" 679 data-label="Responsive Tab: Support" 680 track-type="navMenu" 681 track-metadata-eventDetail="globalMenu" 682 track-metadata-position="nav"> 683 684 <span class="devsite-nav-text" tooltip > 685 Support 686 </span> 687 688 <span class="devsite-nav-icon material-icons" data-icon="forward" 689 > 690 </span> 691 692 693 </a> 694 695 696</li> 697 698 699 700 701 </ul> 702 703 </div> 704 705 <div class="devsite-mobile-nav-bottom"> 706 707 708 <ul class="devsite-nav-list" menu="_book"> 709 <li class="devsite-nav-item"><a href="/getting-started/overview" 710 class="devsite-nav-title" 711 ><span class="devsite-nav-text" tooltip>Overview</span></a></li> 712 713 <li class="devsite-nav-item 714 devsite-nav-heading"><div class="devsite-nav-title devsite-nav-title-no-path">
715 <span class="devsite-nav-text" tooltip>Get started</span> 716 </div></li> 717 718 <li class="devsite-nav-item"><a href="/getting-started/media-devices" 719 class="devsite-nav-title" 720 ><span class="devsite-nav-text" tooltip>Media devices</span></a></li> 721 722 <li class="devsite-nav-item"><a href="/getting-started/media-capture-and-constraints" 723 class="devsite-nav-title" 724 ><span class="devsite-nav-text" tooltip>Media capture and constraints</span></a></li> 725 726 <li class="devsite-nav-item"><a href="/getting-started/peer-connections" 727 class="devsite-nav-title" 728 ><span class="devsite-nav-text" tooltip>Peer connections</span></a></li> 729 730 <li class="devsite-nav-item"><a href="/getting-started/remote-streams" 731 class="devsite-nav-title" 732 ><span class="devsite-nav-text" tooltip>Remote streams</span></a></li> 733 734 <li class="devsite-nav-item"><a href="/getting-started/data-channels" 735 class="devsite-nav-title" 736 ><span class="devsite-nav-text" tooltip>Data channels</span></a></li> 737 738 <li class="devsite-nav-item"><a href="/getting-started/turn-server" 739 class="devsite-nav-title" 740 ><span class="devsite-nav-text" tooltip>TURN server</span></a></li> 741 742 <li class="devsite-nav-item"><a href="/getting-started/testing" 743 class="devsite-nav-title" 744 ><span class="devsite-nav-text" tooltip>Testing</span></a></li> 745 746 <li class="devsite-nav-item"><a href="/getting-started/unified-plan-transition-guide" 747 class="devsite-nav-title" 748 ><span class="devsite-nav-text" tooltip>Unified Plan transition guide</span></a></li> 749 750 <li class="devsite-nav-item 751 devsite-nav-heading"><div class="devsite-nav-title devsite-nav-title-no-path"> 752 <span class="devsite-nav-text" tooltip>Codelabs</span> 753 </div></li> 754 755 <li class="devsite-nav-item"><a href="/getting-started/firebase-rtc-codelab" 756 class="devsite-nav-title" 757 ><span class="devsite-nav-text" tooltip>FirebaseRTC Code lab</span></a></li> 758 </ul> 759 760 761 762 763 764 765 766 767 768 769 770 </div> 771 772 </div> 773</nav> 774 775 </devsite-book-nav> 776 777 <section id="gc-wrapper"> 778 <main role="main" id="main-content" class="devsite-main-content" 779 780 has-book-nav 781 has-sidebar 782 > 783 <div class="devsite-sidebar"> 784 <div class="devsite-sidebar-content"> 785 786 <devsite-toc class="devsite-nav" 787 role="navigation" 788 aria-label="On this page" 789 depth="2" 790 scrollbars 791 data-nosnippet 792 ></devsite-toc> 793 <devsite-recommendations-sidebar class="nocontent devsite-nav" data-nosnippet> 794 </devsite-recommendations-sidebar> 795 </div> 796 </div> 797 <devsite-content> 798 799 800 801 802 803 804 805 806 807 808 809 810<article class="devsite-article"> 811 812 813 814 <div class="devsite-banner devsite-banner-announcement nocontent" data-nosnippet 815 816 817 > 818 <div class="devsite-banner-message"> 819 <div class="devsite-banner-message-text"> 820 <style> 821 .devsite-banner-announcement:not(.devsite-banner-tenant) { 822 background: #202124; 823 color: white; 824 font-weight: 500; 825 } 826 .devsite-banner-announcement a { 827 color: white; 828 font-weight: 700; 829 } 830 .devsite-banner-announcement a:link:not(.button), 831 .devsite-banner-announcement a:visited:not(.button) { 832 background: 0; 833 } 834 .devsite-banner-announcement a:hover, 835 .devsite-banner-announcement a:focus { 836 text-decoration: none; 837 } 838 .devsite-banner-announcement .devsite-banner-message-text { 839 margin: 0 auto; 840 } 841</style> <span class="nocontent"> 842 Google is committed to advancing racial equity for Black communities. 843</span> <a href="https://google.com/racialequity" 844 class="gc-analytics-event nocontent" 845 data-category="Announcement" 846 data-label="Racial Equity">See how.</a> 847 </div> 848 </div> 849 </div> 850 851 852 853 854 <div class="devsite-article-meta nocontent" role="navigation" data-nosnippet> 855 856 857 <ul class="devsite-breadcrumb-list" 858 859 aria-label="Breadcrumb"> 860 861 <li class="devsite-breadcrumb-item 862 "> 863 864 865 866 867 868 <a href="https://webrtc.org/" 869 870 class="devsite-breadcrumb-link gc-analytics-event" 871 872 data-category="Site-Wide Custom Events" 873 874 data-label="Breadcrumbs" 875 876 data-value="1" 877 878 track-type="globalNav" 879 880 track-name="breadcrumb" 881 882 track-metadata-position="1" 883 884 track-metadata-eventdetail="WebRTC" 885 886 > 887 888 WebRTC 889 890 </a> 891 892 893 894 </li> 895 896 <li class="devsite-breadcrumb-item 897 "> 898 899 900 <div class="devsite-breadcrumb-guillemet material-icons" aria-hidden="true"></div> 901 902 903 904 905 906 <a href="https://webrtc.org/getting-started/overview" 907 908 class="devsite-breadcrumb-link gc-analytics-event" 909 910 data-category="Site-Wide Custom Events" 911 912 data-label="Breadcrumbs" 913 914 data-value="2" 915 916 track-type="globalNav" 917 918 track-name="breadcrumb" 919 920 track-metadata-position="2" 921 922 track-metadata-eventdetail="" 923 924 > 925 926 Guides 927 928 </a> 929 930 931 932 </li> 933 934</ul> 935 936 937 <devsite-thumb-rating position="header"> 938 </devsite-thumb-rating> 939 940 941 </div> 942 943 <h1 class="devsite-page-title" tabindex="-1"> 944 Firebase + WebRTC Codelab<devsite-actions hidden data-nosnippet></devsite-actions> 945 946 947 </h1> 948 <div class="devsite-page-title-meta"><devsite-view-release-notes></devsite-view-release-notes></div> 949 950 951 <devsite-toc class="devsite-nav" 952 depth="2" 953 devsite-toc-embedded 954 > 955 </devsite-toc> 956 957 958 <div class="devsite-article-body clearfix 959 "> 960 961 962 963 964 965 966<h2 id="1_introduction" data-text="1. Introduction" tabindex="-1">1. Introduction</h2> 967 968<p>In this codelab, you'll learn how to build a simple video chat application using 969the WebRTC API in your browser and Cloud Firestore for signaling. The 970application is called FirebaseRTC and works as a simple example that will teach 971you the basics of building WebRTC enabled applications.</p> 972 973<blockquote> 974<aside class="note"><strong>Note:</strong><span> Another option for signaling could be Firebase Cloud Messaging. However, 975that is currently only supported in Chrome and in this codelab we will focus 976on a solution that works across all browsers supporting WebRTC.</span></aside></blockquote> 977 978<h3 id="what_youll_learn" data-text="What you'll learn" tabindex="-1">What you'll learn</h3> 979 980<ul> 981<li>Initiating a video call in a web application using WebRTC</li> 982<li>Signaling to the remote party using Cloud Firestore</li> 983</ul> 984 985<h3 id="what_youll_need" data-text="What you'll need" tabindex="-1">What you'll need</h3> 986 987<p>Before starting this codelab, make sure that you've installed:</p> 988 989<ul> 990<li>npm which typically comes with Node.js - Node LTS is recommended</li> 991</ul> 992 993<h2 id="2_create_and_set_up_a_firebase_project" data-text="2. Create and set up a Firebase project" tabindex="-1">2. Create and set up a Firebase project</h2> 994 995<h3 id="create_a_firebase_project" data-text="Create a Firebase project" tabindex="-1">Create a Firebase project</h3> 996 997<ol> 998<li><a href="https://console.firebase.google.com">In the Firebase console</a>, click Add 999project, then name the Firebase project FirebaseRTC.</li> 1000</ol> 1001 1002<p>Remember the Project ID for your Firebase project.</p> 1003 1004<blockquote> 1005<aside class="note"><strong>Note:</strong><span> If you go to the home page of your project, you can see it in Settings > 1006Project Settings (or look at the URL!)</span></aside></blockquote> 1007 1008<ol> 1009<li>Click Create project.</li> 1010</ol> 1011 1012<p>The application that you're going to build uses two Firebase services available 1013on the web:</p> 1014 1015<ul> 1016<li>Cloud Firestore to save structured data on the Cloud and get instant 1017notification when the data is updated</li> 1018<li>Firebase Hosting to host and serve your static assets</li> 1019</ul> 1020 1021<p>For this specific codelab, you've already configured Firebase Hosting in the 1022project you'll be cloning. However, for Cloud Firestore, we'll walk you through 1023the configuration and enabling of the services using the Firebase console.</p> 1024 1025<h3 id="enable_cloud_firestore" data-text="Enable Cloud Firestore" tabindex="-1">Enable Cloud Firestore</h3> 1026 1027<p>The app uses Cloud Firestore to save the chat messages and receive new chat 1028messages.</p> 1029 1030<p>You'll need to enable Cloud Firestore:</p> 1031 1032<ol> 1033<li>In the Firebase console menu's Develop section, click Database.</li> 1034<li>Click <strong>Create database</strong> in the Cloud Firestore pane.</li> 1035<li>Select the <strong>Start in test mode</strong> option, then click Enable after reading the 1036disclaimer about the security rules.</li> 1037</ol> 1038 1039<p>Test mode ensures that you can freely write to the database during development. 1040We'll make our database more secure later on in this codelab.</p> 1041 1042<h2 id="3_get_the_sample_code" data-text="3. Get the sample code" tabindex="-1">3. Get the sample code</h2> 1043 1044<p>Clone the GitHub repository from the command line:</p> 1045<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Bash"><code translate="no" dir="ltr">git<span class="devsite-syntax-w"> </span>clone<span class="devsite-syntax-w"> </span>https://github.com/webrtc/FirebaseRTC 1046</code></pre></devsite-code> 1047<p>The sample code should have been cloned into the <code translate="no" dir="ltr">FirebaseRTC</code> directory. 1048Make sure your command line is run from this directory from now on:</p> 1049<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Bash"><code translate="no" dir="ltr"><span class="devsite-syntax-nb">cd</span><span class="devsite-syntax-w"> </span>FirebaseRTC 1050</code></pre></devsite-code> 1051<h3 id="import_the_starter_app" data-text="Import the starter app" tabindex="-1">Import the starter app</h3> 1052 1053<p>Open the files in <code translate="no" dir="ltr">FirebaseRTC</code> in your editor and change them according to 1054the instructions below. This directory contains the starting code for the 1055codelab which consists of a not-yet functional WebRTC app. We'll make it 1056functional throughout this codelab.</p> 1057 1058<h2 id="4_install_the_firebase_command_line_interface" data-text="4. Install the Firebase Command Line Interface" tabindex="-1">4. Install the Firebase Command Line Interface</h2> 1059 1060<p>The Firebase Command Line Interface (CLI) allows you to serve your web app 1061locally and deploy your web app to Firebase Hosting.</p> 1062 1063<blockquote> 1064<aside class="note"><strong>Note:</strong><span> To install the CLI, you need to install npm which typically comes with 1065Node.js.</span></aside></blockquote> 1066 1067<ol> 1068<li>Install the CLI by running the following npm command: 1069<code translate="no" dir="ltr">sh 1070npm -g install firebase-tools</code></li> 1071</ol> 1072 1073<blockquote> 1074<aside class="note"><strong>Note:</strong><span> Doesn't work? You may need to run the command using <code translate="no" dir="ltr">sudo</code> instead.</span></aside></blockquote> 1075 1076<ol> 1077<li>Verify that the CLI has been installed correctly by running the following 1078command: 1079<code translate="no" dir="ltr">sh 1080firebase --version</code></li> 1081</ol> 1082 1083<p>Make sure the version of the Firebase CLI is v6.7.1 or later.</p> 1084 1085<ol> 1086<li>Authorize the Firebase CLI by running the following command: 1087<code translate="no" dir="ltr">sh 1088firebase login</code></li> 1089</ol> 1090 1091<p>You've set up the web app template to pull your app's configuration for Firebase 1092Hosting from your app's local directory and files. But to do this, you need to 1093associate your app with your Firebase project.</p> 1094 1095<ol> 1096<li><p>Associate your app with your Firebase project by running the following 1097command: 1098<code translate="no" dir="ltr">sh 1099firebase use --add</code></p></li> 1100<li><p>When prompted, select your Project ID, then give your Firebase project an 1101alias.</p></li> 1102</ol> 1103 1104<p>An alias is useful if you have multiple environments (production, staging, etc). 1105However, for this codelab, let's just use the alias of <code translate="no" dir="ltr">default</code>.</p> 1106 1107<ol> 1108<li><p>Follow the remaining instructions in your command line.</p></li> 1109</ol> 1110 1111<h2 id="5_run_the_local_server" data-text="5. Run the local server" tabindex="-1">5. Run the local server</h2> 1112 1113<p>You're ready to actually start work on our app! Let's run the app locally!</p> 1114 1115<ol> 1116<li><p>Run the following Firebase CLI command: 1117<code translate="no" dir="ltr">sh 1118firebase serve --only hosting</code></p></li> 1119<li><p>Your command line should display the following response: 1120<code translate="no" dir="ltr">hosting: Local server: http://localhost:5000</code></p></li> 1121</ol> 1122 1123<p>We're using the Firebase Hosting emulator to serve our app locally. The web app 1124should now be available from http://localhost:5000.</p> 1125 1126<ol> 1127<li>Open your app at http://localhost:5000.</li> 1128</ol> 1129 1130<p>You should see your copy of FirebaseRTC which has been connected to your 1131Firebase project.</p> 1132 1133<p>The app has automatically connected to your Firebase project.</p> 1134 1135<h2 id="6_creating_a_new_room" data-text="6. Creating a new room" tabindex="-1">6. Creating a new room</h2> 1136 1137<p>In this application, each video chat session is called a room. A user can create 1138a new room by clicking a button in their application. This will generate an ID 1139that the remote party can use to join the same room. The ID is used as the key 1140in Cloud Firestore for each room.</p> 1141 1142<p>
1142Each room will contain the <code translate="no" dir="ltr">RTCSessionDescriptions</code> for both the offer and the 1143answer, as well as two separate collections with ICE candidates from each party.</p> 1144 1145<p>Your first task is to implement the missing code for creating a new room with 1146the initial offer from the caller. Open <code translate="no" dir="ltr">public/app.js</code> and find the comment <code translate="no" dir="ltr">// 1147Add code for creating a room here</code> and add the following code:</p> 1148<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="JavaScript"><code translate="no" dir="ltr"><span class="devsite-syntax-kd">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">offer</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">await</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">peerConnection</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">createOffer</span><span class="devsite-syntax-p">();</span> 1149<span class="devsite-syntax-k">await</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">peerConnection</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">setLocalDescription</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nx">offer</span><span class="devsite-syntax-p">);</span> 1150 1151<span class="devsite-syntax-kd">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">roomWithOffer</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> 1152<span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">offer</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> 1153<span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">type</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">offer</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">type</span><span class="devsite-syntax-p">,</span> 1154<span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">sdp</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">offer</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">sdp</span> 1155<span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> 1156<span class="devsite-syntax-p">}</span> 1157<span class="devsite-syntax-kd">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">roomRef</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">await</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">db</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">collection</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'rooms'</span><span class="devsite-syntax-p">).</span><span class="devsite-syntax-nx">add</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nx">roomWithOffer</span><span class="devsite-syntax-p">);</span> 1158<span class="devsite-syntax-kd">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">roomId</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">roomRef</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">id</span><span class="devsite-syntax-p">;</span> 1159<span class="devsite-syntax-nb">document</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">querySelector</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'#currentRoom'</span><span class="devsite-syntax-p">).</span><span class="devsite-syntax-nx">innerText</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-sb">`Current room is </span><span class="devsite-syntax-si">${</span><span class="devsite-syntax-nx">roomId</span><span class="devsite-syntax-si">}</span><span class="devsite-syntax-sb"> - You are the caller!`</span> 1160</code></pre></devsite-code> 1161<p>The first line creates an <code translate="no" dir="ltr">RTCSessionDescription</code> that will represent the offer 1162from the caller. This is then set as the local description, and finally written 1163to the new room object in Cloud Firestore.</p> 1164 1165<p>Next, we will listen for changes to the database and detect when an answer from 1166the callee has been added.</p> 1167<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="JavaScript"><code translate="no" dir="ltr"><span class="devsite-syntax-nx">roomRef</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">onSnapshot</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-k">async</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">snapshot</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">-</span>><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> 1168<span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">console</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">log</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'Got updated room:'</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">snapshot</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">data</span><span class="devsite-syntax-p">());</span> 1169<span class="devsite-syntax-w"> </span><span class="devsite-syntax-kd">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">data</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">snapshot</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">data</span><span class="devsite-syntax-p">();</span> 1170<span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-o">!</span><span class="devsite-syntax-nx">peerConnection</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">currentRemoteDescription</span><span class="devsite-syntax-w"> && </span><span class="devsite-syntax-nx">data</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">answer</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> 1171<span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">console</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">log</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'Set remote description: '</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">data</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">answer</span><span class="devsite-syntax-p">);</span> 1172<span class="devsite-syntax-w"> </span><span class="devsite-syntax-kd">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">answer</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-ow">new</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">RTCSessionDescription</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nx">data</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">answer</span><span class="devsite-syntax-p">)</span> 1173<span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">await</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">peerConnection</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">setRemoteDescription</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nx">answer</span><span class="devsite-syntax-p">);</span> 1174<span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> 1175<span class="devsite-syntax-p">});
1175</span> 1176</code></pre></devsite-code> 1177<p>This will wait until the callee writes the <code translate="no" dir="ltr">RTCSessionDescription</code> for the 1178answer, and set that as the remote description on the caller 1179<code translate="no" dir="ltr">RTCPeerConnection</code>.</p> 1180 1181<h2 id="7_joining_a_room" data-text="7. Joining a room" tabindex="-1">7. Joining a room</h2> 1182 1183<p>The next step is to implement the logic for joining an existing room. The user 1184does this by clicking the <strong>Join room</strong> button and entering the ID for the room 1185to join. Your task here is to implement the creation of the 1186<code translate="no" dir="ltr">RTCSessionDescription</code> for the answer and update the room in the database 1187accordingly.</p> 1188<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="JavaScript"><code translate="no" dir="ltr"><span class="devsite-syntax-kd">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">offer</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">roomSnapshot</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">data</span><span class="devsite-syntax-p">().</span><span class="devsite-syntax-nx">offer</span><span class="devsite-syntax-p">;</span> 1189<span class="devsite-syntax-k">await</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">peerConnection</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">setRemoteDescription</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nx">offer</span><span class="devsite-syntax-p">);</span> 1190<span class="devsite-syntax-kd">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">answer</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">await</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">peerConnection</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">createAnswer</span><span class="devsite-syntax-p">();</span> 1191<span class="devsite-syntax-k">await</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">peerConnection</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">setLocalDescription</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nx">answer</span><span class="devsite-syntax-p">);</span> 1192 1193<span class="devsite-syntax-kd">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">roomWithAnswer</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> 1194<span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">answer</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> 1195<span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">type</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">answer</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">type</span><span class="devsite-syntax-p">,</span> 1196<span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">sdp</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">answer</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">sdp</span> 1197<span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> 1198<span class="devsite-syntax-p">}</span> 1199<span class="devsite-syntax-k">await</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">roomRef</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">update</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nx">roomWithAnswer</span><span class="devsite-syntax-p">);</span> 1200</code></pre></devsite-code> 1201<p>In the code above, we start by extracting the offer from the caller and creating 1202a <code translate="no" dir="ltr">RTCSessionDescription</code> that we set as the remote description. Next, we create 1203the answer, set it as the local description, and update the database. The update 1204of the database will trigger the <code translate="no" dir="ltr">onSnapshot</code> callback on the caller side, which 1205in turn will set the remote description based on the answer from the callee. 1206This completes the exchange of the <code translate="no" dir="ltr">RTCSessionDescription</code> objects between the 1207caller and the callee.</p> 1208 1209<h2 id="8_collect_ice_candidates" data-text="8. Collect ICE candidates" tabindex="-1">8. Collect ICE candidates</h2> 1210 1211<p>Before the caller and callee can connect to each other, they also need to 1212exchange ICE candidates that tell WebRTC how to connect to the remote peer. 1213Your next task is to implement the code that listens for ICE candidates and adds 1214them to a collection in the database. Find the function <code translate="no" dir="ltr">collectIceCandidates</code> 1215and add the following code:</p> 1216<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="JavaScript"><code translate="no" dir="ltr"><span class="devsite-syntax-k">async</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-kd">function</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">collectIceCandidates</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nx">roomRef</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">peerConnection</span><span class="devsite-syntax-p">,</span> 1217<span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">localName</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">remoteName</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> 1218<span class="devsite-syntax-w"> </span><span class="devsite-syntax-kd">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">candidatesCollection</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">roomRef</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">collection</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nx">localName</span><span class="devsite-syntax-p">);</span> 1219 1220<span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">peerConnection</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">addEventListener</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">
1220'icecandidate'</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">event</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">-</span>><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> 1221<span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nx">event</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">candidate</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> 1222<span class="devsite-syntax-w"> </span><span class="devsite-syntax-kd">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">json</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">event</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">candidate</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">toJSON</span><span class="devsite-syntax-p">();</span> 1223<span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">candidatesCollection</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">add</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nx">json</span><span class="devsite-syntax-p">);</span> 1224<span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> 1225<span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">});</span> 1226 1227<span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">roomRef</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">collection</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nx">remoteName</span><span class="devsite-syntax-p">).</span><span class="devsite-syntax-nx">onSnapshot</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nx">snapshot</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">-</span>><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> 1228<span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">snapshot</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">docChanges</span><span class="devsite-syntax-p">().</span><span class="devsite-syntax-nx">forEach</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nx">change</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">-</span>><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> 1229<span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nx">change</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">type</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">===</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s2">"added"</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> 1230<span class="devsite-syntax-w"> </span><span class="devsite-syntax-kd">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">candidate</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-ow">new</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">RTCIceCandidate</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nx">change</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">doc</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">data</span><span class="devsite-syntax-p">());</span> 1231<span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">peerConnection</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">addIceCandidate</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nx">candidate</span><span class="devsite-syntax-p">);</span> 1232<span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> 1233<span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">});
1233</span> 1234<span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">})</span> 1235<span class="devsite-syntax-p">}</span> 1236</code></pre></devsite-code> 1237<p>This function does two things. It collects ICE candidates from the WebRTC API and 1238adds them to the database, and listens for added ICE candidates from the remote 1239peer and adds them to its <code translate="no" dir="ltr">RTCPeerConnection</code> instance. It is important when 1240listening to database changes to filter out anything that isn't a new addition, 1241since we otherwise would have added the same set of ICE candidates over and over 1242again.</p> 1243 1244<h2 id="9_conclusion" data-text="9. Conclusion" tabindex="-1">9. Conclusion</h2> 1245 1246<p>In this codelab you learned how to implement signaling for WebRTC using Cloud 1247Firestore, as well as how to use that for creating a simple video chat 1248application.</p> 1249 1250<p>To learn more, visit the following resources:</p> 1251 1252<ol> 1253<li><a href="https://github.com/webrtc/FirebaseRTC">FirebaseRTC Source Code</a></li> 1254<li><a href="https://webrtc.github.io/samples">WebRTC samples</a></li> 1255<li><a href="https://firebase.google.com/docs/firestore/">Cloud Firestore</a></li> 1256</ol> 1257 1258 1259 1260 1261</div> 1262 1263 1264 1265 1266 1267 <devsite-thumb-rating position="footer"> 1268 </devsite-thumb-rating> 1269 1270 1271 1272 1273 1274 1275 <div class="devsite-floating-action-buttons"></div></article> 1276 1277 1278<devsite-content-footer class="nocontent" data-nosnippet> 1279 <p>Except as otherwise noted, the content of this page is licensed under the <a href="https://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 License</a>, and code samples are licensed under the <a href="https://www.apache.org/licenses/LICENSE-2.0">Apache 2.0 License</a>. For details, see the <a href="https://developers.google.com/site-policies">Google Developers Site Policies</a>. Java is a registered trademark of Oracle and/or its affiliates.</p> 1280 <p>Last updated 2023-03-29 UTC.</p> 1281</devsite-content-footer> 1282 1283 1284<devsite-notification 1285> 1286</devsite-notification> 1287 1288 1289 1290<div class="devsite-content-data"> 1291 1292 1293 <template class="devsite-content-data-template"> 1294 [[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2023-03-29 UTC."],[],[]] 1295 </template> 1296 1297</div> 1298 1299 </devsite-content> 1300 </main> 1301 <devsite-footer-promos class="devsite-footer"> 1302 1303 1304 1305 </devsite-footer-promos> 1306 <devsite-footer-linkboxes class="devsite-footer"> 1307 1308 1309<nav class="devsite-footer-linkboxes nocontent" 1310 aria-label="Footer links" 1311 data-nosnippet> 1312 1313 <ul class="devsite-footer-linkboxes-list"> 1314 1315 <li class="devsite-footer-linkbox "> 1316 <h3 class="devsite-footer-linkbox-heading no-link">Key topics</h3> 1317 <ul class="devsite-footer-linkbox-list"> 1318 1319 <li class="devsite-footer-linkbox-item"> 1320 1321 <a href="//developer.mozilla.org/en-US/docs/Glossary/WebRTC" 1322 class="devsite-footer-linkbox-link gc-analytics-event" 1323 data-category="Site-Wide Custom Events" 1324 1325 data-label="Footer Link (index 1)" 1326 > 1327 1328 1329 WebRTC on MDN 1330 1331 </a> 1332 1333 1334 </li> 1335 1336 <li class="devsite-footer-linkbox-item"> 1337 1338 <a href="//webrtc.github.io/samples/" 1339 class="devsite-footer-linkbox-link gc-analytics-event" 1340 data-category="Site-Wide Custom Events" 1341 1342 data-label="Footer Link (index 2)" 1343 > 1344 1345 1346 Samples 1347 1348 </a> 1349 1350 1351 </li> 1352 1353 <li class="devsite-footer-linkbox-item"> 1354 1355 <a href="//webrtc.googlesource.com/src" 1356 class="devsite-footer-linkbox-link gc-analytics-event" 1357 data-category="Site-Wide Custom Events" 1358 1359 data-label="Footer Link (index 3)" 1360 > 1361 1362 1363 1364 1365 1366 Source repository 1367 1368 </a> 1369 1370 1371 </li> 1372 1373 </ul> 1374 </li> 1375 1376 <li class="devsite-footer-linkbox "> 1377 <h3 class="devsite-footer-linkbox-heading no-link">Support</h3> 1378 <ul class="devsite-footer-linkbox-list"> 1379 1380 <li class="devsite-footer-linkbox-item"> 1381 1382 <a href="//groups.google.com/forum/#!forum/discuss-webrtc" 1383 class="devsite-footer-linkbox-link gc-analytics-event" 1384 data-category="Site-Wide Custom Events" 1385 1386 data-label="Footer Link (index 1)" 1387 > 1388 1389 1390 Google Groups 1391 1392 </a> 1393 1394 1395 </li> 1396 1397 <li class="devsite-footer-linkbox-item"> 1398 1399 <a href="//stackoverflow.com/questions/tagged/webrtc" 1400 class="devsite-footer-linkbox-link gc-analytics-event" 1401 data-category="Site-Wide Custom Events" 1402 1403 data-label="Footer Link (index 2)" 1404 > 1405 1406 1407 Stack Overflow 1408 1409 </a> 1410 1411 1412 </li> 1413 1414 <li class="devsite-footer-linkbox-item"> 1415 1416 <a href="//twitter.com/webrtc" 1417 class="devsite-footer-linkbox-link gc-analytics-event" 1418 data-category="Site-Wide Custom Events" 1419 1420 data-label="Footer Link (index 3)" 1421 > 1422 1423 1424 1425 1426 1427 Twitter 1428 1429 </a> 1430 1431 1432 </li> 1433 1434 </ul> 1435 </li> 1436 1437 </ul> 1438 1439</nav> 1440 1441 </devsite-footer-linkboxes> 1442 <devsite-footer-utility class="devsite-footer"> 1443 1444 1445 1446<div class="devsite-footer-utility nocontent" data-nosnippet> 1447 1448 1449 <nav class="devsite-footer-sites" aria-label="Other Google Developers websites"> 1450 <a href="https://developers.google.com/" 1451 class="devsite-footer-sites-logo-link gc-analytics-event" 1452 data-category="Site-Wide Custom Events" 1453 data-label="Footer Google Developers Link"> 1454 <picture> 1455
1456 <source srcset="https://www.gstatic.com/devrel-devsite/prod/v5be16d8c9f9402e54c2da2ff24cb75c148f5d2bc84c6f8dfc8b9e16ae456160b/webrtc/images/lockup-google-for-developers-dark-theme.svg" 1457 media="(prefers-color-scheme: none)" 1458 class="devsite-dark-theme"> 1459 1460 <img class="devsite-footer-sites-logo" 1461 src="https://www.gstatic.com/devrel-devsite/prod/v5be16d8c9f9402e54c2da2ff24cb75c148f5d2bc84c6f8dfc8b9e16ae456160b/webrtc/images/lockup-google-for-developers.svg" 1462 loading="lazy" 1463 alt="Google Developers"> 1464 </picture> 1465 </a> 1466 <ul class="devsite-footer-sites-list"> 1467 1468 <li class="devsite-footer-sites-item"> 1469 <a href="//developer.android.com" 1470 class="devsite-footer-sites-link 1471 gc-analytics-event" 1472 data-category="Site-Wide Custom Events" 1473 1474 data-label="Footer Android Link" 1475 1476 > 1477 Android 1478 </a> 1479 </li> 1480 1481 <li class="devsite-footer-sites-item"> 1482 <a href="//developer.chrome.com/home" 1483 class="devsite-footer-sites-link 1484 gc-analytics-event" 1485 data-category="Site-Wide Custom Events" 1486 1487 data-label="Footer Chrome Link" 1488 1489 > 1490 Chrome 1491 </a> 1492 </li> 1493 1494 <li class="devsite-footer-sites-item"> 1495 <a href="//firebase.google.com" 1496 class="devsite-footer-sites-link 1497 gc-analytics-event" 1498 data-category="Site-Wide Custom Events" 1499 1500 data-label="Footer Firebase Link" 1501 1502 > 1503 Firebase 1504 </a> 1505 </li> 1506 1507 <li class="devsite-footer-sites-item"> 1508 <a href="//cloud.google.com" 1509 class="devsite-footer-sites-link 1510 gc-analytics-event" 1511 data-category="Site-Wide Custom Events" 1512 1513 data-label="Footer Google Cloud Platform Link" 1514 1515 > 1516 Google Cloud Platform 1517 </a> 1518 </li> 1519 1520 <li class="devsite-footer-sites-item"> 1521 <a href="//developers.google.com/products/" 1522 class="devsite-footer-sites-link 1523 gc-analytics-event" 1524 data-category="Site-Wide Custom Events" 1525 1526 data-label="Footer All products Link" 1527 1528 > 1529 All products 1530 </a> 1531 </li> 1532 1533 </ul> 1534 </nav> 1535 1536 1537 1538 <nav class="devsite-footer-utility-links" aria-label="Utility links"> 1539 1540 <ul class="devsite-footer-utility-list"> 1541 1542 <li class="devsite-footer-utility-item 1543 "> 1544 1545 1546 <a class="devsite-footer-utility-link gc-analytics-event" 1547 href="//policies.google.com/terms" 1548 data-category="Site-Wide Custom Events" 1549 data-label="Footer Terms link" 1550 > 1551 Terms 1552 </a> 1553 1554 </li> 1555 1556 <li class="devsite-footer-utility-item 1557 "> 1558 1559 1560 <a class="devsite-footer-utility-link gc-analytics-event" 1561 href="//policies.google.com/privacy" 1562 data-category="Site-Wide Custom Events" 1563 data-label="Footer Privacy link" 1564 > 1565 Privacy 1566 </a> 1567 1568 </li> 1569 1570 <li class="devsite-footer-utility-item 1571 glue-cookie-notification-bar-control"> 1572 1573 1574 <a class="devsite-footer-utility-link gc-analytics-event" 1575 href="#" 1576 data-category="Site-Wide Custom Events" 1577 data-label="Footer Manage cookies link" 1578 1579 aria-hidden="true" 1580 > 1581 Manage cookies 1582 </a> 1583 1584 </li> 1585 1586 </ul> 1587 1588 1589<devsite-language-selector> 1590 <ul role="presentation"> 1591 1592 1593 <li role="presentation"> 1594 <a role="menuitem" lang="en" 1595 >English</a> 1596 </li> 1597 1598 <li role="presentation"> 1599 <a role="menuitem" lang="de" 1600 >Deutsch</a> 1601 </li> 1602 1603 <li role="presentation"> 1604 <a role="menuitem" lang="es" 1605 >Español</a> 1606 </li> 1607 1608 <li role="presentation"> 1609 <a role="menuitem" lang="es_419" 1610 >Español â América Latina</a> 1611 </li> 1612 1613 <li role="presentation"> 1614 <a role="menuitem" lang="fr" 1615 >Français</a> 1616 </li> 1617 1618 <li role="presentation"> 1619 <a role="menuitem" lang="id" 1620 >Indonesia</a> 1621 </li> 1622 1623 <li role="presentation"> 1624 <a role="menuitem" lang="it" 1625 >Italiano</a> 1626 </li> 1627 1628 <li role="presentation"> 1629 <a role="menuitem" lang="pl" 1630 >Polski</a> 1631 </li> 1632 1633 <li role="presentation"> 1634 <a role="menuitem" lang="pt" 1635 >Português</a> 1636 </li> 1637 1638 <li role="presentation"> 1639 <a role="menuitem" lang="pt_br" 1640 >Português â Brasil</a> 1641 </li> 1642 1643 <li role="presentation"> 1644 <a role="menuitem" lang="vi" 1645 >TiêÌng Việt</a> 1646 </li> 1647 1648 <li role="presentation"> 1649 <a role="menuitem" lang="tr" 1650 >Türkçe</a> 1651 </li> 1652 1653 <li role="presentation"> 1654 <a role="menuitem" lang="ru" 1655 >Ð ÑÑÑкий</a> 1656 </li> 1657 1658 <li role="presentation"> 1659 <a role="menuitem" lang="he" 1660 >×¢×ר×ת</a> 1661 </li> 1662 1663 <li role="presentation"> 1664 <a role="menuitem" lang="ar" 1665 >Ø§ÙØ¹Ø±Ø¨ÙÙØ©</a> 1666 </li> 1667 1668 <li role="presentation"> 1669 <a role="menuitem" lang="fa" 1670 >ÙØ§Ø±Ø³Û</a> 1671 </li> 1672 1673 <li role="presentation"> 1674 <a role="menuitem" lang="hi" 1675 >हिà¤à¤¦à¥</a> 1676 </li> 1677 1678 <li role="presentation"> 1679 <a role="menuitem" lang="bn" 1680 >বাà¦à¦²à¦¾</a> 1681 </li> 1682 1683 <li role="presentation"> 1684 <a role="menuitem" lang="th" 1685 >ภาษาà¹à¸à¸¢</a> 1686 </li> 1687 1688 <li role="presentation"> 1689 <a role="menuitem" lang="zh_cn" 1690 >䏿 â ç®ä½</a> 1691 </li> 1692 1693 <li role="presentation"> 1694 <a role="menuitem" lang="zh_tw" 1695 >䏿 â ç¹é«</a> 1696 </li> 1697 1698 <li role="presentation"> 1699 <a role="menuitem" lang="ja" 1700 >æ¥æ¬èª</a> 1701 </li> 1702 1703 <li role="presentation"> 1704 <a role="menuitem" lang="ko" 1705 >íêµì´</a> 1706 </li> 1707 1708 </ul> 1709</devsite-language-selector> 1710 1711 </nav> 1712</div> 1713 1714 </devsite-footer-utility> 1715 <devsite-panel> 1716 1717 </devsite-panel> 1718 1719 </section> 1720 </section> 1721 <devsite-sitemask></devsite-sitemask> 1722 <devsite-snackbar></devsite-snackbar> 1723 <devsite-tooltip ></devsite-tooltip> 1724 <devsite-heading-link></devsite-heading-link> 1725 <devsite-analytics> 1726 1727
1727<script type="application/json" analytics>[{"dimensions": {"dimension5": false, "dimension1": "Signed out", "dimension2": false, "dimension4": "en", "dimension3": "en"}, "gaid": "UA-23466548-1", "metrics": {"ratings_count": "metric2", "ratings_value": "metric1"}, "purpose": 0}]</script>
vendor: 1 bytes, line 1727
1727
1728<script type="application/json" tag-management>{"at": "True", "ga4": [{"id": "G-KRN165NY0F", "purpose": 0}], "ga4p": [{"id": "G-KRN165NY0F", "purpose": 0}], "gtm": [], "parameters": {"internalUser": "False", "language": {"machineTranslated": "False", "requested": "en", "served": "en"}, "pageType": "article", "projectName": "WebRTC", "signedIn": "False", "tenant": "webrtc", "recommendations": {"sourcePage": "", "sourceType": 0, "sourceRank": 0, "sourceIdenticalDescriptions": 0, "sourceTitleWords": 0, "sourceDescriptionWords": 0, "experiment": ""}, "experiment": {"ids": ""}}}</script>
1728 1729 1730 </devsite-analytics> 1731 1732 1733 1734
1735<script nonce="sa0r4ivZvbhbg9VIvvvn8iqzddDI1q"> 1736 1737 (function(d,e,v,s,i,t,E){d['GoogleDevelopersObject']=i; 1738 t=e.createElement(v);t.async=1;t.src=s;E=e.getElementsByTagName(v)[0]; 1739 E.parentNode.insertBefore(t,E);})(window, document, 'script', 1740 'https://www.gstatic.com/devrel-devsite/prod/v5be16d8c9f9402e54c2da2ff24cb75c148f5d2bc84c6f8dfc8b9e16ae456160b/webrtc/js/app_loader.js', '[25,"en",null,"/js/devsite_app_module.js","https://www.gstatic.com/devrel-devsite/prod/v5be16d8c9f9402e54c2da2ff24cb75c148f5d2bc84c6f8dfc8b9e16ae456160b","https://www.gstatic.com/devrel-devsite/prod/v5be16d8c9f9402e54c2da2ff24cb75c148f5d2bc84c6f8dfc8b9e16ae456160b/webrtc","https://webrtc-dot-devsite-v2-prod-3p.appspot.com",null,null,["/_pwa/webrtc/manifest.json","https://www.gstatic.com/devrel-devsite/prod/v5be16d8c9f9402e54c2da2ff24cb75c148f5d2bc84c6f8dfc8b9e16ae456160b/images/video-placeholder.svg","https://www.gstatic.com/devrel-devsite/prod/v5be16d8c9f9402e54c2da2ff24cb75c148f5d2bc84c6f8dfc8b9e16ae456160b/webrtc/images/favicon.png","https://www.gstatic.com/devrel-devsite/prod/v5be16d8c9f9402e54c2da2ff24cb75c148f5d2bc84c6f8dfc8b9e16ae456160b/webrtc/images/lockup.svg","https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,500,700&display=swap"],1,null,[1,6,8,12,14,17,21,25,50,52,63,70,75,76,80,87,91,92,93,97,98,100,101,102,103,104,105,107,108,109,110,112,113,117,118,120,122,124,125,126,127,129,130,131,132,133,134,135,136,138,140,141,147,148,149,151,152,156,157,158,159,161,163,164,168,169,170,179,180,182,183,186,191,193,196],"AIzaSyCNm9YxQumEXwGJgTDjxoxXK6m1F-9720Q","AIzaSyCc76DZePGtoyUjqKrLdsMGk_ry7sljLbY","webrtc.org","AIzaSyB9bqgQ2t11WJsOX8qNsCQ6U-w91mmqF-I","AIzaSyAdYnStPdzjcJJtQ0mvIaeaMKj7_t6J_Fg",null,null,null,["MiscFeatureFlags__gdp_dashboard_reskin_enabled","MiscFeatureFlags__fix_lower_breadcrumbs","Profiles__enable_profile_collections","MiscFeatureFlags__developers_footer_image","Profiles__enable_auto_apply_credits","CloudShell__cloud_shell_button","Search__enable_ai_search_summaries_for_all","DevPro__enable_embed_profile_creation","MiscFeatureFlags__enable_framebox_badge_methods","Profiles__enable_awarding_url","MiscFeatureFlags__enable_firebase_utm","Concierge__enable_remove_info_panel_tags","MiscFeatureFlags__enable_variable_operator_index_yaml","Profiles__enable_developer_profiles_callout","DevPro__enable_devpro_offers","Cloud__enable_cloud_shell","Profiles__enable_user_type","Profiles__enable_complete_playlist_endpoint","MiscFeatureFlags__enable_explain_this_code","CloudShell__cloud_code_overflow_menu","Cloud__enable_cloud_shell_fte_user_flow","DevPro__enable_free_benefits","Profiles__enable_stripe_subscription_management","Profiles__enable_join_program_group_endpoint","Search__enable_suggestions_from_borg","DevPro__enable_credits_banner","Cloud__enable_cloud_dlp_service","DevPro__enable_g1_ineligible_redirect","Profiles__enable_developer_profile_benefits_ui_redesign","MiscFeatureFlags__enable_explicit_template_dependencies","DevPro__enable_cloud_innovators_plus","MiscFeatureFlags__enable_variable_operator","Search__enable_dynamic_content_confidential_banner","MiscFeatureFlags__enable_appearance_cookies","MiscFeatureFlags__developers_footer_dark_image","DevPro__enable_g1_integration","DevPro__enable_google_payments_buyflow","MiscFeatureFlags__remove_cross_domain_tracking_params","Cloud__enable_cloudx_experiment_ids","DevPro__enable_developer_subscriptions","Analytics__enable_clearcut_logging","Cloud__enable_free_trial_server_call","TpcFeatures__proxy_prod_host","Profiles__enable_developer_profile_pages_as_content","DevPro__enable_devsite_captcha","Cloud__enable_legacy_calculator_redirect","Profiles__enable_public_developer_profiles","DevPro__enable_vertex_credit_card","Profiles__enable_purchase_prompts","Experiments__reqs_query_experiments","Cloud__cache_serialized_dynamic_content","MiscFeatureFlags__enable_dark_theme","Profiles__enable_page_saving","MiscFeatureFlags__enable_project_variables","DevPro__enable_google_payments","EngEduTelemetry__enable_engedu_telemetry","Profiles__enable_recognition_badges","Profiles__enable_release_notes_notifications","Profiles__enable_completecodelab_endpoint","DevPro__enable_firebase_workspaces_card","AIStudioInteractionsToggle__interactions_are_default","Profiles__enable_playlist_community_acl","Profiles__enable_completequiz_endpoint","TpcFeatures__enable_unmirrored_page_left_nav","Profiles__enable_callout_notifications","DevPro__enable_enterprise","DevPro__remove_eu_tax_intake_form","Profiles__enable_targeted_hero","Profiles__require_profile_eligibility_for_signin","SignIn__enable_l1_signup_flow","MiscFeatureFlags__enable_view_transitions","Profiles__enable_dashboard_curated_recommendations","DevPro__enable_nvidia_credits_card","Concierge__enable_actions_menu","DevPro__enable_code_assist","Concierge__enable_pushui","Cloud__fast_free_trial","BookNav__enable_tenant_cache_key","Analytics__enable_devpro_interaction_logging","Search__enable_page_map","DevPro__enable_google_one_card","Search__enable_ai_eligibility_checks"],null,null,"AIzaSyA58TaKli1DculwmAmbpzLVGuWc8eCQgQc","https://developerscontentserving-pa.googleapis.com","AIzaSyDWBU60w0P9hEkr29kkksYs8Z7gvZ8u_wc","https://developerscontentsearch-pa.googleapis.com",2,4,null,"https://developerprofiles-pa.googleapis.com",[25,"webrtc","WebRTC","webrtc.org",null,"webrtc-dot-devsite-v2-prod-3p.appspot.com",null,null,[null,1,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[1],null,null,null,null,null,null,null,null,null,null,null,[1]],null,[35,null,null,null,null,null,"/images/lockup.svg","/images/touchicon-180.png",null,null,null,1,null,1,null,null,null,null,null,null,null,2,null,null,null,"/images/lockup-dark-theme.svg",[]],[],null,
1740null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[2,4,6,7,1,12,14,15,17,18,20,21,22,23,28,30,32,36,39,40,43],null,[[],[1,1]],[[["UA-23466548-1"],["UA-23466548-2"],null,null,["UA-23466548-3"],null,null,[["G-KRN165NY0F"],null,null,[["G-KRN165NY0F",1]]],[["UA-23466548-1",1]],null,[["UA-23466548-3",1]],null,1],[[4,5],[3,4],[1,1],[5,8],[2,2]],[[1,1],[2,2]]],null,4],null,null,1,1,"https://developerscontentinsights-pa.googleapis.com","AIzaSyC11xEGtFhkmSh_iF6l_itbxnFz2GrIBOg","AIzaSyAXJ10nRF73mmdSDINgkCNX5bbd2KPcWm8","https://developers.googleapis.com",null,null,"AIzaSyCjP0KOnHfv8mwe38sfzZJMOnqE3HvrD4A",null,null,"https://developers.googleapis.com"]') 1741 1742</script>
1742 1743 1744 <devsite-a11y-announce></devsite-a11y-announce> 1745 </body> 1746</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.