1 /*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "host/frontend/webrtc/libcommon/connection_controller.h"
18
19 #include <vector>
20
21 #include <android-base/logging.h>
22
23 #include "common/libs/utils/json.h"
24 #include "host/frontend/webrtc/libcommon/utils.h"
25
26 namespace cuttlefish {
27 namespace webrtc_streaming {
28
29 // Different classes are needed because all the interfaces inherit from
30 // classes providing the methods AddRef and Release, needed by scoped_ptr, which
31 // cause ambiguity when a single class (i.e ConnectionController) implements all
32 // of them.
33 // It's safe for these classes to hold a reference to the ConnectionController
34 // because it owns the peer connection, so it will never be destroyed before
35 // these observers.
36 class CreateSessionDescriptionObserverIntermediate
37 : public webrtc::CreateSessionDescriptionObserver {
38 public:
CreateSessionDescriptionObserverIntermediate(ConnectionController & controller)39 CreateSessionDescriptionObserverIntermediate(ConnectionController& controller)
40 : controller_(controller) {}
41
OnSuccess(webrtc::SessionDescriptionInterface * desc)42 void OnSuccess(webrtc::SessionDescriptionInterface* desc) override {
43 auto res = controller_.OnCreateSDPSuccess(desc);
44 if (!res.ok()) {
45 LOG(ERROR) << res.error().FormatForEnv();
46 }
47 }
OnFailure(webrtc::RTCError error)48 void OnFailure(webrtc::RTCError error) override {
49 controller_.OnCreateSDPFailure(error);
50 }
51
52 private:
53 ConnectionController& controller_;
54 };
55
56 class SetSessionDescriptionObserverIntermediate
57 : public webrtc::SetSessionDescriptionObserver {
58 public:
SetSessionDescriptionObserverIntermediate(ConnectionController & controller)59 SetSessionDescriptionObserverIntermediate(ConnectionController& controller)
60 : controller_(controller) {}
61
OnSuccess()62 void OnSuccess() override { controller_.OnSetLocalDescriptionSuccess(); }
OnFailure(webrtc::RTCError error)63 void OnFailure(webrtc::RTCError error) override {
64 controller_.OnSetLocalDescriptionFailure(error);
65 }
66
67 private:
68 ConnectionController& controller_;
69 };
70
71 class SetRemoteDescriptionObserverIntermediate
72 : public webrtc::SetRemoteDescriptionObserverInterface {
73 public:
SetRemoteDescriptionObserverIntermediate(ConnectionController & controller)74 SetRemoteDescriptionObserverIntermediate(ConnectionController& controller)
75 : controller_(controller) {}
76
OnSetRemoteDescriptionComplete(webrtc::RTCError error)77 void OnSetRemoteDescriptionComplete(webrtc::RTCError error) override {
78 controller_.OnSetRemoteDescriptionComplete(error);
79 }
80
81 private:
82 ConnectionController& controller_;
83 };
84
ConnectionController(PeerSignalingHandler & sig_handler,PeerConnectionBuilder & connection_builder,ConnectionController::Observer & observer)85 ConnectionController::ConnectionController(
86 PeerSignalingHandler& sig_handler,
87 PeerConnectionBuilder& connection_builder,
88 ConnectionController::Observer& observer)
89 : sig_handler_(sig_handler),
90 connection_builder_(connection_builder),
91 observer_(observer) {}
92
CreateOffer()93 void ConnectionController::CreateOffer() {
94 // No memory leak here because this is a ref counted object and the
95 // peer connection immediately wraps it with a scoped_refptr
96 peer_connection_->CreateOffer(ThisAsCreateSDPObserver(), {} /*options*/);
97 }
98
RequestOffer(const std::vector<webrtc::PeerConnectionInterface::IceServer> & ice_servers)99 Result<void> ConnectionController::RequestOffer(
100 const std::vector<webrtc::PeerConnectionInterface::IceServer>&
101 ice_servers) {
102 observer_.OnConnectionStateChange(
103 webrtc::PeerConnectionInterface::PeerConnectionState::kNew);
104 Json::Value msg;
105 msg["type"] = "request-offer";
106 if (!ice_servers.empty()) {
107 // Only include the ice servers in the message if non empty
108 msg["ice_servers"] = GenerateIceServersMessage(ice_servers);
109 }
110 CF_EXPECT(sig_handler_.SendMessage(msg),
111 "Failed to send the request-offer message to the device");
112 return {};
113 }
114
FailConnection(const std::string & message)115 void ConnectionController::FailConnection(const std::string& message) {
116 Json::Value reply;
117 reply["type"] = "error";
118 reply["error"] = message;
119 auto res = sig_handler_.SendMessage(reply);
120 if (!res.ok()) {
121 LOG(ERROR) << res.error().FormatForEnv();
122 }
123 observer_.OnConnectionStateChange(CF_ERR(message));
124 }
125
AddPendingIceCandidates()126 void ConnectionController::AddPendingIceCandidates() {
127 // Add any ice candidates that arrived before the remote description
128 for (auto& candidate : pending_ice_candidates_) {
129 peer_connection_->AddIceCandidate(
130 std::move(candidate), [this](webrtc::RTCError error) {
131 if (!error.ok()) {
132 FailConnection(ToString(error.type()) + std::string(": ") +
133 error.message());
134 }
135 });
136 }
137 pending_ice_candidates_.clear();
138 }
139
OnOfferRequestMsg(const std::vector<webrtc::PeerConnectionInterface::IceServer> & ice_servers)140 Result<void> ConnectionController::OnOfferRequestMsg(
141 const std::vector<webrtc::PeerConnectionInterface::IceServer>&
142 ice_servers) {
143 peer_connection_ = CF_EXPECT(connection_builder_.Build(*this, ice_servers),
144 "Failed to create peer connection");
145 CreateOffer();
146 return {};
147 }
148
OnOfferMsg(std::unique_ptr<webrtc::SessionDescriptionInterface> offer)149 Result<void> ConnectionController::OnOfferMsg(
150 std::unique_ptr<webrtc::SessionDescriptionInterface> offer) {
151 peer_connection_->SetRemoteDescription(std::move(offer),
152 ThisAsSetRemoteSDPObserver());
153 return {};
154 }
155
OnAnswerMsg(std::unique_ptr<webrtc::SessionDescriptionInterface> answer)156 Result<void> ConnectionController::OnAnswerMsg(
157 std::unique_ptr<webrtc::SessionDescriptionInterface> answer) {
158 peer_connection_->SetRemoteDescription(std::move(answer),
159 ThisAsSetRemoteSDPObserver());
160 return {};
161 }
162
OnIceCandidateMsg(std::unique_ptr<webrtc::IceCandidateInterface> candidate)163 Result<void> ConnectionController::OnIceCandidateMsg(
164 std::unique_ptr<webrtc::IceCandidateInterface> candidate) {
165 if (peer_connection_->remote_description()) {
166 peer_connection_->AddIceCandidate(
167 std::move(candidate), [this](webrtc::RTCError error) {
168 if (!error.ok()) {
169 FailConnection(ToString(error.type()) + std::string(": ") +
170 error.message());
171 }
172 });
173 } else {
174 // Store the ice candidate to be added later if it arrives before the
175 // remote description. This could happen if the client uses polling
176 // instead of websockets because the candidates are generated immediately
177 // after the remote (offer) description is set and the events and the ajax
178 // calls are asynchronous.
179 pending_ice_candidates_.push_back(std::move(candidate));
180 }
181 return {};
182 }
183
OnErrorMsg(const std::string & msg)184 Result<void> ConnectionController::OnErrorMsg(const std::string& msg) {
185 LOG(ERROR) << "Received error message from peer: " << msg;
186 return {};
187 }
188
OnCreateSDPSuccess(webrtc::SessionDescriptionInterface * desc)189 Result<void> ConnectionController::OnCreateSDPSuccess(
190 webrtc::SessionDescriptionInterface* desc) {
191 std::string offer_str;
192 desc->ToString(&offer_str);
193 std::string sdp_type = desc->type();
194 peer_connection_->SetLocalDescription(ThisAsSetSDPObserver(), desc);
195 // The peer connection takes ownership of the description so it should not be
196 // used after this
197 desc = nullptr;
198
199 Json::Value reply;
200 reply["type"] = sdp_type;
201 reply["sdp"] = offer_str;
202
203 CF_EXPECT(sig_handler_.SendMessage(reply));
204 return {};
205 }
206
OnCreateSDPFailure(const webrtc::RTCError & error)207 void ConnectionController::OnCreateSDPFailure(const webrtc::RTCError& error) {
208 FailConnection(ToString(error.type()) + std::string(": ") + error.message());
209 }
210
OnSetLocalDescriptionSuccess()211 void ConnectionController::OnSetLocalDescriptionSuccess() {
212 // local description set, nothing else to do
213 }
214
OnSetLocalDescriptionFailure(const webrtc::RTCError & error)215 void ConnectionController::OnSetLocalDescriptionFailure(
216 const webrtc::RTCError& error) {
217 LOG(ERROR) << "Error setting local description: Either there is a bug in "
218 "libwebrtc or the local description was (incorrectly) modified "
219 "after creating it";
220 FailConnection(ToString(error.type()) + std::string(": ") + error.message());
221 }
222
OnSetRemoteDescriptionComplete(const webrtc::RTCError & error)223 void ConnectionController::OnSetRemoteDescriptionComplete(
224 const webrtc::RTCError& error) {
225 if (!error.ok()) {
226 // The remote description was rejected, can't connect to device.
227 FailConnection(ToString(error.type()) + std::string(": ") +
228 error.message());
229 return;
230 }
231 AddPendingIceCandidates();
232 auto remote_desc = peer_connection_->remote_description();
233 CHECK(remote_desc) << "The remote description was just added successfully in "
234 "this thread, so it can't be nullptr";
235 if (remote_desc->GetType() != webrtc::SdpType::kOffer) {
236 // Only create and send answer when the remote description is an offer.
237 return;
238 }
239 peer_connection_->CreateAnswer(ThisAsCreateSDPObserver(), {} /*options*/);
240 }
241
242 // No memory leaks with these because the peer_connection immediately wraps
243 // these pointers with scoped_refptr.
244 webrtc::CreateSessionDescriptionObserver*
ThisAsCreateSDPObserver()245 ConnectionController::ThisAsCreateSDPObserver() {
246 return new rtc::RefCountedObject<
247 CreateSessionDescriptionObserverIntermediate>(*this);
248 }
249 webrtc::SetSessionDescriptionObserver*
ThisAsSetSDPObserver()250 ConnectionController::ThisAsSetSDPObserver() {
251 return new rtc::RefCountedObject<SetSessionDescriptionObserverIntermediate>(
252 *this);
253 }
254 rtc::scoped_refptr<webrtc::SetRemoteDescriptionObserverInterface>
ThisAsSetRemoteSDPObserver()255 ConnectionController::ThisAsSetRemoteSDPObserver() {
256 return rtc::scoped_refptr<webrtc::SetRemoteDescriptionObserverInterface>(
257 new rtc::RefCountedObject<SetRemoteDescriptionObserverIntermediate>(
258 *this));
259 }
260
HandleSignalingMessage(const Json::Value & msg)261 void ConnectionController::HandleSignalingMessage(const Json::Value& msg) {
262 auto result = HandleSignalingMessageInner(msg);
263 if (!result.ok()) {
264 LOG(ERROR) << result.error().FormatForEnv();
265 FailConnection(result.error().Message());
266 }
267 }
268
HandleSignalingMessageInner(const Json::Value & message)269 Result<void> ConnectionController::HandleSignalingMessageInner(
270 const Json::Value& message) {
271 auto type = CF_EXPECT(GetValue<std::string>(message, {"type"}),
272 "Failed to get signaling message type");
273
274 if (type == "request-offer") {
275 auto ice_servers = CF_EXPECT(ParseIceServersMessage(message),
276 "Error parsing ice-servers field");
277 return OnOfferRequestMsg(ice_servers);
278 } else if (type == "offer") {
279 auto remote_desc = CF_EXPECT(
280 ParseSessionDescription(type, message, webrtc::SdpType::kOffer));
281 return OnOfferMsg(std::move(remote_desc));
282 } else if (type == "answer") {
283 auto remote_desc = CF_EXPECT(
284 ParseSessionDescription(type, message, webrtc::SdpType::kAnswer));
285 return OnAnswerMsg(std::move(remote_desc));
286 } else if (type == "ice-candidate") {
287 auto candidate = CF_EXPECT(ParseIceCandidate(type, message));
288 return OnIceCandidateMsg(std::move(candidate));
289 } else if (type == "error") {
290 return OnErrorMsg(CF_EXPECT(ParseError(type, message)));
291 } else {
292 return CF_ERR("Unknown client message type: " + type);
293 }
294 }
295
296 // Triggered when the SignalingState changed.
OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState new_state)297 void ConnectionController::OnSignalingChange(
298 webrtc::PeerConnectionInterface::SignalingState new_state) {
299 LOG(VERBOSE) << "Signaling state changed: " << new_state;
300 }
301
302 // Triggered when media is received on a new stream from remote peer.
OnAddStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream)303 void ConnectionController::OnAddStream(
304 rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) {
305 LOG(VERBOSE) << "Stream added: " << stream->id();
306 }
307
308 // Triggered when a remote peer closes a stream.
OnRemoveStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream)309 void ConnectionController::OnRemoveStream(
310 rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) {
311 LOG(VERBOSE) << "Stream removed: " << stream->id();
312 }
313
314 // Triggered when a remote peer opens a data channel.
OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel)315 void ConnectionController::OnDataChannel(
316 rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) {
317 observer_.OnDataChannel(data_channel);
318 }
319
320 // Triggered when renegotiation is needed. For example, an ICE restart
321 // has begun.
OnRenegotiationNeeded()322 void ConnectionController::OnRenegotiationNeeded() {
323 if (!peer_connection_) {
324 return;
325 }
326 CreateOffer();
327 }
328
329 // Called any time the standards-compliant IceConnectionState changes.
OnStandardizedIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState new_state)330 void ConnectionController::OnStandardizedIceConnectionChange(
331 webrtc::PeerConnectionInterface::IceConnectionState new_state) {
332 switch (new_state) {
333 case webrtc::PeerConnectionInterface::kIceConnectionNew:
334 LOG(DEBUG) << "ICE connection state: New";
335 break;
336 case webrtc::PeerConnectionInterface::kIceConnectionChecking:
337 LOG(DEBUG) << "ICE connection state: Checking";
338 break;
339 case webrtc::PeerConnectionInterface::kIceConnectionConnected:
340 LOG(DEBUG) << "ICE connection state: Connected";
341 break;
342 case webrtc::PeerConnectionInterface::kIceConnectionCompleted:
343 LOG(DEBUG) << "ICE connection state: Completed";
344 break;
345 case webrtc::PeerConnectionInterface::kIceConnectionFailed:
346 LOG(DEBUG) << "ICE connection state: Failed";
347 break;
348 case webrtc::PeerConnectionInterface::kIceConnectionDisconnected:
349 LOG(DEBUG) << "ICE connection state: Disconnected";
350 break;
351 case webrtc::PeerConnectionInterface::kIceConnectionClosed:
352 LOG(DEBUG) << "ICE connection state: Closed";
353 break;
354 case webrtc::PeerConnectionInterface::kIceConnectionMax:
355 LOG(DEBUG) << "ICE connection state: Max";
356 break;
357 default:
358 LOG(DEBUG) << "ICE connection state: " << new_state;
359 }
360 }
361
362 // Called any time the PeerConnectionState changes.
OnConnectionChange(webrtc::PeerConnectionInterface::PeerConnectionState new_state)363 void ConnectionController::OnConnectionChange(
364 webrtc::PeerConnectionInterface::PeerConnectionState new_state) {
365 observer_.OnConnectionStateChange(new_state);
366 }
367
368 // Called any time the IceGatheringState changes.
OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState new_state)369 void ConnectionController::OnIceGatheringChange(
370 webrtc::PeerConnectionInterface::IceGatheringState new_state) {
371 std::string state_str;
372 switch (new_state) {
373 case webrtc::PeerConnectionInterface::IceGatheringState::kIceGatheringNew:
374 state_str = "NEW";
375 break;
376 case webrtc::PeerConnectionInterface::IceGatheringState::
377 kIceGatheringGathering:
378 state_str = "GATHERING";
379 break;
380 case webrtc::PeerConnectionInterface::IceGatheringState::
381 kIceGatheringComplete:
382 state_str = "COMPLETE";
383 break;
384 default:
385 state_str = "UNKNOWN";
386 }
387 LOG(VERBOSE) << "ICE Gathering state set to: " << state_str;
388 }
389
390 // A new ICE candidate has been gathered.
OnIceCandidate(const webrtc::IceCandidateInterface * candidate)391 void ConnectionController::OnIceCandidate(
392 const webrtc::IceCandidateInterface* candidate) {
393 std::string candidate_sdp;
394 candidate->ToString(&candidate_sdp);
395 auto sdp_mid = candidate->sdp_mid();
396 auto line_index = candidate->sdp_mline_index();
397
398 Json::Value reply;
399 reply["type"] = "ice-candidate";
400 reply["mid"] = sdp_mid;
401 reply["mLineIndex"] = static_cast<Json::UInt64>(line_index);
402 reply["candidate"] = candidate_sdp;
403
404 auto res = sig_handler_.SendMessage(reply);
405 if (!res.ok()) {
406 LOG(ERROR) << res.error().FormatForEnv();
407 }
408 }
409
410 // Gathering of an ICE candidate failed.
411 // See https://w3c.github.io/webrtc-pc/#event-icecandidateerror
OnIceCandidateError(const std::string & address,int port,const std::string & url,int error_code,const std::string & error_text)412 void ConnectionController::OnIceCandidateError(const std::string& address,
413 int port, const std::string& url,
414 int error_code,
415 const std::string& error_text) {
416 LOG(VERBOSE) << "Gathering of an ICE candidate (address: " << address
417 << ", port: " << port << ", url: " << url
418 << ") failed: " << error_text;
419 }
420
421 // Ice candidates have been removed.
OnIceCandidatesRemoved(const std::vector<cricket::Candidate> &)422 void ConnectionController::OnIceCandidatesRemoved(
423 const std::vector<cricket::Candidate>&) {
424 // ignore
425 }
426
427 // This is called when signaling indicates a transceiver will be receiving
428 // media from the remote endpoint. This is fired during a call to
429 // SetRemoteDescription. The receiving track can be accessed by:
430 // ConnectionController::|transceiver->receiver()->track()| and its
431 // associated streams by |transceiver->receiver()->streams()|. Note: This will
432 // only be called if Unified Plan semantics are specified. This behavior is
433 // specified in section 2.2.8.2.5 of the "Set the RTCSessionDescription"
434 // algorithm: https://w3c.github.io/webrtc-pc/#set-description
OnTrack(rtc::scoped_refptr<webrtc::RtpTransceiverInterface> transceiver)435 void ConnectionController::OnTrack(
436 rtc::scoped_refptr<webrtc::RtpTransceiverInterface> transceiver) {
437 observer_.OnTrack(transceiver);
438 }
439
440 // Called when signaling indicates that media will no longer be received on a
441 // track.
442 // With Plan B semantics, the given receiver will have been removed from the
443 // PeerConnection and the track muted.
444 // With Unified Plan semantics, the receiver will remain but the transceiver
445 // will have changed direction to either sendonly or inactive.
446 // https://w3c.github.io/webrtc-pc/#process-remote-track-removal
OnRemoveTrack(rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver)447 void ConnectionController::OnRemoveTrack(
448 rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver) {
449 observer_.OnRemoveTrack(receiver);
450 }
451
452 } // namespace webrtc_streaming
453 } // namespace cuttlefish
454