• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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