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 #include "host/frontend/webrtc/display_handler.h"
18
19 #include <chrono>
20 #include <memory>
21
22 #include <drm/drm_fourcc.h>
23 #include <libyuv.h>
24
25 #include "host/frontend/webrtc/libdevice/streamer.h"
26 #include "host/libs/screen_connector/composition_manager.h"
27
28 namespace cuttlefish {
29
DisplayHandler(webrtc_streaming::Streamer & streamer,ScreenshotHandler & screenshot_handler,ScreenConnector & screen_connector,std::optional<std::unique_ptr<CompositionManager>> composition_manager)30 DisplayHandler::DisplayHandler(
31 webrtc_streaming::Streamer& streamer, ScreenshotHandler& screenshot_handler,
32 ScreenConnector& screen_connector,
33 std::optional<std::unique_ptr<CompositionManager>> composition_manager)
34 : composition_manager_(std::move(composition_manager)),
35 streamer_(streamer),
36 screenshot_handler_(screenshot_handler),
37 screen_connector_(screen_connector),
38 frame_repeater_([this]() { RepeatFramesPeriodically(); }) {
39 screen_connector_.SetCallback(GetScreenConnectorCallback());
__anon56ead1400202(const DisplayEvent& event) 40 screen_connector_.SetDisplayEventCallback([this](const DisplayEvent& event) {
41 std::visit(
42 [this](auto&& e) {
43 using T = std::decay_t<decltype(e)>;
44 if constexpr (std::is_same_v<DisplayCreatedEvent, T>) {
45 LOG(VERBOSE) << "Display:" << e.display_number << " created "
46 << " w:" << e.display_width
47 << " h:" << e.display_height;
48
49 const auto display_number = e.display_number;
50 const std::string display_id =
51 "display_" + std::to_string(e.display_number);
52 auto display = streamer_.AddDisplay(display_id, e.display_width,
53 e.display_height, 160, true);
54 if (!display) {
55 LOG(ERROR) << "Failed to create display.";
56 return;
57 }
58
59 std::lock_guard<std::mutex> lock(send_mutex_);
60 display_sinks_[display_number] = display;
61 if (composition_manager_.has_value()) {
62 composition_manager_.value()->OnDisplayCreated(e);
63 }
64 } else if constexpr (std::is_same_v<DisplayDestroyedEvent, T>) {
65 LOG(VERBOSE) << "Display:" << e.display_number << " destroyed.";
66
67 const auto display_number = e.display_number;
68 const auto display_id =
69 "display_" + std::to_string(e.display_number);
70 std::lock_guard<std::mutex> lock(send_mutex_);
71 display_sinks_.erase(display_number);
72 streamer_.RemoveDisplay(display_id);
73 } else {
74 static_assert("Unhandled display event.");
75 }
76 },
77 event);
78 });
79 }
80
~DisplayHandler()81 DisplayHandler::~DisplayHandler() {
82 {
83 std::lock_guard lock(repeater_state_mutex_);
84 repeater_state_ = RepeaterState::STOPPED;
85 repeater_state_condvar_.notify_one();
86 }
87 frame_repeater_.join();
88 }
89
90 DisplayHandler::GenerateProcessedFrameCallback
GetScreenConnectorCallback()91 DisplayHandler::GetScreenConnectorCallback() {
92 // only to tell the producer how to create a ProcessedFrame to cache into the
93 // queue
94 auto& composition_manager = composition_manager_;
95 DisplayHandler::GenerateProcessedFrameCallback callback =
96 [&composition_manager](
97 std::uint32_t display_number, std::uint32_t frame_width,
98 std::uint32_t frame_height, std::uint32_t frame_fourcc_format,
99 std::uint32_t frame_stride_bytes, std::uint8_t* frame_pixels,
100 WebRtcScProcessedFrame& processed_frame) {
101 processed_frame.display_number_ = display_number;
102 processed_frame.buf_ =
103 std::make_unique<CvdVideoFrameBuffer>(frame_width, frame_height);
104 if (composition_manager.has_value()) {
105 composition_manager.value()->OnFrame(
106 display_number, frame_width, frame_height, frame_fourcc_format,
107 frame_stride_bytes, frame_pixels);
108 }
109 if (frame_fourcc_format == DRM_FORMAT_ARGB8888 ||
110 frame_fourcc_format == DRM_FORMAT_XRGB8888) {
111 libyuv::ARGBToI420(
112 frame_pixels, frame_stride_bytes, processed_frame.buf_->DataY(),
113 processed_frame.buf_->StrideY(), processed_frame.buf_->DataU(),
114 processed_frame.buf_->StrideU(), processed_frame.buf_->DataV(),
115 processed_frame.buf_->StrideV(), frame_width, frame_height);
116 processed_frame.is_success_ = true;
117 } else if (frame_fourcc_format == DRM_FORMAT_ABGR8888 ||
118 frame_fourcc_format == DRM_FORMAT_XBGR8888) {
119 libyuv::ABGRToI420(
120 frame_pixels, frame_stride_bytes, processed_frame.buf_->DataY(),
121 processed_frame.buf_->StrideY(), processed_frame.buf_->DataU(),
122 processed_frame.buf_->StrideU(), processed_frame.buf_->DataV(),
123 processed_frame.buf_->StrideV(), frame_width, frame_height);
124 processed_frame.is_success_ = true;
125 } else {
126 processed_frame.is_success_ = false;
127 }
128 };
129 return callback;
130 }
131
Loop()132 [[noreturn]] void DisplayHandler::Loop() {
133 for (;;) {
134 auto processed_frame = screen_connector_.OnNextFrame();
135
136 std::shared_ptr<CvdVideoFrameBuffer> buffer =
137 std::move(processed_frame.buf_);
138
139 const uint32_t display_number = processed_frame.display_number_;
140 {
141 std::lock_guard<std::mutex> lock(last_buffers_mutex_);
142 display_last_buffers_[display_number] =
143 std::make_shared<BufferInfo>(BufferInfo{
144 .last_sent_time_stamp = std::chrono::system_clock::now(),
145 .buffer =
146 std::static_pointer_cast<webrtc_streaming::VideoFrameBuffer>(
147 buffer),
148 });
149 }
150 if (processed_frame.is_success_) {
151 SendLastFrame(display_number);
152 }
153 }
154 }
155
SendLastFrame(std::optional<uint32_t> display_number)156 void DisplayHandler::SendLastFrame(std::optional<uint32_t> display_number) {
157 std::map<uint32_t, std::shared_ptr<BufferInfo>> buffers;
158 {
159 std::lock_guard<std::mutex> lock(last_buffers_mutex_);
160 if (display_number) {
161 // Resend the last buffer for a single display.
162 auto last_buffer_it = display_last_buffers_.find(*display_number);
163 if (last_buffer_it == display_last_buffers_.end()) {
164 return;
165 }
166 auto& last_buffer_info = last_buffer_it->second;
167 if (!last_buffer_info) {
168 return;
169 }
170 auto& last_buffer = last_buffer_info->buffer;
171 if (!last_buffer) {
172 return;
173 }
174 buffers[*display_number] = last_buffer_info;
175 } else {
176 // Resend the last buffer for all displays.
177 buffers = display_last_buffers_;
178 }
179 }
180 if (buffers.empty()) {
181 // If a connection request arrives before the first frame is available don't
182 // send any frame.
183 return;
184 }
185 SendBuffers(buffers);
186 }
187
SendBuffers(std::map<uint32_t,std::shared_ptr<BufferInfo>> buffers)188 void DisplayHandler::SendBuffers(
189 std::map<uint32_t, std::shared_ptr<BufferInfo>> buffers) {
190 // SendBuffers can be called from multiple threads simultaneously, locking
191 // here avoids injecting frames with the timestamps in the wrong order and
192 // protects writing the BufferInfo timestamps.
193 std::lock_guard<std::mutex> lock(send_mutex_);
194 auto time_stamp = std::chrono::system_clock::now();
195 int64_t time_stamp_since_epoch =
196 std::chrono::duration_cast<std::chrono::microseconds>(
197 time_stamp.time_since_epoch())
198 .count();
199
200 for (const auto& [display_number, buffer_info] : buffers) {
201 screenshot_handler_.OnFrame(display_number, buffer_info->buffer);
202
203 auto it = display_sinks_.find(display_number);
204 if (it != display_sinks_.end()) {
205 it->second->OnFrame(buffer_info->buffer, time_stamp_since_epoch);
206 buffer_info->last_sent_time_stamp = time_stamp;
207 }
208 }
209 }
210
RepeatFramesPeriodically()211 void DisplayHandler::RepeatFramesPeriodically() {
212 // SendBuffers can be called from multiple threads simultaneously, locking
213 // here avoids injecting frames with the timestamps in the wrong order and
214 // protects writing the BufferInfo timestamps.
215 const std::chrono::milliseconds kRepeatingInterval(20);
216 auto next_send = std::chrono::system_clock::now() + kRepeatingInterval;
217 while (true) {
218 {
219 std::unique_lock lock(repeater_state_mutex_);
220 if (repeater_state_ == RepeaterState::STOPPED) {
221 break;
222 }
223 if (num_active_clients_ > 0) {
224 bool stopped =
225 repeater_state_condvar_.wait_until(lock, next_send, [this]() {
226 // Wait until time interval completes or asked to stop. Continue
227 // waiting even if the number of active clients drops to 0.
228 return repeater_state_ == RepeaterState::STOPPED;
229 });
230 if (stopped || num_active_clients_ == 0) {
231 continue;
232 }
233 } else {
234 repeater_state_condvar_.wait(lock, [this]() {
235 // Wait until asked to stop or have clients
236 return repeater_state_ == RepeaterState::STOPPED ||
237 num_active_clients_ > 0;
238 });
239 // Need to break the loop if stopped or wait for the interval if have
240 // clients.
241 continue;
242 }
243 }
244
245 std::map<uint32_t, std::shared_ptr<BufferInfo>> buffers;
246 {
247 std::lock_guard last_buffers_lock(last_buffers_mutex_);
248 auto time_stamp = std::chrono::system_clock::now();
249
250 for (auto& [display_number, buffer_info] : display_last_buffers_) {
251 if (time_stamp >
252 buffer_info->last_sent_time_stamp + kRepeatingInterval) {
253 if (composition_manager_.has_value()) {
254 composition_manager_.value()->ComposeFrame(
255 display_number, std::static_pointer_cast<CvdVideoFrameBuffer>(
256 buffer_info->buffer));
257 }
258 buffers[display_number] = buffer_info;
259 }
260 }
261 }
262 SendBuffers(buffers);
263 {
264 std::lock_guard last_buffers_lock(last_buffers_mutex_);
265 for (const auto& [_, buffer_info] : display_last_buffers_) {
266 next_send = std::min(
267 next_send, buffer_info->last_sent_time_stamp + kRepeatingInterval);
268 }
269 }
270 }
271 }
272
AddDisplayClient()273 void DisplayHandler::AddDisplayClient() {
274 std::lock_guard lock(repeater_state_mutex_);
275 if (++num_active_clients_ == 1) {
276 repeater_state_condvar_.notify_one();
277 };
278 }
279
RemoveDisplayClient()280 void DisplayHandler::RemoveDisplayClient() {
281 std::lock_guard lock(repeater_state_mutex_);
282 --num_active_clients_;
283 }
284
285 } // namespace cuttlefish
286