• 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 <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