@live-change/peer-connection-frontend 0.8.87 → 0.8.89
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/front/src/components/DeviceSelect.vue +65 -31
- package/front/src/components/userMedia.js +36 -3
- package/index.js +3 -2
- package/package.json +16 -16
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
<div class>Please connect camera.</div>
|
|
10
10
|
<audio v-if="model?.audioInput?.deviceId" ref="outputElement"
|
|
11
11
|
autoplay playsinline :muted="userMediaMuted"
|
|
12
|
-
:src-object.prop.camel="
|
|
12
|
+
:src-object.prop.camel="model.media">
|
|
13
13
|
</audio>
|
|
14
14
|
</div>
|
|
15
15
|
<div v-else class="bg-black-alpha-90 flex align-items-center justify-content-center">
|
|
16
|
-
<video v-if="
|
|
17
|
-
:src-object.prop.camel="
|
|
16
|
+
<video v-if="model.media" autoplay playsinline :muted="userMediaMuted" ref="outputElement"
|
|
17
|
+
:src-object.prop.camel="model.media"
|
|
18
18
|
class="max-w-full max-h-full" style="object-fit: contain; transform: scaleX(-1)">
|
|
19
19
|
</video>
|
|
20
20
|
</div>
|
|
@@ -50,9 +50,9 @@
|
|
|
50
50
|
<CameraButton v-model="model" @disabled-video-click="handleDisabledVideoClick" />
|
|
51
51
|
</div>
|
|
52
52
|
</div>
|
|
53
|
-
<div class="absolute top-0 right-0" v-if="
|
|
53
|
+
<div class="absolute top-0 right-0" v-if="model.media">
|
|
54
54
|
<div class="m-3">
|
|
55
|
-
<VolumeIndicator :stream="
|
|
55
|
+
<VolumeIndicator :stream="model.media" />
|
|
56
56
|
</div>
|
|
57
57
|
</div>
|
|
58
58
|
|
|
@@ -146,7 +146,7 @@
|
|
|
146
146
|
|
|
147
147
|
<pre>DEV: {{ devices }}</pre>
|
|
148
148
|
|
|
149
|
-
<pre>UM: {{
|
|
149
|
+
<pre>UM: {{ model.media }}</pre>-->
|
|
150
150
|
|
|
151
151
|
</div>
|
|
152
152
|
</template>
|
|
@@ -168,12 +168,13 @@
|
|
|
168
168
|
|
|
169
169
|
import { defineProps, defineModel, computed, ref, toRefs, onMounted, watch, watchEffect } from 'vue'
|
|
170
170
|
import { useIntervalFn, useEventListener } from "@vueuse/core"
|
|
171
|
-
import {
|
|
172
|
-
|
|
171
|
+
import {
|
|
172
|
+
getUserMedia as getUserMediaNative, getDisplayMedia as getDisplayMediaNative,
|
|
173
|
+
isUserMediaPermitted, stopMedia
|
|
174
|
+
} from "./userMedia.js"
|
|
173
175
|
import MicrophoneButton from './MicrophoneButton.vue'
|
|
174
176
|
import CameraButton from './CameraButton.vue'
|
|
175
177
|
|
|
176
|
-
|
|
177
178
|
const props = defineProps({
|
|
178
179
|
audioInputRequest: {
|
|
179
180
|
type: String,
|
|
@@ -247,24 +248,58 @@
|
|
|
247
248
|
const videoInputs = computed(() => devices.value.filter(device => device.kind === 'videoinput'))
|
|
248
249
|
|
|
249
250
|
watch(audioInputs, (value) => {
|
|
251
|
+
if(value.length === 0) return
|
|
252
|
+
if(model.value?.audioInput) {
|
|
253
|
+
const exists = value.find(device => device.deviceId === model.value.audioInput.deviceId)
|
|
254
|
+
if(exists) return
|
|
255
|
+
}
|
|
250
256
|
model.value = {
|
|
251
257
|
...model.value,
|
|
252
258
|
audioInput: value[0]
|
|
253
259
|
}
|
|
254
260
|
}, { immediate: true })
|
|
255
261
|
watch(audioOutputs, (value) => {
|
|
262
|
+
if(value.length === 0) return
|
|
263
|
+
if(model.value?.audioOutput) {
|
|
264
|
+
const exists = value.find(device => device.deviceId === model.value.audioOutput.deviceId)
|
|
265
|
+
if(exists) return
|
|
266
|
+
}
|
|
256
267
|
model.value = {
|
|
257
268
|
...model.value,
|
|
258
269
|
audioOutput: value[0]
|
|
259
270
|
}
|
|
260
271
|
}, { immediate: true })
|
|
261
272
|
watch(videoInputs, (value) => {
|
|
273
|
+
if(value.length === 0) return
|
|
274
|
+
if(model.value?.videoInput) {
|
|
275
|
+
const exists = value.find(device => device.deviceId === model.value.videoInput.deviceId)
|
|
276
|
+
if(exists) return
|
|
277
|
+
}
|
|
262
278
|
model.value = {
|
|
263
279
|
...model.value,
|
|
264
280
|
videoInput: value[0]
|
|
265
281
|
}
|
|
266
282
|
}, { immediate: true })
|
|
267
283
|
|
|
284
|
+
/* watch(model.value, (v) => {
|
|
285
|
+
console.trace("MODEL CHANGED", v)
|
|
286
|
+
if(typeof v.audioInput === 'string') throw new Error("AUDIO INPUT IS STRING")
|
|
287
|
+
if(typeof v.audioOutput === 'string') throw new Error("AUDIO OUTPUT IS STRING")
|
|
288
|
+
if(typeof v.videoInput === 'string') throw new Error("VIDEO INPUT IS STRING")
|
|
289
|
+
}, { immediate: true, deep: true })*/
|
|
290
|
+
|
|
291
|
+
function setUserMedia(media) {
|
|
292
|
+
if(media === model.value.media) return
|
|
293
|
+
console.log("MEDIA STREAM CHANGE", media, 'FROM', model.value.media)
|
|
294
|
+
if(model.value.media) {
|
|
295
|
+
stopMedia(model.value.media)
|
|
296
|
+
}
|
|
297
|
+
model.value = {
|
|
298
|
+
...model.value,
|
|
299
|
+
media
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
268
303
|
/* onMounted(() => {
|
|
269
304
|
if(!model.value?.audioInput || !model.value?.audioOutput || !model.value?.videoInput) {
|
|
270
305
|
console.log("AUTO SELECT", audioInputs.value)
|
|
@@ -297,18 +332,12 @@
|
|
|
297
332
|
}
|
|
298
333
|
}, { immediate: true })
|
|
299
334
|
|
|
300
|
-
const userMedia = ref(null)
|
|
301
335
|
let gettingUserMedia = false
|
|
302
336
|
async function updateUserMedia(retry = false) {
|
|
337
|
+
console.log("USER MEDIA UPDATE WHEN MODEL IS", model.value)
|
|
303
338
|
if(gettingUserMedia) return
|
|
304
339
|
gettingUserMedia = true
|
|
305
340
|
try {
|
|
306
|
-
if(userMedia.value && !retry) {
|
|
307
|
-
console.log("CLOSE USER MEDIA")
|
|
308
|
-
userMedia.value.getTracks().forEach(track => track.stop())
|
|
309
|
-
userMedia.value = null
|
|
310
|
-
await new Promise(resolve => setTimeout(resolve, 100))
|
|
311
|
-
}
|
|
312
341
|
const constraints = selectedConstraints.value
|
|
313
342
|
const videoAllowed = videoInputRequest.value !== 'none' && constraints.video
|
|
314
343
|
const audioAllowed = audioInputRequest.value !== 'none' && constraints.audio
|
|
@@ -327,7 +356,7 @@
|
|
|
327
356
|
await new Promise(resolve => setTimeout(resolve, 100))
|
|
328
357
|
}*/
|
|
329
358
|
console.log("Got User Media", mediaStream)
|
|
330
|
-
|
|
359
|
+
setUserMedia(mediaStream)
|
|
331
360
|
if(model.value.cameraAccessError || model.value.mediaError) {
|
|
332
361
|
model.value = {
|
|
333
362
|
...model.value,
|
|
@@ -353,7 +382,7 @@
|
|
|
353
382
|
video: false
|
|
354
383
|
})
|
|
355
384
|
console.log("Got User Media 2", mediaStream)
|
|
356
|
-
|
|
385
|
+
setUserMedia(mediaStream)
|
|
357
386
|
} catch(error) {
|
|
358
387
|
model.value = {
|
|
359
388
|
...model.value,
|
|
@@ -369,6 +398,8 @@
|
|
|
369
398
|
}
|
|
370
399
|
} else if(error.name === 'PermissionDeniedError') {
|
|
371
400
|
showPermissionsDialog()
|
|
401
|
+
} else if(error.name === 'NotAllowedError') {
|
|
402
|
+
showPermissionsDialog()
|
|
372
403
|
} else {
|
|
373
404
|
model.value = {
|
|
374
405
|
...model.value,
|
|
@@ -381,7 +412,15 @@
|
|
|
381
412
|
}
|
|
382
413
|
}
|
|
383
414
|
|
|
384
|
-
watch(() => selectedConstraints.value, () =>
|
|
415
|
+
watch(() => selectedConstraints.value, (constraints, oldConstraints) => {
|
|
416
|
+
console.log("CONSTRAINTS CHANGED FROM", oldConstraints, 'TO', constraints)
|
|
417
|
+
updateUserMedia()
|
|
418
|
+
})
|
|
419
|
+
onMounted(() => {
|
|
420
|
+
if(!model.value.media) {
|
|
421
|
+
updateUserMedia()
|
|
422
|
+
}
|
|
423
|
+
})
|
|
385
424
|
|
|
386
425
|
useIntervalFn(() => {
|
|
387
426
|
if(!retryMediaOnError.value) return
|
|
@@ -392,19 +431,12 @@
|
|
|
392
431
|
|
|
393
432
|
const userMediaMuted = true
|
|
394
433
|
|
|
395
|
-
watch(() => userMedia.value, stream => {
|
|
396
|
-
console.log("MEDIA STREAM CHANGE", stream)
|
|
397
|
-
model.value = {
|
|
398
|
-
...model.value,
|
|
399
|
-
media: stream
|
|
400
|
-
}
|
|
401
|
-
})
|
|
402
434
|
|
|
403
435
|
watchEffect(() => {
|
|
404
|
-
if(
|
|
405
|
-
console.log("STREAM",
|
|
406
|
-
|
|
407
|
-
|
|
436
|
+
if(model.value.media) {
|
|
437
|
+
console.log("STREAM", model.value.media, model.value.audioMuted, model.value.videoMuted)
|
|
438
|
+
model.value.media.getAudioTracks().forEach(track => track.enabled = !model.value.audioMuted)
|
|
439
|
+
model.value.media.getVideoTracks().forEach(track => track.enabled = !model.value.videoMuted)
|
|
408
440
|
}
|
|
409
441
|
})
|
|
410
442
|
|
|
@@ -465,7 +497,7 @@
|
|
|
465
497
|
}
|
|
466
498
|
|
|
467
499
|
function handleEmptyPreviewClick() {
|
|
468
|
-
if(
|
|
500
|
+
if(model.value.media) return
|
|
469
501
|
const { camera, microphone } = permissionsDialog.value.permissions
|
|
470
502
|
if(camera === 'denied' || microphone === 'denied') {
|
|
471
503
|
// open permissions dialog
|
|
@@ -523,10 +555,12 @@
|
|
|
523
555
|
}
|
|
524
556
|
}
|
|
525
557
|
function updateVideoInput(value) {
|
|
558
|
+
console.log("UPDATE VIDEO INPUT", value)
|
|
526
559
|
model.value = {
|
|
527
560
|
...model.value,
|
|
528
561
|
videoInput: value
|
|
529
562
|
}
|
|
563
|
+
console.log("UPDATED VIDEO INPUT", model.value.videoInput)
|
|
530
564
|
}
|
|
531
565
|
|
|
532
566
|
</script>
|
|
@@ -44,8 +44,41 @@ async function isUserMediaPermitted(constraints = { audio: true, video: true })
|
|
|
44
44
|
return true
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
const
|
|
48
|
-
const
|
|
47
|
+
const getUserMediaNative = userMediaFactory()
|
|
48
|
+
const getDisplayMediaNative = displayMediaFactory()
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
const trackedStreams = []
|
|
51
|
+
|
|
52
|
+
async function getUserMedia(...args) {
|
|
53
|
+
const stream = await getUserMediaNative(...args)
|
|
54
|
+
trackedStreams.push(stream)
|
|
55
|
+
console.log("STREAM ADDED", stream, "ALL STREAMS", trackedStreams.length)
|
|
56
|
+
return stream
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function getDisplayMedia(...args) {
|
|
60
|
+
const stream = await getDisplayMediaNative(...args)
|
|
61
|
+
trackedStreams.push(stream)
|
|
62
|
+
console.log("STREAM ADDED", stream, "ALL STREAMS", trackedStreams.length)
|
|
63
|
+
return stream
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function stopMedia(stream) {
|
|
67
|
+
const index = trackedStreams.indexOf(stream)
|
|
68
|
+
if(index >= 0) {
|
|
69
|
+
trackedStreams.splice(index, 1)
|
|
70
|
+
console.log("STREAM REMOVED", stream, "ALL STREAMS", trackedStreams.length)
|
|
71
|
+
} else {
|
|
72
|
+
console.error("STREAM NOT FOUND", stream, "ALL STREAMS", trackedStreams)
|
|
73
|
+
}
|
|
74
|
+
if(stream.getTracks) {
|
|
75
|
+
for(const track of stream.getTracks()) {
|
|
76
|
+
track.stop()
|
|
77
|
+
}
|
|
78
|
+
} else {
|
|
79
|
+
stream.stop()
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export { getUserMedia, getDisplayMedia, isUserMediaPermitted, stopMedia }
|
|
51
84
|
|
package/index.js
CHANGED
|
@@ -13,11 +13,12 @@ export {
|
|
|
13
13
|
|
|
14
14
|
import { createPeer } from './front/src/components/Peer.js'
|
|
15
15
|
import { createPeerConnection } from './front/src/components/PeerConnection.js'
|
|
16
|
-
import { getUserMedia, getDisplayMedia, isUserMediaPermitted } from './front/src/components/userMedia.js'
|
|
16
|
+
import { getUserMedia, getDisplayMedia, isUserMediaPermitted, stopMedia } from './front/src/components/userMedia.js'
|
|
17
17
|
import { mediaStreamsTracks } from './front/src/components/mediaStreamsTracks.js'
|
|
18
18
|
|
|
19
19
|
export {
|
|
20
|
-
createPeer, createPeerConnection, getUserMedia, getDisplayMedia,
|
|
20
|
+
createPeer, createPeerConnection, getUserMedia, getDisplayMedia, stopMedia,
|
|
21
|
+
isUserMediaPermitted, mediaStreamsTracks
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
import { peerConnectionRoutes } from './front/src/router.js'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@live-change/peer-connection-frontend",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.89",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"memDev": "dotenvx run -- node server/start.js memDev --enableSessions --initScript ./init.js --dbAccess",
|
|
6
6
|
"localDevInit": "rm tmp.db; dotenvx run -- node server/start.js localDev --enableSessions --initScript ./init.js",
|
|
@@ -22,19 +22,19 @@
|
|
|
22
22
|
},
|
|
23
23
|
"type": "module",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@live-change/cli": "^0.8.
|
|
26
|
-
"@live-change/dao": "^0.8.
|
|
27
|
-
"@live-change/dao-vue3": "^0.8.
|
|
28
|
-
"@live-change/dao-websocket": "^0.8.
|
|
29
|
-
"@live-change/framework": "^0.8.
|
|
30
|
-
"@live-change/password-authentication-service": "^0.8.
|
|
31
|
-
"@live-change/secret-code-service": "^0.8.
|
|
32
|
-
"@live-change/secret-link-service": "^0.8.
|
|
33
|
-
"@live-change/session-service": "^0.8.
|
|
34
|
-
"@live-change/user-frontend": "^0.8.
|
|
35
|
-
"@live-change/user-service": "^0.8.
|
|
36
|
-
"@live-change/vue3-components": "^0.8.
|
|
37
|
-
"@live-change/vue3-ssr": "^0.8.
|
|
25
|
+
"@live-change/cli": "^0.8.89",
|
|
26
|
+
"@live-change/dao": "^0.8.89",
|
|
27
|
+
"@live-change/dao-vue3": "^0.8.89",
|
|
28
|
+
"@live-change/dao-websocket": "^0.8.89",
|
|
29
|
+
"@live-change/framework": "^0.8.89",
|
|
30
|
+
"@live-change/password-authentication-service": "^0.8.89",
|
|
31
|
+
"@live-change/secret-code-service": "^0.8.89",
|
|
32
|
+
"@live-change/secret-link-service": "^0.8.89",
|
|
33
|
+
"@live-change/session-service": "^0.8.89",
|
|
34
|
+
"@live-change/user-frontend": "^0.8.89",
|
|
35
|
+
"@live-change/user-service": "^0.8.89",
|
|
36
|
+
"@live-change/vue3-components": "^0.8.89",
|
|
37
|
+
"@live-change/vue3-ssr": "^0.8.89",
|
|
38
38
|
"@vueuse/core": "^10.11.0",
|
|
39
39
|
"boxicons": "^2.1.4",
|
|
40
40
|
"codeceptjs-assert": "^0.0.5",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"vue3-scroll-border": "0.1.6"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@live-change/codeceptjs-helper": "^0.8.
|
|
57
|
+
"@live-change/codeceptjs-helper": "^0.8.89",
|
|
58
58
|
"codeceptjs": "^3.6.5",
|
|
59
59
|
"generate-password": "1.7.1",
|
|
60
60
|
"playwright": "^1.41.2",
|
|
@@ -65,5 +65,5 @@
|
|
|
65
65
|
"author": "Michał Łaszczewski <michal@laszczewski.pl>",
|
|
66
66
|
"license": "BSD-3-Clause",
|
|
67
67
|
"description": "",
|
|
68
|
-
"gitHead": "
|
|
68
|
+
"gitHead": "15d4b3dc445480608c993e4057be208192e97023"
|
|
69
69
|
}
|