@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.
@@ -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="userMedia">
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="userMedia" autoplay playsinline :muted="userMediaMuted" ref="outputElement"
17
- :src-object.prop.camel="userMedia"
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="userMedia">
53
+ <div class="absolute top-0 right-0" v-if="model.media">
54
54
  <div class="m-3">
55
- <VolumeIndicator :stream="userMedia" />
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: {{ userMedia }}</pre>-->
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 { getUserMedia as getUserMediaNative, getDisplayMedia as getDisplayMediaNative, isUserMediaPermitted }
172
- from "./userMedia.js"
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
- userMedia.value = mediaStream
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
- userMedia.value = mediaStream
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, () => updateUserMedia(), { immediate: true })
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(userMedia.value) {
405
- console.log("STREAM", userMedia.value, model.value.audioMuted, model.value.videoMuted)
406
- userMedia.value.getAudioTracks().forEach(track => track.enabled = !model.value.audioMuted)
407
- userMedia.value.getVideoTracks().forEach(track => track.enabled = !model.value.videoMuted)
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(userMedia.value) return
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 getUserMedia = userMediaFactory()
48
- const getDisplayMedia = displayMediaFactory()
47
+ const getUserMediaNative = userMediaFactory()
48
+ const getDisplayMediaNative = displayMediaFactory()
49
49
 
50
- export { getUserMedia, getDisplayMedia, isUserMediaPermitted }
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, isUserMediaPermitted, mediaStreamsTracks
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.87",
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.87",
26
- "@live-change/dao": "^0.8.87",
27
- "@live-change/dao-vue3": "^0.8.87",
28
- "@live-change/dao-websocket": "^0.8.87",
29
- "@live-change/framework": "^0.8.87",
30
- "@live-change/password-authentication-service": "^0.8.87",
31
- "@live-change/secret-code-service": "^0.8.87",
32
- "@live-change/secret-link-service": "^0.8.87",
33
- "@live-change/session-service": "^0.8.87",
34
- "@live-change/user-frontend": "^0.8.87",
35
- "@live-change/user-service": "^0.8.87",
36
- "@live-change/vue3-components": "^0.8.87",
37
- "@live-change/vue3-ssr": "^0.8.87",
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.87",
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": "133e0785e028c37eb6f903d7355e5470b2cc65d3"
68
+ "gitHead": "15d4b3dc445480608c993e4057be208192e97023"
69
69
  }