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