1 /*
2  * Copyright (C) 2020 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 #define LOG_TAG "ClientHandler"
18 
19 #include "host/frontend/webrtc/libdevice/client_handler.h"
20 
21 #include <netdb.h>
22 #include <openssl/rand.h>
23 
24 #include <android-base/logging.h>
25 
26 #include "host/libs/config/cuttlefish_config.h"
27 
28 namespace cuttlefish {
29 namespace webrtc_streaming {
30 
31 // Video streams initiating in the client may be added and removed at unexpected
32 // times, causing the webrtc objects to be destroyed and created every time.
33 // This class hides away that complexity and allows to set up sinks only once.
34 class ClientVideoTrackImpl : public ClientVideoTrackInterface {
35  public:
AddOrUpdateSink(rtc::VideoSinkInterface<webrtc::VideoFrame> * sink,const rtc::VideoSinkWants & wants)36   void AddOrUpdateSink(rtc::VideoSinkInterface<webrtc::VideoFrame> *sink,
37                        const rtc::VideoSinkWants &wants) override {
38     sink_ = sink;
39     wants_ = wants;
40     if (video_track_) {
41       video_track_->AddOrUpdateSink(sink, wants);
42     }
43   }
44 
SetVideoTrack(webrtc::VideoTrackInterface * track)45   void SetVideoTrack(webrtc::VideoTrackInterface *track) {
46     video_track_ = track;
47     if (sink_) {
48       video_track_->AddOrUpdateSink(sink_, wants_);
49     }
50   }
51 
UnsetVideoTrack(webrtc::VideoTrackInterface * track)52   void UnsetVideoTrack(webrtc::VideoTrackInterface *track) {
53     if (track == video_track_) {
54       video_track_ = nullptr;
55     }
56   }
57 
58  private:
59   webrtc::VideoTrackInterface* video_track_;
60   rtc::VideoSinkInterface<webrtc::VideoFrame> *sink_ = nullptr;
61   rtc::VideoSinkWants wants_ = {};
62 };
63 
Create(int client_id,std::shared_ptr<ConnectionObserver> observer,PeerConnectionBuilder & connection_builder,std::function<void (const Json::Value &)> send_to_client_cb,std::function<void (bool)> on_connection_changed_cb)64 std::shared_ptr<ClientHandler> ClientHandler::Create(
65     int client_id, std::shared_ptr<ConnectionObserver> observer,
66     PeerConnectionBuilder &connection_builder,
67     std::function<void(const Json::Value &)> send_to_client_cb,
68     std::function<void(bool)> on_connection_changed_cb) {
69   return std::shared_ptr<ClientHandler>(
70       new ClientHandler(client_id, observer, connection_builder,
71                         send_to_client_cb, on_connection_changed_cb));
72 }
73 
ClientHandler(int client_id,std::shared_ptr<ConnectionObserver> observer,PeerConnectionBuilder & connection_builder,std::function<void (const Json::Value &)> send_to_client_cb,std::function<void (bool)> on_connection_changed_cb)74 ClientHandler::ClientHandler(
75     int client_id, std::shared_ptr<ConnectionObserver> observer,
76     PeerConnectionBuilder &connection_builder,
77     std::function<void(const Json::Value &)> send_to_client_cb,
78     std::function<void(bool)> on_connection_changed_cb)
79     : client_id_(client_id),
80       observer_(observer),
81       send_to_client_(send_to_client_cb),
82       on_connection_changed_cb_(on_connection_changed_cb),
83       connection_builder_(connection_builder),
84       controller_(*this, *this, *this),
85       data_channels_handler_(observer),
86       camera_track_(new ClientVideoTrackImpl()) {}
87 
88 rtc::scoped_refptr<webrtc::RtpSenderInterface>
AddTrackToConnection(rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track,rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection,const std::string & label)89 ClientHandler::AddTrackToConnection(
90     rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track,
91     rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection,
92     const std::string &label) {
93   if (!peer_connection) {
94     return nullptr;
95   }
96   // Send each track as part of a different stream with the label as id
97   auto err_or_sender =
98       peer_connection->AddTrack(track, {label} /* stream_id */);
99   if (!err_or_sender.ok()) {
100     LOG(ERROR) << "Failed to add track to the peer connection";
101     return nullptr;
102   }
103   return err_or_sender.MoveValue();
104 }
105 
AddDisplay(rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track,const std::string & label)106 bool ClientHandler::AddDisplay(
107     rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track,
108     const std::string &label) {
109   auto [it, inserted] = displays_.emplace(label, DisplayTrackAndSender{
110                                                      .track = video_track,
111                                                  });
112   auto sender =
113       AddTrackToConnection(video_track, controller_.peer_connection(), label);
114   if (sender) {
115     DisplayTrackAndSender &info = it->second;
116     info.sender = sender;
117   }
118   // Succeed if the peer connection is null or the track was added
119   return controller_.peer_connection() == nullptr || sender;
120 }
121 
RemoveDisplay(const std::string & label)122 bool ClientHandler::RemoveDisplay(const std::string &label) {
123   auto it = displays_.find(label);
124   if (it == displays_.end()) {
125     return false;
126   }
127 
128   if (controller_.peer_connection()) {
129     DisplayTrackAndSender &info = it->second;
130 
131     auto error = controller_.peer_connection()->RemoveTrackOrError(info.sender);
132     if (!error.ok()) {
133       LOG(ERROR) << "Failed to remove video track for display " << label << ": "
134                  << error.message();
135       return false;
136     }
137   }
138 
139   displays_.erase(it);
140   return true;
141 }
142 
AddAudio(rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track,const std::string & label)143 bool ClientHandler::AddAudio(
144     rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track,
145     const std::string &label) {
146   audio_streams_.emplace_back(audio_track, label);
147   auto peer_connection = controller_.peer_connection();
148   if (!peer_connection) {
149     return true;
150   }
151   return AddTrackToConnection(audio_track, controller_.peer_connection(), label)
152       .get();
153 }
154 
GetCameraStream()155 ClientVideoTrackInterface* ClientHandler::GetCameraStream() {
156   return camera_track_.get();
157 }
158 
SendMessage(const Json::Value & msg)159 Result<void> ClientHandler::SendMessage(const Json::Value &msg) {
160   send_to_client_(msg);
161   return {};
162 }
163 
164 Result<rtc::scoped_refptr<webrtc::PeerConnectionInterface>>
Build(webrtc::PeerConnectionObserver & observer,const std::vector<webrtc::PeerConnectionInterface::IceServer> & per_connection_servers)165 ClientHandler::Build(
166     webrtc::PeerConnectionObserver &observer,
167     const std::vector<webrtc::PeerConnectionInterface::IceServer>
168         &per_connection_servers) {
169   auto peer_connection =
170       CF_EXPECT(connection_builder_.Build(observer, per_connection_servers));
171 
172   // Re-add the video and audio tracks after the peer connection has been
173   // created
174   for (auto &[label, info] : displays_) {
175     info.sender =
176         CF_EXPECT(AddTrackToConnection(info.track, peer_connection, label).get());
177   }
178   // Add the audio tracks to the peer connection
179   for (auto &[audio_track, label] : audio_streams_) {
180     // Audio channels are never removed from the connection by the device, so
181     // it's ok to discard the returned sender here. The peer connection keeps
182     // track of it anyways.
183     CF_EXPECT(AddTrackToConnection(audio_track, peer_connection, label).get());
184   }
185 
186   // libwebrtc configures the video encoder with a start bitrate of just 300kbs
187   // which causes it to drop the first 4 frames it receives. Any value over 2Mbs
188   // will be capped at 2Mbs when passed to the encoder by the peer_connection
189   // object, so we pass the maximum possible value here.
190   webrtc::BitrateSettings bitrate_settings;
191   bitrate_settings.start_bitrate_bps = 2000000;  // 2Mbs
192   peer_connection->SetBitrate(bitrate_settings);
193 
194   // At least one data channel needs to be created on the side that creates the
195   // SDP offer (the device) for data channels to be enabled at all.
196   // This channel is meant to carry control commands from the client.
197   auto control_channel = peer_connection->CreateDataChannel(
198       kControlChannelLabel, nullptr /* config */);
199   CF_EXPECT(control_channel.get(), "Failed to create control data channel");
200 
201   data_channels_handler_.OnDataChannelOpen(control_channel);
202 
203   return peer_connection;
204 }
205 
HandleMessage(const Json::Value & message)206 void ClientHandler::HandleMessage(const Json::Value &message) {
207   controller_.HandleSignalingMessage(message);
208 }
209 
Close()210 void ClientHandler::Close() {
211   // We can't simply call peer_connection_->Close() here because this method
212   // could be called from one of the PeerConnectionObserver callbacks and that
213   // would lead to a deadlock (Close eventually tries to destroy an object that
214   // will then wait for the callback to return -> deadlock). Destroying the
215   // peer_connection_ has the same effect. The only alternative is to postpone
216   // that operation until after the callback returns.
217   on_connection_changed_cb_(false);
218 }
219 
OnConnectionStateChange(Result<webrtc::PeerConnectionInterface::PeerConnectionState> new_state)220 void ClientHandler::OnConnectionStateChange(
221     Result<webrtc::PeerConnectionInterface::PeerConnectionState> new_state) {
222   if (!new_state.ok()) {
223     LOG(ERROR) << "Connection error: " << new_state.error().FormatForEnv();
224     Close();
225     return;
226   }
227   switch (*new_state) {
228     case webrtc::PeerConnectionInterface::PeerConnectionState::kConnected:
229       LOG(VERBOSE) << "Client " << client_id_ << ": WebRTC connected";
230       observer_->OnConnected();
231       on_connection_changed_cb_(true);
232       break;
233     case webrtc::PeerConnectionInterface::PeerConnectionState::kDisconnected:
234       LOG(VERBOSE) << "Client " << client_id_ << ": Connection disconnected";
235       Close();
236       break;
237     case webrtc::PeerConnectionInterface::PeerConnectionState::kFailed:
238       LOG(ERROR) << "Client " << client_id_ << ": Connection failed";
239       Close();
240       break;
241     case webrtc::PeerConnectionInterface::PeerConnectionState::kClosed:
242       LOG(VERBOSE) << "Client " << client_id_ << ": Connection closed";
243       Close();
244       break;
245     case webrtc::PeerConnectionInterface::PeerConnectionState::kNew:
246       LOG(VERBOSE) << "Client " << client_id_ << ": Connection new";
247       break;
248     case webrtc::PeerConnectionInterface::PeerConnectionState::kConnecting:
249       LOG(VERBOSE) << "Client " << client_id_ << ": Connection started";
250       break;
251   }
252 }
253 
OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel)254 void ClientHandler::OnDataChannel(
255     rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) {
256   data_channels_handler_.OnDataChannelOpen(data_channel);
257 }
258 
OnTrack(rtc::scoped_refptr<webrtc::RtpTransceiverInterface> transceiver)259 void ClientHandler::OnTrack(
260     rtc::scoped_refptr<webrtc::RtpTransceiverInterface> transceiver) {
261   auto track = transceiver->receiver()->track();
262   if (track && track->kind() == webrtc::MediaStreamTrackInterface::kVideoKind) {
263     // It's ok to take the raw pointer here because we make sure to unset it
264     // when the track is removed
265     camera_track_->SetVideoTrack(
266         static_cast<webrtc::VideoTrackInterface *>(track.get()));
267   }
268 }
OnRemoveTrack(rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver)269 void ClientHandler::OnRemoveTrack(
270     rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver) {
271   auto track = receiver->track();
272   if (track && track->kind() == webrtc::MediaStreamTrackInterface::kVideoKind) {
273     // this only unsets if the track matches the one already in store
274     camera_track_->UnsetVideoTrack(
275         reinterpret_cast<webrtc::VideoTrackInterface *>(track.get()));
276   }
277 }
278 
279 }  // namespace webrtc_streaming
280 }  // namespace cuttlefish
281