tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

conductor.cc (21719B)


      1 /*
      2 *  Copyright 2012 The WebRTC Project Authors. All rights reserved.
      3 *
      4 *  Use of this source code is governed by a BSD-style license
      5 *  that can be found in the LICENSE file in the root of the source
      6 *  tree. An additional intellectual property rights grant can be found
      7 *  in the file PATENTS.  All contributing project authors may
      8 *  be found in the AUTHORS file in the root of the source tree.
      9 */
     10 
     11 #include "examples/peerconnection/client/conductor.h"
     12 
     13 #include <cstddef>
     14 #include <memory>
     15 #include <optional>
     16 #include <string>
     17 #include <utility>
     18 #include <vector>
     19 
     20 #include "absl/base/nullability.h"
     21 #include "absl/memory/memory.h"
     22 #include "api/audio_codecs/builtin_audio_decoder_factory.h"
     23 #include "api/audio_codecs/builtin_audio_encoder_factory.h"
     24 #include "api/audio_options.h"
     25 #include "api/create_modular_peer_connection_factory.h"
     26 #include "api/enable_media.h"
     27 #include "api/environment/environment.h"
     28 #include "api/jsep.h"
     29 #include "api/make_ref_counted.h"
     30 #include "api/media_stream_interface.h"
     31 #include "api/peer_connection_interface.h"
     32 #include "api/rtc_error.h"
     33 #include "api/rtp_receiver_interface.h"
     34 #include "api/rtp_sender_interface.h"
     35 #include "api/scoped_refptr.h"
     36 #include "api/task_queue/task_queue_factory.h"
     37 #include "api/test/create_frame_generator.h"
     38 #include "api/video/video_frame.h"
     39 #include "api/video/video_source_interface.h"
     40 #include "api/video_codecs/video_decoder_factory_template.h"
     41 #include "api/video_codecs/video_decoder_factory_template_dav1d_adapter.h"
     42 #include "api/video_codecs/video_decoder_factory_template_libvpx_vp8_adapter.h"
     43 #include "api/video_codecs/video_decoder_factory_template_libvpx_vp9_adapter.h"
     44 #include "api/video_codecs/video_decoder_factory_template_open_h264_adapter.h"
     45 #include "api/video_codecs/video_encoder_factory_template.h"
     46 #include "api/video_codecs/video_encoder_factory_template_libaom_av1_adapter.h"
     47 #include "api/video_codecs/video_encoder_factory_template_libvpx_vp8_adapter.h"
     48 #include "api/video_codecs/video_encoder_factory_template_libvpx_vp9_adapter.h"
     49 #include "api/video_codecs/video_encoder_factory_template_open_h264_adapter.h"
     50 #include "examples/peerconnection/client/defaults.h"
     51 #include "examples/peerconnection/client/main_wnd.h"
     52 #include "examples/peerconnection/client/peer_connection_client.h"
     53 #include "json/reader.h"
     54 #include "json/value.h"
     55 #include "json/writer.h"
     56 #include "modules/video_capture/video_capture.h"
     57 #include "modules/video_capture/video_capture_factory.h"
     58 #include "pc/video_track_source.h"
     59 #include "rtc_base/checks.h"
     60 #include "rtc_base/logging.h"
     61 #include "rtc_base/strings/json.h"
     62 #include "rtc_base/thread.h"
     63 #include "system_wrappers/include/clock.h"
     64 #include "test/frame_generator_capturer.h"
     65 #include "test/platform_video_capturer.h"
     66 #include "test/test_video_capturer.h"
     67 
     68 namespace {
     69 using webrtc::test::TestVideoCapturer;
     70 
     71 // Names used for a IceCandidate JSON object.
     72 const char kCandidateSdpMidName[] = "sdpMid";
     73 const char kCandidateSdpMlineIndexName[] = "sdpMLineIndex";
     74 const char kCandidateSdpName[] = "candidate";
     75 
     76 // Names used for a SessionDescription JSON object.
     77 const char kSessionDescriptionTypeName[] = "type";
     78 const char kSessionDescriptionSdpName[] = "sdp";
     79 
     80 class DummySetSessionDescriptionObserver
     81    : public webrtc::SetSessionDescriptionObserver {
     82 public:
     83  static webrtc::scoped_refptr<DummySetSessionDescriptionObserver> Create() {
     84    return webrtc::make_ref_counted<DummySetSessionDescriptionObserver>();
     85  }
     86  void OnSuccess() override { RTC_LOG(LS_INFO) << __FUNCTION__; }
     87  void OnFailure(webrtc::RTCError error) override {
     88    RTC_LOG(LS_INFO) << __FUNCTION__ << " " << ToString(error.type()) << ": "
     89                     << error.message();
     90  }
     91 };
     92 
     93 std::unique_ptr<TestVideoCapturer> CreateCapturer(
     94    webrtc::TaskQueueFactory& task_queue_factory) {
     95  const size_t kWidth = 640;
     96  const size_t kHeight = 480;
     97  const size_t kFps = 30;
     98  std::unique_ptr<webrtc::VideoCaptureModule::DeviceInfo> info(
     99      webrtc::VideoCaptureFactory::CreateDeviceInfo());
    100  if (!info) {
    101    return nullptr;
    102  }
    103  int num_devices = info->NumberOfDevices();
    104  for (int i = 0; i < num_devices; ++i) {
    105    std::unique_ptr<TestVideoCapturer> capturer =
    106        webrtc::test::CreateVideoCapturer(kWidth, kHeight, kFps, i);
    107    if (capturer) {
    108      return capturer;
    109    }
    110  }
    111  auto frame_generator = webrtc::test::CreateSquareFrameGenerator(
    112      kWidth, kHeight, std::nullopt, std::nullopt);
    113  return std::make_unique<webrtc::test::FrameGeneratorCapturer>(
    114      webrtc::Clock::GetRealTimeClock(), std::move(frame_generator), kFps,
    115      task_queue_factory);
    116 }
    117 class CapturerTrackSource : public webrtc::VideoTrackSource {
    118 public:
    119  static webrtc::scoped_refptr<CapturerTrackSource> Create(
    120      webrtc::TaskQueueFactory& task_queue_factory) {
    121    std::unique_ptr<TestVideoCapturer> capturer =
    122        CreateCapturer(task_queue_factory);
    123    if (capturer) {
    124      capturer->Start();
    125      return webrtc::make_ref_counted<CapturerTrackSource>(std::move(capturer));
    126    }
    127    return nullptr;
    128  }
    129 
    130 protected:
    131  explicit CapturerTrackSource(std::unique_ptr<TestVideoCapturer> capturer)
    132      : VideoTrackSource(/*remote=*/false), capturer_(std::move(capturer)) {}
    133 
    134 private:
    135  webrtc::VideoSourceInterface<webrtc::VideoFrame>* source() override {
    136    return capturer_.get();
    137  }
    138 
    139  std::unique_ptr<TestVideoCapturer> capturer_;
    140 };
    141 
    142 }  // namespace
    143 
    144 Conductor::Conductor(const webrtc::Environment& env,
    145                     PeerConnectionClient* absl_nonnull client,
    146                     MainWindow* absl_nonnull main_wnd)
    147    : peer_id_(-1),
    148      loopback_(false),
    149      env_(env),
    150      client_(client),
    151      main_wnd_(main_wnd) {
    152  client_->RegisterObserver(this);
    153  main_wnd->RegisterObserver(this);
    154 }
    155 
    156 Conductor::~Conductor() {
    157  RTC_DCHECK(!peer_connection_);
    158 }
    159 
    160 bool Conductor::connection_active() const {
    161  return peer_connection_ != nullptr;
    162 }
    163 
    164 void Conductor::Close() {
    165  client_->SignOut();
    166  DeletePeerConnection();
    167 }
    168 
    169 bool Conductor::InitializePeerConnection() {
    170  RTC_DCHECK(!peer_connection_factory_);
    171  RTC_DCHECK(!peer_connection_);
    172 
    173  if (!signaling_thread_) {
    174    signaling_thread_ = webrtc::Thread::CreateWithSocketServer();
    175    signaling_thread_->Start();
    176  }
    177 
    178  webrtc::PeerConnectionFactoryDependencies deps;
    179  deps.signaling_thread = signaling_thread_.get();
    180  deps.env = env_,
    181  deps.audio_encoder_factory = webrtc::CreateBuiltinAudioEncoderFactory();
    182  deps.audio_decoder_factory = webrtc::CreateBuiltinAudioDecoderFactory();
    183  deps.video_encoder_factory =
    184      std::make_unique<webrtc::VideoEncoderFactoryTemplate<
    185          webrtc::LibvpxVp8EncoderTemplateAdapter,
    186          webrtc::LibvpxVp9EncoderTemplateAdapter,
    187          webrtc::OpenH264EncoderTemplateAdapter,
    188          webrtc::LibaomAv1EncoderTemplateAdapter>>();
    189  deps.video_decoder_factory =
    190      std::make_unique<webrtc::VideoDecoderFactoryTemplate<
    191          webrtc::LibvpxVp8DecoderTemplateAdapter,
    192          webrtc::LibvpxVp9DecoderTemplateAdapter,
    193          webrtc::OpenH264DecoderTemplateAdapter,
    194          webrtc::Dav1dDecoderTemplateAdapter>>();
    195  webrtc::EnableMedia(deps);
    196  peer_connection_factory_ =
    197      webrtc::CreateModularPeerConnectionFactory(std::move(deps));
    198 
    199  if (!peer_connection_factory_) {
    200    main_wnd_->MessageBox("Error", "Failed to initialize PeerConnectionFactory",
    201                          true);
    202    DeletePeerConnection();
    203    return false;
    204  }
    205 
    206  if (!CreatePeerConnection()) {
    207    main_wnd_->MessageBox("Error", "CreatePeerConnection failed", true);
    208    DeletePeerConnection();
    209  }
    210 
    211  AddTracks();
    212 
    213  return peer_connection_ != nullptr;
    214 }
    215 
    216 bool Conductor::ReinitializePeerConnectionForLoopback() {
    217  loopback_ = true;
    218  std::vector<webrtc::scoped_refptr<webrtc::RtpSenderInterface>> senders =
    219      peer_connection_->GetSenders();
    220  peer_connection_ = nullptr;
    221  // Loopback is only possible if encryption is disabled.
    222  webrtc::PeerConnectionFactoryInterface::Options options;
    223  options.disable_encryption = true;
    224  peer_connection_factory_->SetOptions(options);
    225  if (CreatePeerConnection()) {
    226    for (const auto& sender : senders) {
    227      peer_connection_->AddTrack(sender->track(), sender->stream_ids());
    228    }
    229    peer_connection_->CreateOffer(
    230        this, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions());
    231  }
    232  options.disable_encryption = false;
    233  peer_connection_factory_->SetOptions(options);
    234  return peer_connection_ != nullptr;
    235 }
    236 
    237 bool Conductor::CreatePeerConnection() {
    238  RTC_DCHECK(peer_connection_factory_);
    239  RTC_DCHECK(!peer_connection_);
    240 
    241  webrtc::PeerConnectionInterface::RTCConfiguration config;
    242  config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan;
    243  webrtc::PeerConnectionInterface::IceServer server;
    244  server.uri = GetPeerConnectionString();
    245  config.servers.push_back(server);
    246 
    247  webrtc::PeerConnectionDependencies pc_dependencies(this);
    248  auto error_or_peer_connection =
    249      peer_connection_factory_->CreatePeerConnectionOrError(
    250          config, std::move(pc_dependencies));
    251  if (error_or_peer_connection.ok()) {
    252    peer_connection_ = std::move(error_or_peer_connection.value());
    253  }
    254  return peer_connection_ != nullptr;
    255 }
    256 
    257 void Conductor::DeletePeerConnection() {
    258  main_wnd_->StopLocalRenderer();
    259  main_wnd_->StopRemoteRenderer();
    260  peer_connection_ = nullptr;
    261  peer_connection_factory_ = nullptr;
    262  peer_id_ = -1;
    263  loopback_ = false;
    264 }
    265 
    266 void Conductor::EnsureStreamingUI() {
    267  RTC_DCHECK(peer_connection_);
    268  if (main_wnd_->IsWindow()) {
    269    if (main_wnd_->current_ui() != MainWindow::STREAMING)
    270      main_wnd_->SwitchToStreamingUI();
    271  }
    272 }
    273 
    274 //
    275 // PeerConnectionObserver implementation.
    276 //
    277 
    278 void Conductor::OnAddTrack(
    279    webrtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver,
    280    const std::vector<webrtc::scoped_refptr<webrtc::MediaStreamInterface>>&
    281        streams) {
    282  RTC_LOG(LS_INFO) << __FUNCTION__ << " " << receiver->id();
    283  main_wnd_->QueueUIThreadCallback(NEW_TRACK_ADDED,
    284                                   receiver->track().release());
    285 }
    286 
    287 void Conductor::OnRemoveTrack(
    288    webrtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver) {
    289  RTC_LOG(LS_INFO) << __FUNCTION__ << " " << receiver->id();
    290  main_wnd_->QueueUIThreadCallback(TRACK_REMOVED, receiver->track().release());
    291 }
    292 
    293 void Conductor::OnIceCandidate(const webrtc::IceCandidate* candidate) {
    294  RTC_LOG(LS_INFO) << __FUNCTION__ << " " << candidate->sdp_mline_index();
    295  // For loopback test. To save some connecting delay.
    296  if (loopback_) {
    297    if (!peer_connection_->AddIceCandidate(candidate)) {
    298      RTC_LOG(LS_WARNING) << "Failed to apply the received candidate";
    299    }
    300    return;
    301  }
    302 
    303  Json::Value jmessage;
    304  jmessage[kCandidateSdpMidName] = candidate->sdp_mid();
    305  jmessage[kCandidateSdpMlineIndexName] = candidate->sdp_mline_index();
    306  jmessage[kCandidateSdpName] = candidate->ToString();
    307 
    308  Json::StreamWriterBuilder factory;
    309  SendMessage(Json::writeString(factory, jmessage));
    310 }
    311 
    312 //
    313 // PeerConnectionClientObserver implementation.
    314 //
    315 
    316 void Conductor::OnSignedIn() {
    317  RTC_LOG(LS_INFO) << __FUNCTION__;
    318  main_wnd_->SwitchToPeerList(client_->peers());
    319 }
    320 
    321 void Conductor::OnDisconnected() {
    322  RTC_LOG(LS_INFO) << __FUNCTION__;
    323 
    324  DeletePeerConnection();
    325 
    326  if (main_wnd_->IsWindow())
    327    main_wnd_->SwitchToConnectUI();
    328 }
    329 
    330 void Conductor::OnPeerConnected(int id, const std::string& name) {
    331  RTC_LOG(LS_INFO) << __FUNCTION__;
    332  // Refresh the list if we're showing it.
    333  if (main_wnd_->current_ui() == MainWindow::LIST_PEERS)
    334    main_wnd_->SwitchToPeerList(client_->peers());
    335 }
    336 
    337 void Conductor::OnPeerDisconnected(int id) {
    338  RTC_LOG(LS_INFO) << __FUNCTION__;
    339  if (id == peer_id_) {
    340    RTC_LOG(LS_INFO) << "Our peer disconnected";
    341    main_wnd_->QueueUIThreadCallback(PEER_CONNECTION_CLOSED, nullptr);
    342  } else {
    343    // Refresh the list if we're showing it.
    344    if (main_wnd_->current_ui() == MainWindow::LIST_PEERS)
    345      main_wnd_->SwitchToPeerList(client_->peers());
    346  }
    347 }
    348 
    349 void Conductor::OnMessageFromPeer(int peer_id, const std::string& message) {
    350  RTC_DCHECK(peer_id_ == peer_id || peer_id_ == -1);
    351  RTC_DCHECK(!message.empty());
    352 
    353  if (!peer_connection_) {
    354    RTC_DCHECK(peer_id_ == -1);
    355    peer_id_ = peer_id;
    356 
    357    if (!InitializePeerConnection()) {
    358      RTC_LOG(LS_ERROR) << "Failed to initialize our PeerConnection instance";
    359      client_->SignOut();
    360      return;
    361    }
    362  } else if (peer_id != peer_id_) {
    363    RTC_DCHECK(peer_id_ != -1);
    364    RTC_LOG(LS_WARNING)
    365        << "Received a message from unknown peer while already in a "
    366           "conversation with a different peer.";
    367    return;
    368  }
    369 
    370  Json::CharReaderBuilder factory;
    371  std::unique_ptr<Json::CharReader> reader =
    372      absl::WrapUnique(factory.newCharReader());
    373  Json::Value jmessage;
    374  if (!reader->parse(message.data(), message.data() + message.length(),
    375                     &jmessage, nullptr)) {
    376    RTC_LOG(LS_WARNING) << "Received unknown message. " << message;
    377    return;
    378  }
    379  std::string type_str;
    380  std::string json_object;
    381 
    382  webrtc::GetStringFromJsonObject(jmessage, kSessionDescriptionTypeName,
    383                                  &type_str);
    384  if (!type_str.empty()) {
    385    if (type_str == "offer-loopback") {
    386      // This is a loopback call.
    387      // Recreate the peerconnection with DTLS disabled.
    388      if (!ReinitializePeerConnectionForLoopback()) {
    389        RTC_LOG(LS_ERROR) << "Failed to initialize our PeerConnection instance";
    390        DeletePeerConnection();
    391        client_->SignOut();
    392      }
    393      return;
    394    }
    395    std::optional<webrtc::SdpType> type_maybe =
    396        webrtc::SdpTypeFromString(type_str);
    397    if (!type_maybe) {
    398      RTC_LOG(LS_ERROR) << "Unknown SDP type: " << type_str;
    399      return;
    400    }
    401    webrtc::SdpType type = *type_maybe;
    402    std::string sdp;
    403    if (!webrtc::GetStringFromJsonObject(jmessage, kSessionDescriptionSdpName,
    404                                         &sdp)) {
    405      RTC_LOG(LS_WARNING)
    406          << "Can't parse received session description message.";
    407      return;
    408    }
    409    webrtc::SdpParseError error;
    410    std::unique_ptr<webrtc::SessionDescriptionInterface> session_description =
    411        webrtc::CreateSessionDescription(type, sdp, &error);
    412    if (!session_description) {
    413      RTC_LOG(LS_WARNING)
    414          << "Can't parse received session description message. "
    415             "SdpParseError was: "
    416          << error.description;
    417      return;
    418    }
    419    RTC_LOG(LS_INFO) << " Received session description :" << message;
    420    peer_connection_->SetRemoteDescription(
    421        DummySetSessionDescriptionObserver::Create().get(),
    422        session_description.release());
    423    if (type == webrtc::SdpType::kOffer) {
    424      peer_connection_->CreateAnswer(
    425          this, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions());
    426    }
    427  } else {
    428    std::string sdp_mid;
    429    int sdp_mlineindex = 0;
    430    std::string sdp;
    431    if (!webrtc::GetStringFromJsonObject(jmessage, kCandidateSdpMidName,
    432                                         &sdp_mid) ||
    433        !webrtc::GetIntFromJsonObject(jmessage, kCandidateSdpMlineIndexName,
    434                                      &sdp_mlineindex) ||
    435        !webrtc::GetStringFromJsonObject(jmessage, kCandidateSdpName, &sdp)) {
    436      RTC_LOG(LS_WARNING) << "Can't parse received message.";
    437      return;
    438    }
    439    webrtc::SdpParseError error;
    440    std::unique_ptr<webrtc::IceCandidate> candidate(
    441        webrtc::CreateIceCandidate(sdp_mid, sdp_mlineindex, sdp, &error));
    442    if (!candidate) {
    443      RTC_LOG(LS_WARNING) << "Can't parse received candidate message. "
    444                             "SdpParseError was: "
    445                          << error.description;
    446      return;
    447    }
    448    if (!peer_connection_->AddIceCandidate(candidate.get())) {
    449      RTC_LOG(LS_WARNING) << "Failed to apply the received candidate";
    450      return;
    451    }
    452    RTC_LOG(LS_INFO) << " Received candidate :" << message;
    453  }
    454 }
    455 
    456 void Conductor::OnMessageSent(int err) {
    457  // Process the next pending message if any.
    458  main_wnd_->QueueUIThreadCallback(SEND_MESSAGE_TO_PEER, nullptr);
    459 }
    460 
    461 void Conductor::OnServerConnectionFailure() {
    462  main_wnd_->MessageBox("Error", ("Failed to connect to " + server_).c_str(),
    463                        true);
    464 }
    465 
    466 //
    467 // MainWndCallback implementation.
    468 //
    469 
    470 void Conductor::StartLogin(const std::string& server, int port) {
    471  if (client_->is_connected())
    472    return;
    473  server_ = server;
    474  client_->Connect(server, port, GetPeerName());
    475 }
    476 
    477 void Conductor::DisconnectFromServer() {
    478  if (client_->is_connected())
    479    client_->SignOut();
    480 }
    481 
    482 void Conductor::ConnectToPeer(int peer_id) {
    483  RTC_DCHECK(peer_id_ == -1);
    484  RTC_DCHECK(peer_id != -1);
    485 
    486  if (peer_connection_) {
    487    main_wnd_->MessageBox(
    488        "Error", "We only support connecting to one peer at a time", true);
    489    return;
    490  }
    491 
    492  if (InitializePeerConnection()) {
    493    peer_id_ = peer_id;
    494    peer_connection_->CreateOffer(
    495        this, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions());
    496  } else {
    497    main_wnd_->MessageBox("Error", "Failed to initialize PeerConnection", true);
    498  }
    499 }
    500 
    501 void Conductor::AddTracks() {
    502  if (!peer_connection_->GetSenders().empty()) {
    503    return;  // Already added tracks.
    504  }
    505 
    506  webrtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track(
    507      peer_connection_factory_->CreateAudioTrack(
    508          kAudioLabel,
    509          peer_connection_factory_->CreateAudioSource(webrtc::AudioOptions())
    510              .get()));
    511  auto result_or_error = peer_connection_->AddTrack(audio_track, {kStreamId});
    512  if (!result_or_error.ok()) {
    513    RTC_LOG(LS_ERROR) << "Failed to add audio track to PeerConnection: "
    514                      << result_or_error.error().message();
    515  }
    516 
    517  webrtc::scoped_refptr<CapturerTrackSource> video_device =
    518      CapturerTrackSource::Create(env_.task_queue_factory());
    519  if (video_device) {
    520    webrtc::scoped_refptr<webrtc::VideoTrackInterface> video_track_(
    521        peer_connection_factory_->CreateVideoTrack(video_device, kVideoLabel));
    522    main_wnd_->StartLocalRenderer(video_track_.get());
    523 
    524    result_or_error = peer_connection_->AddTrack(video_track_, {kStreamId});
    525    if (!result_or_error.ok()) {
    526      RTC_LOG(LS_ERROR) << "Failed to add video track to PeerConnection: "
    527                        << result_or_error.error().message();
    528    }
    529  } else {
    530    RTC_LOG(LS_ERROR) << "OpenVideoCaptureDevice failed";
    531  }
    532 
    533  main_wnd_->SwitchToStreamingUI();
    534 }
    535 
    536 void Conductor::DisconnectFromCurrentPeer() {
    537  RTC_LOG(LS_INFO) << __FUNCTION__;
    538  if (peer_connection_) {
    539    client_->SendHangUp(peer_id_);
    540    DeletePeerConnection();
    541  }
    542 
    543  if (main_wnd_->IsWindow())
    544    main_wnd_->SwitchToPeerList(client_->peers());
    545 }
    546 
    547 void Conductor::UIThreadCallback(int msg_id, void* data) {
    548  switch (msg_id) {
    549    case PEER_CONNECTION_CLOSED:
    550      RTC_LOG(LS_INFO) << "PEER_CONNECTION_CLOSED";
    551      DeletePeerConnection();
    552 
    553      if (main_wnd_->IsWindow()) {
    554        if (client_->is_connected()) {
    555          main_wnd_->SwitchToPeerList(client_->peers());
    556        } else {
    557          main_wnd_->SwitchToConnectUI();
    558        }
    559      } else {
    560        DisconnectFromServer();
    561      }
    562      break;
    563 
    564    case SEND_MESSAGE_TO_PEER: {
    565      RTC_LOG(LS_INFO) << "SEND_MESSAGE_TO_PEER";
    566      std::string* msg = reinterpret_cast<std::string*>(data);
    567      if (msg) {
    568        // For convenience, we always run the message through the queue.
    569        // This way we can be sure that messages are sent to the server
    570        // in the same order they were signaled without much hassle.
    571        pending_messages_.push_back(msg);
    572      }
    573 
    574      if (!pending_messages_.empty() && !client_->IsSendingMessage()) {
    575        msg = pending_messages_.front();
    576        pending_messages_.pop_front();
    577 
    578        if (!client_->SendToPeer(peer_id_, *msg) && peer_id_ != -1) {
    579          RTC_LOG(LS_ERROR) << "SendToPeer failed";
    580          DisconnectFromServer();
    581        }
    582        delete msg;
    583      }
    584 
    585      if (!peer_connection_)
    586        peer_id_ = -1;
    587 
    588      break;
    589    }
    590 
    591    case NEW_TRACK_ADDED: {
    592      auto* track = reinterpret_cast<webrtc::MediaStreamTrackInterface*>(data);
    593      if (track->kind() == webrtc::MediaStreamTrackInterface::kVideoKind) {
    594        auto* video_track = static_cast<webrtc::VideoTrackInterface*>(track);
    595        main_wnd_->StartRemoteRenderer(video_track);
    596      }
    597      track->Release();
    598      break;
    599    }
    600 
    601    case TRACK_REMOVED: {
    602      // Remote peer stopped sending a track.
    603      auto* track = reinterpret_cast<webrtc::MediaStreamTrackInterface*>(data);
    604      track->Release();
    605      break;
    606    }
    607 
    608    default:
    609      RTC_DCHECK_NOTREACHED();
    610      break;
    611  }
    612 }
    613 
    614 void Conductor::OnSuccess(webrtc::SessionDescriptionInterface* desc) {
    615  peer_connection_->SetLocalDescription(
    616      DummySetSessionDescriptionObserver::Create().get(), desc);
    617 
    618  std::string sdp;
    619  desc->ToString(&sdp);
    620 
    621  // For loopback test. To save some connecting delay.
    622  if (loopback_) {
    623    // Replace message type from "offer" to "answer"
    624    std::unique_ptr<webrtc::SessionDescriptionInterface> session_description =
    625        webrtc::CreateSessionDescription(webrtc::SdpType::kAnswer, sdp);
    626    peer_connection_->SetRemoteDescription(
    627        DummySetSessionDescriptionObserver::Create().get(),
    628        session_description.release());
    629    return;
    630  }
    631 
    632  Json::Value jmessage;
    633  jmessage[kSessionDescriptionTypeName] =
    634      webrtc::SdpTypeToString(desc->GetType());
    635  jmessage[kSessionDescriptionSdpName] = sdp;
    636 
    637  Json::StreamWriterBuilder factory;
    638  SendMessage(Json::writeString(factory, jmessage));
    639 }
    640 
    641 void Conductor::OnFailure(webrtc::RTCError error) {
    642  RTC_LOG(LS_ERROR) << ToString(error.type()) << ": " << error.message();
    643 }
    644 
    645 void Conductor::SendMessage(const std::string& json_object) {
    646  std::string* msg = new std::string(json_object);
    647  main_wnd_->QueueUIThreadCallback(SEND_MESSAGE_TO_PEER, msg);
    648 }