I am currently building web app with Vue. This web app streams RTSP, which I get from underwater drones with cameras. Here is the code: ** SidebarItem**
<li>
<a>{{ name }}</a>
</li>
export default {
props: {
name: String,
url: String,
},
};
Player
<link href="https://fonts.googleapis.com/css2?family=Josefin+Sans&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://unpkg.com/boxicons@latest/css/boxicons.min.css">
<div class="fullscreen-player">
<div :id="elementId" />
</div>
<div class="sidebar-container">
<div class="sidebar-wrapper">
<aside :class="['sidebar', { 'open': showSidebar, 'closed': !showSidebar }]">
<div class="sidebar-background">
<div class="sidebar-header">
<p style="font-weight: bolder;"><i class="bx bx-current-location"></i> Bathyscaphe</p>
</div>
<hr class="rounded">
<div class="select-container">
<div><p style="font-size: 1.2vw; color: #e2e2e2; margin-bottom: 1vh;">Currently streaming:</p> {{ selected }}</div>
<select class="custom-select" v-model="selectedDevice" @change="updateFilteredStreams">
<option id="mySelect" disabled value="">Select the drone</option>
<option v-for="device in devices" :key="device">{{ device }}</option>
</select>
</div>
<hr class="rounded">
<ul>
<li v-for="(url, name) in filteredStreams" :key="name">
<button class="sidebar-button" :name="name" :value="url" @click="handleStreamSelected(name)" :disabled="streamErrors.includes(name)">
<sidebar-item :name="name" :uuid="name"></sidebar-item>
</button>
</li>
</ul>
</div>
</aside>
<toggle-button :show-sidebar="showSidebar" @toggle-sidebar="toggleSidebar"></toggle-button>
</div>
</div>
import RTSPtoWEBPlayer from "rtsptowebplayer";
import ToggleButton from './ToggleButton.vue';
import SidebarItem from './SidebarItem.vue';
import configData from './../../RTSPtoWebRTC/config.json';
export default {
name: "PlayerVue",
computed: {
filteredStreams() {
return Object.entries(this.streams).reduce((filtered, [name, stream]) => {
if (stream.deviceNumber.toString() === this.selectedDevice) {
filtered[name] = stream.url;
}
return filtered;
}, {});
},
},
data() {
return {
config: {},
streams: {},
showSidebar: true,
devices: [],
selectedDevice: '',
filteredStreamsData: {},
uuid: '',
elementId: 'player',
streamErrors: [],
player: null,
};
},
methods: {
toggleSidebar() {
this.showSidebar = !this.showSidebar;
},
updateFilteredStreams() {
this.filteredStreamsData = this.filteredStreams;
},
handleStreamSelected(uuid) {
this.uuid = uuid;
const server = "127.0.0.1:8083";
const source = `http://${server}/stream/receiver/${uuid}`;
this.player.destroy(); // Destroy the existing player
const options = {
controls: false,
parentElement: document.getElementById(this.elementId),
autoplay: true
};
this.player = new RTSPtoWEBPlayer(options);
this.player.load(source);
},
},
created() {
this.config = configData;
this.streams = configData.streams;
this.devices = [...new Set(Object.values(this.streams).map((stream) => stream.deviceNumber))];
this.selectedDevice = this.devices[0].toString();
},
components: {
SidebarItem,
ToggleButton
},
mounted() {
const server = "127.0.0.1:8083";
const uuid = "Japan";
const source = `http://${server}/stream/receiver/${uuid}`;
const options = {
controls: false,
parentElement: document.getElementById(this.elementId),
autoplay: true
};
this.player = new RTSPtoWEBPlayer(options);
this.player.load(source);
},
beforeUnmount() {
this.player.destroy();
}
};
@import url("../assets/sidebar.css");
.fullscreen-player {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
overflow: hidden;
/* fix scaling */
}
**config.json: **
{ "server": { "http_port": ":8083", "ice_servers": [ "stun:stun.example.com:19302" ] }, "streams": { "Japan": { "deviceNumber": "Not Russia", "on_demand": true, "disable_audio": false, "url": "rtsp://admin:12345@95.154.86.198:554/" }, "Vladivostok": { "deviceNumber": "Russia", "on_demand": true, "disable_audio": false, "url": "rtsp://admin:12345@95.154.69.152:554/" }, "Khabarovsk": { "deviceNumber": "Russia", "on_demand": true, "disable_audio": false, "url": "rtsp://admin:12345@95.154.86.198:554/" } } }`
I get RTSP urls from json. And here I face the problem that when the stream is borken: off, url is incorrect et.c. my screen gives me an error. How do I fix it? I want buttons to be disabled when the stream the are reffering to is not somehow working
Uncaught (in promise) DOMException: SIPCC Failed to parse SDP: SDP Parse Error on line 1: End of line beyond end of buffer. setRemoteDescription common_shim.js:243 RTSPtoWEBPlayer rtsp-to-web-player.js:218 like this or: 2023/07/22 21:27:35 Stream Try Connect Vladivostok 2023/07/22 21:27:38 dial tcp 95.154.69.152:554: i/o timeout 2023/07/22 21:27:38 Stream Exit On Demand No Viewer 2023/07/22 21:27:40 Stream Codec Not Found in terminal
Ive tried
async checkStreamStatus(url) {
try {
const response = await fetch(url);
return response.ok;
} catch (error) {
return false;
}
},
}
filteredStreams() {
return Object.entries(this.streams).reduce((filtered, [name, stream]) => {
if (stream.deviceNumber.toString() === this.selectedDevice) {
const streamStatus = this.checkStreamStatus(stream.url);
filtered[name] = { url: stream.url, status: streamStatus };
}
return filtered;
}, {});
},
},
<button class="sidebar-button" :name="name" :value="stream.url" @click="handleStreamSelected(name)" :disabled="!stream.status">
<sidebar-item :name="name" :uuid="name"></sidebar-item>
</button>
</li>
It appears that the streams may not return a proper response when checked using the fetch method as fetch works with HTTP-based responses and may not handle RTSP stream statuses.