remoterigs-raspberrypi 0.1.12 → 0.1.14
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,100 @@ 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
|
}
|
|
103
124
|
const args = [
|
|
104
125
|
"-H", `0.0.0.0:${this.STREAMER_PORT}`,
|
|
105
126
|
"-s",
|
|
106
127
|
//"--stun", this.clientRTCConfigurationViewModel.stunServer,
|
|
107
|
-
"--turn", this.clientRTCConfigurationViewModel.turnServer
|
|
108
128
|
];
|
|
129
|
+
if (turnServer != "") {
|
|
130
|
+
args.push("--turn", turnServer);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
this.Log("no TURN credential received from the server, starting webrtc-streamer without TURN");
|
|
134
|
+
}
|
|
109
135
|
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)}`);
|
|
136
|
+
const streamerProcess = spawn(command, args);
|
|
137
|
+
this.webrtcStreamerProcess = streamerProcess;
|
|
138
|
+
WebRTCStreamerWrapper.sharedProcess = streamerProcess;
|
|
139
|
+
WebRTCStreamerWrapper.sharedTurnServer = turnServer;
|
|
140
|
+
if (streamerProcess.stdout != null) {
|
|
141
|
+
streamerProcess.stdout.on("data", (data) => {
|
|
142
|
+
this.Log(`webrtc-streamer stdout: ${data}`);
|
|
124
143
|
});
|
|
125
|
-
|
|
126
|
-
|
|
144
|
+
}
|
|
145
|
+
if (streamerProcess.stderr != null) {
|
|
146
|
+
streamerProcess.stderr.on("data", (data) => {
|
|
147
|
+
this.Log(`webrtc-streamer stderr: ${data}`);
|
|
127
148
|
});
|
|
128
149
|
}
|
|
150
|
+
streamerProcess.on("error", (err) => {
|
|
151
|
+
this.Error(`webrtc-streamer error: ${JSON.stringify(err)}`);
|
|
152
|
+
});
|
|
153
|
+
streamerProcess.on("close", (code) => {
|
|
154
|
+
this.Log(`webrtc-streamer exited with code ${code}`);
|
|
155
|
+
if (WebRTCStreamerWrapper.sharedProcess === streamerProcess) {
|
|
156
|
+
WebRTCStreamerWrapper.sharedProcess = null;
|
|
157
|
+
WebRTCStreamerWrapper.sharedTurnServer = null;
|
|
158
|
+
}
|
|
159
|
+
});
|
|
129
160
|
this.Log("Spawned webrtc-streamer process: " + command);
|
|
130
161
|
}
|
|
162
|
+
async IsStreamerResponding() {
|
|
163
|
+
try {
|
|
164
|
+
await this.streamerClient.get('/api/version');
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
catch (err) {
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
async WaitUntilStreamerStopped() {
|
|
172
|
+
for (let i = 0; i < 20; i++) {
|
|
173
|
+
if (!(await this.IsStreamerResponding())) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
await new Promise(resolve => setTimeout(resolve, 250));
|
|
177
|
+
}
|
|
178
|
+
this.Error("webrtc-streamer did not stop within 5 seconds");
|
|
179
|
+
}
|
|
180
|
+
static StopProcess(streamerProcess) {
|
|
181
|
+
return new Promise(resolve => {
|
|
182
|
+
if (streamerProcess.exitCode !== null || streamerProcess.signalCode !== null) {
|
|
183
|
+
resolve();
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const timer = setTimeout(() => {
|
|
187
|
+
streamerProcess.kill("SIGKILL");
|
|
188
|
+
resolve();
|
|
189
|
+
}, 5000);
|
|
190
|
+
streamerProcess.once("exit", () => {
|
|
191
|
+
clearTimeout(timer);
|
|
192
|
+
resolve();
|
|
193
|
+
});
|
|
194
|
+
streamerProcess.kill();
|
|
195
|
+
});
|
|
196
|
+
}
|
|
131
197
|
async WaitForStreamer() {
|
|
132
198
|
const maxRetries = 20;
|
|
133
199
|
const retryDelay = 500;
|
|
@@ -173,9 +239,16 @@ export default class WebRTCStreamerWrapper {
|
|
|
173
239
|
}
|
|
174
240
|
async FlushBufferedCandidates(sessionId) {
|
|
175
241
|
const buffer = this.candidateBuffer.get(sessionId);
|
|
242
|
+
this.candidateBuffer.delete(sessionId);
|
|
176
243
|
if (buffer && buffer.length > 0) {
|
|
177
244
|
this.Log(`Flushing ${buffer.length} buffered ICE candidates for session ${sessionId}`);
|
|
178
|
-
|
|
245
|
+
// the buffered candidates were never added: add them now that the remote description is set
|
|
246
|
+
for (const candidateMessage of buffer) {
|
|
247
|
+
const message = new WebRTCMessage();
|
|
248
|
+
message.sessionId = sessionId;
|
|
249
|
+
message.message = candidateMessage;
|
|
250
|
+
await this.AddIceCandidate(message);
|
|
251
|
+
}
|
|
179
252
|
}
|
|
180
253
|
}
|
|
181
254
|
async GetIceServers(message) {
|