[ANNOUNCE]node-red-contrib-ui-media-recorder - beta version

Hi folks,

Based on another discussion (a.o. with @wym and @janvda) I developed the node-red-contrib-ui-media-recorder node, which can record video from the webcam via the Node-RED dashboard.

I'm still stuck on this discourse issue, so would be nice if somebody could help me with it...

And would be nice to get some creative ideas about this one:

Currently I use hardcoded settings for the video (e.g. 640x460), but that should be configurable in the dashboard. Indeed this must be done in client-side, since the server-side doesn't know anything about the hardware capabilities of the connected client devices...

Since the node is not published on NPM yet, you can install it directly from my Github repository:

npm install bartbutenaers/node-red-contrib-ui-media-recorder

And finally a short demo (which requires the node-red-contrib-image-output node):

[{"id":"fc4adf7d.8a73e","type":"ui_button","z":"30fb1577.8f556a","name":"Snapshot image","group":"e5e4ba3f.5290e8","order":2,"width":0,"height":0,"passthru":false,"label":"Snapshot image","tooltip":"","color":"","bgcolor":"","icon":"fa-camera","payload":"take_picture","payloadType":"str","topic":"","x":340,"y":320,"wires":[["63f84e8b.d1da4"]]},{"id":"19263e4c.dd3d92","type":"change","z":"30fb1577.8f556a","name":"","rules":[{"t":"set","p":"interval","pt":"msg","to":"1000","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":340,"y":200,"wires":[["63f84e8b.d1da4"]]},{"id":"85d109dc.a129a8","type":"ui_button","z":"30fb1577.8f556a","name":"Hide video","group":"e5e4ba3f.5290e8","order":3,"width":0,"height":0,"passthru":false,"label":"Hide video","tooltip":"","color":"","bgcolor":"","icon":"fa-eye-slash","payload":"hide_video","payloadType":"str","topic":"","x":350,"y":160,"wires":[["63f84e8b.d1da4"]]},{"id":"5f1946d0.9b5cb8","type":"ui_button","z":"30fb1577.8f556a","name":"Show video","group":"e5e4ba3f.5290e8","order":4,"width":"0","height":"0","passthru":false,"label":"Display video","tooltip":"","color":"","bgcolor":"","icon":"fa-eye ","payload":"display_video","payloadType":"str","topic":"","x":350,"y":120,"wires":[["63f84e8b.d1da4"]]},{"id":"ab2a14e4.1942e8","type":"ui_button","z":"30fb1577.8f556a","name":"Start timer","group":"e5e4ba3f.5290e8","order":5,"width":0,"height":0,"passthru":false,"label":"Start timer","tooltip":"","color":"","bgcolor":"","icon":"fa-clock-o","payload":"start_timer","payloadType":"str","topic":"","x":150,"y":200,"wires":[["19263e4c.dd3d92"]]},{"id":"9914e0da.b67ca","type":"ui_button","z":"30fb1577.8f556a","name":"Stop recording","group":"e5e4ba3f.5290e8","order":7,"width":0,"height":0,"passthru":false,"label":"Stop streaming/timer","tooltip":"","color":"","bgcolor":"","icon":"fa-hand-paper-o","payload":"stop","payloadType":"str","topic":"","x":340,"y":240,"wires":[["63f84e8b.d1da4"]]},{"id":"8bbecf73.74861","type":"ui_button","z":"30fb1577.8f556a","name":"Start streaming","group":"e5e4ba3f.5290e8","order":6,"width":0,"height":0,"passthru":false,"label":"Start streaming","tooltip":"","color":"","bgcolor":"","icon":"fa-video-camera","payload":"start_streaming","payloadType":"str","topic":"","x":340,"y":280,"wires":[["63f84e8b.d1da4"]]},{"id":"c4f6319c.2ccde","type":"image","z":"30fb1577.8f556a","name":"","width":160,"x":800,"y":120,"wires":[]},{"id":"63f84e8b.d1da4","type":"ui_media_recorder","z":"30fb1577.8f556a","group":"e5e4ba3f.5290e8","name":"","order":1,"width":0,"height":0,"mediaType":"video","allowVideoDisplay":true,"startupVideoDisplay":false,"x":580,"y":120,"wires":[["c4f6319c.2ccde"]]},{"id":"e5e4ba3f.5290e8","type":"ui_group","z":"","name":"Recorder demo","tab":"4c302198.634e8","disp":true,"width":"6","collapse":false},{"id":"4c302198.634e8","type":"ui_tab","z":"","name":"Media test","icon":"fa-video-camera","disabled":false,"hidden":false}]

As always, all 'constructive' feedback is highly appreciated...

Have fun with it!
Bart

Will explain this a bit more in detail, to explain why I'm a bit stuck...

Currently I use I my node hardcoded values, to explain the browser which media data I want to get:

  • resolution 640x480
  • front camera
  • ...

I cannot add these settings on the node's config screen, so you can adjust them. Reason is very simple: the config screen runs on the server and suppose N dashboards are running somewhere. The server side has no idea what each connected device supports. Perhaps one dashboard is running on a tablet with only a front camera, but the other dashboard is running on a smartphone with a front and back camera. Idem for supported resolutions, and so on ... So bottom line is that you cannot configure this kind of stuff in the config screen, which means you have to specify it "somewhere" in the dashboard...

In the dashboard I can easily find out what the device supports, but I need to visualize it somehow so the user can specify a desired value.

For example I can get a list of the available media input and output devices, such as microphones, cameras, headsets, and so forth:

navigator.mediaDevices.enumerateDevices()

Which would give me a result like this:

videoinput: FaceTime HD Camera (Built-in) id=csO9c0YpAf274OuCPUA53CNE0YHlIr2yXCi+SqfBZZ8=
audioinput: default (Built-in Microphone) id=RKxXByjnabbADGQNNZqLVLdmXlS0YkETYCIbg+XxnvM=
audioinput: Built-in Microphone id=r2/xw1xUPIyZunfV1lGrKOma5wTOvCkWfZ368XCndm0=

I could add a new node "device selector" that shows a dropdown in the dashboard, that sends the selected value to server. And on the server you could wire it to my media-recorder node, so the recorder knows that it needs to start recording from another device.

A quick scribble might explain the flow a bit better:

image

  1. A new Media-Device-Selector node is added to the flow, where you specify in the config screen that you only want to enumerate the "video" inputs.
  2. This node renders a dropdown list on the dashboard, which enumerates all available video devices.
  3. As soon as the user selects another device from the dropdown, that selection will be send to the server side. And that selection needs to be stored in local storage of the browser, so it will be remembered (like @TotallyInformation advised in the other discussion).
  4. A message will be send across the 'wire' to the media recorder node. That message contains the selected device (i.e. front camera) and the socketid (that identifies which client has send a new selection).
  5. The media recorder node sends the changed setting to the client side, but only to the client that has requested the new device (based on the socketid).
  6. The client side of the Media-Recorder node starts capturing images from the selected device (front camera).

Does this mechanism make sense?

Why do you want/need to record these things on the server side since they are front-end only? That seems to be making life more complex than you need.

Since you are going to use localStorage anyway, that can store the selected camera and video size and anything else related to the front end. Not sure why you would want any of that in the back end? Just build some defaults into the front-end code for when the Dashboard is opened on a new device/browser.

Hi Bart

I thought it would be fun to install your media recorder node.

It installed fine, however it now crashes any further node installation. I was trying to install node-red-contrib-image-output to complete your examples. (I was installing this node through the palette installer)
Here's the log. Any ideas on how to fix it?


-----------------------------------------------------------
2020-03-01T09:34:15.541Z Install : node-red-contrib-image-output 0.5.2

2020-03-01T09:34:13.734Z npm install --no-audit --no-update-notifier --save --save-prefix="~" --production node-red-contrib-image-output@0.5.2
2020-03-01T09:34:20.715Z [err] npm ERR! unpack Could not read data for node-red-contrib-ui-media-recorder@1.0.0
2020-03-01T09:34:20.827Z [out] node-red-project@0.0.1 /opito/node-red
2020-03-01T09:34:20.827Z [out] └─┬ node-red-contrib-image-output@0.5.2 
2020-03-01T09:34:20.827Z [out]   └── jimp-compact@0.9.3 
2020-03-01T09:34:20.827Z [out] 
2020-03-01T09:34:20.827Z [err] npm ERR! Linux 4.15.0-88-generic
2020-03-01T09:34:20.827Z [err] npm ERR! argv "/usr/bin/node" "/usr/bin/npm" "install" "--no-audit" "--no-update-notifier" "--save" "--save-prefix=\"~\"" "--production" "node-red-contrib-image-output@0.5.2"
2020-03-01T09:34:20.827Z [err] npm ERR! node v8.10.0
2020-03-01T09:34:20.827Z [err] npm ERR! npm  v3.5.2
2020-03-01T09:34:20.827Z [err] npm ERR! code E404
2020-03-01T09:34:20.827Z [err] 
2020-03-01T09:34:20.827Z [err] npm ERR! 404 Not found : node-red-contrib-ui-media-recorder
2020-03-01T09:34:20.827Z [err] npm ERR! 404 
2020-03-01T09:34:20.827Z [err] npm ERR! 404  'node-red-contrib-ui-media-recorder' is not in the npm registry.
2020-03-01T09:34:20.827Z [err] npm ERR! 404 You should bug the author to publish it (or use the name yourself!)
2020-03-01T09:34:20.827Z [err] npm ERR! 404 It was specified as a dependency of 'node-red-project'
2020-03-01T09:34:20.827Z [err] npm ERR! 404 
2020-03-01T09:34:20.827Z [err] npm ERR! 404 Note that you can also install from a
2020-03-01T09:34:20.827Z [err] npm ERR! 404 tarball, folder, http url, or git url.
2020-03-01T09:34:20.829Z [err] 
2020-03-01T09:34:20.829Z [err] npm ERR! Please include the following file with any support request:
2020-03-01T09:34:20.829Z [err] npm ERR!     /opito/node-red/npm-debug.log
2020-03-01T09:34:20.832Z rc=1

Thanks Marshall

Hi @marshall,
I have installed my node from Github (via the command in my first post above) and then I have installed another node via the Palette menu in Node-RED. That works all fine here. Unfortunately I have no idea what is going wrong in your setup ...

Can you explain how you installed the media recorder node? Judging by the log it did not install fine: it is trying to install it through npm registry, seemingly after it got added to the package.json file, thus resulting in it retrying the installation on other installs too.

The error you see is that it’s trying to install the node through the npm registry, but since Bart never published it there, it returns a 404 error.

1 Like

Any chance for an audio record only function? This would be so great for Nodered Voice Interaction.
Best regards and thanks for the awesome work, Johannes

If I ever find time ...
Pull requests are always welcome ....

2 Likes

I would but unfortunately I wouldnt even know where to start as i know nothing about web development :see_no_evil:

Hi @afelix

I installed it like this..

It installed in the correct location, and then poped up in node-red no problems at all, there were no error messages during the npm installation that I can recall, only the subsequent packages had the errors.

I uninstalled it, and I think that I can now add packages again (I have to recheck to be sure)

Regards

As for the rechecking, can you humour me for a bit and post the package.json file in the .node-red directory. I’m truly curious to how that error originated.

Is this what you are after?

cat package.json
{
"name": "node-red-project",
"description": "A Node-RED Project",
"version": "0.0.1",
"private": true,
"dependencies": {
"node-red-contrib-bigtimer": "~2.2.0",
"node-red-contrib-calendar-trigger": "~0.9.1",
"node-red-contrib-counter": "~0.1.5",
"node-red-contrib-crypto-js": "~0.1.1",
"node-red-contrib-fast-csv": "~0.4.0",
"node-red-contrib-ftp-server": "~0.3.0",
"node-red-contrib-influxdb": "~0.2.2",
"node-red-contrib-os": "~0.1.7",
"node-red-contrib-repeat": "0.0.27",
"node-red-contrib-splitter": "0.0.16",
"node-red-contrib-string": "~0.2.2",
"node-red-contrib-ui-state-trail": "~0.2.8",
"node-red-contrib-web-worldmap": "~2.0.12",
"node-red-contrib-zip": "~1.0.0",
"node-red-dashboard": "~2.15.4",
"node-red-node-base64": "~0.1.3",
"node-red-node-sqlite": "~0.3.7"
}
}

Yea... nothing in there that explains the error you got. Weird.