1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "extensions/renderer/api/display_source/wifi_display/wifi_display_session.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/timer/timer.h"
12 #include "content/public/renderer/render_frame.h"
13 #include "extensions/renderer/api/display_source/wifi_display/wifi_display_media_manager.h"
14 #include "mojo/public/cpp/bindings/remote.h"
15 #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
16 #include "third_party/wds/src/libwds/public/logging.h"
17 #include "third_party/wds/src/libwds/public/media_manager.h"
18 
19 namespace {
20 const char kErrorInternal[] = "An internal error has occurred";
21 const char kErrorTimeout[] = "Sink became unresponsive";
22 
LogWDSError(const char * format,...)23 static void LogWDSError(const char* format, ...) {
24   va_list args;
25   va_start(args, format);
26   char buffer[256];
27   vsnprintf(buffer, 256, format, args);
28   va_end(args);
29   DVLOG(1) << "[WDS] " << buffer;
30 }
31 
32 }  // namespace
33 
34 namespace extensions {
35 
36 using api::display_source::ErrorType;
37 
WiFiDisplaySession(const DisplaySourceSessionParams & params)38 WiFiDisplaySession::WiFiDisplaySession(const DisplaySourceSessionParams& params)
39     : params_(params), cseq_(0), timer_id_(0), weak_factory_(this) {
40   DCHECK(params_.render_frame);
41   wds::LogSystem::set_error_func(&LogWDSError);
42   params.render_frame->GetBrowserInterfaceBroker()->GetInterface(&service_);
43   service_.set_connection_error_handler(base::Bind(
44           &WiFiDisplaySession::OnIPCConnectionError,
45           weak_factory_.GetWeakPtr()));
46 
47   mojo::Remote<WiFiDisplaySessionServiceClient> client;
48   receiver_.Bind(client.BindNewPipeAndPassReceiver());
49   service_->SetClient(std::move(client));
50   receiver_.set_disconnect_handler(base::Bind(
51       &WiFiDisplaySession::OnIPCConnectionError, weak_factory_.GetWeakPtr()));
52 }
53 
~WiFiDisplaySession()54 WiFiDisplaySession::~WiFiDisplaySession() {
55 }
56 
Start(const CompletionCallback & callback)57 void WiFiDisplaySession::Start(const CompletionCallback& callback) {
58   DCHECK_EQ(DisplaySourceSession::Idle, state_);
59   DCHECK(!terminated_callback_.is_null())
60       << "Should be set with 'SetNotificationCallbacks'";
61   DCHECK(!error_callback_.is_null())
62       << "Should be set with 'SetNotificationCallbacks'";
63 
64   service_->Connect(params_.sink_id, params_.auth_method, params_.auth_data);
65   state_ = DisplaySourceSession::Establishing;
66   start_completion_callback_ = callback;
67 }
68 
Terminate(const CompletionCallback & callback)69 void WiFiDisplaySession::Terminate(const CompletionCallback& callback) {
70   DCHECK_EQ(DisplaySourceSession::Established, state_);
71   Terminate();
72   teminate_completion_callback_ = callback;
73 }
74 
OnConnected(const net::IPAddress & local_ip_address,const net::IPAddress & sink_ip_address)75 void WiFiDisplaySession::OnConnected(const net::IPAddress& local_ip_address,
76                                      const net::IPAddress& sink_ip_address) {
77   DCHECK_EQ(DisplaySourceSession::Established, state_);
78   local_ip_address_ = local_ip_address;
79   media_manager_.reset(new WiFiDisplayMediaManager(
80       params_.video_track, params_.audio_track, sink_ip_address,
81       params_.render_frame->GetBrowserInterfaceBroker(),
82       base::Bind(&WiFiDisplaySession::OnMediaError,
83                  weak_factory_.GetWeakPtr())));
84   wfd_source_.reset(wds::Source::Create(this, media_manager_.get(), this));
85   wfd_source_->Start();
86 }
87 
OnConnectRequestHandled(bool success,const std::string & error)88 void WiFiDisplaySession::OnConnectRequestHandled(bool success,
89                                                  const std::string& error) {
90   DCHECK_EQ(DisplaySourceSession::Establishing, state_);
91   state_ =
92       success ? DisplaySourceSession::Established : DisplaySourceSession::Idle;
93   RunStartCallback(success, error);
94 }
95 
OnTerminated()96 void WiFiDisplaySession::OnTerminated() {
97   DCHECK_NE(DisplaySourceSession::Idle, state_);
98   state_ = DisplaySourceSession::Idle;
99   media_manager_.reset();
100   wfd_source_.reset();
101   terminated_callback_.Run();
102 }
103 
OnDisconnectRequestHandled(bool success,const std::string & error)104 void WiFiDisplaySession::OnDisconnectRequestHandled(bool success,
105                                                     const std::string& error) {
106   RunTerminateCallback(success, error);
107 }
108 
OnError(int32_t type,const std::string & description)109 void WiFiDisplaySession::OnError(int32_t type, const std::string& description) {
110   DCHECK(type > api::display_source::ERROR_TYPE_NONE
111          && type <= api::display_source::ERROR_TYPE_LAST);
112   DCHECK_EQ(DisplaySourceSession::Established, state_);
113   error_callback_.Run(static_cast<ErrorType>(type), description);
114 }
115 
OnMessage(const std::string & data)116 void WiFiDisplaySession::OnMessage(const std::string& data) {
117   DCHECK_EQ(DisplaySourceSession::Established, state_);
118   DCHECK(wfd_source_);
119   wfd_source_->RTSPDataReceived(data);
120 }
121 
GetLocalIPAddress() const122 std::string WiFiDisplaySession::GetLocalIPAddress() const {
123   return local_ip_address_.ToString();
124 }
125 
GetNextCSeq(int * initial_peer_cseq) const126 int WiFiDisplaySession::GetNextCSeq(int* initial_peer_cseq) const {
127   return ++cseq_;
128 }
129 
SendRTSPData(const std::string & message)130 void WiFiDisplaySession::SendRTSPData(const std::string& message) {
131   service_->SendMessage(message);
132 }
133 
CreateTimer(int seconds)134 unsigned WiFiDisplaySession::CreateTimer(int seconds) {
135   std::unique_ptr<base::RepeatingTimer> timer(new base::RepeatingTimer());
136   auto insert_ret =
137       timers_.insert(std::pair<int, std::unique_ptr<base::RepeatingTimer>>(
138           ++timer_id_, std::move(timer)));
139   DCHECK(insert_ret.second);
140   insert_ret.first->second->Start(FROM_HERE,
141                base::TimeDelta::FromSeconds(seconds),
142                base::Bind(&wds::Source::OnTimerEvent,
143                           base::Unretained(wfd_source_.get()),
144                           timer_id_));
145   return static_cast<unsigned>(timer_id_);
146 }
147 
ReleaseTimer(unsigned timer_id)148 void WiFiDisplaySession::ReleaseTimer(unsigned timer_id) {
149   auto it = timers_.find(static_cast<int>(timer_id));
150   if (it != timers_.end())
151     timers_.erase(it);
152 }
153 
ErrorOccurred(wds::ErrorType error)154 void WiFiDisplaySession::ErrorOccurred(wds::ErrorType error) {
155   DCHECK_NE(DisplaySourceSession::Idle, state_);
156   if (error == wds::TimeoutError) {
157     error_callback_.Run(api::display_source::ERROR_TYPE_TIMEOUT_ERROR,
158                         kErrorTimeout);
159   } else {
160     error_callback_.Run(api::display_source::ERROR_TYPE_UNKNOWN_ERROR,
161                         kErrorInternal);
162   }
163   // The session cannot continue.
164   Terminate();
165 }
166 
SessionCompleted()167 void WiFiDisplaySession::SessionCompleted() {
168   DCHECK_NE(DisplaySourceSession::Idle, state_);
169   // The session has finished normally.
170   Terminate();
171 }
172 
OnIPCConnectionError()173 void WiFiDisplaySession::OnIPCConnectionError() {
174   // We must explicitly notify the session termination as it will never
175   // arrive from browser process (IPC is broken).
176   switch (state_) {
177     case DisplaySourceSession::Idle:
178     case DisplaySourceSession::Establishing:
179       RunStartCallback(false, kErrorInternal);
180       break;
181     case DisplaySourceSession::Terminating:
182     case DisplaySourceSession::Established:
183       error_callback_.Run(api::display_source::ERROR_TYPE_UNKNOWN_ERROR,
184                           kErrorInternal);
185       state_ = DisplaySourceSession::Idle;
186       terminated_callback_.Run();
187       break;
188     default:
189       NOTREACHED();
190   }
191 }
192 
OnMediaError(const std::string & error)193 void WiFiDisplaySession::OnMediaError(const std::string& error) {
194   DCHECK_NE(DisplaySourceSession::Idle, state_);
195   error_callback_.Run(api::display_source::ERROR_TYPE_MEDIA_PIPELINE_ERROR,
196                       error);
197   Terminate();
198 }
199 
Terminate()200 void WiFiDisplaySession::Terminate() {
201   if (state_ == DisplaySourceSession::Established) {
202     service_->Disconnect();
203     state_ = DisplaySourceSession::Terminating;
204   }
205 }
206 
RunStartCallback(bool success,const std::string & error_message)207 void WiFiDisplaySession::RunStartCallback(bool success,
208                                           const std::string& error_message) {
209   if (!start_completion_callback_.is_null())
210     start_completion_callback_.Run(success, error_message);
211 }
212 
RunTerminateCallback(bool success,const std::string & error_message)213 void WiFiDisplaySession::RunTerminateCallback(
214     bool success,
215     const std::string& error_message) {
216   if (!teminate_completion_callback_.is_null())
217     teminate_completion_callback_.Run(success, error_message);
218 }
219 
220 }  // namespace extensions
221