@flashphoner/websdk 2.0.202 → 2.0.207
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/docTemplate/README.md +1 -1
- package/examples/demo/sip/phone/phone.js +7 -10
- package/examples/demo/streaming/hls-player/hls-player.html +1 -4
- package/examples/demo/streaming/hls-player/hls-player.js +19 -1
- package/examples/demo/streaming/hls-player/player-page.html +1 -1
- package/examples/demo/streaming/hls-player/video-js.css +142 -51
- package/examples/demo/streaming/hls-player/video.js +27294 -20390
- package/examples/demo/streaming/hls-player/video.min.js +27 -0
- package/examples/demo/streaming/media_devices_manager/manager.js +27 -1
- package/examples/demo/streaming/media_devices_manager/media_device_manager.html +7 -0
- package/examples/demo/streaming/stream-auto-restore/stream-auto-restore.css +23 -0
- package/examples/demo/streaming/stream-auto-restore/stream-auto-restore.html +76 -0
- package/examples/demo/streaming/stream-auto-restore/stream-auto-restore.js +356 -0
- package/examples/typescript/two-way-streaming-ts/.gitignore +23 -0
- package/examples/typescript/two-way-streaming-ts/README.md +36 -0
- package/examples/typescript/two-way-streaming-ts/package.json +45 -0
- package/examples/typescript/two-way-streaming-ts/public/favicon.ico +0 -0
- package/examples/typescript/two-way-streaming-ts/public/index.html +33 -0
- package/examples/typescript/two-way-streaming-ts/public/logo192.png +0 -0
- package/examples/typescript/two-way-streaming-ts/public/logo512.png +0 -0
- package/examples/typescript/two-way-streaming-ts/public/manifest.json +25 -0
- package/examples/typescript/two-way-streaming-ts/public/media/preloader.mp4 +0 -0
- package/examples/typescript/two-way-streaming-ts/public/robots.txt +3 -0
- package/examples/typescript/two-way-streaming-ts/src/TwoWayStreamingApp.css +23 -0
- package/examples/typescript/two-way-streaming-ts/src/TwoWayStreamingApp.tsx +371 -0
- package/examples/typescript/two-way-streaming-ts/src/fp-utils.ts +117 -0
- package/examples/typescript/two-way-streaming-ts/src/index.css +13 -0
- package/examples/typescript/two-way-streaming-ts/src/index.tsx +9 -0
- package/examples/typescript/two-way-streaming-ts/tsconfig.json +26 -0
- package/flashphoner-no-flash.js +19 -19
- package/flashphoner-no-flash.min.js +2 -2
- package/flashphoner-no-webrtc.js +18 -18
- package/flashphoner-no-webrtc.min.js +1 -1
- package/flashphoner-no-wsplayer.js +20 -20
- package/flashphoner-no-wsplayer.min.js +2 -2
- package/flashphoner-room-api.js +6 -6
- package/flashphoner-room-api.min.js +2 -2
- package/flashphoner-temasys-flash-websocket-without-adapterjs.js +20 -20
- package/flashphoner-temasys-flash-websocket.js +20 -20
- package/flashphoner-temasys-flash-websocket.min.js +1 -1
- package/flashphoner-webrtc-only.js +17 -17
- package/flashphoner-webrtc-only.min.js +1 -1
- package/flashphoner.js +20 -20
- package/flashphoner.min.js +2 -2
- package/package.json +2 -1
- package/src/constants.d.ts +1 -0
- package/src/flashphoner-core.d.ts +192 -0
- package/src/flashphoner-core.js +4 -4
- package/src/room-module.d.ts +29 -0
- package/src/webrtc-media-provider.js +2 -2
- package/examples/demo/streaming/hls-player/videojs-hls.min.js +0 -27
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"short_name": "Two Way Streaming",
|
|
3
|
+
"name": "Two Way Streaming React App Sample",
|
|
4
|
+
"icons": [
|
|
5
|
+
{
|
|
6
|
+
"src": "favicon.ico",
|
|
7
|
+
"sizes": "64x64 32x32 24x24 16x16",
|
|
8
|
+
"type": "image/x-icon"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"src": "logo192.png",
|
|
12
|
+
"type": "image/png",
|
|
13
|
+
"sizes": "192x192"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"src": "logo512.png",
|
|
17
|
+
"type": "image/png",
|
|
18
|
+
"sizes": "512x512"
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"start_url": ".",
|
|
22
|
+
"display": "standalone",
|
|
23
|
+
"theme_color": "#000000",
|
|
24
|
+
"background_color": "#ffffff"
|
|
25
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
.fp-Video {
|
|
2
|
+
border: 1px double black;
|
|
3
|
+
width: 322px;
|
|
4
|
+
height: 242px;
|
|
5
|
+
text-align: center;
|
|
6
|
+
background: #c0c0c0;
|
|
7
|
+
margin: 0 auto 0 auto;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.display {
|
|
11
|
+
width: 100%;
|
|
12
|
+
height: 100%;
|
|
13
|
+
display: inline-block;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.display > video, object {
|
|
17
|
+
width: 100%;
|
|
18
|
+
height: 100%;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
video:-webkit-full-screen {
|
|
22
|
+
border-radius: 1px;
|
|
23
|
+
}
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
import React, { Component } from 'react';
|
|
2
|
+
import './TwoWayStreamingApp.css';
|
|
3
|
+
import 'bootstrap/dist/css/bootstrap.min.css';
|
|
4
|
+
import * as FPUtils from './fp-utils';
|
|
5
|
+
import * as Flashphoner from '@flashphoner/websdk';
|
|
6
|
+
|
|
7
|
+
const SESSION_STATUS = Flashphoner.constants.SESSION_STATUS;
|
|
8
|
+
const STREAM_STATUS = Flashphoner.constants.STREAM_STATUS;
|
|
9
|
+
const Browser = Flashphoner.Browser;
|
|
10
|
+
const PRELOADER_URL = process.env.PUBLIC_URL + '/media/preloader.mp4';
|
|
11
|
+
|
|
12
|
+
interface TwoWayStreamingState {
|
|
13
|
+
apiFailed: string,
|
|
14
|
+
session: any,
|
|
15
|
+
sessionStatus: string,
|
|
16
|
+
sessionStatusClass: string,
|
|
17
|
+
localVideo: any,
|
|
18
|
+
remoteVideo: any,
|
|
19
|
+
publishStream: any,
|
|
20
|
+
publishStatus: string,
|
|
21
|
+
publishStatusClass: string,
|
|
22
|
+
playStream: any,
|
|
23
|
+
playStatus: string,
|
|
24
|
+
playStatusClass: string,
|
|
25
|
+
publishStreamName: string,
|
|
26
|
+
publishStreamNameDisabled: boolean,
|
|
27
|
+
playStreamName: string,
|
|
28
|
+
playStreamNameDisabled: boolean,
|
|
29
|
+
connectButtonText: string,
|
|
30
|
+
connectButtonDisabled: boolean,
|
|
31
|
+
serverUrl: string,
|
|
32
|
+
serverUrlDisabled: boolean,
|
|
33
|
+
publishButtonText: string,
|
|
34
|
+
publishButtonDisabled: boolean,
|
|
35
|
+
playButtonText: string,
|
|
36
|
+
playButtonDisabled: boolean
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
class TwoWayStreamingApp extends Component<{}, TwoWayStreamingState> {
|
|
40
|
+
constructor(props: any) {
|
|
41
|
+
super(props);
|
|
42
|
+
this.state = {
|
|
43
|
+
apiFailed: '',
|
|
44
|
+
session: null,
|
|
45
|
+
sessionStatus: '',
|
|
46
|
+
sessionStatusClass: 'text-muted',
|
|
47
|
+
localVideo: null,
|
|
48
|
+
remoteVideo: null,
|
|
49
|
+
publishStream: null,
|
|
50
|
+
publishStatus: '',
|
|
51
|
+
publishStatusClass: 'text-muted',
|
|
52
|
+
playStream: null,
|
|
53
|
+
playStatus: '',
|
|
54
|
+
playStatusClass: 'text-muted',
|
|
55
|
+
publishStreamName: 'streamName',
|
|
56
|
+
publishStreamNameDisabled: true,
|
|
57
|
+
playStreamName: 'streamName',
|
|
58
|
+
playStreamNameDisabled: true,
|
|
59
|
+
connectButtonText: 'Connect',
|
|
60
|
+
connectButtonDisabled: false,
|
|
61
|
+
serverUrl: 'wss://demo.flashphoner.com:8443',
|
|
62
|
+
serverUrlDisabled: false,
|
|
63
|
+
publishButtonText: 'Publish',
|
|
64
|
+
publishButtonDisabled: true,
|
|
65
|
+
playButtonText: 'Play',
|
|
66
|
+
playButtonDisabled: true
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
componentDidMount() {
|
|
71
|
+
try {
|
|
72
|
+
Flashphoner.init({});
|
|
73
|
+
this.setState({
|
|
74
|
+
localVideo: document.getElementById('localVideo'),
|
|
75
|
+
remoteVideo: document.getElementById('remoteVideo')
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
catch(e) {
|
|
79
|
+
console.log(e);
|
|
80
|
+
this.setState({
|
|
81
|
+
apiFailed: 'Your browser does not support WebRTC technology needed for this example',
|
|
82
|
+
connectButtonDisabled: true,
|
|
83
|
+
serverUrlDisabled: true
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
onConnected = (session: any) => {
|
|
89
|
+
this.setState({
|
|
90
|
+
session: session,
|
|
91
|
+
connectButtonText: 'Disconnect',
|
|
92
|
+
connectButtonDisabled: false,
|
|
93
|
+
serverUrlDisabled: true
|
|
94
|
+
});
|
|
95
|
+
this.onUnpublished();
|
|
96
|
+
this.onStopped();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
onDisconnected = () => {
|
|
100
|
+
this.setState({
|
|
101
|
+
session: null,
|
|
102
|
+
connectButtonText: 'Connect',
|
|
103
|
+
connectButtonDisabled: false,
|
|
104
|
+
serverUrlDisabled: false
|
|
105
|
+
});
|
|
106
|
+
this.onUnpublished();
|
|
107
|
+
this.onStopped();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
onPublishing = (stream: any) => {
|
|
111
|
+
this.setState({
|
|
112
|
+
publishStream: stream,
|
|
113
|
+
publishButtonText: 'Unpublish',
|
|
114
|
+
publishButtonDisabled: false
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
onUnpublished = () => {
|
|
119
|
+
let session = this.state.session;
|
|
120
|
+
let itemState = true;
|
|
121
|
+
|
|
122
|
+
if(session && session.status() === SESSION_STATUS.ESTABLISHED) {
|
|
123
|
+
itemState = false;
|
|
124
|
+
}
|
|
125
|
+
this.setState({
|
|
126
|
+
publishStream: null,
|
|
127
|
+
publishButtonText: 'Publish',
|
|
128
|
+
publishButtonDisabled: itemState,
|
|
129
|
+
publishStreamNameDisabled: itemState
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
onPlaying = (stream: any) => {
|
|
134
|
+
this.setState({
|
|
135
|
+
playStream: stream,
|
|
136
|
+
playButtonText: 'Stop',
|
|
137
|
+
playButtonDisabled: false
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
onStopped = () => {
|
|
142
|
+
let session = this.state.session;
|
|
143
|
+
let itemState = true;
|
|
144
|
+
|
|
145
|
+
if(session && session.status() === SESSION_STATUS.ESTABLISHED) {
|
|
146
|
+
itemState = false;
|
|
147
|
+
}
|
|
148
|
+
this.setState({
|
|
149
|
+
playStream: null,
|
|
150
|
+
playButtonText: 'Play',
|
|
151
|
+
playButtonDisabled: itemState,
|
|
152
|
+
playStreamNameDisabled: itemState
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
publishStream = () => {
|
|
157
|
+
let app = this;
|
|
158
|
+
let session = this.state.session;
|
|
159
|
+
let streamName = this.state.publishStreamName;
|
|
160
|
+
let localVideo = this.state.localVideo;
|
|
161
|
+
|
|
162
|
+
if(session && localVideo) {
|
|
163
|
+
session.createStream({
|
|
164
|
+
name: streamName,
|
|
165
|
+
display: localVideo,
|
|
166
|
+
cacheLocalResources: true,
|
|
167
|
+
receiveVideo: false,
|
|
168
|
+
receiveAudio: false
|
|
169
|
+
}).on(STREAM_STATUS.PUBLISHING, (stream: any) => {
|
|
170
|
+
app.setState({publishStatus: STREAM_STATUS.PUBLISHING, publishStatusClass: 'text-success'});
|
|
171
|
+
app.onPublishing(stream);
|
|
172
|
+
}).on(STREAM_STATUS.UNPUBLISHED, () => {
|
|
173
|
+
app.setState({publishStatus: STREAM_STATUS.UNPUBLISHED, publishStatusClass: 'text-success'});
|
|
174
|
+
app.onUnpublished();
|
|
175
|
+
}).on(STREAM_STATUS.FAILED, () => {
|
|
176
|
+
app.setState({publishStatus: STREAM_STATUS.FAILED, publishStatusClass: 'text-danger'});
|
|
177
|
+
app.onUnpublished();
|
|
178
|
+
}).publish();
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
playStream = () => {
|
|
183
|
+
let app = this;
|
|
184
|
+
let session = this.state.session;
|
|
185
|
+
let streamName = this.state.playStreamName;
|
|
186
|
+
let remoteVideo = this.state.remoteVideo;
|
|
187
|
+
|
|
188
|
+
if(session && remoteVideo) {
|
|
189
|
+
session.createStream({
|
|
190
|
+
name: streamName,
|
|
191
|
+
display: remoteVideo
|
|
192
|
+
}).on(STREAM_STATUS.PENDING, (stream: any) => {
|
|
193
|
+
let video: any = document.getElementById(stream.id());
|
|
194
|
+
if (!video.hasListeners) {
|
|
195
|
+
video.hasListeners = true;
|
|
196
|
+
video.addEventListener('resize', (event: any) => {
|
|
197
|
+
FPUtils.resizeVideo(event.target);
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}).on(STREAM_STATUS.PLAYING, (stream: any) => {
|
|
201
|
+
app.setState({playStatus: STREAM_STATUS.PLAYING, playStatusClass: 'text-success'});
|
|
202
|
+
app.onPlaying(stream);
|
|
203
|
+
}).on(STREAM_STATUS.STOPPED, () => {
|
|
204
|
+
app.setState({playStatus: STREAM_STATUS.STOPPED, playStatusClass: 'text-success'});
|
|
205
|
+
app.onStopped();
|
|
206
|
+
}).on(STREAM_STATUS.FAILED, () => {
|
|
207
|
+
app.setState({playStatus: STREAM_STATUS.FAILED, playStatusClass: 'text-danger'});
|
|
208
|
+
app.onStopped();
|
|
209
|
+
}).play();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
onConnectClick = () => {
|
|
214
|
+
let app = this;
|
|
215
|
+
let url = this.state.serverUrl;
|
|
216
|
+
let session = this.state.session;
|
|
217
|
+
|
|
218
|
+
if (!session) {
|
|
219
|
+
console.log("Create new session with url " + url);
|
|
220
|
+
app.setState({connectButtonDisabled: true, serverUrlDisabled: true});
|
|
221
|
+
Flashphoner.createSession({urlServer: url}).on(SESSION_STATUS.ESTABLISHED, (session: any) => {
|
|
222
|
+
app.setState({sessionStatus: SESSION_STATUS.ESTABLISHED, sessionStatusClass: 'text-success'});
|
|
223
|
+
app.onConnected(session);
|
|
224
|
+
}).on(SESSION_STATUS.DISCONNECTED, () => {
|
|
225
|
+
app.setState({sessionStatus: SESSION_STATUS.DISCONNECTED, sessionStatusClass: 'text-success'});
|
|
226
|
+
app.onDisconnected();
|
|
227
|
+
}).on(SESSION_STATUS.FAILED, () => {
|
|
228
|
+
app.setState({sessionStatus: SESSION_STATUS.FAILED, sessionStatusClass: 'text-danger'});
|
|
229
|
+
app.onDisconnected();
|
|
230
|
+
});
|
|
231
|
+
} else {
|
|
232
|
+
app.setState({connectButtonDisabled: true});
|
|
233
|
+
session.disconnect();
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
onPublishClick = () => {
|
|
238
|
+
let app = this;
|
|
239
|
+
let stream = this.state.publishStream;
|
|
240
|
+
let localVideo = this.state.localVideo;
|
|
241
|
+
|
|
242
|
+
if (!localVideo) return;
|
|
243
|
+
if (!stream) {
|
|
244
|
+
app.setState({publishButtonDisabled: true, publishStreamNameDisabled: true});
|
|
245
|
+
if (Browser.isSafariWebRTC()) {
|
|
246
|
+
Flashphoner.playFirstVideo(localVideo, true, PRELOADER_URL).then(() => {
|
|
247
|
+
app.publishStream();
|
|
248
|
+
});
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
app.publishStream();
|
|
252
|
+
} else {
|
|
253
|
+
app.setState({publishButtonDisabled: true});
|
|
254
|
+
stream.stop();
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
onPlayClick = () => {
|
|
259
|
+
let app = this;
|
|
260
|
+
let stream = this.state.playStream;
|
|
261
|
+
let remoteVideo = this.state.remoteVideo;
|
|
262
|
+
|
|
263
|
+
if (!remoteVideo) return;
|
|
264
|
+
if (!stream) {
|
|
265
|
+
app.setState({playButtonDisabled: true, playStreamNameDisabled: true});
|
|
266
|
+
if (Flashphoner.getMediaProviders()[0] === "WSPlayer") {
|
|
267
|
+
Flashphoner.playFirstSound();
|
|
268
|
+
} else if (Browser.isSafariWebRTC()) {
|
|
269
|
+
Flashphoner.playFirstVideo(remoteVideo, false, PRELOADER_URL).then(() => {
|
|
270
|
+
app.playStream();
|
|
271
|
+
});
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
app.playStream();
|
|
275
|
+
} else {
|
|
276
|
+
app.setState({playButtonDisabled: true});
|
|
277
|
+
stream.stop();
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
render() {
|
|
282
|
+
return (
|
|
283
|
+
<div className="container">
|
|
284
|
+
<h2 className="text-danger">{this.state.apiFailed}</h2>
|
|
285
|
+
<div className="row">
|
|
286
|
+
<h2 className="text-center">Two-way Streaming in Typescript</h2>
|
|
287
|
+
</div>
|
|
288
|
+
<div className="row row-space">
|
|
289
|
+
<div className="col-sm-6">
|
|
290
|
+
<div className="text-center text-muted">Local</div>
|
|
291
|
+
<div className="fp-Video">
|
|
292
|
+
<div id="localVideo" className="display"></div>
|
|
293
|
+
</div>
|
|
294
|
+
<div className="input-group col-sm-5" style={{margin: '10px auto 0 auto'}}>
|
|
295
|
+
<input type="text"
|
|
296
|
+
className="form-control"
|
|
297
|
+
placeholder="Stream Name"
|
|
298
|
+
value={this.state.publishStreamName}
|
|
299
|
+
disabled={this.state.publishStreamNameDisabled}
|
|
300
|
+
onChange={(event) => this.setState({publishStreamName: event.target.value})}
|
|
301
|
+
/>
|
|
302
|
+
<div className="input-group-btn">
|
|
303
|
+
<button
|
|
304
|
+
className="btn btn-outline-dark"
|
|
305
|
+
disabled={this.state.publishButtonDisabled}
|
|
306
|
+
onClick={() => this.onPublishClick()}>
|
|
307
|
+
{this.state.publishButtonText}
|
|
308
|
+
</button>
|
|
309
|
+
</div>
|
|
310
|
+
</div>
|
|
311
|
+
<div className="text-center" style={{marginTop: '20px'}}>
|
|
312
|
+
<div className={this.state.publishStatusClass}>{this.state.publishStatus}</div>
|
|
313
|
+
</div>
|
|
314
|
+
</div>
|
|
315
|
+
<div className="col-sm-6">
|
|
316
|
+
<div className="text-center text-muted">Remote</div>
|
|
317
|
+
<div className="fp-Video">
|
|
318
|
+
<div id="remoteVideo" className="display"></div>
|
|
319
|
+
</div>
|
|
320
|
+
<div className="input-group col-sm-5" style={{margin: '10px auto 0 auto'}}>
|
|
321
|
+
<input type="text"
|
|
322
|
+
className="form-control"
|
|
323
|
+
placeholder="Stream Name"
|
|
324
|
+
value={this.state.playStreamName}
|
|
325
|
+
disabled={this.state.playStreamNameDisabled}
|
|
326
|
+
onChange={(event) => this.setState({playStreamName: event.target.value})}
|
|
327
|
+
/>
|
|
328
|
+
<div className="input-group-btn">
|
|
329
|
+
<button
|
|
330
|
+
className="btn btn-outline-dark"
|
|
331
|
+
disabled={this.state.playButtonDisabled}
|
|
332
|
+
onClick={() => this.onPlayClick()}>
|
|
333
|
+
{this.state.playButtonText}
|
|
334
|
+
</button>
|
|
335
|
+
</div>
|
|
336
|
+
</div>
|
|
337
|
+
<div className="text-center" style={{marginTop: '20px'}}>
|
|
338
|
+
<div className={this.state.playStatusClass}>{this.state.playStatus}</div>
|
|
339
|
+
</div>
|
|
340
|
+
</div>
|
|
341
|
+
</div>
|
|
342
|
+
<div className="row row-space">
|
|
343
|
+
<div className="col-sm-6 offset-sm-3">
|
|
344
|
+
<div className="input-group col-sm-5">
|
|
345
|
+
<input type="text"
|
|
346
|
+
className="form-control"
|
|
347
|
+
placeholder="Server Url"
|
|
348
|
+
value={this.state.serverUrl}
|
|
349
|
+
disabled={this.state.serverUrlDisabled}
|
|
350
|
+
onChange={(event) => this.setState({serverUrl: event.target.value})}
|
|
351
|
+
/>
|
|
352
|
+
<div className="input-group-btn">
|
|
353
|
+
<button
|
|
354
|
+
className="btn btn-outline-dark"
|
|
355
|
+
disabled={this.state.connectButtonDisabled}
|
|
356
|
+
onClick={() => this.onConnectClick()}>
|
|
357
|
+
{this.state.connectButtonText}
|
|
358
|
+
</button>
|
|
359
|
+
</div>
|
|
360
|
+
</div>
|
|
361
|
+
<div className="text-center" style={{marginTop: '20px'}}>
|
|
362
|
+
<div className={this.state.sessionStatusClass}>{this.state.sessionStatus}</div>
|
|
363
|
+
</div>
|
|
364
|
+
</div>
|
|
365
|
+
</div>
|
|
366
|
+
</div>
|
|
367
|
+
);
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
export default TwoWayStreamingApp;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// eslint-disable-next-line
|
|
2
|
+
'use strict';
|
|
3
|
+
import { constants } from '@flashphoner/websdk';
|
|
4
|
+
const STREAM_STATUS = constants.STREAM_STATUS;
|
|
5
|
+
|
|
6
|
+
// Set default websocket URL
|
|
7
|
+
export function setURL(): string {
|
|
8
|
+
let proto: string;
|
|
9
|
+
let url: string;
|
|
10
|
+
let port: string;
|
|
11
|
+
if (window.location.protocol === "http:") {
|
|
12
|
+
proto = "ws://";
|
|
13
|
+
port = "8080";
|
|
14
|
+
} else {
|
|
15
|
+
proto = "wss://";
|
|
16
|
+
port = "8443";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
url = proto + window.location.hostname + ":" + port;
|
|
20
|
+
return url;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Get URL parameter by name
|
|
24
|
+
export function getUrlParam(name: string): string | null {
|
|
25
|
+
let url = window.location.href;
|
|
26
|
+
// eslint-disable-next-line
|
|
27
|
+
name = name.replace(/[\[\]]/g, "\\$&");
|
|
28
|
+
let regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
|
|
29
|
+
results = regex.exec(url);
|
|
30
|
+
if (!results) return null;
|
|
31
|
+
if (!results[2]) return '';
|
|
32
|
+
return decodeURIComponent(results[2].replace(/\+/g, " "));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Generate simple uuid
|
|
36
|
+
export function createUUID(length: number): string {
|
|
37
|
+
var s = [];
|
|
38
|
+
var hexDigits = "0123456789abcdef";
|
|
39
|
+
for (var i = 0; i < 36; i++) {
|
|
40
|
+
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
|
|
41
|
+
}
|
|
42
|
+
s[14] = "4";
|
|
43
|
+
s[19] = hexDigits.substr((parseInt(s[19], 16) & 0x3) | 0x8, 1);
|
|
44
|
+
s[8] = s[13] = s[18] = s[23] = "-";
|
|
45
|
+
|
|
46
|
+
var uuid = s.join("");
|
|
47
|
+
|
|
48
|
+
return uuid.substring(0, length);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Helper function to downscale picture size
|
|
52
|
+
export function downScaleToFitSize(videoWidth: number, videoHeight: number, dstWidth: number, dstHeight: number): any {
|
|
53
|
+
let newWidth: number, newHeight: number;
|
|
54
|
+
var videoRatio = videoWidth / videoHeight;
|
|
55
|
+
var dstRatio = dstWidth / dstHeight;
|
|
56
|
+
if (dstRatio > videoRatio) {
|
|
57
|
+
newHeight = dstHeight;
|
|
58
|
+
newWidth = Math.floor(videoRatio * dstHeight);
|
|
59
|
+
} else {
|
|
60
|
+
newWidth = dstWidth;
|
|
61
|
+
newHeight = Math.floor(dstWidth / videoRatio);
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
w: newWidth,
|
|
65
|
+
h: newHeight
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Resize video object to fit parent div.
|
|
71
|
+
* Div structure: div WxH -> div wrapper (display) -> video
|
|
72
|
+
* @param video HTML element from resize event target
|
|
73
|
+
*/
|
|
74
|
+
export function resizeVideo(video: any, width?: number, height?: number) {
|
|
75
|
+
if (!video.parentNode) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
let videoWidth = video.width;
|
|
79
|
+
let videoHeight = video.height;
|
|
80
|
+
if (video instanceof HTMLVideoElement) {
|
|
81
|
+
videoWidth = video.videoWidth;
|
|
82
|
+
videoHeight = video.videoHeight;
|
|
83
|
+
}
|
|
84
|
+
var display = video.parentNode;
|
|
85
|
+
var parentSize = {
|
|
86
|
+
w: display.parentNode.clientWidth,
|
|
87
|
+
h: display.parentNode.clientHeight
|
|
88
|
+
};
|
|
89
|
+
let newSize: any;
|
|
90
|
+
if (width && height) {
|
|
91
|
+
newSize = downScaleToFitSize(width, height, parentSize.w, parentSize.h);
|
|
92
|
+
} else {
|
|
93
|
+
newSize = downScaleToFitSize(videoWidth, videoHeight, parentSize.w, parentSize.h);
|
|
94
|
+
}
|
|
95
|
+
display.style.width = newSize.w + "px";
|
|
96
|
+
display.style.height = newSize.h + "px";
|
|
97
|
+
|
|
98
|
+
//vertical align
|
|
99
|
+
let margin = 0;
|
|
100
|
+
if (parentSize.h - newSize.h > 1) {
|
|
101
|
+
margin = Math.floor((parentSize.h - newSize.h) / 2);
|
|
102
|
+
}
|
|
103
|
+
display.style.margin = margin + "px auto";
|
|
104
|
+
console.log("Resize from " + videoWidth + "x" + videoHeight + " to " + display.offsetWidth + "x" + display.offsetHeight);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function isPlaying(streamStatus: string): boolean {
|
|
108
|
+
switch(streamStatus) {
|
|
109
|
+
case STREAM_STATUS.PLAYING:
|
|
110
|
+
case STREAM_STATUS.RESIZE:
|
|
111
|
+
case STREAM_STATUS.SNAPSHOT_COMPLETE:
|
|
112
|
+
case STREAM_STATUS.NOT_ENOUGH_BANDWIDTH:
|
|
113
|
+
return true;
|
|
114
|
+
default:
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
body {
|
|
2
|
+
margin: 0;
|
|
3
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
|
4
|
+
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
|
5
|
+
sans-serif;
|
|
6
|
+
-webkit-font-smoothing: antialiased;
|
|
7
|
+
-moz-osx-font-smoothing: grayscale;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
code {
|
|
11
|
+
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
|
12
|
+
monospace;
|
|
13
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "es5",
|
|
4
|
+
"jsx": "react-jsx",
|
|
5
|
+
"module": "esnext",
|
|
6
|
+
"esModuleInterop": true,
|
|
7
|
+
"forceConsistentCasingInFileNames": true,
|
|
8
|
+
"strict": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"lib": [
|
|
11
|
+
"dom",
|
|
12
|
+
"dom.iterable",
|
|
13
|
+
"esnext"
|
|
14
|
+
],
|
|
15
|
+
"allowJs": true,
|
|
16
|
+
"allowSyntheticDefaultImports": true,
|
|
17
|
+
"noFallthroughCasesInSwitch": true,
|
|
18
|
+
"moduleResolution": "node",
|
|
19
|
+
"resolveJsonModule": true,
|
|
20
|
+
"isolatedModules": true,
|
|
21
|
+
"noEmit": true
|
|
22
|
+
},
|
|
23
|
+
"include": [
|
|
24
|
+
"src"
|
|
25
|
+
]
|
|
26
|
+
}
|