diff --git a/server/index.js b/server/index.js index eb905ca7..5b20b6f6 100644 --- a/server/index.js +++ b/server/index.js @@ -444,10 +444,11 @@ app.get('/api/softwareinfo', (req, res) => { app.get('/api/videodevices', (req, res) => { vManager.populateAddresses() - vManager.getVideoDevices((err, devices, active, seldevice, selRes, selRot, selbitrate, selfps, SeluseUDP, SeluseUDPIP, SeluseUDPPort, timestamp, fps, FPSMax, vidres) => { + vManager.getVideoDevices((err, devices, active, seldevice, selRes, selRot, selbitrate, selfps, SeluseUDP, SeluseUDPIP, SeluseUDPPort, timestamp, fps, FPSMax, vidres, selMavURI) => { if (!err) { res.setHeader('Content-Type', 'application/json') res.send(JSON.stringify({ + ifaces: vManager.ifaces, dev: devices, vidDeviceSelected: seldevice, vidres: vidres, @@ -463,7 +464,8 @@ app.get('/api/videodevices', (req, res) => { timestamp, error: null, fps: fps, - FPSMax: FPSMax + FPSMax: FPSMax, + mavStreamSelected: selMavURI })) } else { res.setHeader('Content-Type', 'application/json') @@ -722,7 +724,7 @@ app.post('/api/startstopvideo', [check('active').isBoolean(), return res.status(422).json(ret) } // user wants to start/stop video streaming - vManager.startStopStreaming(req.body.active, req.body.device, req.body.height, req.body.width, req.body.format, req.body.rotation, req.body.bitrate, req.body.fps, req.body.useUDP, req.body.useUDPIP, req.body.useUDPPort, req.body.useTimestamp, (err, status, addresses) => { + vManager.startStopStreaming(req.body.active, req.body.device, req.body.height, req.body.width, req.body.format, req.body.rotation, req.body.bitrate, req.body.fps, req.body.useUDP, req.body.useUDPIP, req.body.useUDPPort, req.body.useTimestamp, req.body.mavStreamSelected, (err, status, addresses) => { if (!err) { res.setHeader('Content-Type', 'application/json') const ret = { streamingStatus: status, streamAddresses: addresses } diff --git a/server/videostream.js b/server/videostream.js index e7daee72..5941fd50 100644 --- a/server/videostream.js +++ b/server/videostream.js @@ -26,12 +26,12 @@ class videoStream { // need to scan for video devices first though if (this.active) { this.active = false - this.getVideoDevices((error, devices, active, seldevice, selRes, selRot, selbitrate, thisps, selUDP, selUDPIP, selUDPPort, useTimestamp) => { + this.getVideoDevices((error, devices, active, seldevice, selRes, selRot, selbitrate, thisps, selUDP, selUDPIP, selUDPPort, useTimestamp, selMavURI) => { if (!error) { this.startStopStreaming(true, this.savedDevice.device, this.savedDevice.height, this.savedDevice.width, this.savedDevice.format, this.savedDevice.rotation, this.savedDevice.bitrate, this.savedDevice.fps, this.savedDevice.useUDP, - this.savedDevice.useUDPIP, this.savedDevice.useUDPPort, this.savedDevice.useTimestamp, + this.savedDevice.useUDPIP, this.savedDevice.useUDPPort, this.savedDevice.useTimestamp, this.savedDevice.mavStreamSelected, (err, status, addresses) => { if (err) { // failed setup, reset settings @@ -62,7 +62,7 @@ class videoStream { // video streaming getVideoDevices (callback) { // get all video device details - // callback is: err, devices, active, seldevice, selRes, selRot, selbitrate, selfps, SeluseUDP, SeluseUDPIP, SeluseUDPPort, timestamp, fps, FPSMax, vidres + // callback is: err, devices, active, seldevice, selRes, selRot, selbitrate, selfps, SeluseUDP, SeluseUDPIP, SeluseUDPPort, timestamp, fps, FPSMax, vidres, selMavURI exec('python3 ./python/gstcaps.py', (error, stdout, stderr) => { const warnstrings = ['DeprecationWarning', 'gst_element_message_full_with_details', 'camera_manager.cpp', 'Unsupported V4L2 pixel format'] if (stderr && !warnstrings.some(wrn => stderr.includes(wrn))) { @@ -107,7 +107,7 @@ class videoStream { { label: this.savedDevice.rotation.toString() + '°', value: this.savedDevice.rotation }, this.savedDevice.bitrate, selFPS, this.savedDevice.useUDP, this.savedDevice.useUDPIP, this.savedDevice.useUDPPort, this.savedDevice.useTimestamp, (selRes[0].fps !== undefined) ? selRes[0].fps : [], - selRes[0].fpsmax, seldevice[0].caps) + selRes[0].fpsmax, seldevice[0].caps, this.savedDevice.mavStreamSelected) } else { // bad settings console.error('Bad video settings. Resetting' + seldevice + ', ' + selRes) @@ -161,7 +161,8 @@ class videoStream { return iface } - async startStopStreaming (active, device, height, width, format, rotation, bitrate, fps, useUDP, useUDPIP, useUDPPort, useTimestamp, callback) { + async startStopStreaming (active, device, height, width, format, rotation, bitrate, fps, useUDP, useUDPIP, useUDPPort, useTimestamp, mavStreamSelected, callback) { + // if current state same, don't do anything if (this.active === active) { console.log('Video current same') @@ -200,7 +201,8 @@ class videoStream { useUDP, useUDPIP, useUDPPort, - useTimestamp + useTimestamp, + mavStreamSelected } // note that video device URL's are the alphanumeric characters only. So /dev/video0 -> devvideo0 @@ -295,7 +297,7 @@ class videoStream { } if (packet.header.msgid === common.CommandLong.MSG_ID & data._param1 === common.VideoStreamInformation.MSG_ID) { - console.log("Responding to MAVLink request for VideoStreamInformation") + console.log('Responding to MAVLink request for VideoStreamInformation') this.winston.info('Responding to MAVLink request for VideoStreamInformation') const senderSysId = packet.header.sysid @@ -303,14 +305,14 @@ class videoStream { // build a VIDEO_STREAM_INFORMATION packet const msg = new common.VideoStreamInformation() - + // rpanion only supports a single stream, so streamId and count will always be 1 msg.streamId = 1; msg.count = 1; // 0 = VIDEO_STREAM_TYPE_RTSP // 1 = VIDEO_STREAM_TYPE_RTPUDP - if(this.savedDevice.useUDP = "rtp") { + if (this.savedDevice.useUDP == 'rtp') { msg.type = 1 } else { msg.type = 0 @@ -318,23 +320,22 @@ class videoStream { // 1 = VIDEO_STREAM_STATUS_FLAGS_RUNNING // 2 = VIDEO_STREAM_STATUS_FLAGS_THERMAL - msg.flags = 1; - msg.framerate = this.savedDevice.fps; - msg.resolutionH = this.savedDevice.width; - msg.resolutionV = this.savedDevice.height; - msg.bitrate = this.savedDevice.bitrate; - msg.rotation = this.savedDevice.rotation; + msg.flags = 1 + msg.framerate = this.savedDevice.fps + msg.resolutionH = this.savedDevice.width + msg.resolutionV = this.savedDevice.height + msg.bitrate = this.savedDevice.bitrate + msg.rotation = this.savedDevice.rotation // Rpanion doesn't collect field of view values, so just set to zero - msg.hfov = 0; - msg.name = this.savedDevice.device; + msg.hfov = 0 + msg.name = this.savedDevice.device // To do: add a UI option to select which interface's URI to send - msg.uri = this.deviceAddresses[1]; + msg.uri = this.deviceAddresses[this.savedDevice.mavStreamSelected] + // console.log("mavStreamSelected: " + this.savedDevice.mavStreamSelected) this.eventEmitter.emit('videostreaminfo', msg, senderSysId, senderCompId) } - -} - + } } module.exports = videoStream diff --git a/src/video.js b/src/video.js index c7eba534..e68d4bf6 100644 --- a/src/video.js +++ b/src/video.js @@ -12,6 +12,7 @@ class VideoPage extends basePage { constructor(props) { super(props); this.state = { + ifaces: [], dev: [], vidDeviceSelected: this.props.vidDeviceSelected, vidres: [], @@ -30,7 +31,8 @@ class VideoPage extends basePage { loading: true, error: null, infoMessage: null, - timestamp: false + timestamp: false, + mavStreamSelected: { label: "127.0.0.1", value: 0 } } } @@ -94,6 +96,11 @@ class VideoPage extends basePage { this.setState({ timestamp: !this.state.timestamp }); } + handleMavStreamChange = (value) => { + //new value for selected stream IP + this.setState({ mavStreamSelected: value }); + } + handleStreaming = (event) => { //user clicked start/stop streaming this.setState({ waiting: true }, () => { @@ -117,6 +124,7 @@ class VideoPage extends basePage { useUDPIP: this.state.useUDPIP, useUDPPort: this.state.useUDPPort, useTimestamp: this.state.timestamp, + mavStreamSelected: this.state.mavStreamSelected.value, }) }).then(response => response.json()).then(state => { this.setState(state); this.setState({ waiting: false }) }); }); @@ -186,6 +194,12 @@ class VideoPage extends basePage { fps (max: {this.state.FPSMax}) +
+ +
+