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