`oh-sipclient`: Various fixes & improvements (#1857)

Closes #1690.
Closes #1691.

* Improves alert message shown when HTTP is used to clearly indicate
that the SIP widget will only work with HTTPS.
* Fixes an error thrown when the SIP widget was not properly initialized
and leaves foreground.
* Upgrades JsSIP.
* Improves styling to use 100% of available height.

--
Signed-off-by: Florian Hotze <florianh_dev@icloud.com>
pull/1878/head
Florian Hotze 2023-05-07 14:22:56 +02:00 committed by GitHub
parent 52da897b33
commit b9d57f04dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 61 additions and 27 deletions

View File

@ -113,6 +113,11 @@ Usage is explained at the [`oh-sipclient` component docs](/docs/ui/components/oh
Default video aspect ratio used to size the widget before video is loaded. Defaults to 4/3, 16/9 and 1 are common alternatives.
</PropDescription>
</PropBlock>
<PropBlock type="BOOLEAN" name="disableRegister" label="Disable REGISTER">
<PropDescription>
SIP registration can be disabled in case you only want to initiate calls, but not receive calls with the SIP widgets.
</PropDescription>
</PropBlock>
<PropBlock type="BOOLEAN" name="enableSIPDebug" label="Enable SIP debugging to the browser console (dev tools)">
</PropBlock>
</PropGroup>

View File

@ -117,6 +117,11 @@ This can be achieved by configuring the widget as usual, but setting SIP usernam
Default video aspect ratio used to size the widget before video is loaded. Defaults to 4/3, 16/9 and 1 are common alternatives.
</PropDescription>
</PropBlock>
<PropBlock type="BOOLEAN" name="disableRegister" label="Disable REGISTER">
<PropDescription>
SIP registration can be disabled in case you only want to initiate calls, but not receive calls with the SIP widgets.
</PropDescription>
</PropBlock>
<PropBlock type="BOOLEAN" name="enableSIPDebug" label="Enable SIP debugging to the browser console (dev tools)">
</PropBlock>
</PropGroup>

View File

@ -29,7 +29,7 @@
"framework7-icons": "^3.0.1",
"framework7-vue": "^5.7.12",
"jse-eval": "^1.5.1",
"jssip": "^3.9.1",
"jssip": "^3.10.0",
"leaflet": "^1.7.1",
"leaflet-providers": "^1.11.0",
"lodash": "^4.17.20",
@ -3915,6 +3915,11 @@
"integrity": "sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg==",
"dev": true
},
"node_modules/@types/events": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
"integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g=="
},
"node_modules/@types/glob": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz",
@ -3991,7 +3996,8 @@
"node_modules/@types/node": {
"version": "14.18.12",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.12.tgz",
"integrity": "sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A=="
"integrity": "sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A==",
"dev": true
},
"node_modules/@types/parse-json": {
"version": "4.0.0",
@ -14022,12 +14028,12 @@
}
},
"node_modules/jssip": {
"version": "3.9.1",
"resolved": "https://registry.npmjs.org/jssip/-/jssip-3.9.1.tgz",
"integrity": "sha512-hl8jxkte4p0zHl9Nen03rdwP8lbBwMy3SnrmzVf7f+Jhvnz7gF/WXdFi35zpEpxAmxFLczxD4U8ATK/CHEwhqw==",
"version": "3.10.0",
"resolved": "https://registry.npmjs.org/jssip/-/jssip-3.10.0.tgz",
"integrity": "sha512-iJj+bhnNl0S296sUDc2ZjIbAetnelzZ92aWARyW01oKZ0X8t+5aGrYfJdMFliLFm8hxMcnkep3vmSRGe/yRjsA==",
"dependencies": {
"@types/debug": "^4.1.5",
"@types/node": "^14.14.34",
"@types/debug": "^4.1.7",
"@types/events": "^3.0.0",
"debug": "^4.3.1",
"events": "^3.3.0",
"sdp-transform": "^2.14.1"
@ -27509,6 +27515,11 @@
"integrity": "sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg==",
"dev": true
},
"@types/events": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
"integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g=="
},
"@types/glob": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz",
@ -27585,7 +27596,8 @@
"@types/node": {
"version": "14.18.12",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.12.tgz",
"integrity": "sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A=="
"integrity": "sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A==",
"dev": true
},
"@types/parse-json": {
"version": "4.0.0",
@ -35880,12 +35892,12 @@
}
},
"jssip": {
"version": "3.9.1",
"resolved": "https://registry.npmjs.org/jssip/-/jssip-3.9.1.tgz",
"integrity": "sha512-hl8jxkte4p0zHl9Nen03rdwP8lbBwMy3SnrmzVf7f+Jhvnz7gF/WXdFi35zpEpxAmxFLczxD4U8ATK/CHEwhqw==",
"version": "3.10.0",
"resolved": "https://registry.npmjs.org/jssip/-/jssip-3.10.0.tgz",
"integrity": "sha512-iJj+bhnNl0S296sUDc2ZjIbAetnelzZ92aWARyW01oKZ0X8t+5aGrYfJdMFliLFm8hxMcnkep3vmSRGe/yRjsA==",
"requires": {
"@types/debug": "^4.1.5",
"@types/node": "^14.14.34",
"@types/debug": "^4.1.7",
"@types/events": "^3.0.0",
"debug": "^4.3.1",
"events": "^3.3.0",
"sdp-transform": "^2.14.1"

View File

@ -81,7 +81,7 @@
"framework7-icons": "^3.0.1",
"framework7-vue": "^5.7.12",
"jse-eval": "^1.5.1",
"jssip": "^3.9.1",
"jssip": "^3.10.0",
"leaflet": "^1.7.1",
"leaflet-providers": "^1.11.0",
"lodash": "^4.17.20",

View File

@ -13,5 +13,6 @@ export default () => [
pb('enableVideo', 'Enable Video', 'Enable video calling'),
pb('enableLocalVideo', 'Enable Local Video View', 'Display the local camera on video calls'),
pt('defaultVideoAspectRatio', 'Default Aspect Ratio', 'Default video aspect ratio used to size the widget before video is loaded. Defaults to 4/3, 16/9 and 1 are common alternatives.').a(),
pb('disableRegister', 'Disable REGISTER', 'SIP registration can be disabled in case you only want to initiate calls, but not receive calls with the SIP widgets.').a(),
pb('enableSIPDebug', 'Enable SIP debugging to the browser console (dev tools)').a()
]

View File

@ -10,23 +10,23 @@
<video v-show="showLocalVideo" ref="localVideo" autoplay playsinline muted="muted" class="local-video" />
</div>
<!-- Show yellow dial button if connection is not established -->
<f7-button v-if="!connected" :style="{ height: config.iconSize + 'px' }" icon-f7="phone_fill_arrow_up_right" icon-color="yellow" :icon-size="config.iconSize" />
<f7-button v-if="!connected" :style="computedButtonStyle" icon-f7="phone_fill_arrow_up_right" icon-color="yellow" :icon-size="config.iconSize" />
<!-- Show dial menu when there`s no call -->
<f7-button v-else-if="(!session || session.isEnded())" :style="{ height: config.iconSize + 'px' }" icon-f7="phone_fill_arrow_up_right" icon-color="green" :icon-size="config.iconSize" @click.stop="dial()" />
<f7-button v-else-if="(!session || session.isEnded())" :style="computedButtonStyle" icon-f7="phone_fill_arrow_up_right" icon-color="green" :icon-size="config.iconSize" @click.stop="dial()" />
<!-- Show answer button on incoming call -->
<f7-segmented v-else-if="session && session.direction === 'incoming' && session.isInProgress()">
<f7-button :style="{ height: config.iconSize + 'px' }" icon-f7="phone_fill_arrow_down_left" icon-color="green" :icon-size="config.iconSize" @click.stop="answer()">
{{ (!config.hideCallerId) ? this.remoteParty : '' }}
<f7-segmented v-else-if="session && session.direction === 'incoming' && session.isInProgress()" style="width: 100%; height: 100%">
<f7-button :style="computedButtonStyle" icon-f7="phone_fill_arrow_down_left" icon-color="green" :icon-size="config.iconSize" @click.stop="answer()">
{{ (!config.hideCallerId) ? remoteParty : '' }}
</f7-button>
<f7-button :style="{ height: config.iconSize + 'px' }" icon-f7="phone_down_fill" icon-color="red" :icon-size="config.iconSize" @click.stop="session.terminate()" />
<f7-button :style="computedButtonStyle" icon-f7="phone_down_fill" icon-color="red" :icon-size="config.iconSize" @click.stop="session.terminate()" />
</f7-segmented>
<f7-segmented v-else>
<f7-segmented v-else style="width: 100%; height: 100%">
<!-- Show hangup button for outgoing call -->
<f7-button v-if="session && session.isInProgress()" :style="{ height: config.iconSize + 'px' }" icon-f7="phone_down_fill" icon-color="yellow" :icon-size="config.iconSize" @click.stop="session.terminate()" />
<f7-button v-if="session && session.isInProgress()" :style="computedButtonStyle" icon-f7="phone_down_fill" icon-color="yellow" :icon-size="config.iconSize" @click.stop="session.terminate()" />
<!-- Show hangup button for ongoing call -->
<f7-button v-else-if="session && !session.isEnded()" :style="{ height: config.iconSize + 'px' }" icon-f7="phone_down_fill" icon-color="red" :icon-size="config.iconSize" @click.stop="session.terminate()" />
<f7-button v-else-if="session && !session.isEnded()" :style="computedButtonStyle" icon-f7="phone_down_fill" icon-color="red" :icon-size="config.iconSize" @click.stop="session.terminate()" />
<!-- Show send dtmf button if in a call and feature is enabled-->
<f7-button v-if="session && !session.isInProgress() && !session.isEnded() && config.dtmfString && config.dtmfString.length > 0" :style="{ height: config.iconSize + 'px' }" icon-f7="number_square" icon-color="orange" :icon-size="config.iconSize" @click.stop="sendDTMF()" />
<f7-button v-if="session && !session.isInProgress() && !session.isEnded() && config.dtmfString && config.dtmfString.length > 0" :style="computedButtonStyle" icon-f7="number_square" icon-color="orange" :icon-size="config.iconSize" @click.stop="sendDTMF()" />
</f7-segmented>
</div>
</template>
@ -34,6 +34,7 @@
<style lang="stylus">
.main-container
width: 100%
height: 100%
.video-container
position relative
.remote-video
@ -73,6 +74,15 @@ export default {
},
mixins: [mixin, foregroundService, actionsMixin],
widget: OhSIPClientDefinition,
computed: {
computedButtonStyle () {
return {
'min-height': this.config.iconSize + 'px',
height: '100%',
display: 'flex'
}
}
},
methods: {
startForegroundActivity () {
// Load device specific configuration
@ -90,7 +100,7 @@ export default {
// Make sure we have Mic/Camera permissions
if (!navigator.mediaDevices) {
this.$f7.dialog.alert('Please ensure that HTTPS is in use and WebRTC is supported in this browser.')
this.$f7.dialog.alert('To use the SIP widget, please make sure that HTTPS is in use and WebRTC is supported by this browser.')
} else {
navigator.mediaDevices.getUserMedia({ audio: true, video: this.config.enableVideo })
.then((stream) => {
@ -108,7 +118,7 @@ export default {
},
stopForegroundActivity () {
// Stop MediaDevices access here, otherwise Mic/Camera access will stay active on iOS
this.stream.getTracks().forEach((track) => track.stop())
if (this.stream) this.stream.getTracks().forEach((track) => track.stop())
if (this.phone) this.phone.stop()
},
/**
@ -131,7 +141,8 @@ export default {
sockets: [socket],
uri: 'sip:' + this.config.username + '@' + this.config.domain,
password: this.config.password,
session_timers: false
session_timers: false,
register: (this.config.disableRegister !== true)
}
this.phone = new JsSIP.UA(configuration)