I prepared a webcam streaming app and therefore previewed a users webcam in a video tag using "navigator.mediaDevices.getUserMedia".
After the user hits a button and "RTCmulticonnection" opens a room, I want to add the preview webcam / video to be used as webcam-stream.
I just don't get it working.
The part Im going to show you starts after the socket.io Connection is established - the "connection.open" method also returns that the room has been created and the connection is established. So Signaling works - I just don't know how to simply attach my Video to the (RTCmulsiconnection) connection Object.
I have tried to use the "attachStreams" method, but remained unsuccessfully.
//Get Users Webcam
navigator.mediaDevices.getUserMedia({
audio: true,
video: true
}).then(function(stream) {
$("#mediaPreview").show();
let preview = document.getElementById('mediaPreviewVideo');
preview.srcObject = stream;
preview.volume = 0;
preview.play();
});
//Start stream
$("#btnMediaStreamStart").on('click', function(e) {
//Prevent Default & Hide
e.preventDefault();
//Add Classes
$("#mediaPreviewVideo").addClass('webcam-online');
$("#mediaStreamStatus").show().addClass('bg-success').html('<small><strong>Live</strong></small>');
connection.socketURL = 'localhost:9001/';
let connectionRoom = '123';
connection.open(connectionRoom, function(e) {
if (e === true) {
connection.attachStreams.forEach(function(localStream) {
//How to attach the cam stream? Is my previously created video even part of the "streams"?
});
connection.mediaConstraints = {
audio: {
deviceId: selectAudio
},
video: {
deviceId: selectVideo
}
};
}
});
Try using
connection.addStream(stream);
where stream is your already captured stream - perhaps via getUserMedia()
I am creating a chrome extension which captures audio from a tab using the chrome tabCapture API. I would like to play this audio stream in another html page in hopes of eventually creating a visualizer for it.
I capture the audio in a background script like so
chrome.browserAction.onClicked.addListener(function(activeTab) {
var constraints = {
audio: true,
video: false,
};
var visualizerPage = chrome.extension.getURL("/views/visualizer.html");
chrome.tabCapture.capture(constraints, function(stream) {
console.log("\ngot stream");
console.log(stream);
chrome.tabs.create({
url: visualizerPage
}, function(tab) {
chrome.tabs.sendMessage(tabID, {
"message": "stream",
"stream": stream
});
});
});
the audio stream is captured from whatever page the extension was clicked on. Another tab is opened, and the audio stream is sent to it as a message.
The javascript for the visualizer.html page is
function loadStream(stream) {
// what do I have to put here to play the stream?
}
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.message === "stream") {
var stream = request.stream;
if (!stream) {
console.log("stream is null");
return;
}
console.log(stream);
loadStream(stream);
}
else if (request.message === "statusChanged") {
console.log("statusChanged");
}
});
What I have so far is to load the audio stream into the web audio api using an audio context
var context = new AudioContext();
var source = context.createMediaStreamSource(stream);
but the script just hangs when trying to create the source.
The problem is I am not really sure what type the stream is (tabCapture api says its a LocalMediaStream).
How can I get the page to play the audio stream?
Try this in loadStream function:
var audio = new Audio();
audio.src = URL.createObjectURL(stream);
audio.play();
On my nexus4 (Android 4.4.4) I am trying to switch between 'user' facing camera and 'environment' facing camera.
Accessing either one directly works.
Switching between them bij making another call to navigator.getUserMedia() setting new constraints fails. The failure results in a black screen video & MediaStream.ended=true.
Why is MediaStream.ended=true on my second call to getUserMedia?
In my view I dynamically create buttons for the number of video sources. Two in this case. Clicking the buttons will call camera.getUserMedia() and passes in a media source:
camera.getUserMedia = function(source){
var constraints = {
video: true,
audio: false
};
if(source){
constraints.video = {optional: [{
sourceId: source.id
}]};
}
navigator.getMedia(
constraints,
function(stream) {
var vendorURL = window.URL || window.webkitURL;
video.src = vendorURL.createObjectURL(stream);
video.play();
streaming = true;
},
function(err) {
...
}
);
};
I have solved this problem by storing the stream on the camera object and then before binding the stream to the video element I will call stop on it. Not really sure what is exactly happening though (maybe somebody can add the explanation in the comments).
camera.getUserMedia = function(source){
if(camera.stream){
camera.stream.stop();
}
...
navigator.getMedia(
constraints,
function(stream) {
camera.stream = stream;
...
},
function(err) {
...
}
);
};
I'm making a chrome app and I'd like to have custom controls for the video playback but I'm having some difficulties with the mute button. Most of the videos that will be played in the app are silent so I'd like to be able to disable the button when there is no audio track just like chrome does with the default controls.
Tried using the volume value but it returns "1" even though there's no audio track. Checking if the video is muted didn't work either.
Here's a snippet.
Any suggestions?
Shorter function based on upuoth's answer and extended to support IE10+
function hasAudio (video) {
return video.mozHasAudio ||
Boolean(video.webkitAudioDecodedByteCount) ||
Boolean(video.audioTracks && video.audioTracks.length);
}
Usage:
var video = document.querySelector('video');
if(hasAudio(video)) {
console.log("video has audio");
} else{
console.log("video doesn't have audio");
}
At some point, browsers might start implementing the audioTracks property. For now, you can use webkitAudioDecodedByteCount for webkit, and mozHasAudio for firefox.
document.getElementById("video").addEventListener("loadeddata", function() {
if (typeof this.webkitAudioDecodedByteCount !== "undefined") {
// non-zero if video has audio track
if (this.webkitAudioDecodedByteCount > 0)
console.log("video has audio");
else
console.log("video doesn't have audio");
}
else if (typeof this.mozHasAudio !== "undefined") {
// true if video has audio track
if (this.mozHasAudio)
console.log("video has audio");
else
console.log("video doesn't have audio");
}
else
console.log("can't tell if video has audio");
});
For some reason #fregante's hasAudio function stopped working in Chrome at some point - even after waiting for the "loadeddata" and "loadedmetadata" events, and even the "canplaythrough" event. It may have something to do with the video format I'm using (webm). In any case, I solved it by playing the video for a short amount of time:
// after waiting for the "canplaythrough" event:
hasAudio(video); // false
video.play();
await new Promise(r => setTimeout(r, 1000));
video.pause();
hasAudio(video); // true
There are different ways to check whether a video file has audio or not, one of which is to use mozHasAudio, video.webkitAudioDecodedByteCount and video.audioTracks?.length properties of video, clean and simple...
const video = component.node.querySelector("video");
video.onloadeddata = function() {
if ((typeof video.mozHasAudio !== "undefined" && video.mozHasAudio) ||
(typeof video.webkitAudioDecodedByteCount !== "undefined" && video.webkitAudioDecodedByteCount > 0) ||
Boolean(video.audioTracks?.length)) {
console.log("This video has audio tracks.");
} else {
console.log("This video has no audio tracks.");
}
};
I opened a webcam by using the following JavaScript code:
const stream = await navigator.mediaDevices.getUserMedia({ /* ... */ });
Is there any JavaScript code to stop or close the webcam?
Since this answer has been originally posted the browser API has changed.
.stop() is no longer available on the stream that gets passed to the callback.
The developer will have to access the tracks that make up the stream (audio or video) and stop each of them individually.
More info here: https://developers.google.com/web/updates/2015/07/mediastream-deprecations?hl=en#stop-ended-and-active
Example (from the link above):
stream.getTracks().forEach(function(track) {
track.stop();
});
Browser support may differ.
Previously, navigator.getUserMedia provided you with a stream in the success callback, you could call .stop() on that stream to stop the recording (at least in Chrome, seems FF doesn't like it)
Use any of these functions:
// stop both mic and camera
function stopBothVideoAndAudio(stream) {
stream.getTracks().forEach(function(track) {
if (track.readyState == 'live') {
track.stop();
}
});
}
// stop only camera
function stopVideoOnly(stream) {
stream.getTracks().forEach(function(track) {
if (track.readyState == 'live' && track.kind === 'video') {
track.stop();
}
});
}
// stop only mic
function stopAudioOnly(stream) {
stream.getTracks().forEach(function(track) {
if (track.readyState == 'live' && track.kind === 'audio') {
track.stop();
}
});
}
Don't use stream.stop(), it's deprecated
MediaStream Deprecations
Use stream.getTracks().forEach(track => track.stop())
FF, Chrome and Opera has started exposing getUserMedia via navigator.mediaDevices as standard now (Might change :)
online demo
navigator.mediaDevices.getUserMedia({audio:true,video:true})
.then(stream => {
window.localStream = stream;
})
.catch( (err) =>{
console.log(err);
});
// later you can do below
// stop both video and audio
localStream.getTracks().forEach( (track) => {
track.stop();
});
// stop only audio
localStream.getAudioTracks()[0].stop();
// stop only video
localStream.getVideoTracks()[0].stop();
Suppose we have streaming in video tag and id is video - <video id="video"></video> then we should have following code -
var videoEl = document.getElementById('video');
// now get the steam
stream = videoEl.srcObject;
// now get all tracks
tracks = stream.getTracks();
// now close each track by having forEach loop
tracks.forEach(function(track) {
// stopping every track
track.stop();
});
// assign null to srcObject of video
videoEl.srcObject = null;
Starting Webcam Video with different browsers
For Opera 12
window.navigator.getUserMedia(param, function(stream) {
video.src =window.URL.createObjectURL(stream);
}, videoError );
For Firefox Nightly 18.0
window.navigator.mozGetUserMedia(param, function(stream) {
video.mozSrcObject = stream;
}, videoError );
For Chrome 22
window.navigator.webkitGetUserMedia(param, function(stream) {
video.src =window.webkitURL.createObjectURL(stream);
}, videoError );
Stopping Webcam Video with different browsers
For Opera 12
video.pause();
video.src=null;
For Firefox Nightly 18.0
video.pause();
video.mozSrcObject=null;
For Chrome 22
video.pause();
video.src="";
With this the Webcam light go down everytime...
Try method below:
var mediaStream = null;
navigator.getUserMedia(
{
audio: true,
video: true
},
function (stream) {
mediaStream = stream;
mediaStream.stop = function () {
this.getAudioTracks().forEach(function (track) {
track.stop();
});
this.getVideoTracks().forEach(function (track) { //in case... :)
track.stop();
});
};
/*
* Rest of your code.....
* */
});
/*
* somewhere insdie your code you call
* */
mediaStream.stop();
You can end the stream directly using the stream object returned in the success handler to getUserMedia. e.g.
localMediaStream.stop()
video.src="" or null would just remove the source from video tag. It wont release the hardware.
Since you need the tracks to close the streaming, and you need the stream boject to get to the tracks, the code I have used with the help of the Muaz Khan's answer above is as follows:
if (navigator.getUserMedia) {
navigator.getUserMedia(constraints, function (stream) {
videoEl.src = stream;
videoEl.play();
document.getElementById('close').addEventListener('click', function () {
stopStream(stream);
});
}, errBack);
function stopStream(stream) {
console.log('stop called');
stream.getVideoTracks().forEach(function (track) {
track.stop();
});
Of course this will close all the active video tracks. If you have multiple, you should select accordingly.
If the .stop() is deprecated then I don't think we should re-add it like #MuazKhan dose. It's a reason as to why things get deprecated and should not be used anymore. Just create a helper function instead... Here is a more es6 version
function stopStream (stream) {
for (let track of stream.getTracks()) {
track.stop()
}
}
You need to stop all tracks (from webcam, microphone):
localStream.getTracks().forEach(track => track.stop());
Start and Stop Web Camera,(Update 2020 React es6 )
Start Web Camera
stopWebCamera =()=>
//Start Web Came
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
//use WebCam
navigator.mediaDevices.getUserMedia({ video: true }).then(stream => {
this.localStream = stream;
this.video.srcObject = stream;
this.video.play();
});
}
}
Stop Web Camera or Video playback in general
stopVideo =()=>
{
this.video.pause();
this.video.src = "";
this.video.srcObject = null;
// As per new API stop all streams
if (this.localStream)
this.localStream.getTracks().forEach(track => track.stop());
}
Stop Web Camera function works even with video streams:
this.video.src = this.state.videoToTest;
this.video.play();
Using .stop() on the stream works on chrome when connected via http. It does not work when using ssl (https).
Please check this: https://jsfiddle.net/wazb1jks/3/
navigator.getUserMedia(mediaConstraints, function(stream) {
window.streamReference = stream;
}, onMediaError);
Stop Recording
function stopStream() {
if (!window.streamReference) return;
window.streamReference.getAudioTracks().forEach(function(track) {
track.stop();
});
window.streamReference.getVideoTracks().forEach(function(track) {
track.stop();
});
window.streamReference = null;
}
The following code worked for me:
public vidOff() {
let stream = this.video.nativeElement.srcObject;
let tracks = stream.getTracks();
tracks.forEach(function (track) {
track.stop();
});
this.video.nativeElement.srcObject = null;
this.video.nativeElement.stop();
}
Have a reference of stream form successHandle
var streamRef;
var handleVideo = function (stream) {
streamRef = stream;
}
//this will stop video and audio both track
streamRef.getTracks().map(function (val) {
val.stop();
});