aboutsummaryrefslogtreecommitdiff
path: root/host/libs/screen_connector/screen_connector.h
blob: bc56cedf6c117abf3c997ea09a8c55631c3d640d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <cstdint>
#include <functional>
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include <string_view>
#include <thread>
#include <type_traits>
#include <unordered_set>

#include <android-base/logging.h>
#include <fruit/fruit.h>

#include "common/libs/confui/confui.h"
#include "common/libs/fs/shared_fd.h"
#include "common/libs/utils/contains.h"
#include "common/libs/utils/size_utils.h"
#include "host/libs/config/cuttlefish_config.h"
#include "host/libs/confui/host_mode_ctrl.h"
#include "host/libs/confui/host_utils.h"
#include "host/libs/screen_connector/screen_connector_common.h"
#include "host/libs/screen_connector/screen_connector_multiplexer.h"
#include "host/libs/screen_connector/screen_connector_queue.h"
#include "host/libs/screen_connector/wayland_screen_connector.h"

namespace cuttlefish {

template <typename ProcessedFrameType>
class ScreenConnector : public ScreenConnectorInfo,
                        public ScreenConnectorFrameRenderer {
 public:
  static_assert(cuttlefish::is_movable<ProcessedFrameType>::value,
                "ProcessedFrameType should be std::move-able.");
  static_assert(std::is_base_of<ScreenConnectorFrameInfo, ProcessedFrameType>::value,
                "ProcessedFrameType should inherit ScreenConnectorFrameInfo");

  using FrameMultiplexer = ScreenConnectorInputMultiplexer<ProcessedFrameType>;

  INJECT(ScreenConnector(WaylandScreenConnector& sc_android_src,
                         HostModeCtrl& host_mode_ctrl))
      : sc_android_src_(sc_android_src),
        host_mode_ctrl_{host_mode_ctrl},
        on_next_frame_cnt_{0},
        render_confui_cnt_{0},
        sc_frame_multiplexer_{host_mode_ctrl_} {
    auto config = cuttlefish::CuttlefishConfig::Get();
    if (!config) {
      LOG(FATAL) << "CuttlefishConfig is not available.";
    }
    auto instance = config->ForDefaultInstance();
    std::unordered_set<std::string_view> valid_gpu_modes{
        cuttlefish::kGpuModeCustom,
        cuttlefish::kGpuModeDrmVirgl,
        cuttlefish::kGpuModeGfxstream,
        cuttlefish::kGpuModeGfxstreamGuestAngle,
        cuttlefish::kGpuModeGfxstreamGuestAngleHostSwiftShader,
        cuttlefish::kGpuModeGuestSwiftshader};
    if (!Contains(valid_gpu_modes, instance.gpu_mode())) {
      LOG(FATAL) << "Invalid gpu mode: " << instance.gpu_mode();
    }
  }

  /**
   * This is the type of the callback function WebRTC is supposed to provide
   * ScreenConnector with.
   *
   * The callback function is how a raw bytes frame should be processed for
   * WebRTC
   *
   */
  using GenerateProcessedFrameCallback = std::function<void(
      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*/,
      /* ScImpl enqueues this type into the Q */
      ProcessedFrameType& msg)>;

  virtual ~ScreenConnector() = default;

  /**
   * set the callback function to be eventually used by Wayland-Based
   * Connector
   *
   */
  void SetCallback(GenerateProcessedFrameCallback&& frame_callback) {
    std::lock_guard<std::mutex> lock(streamer_callback_mutex_);
    callback_from_streamer_ = std::move(frame_callback);
    streamer_callback_set_cv_.notify_all();

    sc_android_src_.SetFrameCallback(
        [this](std::uint32_t display_number, std::uint32_t frame_w,
               std::uint32_t frame_h, std::uint32_t frame_stride_bytes,
               std::uint8_t* frame_bytes) {
          const bool is_confui_mode = host_mode_ctrl_.IsConfirmatioUiMode();
          if (is_confui_mode) {
            return;
          }

          ProcessedFrameType processed_frame;

          {
            std::lock_guard<std::mutex> lock(streamer_callback_mutex_);
            callback_from_streamer_(display_number, frame_w, frame_h,
                                    frame_stride_bytes, frame_bytes,
                                    processed_frame);
          }

          sc_frame_multiplexer_.PushToAndroidQueue(std::move(processed_frame));
        });
  }

  bool IsCallbackSet() const override {
    if (callback_from_streamer_) {
      return true;
    }
    return false;
  }

  void SetDisplayEventCallback(DisplayEventCallback event_callback) {
    sc_android_src_.SetDisplayEventCallback(std::move(event_callback));
  }

  /* returns the processed frame that also includes meta-info such as success/fail
   * and display number from the guest
   *
   * NOTE THAT THIS IS THE ONLY CONSUMER OF THE TWO QUEUES
   */
  ProcessedFrameType OnNextFrame() { return sc_frame_multiplexer_.Pop(); }

  /**
   * ConfUi calls this when it has frames to render
   *
   * This won't be called if not by Confirmation UI. This won't affect rendering
   * Android guest frames if Confirmation UI HAL is not active.
   *
   */
  bool 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) override {
    render_confui_cnt_++;
    // wait callback is not set, the streamer is not ready
    // return with LOG(ERROR)
    if (!IsCallbackSet()) {
      ConfUiLog(ERROR) << "callback function to process frames is not yet set";
      return false;
    }
    ProcessedFrameType processed_frame;
    auto this_thread_name = cuttlefish::confui::thread::GetName();
    ConfUiLog(DEBUG) << this_thread_name
                     << "is sending a #" + std::to_string(render_confui_cnt_)
                     << "Conf UI frame";
    callback_from_streamer_(display_number, frame_width, frame_height,
                            frame_stride_bytes, frame_bytes, processed_frame);
    // now add processed_frame to the queue
    sc_frame_multiplexer_.PushToConfUiQueue(std::move(processed_frame));
    return true;
  }

 protected:
  ScreenConnector() = delete;

 private:
  WaylandScreenConnector& sc_android_src_;
  HostModeCtrl& host_mode_ctrl_;
  unsigned long long int on_next_frame_cnt_;
  unsigned long long int render_confui_cnt_;
  /**
   * internally has conf ui & android queues.
   *
   * multiplexting the two input queues, so the consumer gets one input
   * at a time from the right queue
   */
  FrameMultiplexer sc_frame_multiplexer_;
  GenerateProcessedFrameCallback callback_from_streamer_;
  std::mutex streamer_callback_mutex_; // mutex to set & read callback_from_streamer_
  std::condition_variable streamer_callback_set_cv_;
};

}  // namespace cuttlefish