Electron disable specific camera device access or set default webcam - node.js

We are using atom electron to run an app in a "kiosk" type setting, we have 4 webcam devices connected to the physical computer, we want specifically 1 of those to be used for webrtc inside of the electron browser, then other 3 we use some C code to capture still frames. We know the USB path or the /dev/video{#} for the device we want.
Is there a way to either disable access by the view layer to the 3 webcams in node before we launch the electron window? Or another option is to set the default camera before we launch the view layer so that it will default to the webcam we want.
In the view layer we can get a list of devices and see if they are audio or video, but we can't get their /dev/video# or their USB path to figure out which one is the target webrtc cam, so this has not been very helpful yet.
Any help is great, I feel weird for having to post a question since for the last 12 years I have been able to find what I needed by searching, but its been about 3 hours so its time to ask for help.

I don't think Chromium provides a way to retrieve the USB path for a media source. You'll probably need to display a configuration screen to allow the user to select the correct camera (similar to this demo) the first time around and then use the source/device id as a mandatory constraint from that point on.
Another option is to find the correct camera based on the device label, though obviously this will only work if each camera has a distinct label. You can get all the device labels and ids by running this snippet in the DevTools console:
navigator.mediaDevices.enumerateDevices()
.then(devices => devices.forEach(
device => console.log(`kind: ${device.kind}: ${device.label} id=${device.deviceId}`)
))
.catch(err => console.log(err));
Either way, once you have the source/device id you can specify it as a mandatory constraint to ensure that only that one particular camera is used:
navigator.webkitGetUserMedia(
{
audio: false,
video: {
mandatory: {
chromeMediaSourceId: 'the camera source id obtained earlier',
}
}
},
stream => console.dir(stream),
error => console.log(error)
);

Related

Web Bluetooth - Show extra info on scanning dialog

I'm trying to support web-bluetooth to connect to my devices and perform a simple task (such as playing LED).
However, the device information showed on the scanning dialog when calling navigator.bluetooth.requestDevice is not so clear. It only shows the device name and a random (?) hex string.
The problem here is all my devices have the same name (AWESOME_LED), thus it's not easy for the user to select the correct LED if all scanning items show the same device name info. As far as I know, we can not custom to add more info showing on the scanning dialog.
I come up with a new solution that is changing the device name to unique for each LED with the format AWESOME_LED + [uniqueid] e.g AWESOME_LED1, AWESOME_LED2, AWESOME_LED3 so that the user can distinguish one from the others.
My question are:
Is there any alternative solution without making the device name unique?
If not, is there any problem / rejection / limitation from Apple or Google for my current app on App Store / Google Play by not using the same device name for all devices? I have been investigating it at Apple forums / Accessory Design Guidelines and looks like there are no problems, just to make sure if anyone has faced trouble from Apple / Google.
Thanks for your help.
Scanning dialog
My question are:
Is there any alternative solution without making the device name unique?
The browser prompt is not customisable yet. One solution you highlighted already is to make your LED device name unique. If you're able to control the device, why not having one AWESOME_DEVICE name and a GATT characteristic you can write to that controls individual LED colors. Maybe something like:
const device = await navigator.bluetooth.requestDevice({
filters: [{ name: "AWESOME_DEVICE" }],
});
const server = await device.gatt.connect();
const service = await server.getPrimaryService(0x1234); // Your service UUID
const characteristic = await service.getCharacteristic(0x5678); // Your characteristic UUID
// Set LED #1 to red color.
await characteristic.writeValue(
new Uint8Array(/*ledIndex=*/ 1, /*r=*/ 255, /*g=*/ 0, /*b=*/ 0)
);
If not, is there any problem / rejection / limitation from Apple or Google for my current app on App Store / Google Play by not using the
same device name for all devices? I have been investigating it at
[Apple forums][1] / [Accessory Design Guidelines][2] and looks like
there are no problems, just to make sure if anyone has faced trouble
from Apple / Google.
None that I'm aware of.

Screen Recording with both headphone & system audio

I am trying to build a web-application with the functionality of screen-recording with system audio + headphone-mic audio being captured in the saved video.
I have been thoroughly googling on a solution for this, however my findings show multiple browser solutions where the above works so long as headphones are NOT connected, meaning the microphone input is coming from the system rather than headset.
In the case that you connect headphones, all of these solutions capture the screen without video-audio, and the microphone audio from my headset. So to re-clarify on this, it should have recorded video-audio from the video being played whilst recording, and the headset-mic audio also.
This is thoroughly available in native applications, however I am searching for a way to do this on a browser.
If there are no solutions for this currently that anybody knows of, some insight on the limitations around developing this would also really help, thank you.
Your browser manages the media input being received in the selected tab/window
To receive media input, you need to ensure you have the checkbox Share Audio in the image below checked. However this will only record media-audio being played in your headphones, when it comes to receiving microphone audio, the opposite must be done i.e the checkbox should be unchecked, or merge the microphone audio separately on saving the recorded video
https://slack-files.com/T1JA07M6W-F0297CM7F32-89e7407216
create two const, one retrieving on-screen video, other retrieving audio media:
const DISPLAY_STREAM = await navigator.mediaDevices.getDisplayMedia({video: {cursor: "motion"}, audio: {'echoCancellation': true}}); // retrieving screen-media
const VOICE_STREAM = await navigator.mediaDevices.getUserMedia({ audio: {'echoCancellation': true}, video: false }); // retrieving microphone-media
Use AudioContext to retrieve audio sources from getUserMedia() and getDisplayMedia() separately:
const AUDIO_CONTEXT = new AudioContext();
const MEDIA_AUDIO = AUDIO_CONTEXT.createMediaStreamSource(DISPLAY_STREAM); // passing source of on-screen audio
const MIC_AUDIO = AUDIO_CONTEXT.createMediaStreamSource(VOICE_STREAM); // passing source of microphone audio
Use the method below to create a new audio source which will be used as as the merger or merged version of audio, then passing audios into the merger:
const AUDIO_MERGER = AUDIO_CONTEXT.createMediaStreamDestination(); // audio merger
MEDIA_AUDIO.connect(AUDIO_MERGER); // passing media-audio to merger
MIC_AUDIO.connect(AUDIO_MERGER); // passing microphone-audio to merger
Finally, connect the merged-audio and video together into one array to form a track, and pass it to the MediaStreamer:
const TRACKS = [...DISPLAY_STREAM.getVideoTracks(), ...AUDIO_MERGER.stream.getTracks()] // connecting on-screen video with merged-audio
stream = new MediaStream(TRACKS);

Web Bluetooth: Want to filter on manufacturer data when using navigator.bluetooth.requestDevice

I see that Google Chrome has not implemented filtering on manufacturer data. Issue 707635, does not seem to have any progress.
The Web Bluetooth specification has an (unstable) spec for filtering manufacturerData when using navigator.bluetooth.requestDevice (https://webbluetoothcg.github.io/web-bluetooth/#example-filter-by-manufacturer-service-data
Does anyone know if there is any progress on this or made this kind of filtering work?
Following our discussion, I've added support for manufacturer data filter in Web Bluetooth in Chrome 92. See https://crbug.com/707635
Here's an example:
// Filter Bluetooth devices from Google company with manufacturer data bytes
// that start with [0x01, 0x02].
navigator.bluetooth.requestDevice({
filters: [{
manufacturerData: [{
companyIdentifier: 0x00e0,
dataPrefix: new Uint8Array([0x01, 0x02])
}]
}],
optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });
You'll find a sample at https://googlechrome.github.io/samples/web-bluetooth/manufacturer-data-filter.html and some developer documentation at https://web.dev/bluetooth/#manufacturer-data-filter
Let me know if that works for you ;)
The Chrome team has NOT made progress on this yet as you've noted. In the mean time, would filtering by device name, device name prefix, or GATT services work out for you?
You can try it with https://googlechrome.github.io/samples/web-bluetooth/device-info.html.
Short answer:
'Star' issue 707635 to receive updates and signal interest.
If you have a clear example / business case to share consider adding a comment to help developers understand how to prioritize this work.
Chromium is open source, consider contributing or finding a developer to do this work.

Chrome screen sharing get monitor info

I implemented chrome extension which using chrome.desktopCapture.chooseDesktopMedia to retrieve screen id.
This is my background script:
chrome.runtime.onConnect.addListener(function (port) {
port.onMessage.addListener(messageHandler);
// listen to "content-script.js"
function messageHandler(message) {
if(message == 'get-screen-id') {
chrome.desktopCapture.chooseDesktopMedia(['screen', 'window'], port.sender.tab, onUserAction);
}
}
function onUserAction(sourceId) {
//Access denied
if(!sourceId || !sourceId.length) {
return port.postMessage('permission-denie');
}
port.postMessage({
sourceId: sourceId
});
}
});
I need to get shared monitor info(resolution, landscape or portrait).
My question is: If customer using more than one monitor, how can i determine which monitor he picked?
Can i add for example "system.display" permissions to my extension and get picked monitor info from "chrome.system.display.getInfo"?
You are right. You could add system.display permission and call chrome.system.display.getDisplayLayout(callbackFuncion(DisplayLayout)) and handle the DisplayLayout.position in the callback to get the layout and the chrome.system.display.getInfo to handle the array of displayInfo in the callback. You should look for 'isPrimary' value
This is a year old question, but I came across it since I was after the same information and I finally managed to figure how you can identify which monitor the user selected for screen-sharing in Chrome.
First of all: this information will not come from the extension that you probably built for screen-sharing in Chrome, because:
The chrome.desktopCapture.chooseDesktopMedia API callback only returns a sourceId, which is a string that represents a stream id, that you can then use to call the getMediaSource API to build the media stream.
The chrome.system.display.getInfo will give you a list of the displays, yes, but from that info you can't tell which one is being shared, and there is no way to match the sourceId with any of the fields returned for each display.
So... the solution I've found comes from the MediaStream object itself. Once you have the stream, after calling getMediaSource, you need to get the video track, and in there you will find a property called "label". This label gives you an idea of which screen the user picked.
You can get the video track with something like:
const videoTrack = mediaStream.getVideoTracks()[0];
(Check the getVideoTracks API here: https://developer.mozilla.org/en-US/docs/Web/API/MediaStream/getVideoTracks).
If you print that object, you will see the "label" field. In Chrome screen 1 shows as "0:0", whereas screen 2 shows as "1:0", and I assume screen i would be "i-1:0" (I've only tested with 2 screens).
Here is a capture of that object printed in the console:
And not only works for Chrome, but for other browsers that implement it! In Firefox they show up as "Screen i":
Also, if you check Chrome chrome://webrtc-internals you'll see this is what they show in the addStream event:
And that's it! It's not ideal, since this is a label, more than a real screen identifier, but well, it's something to work with. Once you have the screen identified, in Chrome you can work with the chrome.system.display.getInfo to get information for that display.

How can I select an audio output device in directshow

I was wondering how I can select the output device for audio in directshow. I am able to get available audio output devices in directshow. But how can I make one of these to be audio output device. Its always going for the default audio device. I want to be able to output audio on my choice of device. I have been struggling through google but couldn't find anything useful. All I could get was this link but it doesn't really solve my problem.
Any help will be really helpful for me.
First off, if you're not using DirectShow .NET (DirectShowLib), get that here: It serves as a (very complete) interface between unmanaged DirectShow and C#
What follows is a pretty simple example of how to play an audio file, to the desired audio device
using DirectShowLib;
private IGraphBuilder m_objFilterGraph = null;
private IBasicAudio m_objBasicAudio = null;
private IMediaControl m_objMediaControl = null;
private void playAudioToDevice(string fName, int devIndex)
{
object source = null;
DsDevice[] devices;
devices = DsDevice.GetDevicesOfCat(FilterCategory.AudioRendererCategory);
DsDevice device = (DsDevice)devices[devIndex];
Guid iid = typeof(IBaseFilter).GUID;
device.Mon.BindToObject(null, null, ref iid, out source);
m_objFilterGraph = (IGraphBuilder)new FilterGraph();
m_objFilterGraph.AddFilter((IBaseFilter)source, "Audio Render");
m_objFilterGraph.RenderFile(fName, "");
m_objBasicAudio = m_objFilterGraph as IBasicAudio;
m_objMediaControl = m_objFilterGraph as IMediaControl;
m_objMediaControl.Run();
}
It is up to user to manage audio devices and choose a primary device (such as via Control Panel applet). You can find ways to switch devices programmatically in Windows XP, however in Vista+ it is impossible without interactive user action by design.
See also Larry's answer here: How to change default sound playback device programmatically?
UPDATE: The mentioned above refers to modifying system configuration trying to alter default audio output device. An application is however not limited to default device only. Instead, it can enumerate available devices (see Using the System Device Enumerator + CLSID_AudioRendererCategory) and then create an instance of renderer for specific device with BindToObject call. From there on, it is a regular filter, just bound internally to device of interest.

Resources