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/connection_observer.h"
18
19 #include <linux/input.h>
20
21 #include <thread>
22 #include <vector>
23
24 #include <android-base/logging.h>
25 #include <gflags/gflags.h>
26
27 #include "common/libs/fs/shared_buf.h"
28 #include "host/frontend/webrtc/adb_handler.h"
29 #include "host/libs/config/cuttlefish_config.h"
30
31 DECLARE_bool(write_virtio_input);
32
33 namespace cuttlefish {
34
35 // TODO (b/147511234): de-dup this from vnc server and here
36 struct virtio_input_event {
37 uint16_t type;
38 uint16_t code;
39 int32_t value;
40 };
41
42 struct InputEventBuffer {
43 virtual ~InputEventBuffer() = default;
44 virtual void AddEvent(uint16_t type, uint16_t code, int32_t value) = 0;
45 virtual size_t size() const = 0;
46 virtual const void *data() const = 0;
47 };
48
49 template <typename T>
50 struct InputEventBufferImpl : public InputEventBuffer {
InputEventBufferImplcuttlefish::InputEventBufferImpl51 InputEventBufferImpl() {
52 buffer_.reserve(6); // 6 is usually enough
53 }
AddEventcuttlefish::InputEventBufferImpl54 void AddEvent(uint16_t type, uint16_t code, int32_t value) override {
55 buffer_.push_back({.type = type, .code = code, .value = value});
56 }
datacuttlefish::InputEventBufferImpl57 T *data() { return buffer_.data(); }
datacuttlefish::InputEventBufferImpl58 const void *data() const override { return buffer_.data(); }
sizecuttlefish::InputEventBufferImpl59 std::size_t size() const override { return buffer_.size() * sizeof(T); }
60
61 private:
62 std::vector<T> buffer_;
63 };
64
GetEventBuffer()65 std::unique_ptr<InputEventBuffer> GetEventBuffer() {
66 if (FLAGS_write_virtio_input) {
67 return std::unique_ptr<InputEventBuffer>(
68 new InputEventBufferImpl<virtio_input_event>());
69 } else {
70 return std::unique_ptr<InputEventBuffer>(
71 new InputEventBufferImpl<input_event>());
72 }
73 }
74
75 class ConnectionObserverImpl
76 : public cuttlefish::webrtc_streaming::ConnectionObserver {
77 public:
ConnectionObserverImpl(cuttlefish::SharedFD touch_fd,cuttlefish::SharedFD keyboard_fd,std::weak_ptr<DisplayHandler> display_handler,std::shared_ptr<RunLoop> run_loop)78 ConnectionObserverImpl(cuttlefish::SharedFD touch_fd,
79 cuttlefish::SharedFD keyboard_fd,
80 std::weak_ptr<DisplayHandler> display_handler,
81 std::shared_ptr<RunLoop> run_loop)
82 : touch_client_(touch_fd),
83 keyboard_client_(keyboard_fd),
84 weak_display_handler_(display_handler),
85 run_loop_(run_loop) {}
86 virtual ~ConnectionObserverImpl() = default;
87
OnConnected()88 void OnConnected() override {
89 auto display_handler = weak_display_handler_.lock();
90 if (display_handler) {
91 // A long time may pass before the next frame comes up from the guest.
92 // Send the last one to avoid showing a black screen to the user during
93 // that time.
94 display_handler->SendLastFrame();
95 }
96 }
OnTouchEvent(const std::string &,int x,int y,bool down)97 void OnTouchEvent(const std::string & /*display_label*/, int x, int y,
98 bool down) override {
99 auto buffer = GetEventBuffer();
100 if (!buffer) {
101 LOG(ERROR) << "Failed to allocate event buffer";
102 return;
103 }
104 buffer->AddEvent(EV_ABS, ABS_X, x);
105 buffer->AddEvent(EV_ABS, ABS_Y, y);
106 buffer->AddEvent(EV_KEY, BTN_TOUCH, down);
107 buffer->AddEvent(EV_SYN, 0, 0);
108 cuttlefish::WriteAll(touch_client_,
109 reinterpret_cast<const char *>(buffer->data()),
110 buffer->size());
111 }
OnMultiTouchEvent(const std::string & display_label,int,int,int x,int y,bool initialDown)112 void OnMultiTouchEvent(const std::string &display_label, int /*id*/,
113 int /*slot*/, int x, int y,
114 bool initialDown) override {
115 OnTouchEvent(display_label, x, y, initialDown);
116 }
OnKeyboardEvent(uint16_t code,bool down)117 void OnKeyboardEvent(uint16_t code, bool down) override {
118 auto buffer = GetEventBuffer();
119 if (!buffer) {
120 LOG(ERROR) << "Failed to allocate event buffer";
121 return;
122 }
123 buffer->AddEvent(EV_KEY, code, down);
124 buffer->AddEvent(EV_SYN, 0, 0);
125 cuttlefish::WriteAll(keyboard_client_,
126 reinterpret_cast<const char *>(buffer->data()),
127 buffer->size());
128 }
OnAdbChannelOpen(std::function<bool (const uint8_t *,size_t)> adb_message_sender)129 void OnAdbChannelOpen(std::function<bool(const uint8_t *, size_t)>
130 adb_message_sender) override {
131 LOG(VERBOSE) << "Adb Channel open";
132 adb_handler_.reset(new cuttlefish::webrtc_streaming::AdbHandler(
133 run_loop_,
134 cuttlefish::CuttlefishConfig::Get()
135 ->ForDefaultInstance()
136 .adb_ip_and_port(),
137 adb_message_sender));
138 adb_handler_->run();
139 }
OnAdbMessage(const uint8_t * msg,size_t size)140 void OnAdbMessage(const uint8_t *msg, size_t size) override {
141 adb_handler_->handleMessage(msg, size);
142 }
143
144 private:
145 cuttlefish::SharedFD touch_client_;
146 cuttlefish::SharedFD keyboard_client_;
147 std::shared_ptr<cuttlefish::webrtc_streaming::AdbHandler> adb_handler_;
148 std::weak_ptr<DisplayHandler> weak_display_handler_;
149 std::shared_ptr<RunLoop> run_loop_;
150 };
151
CfConnectionObserverFactory(cuttlefish::SharedFD touch_fd,cuttlefish::SharedFD keyboard_fd)152 CfConnectionObserverFactory::CfConnectionObserverFactory(
153 cuttlefish::SharedFD touch_fd, cuttlefish::SharedFD keyboard_fd)
154 : touch_fd_(touch_fd),
155 keyboard_fd_(keyboard_fd),
156 run_loop_(RunLoop::main()),
157 run_loop_thread_([this]() { run_loop_->run(); }) {}
158
159 std::shared_ptr<cuttlefish::webrtc_streaming::ConnectionObserver>
CreateObserver()160 CfConnectionObserverFactory::CreateObserver() {
161 return std::shared_ptr<cuttlefish::webrtc_streaming::ConnectionObserver>(
162 new ConnectionObserverImpl(touch_fd_, keyboard_fd_, weak_display_handler_,
163 run_loop_));
164 }
165
SetDisplayHandler(std::weak_ptr<DisplayHandler> display_handler)166 void CfConnectionObserverFactory::SetDisplayHandler(
167 std::weak_ptr<DisplayHandler> display_handler) {
168 weak_display_handler_ = display_handler;
169 }
170 } // namespace cuttlefish
171