remoterigs-raspberrypi 0.1.13 → 0.1.15
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/package.json
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import { spawn } from 'child_process';
|
|
1
|
+
import { spawn, spawnSync } from 'child_process';
|
|
2
2
|
import axios from 'axios';
|
|
3
3
|
import { LogSettingType, VideoType, WebRTCMessage } from '../models/models.js';
|
|
4
4
|
import SignalR from './signalr.js';
|
|
5
5
|
import Debug from './debug.js';
|
|
6
6
|
export default class WebRTCStreamerWrapper {
|
|
7
|
+
// one webrtc-streamer process for the whole client: every sign in creates new components (and wrappers),
|
|
8
|
+
// the process is only restarted when the TURN credential changed
|
|
9
|
+
static { this.sharedProcess = null; }
|
|
10
|
+
static { this.sharedTurnServer = null; }
|
|
7
11
|
constructor(component, clientRTCConfigurationViewModel, videoType) {
|
|
8
12
|
this.component = component;
|
|
9
13
|
this.clientRTCConfigurationViewModel = clientRTCConfigurationViewModel;
|
|
@@ -41,6 +45,10 @@ export default class WebRTCStreamerWrapper {
|
|
|
41
45
|
}
|
|
42
46
|
// Stop webrtc-streamer process
|
|
43
47
|
if (this.webrtcStreamerProcess) {
|
|
48
|
+
if (WebRTCStreamerWrapper.sharedProcess === this.webrtcStreamerProcess) {
|
|
49
|
+
WebRTCStreamerWrapper.sharedProcess = null;
|
|
50
|
+
WebRTCStreamerWrapper.sharedTurnServer = null;
|
|
51
|
+
}
|
|
44
52
|
this.webrtcStreamerProcess.kill();
|
|
45
53
|
this.webrtcStreamerProcess = null;
|
|
46
54
|
}
|
|
@@ -92,42 +100,102 @@ export default class WebRTCStreamerWrapper {
|
|
|
92
100
|
}
|
|
93
101
|
}
|
|
94
102
|
async StartWebRTCStreamer() {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
103
|
+
const turnServer = this.clientRTCConfigurationViewModel.turnServer ?? "";
|
|
104
|
+
const running = WebRTCStreamerWrapper.sharedProcess;
|
|
105
|
+
if (running != null && running.exitCode === null && running.signalCode === null) {
|
|
106
|
+
if (WebRTCStreamerWrapper.sharedTurnServer === turnServer) {
|
|
107
|
+
this.Log("webrtc-streamer is already running with the current TURN credential");
|
|
108
|
+
this.webrtcStreamerProcess = running;
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
// a new sign in brought a new TURN credential (the old one may have been deleted at Metered)
|
|
112
|
+
this.Log("TURN credential changed, restarting webrtc-streamer...");
|
|
113
|
+
await WebRTCStreamerWrapper.StopProcess(running);
|
|
99
114
|
}
|
|
100
|
-
|
|
115
|
+
else if (await this.IsStreamerResponding()) {
|
|
116
|
+
// started by someone else: its TURN credential is unknown, so restart it with the current one
|
|
117
|
+
this.Log("webrtc-streamer is running from an unknown streamerProcess, restarting it with the current TURN credential...");
|
|
118
|
+
spawnSync("pkill", ["-x", "webrtc-streamer"]);
|
|
119
|
+
await this.WaitUntilStreamerStopped();
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
101
122
|
this.Log("webrtc-streamer not running, starting it...");
|
|
102
123
|
}
|
|
124
|
+
const stunServer = this.clientRTCConfigurationViewModel.stunServer ?? "";
|
|
103
125
|
const args = [
|
|
104
126
|
"-H", `0.0.0.0:${this.STREAMER_PORT}`,
|
|
105
|
-
"-s",
|
|
106
|
-
//"
|
|
107
|
-
"
|
|
127
|
+
// "-s<host:port>" (no space): our own STUN server, so the rig also has a public (srflx) candidate;
|
|
128
|
+
// "-s-" = no STUN
|
|
129
|
+
stunServer != "" ? `-s${stunServer}` : "-s-",
|
|
108
130
|
];
|
|
131
|
+
if (turnServer != "") {
|
|
132
|
+
args.push("--turn", turnServer);
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
this.Log("no TURN credential received from the server, starting webrtc-streamer without TURN");
|
|
136
|
+
}
|
|
109
137
|
const command = "webrtc-streamer";
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
if (this.webrtcStreamerProcess.stderr != null) {
|
|
118
|
-
this.webrtcStreamerProcess.stderr.on("data", (data) => {
|
|
119
|
-
this.Log(`webrtc-streamer stderr: ${data}`);
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
this.webrtcStreamerProcess.on("error", (err) => {
|
|
123
|
-
this.Error(`webrtc-streamer error: ${JSON.stringify(err)}`);
|
|
138
|
+
const streamerProcess = spawn(command, args);
|
|
139
|
+
this.webrtcStreamerProcess = streamerProcess;
|
|
140
|
+
WebRTCStreamerWrapper.sharedProcess = streamerProcess;
|
|
141
|
+
WebRTCStreamerWrapper.sharedTurnServer = turnServer;
|
|
142
|
+
if (streamerProcess.stdout != null) {
|
|
143
|
+
streamerProcess.stdout.on("data", (data) => {
|
|
144
|
+
this.Log(`webrtc-streamer stdout: ${data}`);
|
|
124
145
|
});
|
|
125
|
-
|
|
126
|
-
|
|
146
|
+
}
|
|
147
|
+
if (streamerProcess.stderr != null) {
|
|
148
|
+
streamerProcess.stderr.on("data", (data) => {
|
|
149
|
+
this.Log(`webrtc-streamer stderr: ${data}`);
|
|
127
150
|
});
|
|
128
151
|
}
|
|
152
|
+
streamerProcess.on("error", (err) => {
|
|
153
|
+
this.Error(`webrtc-streamer error: ${JSON.stringify(err)}`);
|
|
154
|
+
});
|
|
155
|
+
streamerProcess.on("close", (code) => {
|
|
156
|
+
this.Log(`webrtc-streamer exited with code ${code}`);
|
|
157
|
+
if (WebRTCStreamerWrapper.sharedProcess === streamerProcess) {
|
|
158
|
+
WebRTCStreamerWrapper.sharedProcess = null;
|
|
159
|
+
WebRTCStreamerWrapper.sharedTurnServer = null;
|
|
160
|
+
}
|
|
161
|
+
});
|
|
129
162
|
this.Log("Spawned webrtc-streamer process: " + command);
|
|
130
163
|
}
|
|
164
|
+
async IsStreamerResponding() {
|
|
165
|
+
try {
|
|
166
|
+
await this.streamerClient.get('/api/version');
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
async WaitUntilStreamerStopped() {
|
|
174
|
+
for (let i = 0; i < 20; i++) {
|
|
175
|
+
if (!(await this.IsStreamerResponding())) {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
await new Promise(resolve => setTimeout(resolve, 250));
|
|
179
|
+
}
|
|
180
|
+
this.Error("webrtc-streamer did not stop within 5 seconds");
|
|
181
|
+
}
|
|
182
|
+
static StopProcess(streamerProcess) {
|
|
183
|
+
return new Promise(resolve => {
|
|
184
|
+
if (streamerProcess.exitCode !== null || streamerProcess.signalCode !== null) {
|
|
185
|
+
resolve();
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const timer = setTimeout(() => {
|
|
189
|
+
streamerProcess.kill("SIGKILL");
|
|
190
|
+
resolve();
|
|
191
|
+
}, 5000);
|
|
192
|
+
streamerProcess.once("exit", () => {
|
|
193
|
+
clearTimeout(timer);
|
|
194
|
+
resolve();
|
|
195
|
+
});
|
|
196
|
+
streamerProcess.kill();
|
|
197
|
+
});
|
|
198
|
+
}
|
|
131
199
|
async WaitForStreamer() {
|
|
132
200
|
const maxRetries = 20;
|
|
133
201
|
const retryDelay = 500;
|