Stop/Close webcam using getUserMedia and RTCPeerConnection Chrome 25 - javascript

I'm on Chrome 25 successfully using getUserMedia and RTCPeerConnection to connect audio from a web page to another party, but I'm unable to get the API to stop the red blinking indication icon in the Chrome tab that media is being used on that page. My question is essentially a duplicate of Stop/Close webcam which is opened by navigator.getUserMedia except that the resolution there isn't working. If I have a page that just uses getUserMedia with no remote media (no peer), then stopping the camera turns off the blinking tab indicator. Adding remote streams seems to be a/the issue. Here's what I've currently got for my "close" code:
if (localStream) {
if (peerConnection && peerConnection.removeStream) {
peerConnection.removeStream(localStream);
}
if (localStream.stop) {
localStream.stop();
}
localStream.onended = null;
localStream = null;
}
if (localElement) {
localElement.onerror = null;
localElement.pause();
localElement.src = undefined;
localElement = null;
}
if (remoteStream) {
if (peerConnection && peerConnection.removeStream) {
peerConnection.removeStream(remoteStream);
}
if(remoteStream.stop) {
remoteStream.stop();
}
remoteStream.onended = null;
remoteStream = null;
}
if (remoteElement) {
remoteElement.onerror = null;
remoteElement.pause();
remoteElement.src = undefined;
remoteElement = null;
}
if (peerConnection) {
peerConnection.close();
peerConnection = null;
}
I've tried with and without the removeStream() call, I've tried with and without the stop() call, I've tried the element.src="" and element.src=null, I'm running out of ideas. Anyone know if this is a bug or user/my error in the use of the API?
EDIT: I set my default device (using Windows) to a camera that has a light when it's in use, and upon stopping, the camera light goes off, so perhaps this is a Chrome bug. I also discovered that if I use chrome://settings/content to change the microphone device to anything other than "Default", Chrome audio fails altogether. And finally, I realized that using element.src=undefined resulted in Chrome attempting to load a resource and throwing a 404 so that's clearly not correct... so back to element.src='' on that.

Ended up being my fault (yes, shocking). Turns out I wasn't saving localStream correctly in the onUserMediaSuccess callback of getUserMedia... once that was set, Chrome is turning off the blinking recording icon. That didn't explain the other anomalies, but it closes the main point of the question.

I just got this working yesterday after trawling through the WebRTC specification. I don't know if this is the "right" way to do it, but I found that renegotiating the PeerConnection with a new offer after removing the stream did the trick.
var pc = peerConnections[socketId];
pc.removeStream(stream);
pc.createOffer( function(session_description) {
pc.setLocalDescription(session_description);
_socket.send(JSON.stringify({
"eventName": "send_offer",
"data":{
"socketId": socketId,
"sdp": session_description
}
}));
},
function(error) {},
defaultConstraints);

Related

JS VIDEO | DOMException: Could not start video source

I want to get a video from the webcam using JS but no footage.
MESSAGE:
DOMException: Could not start video source
App.js
const video = document.getElementById("video");
function startVideo() {
navigator.getUserMedia(
{
video: {}
},
stream => (video.srcObject = stream),
err => console.log(err)
);
}
startVideo();
index.html
...
<body>
<video id="video" width="720" height="540" autoplay muted></video>
</body>
...
thanks for your help
If anyone else is having this problem and nothing else helps. Make sure that your camera is not already claimed/used by a different software/browser.
TLDR: I have tested your code and had to change it a bit:
https://codepen.io/puradawid/pen/PoqxzPQ
It looks like the problem lays here:
navigator.getUserMedia({
video: {}
},
stream => { video.srcObject = stream },
err => console.log(err)
);
Regarding to docs navigator.getUserMedia is deprecated and there is navigator.mediaDevices.getUserMedia that supports it. However, changing that up doesn't solve the correct problem which is your callback functions. This method returns Promise that is controlled by .then(), so changing it allows me to see my face in codepen:
navigator.mediaDevices.getUserMedia({
video: true
}).then(
stream => (video.srcObject = stream),
err => console.log(err)
);
I ran into this problem on certain android devices (Sony XA2) when trying to toggle the camera on a mobile browser because I am calling navigator.mediaDevices.getUserMedia repeatedly on each camera toggle.
The solution that I found was to make sure to stop all the tracks in previous streams that you created.
this.stream.getTracks().forEach(t => {
t.stop();
this.stream.removeTrack(t);
});
Without the previous code you can't seem to toggle camera on certain Android devices: (Demo),
(Code)
The error shown was DOMException: Requested device not found
By stopping previous tracks: you are able to start a new stream:
(Demo)
Code
Note: The following code snippet doesn't seem to execute in stack overflow due to security restrictions, so please use the jsfiddle links.
class Camera {
constructor({ video }) {
this.facingMode = "environment";
this.video = video;
video.onloadedmetadata = () => {
video.play();
};
}
async toggleCamera() {
if (this.facingMode === "environment") {
this.facingMode = "user";
} else {
this.facingMode = "environment";
}
try {
if (this.stream){
/* On some android devices, it is necessary to stop the previous track*/
this.stream.getTracks().forEach(t => t.stop());
}
this.stream = await navigator.mediaDevices.getUserMedia({
video: {
facingMode: this.facingMode,
}
});
} catch (e) {
console.error(e);
}
this.video.srcObject = this.stream;
}
}
const camera = new Camera({
video: document.querySelector("video"),
});
const button = document.querySelector("button");
button.addEventListener('click', () => {
camera.toggleCamera();
});
<button>
Toggle Camera
</button>
<video></video>
In Windows 10 go to settings->privacy->App permission(left side)->Microphone-> enable 'Allow apps to access your microphone'
After that retry with your JS program....It will work!!
If anyone have such an error and you are working on a laptop. You can try bending your laptop monitor in both directions. Sometimes the cable comes loose. This helped in my case.
Also look into Feature-Policy HTTP header, both on the website and on the host web server config, and make sure camera access is allowed.
I have tried all the other solution but nothing is work. Then finally i need to uninstall my camera driver in Device Manager and then scan for hardware changes. Try to run the app again and it's working.
I'm building electron desktop app in windows 10.
electron: 15.3.0
Source video that helped me: https://www.youtube.com/watch?v=XE2ULFlzkxw
I went to the browser settings for camera and noticed that the default camera was showing as "Leap Motion" which is not a standard camera device. I changed to an actual webcam and the problem was solved.
Sometimes this type of error also appears when you try to make a peer-to-peer call system and your tests are done on the same device. The camera is already used by the initiator and the receiver can no longer activate the camera.

JavaScript play() function does not working in Chrome

I created an audio object and want to play it when user leave the window. So, my code is here:
$('body').on('mouseleave', function(){
var audio = new Audio( 'quite-impressed.mp3' )
audio.play()
})
It works well in Firefox. It also works in Chrome if I click in the page and then leave mouse outside of the body. But, when I leave the mouse without clicking in the page an error showed in the console and the audio does not play
Uncaught (in promise) DOMException: play() failed because the user didn't interact with the document first. https://developers.google.com/web/updates/2017/09/autoplay-policy-changes
But, in this example site it works fine without interacting with the page. How can I make it possible? Thanks in advance.
It seems they use an AudioContext to play that sound.
Chrome did came back a few months ago about blocking the AudioContext API, because a lot of fair uses were not prepared for such restriction and thus got broken by it.
But M71, which will get released in December 2018 will reenable that restriction, you can read about it here: https://developers.google.com/web/updates/2017/09/autoplay-policy-changes#webaudio
// this will work in Chrome < 70 but not af
onmouseout = e => {
const ctx = new AudioContext();
const osc = ctx.createOscillator();
osc.connect(ctx.destination);
osc.start(0);
osc.stop(1);
}
Outsourced live example, since Stacksnippets are always granted the user gesture anyway: https://jsfiddle.net/zy3ev8ka/
Try this:
window.audio = new Audio( 'quite-impressed.mp3' )
$('body').on('mouseleave', function(){
audio.play()
})
This worked for me on Chrome 77:
On address bar: chrome://settings/content/sound
Turn off "Allow sites to play sound (recommended)"
Turn it on again
if your js play function is not running and if your code is correct then this may help,you have to allow your browser to get that sound file
just goto settings =>privacy and security => site-settings =>sound.
and then add your local url at add to play section..

Problems in playing Fairplay Encrypted content on Safari browser

We are trying to write player in Javascript which should play fairplay encrypted content on safari browser. We figured 'encrypted' event is not supported on Safari browser and we added event listener for 'WebKitNeedKey' event. We coded the flow as below.
addEventListener('webkitneedkey, onWebKitNeedKey);
onWebKitNeedKey(evt) {
videoElement = document.getElementById('videoID');
if (videoElement.webkitKeys) {
videoElement.webkitSetMediaKeys(new WebKitMediaKeys('com.apple.fps.2_0'));
}
const session = videoElement.webkitKeys.createSession('video/mp4', event.initData);
session.addEventListener('webkitkeymessage', onWebKitKeyMessage);
session.addEventListener('webkitkeyerror', onWebKitKeyError);
session.addEventListener('webkitkeyadded', onWebKitKeyAdded);
}
onWebKitKeyMessage(evt) {
console.log(`received webkit key message : ${evt}`);
}
onWebKitKeyError(evt) {
console.log(`received webkit key error : ${evt}`);
}
onWebKitKeyAdded(evt) {
console.log(`received webkit key added : ${evt}`);
}
Now I am getting the webkitneedkey event and after setting the keys, I am getting webkitkeymessage event. I am planning to implement the logic of contacting the server for the license as per https://github.com/WebPlatformForEmbedded/WPEWebKit/blob/master/LayoutTests/http/tests/media/clearkey/clear-key-hls-aes128.html
I have following questions. Can any one please help me to resolve the below questions?
1) Do we need to set the source to '.m3u8'? Is it mandatory? I am getting the events even without setting the source to .m3u8
2) Is my approach correct in onWebKitNeedKey? Can I send evt.initData directly to webkitSetMediaKeys without modifying? Do I need to extract the content ID from evt.initData if I use key as 'com.apple.fps.2_0' instead of 'com.apple.fps.1_0'?

WebRTC switch back to front camera with gUM not streaming on Android/Chrome

On Samsung Galaxy S2 Android 6.0.1 + Chrome v55, when I getUserMedia on page load, the video track acquired appears live.
When I select the back camera from my camera select, I trigger another time my gUM with constraints to use that exact facing back cameraId, the video track is ended, I have a black rectangle instead of a stream.
var constraints = {
video: {
deviceId: {
exact: defaultVideoDeviceId
}
},
audio: true
};
gUM wrapper
function gUM(constraints, callback) {
console.debug("WebRTC constraints", constraints);
// Stopping streaming before starting the new one
if (window.streams.local) {
window.streams.local.getTracks().forEach(function(track) {
track.stop();
});
}
navigator.mediaDevices.getUserMedia(constraints)
.then(stream => {
console.debug("New MediaStream > Tracks", stream.getTracks());
window.streams.local = stream;
callback && callback(stream);
})
.catch(err => {
console.log("Raised error when capturing:", err);
});
}
If I switch back to front, it acquires a new MediaStream and it plays the video.
I'm facing a similar problem too.
My test is a bit different since I'm trying to make a GUM of the back camera while I have a GUM a media stream active that is using the front camera.
I tested in several android devices and only the Xiaomi MI Mix 2 with the MIUI beta 875 with android 8.1 works. This can be because that rom uses the new camera2 android api, or because the Mi Mix 2 camera hardware allows the usage of both the back and the front camera at the same time.
The annoying thing is that sometimes, on certain devices, the GUM doesn't fail, but hangs indefinitely.
Maybe listening to the MediaStreamTrack.onended event after the track.stop() method call, can help to understand when resources are completely free so as you can try a new GUM with different constraints.
Please let me know if you discovered something.
Simone

Can't access the camera from the app on Lumia 520 (running Windows Phone 8.1 Preview)

I am a WP dev beginner and learning how to write a simple video recorder app. I am using javascript and HTML on VS Pro 2013 and debugging on my actual device Lumia 520 (running Windows Phone 8.1 Preview). I read through a body of documentations and found that the MediaCapture class was the core class for this purpose. So I started following some tutorials and wrote up some functions to access the camera and display a preview in a HTML5 video tag. However, I wasn't successful in getting the MediaCapture object initialized, not even displaying the preview. Below are the major functions of which the first one was problematic:
function initCapture() {
findRearFacingCamera().then(function (cameraId) {
try {
if (cameraId != null && cameraId != "") {
// Initialize the settings
captureInitSettings = null;
captureInitSettings = new Windows.Media.Capture.MediaCaptureInitializationSettings();
captureInitSettings.videoDeviceId = cameraId;
captureInitSettings.streamingCaptureMode = Windows.Media.Capture.StreamingCaptureMode.video;
captureInitSettings.photoCaptureSource = Windows.Media.Capture.PhotoCaptureSource.videoPreview;
captureInitSettings.realTimeModeEnabled = true;
// Initialize the capture
oMediaCapture = null;
oMediaCapture = new Windows.Media.Capture.MediaCapture();
oMediaCapture.initializeAsync(captureInitSettings).then(preview, errorHandler);
}
} catch (e) { }
});
}
function preview() {
var preview = document.getElementById("PreviewScreen");
preview.msZoom = true;
if (preview != null) {
preview.src = URL.createObjectURL(oMediaCapture);
preview.play();
}
}
function errorHandler(e) {
var information = document.getElementById("message");
information.innerHTML = e.message;
}
During debugging, I paused at the statement oMediaCapture = new Windows.Media.Capture.MediaCapture(); in the initCapture() function. At this point, captureInitSettings.videoDeviceId has the value: "\\?\DISPLAY#QCOM_AVStream#3&25691128&0&UID32768#{e5323777-f976-4f5b-9b55-b94699c46e44}\Back Sensor", which I believed was a correct identification of the rear camera that I intended to use. Then, when I continued with a break point set at var preview = document.getElementById("PreviewScreen"); in function preview(), which was supposed to be called upon successful initialization of the MediaCapture object, the program was trapped into the errorHandler() function instead, with the error message being "Access is denied" with error number "-2147024891". So I guess the problem rose from the .initializeAsync() function, which was unsuccessful. Deeper causes might also be related to the permission to access the camera. BTW, I have enabled the webcam and microphone capabilities for this app, which was not the issue.
I believe I was missing something either in the code or in the big picture of the development settings. Please help me identify the issue and let me know if any additional information is needed. Much appreciated!
Did you make sure you added the Rear Camera requirement in your Package Manifest?
Turned out the problem was really with my device. Recall that I was testing on a Lumia 520 with Windows Phone 8.1 preview, the firmware stayed at Lumia Black. After upgrading the firmware to Lumia Cyan (parallel to Windows Phone 8.1) using the Nokia Recovery Software Tool, the problem disappeared.

Categories

Resources