@live-change/peer-connection-frontend 0.8.73 → 0.8.74

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.
@@ -8,11 +8,13 @@ export {}
8
8
  declare module 'vue' {
9
9
  export interface GlobalComponents {
10
10
  Button: typeof import('primevue/button')['default']
11
+ CameraButton: typeof import('./src/components/CameraButton.vue')['default']
11
12
  Debugger: typeof import('./src/components/Debugger.vue')['default']
12
13
  DeviceSelect: typeof import('./src/components/DeviceSelect.vue')['default']
13
14
  Dialog: typeof import('primevue/dialog')['default']
14
15
  Dropdown: typeof import('primevue/dropdown')['default']
15
16
  InputSwitch: typeof import('primevue/inputswitch')['default']
17
+ MicrophoneButton: typeof import('./src/components/MicrophoneButton.vue')['default']
16
18
  PermissionsDialog: typeof import('./src/components/PermissionsDialog.vue')['default']
17
19
  RouterLink: typeof import('vue-router')['RouterLink']
18
20
  RouterView: typeof import('vue-router')['RouterView']
@@ -7,13 +7,13 @@
7
7
  <i class="pi pi-eye-slash text-9xl text-gray-500" style="font-size: 2.5rem" />
8
8
  <div class="text-xl">Video input not found!</div>
9
9
  <div class>Please connect camera.</div>
10
- <audio v-if="model?.audioInput?.deviceId"
10
+ <audio v-if="model?.audioInput?.deviceId" ref="outputElement"
11
11
  autoplay playsinline :muted="userMediaMuted"
12
12
  :src-object.prop.camel="userMedia">
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"
16
+ <video v-if="userMedia" autoplay playsinline :muted="userMediaMuted" ref="outputElement"
17
17
  :src-object.prop.camel="userMedia"
18
18
  class="max-w-full max-h-full" style="object-fit: contain; transform: scaleX(-1)">
19
19
  </video>
@@ -34,7 +34,9 @@
34
34
  <div v-if="audioInputRequest !== 'none' && audioInputs.length > 0"
35
35
  class="flex flex-column align-items-stretch flex-grow-1">
36
36
  <div class="text-sm mb-1 pl-1">Microphone</div>
37
- <Dropdown v-model="model.audioInput" :options="audioInputs"
37
+ <Dropdown :modelValue="model.audioInput"
38
+ @update:modelValue="value => updateAudioInput(value)"
39
+ :options="audioInputs"
38
40
  optionLabel="label"
39
41
  placeholder="Select">
40
42
  <template #value="slotProps">
@@ -51,7 +53,9 @@
51
53
  <div v-if="audioOutputRequest !== 'none' && audioOutputs.length > 0"
52
54
  class="flex flex-column align-items-stretch flex-grow-1">
53
55
  <div class="text-sm mb-1 pl-1">Audio output</div>
54
- <Dropdown v-model="model.audioOutput" :options="audioOutputs" optionLabel="label"
56
+ <Dropdown :modelValue="model.audioOutput"
57
+ @update:modelValue="value => updateAudioOutput(value)"
58
+ :options="audioOutputs" optionLabel="label"
55
59
  placeholder="Select">
56
60
  <template #value="slotProps">
57
61
  <div class="flex flex-row align-items-center">
@@ -68,7 +72,9 @@
68
72
  <div v-if="videoInputRequest !== 'none' && videoInputs.length > 0"
69
73
  class="flex flex-column align-items-stretch flex-grow-1">
70
74
  <div class="text-sm mb-1 pl-1">Camera</div>
71
- <Dropdown v-model="model.videoInput" :options="videoInputs" optionLabel="label"
75
+ <Dropdown :modelValue="model.videoInput"
76
+ @update:modelValue="value => updateVideoInput(value)"
77
+ :options="videoInputs" optionLabel="label"
72
78
  placeholder="Select">
73
79
  <template #value="slotProps">
74
80
  <div class="flex flex-row align-items-center">
@@ -106,6 +112,7 @@
106
112
  label="Cancel" icon="pi pi-times" class="p-button-warning" autofocus />
107
113
  </template>
108
114
  </PermissionsDialog>
115
+
109
116
  <!--
110
117
 
111
118
  <pre>PD: {{ permissionsDialog }}</pre>
@@ -299,6 +306,20 @@
299
306
  }
300
307
  })
301
308
 
309
+ const outputElement = ref(null)
310
+ watchEffect(() => {
311
+ const output = outputElement.value
312
+ const outputDeviceId = model.value?.audioOutput?.deviceId
313
+ if(!output) return
314
+ (async () => {
315
+ console.log("SET OUTPUT DEVICE", outputDeviceId)
316
+ if(outputDeviceId) {
317
+ await output.setSinkId(outputDeviceId)
318
+ } else {
319
+ //await output.setSinkId(null)
320
+ }
321
+ })()
322
+ })
302
323
 
303
324
  const permissionsDialog = ref({ })
304
325
  const permissionsCallbacks = ref({})
@@ -387,6 +408,25 @@
387
408
  //updateUserMedia()
388
409
  })
389
410
 
411
+ function updateAudioInput(value) {
412
+ model.value = {
413
+ ...model.value,
414
+ audioInput: value
415
+ }
416
+ }
417
+ function updateAudioOutput(value) {
418
+ model.value = {
419
+ ...model.value,
420
+ audioOutput: value
421
+ }
422
+ }
423
+ function updateVideoInput(value) {
424
+ model.value = {
425
+ ...model.value,
426
+ videoInput: value
427
+ }
428
+ }
429
+
390
430
  </script>
391
431
 
392
432
  <style scoped>
@@ -0,0 +1,167 @@
1
+ <template>
2
+ <OverlayPanel ref="mediaSettingsOverlay">
3
+ <div class="flex flex-column gap-2 pt-2 justify-content-around" style="min-width: 20rem; max-width: 90vw">
4
+ <pre>{{ model }}</pre>
5
+ <div v-if="audioInputRequest !== 'none' && audioInputs.length > 0"
6
+ class="flex flex-column align-items-stretch flex-grow-1">
7
+ <div class="text-sm mb-1 pl-1">Microphone</div>
8
+ <Dropdown :modelValue="model.audioInput"
9
+ @update:modelValue="value => updateAudioInput(value)"
10
+ :options="audioInputs"
11
+ optionLabel="label"
12
+ placeholder="Select">
13
+ <template #value="slotProps">
14
+ <div class="flex flex-row align-items-center">
15
+ <i class="pi pi-microphone mr-2" />
16
+ &nbsp;
17
+ <div class="absolute overflow-hidden text-overflow-ellipsis" style="left: 2em; right: 2em;">
18
+ {{ slotProps.value ? slotProps.value.label : slotProps.placeholder }}
19
+ </div>
20
+ </div>
21
+ </template>
22
+ </Dropdown>
23
+ </div>
24
+ <div v-if="audioOutputRequest !== 'none' && audioOutputs.length > 0"
25
+ class="flex flex-column align-items-stretch flex-grow-1">
26
+ <div class="text-sm mb-1 pl-1">Audio output</div>
27
+ <Dropdown :modelValue="model.audioOutput"
28
+ @update:modelValue="value => updateAudioOutput(value)"
29
+ :options="audioOutputs" optionLabel="label"
30
+ placeholder="Select">
31
+ <template #value="slotProps">
32
+ <div class="flex flex-row align-items-center">
33
+ <i class="pi pi-volume-up mr-2" />
34
+ &nbsp;
35
+ <div class="absolute overflow-hidden text-overflow-ellipsis" style="left: 2em; right: 2em;">
36
+ {{ slotProps.value ? slotProps.value.label : slotProps.placeholder }}
37
+ </div>
38
+ </div>
39
+ </template>
40
+ </Dropdown>
41
+ </div>
42
+
43
+ <div v-if="videoInputRequest !== 'none' && videoInputs.length > 0"
44
+ class="flex flex-column align-items-stretch flex-grow-1">
45
+ <div class="text-sm mb-1 pl-1">Camera</div>
46
+ <Dropdown :modelValue="model.videoInput"
47
+ @update:modelValue="value => updateVideoInput(value)"
48
+ :options="videoInputs" optionLabel="label"
49
+ placeholder="Select">
50
+ <template #value="slotProps">
51
+ <div class="flex flex-row align-items-center">
52
+ <i class="pi pi-camera mr-2" />
53
+ &nbsp;
54
+ <div class="absolute overflow-hidden text-overflow-ellipsis" style="left: 2em; right: 2em;">
55
+ {{ slotProps.value ? slotProps.value.label : slotProps.placeholder }}
56
+ </div>
57
+ </div>
58
+ </template>
59
+ </Dropdown>
60
+ </div>
61
+ </div>
62
+ </OverlayPanel>
63
+
64
+ <Button @click="toggleMediaSettings" raised
65
+ icon="bx bx-cog" severity="" rounded v-ripple />
66
+ </template>
67
+
68
+ <script setup>
69
+ import Button from 'primevue/button'
70
+ import OverlayPanel from 'primevue/overlaypanel'
71
+ import Dropdown from 'primevue/dropdown'
72
+
73
+
74
+ import { defineModel, defineProps, defineEmits, computed, ref, toRefs, onMounted } from 'vue'
75
+ import { useEventListener } from '@vueuse/core'
76
+
77
+ const props = defineProps({
78
+ audioInputRequest: {
79
+ type: String,
80
+ default: 'wanted'
81
+ },
82
+ audioOutputRequest: {
83
+ type: String,
84
+ default: 'wanted' // can be wanted required or none
85
+ },
86
+ videoInputRequest: {
87
+ type: String,
88
+ default: 'wanted'
89
+ },
90
+ constraints: {
91
+ type: Object,
92
+ default: () => ({})
93
+ }
94
+ })
95
+ const { audioInputRequest, audioOutputRequest, videoInputRequest, constraints } = toRefs(props)
96
+
97
+ const model = defineModel({
98
+ required: true,
99
+ type: Object,
100
+ properties: {
101
+ audioInput: {
102
+ type: Object
103
+ },
104
+ audioOutput: {
105
+ type: Object
106
+ },
107
+ videoInput: {
108
+ type: Object
109
+ },
110
+ audioMuted: {
111
+ type: Boolean
112
+ },
113
+ videoMuted: {
114
+ type: Boolean
115
+ },
116
+ userMedia: {
117
+ type: Object
118
+ }
119
+ }
120
+ })
121
+
122
+ const devices = ref([])
123
+ async function updateDevices() {
124
+ console.log("UPDATE DEVICES")
125
+ devices.value = await navigator.mediaDevices.enumerateDevices()
126
+ console.log("DEVICES", JSON.stringify(devices.value))
127
+ }
128
+ if(typeof window !== 'undefined') {
129
+ useEventListener(navigator.mediaDevices, 'devicechange', updateDevices)
130
+ onMounted(updateDevices)
131
+ }
132
+
133
+ const audioInputs = computed(() => devices.value.filter(device => device.kind === 'audioinput'))
134
+ const audioOutputs = computed(() => devices.value.filter(device => device.kind === 'audiooutput'))
135
+ const videoInputs = computed(() => devices.value.filter(device => device.kind === 'videoinput'))
136
+
137
+ const mediaSettingsOverlay = ref()
138
+
139
+ function toggleMediaSettings(ev) {
140
+ mediaSettingsOverlay.value.toggle(ev)
141
+ console.log('toggleMediaSettings')
142
+ }
143
+
144
+ function updateAudioInput(value) {
145
+ model.value = {
146
+ ...model.value,
147
+ audioInput: value
148
+ }
149
+ }
150
+ function updateAudioOutput(value) {
151
+ model.value = {
152
+ ...model.value,
153
+ audioOutput: value
154
+ }
155
+ }
156
+ function updateVideoInput(value) {
157
+ model.value = {
158
+ ...model.value,
159
+ videoInput: value
160
+ }
161
+ }
162
+
163
+ </script>
164
+
165
+ <style scoped>
166
+
167
+ </style>
package/index.js CHANGED
@@ -4,8 +4,12 @@ import PermissionsDialog from './front/src/components/PermissionsDialog.vue'
4
4
  import VolumeIndicator from './front/src/components/VolumeIndicator.vue'
5
5
  import CameraButton from './front/src/components/CameraButton.vue'
6
6
  import MicrophoneButton from './front/src/components/MicrophoneButton.vue'
7
+ import MediaSettingsButton from './front/src/components/MediaSettingsButton.vue'
7
8
 
8
- export { Debugger, DeviceSelect, PermissionsDialog, VolumeIndicator, CameraButton, MicrophoneButton }
9
+ export {
10
+ Debugger, DeviceSelect, PermissionsDialog, VolumeIndicator,
11
+ CameraButton, MicrophoneButton, MediaSettingsButton
12
+ }
9
13
 
10
14
  import { createPeer } from './front/src/components/Peer.js'
11
15
  import { createPeerConnection } from './front/src/components/PeerConnection.js'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@live-change/peer-connection-frontend",
3
- "version": "0.8.73",
3
+ "version": "0.8.74",
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.73",
26
- "@live-change/dao": "^0.8.73",
27
- "@live-change/dao-vue3": "^0.8.73",
28
- "@live-change/dao-websocket": "^0.8.73",
29
- "@live-change/framework": "^0.8.73",
30
- "@live-change/password-authentication-service": "^0.8.73",
31
- "@live-change/secret-code-service": "^0.8.73",
32
- "@live-change/secret-link-service": "^0.8.73",
33
- "@live-change/session-service": "^0.8.73",
34
- "@live-change/user-frontend": "^0.8.73",
35
- "@live-change/user-service": "^0.8.73",
36
- "@live-change/vue3-components": "^0.8.73",
37
- "@live-change/vue3-ssr": "^0.8.73",
25
+ "@live-change/cli": "^0.8.74",
26
+ "@live-change/dao": "^0.8.74",
27
+ "@live-change/dao-vue3": "^0.8.74",
28
+ "@live-change/dao-websocket": "^0.8.74",
29
+ "@live-change/framework": "^0.8.74",
30
+ "@live-change/password-authentication-service": "^0.8.74",
31
+ "@live-change/secret-code-service": "^0.8.74",
32
+ "@live-change/secret-link-service": "^0.8.74",
33
+ "@live-change/session-service": "^0.8.74",
34
+ "@live-change/user-frontend": "^0.8.74",
35
+ "@live-change/user-service": "^0.8.74",
36
+ "@live-change/vue3-components": "^0.8.74",
37
+ "@live-change/vue3-ssr": "^0.8.74",
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.73",
57
+ "@live-change/codeceptjs-helper": "^0.8.74",
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": "2f0b5d33803640d1036bfa85ae4ea2af63db0b54"
68
+ "gitHead": "d8c3d9737790e0e320216cfcdfc07012ad139911"
69
69
  }