@live-change/peer-connection-frontend 0.8.36 → 0.8.38
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/components.d.ts +2 -0
- package/front/src/App.vue +1 -0
- package/front/src/components/Debugger.vue +3 -46
- package/front/src/components/{DevicesSelect.vue → DeviceSelect.vue} +43 -19
- package/front/src/components/PermissionsDialog.vue +1 -0
- package/front/src/components/VolumeIndicator.vue +211 -0
- package/front/src/router.js +1 -1
- package/index.js +6 -2
- package/package.json +18 -16
- package/server/app.config.js +7 -0
package/front/components.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ declare module 'vue' {
|
|
|
9
9
|
export interface GlobalComponents {
|
|
10
10
|
Button: typeof import('primevue/button')['default']
|
|
11
11
|
Debugger: typeof import('./src/components/Debugger.vue')['default']
|
|
12
|
+
DeviceSelect: typeof import('./src/components/DeviceSelect.vue')['default']
|
|
12
13
|
DevicesSelect: typeof import('./src/components/DevicesSelect.vue')['default']
|
|
13
14
|
Dialog: typeof import('primevue/dialog')['default']
|
|
14
15
|
Dropdown: typeof import('primevue/dropdown')['default']
|
|
@@ -16,5 +17,6 @@ declare module 'vue' {
|
|
|
16
17
|
PermissionsDialog: typeof import('./src/components/PermissionsDialog.vue')['default']
|
|
17
18
|
RouterLink: typeof import('vue-router')['RouterLink']
|
|
18
19
|
RouterView: typeof import('vue-router')['RouterView']
|
|
20
|
+
VolumeIndicator: typeof import('./src/components/VolumeIndicator.vue')['default']
|
|
19
21
|
}
|
|
20
22
|
}
|
package/front/src/App.vue
CHANGED
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
|
|
44
44
|
<div>
|
|
45
45
|
<h2>User media</h2>
|
|
46
|
-
<
|
|
46
|
+
<DeviceSelect v-model="selectedDevices" />
|
|
47
47
|
<hr>
|
|
48
48
|
<pre>{{ selectedDevices }}</pre>
|
|
49
49
|
<div class="mt-1 mb-3 flex align-items-center">
|
|
@@ -64,16 +64,12 @@
|
|
|
64
64
|
</video>
|
|
65
65
|
</div>
|
|
66
66
|
|
|
67
|
-
|
|
68
67
|
</div>
|
|
69
68
|
</template>
|
|
70
69
|
|
|
71
70
|
<script setup>
|
|
72
71
|
import Button from "primevue/button"
|
|
73
|
-
import
|
|
74
|
-
import Dialog from "primevue/dialog"
|
|
75
|
-
import PermissionsDialog from './PermissionsDialog.vue'
|
|
76
|
-
import DevicesSelect from './DevicesSelect.vue'
|
|
72
|
+
import DeviceSelect from './DeviceSelect.vue'
|
|
77
73
|
|
|
78
74
|
import { ref, unref, computed, watch, onMounted, onUnmounted, getCurrentInstance } from 'vue'
|
|
79
75
|
import { path, live, actions, api as useApi } from '@live-change/vue3-ssr'
|
|
@@ -82,7 +78,7 @@
|
|
|
82
78
|
const appContext = (typeof window != 'undefined') && getCurrentInstance()?.appContext
|
|
83
79
|
|
|
84
80
|
import { createPeer } from "./Peer.js"
|
|
85
|
-
import {
|
|
81
|
+
import { getDisplayMedia as getDisplayMediaNative }
|
|
86
82
|
from "./userMedia.js"
|
|
87
83
|
import { mediaStreamsTracks } from './mediaStreamsTracks.js'
|
|
88
84
|
|
|
@@ -169,43 +165,6 @@
|
|
|
169
165
|
createPeerPromise = null
|
|
170
166
|
}
|
|
171
167
|
|
|
172
|
-
const permissionsDialog = ref(false)
|
|
173
|
-
const permissionsCallbacks = ref(null)
|
|
174
|
-
|
|
175
|
-
async function showPermissionsDialog() {
|
|
176
|
-
return new Promise((resolve, reject) => {
|
|
177
|
-
permissionsCallbacks.value = {
|
|
178
|
-
disabled: () => {
|
|
179
|
-
resolve(false)
|
|
180
|
-
},
|
|
181
|
-
ok: () => {
|
|
182
|
-
resolve(true)
|
|
183
|
-
},
|
|
184
|
-
cancel: () => {
|
|
185
|
-
reject('canceled by user')
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
permissionsDialog.value = {
|
|
189
|
-
visible: true
|
|
190
|
-
}
|
|
191
|
-
})
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const connectDeviceDialog = ref(false)
|
|
195
|
-
const connectDeviceCallbacks = ref(null)
|
|
196
|
-
|
|
197
|
-
async function askToConnectCamera(constraints) {
|
|
198
|
-
return new Promise((resolve, reject) => {
|
|
199
|
-
connectDeviceCallbacks.value = {
|
|
200
|
-
connected: () => resolve({ ...constraints }),
|
|
201
|
-
camera: () => resolve({ ...constraints, audio: false }),
|
|
202
|
-
microphone: () => resolve({ ...constraints, video: false }),
|
|
203
|
-
cancel: () => resolve(null)
|
|
204
|
-
}
|
|
205
|
-
connectDeviceDialog.value = true
|
|
206
|
-
})
|
|
207
|
-
}
|
|
208
|
-
|
|
209
168
|
async function getDisplayMedia() { // media stream retrival logic
|
|
210
169
|
let initialConstraints = { video: true } // make a copy
|
|
211
170
|
let constraints = { ...initialConstraints }
|
|
@@ -231,7 +190,6 @@
|
|
|
231
190
|
displayMedia.value = null
|
|
232
191
|
}
|
|
233
192
|
|
|
234
|
-
|
|
235
193
|
function sendTestMessage() {
|
|
236
194
|
for(const connection of peer.value.connections) {
|
|
237
195
|
peer.value.sendMessage({
|
|
@@ -242,7 +200,6 @@
|
|
|
242
200
|
}
|
|
243
201
|
}
|
|
244
202
|
|
|
245
|
-
|
|
246
203
|
</script>
|
|
247
204
|
|
|
248
205
|
<style scoped lang="scss">
|
|
@@ -19,22 +19,29 @@
|
|
|
19
19
|
</video>
|
|
20
20
|
</div>
|
|
21
21
|
<div class="absolute top-0 left-0 w-full h-full flex flex-column justify-content-end align-items-center">
|
|
22
|
-
<div class="flex flex-row justify-content-between align-items-center h-5rem w-
|
|
22
|
+
<div class="flex flex-row justify-content-between align-items-center h-5rem w-7rem media-buttons">
|
|
23
|
+
|
|
23
24
|
<Button v-if="!selectedConstraints?.audio?.deviceId"
|
|
24
|
-
@click="handleDisabledAudioClick"
|
|
25
|
-
icon="
|
|
25
|
+
@click="handleDisabledAudioClick" raised
|
|
26
|
+
icon="bx bx-microphone-off" severity="secondary" rounded v-ripple />
|
|
26
27
|
<Button v-else-if="audioInputMuted" @click="audioInputMuted = false" raised
|
|
27
|
-
icon="
|
|
28
|
+
icon="bx bx-microphone-off" severity="danger" rounded v-ripple />
|
|
28
29
|
<Button v-else @click="audioInputMuted = true" raised
|
|
29
|
-
icon="
|
|
30
|
+
icon="bx bx-microphone" severity="success" rounded v-ripple />
|
|
30
31
|
|
|
31
32
|
<Button v-if="!selectedConstraints?.video?.deviceId"
|
|
32
|
-
@click="handleDisabledVideoClick"
|
|
33
|
-
icon="
|
|
33
|
+
@click="handleDisabledVideoClick" raised
|
|
34
|
+
icon="bx bx-camera-off" severity="secondary" rounded v-ripple />
|
|
34
35
|
<Button v-else-if="videoInputMuted" @click="videoInputMuted = false" raised
|
|
35
|
-
icon="
|
|
36
|
+
icon="bx bx-camera-off" severity="danger" rounded v-ripple />
|
|
36
37
|
<Button v-else @click="videoInputMuted = true" raised
|
|
37
|
-
icon="
|
|
38
|
+
icon="bx bx-camera" severity="success" rounded v-ripple />
|
|
39
|
+
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
<div class="absolute top-0 right-0">
|
|
43
|
+
<div class="m-3">
|
|
44
|
+
<VolumeIndicator :stream="userMedia" />
|
|
38
45
|
</div>
|
|
39
46
|
</div>
|
|
40
47
|
</div>
|
|
@@ -125,6 +132,14 @@
|
|
|
125
132
|
</div>
|
|
126
133
|
</template>
|
|
127
134
|
|
|
135
|
+
<style lang="scss">
|
|
136
|
+
.media-buttons {
|
|
137
|
+
.bx::before {
|
|
138
|
+
font-size: 1.69em;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
</style>
|
|
142
|
+
|
|
128
143
|
<script setup>
|
|
129
144
|
|
|
130
145
|
import { defineProps, defineModel, computed, ref, toRefs, onMounted, watch } from 'vue'
|
|
@@ -132,6 +147,7 @@
|
|
|
132
147
|
import { getUserMedia as getUserMediaNative, getDisplayMedia as getDisplayMediaNative, isUserMediaPermitted }
|
|
133
148
|
from "./userMedia.js"
|
|
134
149
|
import PermissionsDialog from './PermissionsDialog.vue'
|
|
150
|
+
import VolumeIndicator from './VolumeIndicator.vue'
|
|
135
151
|
|
|
136
152
|
const props = defineProps({
|
|
137
153
|
audioInputRequest: {
|
|
@@ -184,8 +200,10 @@
|
|
|
184
200
|
devices.value = await navigator.mediaDevices.enumerateDevices()
|
|
185
201
|
console.log("DEVICES", JSON.stringify(devices.value))
|
|
186
202
|
}
|
|
187
|
-
|
|
188
|
-
|
|
203
|
+
if(typeof window !== 'undefined') {
|
|
204
|
+
useEventListener(navigator.mediaDevices, 'devicechange', updateDevices)
|
|
205
|
+
onMounted(updateDevices)
|
|
206
|
+
}
|
|
189
207
|
|
|
190
208
|
const audioInputs = computed(() => devices.value.filter(device => device.kind === 'audioinput'))
|
|
191
209
|
const audioOutputs = computed(() => devices.value.filter(device => device.kind === 'audiooutput'))
|
|
@@ -208,13 +226,22 @@
|
|
|
208
226
|
})
|
|
209
227
|
|
|
210
228
|
watch(audioInputs, (value) => {
|
|
211
|
-
model.value
|
|
229
|
+
model.value = {
|
|
230
|
+
...model.value,
|
|
231
|
+
audioInput: value[0]
|
|
232
|
+
}
|
|
212
233
|
}, { immediate: true })
|
|
213
234
|
watch(audioOutputs, (value) => {
|
|
214
|
-
model.value
|
|
235
|
+
model.value = {
|
|
236
|
+
...model.value,
|
|
237
|
+
audioOutput: value[0]
|
|
238
|
+
}
|
|
215
239
|
}, { immediate: true })
|
|
216
240
|
watch(videoInputs, (value) => {
|
|
217
|
-
model.value
|
|
241
|
+
model.value = {
|
|
242
|
+
...model.value,
|
|
243
|
+
videoInput: value[0]
|
|
244
|
+
}
|
|
218
245
|
}, { immediate: true })
|
|
219
246
|
|
|
220
247
|
/* onMounted(() => {
|
|
@@ -234,9 +261,9 @@
|
|
|
234
261
|
const selectedConstraints = ref({ video: false, audio: false })
|
|
235
262
|
watch(() => ({
|
|
236
263
|
video: limitedMedia.value === 'audio' ? false :
|
|
237
|
-
{ deviceId: model.value
|
|
264
|
+
{ deviceId: model.value?.videoInput?.deviceId, ...constraints.value.video },
|
|
238
265
|
audio: limitedMedia.value === 'video' ? false :
|
|
239
|
-
{ deviceId: model.value
|
|
266
|
+
{ deviceId: model.value?.audioInput?.deviceId, ...constraints.value.audio }
|
|
240
267
|
}), ({ video, audio }) => {
|
|
241
268
|
console.log("SELECTED CONSTRAINTS", {
|
|
242
269
|
video: selectedConstraints.value.video?.deviceId,
|
|
@@ -383,9 +410,6 @@
|
|
|
383
410
|
//updateUserMedia()
|
|
384
411
|
})
|
|
385
412
|
|
|
386
|
-
window.um = userMedia
|
|
387
|
-
window.model = model
|
|
388
|
-
|
|
389
413
|
</script>
|
|
390
414
|
|
|
391
415
|
<style scoped>
|
|
@@ -96,6 +96,7 @@
|
|
|
96
96
|
const emit = defineEmits(['ok'])
|
|
97
97
|
|
|
98
98
|
watch(() => JSON.stringify(requiredPermissions.value), async value => {
|
|
99
|
+
if(typeof window === 'undefined') return
|
|
99
100
|
console.log("requiredPermissions", value)
|
|
100
101
|
|
|
101
102
|
for(const requiredPermission of JSON.parse(value)) {
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="flex flex-row border-circle w-2rem h-2rem bg-primary-800
|
|
3
|
+
align-items-center justify-content-center">
|
|
4
|
+
<div class="volume-indicator-bar bg-white border-round" ref="low"></div>
|
|
5
|
+
<div class="volume-indicator-bar bg-white border-round" ref="mid"></div>
|
|
6
|
+
<div class="volume-indicator-bar bg-white border-round" ref="high"></div>
|
|
7
|
+
</div>
|
|
8
|
+
</template>
|
|
9
|
+
|
|
10
|
+
<style scoped lang="scss">
|
|
11
|
+
.volume-indicator-bar {
|
|
12
|
+
width: 0.3rem;
|
|
13
|
+
margin: 0.1rem;
|
|
14
|
+
}
|
|
15
|
+
.border-circle {
|
|
16
|
+
border-radius: 50%;
|
|
17
|
+
}
|
|
18
|
+
.bg-primary-700 {
|
|
19
|
+
background-color: #1976D2;
|
|
20
|
+
}
|
|
21
|
+
</style>
|
|
22
|
+
|
|
23
|
+
<script setup>
|
|
24
|
+
|
|
25
|
+
import { ref, defineProps, computed, toRefs, onMounted, onUnmounted, watch } from 'vue'
|
|
26
|
+
|
|
27
|
+
const props = defineProps({
|
|
28
|
+
stream: {
|
|
29
|
+
type: Object,
|
|
30
|
+
required: true
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
const { stream } = toRefs(props)
|
|
35
|
+
|
|
36
|
+
const speed = 0.46
|
|
37
|
+
const maxLogVolume = -2
|
|
38
|
+
const minLogVolume = -7
|
|
39
|
+
const lowFrequency = 230
|
|
40
|
+
const midFrequency = 460
|
|
41
|
+
const highFrequency = 1230
|
|
42
|
+
const filterQ = 0.1
|
|
43
|
+
const detune = 100
|
|
44
|
+
|
|
45
|
+
const minHeight = 3
|
|
46
|
+
const maxHeight = 15
|
|
47
|
+
|
|
48
|
+
const low = ref(null)
|
|
49
|
+
const mid = ref(null)
|
|
50
|
+
const high = ref(null)
|
|
51
|
+
|
|
52
|
+
let audioContext, mediaStreamSource
|
|
53
|
+
let lowFilter, midFilter, highFilter
|
|
54
|
+
let lowProcessor, midProcessor, highProcessor
|
|
55
|
+
let lowSlow = 0, midSlow = 0, highSlow = 0
|
|
56
|
+
|
|
57
|
+
function measureAmplitudeProcess(cb) {
|
|
58
|
+
return function(event) {
|
|
59
|
+
const numberOfChannels = event.inputBuffer.numberOfChannels
|
|
60
|
+
let instant = 0
|
|
61
|
+
for(let channelId = 0; channelId < numberOfChannels; channelId++) {
|
|
62
|
+
let sum = 0
|
|
63
|
+
const input = event.inputBuffer.getChannelData(channelId)
|
|
64
|
+
for (let i = 0; i < input.length; ++i) {
|
|
65
|
+
sum += input[i] * input[i]
|
|
66
|
+
}
|
|
67
|
+
instant += sum / input.length
|
|
68
|
+
}
|
|
69
|
+
cb(Math.sqrt(instant))
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function handleLow(instant) {
|
|
74
|
+
if(!low.value) return console.log("no low element")
|
|
75
|
+
instant = Math.log(instant)
|
|
76
|
+
let value = lowSlow
|
|
77
|
+
if(!Number.isFinite(value)) value = -1000
|
|
78
|
+
value = instant * speed + value * (1 - speed)
|
|
79
|
+
if(value > maxLogVolume) value = maxLogVolume
|
|
80
|
+
if(value < minLogVolume) value = minLogVolume
|
|
81
|
+
const height = ((value - minLogVolume)/(maxLogVolume - minLogVolume))
|
|
82
|
+
* (maxHeight - minHeight) + minHeight
|
|
83
|
+
lowSlow = value
|
|
84
|
+
low.value.style.height = height + 'px'
|
|
85
|
+
}
|
|
86
|
+
function handleMid(instant) {
|
|
87
|
+
if(!mid.value) return console.log("no mid element")
|
|
88
|
+
instant = Math.log(instant)
|
|
89
|
+
let value = midSlow
|
|
90
|
+
if(!Number.isFinite(value)) value = -1000
|
|
91
|
+
value = instant * speed + value * (1 - speed)
|
|
92
|
+
if(value > maxLogVolume) value = maxLogVolume
|
|
93
|
+
if(value < minLogVolume) value = minLogVolume
|
|
94
|
+
const height = ((value - minLogVolume)/(maxLogVolume - minLogVolume))
|
|
95
|
+
* (maxHeight - minHeight) + minHeight
|
|
96
|
+
midSlow = value
|
|
97
|
+
mid.value.style.height = height + 'px'
|
|
98
|
+
}
|
|
99
|
+
function handleHigh(instant) {
|
|
100
|
+
if(!high.value) return console.log("no high element")
|
|
101
|
+
instant = Math.log(instant)
|
|
102
|
+
let value = highSlow
|
|
103
|
+
if(!Number.isFinite(value)) value = -1000
|
|
104
|
+
value = instant * speed + value * (1 - speed)
|
|
105
|
+
if(value > maxLogVolume) value = maxLogVolume
|
|
106
|
+
if(value < minLogVolume) value = minLogVolume
|
|
107
|
+
const height = ((value - minLogVolume)/(maxLogVolume - minLogVolume))
|
|
108
|
+
* (maxHeight - minHeight) + minHeight
|
|
109
|
+
highSlow = value
|
|
110
|
+
high.value.style.height = height + 'px'
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function startProcessingAudioStream(sourceStream) {
|
|
114
|
+
audioContext = new (window.AudioContext || window.webkitAudioContext)()
|
|
115
|
+
|
|
116
|
+
lowFilter = audioContext.createBiquadFilter()
|
|
117
|
+
lowFilter.type = 'lowpass'
|
|
118
|
+
lowFilter.frequency.value = lowFrequency
|
|
119
|
+
lowFilter.detune.value = detune
|
|
120
|
+
lowFilter.Q.value = filterQ
|
|
121
|
+
|
|
122
|
+
midFilter = audioContext.createBiquadFilter()
|
|
123
|
+
midFilter.type = 'bandpass'
|
|
124
|
+
midFilter.frequency.value = midFrequency
|
|
125
|
+
midFilter.detune.value = detune
|
|
126
|
+
midFilter.Q.value = filterQ
|
|
127
|
+
|
|
128
|
+
highFilter = audioContext.createBiquadFilter()
|
|
129
|
+
highFilter.type = 'highpass'
|
|
130
|
+
highFilter.frequency.value = highFrequency
|
|
131
|
+
highFilter.detune.value = detune
|
|
132
|
+
highFilter.Q.value = filterQ
|
|
133
|
+
|
|
134
|
+
lowProcessor = audioContext.createScriptProcessor(
|
|
135
|
+
2*2048, 1, 1)
|
|
136
|
+
lowProcessor.addEventListener('audioprocess', measureAmplitudeProcess(a => handleLow(a)))
|
|
137
|
+
|
|
138
|
+
midProcessor = audioContext.createScriptProcessor(
|
|
139
|
+
2*2048, 1, 1)
|
|
140
|
+
midProcessor.addEventListener('audioprocess', measureAmplitudeProcess(a => handleMid(a)))
|
|
141
|
+
|
|
142
|
+
highProcessor = audioContext.createScriptProcessor(
|
|
143
|
+
2*2048, 1, 1)
|
|
144
|
+
highProcessor.addEventListener('audioprocess', measureAmplitudeProcess(a => handleHigh(a)))
|
|
145
|
+
|
|
146
|
+
lowFilter.connect(lowProcessor)
|
|
147
|
+
midFilter.connect(midProcessor)
|
|
148
|
+
highFilter.connect(highProcessor)
|
|
149
|
+
|
|
150
|
+
lowProcessor.connect(audioContext.destination)
|
|
151
|
+
midProcessor.connect(audioContext.destination)
|
|
152
|
+
highProcessor.connect(audioContext.destination)
|
|
153
|
+
|
|
154
|
+
mediaStreamSource = audioContext.createMediaStreamSource(sourceStream)
|
|
155
|
+
mediaStreamSource.connect(lowFilter)
|
|
156
|
+
mediaStreamSource.connect(midFilter)
|
|
157
|
+
mediaStreamSource.connect(highFilter)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function stopProcessingAudioStream() {
|
|
161
|
+
if(mediaStreamSource) {
|
|
162
|
+
mediaStreamSource.disconnect()
|
|
163
|
+
mediaStreamSource = null
|
|
164
|
+
}
|
|
165
|
+
if(audioContext) audioContext.close()
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function handleStreamChange() {
|
|
169
|
+
updateSource()
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
watch(stream, (newStream, oldStream) => {
|
|
173
|
+
if(oldStream) {
|
|
174
|
+
oldStream.removeEventListener('addtrack', handleStreamChange)
|
|
175
|
+
oldStream.removeEventListener('removetrack', handleStreamChange)
|
|
176
|
+
}
|
|
177
|
+
updateSource()
|
|
178
|
+
if(newStream) {
|
|
179
|
+
newStream.addEventListener('addtrack', handleStreamChange)
|
|
180
|
+
newStream.addEventListener('removetrack', handleStreamChange)
|
|
181
|
+
}
|
|
182
|
+
}, { immediate: true })
|
|
183
|
+
|
|
184
|
+
onMounted(() => {
|
|
185
|
+
updateSource()
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
function updateSource() {
|
|
189
|
+
console.log("UPDATE SOURCE", stream.value, "STARTED?")
|
|
190
|
+
if(mediaStreamSource) {
|
|
191
|
+
stopProcessingAudioStream()
|
|
192
|
+
}
|
|
193
|
+
if(stream.value && stream.value.getAudioTracks().length > 0) {
|
|
194
|
+
console.log("GOT AUDIO TRACKS!")
|
|
195
|
+
startProcessingAudioStream(stream.value)
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
onUnmounted(() => {
|
|
200
|
+
if(stream.value) {
|
|
201
|
+
stream.value.removeEventListener('addtrack', handleStreamChange)
|
|
202
|
+
stream.value.removeEventListener('removetrack', handleStreamChange)
|
|
203
|
+
}
|
|
204
|
+
stopProcessingAudioStream()
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
</script>
|
|
208
|
+
|
|
209
|
+
<style scoped>
|
|
210
|
+
|
|
211
|
+
</style>
|
package/front/src/router.js
CHANGED
|
@@ -34,7 +34,7 @@ export function createRouter(app, config) {
|
|
|
34
34
|
history: import.meta.env.SSR ? createMemoryHistory() : createWebHistory(),
|
|
35
35
|
routes: [
|
|
36
36
|
...dbAdminRoutes({ prefix: '/_db', route: r => ({ ...r, meta: { ...r.meta, raw: true }}) }),
|
|
37
|
-
...peerConnectionRoutes(config),
|
|
37
|
+
...peerConnectionRoutes({ ...config, prefix: '/peer-connection' }),
|
|
38
38
|
{
|
|
39
39
|
name: 'peer-connection:test-debugger', path: '/', meta: { },
|
|
40
40
|
component: () => import("./components/Debugger.vue"),
|
package/index.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import Debugger from './front/src/components/Debugger.vue'
|
|
2
2
|
import DeviceSelect from './front/src/components/DeviceSelect.vue'
|
|
3
3
|
import PermissionsDialog from './front/src/components/PermissionsDialog.vue'
|
|
4
|
+
import VolumeIndicator from './front/src/components/VolumeIndicator.vue'
|
|
4
5
|
|
|
5
|
-
export { Debugger, DeviceSelect, PermissionsDialog }
|
|
6
|
+
export { Debugger, DeviceSelect, PermissionsDialog, VolumeIndicator }
|
|
6
7
|
|
|
7
8
|
import { createPeer } from './front/src/components/Peer.js'
|
|
8
9
|
import { createPeerConnection } from './front/src/components/PeerConnection.js'
|
|
9
10
|
import { getUserMedia, getDisplayMedia, isUserMediaPermitted } from './front/src/components/userMedia.js'
|
|
11
|
+
import { mediaStreamsTracks } from './front/src/components/mediaStreamsTracks.js'
|
|
10
12
|
|
|
11
|
-
export {
|
|
13
|
+
export {
|
|
14
|
+
createPeer, createPeerConnection, getUserMedia, getDisplayMedia, isUserMediaPermitted, mediaStreamsTracks
|
|
15
|
+
}
|
|
12
16
|
|
|
13
17
|
import { peerConnectionRoutes } from './front/src/router.js'
|
|
14
18
|
export { peerConnectionRoutes }
|
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.38",
|
|
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,23 +22,25 @@
|
|
|
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.38",
|
|
26
|
+
"@live-change/dao": "^0.8.38",
|
|
27
|
+
"@live-change/dao-vue3": "^0.8.38",
|
|
28
|
+
"@live-change/dao-websocket": "^0.8.38",
|
|
29
|
+
"@live-change/framework": "^0.8.38",
|
|
30
|
+
"@live-change/password-authentication-service": "^0.8.38",
|
|
31
|
+
"@live-change/secret-code-service": "^0.8.38",
|
|
32
|
+
"@live-change/secret-link-service": "^0.8.38",
|
|
33
|
+
"@live-change/session-service": "^0.8.38",
|
|
34
|
+
"@live-change/user-frontend": "^0.8.38",
|
|
35
|
+
"@live-change/user-service": "^0.8.38",
|
|
36
|
+
"@live-change/vue3-components": "^0.8.38",
|
|
37
|
+
"@live-change/vue3-ssr": "^0.8.38",
|
|
38
38
|
"@vueuse/core": "^10.11.0",
|
|
39
|
+
"boxicons": "^2.1.4",
|
|
39
40
|
"codeceptjs-assert": "^0.0.5",
|
|
40
41
|
"compression": "^1.7.4",
|
|
41
42
|
"cross-env": "^7.0.3",
|
|
43
|
+
"feather-icons": "^4.29.2",
|
|
42
44
|
"get-port-sync": "1.0.1",
|
|
43
45
|
"primeflex": "^3.3.1",
|
|
44
46
|
"primeicons": "^7.0.0",
|
|
@@ -52,7 +54,7 @@
|
|
|
52
54
|
"vue3-scroll-border": "0.1.6"
|
|
53
55
|
},
|
|
54
56
|
"devDependencies": {
|
|
55
|
-
"@live-change/codeceptjs-helper": "^0.8.
|
|
57
|
+
"@live-change/codeceptjs-helper": "^0.8.38",
|
|
56
58
|
"codeceptjs": "^3.5.12",
|
|
57
59
|
"generate-password": "1.7.1",
|
|
58
60
|
"playwright": "^1.41.2",
|
|
@@ -63,5 +65,5 @@
|
|
|
63
65
|
"author": "Michał Łaszczewski <michal@laszczewski.pl>",
|
|
64
66
|
"license": "BSD-3-Clause",
|
|
65
67
|
"description": "",
|
|
66
|
-
"gitHead": "
|
|
68
|
+
"gitHead": "69b15b8d593c02482e1f36590089a176d72bb4cd"
|
|
67
69
|
}
|
package/server/app.config.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import App from "@live-change/framework"
|
|
2
2
|
const app = App.app()
|
|
3
3
|
|
|
4
|
+
import dotenv from 'dotenv'
|
|
5
|
+
dotenv.config()
|
|
6
|
+
|
|
4
7
|
const contactTypes = ['email', 'phone']
|
|
5
8
|
const remoteAccountTypes = ['google']
|
|
6
9
|
|
|
@@ -108,6 +111,10 @@ app.config = {
|
|
|
108
111
|
turn: {
|
|
109
112
|
urls: 'turn:turn.chaosu.pl:4433'
|
|
110
113
|
}
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: 'videoCall',
|
|
117
|
+
path: "@live-change/video-call-service",
|
|
111
118
|
}
|
|
112
119
|
]
|
|
113
120
|
}
|