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