nricemediastream.cpp (24102B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 // Original author: ekr@rtfm.com 8 9 // Some of this code is cut-and-pasted from nICEr. Copyright is: 10 11 /* 12 Copyright (c) 2007, Adobe Systems, Incorporated 13 All rights reserved. 14 15 Redistribution and use in source and binary forms, with or without 16 modification, are permitted provided that the following conditions are 17 met: 18 19 * Redistributions of source code must retain the above copyright 20 notice, this list of conditions and the following disclaimer. 21 22 * Redistributions in binary form must reproduce the above copyright 23 notice, this list of conditions and the following disclaimer in the 24 documentation and/or other materials provided with the distribution. 25 26 * Neither the name of Adobe Systems, Network Resonance nor the names of its 27 contributors may be used to endorse or promote products derived from 28 this software without specific prior written permission. 29 30 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 31 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 32 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 33 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 34 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 36 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 37 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 38 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 39 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 40 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41 */ 42 43 #include <string> 44 #include <vector> 45 46 #include "logging.h" 47 #include "nsError.h" 48 #include "nsThreadUtils.h" 49 50 // nICEr includes 51 extern "C" { 52 // clang-format off 53 #include "nr_api.h" 54 #include "transport_addr.h" 55 #include "nr_socket.h" 56 #include "ice_ctx.h" 57 #include "ice_candidate.h" 58 #include "ice_handler.h" 59 // clang-format on 60 } 61 62 // Local includes 63 #include "nricectx.h" 64 #include "nricemediastream.h" 65 66 namespace mozilla { 67 68 MOZ_MTLOG_MODULE("mtransport") 69 70 static bool ToNrIceAddr(nr_transport_addr& addr, NrIceAddr* out) { 71 int r; 72 char addrstring[INET6_ADDRSTRLEN + 1]; 73 74 r = nr_transport_addr_get_addrstring(&addr, addrstring, sizeof(addrstring)); 75 if (r) return false; 76 out->host = addrstring; 77 78 int port; 79 r = nr_transport_addr_get_port(&addr, &port); 80 if (r) return false; 81 82 out->port = port; 83 84 switch (addr.protocol) { 85 case IPPROTO_TCP: 86 if (addr.tls) { 87 out->transport = kNrIceTransportTls; 88 } else { 89 out->transport = kNrIceTransportTcp; 90 } 91 break; 92 case IPPROTO_UDP: 93 out->transport = kNrIceTransportUdp; 94 break; 95 default: 96 MOZ_CRASH(); 97 return false; 98 } 99 100 return true; 101 } 102 103 static bool ToNrIceCandidate(const nr_ice_candidate& candc, 104 NrIceCandidate* out) { 105 MOZ_ASSERT(out); 106 int r; 107 // Const-cast because the internal nICEr code isn't const-correct. 108 nr_ice_candidate* cand = const_cast<nr_ice_candidate*>(&candc); 109 110 if (!ToNrIceAddr(cand->addr, &out->cand_addr)) return false; 111 112 if (cand->mdns_addr) { 113 out->mdns_addr = cand->mdns_addr; 114 } 115 116 if (cand->isock) { 117 nr_transport_addr addr; 118 r = nr_socket_getaddr(cand->isock->sock, &addr); 119 if (r) return false; 120 121 out->is_proxied = addr.is_proxied; 122 123 if (!ToNrIceAddr(addr, &out->local_addr)) return false; 124 } 125 126 NrIceCandidate::Type type; 127 128 switch (cand->type) { 129 case HOST: 130 type = NrIceCandidate::ICE_HOST; 131 break; 132 case SERVER_REFLEXIVE: 133 type = NrIceCandidate::ICE_SERVER_REFLEXIVE; 134 break; 135 case PEER_REFLEXIVE: 136 type = NrIceCandidate::ICE_PEER_REFLEXIVE; 137 break; 138 case RELAYED: 139 type = NrIceCandidate::ICE_RELAYED; 140 break; 141 default: 142 return false; 143 } 144 145 NrIceCandidate::TcpType tcp_type; 146 switch (cand->tcp_type) { 147 case TCP_TYPE_ACTIVE: 148 tcp_type = NrIceCandidate::ICE_ACTIVE; 149 break; 150 case TCP_TYPE_PASSIVE: 151 tcp_type = NrIceCandidate::ICE_PASSIVE; 152 break; 153 case TCP_TYPE_SO: 154 tcp_type = NrIceCandidate::ICE_SO; 155 break; 156 default: 157 tcp_type = NrIceCandidate::ICE_NONE; 158 break; 159 } 160 161 out->type = type; 162 out->tcp_type = tcp_type; 163 out->codeword = candc.codeword; 164 out->label = candc.label; 165 out->trickled = candc.trickled; 166 out->priority = candc.priority; 167 return true; 168 } 169 170 // Make an NrIceCandidate from the candidate |cand|. 171 // This is not a member fxn because we want to hide the 172 // defn of nr_ice_candidate but we pass by reference. 173 static UniquePtr<NrIceCandidate> MakeNrIceCandidate( 174 const nr_ice_candidate& candc) { 175 UniquePtr<NrIceCandidate> out(new NrIceCandidate()); 176 177 if (!ToNrIceCandidate(candc, out.get())) { 178 return nullptr; 179 } 180 return out; 181 } 182 183 static bool Matches(const nr_ice_media_stream* stream, const std::string& ufrag, 184 const std::string& pwd) { 185 return stream && (stream->ufrag == ufrag) && (stream->pwd == pwd); 186 } 187 188 NrIceMediaStream::NrIceMediaStream(NrIceCtx* ctx, const std::string& id, 189 const std::string& name, size_t components) 190 : state_(ICE_CONNECTING), 191 ctx_(ctx), 192 name_(name), 193 components_(components), 194 stream_(nullptr), 195 old_stream_(nullptr), 196 id_(id) {} 197 198 NrIceMediaStream::~NrIceMediaStream() { 199 // We do not need to destroy anything. All major resources 200 // are attached to the ice ctx. 201 } 202 203 nsresult NrIceMediaStream::ConnectToPeer( 204 const std::string& ufrag, const std::string& pwd, 205 const std::vector<std::string>& attributes) { 206 MOZ_ASSERT(stream_); 207 208 if (Matches(old_stream_, ufrag, pwd)) { 209 bool wasGathering = !AllGenerationsDoneGathering(); 210 // (We swap before we close so we never have stream_ == nullptr) 211 MOZ_MTLOG(ML_DEBUG, 212 "Rolling back to old stream ufrag=" << ufrag << " " << name_); 213 std::swap(stream_, old_stream_); 214 CloseStream(&old_stream_); 215 if (wasGathering && AllGenerationsDoneGathering()) { 216 // Special case; we do not need to send another empty candidate, but we 217 // do need to handle the transition from gathering to complete. 218 SignalGatheringStateChange(GetId(), ICE_STREAM_GATHER_COMPLETE); 219 } 220 } else if (old_stream_) { 221 // Right now we wait for ICE to complete before closing the old stream. 222 // It might be worth it to close it sooner, but we don't want to close it 223 // right away. 224 MOZ_MTLOG(ML_DEBUG, 225 "ICE restart committed, marking old stream as obsolete, " 226 "beginning switchover to ufrag=" 227 << ufrag << " " << name_); 228 nr_ice_media_stream_set_obsolete(old_stream_); 229 } 230 231 nr_ice_media_stream* peer_stream; 232 if (nr_ice_peer_ctx_find_pstream(ctx_->peer(), stream_, &peer_stream)) { 233 // No peer yet 234 std::vector<char*> attributes_in; 235 attributes_in.reserve(attributes.size()); 236 for (auto& attribute : attributes) { 237 MOZ_MTLOG(ML_DEBUG, "Setting " << attribute << " on stream " << name_); 238 attributes_in.push_back(const_cast<char*>(attribute.c_str())); 239 } 240 241 // Still need to call nr_ice_ctx_parse_stream_attributes. 242 int r = nr_ice_peer_ctx_parse_stream_attributes( 243 ctx_->peer(), stream_, 244 attributes_in.empty() ? nullptr : &attributes_in[0], 245 attributes_in.size()); 246 if (r) { 247 MOZ_MTLOG(ML_ERROR, 248 "Couldn't parse attributes for stream " << name_ << "'"); 249 return NS_ERROR_FAILURE; 250 } 251 } 252 253 return NS_OK; 254 } 255 256 nsresult NrIceMediaStream::SetIceCredentials(const std::string& ufrag, 257 const std::string& pwd) { 258 if (Matches(stream_, ufrag, pwd)) { 259 return NS_OK; 260 } 261 262 if (Matches(old_stream_, ufrag, pwd)) { 263 return NS_OK; 264 } 265 266 MOZ_MTLOG(ML_DEBUG, "Setting ICE credentials for " << name_ << " - " << ufrag 267 << ":" << pwd); 268 CloseStream(&old_stream_); 269 old_stream_ = stream_; 270 271 std::string name(name_ + " - " + ufrag + ":" + pwd); 272 273 int r = nr_ice_add_media_stream(ctx_->ctx(), name.c_str(), ufrag.c_str(), 274 pwd.c_str(), components_, &stream_); 275 if (r) { 276 MOZ_MTLOG(ML_ERROR, "Couldn't create ICE media stream for '" 277 << name_ << "': error=" << r); 278 stream_ = old_stream_; 279 old_stream_ = nullptr; 280 return NS_ERROR_FAILURE; 281 } 282 283 state_ = ICE_CONNECTING; 284 285 MOZ_MTLOG(ML_WARNING, 286 "SetIceCredentials new=" << stream_ << " old=" << old_stream_); 287 288 return NS_OK; 289 } 290 291 // Parse trickle ICE candidate 292 nsresult NrIceMediaStream::ParseTrickleCandidate(const std::string& candidate, 293 const std::string& ufrag, 294 const std::string& mdns_addr) { 295 nr_ice_media_stream* stream = GetStreamForRemoteUfrag(ufrag); 296 if (!stream) { 297 return NS_ERROR_FAILURE; 298 } 299 300 MOZ_MTLOG(ML_NOTICE, "NrIceCtx(" << ctx_->ctx()->label << ")/STREAM(" 301 << name() << ") : parsing trickle candidate " 302 << candidate); 303 304 int r = nr_ice_peer_ctx_parse_trickle_candidate( 305 ctx_->peer(), stream, const_cast<char*>(candidate.c_str()), 306 mdns_addr.c_str()); 307 308 if (r) { 309 if (r == R_ALREADY) { 310 MOZ_MTLOG(ML_INFO, "Trickle candidate is redundant for stream '" 311 << name_ 312 << "' because it is completed: " << candidate); 313 } else if (r == R_REJECTED) { 314 MOZ_MTLOG(ML_INFO, 315 "Trickle candidate is ignored for stream '" 316 << name_ 317 << "', probably because it is for an unused component" 318 << ": " << candidate); 319 } else { 320 MOZ_MTLOG(ML_ERROR, "Couldn't parse trickle candidate for stream '" 321 << name_ << "': " << candidate); 322 return NS_ERROR_FAILURE; 323 } 324 } 325 326 return NS_OK; 327 } 328 329 // Returns NS_ERROR_NOT_AVAILABLE if component is unpaired or disabled. 330 nsresult NrIceMediaStream::GetActivePair(int component, 331 UniquePtr<NrIceCandidate>* localp, 332 UniquePtr<NrIceCandidate>* remotep) { 333 int r; 334 nr_ice_candidate* local_int; 335 nr_ice_candidate* remote_int; 336 337 if (!stream_) { 338 return NS_ERROR_NOT_AVAILABLE; 339 } 340 341 r = nr_ice_media_stream_get_active(ctx_->peer(), stream_, component, 342 &local_int, &remote_int); 343 // If result is R_REJECTED then component is unpaired or disabled. 344 if (r == R_REJECTED) return NS_ERROR_NOT_AVAILABLE; 345 346 if (r) return NS_ERROR_FAILURE; 347 348 UniquePtr<NrIceCandidate> local(MakeNrIceCandidate(*local_int)); 349 if (!local) return NS_ERROR_FAILURE; 350 351 UniquePtr<NrIceCandidate> remote(MakeNrIceCandidate(*remote_int)); 352 if (!remote) return NS_ERROR_FAILURE; 353 354 if (localp) *localp = std::move(local); 355 if (remotep) *remotep = std::move(remote); 356 357 return NS_OK; 358 } 359 360 nsresult NrIceMediaStream::GetCandidatePairs( 361 std::vector<NrIceCandidatePair>* out_pairs) const { 362 MOZ_ASSERT(out_pairs); 363 if (!stream_) { 364 return NS_ERROR_NOT_AVAILABLE; 365 } 366 367 // If we haven't at least started checking then there is nothing to report 368 if (ctx_->peer()->state != NR_ICE_PEER_STATE_PAIRED) { 369 return NS_OK; 370 } 371 372 // Get the check_list on the peer stream (this is where the check_list 373 // actually lives, not in stream_) 374 nr_ice_media_stream* peer_stream; 375 int r = nr_ice_peer_ctx_find_pstream(ctx_->peer(), stream_, &peer_stream); 376 if (r != 0) { 377 return NS_ERROR_FAILURE; 378 } 379 380 nr_ice_cand_pair *p1, *p2; 381 out_pairs->clear(); 382 383 TAILQ_FOREACH(p1, &peer_stream->check_list, check_queue_entry) { 384 MOZ_ASSERT(p1); 385 MOZ_ASSERT(p1->local); 386 MOZ_ASSERT(p1->remote); 387 NrIceCandidatePair pair; 388 389 p2 = TAILQ_FIRST(&peer_stream->check_list); 390 while (p2) { 391 if (p1 == p2) { 392 /* Don't compare with our self. */ 393 p2 = TAILQ_NEXT(p2, check_queue_entry); 394 continue; 395 } 396 if (strncmp(p1->codeword, p2->codeword, sizeof(p1->codeword)) == 0) { 397 /* In case of duplicate pairs we only report the one winning pair */ 398 if (((p2->remote->component && (p2->remote->component->active == p2)) && 399 !(p1->remote->component && 400 (p1->remote->component->active == p1))) || 401 ((p2->peer_nominated || p2->nominated) && 402 !(p1->peer_nominated || p1->nominated)) || 403 (p2->priority > p1->priority) || 404 ((p2->state == NR_ICE_PAIR_STATE_SUCCEEDED) && 405 (p1->state != NR_ICE_PAIR_STATE_SUCCEEDED)) || 406 ((p2->state != NR_ICE_PAIR_STATE_CANCELLED) && 407 (p1->state == NR_ICE_PAIR_STATE_CANCELLED))) { 408 /* p2 is a better pair. */ 409 break; 410 } 411 } 412 p2 = TAILQ_NEXT(p2, check_queue_entry); 413 } 414 if (p2) { 415 /* p2 points to a duplicate but better pair so skip this one */ 416 continue; 417 } 418 419 switch (p1->state) { 420 case NR_ICE_PAIR_STATE_FROZEN: 421 pair.state = NrIceCandidatePair::State::STATE_FROZEN; 422 break; 423 case NR_ICE_PAIR_STATE_WAITING: 424 pair.state = NrIceCandidatePair::State::STATE_WAITING; 425 break; 426 case NR_ICE_PAIR_STATE_IN_PROGRESS: 427 pair.state = NrIceCandidatePair::State::STATE_IN_PROGRESS; 428 break; 429 case NR_ICE_PAIR_STATE_FAILED: 430 pair.state = NrIceCandidatePair::State::STATE_FAILED; 431 break; 432 case NR_ICE_PAIR_STATE_SUCCEEDED: 433 pair.state = NrIceCandidatePair::State::STATE_SUCCEEDED; 434 break; 435 case NR_ICE_PAIR_STATE_CANCELLED: 436 pair.state = NrIceCandidatePair::State::STATE_CANCELLED; 437 break; 438 default: 439 MOZ_ASSERT(0); 440 } 441 442 pair.priority = p1->priority; 443 pair.nominated = p1->peer_nominated || p1->nominated; 444 pair.component_id = p1->remote->component->component_id; 445 446 // As discussed with drno: a component's can_send field (set to true 447 // by ICE consent) is a very close approximation for writable and 448 // readable. Note: the component for the local candidate never has 449 // the can_send member set to true, remote for both readable and 450 // writable. (mjf) 451 pair.writable = p1->remote->component->can_send; 452 pair.readable = p1->remote->component->can_send; 453 pair.selected = 454 p1->remote->component && p1->remote->component->active == p1; 455 pair.codeword = p1->codeword; 456 pair.bytes_sent = p1->bytes_sent; 457 pair.bytes_recvd = p1->bytes_recvd; 458 pair.ms_since_last_send = 459 p1->last_sent.tv_sec * 1000 + p1->last_sent.tv_usec / 1000; 460 pair.ms_since_last_recv = 461 p1->last_recvd.tv_sec * 1000 + p1->last_recvd.tv_usec / 1000; 462 pair.responses_recvd = p1->responses_recvd; 463 pair.current_rtt_ms = p1->current_rtt_ms; 464 pair.total_rtt_ms = p1->total_rtt_ms; 465 466 if (!ToNrIceCandidate(*(p1->local), &pair.local) || 467 !ToNrIceCandidate(*(p1->remote), &pair.remote)) { 468 return NS_ERROR_FAILURE; 469 } 470 471 out_pairs->push_back(pair); 472 } 473 474 return NS_OK; 475 } 476 477 nsresult NrIceMediaStream::GetDefaultCandidate( 478 int component, NrIceCandidate* candidate) const { 479 if (!stream_) { 480 return NS_ERROR_NOT_AVAILABLE; 481 } 482 483 nr_ice_candidate* cand; 484 485 int r = nr_ice_media_stream_get_default_candidate(stream_, component, &cand); 486 if (r) { 487 if (r == R_NOT_FOUND) { 488 MOZ_MTLOG(ML_INFO, "Couldn't get default ICE candidate for '" 489 << name_ << "', no candidates."); 490 } else { 491 MOZ_MTLOG(ML_ERROR, "Couldn't get default ICE candidate for '" 492 << name_ << "', " << r); 493 } 494 return NS_ERROR_FAILURE; 495 } 496 497 if (!ToNrIceCandidate(*cand, candidate)) { 498 MOZ_MTLOG(ML_ERROR, 499 "Failed to convert default ICE candidate for '" << name_ << "'"); 500 return NS_ERROR_FAILURE; 501 } 502 503 return NS_OK; 504 } 505 506 std::vector<std::string> NrIceMediaStream::GetAttributes() const { 507 char** attrs = nullptr; 508 int attrct; 509 int r; 510 std::vector<std::string> ret; 511 512 if (!stream_) { 513 return ret; 514 } 515 516 r = nr_ice_media_stream_get_attributes(stream_, &attrs, &attrct); 517 if (r) { 518 MOZ_MTLOG(ML_ERROR, "Couldn't get ICE candidates for '" << name_ << "'"); 519 return ret; 520 } 521 522 for (int i = 0; i < attrct; i++) { 523 ret.push_back(attrs[i]); 524 RFREE(attrs[i]); 525 } 526 527 RFREE(attrs); 528 529 return ret; 530 } 531 532 static nsresult GetCandidatesFromStream( 533 nr_ice_media_stream* stream, std::vector<NrIceCandidate>* candidates) { 534 MOZ_ASSERT(candidates); 535 nr_ice_component* comp = STAILQ_FIRST(&stream->components); 536 while (comp) { 537 if (comp->state != NR_ICE_COMPONENT_DISABLED) { 538 nr_ice_candidate* cand = TAILQ_FIRST(&comp->candidates); 539 while (cand) { 540 NrIceCandidate new_cand; 541 // This can fail if the candidate is server reflexive or relayed, and 542 // has not yet received a response (ie; it doesn't know its address 543 // yet). For the purposes of this code, this isn't a candidate we're 544 // interested in, since it is not fully baked yet. 545 if (ToNrIceCandidate(*cand, &new_cand)) { 546 candidates->push_back(new_cand); 547 } 548 cand = TAILQ_NEXT(cand, entry_comp); 549 } 550 } 551 comp = STAILQ_NEXT(comp, entry); 552 } 553 554 return NS_OK; 555 } 556 557 nsresult NrIceMediaStream::GetLocalCandidates( 558 std::vector<NrIceCandidate>* candidates) const { 559 if (!stream_) { 560 return NS_ERROR_NOT_AVAILABLE; 561 } 562 563 return GetCandidatesFromStream(stream_, candidates); 564 } 565 566 nsresult NrIceMediaStream::GetRemoteCandidates( 567 std::vector<NrIceCandidate>* candidates) const { 568 if (!stream_) { 569 return NS_ERROR_NOT_AVAILABLE; 570 } 571 572 // If we haven't at least started checking then there is nothing to report 573 if (ctx_->peer()->state != NR_ICE_PEER_STATE_PAIRED) { 574 return NS_OK; 575 } 576 577 nr_ice_media_stream* peer_stream; 578 int r = nr_ice_peer_ctx_find_pstream(ctx_->peer(), stream_, &peer_stream); 579 if (r != 0) { 580 return NS_ERROR_FAILURE; 581 } 582 583 return GetCandidatesFromStream(peer_stream, candidates); 584 } 585 586 nsresult NrIceMediaStream::DisableComponent(int component_id) { 587 if (!stream_) return NS_ERROR_FAILURE; 588 589 int r = nr_ice_media_stream_disable_component(stream_, component_id); 590 if (r) { 591 MOZ_MTLOG(ML_ERROR, "Couldn't disable '" << name_ << "':" << component_id); 592 return NS_ERROR_FAILURE; 593 } 594 595 return NS_OK; 596 } 597 598 nsresult NrIceMediaStream::GetConsentStatus(int component_id, bool* can_send, 599 struct timeval* ts) { 600 if (!stream_) return NS_ERROR_FAILURE; 601 602 nr_ice_media_stream* peer_stream; 603 int r = nr_ice_peer_ctx_find_pstream(ctx_->peer(), stream_, &peer_stream); 604 if (r) { 605 MOZ_MTLOG(ML_ERROR, "Failed to find peer stream for '" 606 << name_ << "':" << component_id); 607 return NS_ERROR_FAILURE; 608 } 609 610 int send = 0; 611 r = nr_ice_media_stream_get_consent_status(peer_stream, component_id, &send, 612 ts); 613 if (r) { 614 MOZ_MTLOG(ML_ERROR, "Failed to get consent status for '" 615 << name_ << "':" << component_id); 616 return NS_ERROR_FAILURE; 617 } 618 *can_send = !!send; 619 620 return NS_OK; 621 } 622 623 bool NrIceMediaStream::HasStream(nr_ice_media_stream* stream) const { 624 return (stream == stream_) || (stream == old_stream_); 625 } 626 627 nsresult NrIceMediaStream::SendPacket(int component_id, 628 const unsigned char* data, size_t len) { 629 nr_ice_media_stream* stream = old_stream_ ? old_stream_ : stream_; 630 if (!stream) { 631 return NS_ERROR_FAILURE; 632 } 633 634 int r = nr_ice_media_stream_send(ctx_->peer(), stream, component_id, 635 const_cast<unsigned char*>(data), len); 636 if (r) { 637 MOZ_MTLOG(ML_ERROR, "Couldn't send media on '" << name_ << "'"); 638 if (r == R_WOULDBLOCK) { 639 return NS_BASE_STREAM_WOULD_BLOCK; 640 } 641 642 return NS_BASE_STREAM_OSERROR; 643 } 644 645 return NS_OK; 646 } 647 648 void NrIceMediaStream::Ready(nr_ice_media_stream* stream) { 649 if (stream == stream_) { 650 NS_DispatchToCurrentThread(NewRunnableMethod<nr_ice_media_stream*>( 651 "NrIceMediaStream::DeferredCloseOldStream", this, 652 &NrIceMediaStream::DeferredCloseOldStream, old_stream_)); 653 } 654 655 // This function is called whenever a stream becomes ready, but it 656 // gets fired multiple times when a stream gets nominated repeatedly. 657 if (state_ != ICE_OPEN) { 658 MOZ_MTLOG(ML_DEBUG, "Marking stream ready '" << name_ << "'"); 659 state_ = ICE_OPEN; 660 SignalReady(this); 661 } else { 662 MOZ_MTLOG(ML_DEBUG, 663 "Stream ready callback fired again for '" << name_ << "'"); 664 } 665 } 666 667 void NrIceMediaStream::Failed() { 668 if (state_ != ICE_CLOSED) { 669 MOZ_MTLOG(ML_DEBUG, "Marking stream failed '" << name_ << "'"); 670 state_ = ICE_CLOSED; 671 // We don't need the old stream anymore. 672 NS_DispatchToCurrentThread(NewRunnableMethod<nr_ice_media_stream*>( 673 "NrIceMediaStream::DeferredCloseOldStream", this, 674 &NrIceMediaStream::DeferredCloseOldStream, old_stream_)); 675 SignalFailed(this); 676 } 677 } 678 679 void NrIceMediaStream::OnGatheringStarted(nr_ice_media_stream* stream) { 680 MOZ_MTLOG(ML_WARNING, "OnGatheringStarted called for " << stream); 681 SignalGatheringStateChange(GetId(), ICE_STREAM_GATHER_STARTED); 682 } 683 684 void NrIceMediaStream::OnGatheringComplete(nr_ice_media_stream* stream) { 685 MOZ_MTLOG(ML_WARNING, "OnGatheringComplete called for " << stream); 686 // Spec says to queue two separate tasks; one for the empty candidate, and 687 // the next for the state change. 688 SignalCandidate(this, "", stream->ufrag, "", ""); 689 if (AllGenerationsDoneGathering()) { 690 SignalGatheringStateChange(GetId(), ICE_STREAM_GATHER_COMPLETE); 691 } 692 } 693 694 void NrIceMediaStream::Close() { 695 MOZ_MTLOG(ML_DEBUG, "Marking stream closed '" << name_ << "'"); 696 state_ = ICE_CLOSED; 697 698 CloseStream(&old_stream_); 699 CloseStream(&stream_); 700 ctx_ = nullptr; 701 } 702 703 void NrIceMediaStream::CloseStream(nr_ice_media_stream** stream) { 704 if (*stream) { 705 int r = nr_ice_remove_media_stream(ctx_->ctx(), stream); 706 if (r) { 707 MOZ_ASSERT(false, "Failed to remove stream"); 708 MOZ_MTLOG(ML_ERROR, "Failed to remove stream, error=" << r); 709 } 710 *stream = nullptr; 711 } 712 } 713 714 void NrIceMediaStream::DeferredCloseOldStream(const nr_ice_media_stream* old) { 715 if (old == old_stream_) { 716 CloseStream(&old_stream_); 717 } 718 } 719 720 nr_ice_media_stream* NrIceMediaStream::GetStreamForRemoteUfrag( 721 const std::string& aUfrag) { 722 if (aUfrag.empty()) { 723 return stream_; 724 } 725 726 nr_ice_media_stream* peer_stream = nullptr; 727 728 if (!nr_ice_peer_ctx_find_pstream(ctx_->peer(), stream_, &peer_stream) && 729 aUfrag == peer_stream->ufrag) { 730 return stream_; 731 } 732 733 if (old_stream_ && 734 !nr_ice_peer_ctx_find_pstream(ctx_->peer(), old_stream_, &peer_stream) && 735 aUfrag == peer_stream->ufrag) { 736 return old_stream_; 737 } 738 739 return nullptr; 740 } 741 742 bool NrIceMediaStream::AllGenerationsDoneGathering() const { 743 if (stream_ && !nr_ice_media_stream_is_done_gathering(stream_)) { 744 return false; 745 } 746 if (old_stream_ && !nr_ice_media_stream_is_done_gathering(old_stream_)) { 747 return false; 748 } 749 return true; 750 } 751 752 bool NrIceMediaStream::AnyGenerationIsConnected() const { 753 nr_ice_media_stream* peer_stream = nullptr; 754 755 if (stream_ && 756 !nr_ice_peer_ctx_find_pstream(ctx_->peer(), stream_, &peer_stream)) { 757 if (peer_stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_CONNECTED && 758 !peer_stream->disconnected) { 759 return true; 760 } 761 } 762 763 if (old_stream_ && 764 !nr_ice_peer_ctx_find_pstream(ctx_->peer(), old_stream_, &peer_stream)) { 765 if (peer_stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_CONNECTED && 766 !peer_stream->disconnected) { 767 return true; 768 } 769 } 770 return false; 771 } 772 } // namespace mozilla