@flashphoner/sfusdk-examples 2.0.56
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 +43 -0
- package/package.json +32 -0
- package/src/client/chat.js +67 -0
- package/src/client/config.json +26 -0
- package/src/client/controls.js +314 -0
- package/src/client/display.js +502 -0
- package/src/client/main.css +45 -0
- package/src/client/main.html +220 -0
- package/src/client/main.js +157 -0
- package/src/client/resources/details_close.png +0 -0
- package/src/client/resources/details_open.png +0 -0
- package/src/client/util.js +67 -0
- package/src/commons/js/config.js +81 -0
- package/src/commons/js/display.js +484 -0
- package/src/commons/js/util.js +202 -0
- package/src/commons/media/silence.mp3 +0 -0
- package/src/controller/dependencies/sigma/sigma.renderers.edgeLabels.min.js +1 -0
- package/src/controller/dependencies/sigma/sigma.renderers.parallelEdges.min.js +1 -0
- package/src/controller/dependencies/sigma/sigma.require.js +12076 -0
- package/src/controller/graph-view.js +32 -0
- package/src/controller/main.css +45 -0
- package/src/controller/main.html +79 -0
- package/src/controller/main.js +65 -0
- package/src/controller/parser.js +202 -0
- package/src/controller/resources/details_close.png +0 -0
- package/src/controller/resources/details_open.png +0 -0
- package/src/controller/rest.js +56 -0
- package/src/controller/table-view.js +64 -0
- package/src/controller/test-data.js +382 -0
- package/src/player/config.json +8 -0
- package/src/player/player.css +19 -0
- package/src/player/player.html +54 -0
- package/src/player/player.js +209 -0
- package/src/sfu.ts +28 -0
- package/src/two-way-streaming/config.json +34 -0
- package/src/two-way-streaming/two-way-streaming.css +26 -0
- package/src/two-way-streaming/two-way-streaming.html +72 -0
- package/src/two-way-streaming/two-way-streaming.js +375 -0
- package/tsconfig.json +15 -0
- package/webpack.config.js +40 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>SFU Client</title>
|
|
7
|
+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/css/bootstrap.min.css" rel="stylesheet"
|
|
8
|
+
integrity="sha384-eOJMYsd53ii+scO/bJGFsiCZc+5NDVN2yr8+0RDqr0Ql0h+rP48ckxlpbzKgwra6" crossorigin="anonymous">
|
|
9
|
+
<!-- JavaScript Bundle with Popper -->
|
|
10
|
+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/js/bootstrap.bundle.min.js"
|
|
11
|
+
integrity="sha384-JEW9xMcG8R+pH31jmWH6WWP0WintQrMb4s7ZOdauHnUtxwoG2vI5DkLtS3qm9Ekf"
|
|
12
|
+
crossorigin="anonymous"></script>
|
|
13
|
+
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js"></script>
|
|
14
|
+
<link href="https://cdn.datatables.net/1.10.24/css/jquery.dataTables.min.css" rel="stylesheet"/>
|
|
15
|
+
<script src="https://cdn.datatables.net/1.10.24/js/jquery.dataTables.min.js"></script>
|
|
16
|
+
<link rel="stylesheet" href="main.css">
|
|
17
|
+
<script type="text/javascript" src="../sfu.js"></script>
|
|
18
|
+
<script type="text/javascript" src="chat.js"></script>
|
|
19
|
+
<script type="text/javascript" src="display.js"></script>
|
|
20
|
+
<script type="text/javascript" src="util.js"></script>
|
|
21
|
+
<script type="text/javascript" src="controls.js"></script>
|
|
22
|
+
<script type="text/javascript" src="main.js"></script>
|
|
23
|
+
</head>
|
|
24
|
+
<body onload="init()">
|
|
25
|
+
<div class="container-fluid" id="main">
|
|
26
|
+
<div id="errorMsg"></div>
|
|
27
|
+
<div class="row border border-primary">
|
|
28
|
+
</div>
|
|
29
|
+
<div class="row border border-primary">
|
|
30
|
+
<!-- ROW 2 config + chat -->
|
|
31
|
+
<div class="col border border-secondary">
|
|
32
|
+
<!-- Tracks console -->
|
|
33
|
+
<ul class="nav nav-tabs" id="tracksTablist" role="tablist">
|
|
34
|
+
<li class="nav-item" role="presentation">
|
|
35
|
+
<button class="nav-link active" id="videoTracksTab" data-bs-toggle="tab" data-bs-target="#videoTracks" type="button" role="tab" aria-controls="videoTracks" aria-selected="true">VideoTracks</button>
|
|
36
|
+
</li>
|
|
37
|
+
<li class="nav-item" role="presentation">
|
|
38
|
+
<button class="nav-link" id="audioTracksTab" data-bs-toggle="tab" data-bs-target="#audioTracks" type="button" role="tab" aria-controls="audioTracks" aria-selected="false">AudioTracks</button>
|
|
39
|
+
</li>
|
|
40
|
+
</ul>
|
|
41
|
+
<div class="tab-content" id="tracksTabContent">
|
|
42
|
+
<div class="tab-pane fade show active mt-2" id="videoTracks" role="tabpanel" aria-labelledby="raw-tab">
|
|
43
|
+
<table class="table" id="videoTracksTable">
|
|
44
|
+
<thead>
|
|
45
|
+
<tr>
|
|
46
|
+
<th></th>
|
|
47
|
+
<th>Source</th>
|
|
48
|
+
<th>Width</th>
|
|
49
|
+
<th>Height</th>
|
|
50
|
+
<th>Codec</th>
|
|
51
|
+
<th>Action</th>
|
|
52
|
+
</tr>
|
|
53
|
+
</thead>
|
|
54
|
+
<tfoot>
|
|
55
|
+
<tr>
|
|
56
|
+
<th></th>
|
|
57
|
+
<th>
|
|
58
|
+
<select class="form-select-sm" id="addVideoTrackSource">
|
|
59
|
+
<option value="camera" selected>camera</option>
|
|
60
|
+
<option value="screen">screen</option>
|
|
61
|
+
</select>
|
|
62
|
+
</th>
|
|
63
|
+
<th>
|
|
64
|
+
<input class="form-control-sm" id="addVideoTrackWidth" type="number" value="1280">
|
|
65
|
+
</th>
|
|
66
|
+
<th>
|
|
67
|
+
<input class="form-control-sm" id="addVideoTrackHeight" type="number" value="720">
|
|
68
|
+
</th>
|
|
69
|
+
<th>
|
|
70
|
+
<select class="form-select-sm" id="addVideoTrackCodec">
|
|
71
|
+
<option value="H264" selected>H264</option>
|
|
72
|
+
<option value="VP8">VP8</option>
|
|
73
|
+
</select>
|
|
74
|
+
</th>
|
|
75
|
+
<th>
|
|
76
|
+
<button class="btn btn-primary" id="addVideoTrack">Add</button>
|
|
77
|
+
</th>
|
|
78
|
+
</tr>
|
|
79
|
+
</tfoot>
|
|
80
|
+
<tbody id="videoTracksTableBody"></tbody>
|
|
81
|
+
</table>
|
|
82
|
+
<div class="row mt-4">
|
|
83
|
+
<div class="col-sm-1"></div>
|
|
84
|
+
<div class="col">
|
|
85
|
+
<table class="table" id="videoTrackEncodingsTable">
|
|
86
|
+
<thead>
|
|
87
|
+
<tr>
|
|
88
|
+
<th>RID</th>
|
|
89
|
+
<th>Active</th>
|
|
90
|
+
<th>MaxBitrate</th>
|
|
91
|
+
<th>ResolutionScale</th>
|
|
92
|
+
<th>Action</th>
|
|
93
|
+
</tr>
|
|
94
|
+
</thead>
|
|
95
|
+
<tfoot>
|
|
96
|
+
<tr>
|
|
97
|
+
<th>
|
|
98
|
+
<select class="form-select-sm" id="addVideoTrackEncodingRid">
|
|
99
|
+
<option value="h" selected>h</option>
|
|
100
|
+
<option value="m">m</option>
|
|
101
|
+
<option value="l">l</option>
|
|
102
|
+
</select>
|
|
103
|
+
</th>
|
|
104
|
+
<th>
|
|
105
|
+
<select class="form-select-sm" id="addVideoTrackEncodingActive">
|
|
106
|
+
<option value="true" selected>true</option>
|
|
107
|
+
<option value="false">false</option>
|
|
108
|
+
</select>
|
|
109
|
+
</th>
|
|
110
|
+
<th>
|
|
111
|
+
<input class="form-control-sm" id="addVideoTrackEncodingMaxBitrate" type="number" value="900000">
|
|
112
|
+
</th>
|
|
113
|
+
<th>
|
|
114
|
+
<select class="form-select-sm" id="addVideoTrackEncodingResolutionScale">
|
|
115
|
+
<option value="1" selected>1</option>
|
|
116
|
+
<option value="2">2</option>
|
|
117
|
+
<option value="4">4</option>
|
|
118
|
+
<option value="6">6</option>
|
|
119
|
+
</select>
|
|
120
|
+
</th>
|
|
121
|
+
<th>
|
|
122
|
+
<button class="btn btn-primary" id="addVideoTrackEncoding">Add</button>
|
|
123
|
+
</th>
|
|
124
|
+
</tr>
|
|
125
|
+
</tfoot>
|
|
126
|
+
<tbody id="videoTrackEncodingsTableBody"></tbody>
|
|
127
|
+
</table>
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
<div class="tab-pane fade" id="audioTracks" role="tabpanel" aria-labelledby="audioTracksTab">
|
|
132
|
+
<table class="table" id="audioTracksTable">
|
|
133
|
+
<caption class="caption-top">Audio tracks</caption>
|
|
134
|
+
<thead>
|
|
135
|
+
<tr>
|
|
136
|
+
<th>Source</th>
|
|
137
|
+
<th>Channels</th>
|
|
138
|
+
<th>Action</th>
|
|
139
|
+
</tr>
|
|
140
|
+
</thead>
|
|
141
|
+
<tfoot>
|
|
142
|
+
<tr>
|
|
143
|
+
<th>
|
|
144
|
+
<select class="form-select-sm" id="addAudioTrackSource">
|
|
145
|
+
<option value="mic" selected>mic</option>
|
|
146
|
+
</select>
|
|
147
|
+
</th>
|
|
148
|
+
<th>
|
|
149
|
+
<select class="form-select-sm" id="addAudioTrackChannels">
|
|
150
|
+
<option value="1" selected>1</option>
|
|
151
|
+
<option value="2">2</option>
|
|
152
|
+
</select>
|
|
153
|
+
</th>
|
|
154
|
+
<th>
|
|
155
|
+
<button id="addAudioTrack" class="btn btn-primary form-control-sm">Add</button>
|
|
156
|
+
</th>
|
|
157
|
+
</tr>
|
|
158
|
+
</tfoot>
|
|
159
|
+
<tbody></tbody>
|
|
160
|
+
</table>
|
|
161
|
+
</div>
|
|
162
|
+
</div>
|
|
163
|
+
</div>
|
|
164
|
+
<div class="col border border-secondary">
|
|
165
|
+
<div id="chat">
|
|
166
|
+
<!-- chat -->
|
|
167
|
+
<div id="messages" style="text-align: left"></div>
|
|
168
|
+
<input id="localMessage" type="text" value="">
|
|
169
|
+
<button id="sendMessage">send</button>
|
|
170
|
+
</div>
|
|
171
|
+
</div>
|
|
172
|
+
</div>
|
|
173
|
+
<div class="row border border-primary">
|
|
174
|
+
<!-- ROW3 local and remote displays -->
|
|
175
|
+
<div class="col border border-secondary">
|
|
176
|
+
<!-- Local display -->
|
|
177
|
+
<div id="localDisplay"></div>
|
|
178
|
+
</div>
|
|
179
|
+
<div class="col border border-secondary">
|
|
180
|
+
<!-- Remote display -->
|
|
181
|
+
<div id="display"></div>
|
|
182
|
+
</div>
|
|
183
|
+
</div>
|
|
184
|
+
</div>
|
|
185
|
+
|
|
186
|
+
<div class="modal" tabindex="-1" id="entranceModal">
|
|
187
|
+
<div class="modal-dialog">
|
|
188
|
+
<div class="modal-content">
|
|
189
|
+
<div class="modal-header">
|
|
190
|
+
<h5 class="modal-title">Room</h5>
|
|
191
|
+
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
192
|
+
</div>
|
|
193
|
+
<div class="modal-body">
|
|
194
|
+
<!-- ROW1 -->
|
|
195
|
+
<div class="row">
|
|
196
|
+
<label for="url">Server url</label>
|
|
197
|
+
<input id="url" type="text" class="form-control" value="ws://127.0.0.1:8080">
|
|
198
|
+
</div>
|
|
199
|
+
<div class="row">
|
|
200
|
+
<label for="roomName">Room name</label>
|
|
201
|
+
<input class="form-control" id="roomName" type="text" value="ROOM1">
|
|
202
|
+
</div>
|
|
203
|
+
<div class="row">
|
|
204
|
+
<label for="roomPin">PIN</label>
|
|
205
|
+
<input class="form-control" id="roomPin" type="text" value="1234">
|
|
206
|
+
</div>
|
|
207
|
+
<div class="row">
|
|
208
|
+
<label for="nickName">Nickname</label>
|
|
209
|
+
<input class="form-control" id="nickName" type="text" value="Bob">
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
<div class="modal-footer">
|
|
213
|
+
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
|
214
|
+
<button class="btn btn-primary" id="startButton" onclick="connect()">Enter</button>
|
|
215
|
+
</div>
|
|
216
|
+
</div>
|
|
217
|
+
</div>
|
|
218
|
+
</div>
|
|
219
|
+
</body>
|
|
220
|
+
</html>
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
const constants = SFU.constants;
|
|
2
|
+
const sfu = SFU;
|
|
3
|
+
let localDisplay;
|
|
4
|
+
let cControls;
|
|
5
|
+
|
|
6
|
+
const defaultConfig = {
|
|
7
|
+
room: {
|
|
8
|
+
url: "wss://127.0.0.1:8888",
|
|
9
|
+
name: "ROOM1",
|
|
10
|
+
pin: "1234",
|
|
11
|
+
nickName: "Alice"
|
|
12
|
+
},
|
|
13
|
+
media: {
|
|
14
|
+
audio: {
|
|
15
|
+
tracks: [
|
|
16
|
+
{
|
|
17
|
+
source: "mic",
|
|
18
|
+
channels: 1
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
video: {
|
|
23
|
+
tracks: [
|
|
24
|
+
{
|
|
25
|
+
source: "camera",
|
|
26
|
+
width: 1280,
|
|
27
|
+
height: 720,
|
|
28
|
+
codec: "H264",
|
|
29
|
+
encodings: [
|
|
30
|
+
{ rid: "h", active: true, maxBitrate: 900000 },
|
|
31
|
+
{ rid: "m", active: true, maxBitrate: 300000, scaleResolutionDownBy: 2 }
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* load config and show entrance modal
|
|
41
|
+
*/
|
|
42
|
+
const init = function() {
|
|
43
|
+
//read config
|
|
44
|
+
$.getJSON("config.json", function(config){
|
|
45
|
+
cControls = createControls(config);
|
|
46
|
+
}).fail(function(){
|
|
47
|
+
//use default config
|
|
48
|
+
cControls = createControls(defaultConfig);
|
|
49
|
+
});
|
|
50
|
+
//create local display to show local streams
|
|
51
|
+
localDisplay = initLocalDisplay(document.getElementById("localDisplay"));
|
|
52
|
+
//open entrance modal
|
|
53
|
+
$('#entranceModal').modal('show');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* connect to server
|
|
58
|
+
*/
|
|
59
|
+
function connect() {
|
|
60
|
+
//hide modal
|
|
61
|
+
$('#entranceModal').modal('hide');
|
|
62
|
+
//disable controls
|
|
63
|
+
cControls.muteInput();
|
|
64
|
+
//create peer connection
|
|
65
|
+
const pc = new RTCPeerConnection();
|
|
66
|
+
//get config object for room creation
|
|
67
|
+
const roomConfig = cControls.roomConfig();
|
|
68
|
+
roomConfig.pc = pc;
|
|
69
|
+
//kick off connect to server and local room creation
|
|
70
|
+
const session = sfu.createRoom(roomConfig);
|
|
71
|
+
session.on(constants.SFU_EVENT.CONNECTED, function() {
|
|
72
|
+
const room = session.room();
|
|
73
|
+
//connected to server
|
|
74
|
+
const chatDiv = document.getElementById('messages');
|
|
75
|
+
const chatInput = document.getElementById('localMessage');
|
|
76
|
+
const chatButton = document.getElementById('sendMessage');
|
|
77
|
+
//create and bind chat to the new room
|
|
78
|
+
createChat(room, chatDiv, chatInput, chatButton);
|
|
79
|
+
|
|
80
|
+
room.on(constants.SFU_ROOM_EVENT.FAILED, function(e) {
|
|
81
|
+
const errField = document.getElementById("errorMsg");
|
|
82
|
+
errField.style.color = "red";
|
|
83
|
+
errField.innerText = e;
|
|
84
|
+
}).on(constants.SFU_ROOM_EVENT.OPERATION_FAILED, function (e) {
|
|
85
|
+
const errField = document.getElementById("errorMsg");
|
|
86
|
+
errField.style.color = "red";
|
|
87
|
+
errField.innerText = e.operation + " failed: " + e.error;
|
|
88
|
+
})
|
|
89
|
+
//setup remote display for showing remote audio/video tracks
|
|
90
|
+
const remoteDisplay = document.getElementById("display");
|
|
91
|
+
initRemoteDisplay(room, remoteDisplay, pc);
|
|
92
|
+
|
|
93
|
+
//get configured local video streams
|
|
94
|
+
let streams = cControls.getVideoStreams();
|
|
95
|
+
//combine local video streams with audio streams
|
|
96
|
+
streams.push.apply(streams, cControls.getAudioStreams());
|
|
97
|
+
let config = {};
|
|
98
|
+
//add our local streams to the room (to PeerConnection)
|
|
99
|
+
streams.forEach(function (s) {
|
|
100
|
+
//add local stream to local display
|
|
101
|
+
localDisplay.add(s.stream.id, "local", s.stream);
|
|
102
|
+
//add each track to PeerConnection
|
|
103
|
+
s.stream.getTracks().forEach((track) => {
|
|
104
|
+
if (s.source === "screen") {
|
|
105
|
+
config[track.id] = s.source;
|
|
106
|
+
}
|
|
107
|
+
addTrackToPeerConnection(pc, s.stream, track, s.encodings);
|
|
108
|
+
subscribeTrackToEndedEvent(room, track, pc);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
//add callback for the new local stream to the local controls
|
|
112
|
+
cControls.onTrack(function (s) {
|
|
113
|
+
let config = {};
|
|
114
|
+
//add local stream to local display
|
|
115
|
+
localDisplay.add(s.stream.id, "local", s.stream);
|
|
116
|
+
//add each track to PeerConnection
|
|
117
|
+
s.stream.getTracks().forEach((track) => {
|
|
118
|
+
if (s.source === "screen") {
|
|
119
|
+
config[track.id] = s.source;
|
|
120
|
+
}
|
|
121
|
+
addTrackToPeerConnection(pc, s.stream, track, s.encodings);
|
|
122
|
+
subscribeTrackToEndedEvent(room, track, pc);
|
|
123
|
+
});
|
|
124
|
+
//kickoff renegotiation
|
|
125
|
+
room.updateState(config);
|
|
126
|
+
});
|
|
127
|
+
//join room
|
|
128
|
+
room.join(config);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const subscribeTrackToEndedEvent = function(room, track, pc) {
|
|
133
|
+
track.addEventListener("ended", function() {
|
|
134
|
+
//track ended, see if we need to cleanup
|
|
135
|
+
let negotiate = false;
|
|
136
|
+
for (const sender of pc.getSenders()) {
|
|
137
|
+
if (sender.track === track) {
|
|
138
|
+
pc.removeTrack(sender);
|
|
139
|
+
//track found, set renegotiation flag
|
|
140
|
+
negotiate = true;
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (negotiate) {
|
|
145
|
+
//kickoff renegotiation
|
|
146
|
+
room.updateState();
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const addTrackToPeerConnection = function(pc, stream, track, encodings) {
|
|
152
|
+
pc.addTransceiver(track, {
|
|
153
|
+
direction: "sendonly",
|
|
154
|
+
streams: [stream],
|
|
155
|
+
sendEncodings: encodings ? encodings : [] //passing encoding types for video simulcast tracks
|
|
156
|
+
});
|
|
157
|
+
}
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
const stripCodecs = function(sdp, codecs) {
|
|
2
|
+
if (!codecs.length) return sdp;
|
|
3
|
+
var sdpArray = sdp.split("\n");
|
|
4
|
+
var codecsArray = codecs.split(",");
|
|
5
|
+
|
|
6
|
+
//search and delete codecs line
|
|
7
|
+
var pt = [];
|
|
8
|
+
var i;
|
|
9
|
+
for (var p = 0; p < codecsArray.length; p++) {
|
|
10
|
+
console.log("Searching for codec " + codecsArray[p]);
|
|
11
|
+
for (i = 0; i < sdpArray.length; i++) {
|
|
12
|
+
if (sdpArray[i].search(new RegExp(codecsArray[p],'i')) !== -1 && sdpArray[i].indexOf("a=rtpmap") === 0) {
|
|
13
|
+
console.log(codecsArray[p] + " detected");
|
|
14
|
+
pt.push(sdpArray[i].match(/[0-9]+/)[0]);
|
|
15
|
+
sdpArray[i] = "";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
if (pt.length) {
|
|
20
|
+
//searching for fmtp
|
|
21
|
+
for (p = 0; p < pt.length; p++) {
|
|
22
|
+
for (i = 0; i < sdpArray.length; i++) {
|
|
23
|
+
if (sdpArray[i].search("a=fmtp:" + pt[p]) !== -1 || sdpArray[i].search("a=rtcp-fb:" + pt[p]) !== -1) {
|
|
24
|
+
sdpArray[i] = "";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
//delete entries from m= line
|
|
30
|
+
for (i = 0; i < sdpArray.length; i++) {
|
|
31
|
+
if (sdpArray[i].search("m=audio") !== -1 || sdpArray[i].search("m=video") !== -1) {
|
|
32
|
+
var mLineSplitted = sdpArray[i].split(" ");
|
|
33
|
+
var newMLine = "";
|
|
34
|
+
for (var m = 0; m < mLineSplitted.length; m++) {
|
|
35
|
+
if (pt.indexOf(mLineSplitted[m].trim()) === -1 || m <= 2) {
|
|
36
|
+
newMLine += mLineSplitted[m];
|
|
37
|
+
if (m < mLineSplitted.length - 1) {
|
|
38
|
+
newMLine = newMLine + " ";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
sdpArray[i] = newMLine;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
//normalize sdp after modifications
|
|
48
|
+
var result = "";
|
|
49
|
+
for (i = 0; i < sdpArray.length; i++) {
|
|
50
|
+
if (sdpArray[i] !== "") {
|
|
51
|
+
result += sdpArray[i] + "\n";
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const stripVideoCodecsExcept = function (sdp, codec) {
|
|
58
|
+
let actualStripCodec = "rtx";
|
|
59
|
+
if (codec === "VP8") {
|
|
60
|
+
actualStripCodec += ",H264";
|
|
61
|
+
} else if (codec === "H264") {
|
|
62
|
+
actualStripCodec += ",VP8";
|
|
63
|
+
} else {
|
|
64
|
+
return sdp;
|
|
65
|
+
}
|
|
66
|
+
return stripCodecs(sdp, actualStripCodec);
|
|
67
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
const getRoomConfig = function(config) {
|
|
2
|
+
let roomConfig = {
|
|
3
|
+
url: config.url || "ws://127.0.0.1:8080",
|
|
4
|
+
roomName: config.name || "ROOM1",
|
|
5
|
+
pin: config.pin || "1234",
|
|
6
|
+
nickname: config.nickName || "User1"
|
|
7
|
+
};
|
|
8
|
+
return roomConfig;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const getVideoStreams = async function(config) {
|
|
12
|
+
let streams = [];
|
|
13
|
+
if (config.media && config.media.video && config.media.video.tracks) {
|
|
14
|
+
streams = await getStreams(config.media.video.tracks);
|
|
15
|
+
}
|
|
16
|
+
return streams;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const getAudioStreams = async function(config) {
|
|
20
|
+
let streams = [];
|
|
21
|
+
if (config.media && config.media.audio && config.media.audio.tracks) {
|
|
22
|
+
streams = await getStreams(config.media.audio.tracks);
|
|
23
|
+
}
|
|
24
|
+
return streams;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const getStreams = async function(tracks) {
|
|
28
|
+
let streams = [];
|
|
29
|
+
for (let track of tracks) {
|
|
30
|
+
let stream = await getMedia(track);
|
|
31
|
+
if (stream) {
|
|
32
|
+
streams.push({
|
|
33
|
+
stream: stream,
|
|
34
|
+
encodings: track.encodings,
|
|
35
|
+
source: track.source
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return streams;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const getMedia = async function(track) {
|
|
43
|
+
//convert to constraints
|
|
44
|
+
let screen = false;
|
|
45
|
+
const constraints= {};
|
|
46
|
+
if (track.source === "mic") {
|
|
47
|
+
//audio
|
|
48
|
+
constraints.audio = {};
|
|
49
|
+
if (track.constraints) {
|
|
50
|
+
constraints.audio = track.constraints;
|
|
51
|
+
}
|
|
52
|
+
if (track.channels && track.channels === 2) {
|
|
53
|
+
constraints.audio.echoCancellation = false;
|
|
54
|
+
constraints.audio.googEchoCancellation = false;
|
|
55
|
+
}
|
|
56
|
+
} else if (track.source === "camera") {
|
|
57
|
+
constraints.video = {};
|
|
58
|
+
if (track.constraints) {
|
|
59
|
+
constraints.video = track.constraints;
|
|
60
|
+
}
|
|
61
|
+
constraints.video.width = track.width;
|
|
62
|
+
constraints.video.height = track.height;
|
|
63
|
+
} else if (track.source === "screen") {
|
|
64
|
+
constraints.video = {};
|
|
65
|
+
if (track.constraints) {
|
|
66
|
+
constraints.video = track.constraints;
|
|
67
|
+
}
|
|
68
|
+
constraints.video.width = track.width;
|
|
69
|
+
constraints.video.height = track.height;
|
|
70
|
+
screen = true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
//get access to a/v
|
|
74
|
+
let stream;
|
|
75
|
+
if (screen) {
|
|
76
|
+
stream = await navigator.mediaDevices.getDisplayMedia(constraints);
|
|
77
|
+
} else {
|
|
78
|
+
stream = await navigator.mediaDevices.getUserMedia(constraints);
|
|
79
|
+
}
|
|
80
|
+
return stream;
|
|
81
|
+
}
|