@reactoo/watchtogether-sdk-js 2.5.14 → 2.5.18
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/dist/watchtogether-sdk.js +8 -8
- package/dist/watchtogether-sdk.min.js +2 -2
- package/example/audio_controls/audio_controls.html +200 -0
- package/example/audio_controls/audiocontrols.js +230 -0
- package/example/index.html +12 -23
- package/package.json +1 -1
- package/src/models/room-session.js +3 -3
- package/src/models/utils.js +26 -38
- package/src/modules/wt-room.js +161 -213
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<title>The Example</title>
|
|
6
|
+
<script src="./audiocontrols.js"></script>
|
|
7
|
+
<script src="../../dist/watchtogether-sdk.js"></script>
|
|
8
|
+
</head>
|
|
9
|
+
<body style="padding: 0; margin: 0; margin-top: 20px">
|
|
10
|
+
|
|
11
|
+
<div style="display: flex">
|
|
12
|
+
<div style="flex: 0 0 50%; text-align: center">
|
|
13
|
+
<div id="input-container" style="display: none">
|
|
14
|
+
<textarea id="input" style="width: 80%; height: 500px; padding: 0"></textarea>
|
|
15
|
+
<br>
|
|
16
|
+
<button onclick="applyAudioControlsObject()" style="width: 80%">Apply audio controls object</button>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
<div style="flex: 0 0 50%; text-align: center">
|
|
20
|
+
<select id="audio-devices" style="width: 80%" onchange="selectedAudioDeviceId = this.value"></select>
|
|
21
|
+
<br>
|
|
22
|
+
<select id="video-devices" style="width: 80%" onchange="selectedVideoDeviceId = this.value"></select>
|
|
23
|
+
<button style="width: 80%" onclick="getDevicesPermissionAndEnumerateDevices()">Enumerate devices</button>
|
|
24
|
+
|
|
25
|
+
<br><br><br><br>
|
|
26
|
+
|
|
27
|
+
<div id="stream-container" style="display: none">
|
|
28
|
+
<div style="width: 80%; margin-left: auto; margin-right: auto">
|
|
29
|
+
<video id="stream" style="width: 100%; height: 300px; background-color: black; object-fit: contain" autoplay></video>
|
|
30
|
+
</div>
|
|
31
|
+
<button style="width: 80%" onclick="attachStream()">Attach stream to video element</button>
|
|
32
|
+
<br>OR<br>
|
|
33
|
+
<label for="room-id">Room ID : </label>
|
|
34
|
+
<input id="room-id" size="35" onchange="roomId = this.value">
|
|
35
|
+
<button style="width: 80%" onclick="sendStreamToRoom()">Send stream to room</button>
|
|
36
|
+
<br>
|
|
37
|
+
<button id="producer-link" style="width: 80%" onclick="goToProducer()">Producer preview</button>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<script>
|
|
43
|
+
let audioControlsObject = {
|
|
44
|
+
enabled: true,
|
|
45
|
+
gain: {
|
|
46
|
+
value: 1,
|
|
47
|
+
decibels: 0
|
|
48
|
+
},
|
|
49
|
+
equalizer: {
|
|
50
|
+
lowshelf: {
|
|
51
|
+
frequency: 220,
|
|
52
|
+
gain: 0
|
|
53
|
+
},
|
|
54
|
+
peaking: {
|
|
55
|
+
frequency: 2400,
|
|
56
|
+
gain: 0,
|
|
57
|
+
q: 0.3,
|
|
58
|
+
qType: "low"
|
|
59
|
+
},
|
|
60
|
+
highshelf: {
|
|
61
|
+
frequency: 12000,
|
|
62
|
+
gain: 0
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
compressor: {
|
|
66
|
+
threshold: 0,
|
|
67
|
+
ratio: 2,
|
|
68
|
+
knee: 2,
|
|
69
|
+
attack: 0.001,
|
|
70
|
+
release: 0.15,
|
|
71
|
+
speed: "medium"
|
|
72
|
+
},
|
|
73
|
+
delay: 0,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
let roomId = "03159020-59a8-4d10-a801-8aef895141a3";
|
|
77
|
+
let sdkInstance = null;
|
|
78
|
+
let roomSession = null;
|
|
79
|
+
|
|
80
|
+
let audioControls = null;
|
|
81
|
+
|
|
82
|
+
let enumeratedAudioDevices = null;
|
|
83
|
+
let enumeratedVideoDevices = null;
|
|
84
|
+
let selectedAudioDeviceId = null;
|
|
85
|
+
let selectedVideoDeviceId = null;
|
|
86
|
+
|
|
87
|
+
const inputContainerElement = document.getElementById('input-container');
|
|
88
|
+
const inputElement = document.getElementById('input');
|
|
89
|
+
const audioDevicesSelectElement = document.getElementById("audio-devices");
|
|
90
|
+
const videoDevicesSelectElement = document.getElementById("video-devices");
|
|
91
|
+
const streamContainerElement = document.getElementById('stream-container');
|
|
92
|
+
const streamElement = document.getElementById('stream');
|
|
93
|
+
const roomIdInputElement = document.getElementById('room-id');
|
|
94
|
+
|
|
95
|
+
document.addEventListener("DOMContentLoaded", function() {
|
|
96
|
+
audioControls = new AudioControls();
|
|
97
|
+
inputElement.value = JSON.stringify(audioControlsObject, null, 2);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
function applyAudioControlsObject() {
|
|
101
|
+
audioControlsObject = JSON.parse(inputElement.value);
|
|
102
|
+
audioControls.setParametersFromAudioControlsObject(audioControlsObject);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function enumerateDevices() {
|
|
106
|
+
enumeratedAudioDevices = [];
|
|
107
|
+
|
|
108
|
+
return navigator.mediaDevices.enumerateDevices()
|
|
109
|
+
.then(devices => {
|
|
110
|
+
enumeratedAudioDevices = [];
|
|
111
|
+
enumeratedVideoDevices = [];
|
|
112
|
+
|
|
113
|
+
devices.forEach(device => {
|
|
114
|
+
const deviceDetail = {
|
|
115
|
+
id: device.deviceId,
|
|
116
|
+
label: device.label
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
if (device.kind === 'audioinput') {
|
|
120
|
+
enumeratedAudioDevices.push(deviceDetail);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (device.kind === 'videoinput') {
|
|
124
|
+
enumeratedVideoDevices.push(deviceDetail);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function getUserMedia(audioDeviceId, videoDeviceId) {
|
|
131
|
+
const constraints = {
|
|
132
|
+
audio: audioDeviceId ? {deviceId: {exact: audioDeviceId}} : true,
|
|
133
|
+
video: {frameRate: {ideal: 10, max: 20}, width: {ideal: 320, max: 480}, height: {ideal: 240, max: 360}}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
if (videoDeviceId) {
|
|
137
|
+
constraints.video.deviceId = {exact: videoDeviceId};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return navigator.mediaDevices.getUserMedia(constraints);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function getDevicesPermissionAndEnumerateDevices() {
|
|
144
|
+
getUserMedia()
|
|
145
|
+
.then(stream => stream.getTracks().forEach(key => stream.removeTrack(key)))
|
|
146
|
+
.then(() => enumerateDevices())
|
|
147
|
+
.then(() => {
|
|
148
|
+
while (audioDevicesSelectElement.firstChild) {
|
|
149
|
+
audioDevicesSelectElement.removeChild(audioDevicesSelectElement.lastChild);
|
|
150
|
+
}
|
|
151
|
+
while (videoDevicesSelectElement.firstChild) {
|
|
152
|
+
videoDevicesSelectElement.removeChild(videoDevicesSelectElement.lastChild);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
enumeratedAudioDevices.forEach(device => {
|
|
156
|
+
const optionElement = document.createElement('option');
|
|
157
|
+
optionElement.value = device.id;
|
|
158
|
+
optionElement.innerHTML = device.label;
|
|
159
|
+
audioDevicesSelectElement.appendChild(optionElement);
|
|
160
|
+
});
|
|
161
|
+
enumeratedVideoDevices.forEach(device => {
|
|
162
|
+
const optionElement = document.createElement('option');
|
|
163
|
+
optionElement.value = device.id;
|
|
164
|
+
optionElement.innerHTML = device.label;
|
|
165
|
+
videoDevicesSelectElement.appendChild(optionElement);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
inputContainerElement.style.display = "block";
|
|
169
|
+
streamContainerElement.style.display = "block";
|
|
170
|
+
|
|
171
|
+
roomIdInputElement.value = roomId;
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function attachStream () {
|
|
176
|
+
getUserMedia(selectedAudioDeviceId, selectedVideoDeviceId).then(stream => {
|
|
177
|
+
streamElement.srcObject = audioControls.setStream(stream);
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function sendStreamToRoom () {
|
|
182
|
+
getUserMedia(selectedAudioDeviceId, selectedVideoDeviceId).then(stream => {
|
|
183
|
+
sdkInstance = WatchTogetherSDK({debug:true, storagePrefix: "user_1"})();
|
|
184
|
+
sdkInstance.auth.deviceLogin("user_1")
|
|
185
|
+
.then(() => sdkInstance.room.createSession({roomId}))
|
|
186
|
+
.then(session => {
|
|
187
|
+
roomSession = session;
|
|
188
|
+
return Promise.all([session, session.connect()])
|
|
189
|
+
})
|
|
190
|
+
.then(([session, _]) => session.publishLocal(audioControls.setStream(stream), {getStreamIfEmpty: false}));
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function goToProducer() {
|
|
195
|
+
window.open('https://producer.reactoo.com/#/detail/room-monitor/' + roomId, '_blank').focus();
|
|
196
|
+
}
|
|
197
|
+
</script>
|
|
198
|
+
|
|
199
|
+
</body>
|
|
200
|
+
</html>
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
// https://createjs.com/docs/soundjs/files/soundjs_webaudio_WebAudioPlugin.js.html
|
|
2
|
+
// https://mdn.github.io/webaudio-examples/compressor-example/
|
|
3
|
+
// https://codepen.io/webciter/pen/WNbPyrY
|
|
4
|
+
|
|
5
|
+
let ac = window.AudioContext || window.webkitAudioContext;
|
|
6
|
+
|
|
7
|
+
class AudioControls {
|
|
8
|
+
|
|
9
|
+
audioContext;
|
|
10
|
+
|
|
11
|
+
eventListeners;
|
|
12
|
+
|
|
13
|
+
streamSource;
|
|
14
|
+
gainNode;
|
|
15
|
+
equalizerNodes; // List of nodes
|
|
16
|
+
compressorNode;
|
|
17
|
+
delayNode;
|
|
18
|
+
streamDestination;
|
|
19
|
+
|
|
20
|
+
gainDefaultParameters = {
|
|
21
|
+
gain: 1
|
|
22
|
+
};
|
|
23
|
+
// frequency - The middle of the frequency range getting a boost or an attenuation.
|
|
24
|
+
// Q (only applied to peaking, others ignore it) - from 0.0001 to 1000 - The width of the frequency band. The greater the Q value, the smaller the frequency band.
|
|
25
|
+
// gain - from -40 to 40 db - The boost, in dB, to be applied; if negative, it will be an attenuation.
|
|
26
|
+
// type - must be read only
|
|
27
|
+
equalizerDefaultParameters = [
|
|
28
|
+
{frequency: 220, gain: 0, type: 'lowshelf'}, // Frequencies lower than the frequency get a boost, or an attenuation; frequencies over it are unchanged.
|
|
29
|
+
{frequency: 2400, gain: 0, type: 'peaking', Q: 0.3}, // Frequencies inside the range get a boost or an attenuation; frequencies outside it are unchanged.
|
|
30
|
+
{frequency: 12000, gain: 0, type: 'highshelf'} // Frequencies higher than the frequency get a boost or an attenuation; frequencies lower than it are unchanged
|
|
31
|
+
];
|
|
32
|
+
compressorDefaultParameters = {
|
|
33
|
+
threshold: 0, // from -100 to 0 0 - compression will start at 0db - no compression
|
|
34
|
+
knee: 30, // from 0 to 40 0 - hard knee - no smooth transition to compression
|
|
35
|
+
ratio: 2, // from 1 to 20 1 - ratio 1:1 will not affect anything
|
|
36
|
+
attack: 0.001, // from 0 to 1 0 - no time required to reduce the gain by 10 dB
|
|
37
|
+
release: 0.15, // from 0 to 1 0 - no time required to increase the gain by 10 dB
|
|
38
|
+
};
|
|
39
|
+
delayDefaultParameters = {
|
|
40
|
+
delay: 0
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
constructor() {
|
|
44
|
+
this.audioContext = new ac();
|
|
45
|
+
|
|
46
|
+
this.streamDestination = this.audioContext.createMediaStreamDestination();
|
|
47
|
+
|
|
48
|
+
this.delayNode = this.audioContext.createDelay(179);
|
|
49
|
+
this.setDelay(this.delayDefaultParameters.delay);
|
|
50
|
+
this.delayNode.connect(this.streamDestination);
|
|
51
|
+
|
|
52
|
+
this.compressorNode = this.audioContext.createDynamicsCompressor();
|
|
53
|
+
this.setCompressorParameters(this.compressorDefaultParameters);
|
|
54
|
+
this.compressorNode.connect(this.delayNode);
|
|
55
|
+
|
|
56
|
+
this.equalizerNodes = this.equalizerDefaultParameters.map( parameters => {
|
|
57
|
+
const biquadFilter = this.audioContext.createBiquadFilter();
|
|
58
|
+
biquadFilter.type = parameters.type;
|
|
59
|
+
|
|
60
|
+
return biquadFilter;
|
|
61
|
+
});
|
|
62
|
+
this.equalizerDefaultParameters.forEach( parameters => {
|
|
63
|
+
this.setEqualizerParameters(parameters);
|
|
64
|
+
});
|
|
65
|
+
this.equalizerNodes.forEach( (node, nodeIndex) => {
|
|
66
|
+
if (nodeIndex < this.equalizerNodes.length - 1) {
|
|
67
|
+
node.connect(this.equalizerNodes[nodeIndex + 1]);
|
|
68
|
+
} else {
|
|
69
|
+
node.connect(this.compressorNode);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
this.gainNode = this.audioContext.createGain();
|
|
74
|
+
this.setGain(this.gainDefaultParameters.gain);
|
|
75
|
+
this.gainNode.connect(this.equalizerNodes[0]);
|
|
76
|
+
|
|
77
|
+
this.streamSource = null;
|
|
78
|
+
|
|
79
|
+
this.eventListeners = {};
|
|
80
|
+
|
|
81
|
+
document.body.addEventListener('click', () => {
|
|
82
|
+
this.resume();
|
|
83
|
+
}, { once: true });
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
emit (label, ...args) {
|
|
87
|
+
let callbacks = this.eventListeners[label];
|
|
88
|
+
if(callbacks) {
|
|
89
|
+
callbacks.forEach(callback => callback.apply(null, args))
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
addEventListener (event, fn) {
|
|
94
|
+
if(!this.eventListeners[event]) {
|
|
95
|
+
this.eventListeners[event] = []
|
|
96
|
+
}
|
|
97
|
+
this.eventListeners[event].push(fn);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
removeEventListener (event, fn) {
|
|
101
|
+
if(!this.eventListeners[event]) {
|
|
102
|
+
return
|
|
103
|
+
}
|
|
104
|
+
let index = this.eventListeners[event].findIndex(listener => listener === fn);
|
|
105
|
+
if(index > -1) {
|
|
106
|
+
this.eventListeners[event].splice(index, 1);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
clearEventListeners () {
|
|
111
|
+
for(let key in this.eventListeners) {
|
|
112
|
+
this.eventListeners[key].length = 0;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
render() {
|
|
117
|
+
this.drawId = setTimeout(() => {
|
|
118
|
+
this.emit('compressorReduction', this.compressorNode.reduction);
|
|
119
|
+
this.render();
|
|
120
|
+
}, 1000 / 10)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
startRenderLoop() {
|
|
124
|
+
clearTimeout(this.drawId);
|
|
125
|
+
this.render();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
stopRenderLoop() {
|
|
129
|
+
clearTimeout(this.drawId);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
setStream(stream) {
|
|
133
|
+
if (this.streamSource) {
|
|
134
|
+
this.streamSource.disconnect(this.gainNode);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
this.streamSource = this.audioContext.createMediaStreamSource(stream);
|
|
138
|
+
this.streamSource.connect(this.gainNode);
|
|
139
|
+
|
|
140
|
+
this.resume();
|
|
141
|
+
|
|
142
|
+
// this.streamDestination.stream.getVideoTracks().forEach(t => this.streamDestination.stream.removeTrack(t));
|
|
143
|
+
// stream.getVideoTracks().forEach(t => {
|
|
144
|
+
// this.streamDestination.stream.addTrack(t)
|
|
145
|
+
// });
|
|
146
|
+
// return this.streamDestination.stream;
|
|
147
|
+
|
|
148
|
+
const finalStream = new MediaStream();
|
|
149
|
+
|
|
150
|
+
const [videotrack] = stream.getVideoTracks();
|
|
151
|
+
if(videotrack) {
|
|
152
|
+
finalStream.addTrack(videotrack);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const [audiotrack] = this.streamDestination.stream.getAudioTracks();
|
|
156
|
+
if(audiotrack) {
|
|
157
|
+
finalStream.addTrack(audiotrack);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// https://stackoverflow.com/a/63844077
|
|
161
|
+
// new Audio().srcObject = stream;
|
|
162
|
+
// new Audio().srcObject = finalStream;
|
|
163
|
+
|
|
164
|
+
return finalStream;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
resume() {
|
|
168
|
+
if (this.audioContext.state === 'suspended') {
|
|
169
|
+
this.audioContext.resume();
|
|
170
|
+
this.startRenderLoop();
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
setGain(gain) {
|
|
175
|
+
this.gainNode.gain.setValueAtTime(gain, Math.floor(this.audioContext.currentTime));
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
setEqualizerParameters(equalizerParameters, nodeType) {
|
|
179
|
+
const nodeIndex = ['lowshelf', 'peaking', 'highshelf'].findIndex(e => e === nodeType || e === equalizerParameters.type);
|
|
180
|
+
|
|
181
|
+
if (nodeIndex !== -1) {
|
|
182
|
+
['frequency', 'gain', 'Q'].forEach( parameterName => {
|
|
183
|
+
if (equalizerParameters.hasOwnProperty(parameterName) && equalizerParameters[parameterName] !== undefined) {
|
|
184
|
+
this.equalizerNodes[nodeIndex][parameterName].value = equalizerParameters[parameterName];
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
setCompressorParameters(compressorParameters) {
|
|
191
|
+
['threshold', 'knee', 'ratio', 'attack', 'release'].forEach( parameterName => {
|
|
192
|
+
if (compressorParameters.hasOwnProperty(parameterName) && compressorParameters[parameterName] !== undefined) {
|
|
193
|
+
this.compressorNode[parameterName].value = compressorParameters[parameterName];
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
setDelay(delay) {
|
|
199
|
+
this.delayNode.delayTime.setValueAtTime(delay, Math.floor(this.audioContext.currentTime));
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
setParametersFromAudioControlsObject(audioControlsObject) {
|
|
203
|
+
if (audioControlsObject.enabled) {
|
|
204
|
+
this.setGain(audioControlsObject.gain.value);
|
|
205
|
+
Object.keys(audioControlsObject.equalizer)
|
|
206
|
+
.forEach(type => this.setEqualizerParameters(audioControlsObject.equalizer[type], type));
|
|
207
|
+
this.setCompressorParameters(audioControlsObject.compressor);
|
|
208
|
+
this.setDelay(audioControlsObject.delay);
|
|
209
|
+
} else {
|
|
210
|
+
this.setGain(this.gainDefaultParameters.gain);
|
|
211
|
+
this.equalizerDefaultParameters
|
|
212
|
+
.forEach( p => this.setEqualizerParameters(p));
|
|
213
|
+
this.setCompressorParameters(this.compressorDefaultParameters);
|
|
214
|
+
this.setDelay(0);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
destroy() {
|
|
219
|
+
this.stopRenderLoop();
|
|
220
|
+
this.streamSource.disconnect(this.gainNode);
|
|
221
|
+
this.audioContext.close();
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Uncomment this to use in VUE
|
|
226
|
+
// export default {
|
|
227
|
+
// install: function(Vue) {
|
|
228
|
+
// Object.defineProperty(Vue.prototype, '$audiocontrols', { value: AudioControls });
|
|
229
|
+
// }
|
|
230
|
+
// }
|
package/example/index.html
CHANGED
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
<button onclick="unpublish()">unpublish</button>
|
|
18
18
|
<button onclick="toggleVideo()">toggle video</button>
|
|
19
19
|
<button onclick="toggleAudio()">toggle audio</button>
|
|
20
|
-
<button onclick="setRoom()">gulugulu</button>
|
|
21
20
|
</div>
|
|
22
21
|
|
|
23
22
|
</div>
|
|
@@ -71,47 +70,35 @@
|
|
|
71
70
|
|
|
72
71
|
|
|
73
72
|
function disconnectRoom() {
|
|
74
|
-
Instance.room.getSessionByConstructId(constructId)
|
|
75
|
-
.then(session => session.disconnect());
|
|
73
|
+
Instance.room.getSessionByConstructId(constructId).disconnect()
|
|
76
74
|
}
|
|
77
75
|
|
|
78
76
|
function startRoom() {
|
|
79
|
-
Instance.room.getSessionByConstructId(constructId)
|
|
80
|
-
|
|
81
|
-
.then(() => Instance.
|
|
82
|
-
.then(
|
|
77
|
+
let sess = Instance.room.getSessionByConstructId(constructId);
|
|
78
|
+
sess.connect()
|
|
79
|
+
.then(() => Instance.utils.getUserStream({hasVideo:true}))
|
|
80
|
+
.then((stream) => sess.publishLocal(stream))
|
|
83
81
|
}
|
|
84
82
|
|
|
85
83
|
function unpublish() {
|
|
86
|
-
Instance.room.getSessionByConstructId(constructId)
|
|
87
|
-
.then(session => session.unpublishLocal());
|
|
84
|
+
Instance.room.getSessionByConstructId(constructId).unpublishLocal()
|
|
88
85
|
}
|
|
89
86
|
|
|
90
87
|
function publish() {
|
|
91
|
-
Instance.room.getSessionByConstructId(constructId)
|
|
92
|
-
.then(session => session.publishLocal(null, {unpublishFirst:true}));
|
|
88
|
+
Instance.room.getSessionByConstructId(constructId).publishLocal(null, {unpublishFirst:true})
|
|
93
89
|
|
|
94
90
|
}
|
|
95
91
|
|
|
96
92
|
function toggleVideo() {
|
|
97
|
-
Instance.room.getSessionByConstructId(constructId)
|
|
98
|
-
.then(session => session.toggleVideo());
|
|
93
|
+
Instance.room.getSessionByConstructId(constructId).toggleVideo()
|
|
99
94
|
}
|
|
100
95
|
|
|
101
96
|
function toggleAudio() {
|
|
102
|
-
Instance.room.getSessionByConstructId(constructId)
|
|
103
|
-
.then(session => session.toggleAudio());
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function setRoom() {
|
|
107
|
-
Instance.room.updateRoom({roomId, isPublic: false})
|
|
97
|
+
Instance.room.getSessionByConstructId(constructId).toggleAudio()
|
|
108
98
|
}
|
|
109
99
|
|
|
110
100
|
let Instance = WatchTogetherSDK({debug:true})({instanceType:'reactooDemo'});
|
|
111
101
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
102
|
Instance.auth.$on('login', () => {
|
|
116
103
|
console.log('We are in');
|
|
117
104
|
});
|
|
@@ -160,7 +147,9 @@
|
|
|
160
147
|
})
|
|
161
148
|
|
|
162
149
|
})
|
|
163
|
-
.then(r => Instance.room.createSession({constructId, roomId:r.roomId, pinHash: r.pinHash
|
|
150
|
+
.then(r => Instance.room.createSession({constructId, roomId:r.roomId, pinHash: r.pinHash, options: {
|
|
151
|
+
//subscriptionRules: {participant: {videoWall: [], watchTogether: []}}
|
|
152
|
+
}})) // pin hash is not needed if you're owner of the room
|
|
164
153
|
.then(session => {
|
|
165
154
|
|
|
166
155
|
session.$on('connecting', (status) => {
|
package/package.json
CHANGED
|
@@ -35,7 +35,7 @@ let roomSession = function ({roomId, pinHash, isTalkback, isMonitor, isInstructo
|
|
|
35
35
|
|
|
36
36
|
room.on('addLocalParticipant', () => {
|
|
37
37
|
|
|
38
|
-
// TODO: this doesnt seem to be fixable until we switch to
|
|
38
|
+
// TODO: this doesnt seem to be fixable until we switch to different type of messaging
|
|
39
39
|
// At some random case we don't get message back if we don't wait
|
|
40
40
|
|
|
41
41
|
clearTimeout(alpTimeoutId);
|
|
@@ -189,10 +189,10 @@ let roomSession = function ({roomId, pinHash, isTalkback, isMonitor, isInstructo
|
|
|
189
189
|
}
|
|
190
190
|
},
|
|
191
191
|
|
|
192
|
-
renderPlayer: function (playerWrapper, fullscreenElement) {
|
|
192
|
+
renderPlayer: function (playerWrapper, fullscreenElement, roomId) {
|
|
193
193
|
try {
|
|
194
194
|
this.syncModule = syncUniversal({room, wt, roomSession: this, emitter});
|
|
195
|
-
this.playerInterface = wt.__privates.playerFactory(playerWrapper, fullscreenElement, this.syncModule.getHandlers(), {roomId
|
|
195
|
+
this.playerInterface = wt.__privates.playerFactory(playerWrapper, fullscreenElement, this.syncModule.getHandlers(), {roomId});
|
|
196
196
|
this.syncModule.initialize({playerInterface: this.playerInterface});
|
|
197
197
|
return true;
|
|
198
198
|
} catch (e) {
|
package/src/models/utils.js
CHANGED
|
@@ -1,44 +1,32 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
export default {
|
|
4
|
-
getUserStream(hasVideo, isHd, aDeviceId, vDeviceId, lfps,
|
|
5
|
-
let fullConstraints
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
},
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
};
|
|
32
|
-
audioOnlyConstraints = {
|
|
33
|
-
audio: {
|
|
34
|
-
...(aDeviceId && {deviceId: {exact:aDeviceId}}),
|
|
35
|
-
autoGainControl: false,
|
|
36
|
-
echoCancellation: true,
|
|
37
|
-
noiseSuppression: true,
|
|
38
|
-
channelCount: 1
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
}
|
|
4
|
+
getUserStream({hasVideo, isHd, aDeviceId, vDeviceId, lfps, autoGainControl = false, muteAudio = false, muteVideo = false} = {}) {
|
|
5
|
+
let fullConstraints = {
|
|
6
|
+
audio: {
|
|
7
|
+
...(aDeviceId && {deviceId: {exact:aDeviceId}}),
|
|
8
|
+
autoGainControl,
|
|
9
|
+
echoCancellation: true,
|
|
10
|
+
noiseSuppression: true,
|
|
11
|
+
channelCount: 1
|
|
12
|
+
},
|
|
13
|
+
video: {
|
|
14
|
+
...(vDeviceId && {deviceId: {exact:vDeviceId}}),
|
|
15
|
+
facingMode: {ideal: "user"},
|
|
16
|
+
...(lfps ? {frameRate: { ideal: 10, max: 30 }} : {frameRate: { ideal: 24, max: 30 }}),
|
|
17
|
+
width: {ideal: isHd ? 1280 : 320},
|
|
18
|
+
height: {ideal: isHd ? 720 : 240},
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
let audioOnlyConstraints = {
|
|
22
|
+
audio: {
|
|
23
|
+
...(aDeviceId && {deviceId: {exact:aDeviceId}}),
|
|
24
|
+
autoGainControl,
|
|
25
|
+
echoCancellation: true,
|
|
26
|
+
noiseSuppression: true,
|
|
27
|
+
channelCount: 1
|
|
28
|
+
}
|
|
29
|
+
};
|
|
42
30
|
|
|
43
31
|
return navigator.mediaDevices.getUserMedia(hasVideo ? fullConstraints : audioOnlyConstraints)
|
|
44
32
|
.then(stream => {
|