From fb2121173a846ff609749f8bf6171170fc783e24 Mon Sep 17 00:00:00 2001 From: Stefan Dej Date: Wed, 21 Aug 2024 21:38:36 +0200 Subject: [PATCH 1/9] refactor: refactor then/catch to try/catch Signed-off-by: Stefan Dej --- .../webcams/streamers/WebrtcMediaMTX.vue | 126 +++++++++--------- 1 file changed, 62 insertions(+), 64 deletions(-) diff --git a/src/components/webcams/streamers/WebrtcMediaMTX.vue b/src/components/webcams/streamers/WebrtcMediaMTX.vue index 189e9e18e..93d865e36 100644 --- a/src/components/webcams/streamers/WebrtcMediaMTX.vue +++ b/src/components/webcams/streamers/WebrtcMediaMTX.vue @@ -96,7 +96,7 @@ export default class WebrtcMediaMTX extends Mixins(BaseMixin, WebcamMixin) { return this.$store.getters['gui/getPanelExpand']('webcam-panel', this.viewport) ?? false } - // start or stop the video when the expand state changes + // start or stop the video when the expanded state changes @Watch('expanded') expandChanged(newExpanded: boolean): void { if (!newExpanded) { @@ -198,7 +198,7 @@ export default class WebrtcMediaMTX extends Mixins(BaseMixin, WebcamMixin) { return frag } - start() { + async start() { // stop if url is not valid if (this.url === null) { this.log('invalid url') @@ -209,14 +209,13 @@ export default class WebrtcMediaMTX extends Mixins(BaseMixin, WebcamMixin) { this.log('requesting ICE servers from ' + this.url) - fetch(this.url, { - method: 'OPTIONS', - }) - .then((res) => this.onIceServers(res)) - .catch((err) => { - this.log('error: ' + err) - this.scheduleRestart() - }) + try { + const res = await fetch(this.url, { method: 'OPTIONS' }) + this.onIceServers(res) + } catch (err) { + this.log('error: ' + err) + this.scheduleRestart() + } } onIceServers(res: Response) { @@ -246,40 +245,37 @@ export default class WebrtcMediaMTX extends Mixins(BaseMixin, WebcamMixin) { } // eslint-disable-next-line no-undef - onLocalOffer(offer: RTCSessionDescriptionInit) { - this.offerData = this.parseOffer(offer.sdp ?? '') - this.pc?.setLocalDescription(offer) - - fetch(this.url ?? '', { - method: 'POST', - headers: { - 'Content-Type': 'application/sdp', - }, - body: offer.sdp, - }) - .then((res) => { - if (res.status !== 201) throw new Error('bad status code') - this.eTag = res.headers.get('ETag') - const location = res.headers.get('Location') ?? '' - this.sessionUuid = location?.substring(location.lastIndexOf('/') + 1) ?? null + async onLocalOffer(offer: RTCSessionDescriptionInit) { + try { + const res = await fetch(this.url ?? '', { + method: 'POST', + headers: { 'Content-Type': 'application/sdp' }, + body: offer.sdp, + }) - // fallback for MediaMTX v1.0.x with broken ETag header - if (res.headers.has('E-Tag')) this.eTag = res.headers.get('E-Tag') + if (res.status !== 201) new Error('bad status code') - return res.text() - }) - .then((sdp) => { - this.onRemoteAnswer( - new RTCSessionDescription({ - type: 'answer', - sdp, - }) - ) - }) - .catch((err) => { - this.log(err) - this.scheduleRestart() - }) + this.offerData = this.parseOffer(offer.sdp ?? '') + this.pc?.setLocalDescription(offer) + + this.eTag = res.headers.get('ETag') + const location = res.headers.get('Location') ?? '' + this.sessionUuid = location?.substring(location.lastIndexOf('/') + 1) ?? null + + // fallback for MediaMTX v1.0.x with broken ETag header + if (res.headers.has('E-Tag')) this.eTag = res.headers.get('E-Tag') + + const sdp = await res.text() + this.onRemoteAnswer( + new RTCSessionDescription({ + type: 'answer', + sdp, + }) + ) + } catch (err: any) { + this.log(err?.message ?? err ?? 'unknown error') + this.scheduleRestart() + } } onRemoteAnswer(answer: RTCSessionDescription) { @@ -319,7 +315,7 @@ export default class WebrtcMediaMTX extends Mixins(BaseMixin, WebcamMixin) { } } - sendLocalCandidates(candidates: RTCIceCandidate[]) { + async sendLocalCandidates(candidates: RTCIceCandidate[]) { if (this.sessionUuid === null) { this.log('Session-UUID is null') this.scheduleRestart() @@ -328,29 +324,31 @@ export default class WebrtcMediaMTX extends Mixins(BaseMixin, WebcamMixin) { } const url = (this.url ?? '') + '/' + this.sessionUuid - fetch(url, { - method: 'PATCH', - headers: { - 'Content-Type': 'application/trickle-ice-sdpfrag', - 'If-Match': this.eTag, - // eslint-disable-next-line no-undef - } as HeadersInit, - body: this.generateSdpFragment(this.offerData, candidates), - }) - .then((res) => { - switch (res.status) { - case 204: - break - case 404: - throw new Error('stream not found') - default: - throw new Error(`bad status code ${res.status}`) - } + try { + const res = await fetch(url, { + method: 'PATCH', + headers: { + 'Content-Type': 'application/trickle-ice-sdpfrag', + 'If-Match': this.eTag, + // eslint-disable-next-line no-undef + } as HeadersInit, + body: this.generateSdpFragment(this.offerData, candidates), }) - .catch((err) => { - this.log(err) + + if (res.status === 204) return + + if (res.status === 404) { + this.log('stream not found') this.scheduleRestart() - }) + return + } + + this.log(`bad status code ${res.status}`) + this.scheduleRestart() + } catch (err: any) { + this.log(err) + this.scheduleRestart() + } } terminate() { From f4aa3a5f8917c07170aa18b823382647d80b88a3 Mon Sep 17 00:00:00 2001 From: Stefan Dej Date: Wed, 21 Aug 2024 23:04:04 +0200 Subject: [PATCH 2/9] fix(MediaMTX): fix webcam state when panel is closed on dashboard Signed-off-by: Stefan Dej --- src/components/panels/WebcamPanel.vue | 2 +- src/components/webcams/WebcamWrapper.vue | 9 +++++++-- src/components/webcams/WebcamWrapperItem.vue | 3 ++- .../webcams/streamers/WebrtcMediaMTX.vue | 20 ++++++------------- src/pages/Webcam.vue | 2 +- 5 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/components/panels/WebcamPanel.vue b/src/components/panels/WebcamPanel.vue index 652c3e5c8..b0f935cc3 100644 --- a/src/components/panels/WebcamPanel.vue +++ b/src/components/panels/WebcamPanel.vue @@ -42,7 +42,7 @@ - + diff --git a/src/components/webcams/WebcamWrapper.vue b/src/components/webcams/WebcamWrapper.vue index cd2dfb679..a67f3196a 100644 --- a/src/components/webcams/WebcamWrapper.vue +++ b/src/components/webcams/WebcamWrapper.vue @@ -4,13 +4,17 @@ - + @@ -31,6 +35,7 @@ export default class WebcamWrapper extends Mixins(BaseMixin) { @Prop({ type: Object, required: true }) webcam!: GuiWebcamStateWebcam @Prop({ type: Boolean, default: true }) showFps!: Boolean @Prop({ type: String, default: null }) printerUrl!: string | null + @Prop({ type: String, default: null }) page!: string | null get webcams(): GuiWebcamStateWebcam[] { return this.$store.getters['gui/webcams/getWebcams'] diff --git a/src/components/webcams/WebcamWrapperItem.vue b/src/components/webcams/WebcamWrapperItem.vue index 4e7217ef1..8d95a42f7 100644 --- a/src/components/webcams/WebcamWrapperItem.vue +++ b/src/components/webcams/WebcamWrapperItem.vue @@ -25,7 +25,7 @@