103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// found in the LICENSE file.
403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "remoting/host/cast_extension_session.h"
603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "base/bind.h"
803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "base/json/json_reader.h"
903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "base/json/json_writer.h"
1003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "base/logging.h"
1103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "base/synchronization/waitable_event.h"
1203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "net/url_request/url_request_context_getter.h"
1303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "remoting/host/cast_video_capturer_adapter.h"
1403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "remoting/host/chromium_port_allocator_factory.h"
1503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "remoting/host/client_session.h"
1603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "remoting/proto/control.pb.h"
1703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "remoting/protocol/client_stub.h"
1803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "third_party/libjingle/source/talk/app/webrtc/mediastreaminterface.h"
1903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "third_party/libjingle/source/talk/app/webrtc/test/fakeconstraints.h"
2003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "third_party/libjingle/source/talk/app/webrtc/videosourceinterface.h"
2103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
2203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)namespace remoting {
2303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
2403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// Used as the type attribute of all Cast protocol::ExtensionMessages.
2503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)const char kExtensionMessageType[] = "cast_message";
2603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
2703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// Top-level keys used in all extension messages between host and client.
2803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// Must keep synced with webapp.
2903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)const char kTopLevelData[] = "chromoting_data";
3003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)const char kTopLevelSubject[] = "subject";
3103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
3203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// Keys used to describe the subject of a cast extension message. WebRTC-related
3303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// message subjects are prepended with "webrtc_".
3403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// Must keep synced with webapp.
3503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)const char kSubjectReady[] = "ready";
3603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)const char kSubjectTest[] = "test";
3703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)const char kSubjectNewCandidate[] = "webrtc_candidate";
3803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)const char kSubjectOffer[] = "webrtc_offer";
3903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)const char kSubjectAnswer[] = "webrtc_answer";
4003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
4103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// WebRTC headers used inside messages with subject = "webrtc_*".
4203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)const char kWebRtcCandidate[] = "candidate";
4303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)const char kWebRtcSessionDescType[] = "type";
4403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)const char kWebRtcSessionDescSDP[] = "sdp";
4503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)const char kWebRtcSDPMid[] = "sdpMid";
4603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)const char kWebRtcSDPMLineIndex[] = "sdpMLineIndex";
4703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
4803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// Media labels used over the PeerConnection.
4903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)const char kVideoLabel[] = "cast_video_label";
5003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)const char kStreamLabel[] = "stream_label";
5103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
5203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// Default STUN server used to construct
5303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// webrtc::PeerConnectionInterface::RTCConfiguration for the PeerConnection.
5403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)const char kDefaultStunURI[] = "stun:stun.l.google.com:19302";
5503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
5603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)const char kWorkerThreadName[] = "CastExtensionSessionWorkerThread";
5703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
5803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// Interval between each call to PollPeerConnectionStats().
5903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)const int kStatsLogIntervalSec = 10;
6003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
6103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// Minimum frame rate for video streaming over the PeerConnection in frames per
6203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// second, added as a media constraint when constructing the video source for
6303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// the Peer Connection.
6403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)const int kMinFramesPerSecond = 5;
6503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
6603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// A webrtc::SetSessionDescriptionObserver implementation used to receive the
6703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// results of setting local and remote descriptions of the PeerConnection.
6803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)class CastSetSessionDescriptionObserver
6903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    : public webrtc::SetSessionDescriptionObserver {
7003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) public:
7103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  static CastSetSessionDescriptionObserver* Create() {
7203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return new rtc::RefCountedObject<CastSetSessionDescriptionObserver>();
7303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
7403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  virtual void OnSuccess() OVERRIDE {
7503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    VLOG(1) << "Setting session description succeeded.";
7603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
7703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  virtual void OnFailure(const std::string& error) OVERRIDE {
7803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    LOG(ERROR) << "Setting session description failed: " << error;
7903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
8003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
8103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) protected:
8203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  CastSetSessionDescriptionObserver() {}
8303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  virtual ~CastSetSessionDescriptionObserver() {}
8403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
8503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(CastSetSessionDescriptionObserver);
8603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)};
8703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
8803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// A webrtc::CreateSessionDescriptionObserver implementation used to receive the
8903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// results of creating descriptions for this end of the PeerConnection.
9003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)class CastCreateSessionDescriptionObserver
9103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    : public webrtc::CreateSessionDescriptionObserver {
9203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) public:
9303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  static CastCreateSessionDescriptionObserver* Create(
9403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      CastExtensionSession* session) {
9503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return new rtc::RefCountedObject<CastCreateSessionDescriptionObserver>(
9603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        session);
9703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
9803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  virtual void OnSuccess(webrtc::SessionDescriptionInterface* desc) OVERRIDE {
9903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (cast_extension_session_ == NULL) {
10003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      LOG(ERROR)
10103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          << "No CastExtensionSession. Creating session description succeeded.";
10203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      return;
10303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
10403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    cast_extension_session_->OnCreateSessionDescription(desc);
10503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
10603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  virtual void OnFailure(const std::string& error) OVERRIDE {
10703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (cast_extension_session_ == NULL) {
10803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      LOG(ERROR)
10903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          << "No CastExtensionSession. Creating session description failed.";
11003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      return;
11103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
11203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    cast_extension_session_->OnCreateSessionDescriptionFailure(error);
11303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
11403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  void SetCastExtensionSession(CastExtensionSession* cast_extension_session) {
11503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    cast_extension_session_ = cast_extension_session;
11603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
11703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
11803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) protected:
11903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  explicit CastCreateSessionDescriptionObserver(CastExtensionSession* session)
12003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      : cast_extension_session_(session) {}
12103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  virtual ~CastCreateSessionDescriptionObserver() {}
12203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
12303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) private:
12403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  CastExtensionSession* cast_extension_session_;
12503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
12603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(CastCreateSessionDescriptionObserver);
12703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)};
12803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
12903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// A webrtc::StatsObserver implementation used to receive statistics about the
13003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// current PeerConnection.
13103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)class CastStatsObserver : public webrtc::StatsObserver {
13203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) public:
13303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  static CastStatsObserver* Create() {
13403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return new rtc::RefCountedObject<CastStatsObserver>();
13503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
13603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
13703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  virtual void OnComplete(
13803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      const std::vector<webrtc::StatsReport>& reports) OVERRIDE {
13903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    typedef webrtc::StatsReport::Values::iterator ValuesIterator;
14003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
14103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    VLOG(1) << "Received " << reports.size() << " new StatsReports.";
14203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
14303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    int index;
14403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    std::vector<webrtc::StatsReport>::const_iterator it;
14503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    for (it = reports.begin(), index = 0; it != reports.end(); ++it, ++index) {
14603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      webrtc::StatsReport::Values v = it->values;
14703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      VLOG(1) << "Report " << index << ":";
14803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      for (ValuesIterator vIt = v.begin(); vIt != v.end(); ++vIt) {
14903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        VLOG(1) << "Stat: " << vIt->name << "=" << vIt->value << ".";
15003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      }
15103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
15203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
15303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
15403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) protected:
15503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  CastStatsObserver() {}
15603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  virtual ~CastStatsObserver() {}
15703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
15803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(CastStatsObserver);
15903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)};
16003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
16103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// TODO(aiguha): Fix PeerConnnection-related tear down crash caused by premature
16203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// destruction of cricket::CaptureManager (which occurs on releasing
16303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// |peer_conn_factory_|). See crbug.com/403840.
16403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)CastExtensionSession::~CastExtensionSession() {
16503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK(caller_task_runner_->BelongsToCurrentThread());
16603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
16703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Explicitly clear |create_session_desc_observer_|'s pointer to |this|,
16803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // since the CastExtensionSession is destructing. Otherwise,
16903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // |create_session_desc_observer_| would be left with a dangling pointer.
17003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  create_session_desc_observer_->SetCastExtensionSession(NULL);
17103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
17203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  CleanupPeerConnection();
17303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
17403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
17503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// static
17603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)scoped_ptr<CastExtensionSession> CastExtensionSession::Create(
17703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
17803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    scoped_refptr<net::URLRequestContextGetter> url_request_context_getter,
17903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const protocol::NetworkSettings& network_settings,
18003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    ClientSessionControl* client_session_control,
18103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    protocol::ClientStub* client_stub) {
18203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  scoped_ptr<CastExtensionSession> cast_extension_session(
18303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      new CastExtensionSession(caller_task_runner,
18403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                               url_request_context_getter,
18503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                               network_settings,
18603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                               client_session_control,
18703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                               client_stub));
18803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!cast_extension_session->WrapTasksAndSave()) {
18903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return scoped_ptr<CastExtensionSession>();
19003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
19103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!cast_extension_session->InitializePeerConnection()) {
19203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return scoped_ptr<CastExtensionSession>();
19303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
19403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return cast_extension_session.Pass();
19503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
19603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
19703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void CastExtensionSession::OnCreateSessionDescription(
19803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    webrtc::SessionDescriptionInterface* desc) {
19903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!caller_task_runner_->BelongsToCurrentThread()) {
20003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    caller_task_runner_->PostTask(
20103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        FROM_HERE,
20203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        base::Bind(&CastExtensionSession::OnCreateSessionDescription,
20303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                   base::Unretained(this),
20403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                   desc));
20503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return;
20603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
20703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
20803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  peer_connection_->SetLocalDescription(
20903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      CastSetSessionDescriptionObserver::Create(), desc);
21003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
21103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  scoped_ptr<base::DictionaryValue> json(new base::DictionaryValue());
21203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  json->SetString(kWebRtcSessionDescType, desc->type());
21303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  std::string subject =
21403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      (desc->type() == "offer") ? kSubjectOffer : kSubjectAnswer;
21503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  std::string desc_str;
21603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  desc->ToString(&desc_str);
21703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  json->SetString(kWebRtcSessionDescSDP, desc_str);
21803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  std::string json_str;
21903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!base::JSONWriter::Write(json.get(), &json_str)) {
22003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    LOG(ERROR) << "Failed to serialize sdp message.";
22103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return;
22203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
22303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
22403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  SendMessageToClient(subject.c_str(), json_str);
22503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
22603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
22703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void CastExtensionSession::OnCreateSessionDescriptionFailure(
22803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const std::string& error) {
22903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  VLOG(1) << "Creating Session Description failed: " << error;
23003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
23103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
23203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// TODO(aiguha): Support the case(s) where we've grabbed the capturer already,
23303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// but another extension reset the video pipeline. We should remove the
23403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// stream from the peer connection here, and then attempt to re-setup the
23503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// peer connection in the OnRenegotiationNeeded() callback.
23603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// See crbug.com/403843.
2371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid CastExtensionSession::OnCreateVideoCapturer(
2381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    scoped_ptr<webrtc::DesktopCapturer>* capturer) {
23903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (has_grabbed_capturer_) {
24003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    LOG(ERROR) << "The video pipeline was reset unexpectedly.";
24103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    has_grabbed_capturer_ = false;
24203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    peer_connection_->RemoveStream(stream_.release());
2431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
24403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
24503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
24603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (received_offer_) {
24703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    has_grabbed_capturer_ = true;
2481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (SetupVideoStream(capturer->Pass())) {
24903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      peer_connection_->CreateAnswer(create_session_desc_observer_, NULL);
25003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    } else {
25103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      has_grabbed_capturer_ = false;
25203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      // Ignore the received offer, since we failed to setup a video stream.
25303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      received_offer_ = false;
25403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
2551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
25603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
25703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
25803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
25903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool CastExtensionSession::ModifiesVideoPipeline() const {
26003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return true;
26103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
26203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
26303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// Returns true if the |message| is a Cast ExtensionMessage, even if
26403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// it was badly formed or a resulting action failed. This is done so that
26503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// the host does not continue to attempt to pass |message| to other
26603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// HostExtensionSessions.
26703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool CastExtensionSession::OnExtensionMessage(
26803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    ClientSessionControl* client_session_control,
26903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    protocol::ClientStub* client_stub,
27003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const protocol::ExtensionMessage& message) {
27103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (message.type() != kExtensionMessageType) {
27203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return false;
27303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
27403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
27503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  scoped_ptr<base::Value> value(base::JSONReader::Read(message.data()));
27603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  base::DictionaryValue* client_message;
27703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!(value && value->GetAsDictionary(&client_message))) {
27803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    LOG(ERROR) << "Could not read cast extension message.";
27903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return true;
28003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
28103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
28203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  std::string subject;
28303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!client_message->GetString(kTopLevelSubject, &subject)) {
28403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    LOG(ERROR) << "Invalid Cast Extension Message (missing subject header).";
28503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return true;
28603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
28703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
28803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (subject == kSubjectOffer && !received_offer_) {
28903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // Reset the video pipeline so we can grab the screen capturer and setup
29003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // a video stream.
29103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (ParseAndSetRemoteDescription(client_message)) {
29203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      received_offer_ = true;
29303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      LOG(INFO) << "About to ResetVideoPipeline.";
29403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      client_session_control_->ResetVideoPipeline();
29503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
29603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
29703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  } else if (subject == kSubjectAnswer) {
29803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    ParseAndSetRemoteDescription(client_message);
29903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  } else if (subject == kSubjectNewCandidate) {
30003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    ParseAndAddICECandidate(client_message);
30103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  } else {
30203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    VLOG(1) << "Unexpected CastExtension Message: " << message.data();
30303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
30403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return true;
30503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
30603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
30703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// Private methods ------------------------------------------------------------
30803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
30903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)CastExtensionSession::CastExtensionSession(
31003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
31103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    scoped_refptr<net::URLRequestContextGetter> url_request_context_getter,
31203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const protocol::NetworkSettings& network_settings,
31303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    ClientSessionControl* client_session_control,
31403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    protocol::ClientStub* client_stub)
31503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    : caller_task_runner_(caller_task_runner),
31603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      url_request_context_getter_(url_request_context_getter),
31703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      network_settings_(network_settings),
31803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      client_session_control_(client_session_control),
31903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      client_stub_(client_stub),
32003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      stats_observer_(CastStatsObserver::Create()),
32103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      received_offer_(false),
32203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      has_grabbed_capturer_(false),
32303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      signaling_thread_wrapper_(NULL),
32403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      worker_thread_wrapper_(NULL),
32503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      worker_thread_(kWorkerThreadName) {
32603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK(caller_task_runner_->BelongsToCurrentThread());
3271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(url_request_context_getter_.get());
32803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK(client_session_control_);
32903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK(client_stub_);
33003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
33103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // The worker thread is created with base::MessageLoop::TYPE_IO because
33203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // the PeerConnection performs some port allocation operations on this thread
33303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // that require it. See crbug.com/404013.
33403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
33503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  worker_thread_.StartWithOptions(options);
33603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  worker_task_runner_ = worker_thread_.task_runner();
33703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
33803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
33903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool CastExtensionSession::ParseAndSetRemoteDescription(
34003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    base::DictionaryValue* message) {
34103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK(peer_connection_.get() != NULL);
34203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
34303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  base::DictionaryValue* message_data;
34403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!message->GetDictionary(kTopLevelData, &message_data)) {
34503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    LOG(ERROR) << "Invalid Cast Extension Message (missing data).";
34603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return false;
34703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
34803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
34903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  std::string webrtc_type;
35003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!message_data->GetString(kWebRtcSessionDescType, &webrtc_type)) {
35103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    LOG(ERROR)
35203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        << "Invalid Cast Extension Message (missing webrtc type header).";
35303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return false;
35403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
35503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
35603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  std::string sdp;
35703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!message_data->GetString(kWebRtcSessionDescSDP, &sdp)) {
35803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    LOG(ERROR) << "Invalid Cast Extension Message (missing webrtc sdp header).";
35903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return false;
36003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
36103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
36203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  webrtc::SdpParseError error;
36303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  webrtc::SessionDescriptionInterface* session_description(
36403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      webrtc::CreateSessionDescription(webrtc_type, sdp, &error));
36503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
36603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!session_description) {
36703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    LOG(ERROR) << "Invalid Cast Extension Message (could not parse sdp).";
36803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    VLOG(1) << "SdpParseError was: " << error.description;
36903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return false;
37003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
37103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
37203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  peer_connection_->SetRemoteDescription(
37303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      CastSetSessionDescriptionObserver::Create(), session_description);
37403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return true;
37503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
37603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
37703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool CastExtensionSession::ParseAndAddICECandidate(
37803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    base::DictionaryValue* message) {
37903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK(peer_connection_.get() != NULL);
38003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
38103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  base::DictionaryValue* message_data;
38203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!message->GetDictionary(kTopLevelData, &message_data)) {
38303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    LOG(ERROR) << "Invalid Cast Extension Message (missing data).";
38403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return false;
38503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
38603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
38703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  std::string candidate_str;
38803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  std::string sdp_mid;
38903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  int sdp_mlineindex = 0;
39003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!message_data->GetString(kWebRtcSDPMid, &sdp_mid) ||
39103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      !message_data->GetInteger(kWebRtcSDPMLineIndex, &sdp_mlineindex) ||
39203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      !message_data->GetString(kWebRtcCandidate, &candidate_str)) {
39303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    LOG(ERROR) << "Invalid Cast Extension Message (could not parse).";
39403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return false;
39503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
39603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
39703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  rtc::scoped_ptr<webrtc::IceCandidateInterface> candidate(
39803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      webrtc::CreateIceCandidate(sdp_mid, sdp_mlineindex, candidate_str));
39903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!candidate.get()) {
40003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    LOG(ERROR)
40103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        << "Invalid Cast Extension Message (could not create candidate).";
40203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return false;
40303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
40403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
40503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!peer_connection_->AddIceCandidate(candidate.get())) {
40603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    LOG(ERROR) << "Failed to apply received ICE Candidate to PeerConnection.";
40703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return false;
40803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
40903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
41003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  VLOG(1) << "Received and Added ICE Candidate: " << candidate_str;
41103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
41203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return true;
41303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
41403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
41503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool CastExtensionSession::SendMessageToClient(const std::string& subject,
41603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                               const std::string& data) {
41703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK(caller_task_runner_->BelongsToCurrentThread());
41803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
41903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (client_stub_ == NULL) {
42003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    LOG(ERROR) << "No Client Stub. Cannot send message to client.";
42103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return false;
42203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
42303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
42403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  base::DictionaryValue message_dict;
42503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  message_dict.SetString(kTopLevelSubject, subject);
42603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  message_dict.SetString(kTopLevelData, data);
42703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  std::string message_json;
42803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
42903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!base::JSONWriter::Write(&message_dict, &message_json)) {
43003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    LOG(ERROR) << "Failed to serialize JSON message.";
43103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return false;
43203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
43303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
43403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  protocol::ExtensionMessage message;
43503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  message.set_type(kExtensionMessageType);
43603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  message.set_data(message_json);
43703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  client_stub_->DeliverHostMessage(message);
43803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return true;
43903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
44003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
44103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void CastExtensionSession::EnsureTaskAndSetSend(rtc::Thread** ptr,
44203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                                base::WaitableEvent* event) {
44303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop();
44403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  jingle_glue::JingleThreadWrapper::current()->set_send_allowed(true);
44503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  *ptr = jingle_glue::JingleThreadWrapper::current();
44603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
44703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (event != NULL) {
44803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    event->Signal();
44903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
45003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
45103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
45203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool CastExtensionSession::WrapTasksAndSave() {
45303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK(caller_task_runner_->BelongsToCurrentThread());
45403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
45503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  EnsureTaskAndSetSend(&signaling_thread_wrapper_);
45603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (signaling_thread_wrapper_ == NULL)
45703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return false;
45803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
45903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  base::WaitableEvent wrap_worker_thread_event(true, false);
46003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  worker_task_runner_->PostTask(
46103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      FROM_HERE,
46203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      base::Bind(&CastExtensionSession::EnsureTaskAndSetSend,
46303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                 base::Unretained(this),
46403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                 &worker_thread_wrapper_,
46503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                 &wrap_worker_thread_event));
46603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  wrap_worker_thread_event.Wait();
46703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
46803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return (worker_thread_wrapper_ != NULL);
46903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
47003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
47103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool CastExtensionSession::InitializePeerConnection() {
47203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK(caller_task_runner_->BelongsToCurrentThread());
47303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK(!peer_conn_factory_);
47403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK(!peer_connection_);
47503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK(worker_thread_wrapper_ != NULL);
47603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK(signaling_thread_wrapper_ != NULL);
47703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
47803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  peer_conn_factory_ = webrtc::CreatePeerConnectionFactory(
47903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      worker_thread_wrapper_, signaling_thread_wrapper_, NULL, NULL, NULL);
48003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
48103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!peer_conn_factory_.get()) {
48203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    CleanupPeerConnection();
48303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return false;
48403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
48503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
48603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  VLOG(1) << "Created PeerConnectionFactory successfully.";
48703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
48803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  webrtc::PeerConnectionInterface::IceServers servers;
48903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  webrtc::PeerConnectionInterface::IceServer server;
49003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  server.uri = kDefaultStunURI;
49103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  servers.push_back(server);
49203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  webrtc::PeerConnectionInterface::RTCConfiguration rtc_config;
49303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  rtc_config.servers = servers;
49403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
49503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // DTLS-SRTP is the preferred encryption method. If set to kValueFalse, the
49603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // peer connection uses SDES. Disabling SDES as well will cause the peer
49703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // connection to fail to connect.
49803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Note: For protection and unprotection of SRTP packets, the libjingle
49903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // ENABLE_EXTERNAL_AUTH flag must not be set.
50003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  webrtc::FakeConstraints constraints;
50103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,
50203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                           webrtc::MediaConstraintsInterface::kValueTrue);
50303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
50403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  rtc::scoped_refptr<webrtc::PortAllocatorFactoryInterface>
50503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      port_allocator_factory = ChromiumPortAllocatorFactory::Create(
50603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          network_settings_, url_request_context_getter_);
50703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
50803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  peer_connection_ = peer_conn_factory_->CreatePeerConnection(
50903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      rtc_config, &constraints, port_allocator_factory, NULL, this);
51003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
51103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!peer_connection_.get()) {
51203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    CleanupPeerConnection();
51303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return false;
51403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
51503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
51603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  VLOG(1) << "Created PeerConnection successfully.";
51703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
51803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  create_session_desc_observer_ =
51903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      CastCreateSessionDescriptionObserver::Create(this);
52003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
52103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Send a test message to the client. Then, notify the client to start
52203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // webrtc offer/answer negotiation.
52303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!SendMessageToClient(kSubjectTest, "Hello, client.") ||
52403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      !SendMessageToClient(kSubjectReady, "Host ready to receive offers.")) {
52503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    LOG(ERROR) << "Failed to send messages to client.";
52603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return false;
52703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
52803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
52903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return true;
53003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
53103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
53203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool CastExtensionSession::SetupVideoStream(
53303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    scoped_ptr<webrtc::DesktopCapturer> desktop_capturer) {
53403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK(caller_task_runner_->BelongsToCurrentThread());
53503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK(desktop_capturer);
53603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
53703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (stream_) {
53803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    VLOG(1) << "Already added MediaStream. Aborting Setup.";
53903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return false;
54003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
54103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
54203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  scoped_ptr<CastVideoCapturerAdapter> cast_video_capturer_adapter(
54303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      new CastVideoCapturerAdapter(desktop_capturer.Pass()));
54403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
54503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Set video stream constraints.
54603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  webrtc::FakeConstraints video_constraints;
54703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  video_constraints.AddMandatory(
54803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      webrtc::MediaConstraintsInterface::kMinFrameRate, kMinFramesPerSecond);
54903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
55003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track =
55103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      peer_conn_factory_->CreateVideoTrack(
55203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          kVideoLabel,
55303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          peer_conn_factory_->CreateVideoSource(
55403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)              cast_video_capturer_adapter.release(), &video_constraints));
55503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
55603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  stream_ = peer_conn_factory_->CreateLocalMediaStream(kStreamLabel);
55703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
55803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!stream_->AddTrack(video_track) ||
55903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      !peer_connection_->AddStream(stream_, NULL)) {
56003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return false;
56103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
56203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
56303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  VLOG(1) << "Setup video stream successfully.";
56403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
56503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return true;
56603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
56703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
56803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void CastExtensionSession::PollPeerConnectionStats() {
56903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!connection_active()) {
57003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    VLOG(1) << "Cannot poll stats while PeerConnection is inactive.";
57103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
57203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> video_track =
57303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      stream_->FindVideoTrack(kVideoLabel);
57403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  peer_connection_->GetStats(
57503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      stats_observer_,
57603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      video_track.release(),
57703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      webrtc::PeerConnectionInterface::kStatsOutputLevelStandard);
57803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
57903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
58003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void CastExtensionSession::CleanupPeerConnection() {
58103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  peer_connection_->Close();
58203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  peer_connection_ = NULL;
58303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  stream_ = NULL;
58403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  peer_conn_factory_ = NULL;
58503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  worker_thread_.Stop();
58603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
58703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
58803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool CastExtensionSession::connection_active() const {
58903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return peer_connection_.get() != NULL;
59003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
59103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
59203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// webrtc::PeerConnectionObserver implementation -------------------------------
59303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
59403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void CastExtensionSession::OnError() {
59503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  VLOG(1) << "PeerConnectionObserver: an error occurred.";
59603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
59703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
59803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void CastExtensionSession::OnSignalingChange(
59903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    webrtc::PeerConnectionInterface::SignalingState new_state) {
60003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  VLOG(1) << "PeerConnectionObserver: SignalingState changed to:" << new_state;
60103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
60203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
60303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void CastExtensionSession::OnStateChange(
60403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    webrtc::PeerConnectionObserver::StateType state_changed) {
60503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  VLOG(1) << "PeerConnectionObserver: StateType changed to: " << state_changed;
60603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
60703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
60803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void CastExtensionSession::OnAddStream(webrtc::MediaStreamInterface* stream) {
60903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  VLOG(1) << "PeerConnectionObserver: stream added: " << stream->label();
61003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
61103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
61203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void CastExtensionSession::OnRemoveStream(
61303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    webrtc::MediaStreamInterface* stream) {
61403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  VLOG(1) << "PeerConnectionObserver: stream removed: " << stream->label();
61503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
61603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
61703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void CastExtensionSession::OnDataChannel(
61803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    webrtc::DataChannelInterface* data_channel) {
61903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  VLOG(1) << "PeerConnectionObserver: data channel: " << data_channel->label();
62003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
62103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
62203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void CastExtensionSession::OnRenegotiationNeeded() {
62303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  VLOG(1) << "PeerConnectionObserver: renegotiation needed.";
62403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
62503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
62603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void CastExtensionSession::OnIceConnectionChange(
62703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    webrtc::PeerConnectionInterface::IceConnectionState new_state) {
62803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  VLOG(1) << "PeerConnectionObserver: IceConnectionState changed to: "
62903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          << new_state;
63003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
63103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // TODO(aiguha): Maybe start timer only if enabled by command-line flag or
63203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // at a particular verbosity level.
63303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!stats_polling_timer_.IsRunning() &&
63403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      new_state == webrtc::PeerConnectionInterface::kIceConnectionConnected) {
63503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    stats_polling_timer_.Start(
63603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        FROM_HERE,
63703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        base::TimeDelta::FromSeconds(kStatsLogIntervalSec),
63803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        this,
63903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        &CastExtensionSession::PollPeerConnectionStats);
64003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
64103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
64203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
64303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void CastExtensionSession::OnIceGatheringChange(
64403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    webrtc::PeerConnectionInterface::IceGatheringState new_state) {
64503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  VLOG(1) << "PeerConnectionObserver: IceGatheringState changed to: "
64603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          << new_state;
64703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
64803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
64903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void CastExtensionSession::OnIceComplete() {
65003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  VLOG(1) << "PeerConnectionObserver: all ICE candidates found.";
65103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
65203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
65303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void CastExtensionSession::OnIceCandidate(
65403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const webrtc::IceCandidateInterface* candidate) {
65503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  std::string candidate_str;
65603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!candidate->ToString(&candidate_str)) {
65703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    LOG(ERROR) << "PeerConnectionObserver: failed to serialize candidate.";
65803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return;
65903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
66003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  scoped_ptr<base::DictionaryValue> json(new base::DictionaryValue());
66103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  json->SetString(kWebRtcSDPMid, candidate->sdp_mid());
66203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  json->SetInteger(kWebRtcSDPMLineIndex, candidate->sdp_mline_index());
66303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  json->SetString(kWebRtcCandidate, candidate_str);
66403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  std::string json_str;
66503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!base::JSONWriter::Write(json.get(), &json_str)) {
66603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    LOG(ERROR) << "Failed to serialize candidate message.";
66703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return;
66803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
66903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  SendMessageToClient(kSubjectNewCandidate, json_str);
67003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
67103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
67203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}  // namespace remoting
673