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