android-emulator-webrtc 1.0.18 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +93 -204
- package/dist/components/emulator/emulator.d.ts +64 -0
- package/dist/components/emulator/emulator.js +161 -173
- package/dist/components/emulator/net/emulator_status.d.ts +45 -0
- package/dist/components/emulator/net/emulator_status.js +35 -42
- package/dist/components/emulator/net/logcat.js +37 -54
- package/dist/components/emulator/net/logger.d.ts +7 -0
- package/dist/components/emulator/net/logger.js +20 -0
- package/dist/components/emulator/net/ws_jsep_protocol_driver.d.ts +213 -0
- package/dist/components/emulator/net/ws_jsep_protocol_driver.js +640 -0
- package/dist/components/emulator/views/event_handler.d.ts +37 -0
- package/dist/components/emulator/views/event_handler.js +274 -260
- package/dist/components/emulator/views/webrtc_view.d.ts +27 -0
- package/dist/components/emulator/views/webrtc_view.js +42 -20
- package/dist/index.d.ts +8 -0
- package/dist/index.js +0 -7
- package/dist/proto/emulator_controller_pb.d.ts +1 -0
- package/dist/proto/emulator_controller_pb.js +146 -287
- package/dist/src/components/emulator/emulator.d.ts +64 -0
- package/dist/src/components/emulator/net/emulator_status.d.ts +45 -0
- package/dist/src/components/emulator/net/logger.d.ts +7 -0
- package/dist/src/components/emulator/net/ws_jsep_protocol_driver.d.ts +213 -0
- package/dist/src/components/emulator/views/event_handler.d.ts +37 -0
- package/dist/src/components/emulator/views/webrtc_view.d.ts +27 -0
- package/dist/src/index.d.ts +8 -0
- package/dist/src/proto/emulator_controller_pb.d.ts +1 -0
- package/package.json +17 -17
- package/proto/emulator_controller.proto +746 -181
- package/.vscode/launch.json +0 -21
- package/.vscode/settings.json +0 -3
- package/CONTRIBUTING.md +0 -28
- package/Makefile +0 -123
- package/android-emulator-webrtc.code-workspace +0 -7
- package/api_descriptor.pb +0 -0
- package/babel.config.js +0 -16
- package/cloudbuild.yaml +0 -41
- package/cloudbuilders/.gcloudignore +0 -1
- package/cloudbuilders/Dockerfile +0 -20
- package/cloudbuilders/README.md +0 -29
- package/cloudbuilders/cloudbuild.yaml +0 -19
- package/dist/components/emulator/net/jsep_protocol_driver.js +0 -365
- package/dist/components/emulator/views/simple_png_view.js +0 -110
- package/dist/proto/emulator_controller_grpc_web_pb.js +0 -1601
- package/dist/proto/emulator_web_client.js +0 -176
- package/dist/proto/rtc_service_grpc_web_pb.js +0 -231
- package/dist/proto/rtc_service_pb.js +0 -338
- package/emulator/index.js +0 -1
- package/eslint_prefix.py +0 -37
- package/gen_md_doc.js +0 -40
- package/npmrc.enc +0 -0
- package/proto/rtc_service.proto +0 -117
- package/protoc-plugin/Makefile +0 -31
- package/protoc-plugin/grpc_generator.cc +0 -1755
- package/src/components/emulator/emulator.js +0 -217
- package/src/components/emulator/net/emulator_status.js +0 -94
- package/src/components/emulator/net/jsep_protocol_driver.js +0 -364
- package/src/components/emulator/net/logcat.js +0 -155
- package/src/components/emulator/views/event_handler.js +0 -268
- package/src/components/emulator/views/simple_png_view.js +0 -105
- package/src/components/emulator/views/webrtc_view.js +0 -142
- package/src/index.js +0 -20
- package/src/proto/emulator_web_client.js +0 -140
- package/test/cloudbuild.yaml +0 -41
- package/test/emulator.test.js +0 -125
- package/test/event_handler.test.js +0 -91
- package/test/fake_events.js +0 -50
- package/test/jsep_protocol_driver.test.js +0 -228
- package/test/simple_png_view.test.js +0 -145
- package/test/touch_event_handler.test.js +0 -118
|
@@ -9,8 +9,6 @@ var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/creat
|
|
|
9
9
|
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
10
10
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
11
11
|
var _events = require("events");
|
|
12
|
-
require("../../../proto/emulator_controller_pb");
|
|
13
|
-
var _emulator_web_client = require("../../../proto/emulator_web_client");
|
|
14
12
|
/*
|
|
15
13
|
* Copyright 2019 The Android Open Source Project
|
|
16
14
|
*
|
|
@@ -29,7 +27,7 @@ var _emulator_web_client = require("../../../proto/emulator_web_client");
|
|
|
29
27
|
/**
|
|
30
28
|
* Observe the logcat stream from the emulator.
|
|
31
29
|
*
|
|
32
|
-
* Streaming is done by
|
|
30
|
+
* Streaming is done by polling the emulator REST endpoint.
|
|
33
31
|
*
|
|
34
32
|
* It will send out the following events:
|
|
35
33
|
*
|
|
@@ -46,10 +44,10 @@ var Logcat = /*#__PURE__*/(0, _createClass2["default"])(
|
|
|
46
44
|
* - `unauthorized()` a function that gets called when a 401 was received.
|
|
47
45
|
*
|
|
48
46
|
* @constructor
|
|
49
|
-
* @param {
|
|
50
|
-
* @param {object} auth
|
|
47
|
+
* @param {string} logcatUrl Full REST URL to the logcat endpoint.
|
|
48
|
+
* @param {object} auth Authentication helper.
|
|
51
49
|
*/
|
|
52
|
-
function Logcat(
|
|
50
|
+
function Logcat(logcatUrl, auth) {
|
|
53
51
|
var _this = this;
|
|
54
52
|
(0, _classCallCheck2["default"])(this, Logcat);
|
|
55
53
|
/**
|
|
@@ -78,9 +76,6 @@ function Logcat(uriOrEmulator, auth) {
|
|
|
78
76
|
* @memberof Logcat
|
|
79
77
|
*/
|
|
80
78
|
(0, _defineProperty2["default"])(this, "stop", function () {
|
|
81
|
-
if (_this.stream) {
|
|
82
|
-
_this.stream.cancel();
|
|
83
|
-
}
|
|
84
79
|
if (_this.timerID) {
|
|
85
80
|
clearInterval(_this.timerID);
|
|
86
81
|
_this.timerID = null;
|
|
@@ -89,70 +84,58 @@ function Logcat(uriOrEmulator, auth) {
|
|
|
89
84
|
});
|
|
90
85
|
(0, _defineProperty2["default"])(this, "pollStream", function () {
|
|
91
86
|
var self = _this;
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
87
|
+
var url = new URL(_this.logcatUrl);
|
|
88
|
+
url.searchParams.append("start", _this.offset);
|
|
89
|
+
var headers = {
|
|
90
|
+
"Accept": "application/json"
|
|
91
|
+
};
|
|
92
|
+
if (_this.auth && _this.auth.authHeader) {
|
|
93
|
+
Object.assign(headers, _this.auth.authHeader());
|
|
94
|
+
}
|
|
95
|
+
fetch(url.toString(), {
|
|
96
|
+
headers: headers
|
|
97
|
+
}).then(function (res) {
|
|
98
|
+
if (res.status === 401 && _this.auth && _this.auth.unauthorized) {
|
|
99
|
+
_this.auth.unauthorized();
|
|
98
100
|
}
|
|
99
|
-
if (
|
|
100
|
-
|
|
101
|
-
if (nextOffset > self.offset) {
|
|
102
|
-
self.offset = response.getNext();
|
|
103
|
-
self.events.emit("data", response.getContents());
|
|
104
|
-
}
|
|
101
|
+
if (!res.ok) {
|
|
102
|
+
throw new Error("HTTP error " + res.status);
|
|
105
103
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
var request = new proto.android.emulation.control.LogMessage();
|
|
113
|
-
request.setStart(_this.offset);
|
|
114
|
-
_this.stream = _this.emulator.streamLogcat(request);
|
|
115
|
-
_this.stream.on("data", function (response) {
|
|
116
|
-
self.offset = response.getNext();
|
|
117
|
-
var contents = response.getContents();
|
|
118
|
-
self.events.emit("data", contents);
|
|
119
|
-
});
|
|
120
|
-
_this.stream.on("error", function (error) {
|
|
121
|
-
if (error.code = 1) {
|
|
122
|
-
// Ignore we got cancelled.
|
|
104
|
+
return res.json();
|
|
105
|
+
}).then(function (response) {
|
|
106
|
+
var nextOffset = response.next;
|
|
107
|
+
if (nextOffset > self.offset) {
|
|
108
|
+
self.offset = nextOffset;
|
|
109
|
+
self.events.emit("data", response.contents);
|
|
123
110
|
}
|
|
111
|
+
})["catch"](function (err) {
|
|
112
|
+
console.error("Logcat error:", err);
|
|
113
|
+
_this.stop();
|
|
124
114
|
});
|
|
125
115
|
});
|
|
126
116
|
/**
|
|
127
117
|
* Requests the logcat stream, invoking the callback when a log line arrives.
|
|
128
118
|
*
|
|
129
|
-
* *Note:* Streaming can cause serious UI delays, so best not to use it.
|
|
130
|
-
*
|
|
131
119
|
* @param {Callback} fnNotify when a new log line arrives.
|
|
132
|
-
* @param {number} refreshRate polling interval
|
|
120
|
+
* @param {number} refreshRate polling interval. Must be > 0.
|
|
133
121
|
* @memberof Logcat
|
|
134
122
|
*/
|
|
135
123
|
(0, _defineProperty2["default"])(this, "start", function (fnNotify) {
|
|
136
124
|
var refreshRate = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1000;
|
|
137
125
|
if (fnNotify) _this.on("data", fnNotify);
|
|
138
126
|
_this.refreshRate = refreshRate;
|
|
139
|
-
if (_this.refreshRate
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}, _this.refreshRate);
|
|
143
|
-
} else {
|
|
144
|
-
_this.stream();
|
|
127
|
+
if (_this.refreshRate <= 0) {
|
|
128
|
+
console.warn("Streaming logcat is no longer supported. Falling back to 1000ms polling.");
|
|
129
|
+
_this.refreshRate = 1000;
|
|
145
130
|
}
|
|
131
|
+
_this.timerID = setInterval(function () {
|
|
132
|
+
return _this.pollStream();
|
|
133
|
+
}, _this.refreshRate);
|
|
146
134
|
_this.events.emit("start");
|
|
147
135
|
});
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
} else {
|
|
151
|
-
this.emulator = new _emulator_web_client.EmulatorControllerService(uriOrEmulator, auth);
|
|
152
|
-
}
|
|
136
|
+
this.logcatUrl = logcatUrl;
|
|
137
|
+
this.auth = auth;
|
|
153
138
|
this.offset = 0;
|
|
154
|
-
this.lastline = "";
|
|
155
|
-
this.stream = null;
|
|
156
139
|
this.events = new _events.EventEmitter();
|
|
157
140
|
this.refreshRate = 1000;
|
|
158
141
|
this.timerID = null;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports["default"] = void 0;
|
|
8
|
+
var _loglevel = _interopRequireDefault(require("loglevel"));
|
|
9
|
+
/**
|
|
10
|
+
* @fileoverview Configures and exports a loglevel logger instance scoped to
|
|
11
|
+
* the 'android-emulator-webrtc' package.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
// Create a logger specific to the emulator package
|
|
15
|
+
var logger = _loglevel["default"].getLogger("android-emulator-webrtc");
|
|
16
|
+
|
|
17
|
+
// Default to "info" level so that verbose signaling (debug) is hidden by default,
|
|
18
|
+
// but warnings and errors are still printed.
|
|
19
|
+
logger.setDefaultLevel("info");
|
|
20
|
+
var _default = exports["default"] = logger;
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
export interface WsJsepConfig {
|
|
2
|
+
enableLogging?: boolean;
|
|
3
|
+
onError?: (error: Error | Event) => void;
|
|
4
|
+
maxReconnectAttempts?: number;
|
|
5
|
+
reconnectDelay?: number;
|
|
6
|
+
reconnectBackoffFactor?: number;
|
|
7
|
+
[key: string]: any;
|
|
8
|
+
}
|
|
9
|
+
export interface StreamCallbacks {
|
|
10
|
+
onConnected?: (track: MediaStreamTrack) => void;
|
|
11
|
+
onDisconnected?: (driver: WsJsepProtocol) => void;
|
|
12
|
+
}
|
|
13
|
+
export interface EmulatorController {
|
|
14
|
+
sendMouse?(msg: any): void;
|
|
15
|
+
sendKey?(msg: any): void;
|
|
16
|
+
sendTouch?(msg: any): void;
|
|
17
|
+
}
|
|
18
|
+
export interface JsepSignal {
|
|
19
|
+
start?: RTCConfiguration;
|
|
20
|
+
type?: "offer" | "answer";
|
|
21
|
+
sdp?: RTCSessionDescriptionInit | string;
|
|
22
|
+
candidate?: RTCIceCandidateInit | string;
|
|
23
|
+
bye?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* A JSEP protocol driver that uses WebSockets for signaling.
|
|
27
|
+
*
|
|
28
|
+
* @export
|
|
29
|
+
* @class WsJsepProtocol
|
|
30
|
+
*/
|
|
31
|
+
export default class WsJsepProtocol {
|
|
32
|
+
wsUrl: string;
|
|
33
|
+
emulator: EmulatorController | null;
|
|
34
|
+
config: WsJsepConfig;
|
|
35
|
+
onError?: (error: Error | Event) => void;
|
|
36
|
+
maxReconnectAttempts: number;
|
|
37
|
+
reconnectDelay: number;
|
|
38
|
+
reconnectBackoffFactor: number;
|
|
39
|
+
connected: boolean;
|
|
40
|
+
event_forwarders: Record<string, RTCDataChannel>;
|
|
41
|
+
peerConnection: RTCPeerConnection | null;
|
|
42
|
+
ws: WebSocket | null;
|
|
43
|
+
pendingCandidates: (RTCIceCandidateInit | string)[];
|
|
44
|
+
remoteDescriptionSet: boolean;
|
|
45
|
+
signalQueue: JsepSignal[];
|
|
46
|
+
isProcessingSignal: boolean;
|
|
47
|
+
onConnected: ((track: MediaStreamTrack) => void) | null;
|
|
48
|
+
onDisconnected: ((driver: WsJsepProtocol) => void) | null;
|
|
49
|
+
reconnectAttempts: number;
|
|
50
|
+
reconnectTimeoutId: any | null;
|
|
51
|
+
/**
|
|
52
|
+
* Creates an instance of WsJsepProtocol.
|
|
53
|
+
*
|
|
54
|
+
* @param wsUrl The WebSocket JSEP signaling URL.
|
|
55
|
+
* @param emulator Fallback emulator controller for sending events when WebRTC is unavailable.
|
|
56
|
+
* @param config Configuration options.
|
|
57
|
+
*/
|
|
58
|
+
constructor(wsUrl: string, emulator?: EmulatorController | null, config?: WsJsepConfig);
|
|
59
|
+
/**
|
|
60
|
+
* Establishes the WebSocket connection and starts the signaling process.
|
|
61
|
+
* Cleans up any existing connection beforehand.
|
|
62
|
+
*
|
|
63
|
+
* @param callbacks Callbacks for stream lifecycle events.
|
|
64
|
+
*/
|
|
65
|
+
startStream: (callbacks?: StreamCallbacks) => void;
|
|
66
|
+
/**
|
|
67
|
+
* Internal method to establish WebSocket connection.
|
|
68
|
+
*
|
|
69
|
+
* @private
|
|
70
|
+
*/
|
|
71
|
+
_connect: () => void;
|
|
72
|
+
/**
|
|
73
|
+
* Queues a reconnection attempt with exponential backoff.
|
|
74
|
+
*
|
|
75
|
+
* @private
|
|
76
|
+
*/
|
|
77
|
+
_queueReconnect: () => void;
|
|
78
|
+
/**
|
|
79
|
+
* Internal handler for incoming WebSocket messages. Parses the signal
|
|
80
|
+
* and queues it for sequential processing.
|
|
81
|
+
*
|
|
82
|
+
* @private
|
|
83
|
+
* @param event The WebSocket message event.
|
|
84
|
+
*/
|
|
85
|
+
_handleWsMessage: (event: MessageEvent) => void;
|
|
86
|
+
/**
|
|
87
|
+
* Sequentially processes JSEP signals from the queue.
|
|
88
|
+
*
|
|
89
|
+
* @private
|
|
90
|
+
*/
|
|
91
|
+
_processSignalQueue: () => Promise<void>;
|
|
92
|
+
/**
|
|
93
|
+
* Handles WebSocket connection close events.
|
|
94
|
+
*
|
|
95
|
+
* @private
|
|
96
|
+
* @param event The WebSocket close event.
|
|
97
|
+
*/
|
|
98
|
+
_handleWsClose: (event: CloseEvent) => void;
|
|
99
|
+
/**
|
|
100
|
+
* Handles WebSocket error events.
|
|
101
|
+
*
|
|
102
|
+
* @private
|
|
103
|
+
* @param error The WebSocket error event.
|
|
104
|
+
*/
|
|
105
|
+
_handleWsError: (error: Event) => void;
|
|
106
|
+
/**
|
|
107
|
+
* Processes a single JSEP signal (e.g., start, offer, answer, candidate, bye).
|
|
108
|
+
*
|
|
109
|
+
* @private
|
|
110
|
+
* @param signal The JSEP signaling message.
|
|
111
|
+
*/
|
|
112
|
+
_handleSignal: (signal: JsepSignal) => Promise<void>;
|
|
113
|
+
/**
|
|
114
|
+
* Initializes the RTCPeerConnection and local data channels based on the start configuration.
|
|
115
|
+
*
|
|
116
|
+
* @private
|
|
117
|
+
* @param config The signaling start configuration.
|
|
118
|
+
*/
|
|
119
|
+
_handleStart: (config: RTCConfiguration) => Promise<void>;
|
|
120
|
+
/**
|
|
121
|
+
* Handles incoming media track events from the RTCPeerConnection.
|
|
122
|
+
*
|
|
123
|
+
* @private
|
|
124
|
+
* @param e The track event.
|
|
125
|
+
*/
|
|
126
|
+
_handlePeerConnectionTrack: (e: RTCTrackEvent) => void;
|
|
127
|
+
/**
|
|
128
|
+
* Handles ICE candidate generation from the local RTCPeerConnection.
|
|
129
|
+
*
|
|
130
|
+
* @private
|
|
131
|
+
* @param e The ICE candidate event.
|
|
132
|
+
*/
|
|
133
|
+
_handlePeerIceCandidate: (e: RTCPeerConnectionIceEvent) => void;
|
|
134
|
+
/**
|
|
135
|
+
* Monitors connection state changes on the RTCPeerConnection to trigger disconnection.
|
|
136
|
+
*
|
|
137
|
+
* @private
|
|
138
|
+
* @param e The state change event.
|
|
139
|
+
*/
|
|
140
|
+
_handlePeerConnectionStateChange: (e: Event) => void;
|
|
141
|
+
/**
|
|
142
|
+
* Registers a data channel for event forwarding.
|
|
143
|
+
*
|
|
144
|
+
* @private
|
|
145
|
+
* @param channel The data channel.
|
|
146
|
+
*/
|
|
147
|
+
_setupDataChannel: (channel: RTCDataChannel) => void;
|
|
148
|
+
/**
|
|
149
|
+
* Handles remote data channel creation.
|
|
150
|
+
*
|
|
151
|
+
* @private
|
|
152
|
+
* @param e The data channel event.
|
|
153
|
+
*/
|
|
154
|
+
_handleDataChannel: (e: RTCDataChannelEvent) => void;
|
|
155
|
+
/**
|
|
156
|
+
* Processes a remote SDP offer or answer, applying it to the RTCPeerConnection.
|
|
157
|
+
*
|
|
158
|
+
* @private
|
|
159
|
+
* @param sdp The session description.
|
|
160
|
+
*/
|
|
161
|
+
_handleSDP: (sdp: RTCSessionDescriptionInit) => Promise<void>;
|
|
162
|
+
/**
|
|
163
|
+
* Adds a remote ICE candidate to the RTCPeerConnection.
|
|
164
|
+
*
|
|
165
|
+
* @private
|
|
166
|
+
* @param candidate The ICE candidate object or string.
|
|
167
|
+
*/
|
|
168
|
+
_addIceCandidate: (candidate: RTCIceCandidateInit | string) => void;
|
|
169
|
+
/**
|
|
170
|
+
* Handles an incoming remote ICE candidate, queueing it if the remote description is not yet set.
|
|
171
|
+
*
|
|
172
|
+
* @private
|
|
173
|
+
* @param candidate The remote ICE candidate.
|
|
174
|
+
*/
|
|
175
|
+
_handleCandidate: (candidate: RTCIceCandidateInit | string) => void;
|
|
176
|
+
/**
|
|
177
|
+
* Handles the 'bye' signal from the remote side, triggering disconnection.
|
|
178
|
+
*
|
|
179
|
+
* @private
|
|
180
|
+
*/
|
|
181
|
+
_handleBye: () => void;
|
|
182
|
+
/**
|
|
183
|
+
* Serializes and sends a JSEP JSON message over the WebSocket.
|
|
184
|
+
*
|
|
185
|
+
* @private
|
|
186
|
+
* @param jsonObject The JSON payload.
|
|
187
|
+
*/
|
|
188
|
+
_sendJsep: (jsonObject: JsepSignal) => void;
|
|
189
|
+
/**
|
|
190
|
+
* Sends a control message (mouse, keyboard, touch) over either the corresponding
|
|
191
|
+
* WebRTC DataChannel or via the fallback emulator controller.
|
|
192
|
+
*
|
|
193
|
+
* @param label The channel label ("mouse", "keyboard", "touch").
|
|
194
|
+
* @param msg The protobuf message instance.
|
|
195
|
+
*/
|
|
196
|
+
send: (label: string, msg: any) => void;
|
|
197
|
+
/**
|
|
198
|
+
* Cleans up the current connection's WebSocket and PeerConnection state,
|
|
199
|
+
* but does not mark the driver as permanently disconnected or trigger
|
|
200
|
+
* the onDisconnected callback. Used during reconnection.
|
|
201
|
+
*
|
|
202
|
+
* @private
|
|
203
|
+
*/
|
|
204
|
+
_disconnectState: () => void;
|
|
205
|
+
/**
|
|
206
|
+
* Disconnects both the WebSocket signaling connection and the WebRTC PeerConnection.
|
|
207
|
+
*/
|
|
208
|
+
disconnect: () => void;
|
|
209
|
+
/**
|
|
210
|
+
* Fully cleans up signaling and WebRTC state.
|
|
211
|
+
*/
|
|
212
|
+
cleanup: () => void;
|
|
213
|
+
}
|