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