1 /* 2 * Copyright (C) 2019 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 #pragma once 18 19 #include <cstdint> 20 #include <functional> 21 #include <memory> 22 #include <mutex> 23 #include <optional> 24 #include <string> 25 #include <string_view> 26 #include <thread> 27 #include <type_traits> 28 #include <unordered_set> 29 30 #include <android-base/logging.h> 31 #include <fruit/fruit.h> 32 33 #include "common/libs/confui/confui.h" 34 #include "common/libs/fs/shared_fd.h" 35 #include "common/libs/utils/contains.h" 36 #include "common/libs/utils/size_utils.h" 37 #include "host/libs/config/cuttlefish_config.h" 38 #include "host/libs/confui/host_mode_ctrl.h" 39 #include "host/libs/confui/host_utils.h" 40 #include "host/libs/screen_connector/screen_connector_common.h" 41 #include "host/libs/screen_connector/screen_connector_multiplexer.h" 42 #include "host/libs/screen_connector/screen_connector_queue.h" 43 #include "host/libs/screen_connector/wayland_screen_connector.h" 44 45 namespace cuttlefish { 46 47 template <typename ProcessedFrameType> 48 class ScreenConnector : public ScreenConnectorInfo, 49 public ScreenConnectorFrameRenderer { 50 public: 51 static_assert(cuttlefish::is_movable<ProcessedFrameType>::value, 52 "ProcessedFrameType should be std::move-able."); 53 static_assert(std::is_base_of<ScreenConnectorFrameInfo, ProcessedFrameType>::value, 54 "ProcessedFrameType should inherit ScreenConnectorFrameInfo"); 55 56 using FrameMultiplexer = ScreenConnectorInputMultiplexer<ProcessedFrameType>; 57 INJECT(ScreenConnector (WaylandScreenConnector & sc_android_src,HostModeCtrl & host_mode_ctrl))58 INJECT(ScreenConnector(WaylandScreenConnector& sc_android_src, 59 HostModeCtrl& host_mode_ctrl)) 60 : sc_android_src_(sc_android_src), 61 host_mode_ctrl_{host_mode_ctrl}, 62 on_next_frame_cnt_{0}, 63 render_confui_cnt_{0}, 64 sc_frame_multiplexer_{host_mode_ctrl_} { 65 auto config = cuttlefish::CuttlefishConfig::Get(); 66 if (!config) { 67 LOG(FATAL) << "CuttlefishConfig is not available."; 68 } 69 auto instance = config->ForDefaultInstance(); 70 std::unordered_set<std::string_view> valid_gpu_modes{ 71 cuttlefish::kGpuModeDrmVirgl, cuttlefish::kGpuModeGfxstream, 72 cuttlefish::kGpuModeGfxstreamGuestAngle, 73 cuttlefish::kGpuModeGuestSwiftshader}; 74 if (!Contains(valid_gpu_modes, instance.gpu_mode())) { 75 LOG(FATAL) << "Invalid gpu mode: " << instance.gpu_mode(); 76 } 77 } 78 79 /** 80 * This is the type of the callback function WebRTC is supposed to provide 81 * ScreenConnector with. 82 * 83 * The callback function is how a raw bytes frame should be processed for 84 * WebRTC 85 * 86 */ 87 using GenerateProcessedFrameCallback = std::function<void( 88 std::uint32_t /*display_number*/, std::uint32_t /*frame_width*/, 89 std::uint32_t /*frame_height*/, std::uint32_t /*frame_stride_bytes*/, 90 std::uint8_t* /*frame_bytes*/, 91 /* ScImpl enqueues this type into the Q */ 92 ProcessedFrameType& msg)>; 93 94 virtual ~ScreenConnector() = default; 95 96 /** 97 * set the callback function to be eventually used by Wayland-Based 98 * Connector 99 * 100 */ SetCallback(GenerateProcessedFrameCallback && frame_callback)101 void SetCallback(GenerateProcessedFrameCallback&& frame_callback) { 102 std::lock_guard<std::mutex> lock(streamer_callback_mutex_); 103 callback_from_streamer_ = std::move(frame_callback); 104 streamer_callback_set_cv_.notify_all(); 105 106 sc_android_src_.SetFrameCallback( 107 [this](std::uint32_t display_number, std::uint32_t frame_w, 108 std::uint32_t frame_h, std::uint32_t frame_stride_bytes, 109 std::uint8_t* frame_bytes) { 110 const bool is_confui_mode = host_mode_ctrl_.IsConfirmatioUiMode(); 111 if (is_confui_mode) { 112 return; 113 } 114 115 ProcessedFrameType processed_frame; 116 117 { 118 std::lock_guard<std::mutex> lock(streamer_callback_mutex_); 119 callback_from_streamer_(display_number, frame_w, frame_h, 120 frame_stride_bytes, frame_bytes, 121 processed_frame); 122 } 123 124 sc_frame_multiplexer_.PushToAndroidQueue(std::move(processed_frame)); 125 }); 126 } 127 IsCallbackSet()128 bool IsCallbackSet() const override { 129 if (callback_from_streamer_) { 130 return true; 131 } 132 return false; 133 } 134 SetDisplayEventCallback(DisplayEventCallback event_callback)135 void SetDisplayEventCallback(DisplayEventCallback event_callback) { 136 sc_android_src_.SetDisplayEventCallback(std::move(event_callback)); 137 } 138 139 /* returns the processed frame that also includes meta-info such as success/fail 140 * and display number from the guest 141 * 142 * NOTE THAT THIS IS THE ONLY CONSUMER OF THE TWO QUEUES 143 */ OnNextFrame()144 ProcessedFrameType OnNextFrame() { return sc_frame_multiplexer_.Pop(); } 145 146 /** 147 * ConfUi calls this when it has frames to render 148 * 149 * This won't be called if not by Confirmation UI. This won't affect rendering 150 * Android guest frames if Confirmation UI HAL is not active. 151 * 152 */ RenderConfirmationUi(std::uint32_t display_number,std::uint32_t frame_width,std::uint32_t frame_height,std::uint32_t frame_stride_bytes,std::uint8_t * frame_bytes)153 bool RenderConfirmationUi(std::uint32_t display_number, 154 std::uint32_t frame_width, 155 std::uint32_t frame_height, 156 std::uint32_t frame_stride_bytes, 157 std::uint8_t* frame_bytes) override { 158 render_confui_cnt_++; 159 // wait callback is not set, the streamer is not ready 160 // return with LOG(ERROR) 161 if (!IsCallbackSet()) { 162 ConfUiLog(ERROR) << "callback function to process frames is not yet set"; 163 return false; 164 } 165 ProcessedFrameType processed_frame; 166 auto this_thread_name = cuttlefish::confui::thread::GetName(); 167 ConfUiLog(DEBUG) << this_thread_name 168 << "is sending a #" + std::to_string(render_confui_cnt_) 169 << "Conf UI frame"; 170 callback_from_streamer_(display_number, frame_width, frame_height, 171 frame_stride_bytes, frame_bytes, processed_frame); 172 // now add processed_frame to the queue 173 sc_frame_multiplexer_.PushToConfUiQueue(std::move(processed_frame)); 174 return true; 175 } 176 177 protected: 178 ScreenConnector() = delete; 179 180 private: 181 WaylandScreenConnector& sc_android_src_; 182 HostModeCtrl& host_mode_ctrl_; 183 unsigned long long int on_next_frame_cnt_; 184 unsigned long long int render_confui_cnt_; 185 /** 186 * internally has conf ui & android queues. 187 * 188 * multiplexting the two input queues, so the consumer gets one input 189 * at a time from the right queue 190 */ 191 FrameMultiplexer sc_frame_multiplexer_; 192 GenerateProcessedFrameCallback callback_from_streamer_; 193 std::mutex streamer_callback_mutex_; // mutex to set & read callback_from_streamer_ 194 std::condition_variable streamer_callback_set_cv_; 195 }; 196 197 } // namespace cuttlefish 198