Twilio DataTrack API stop? - javascript

So I'm creating a simple zoom clone app and got an issue with the DataTrack API.
Initialized DataTrack
this.dataTrack = new LocalDataTrack();
The issue is that after leaving/disconnecting in the room the record Icon in the browser is still there.
LeaveRoom func
this.room.localParticipant.videoTracks.forEach((publication) => {
publication.track.stop();
publication.unpublish();
});
console.log("this.dataTrack", this.dataTrack); // HOW TO STOP THIS ?

The LocalDataTrack object has an id property.
You can get the MediaStreamTrack by looking up the media stream tracks from the media streams.
const userMedia = navigator.mediaDevices.getUserMedia({video:true, audio:true});
const tracks = userMedia.then(mediaStreams => {
const tracks = mediaStreams.getTracks();
for(let track of tracks) {
if(track.id === this.dataTrack.id) {
track.stop();
}
}
});

These are the 3 I do. Works like a charm.
//Remove chromes "your browser is using the camera" icon
track.forEach((track) => track.stop())
room.localParticipant.unpublishTracks(track)
track.forEach((track) => track.detach())

Related

Video Player Local Storage

I want to store video duration and ``src to local storage, but this code not working. The video src and duration showing in inspect element application local storage but not working for the video player.
window.addEventListener("unload", () => {
let setDuration = localStorage.setItem(
"duration",
`${mainVideo.currentTime}`
);
let setSrc = localStorage.setItem("src", `${mainVideo.getAttribute("src")}`);
});
window.addEventListener("load", () => {
let getDuration = localStorage.getItem("duration");
let getSrc = localStorage.getItem("src").src;
if (getSrc) {
mainVideo.src = getSrc;
mainVideo.currentTime = getDuration;
}
});
One problem certainly lays right here
localStorage.getItem("src").src
You are trying to read the property src but localStorage.getItem("src") returns a string or null not an object. Remove the .src part and that error will be resolved.
I'm sorry if that wasn't your problem. If so please provide further information about your problem or any error messages.

React "Failed to execute 'stop' on 'MediaRecorder': The MediaRecorder's state is 'inactive'."

I want to write a small Audio Recording Website with ReactJS, but I alway get this error:
Failed to execute 'stop' on 'MediaRecorder': The MediaRecorder's state is 'inactive'.
Here's a part of the code I've written:
var [recording, setRecording] = useState(false);
var audiochunks = [];
var mrecorder;
navigator.mediaDevices.getUserMedia({audio:true}).then(stream => {
mrecorder = new MediaRecorder(stream);
mrecorder.addEventListener("dataavailable", event => {
audiochunks.push(event.data);
});
})
function toggle_recording(){ setRecording(!recording); handle_record() }
function handle_record(){
if(recording){
mrecorder.stop();
}
else{
mrecorder.start();
}
}
/**JSX Part of App.js component*/
return(
<section>
<button onclick=toggle_recording/>
</section>
)
The buton toggles the recording state true or false and starts or stops the MediaRecorder.
Is it possible that the error comes up because I first declined the variable and initialized it in the getUserMedia function?
I hope you can hep me!
Thanks in advice,
Disembleergon
I believe that the MediaRecorder will throw an error when you try to stop the recording when the recorder is already in an inactive state. One thing you can do is to short circuit your stop action if mediaRecorder is already in an inactive state.
const stopRecording = () => {
if (mediaRecorder.state === 'inactive') return
mediaRecorder.stop()
}
By looking at your code, however, what I think could be the issue is that your mrecorder is a var. You should store it in useState so that when the re-render occurs on your component that your original mrecorder does not get wiped.

Screen sharing using webRTC when audio call in javascript

I am going to make screen sharing function using webRTC.
My code is working well when video calling
But in audio call status, that is not working.
Here is my code.
This is for create peer Connection and add stream for audio calling
const senders = [];
var mediaConstraints = {audio: true, video: false}
navigator.mediaDevices.getUserMedia(mediaConstraints)
.then(function (localStream) {
localLiveStream = localStream;
document.getElementById("local_video").srcObject = localLiveStream;
localLiveStream.getTracks().forEach(track => senders.push(myPeerConnection.addTrack(track, localLiveStream)));
})
.catch(handleGetUserMediaError);
when screen share field
mediaConstraints.video = true;
let displayStream = await navigator.mediaDevices.getDisplayMedia(mediaConstraints)
if (displayStream) {
document.getElementById("local_video").srcObject = displayStream;
console.log("senders: ", senders);
try {
senders.find(sender => sender.track.kind === 'video').replaceTrack(displayStream.getTracks()[0]);
} catch (e) {
console.log("Error: ", e)
}
}
In screen sharing status, sender.track.kind is "audio"
So
senders.find(sender => sender.track.kind === 'video') = null.
As this, replaceTrack makes error
is there any other way for screen share?
You need to add a video track in order to achieve this. It will require renegotiation.
So add the screen track (not replace) to the connection and then create the offer again!
connection.addTrack(screenVideoTrack);
Check this for reference:
https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/onnegotiationneeded

VideoJS Single Play List Video Duration?

Im extending the VideoJS default Playlist plugin. Everything is going well tell now, My Issue I need to retrieve each video item duration. As per the API I tried the following:
player.playlist().forEach((item,index) => {
if (player.readyState() < 1) {
// do not have metadata tell this moment.
// waiting
player.one("loadedmetadata", onLoadedMetadata);
}
else {
// metadata already loaded
onLoadedMetadata();
}
function onLoadedMetadata() {
console.log(player.duration()); //<----NEED HELP HERE PLEASE
}
});
The result I got is the first item duration repeated 5 times (count of playlist item) and its not yet loaded in the player window.
Would you please help with fix to show each Playlist video item duration separately?
All the related issues in stackoverflow talking about the player screen itself (I hope I did not miss correct question here) But Im looking for each PlayList item duration.
Thank you.
I'm using the following:
Video.js 7.9.5
video-js-Playlist 4.2
video-js-playlist-ui 3.8.0
I fix my problem with new helper function and 1 extra step in video-js-playlist-ui 3.8.0
The fix as the following:
Step one: Helper function to get the item duration from video-js-playlist-ui plugin:
const itemDuration = function (item) {
const settings = {
itemVideoEl: document.createElement("video"),
itemVideoSource: document.createElement("source"),
itemVideoSrc: item.sources[0].src,
itemType: item.sources[0].type,
};
const { itemVideoEl, itemVideoSource, itemVideoSrc, itemType } = settings;
itemVideoSource.src = itemVideoSrc;
itemVideoSource.type = itemType;
itemVideoEl.appendChild(itemVideoSource);
const getDuration = [];
itemVideoEl.addEventListener("loadedmetadata", (event) => {
const duration = itemVideoEl.duration;
getDuration.push(duration);
});
item.duration = getDuration;
return item;
};
Step two: Add timeout to creating items inside video-js-playlist-ui plugin:
This will guarantee to show the video time in the HTML DOM.
class PlaylistMenuItem extends Component { //default class
createEl() { //default function
const item = itemDuration(this.options_.item); //<---REPLACED WITH THE NEW HELPER FUNCTION
const li = document.createElement("li");//default value
const showDescription = this.options_.showDescription;//default value
setTimeout(() => {
//The rest of the default function createEl() comes here.
},1000);
}
}
NOTE:
My fix is working for HTML5 Video/Audio only, I know more techs will need extra steps, so this is only a hint for anyone may stuck in the same situation. Hope this answer will help other people as I always get help from here.
Thank you.

WebRTC switch camera

I am currently working for WebRTC multipeer connection. I want to implement feature to switch camera from front to back while on call.
This is the code I am using to switch cameras
async function changevideo() {
const audioSource = audioInputSelect.value;
const videoSource = videoSelect.options[videoSelect.selectedIndex].value;
var tempconstraints ={
video: {
deviceId: videoSource ? { exact: videoSource } : undefined,
width: { max: 320 },
height: { max: 240 }
},
audio: { deviceId: audioSource ? { exact: audioSource } : undefined },
};
var newstream = await navigator.mediaDevices.getUserMedia(tempconstraints);
if (connections[socketId]) {
Promise.all(connections[socketId].getSenders().map(function (sender) {
debugger;
return sender.replaceTrack(newstream.getTracks().find(function (track) {
debugger;
return track.kind === sender.track.kind;
})).then(data =>
{
console.log(data);
});;
}));
var track = localStream.getTracks().find(function (track) { return track.kind == videoTrack.kind });
localStream.removeTrack(track);
localStream.addTrack(videoTrack);
connections[tempsocketid].onnegotiationneeded = function () {
connections[tempsocketid].createOffer().then(function (offer) {
return connections[tempsocketid].setLocalDescription(offer);
}).then(function () {
socket.emit('signal', socketId, JSON.stringify({ 'sdp': connections[tempsocketid].localDescription, 'room': roomNumber }), roomNumber);
}).catch(e => console.log(e));
}
}
}
Here connections contains the RTCpeerconnection details of all type of connections connected.
socketId is the id of main user on which I want to switch camera. So, connections[socketId] gives me the RTCPeerConnection details of user with socketId.
newstream is the stream after switching camera.
If I directly update src of video to newstream then my camera changes only on my device.
I have searched alot but everywhere I am getting solution to use replaceTrack but it is not wokring in my case. Everytime I use it nothing happens on screen and I am also not getting any error in console.
Update
I have used the onnegotiationneeded with remove and add track.
tempsocketid is the socketId of another user who is connected.
So I have 2 users one have socketid stored in socketId and another having socketid stored in tempsocketid. So currently I am trying to switch camera of user with socketid socketId
and when negotiation is called then I am getting error in another users console.
DOMException: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Error processing ICE candidate
You are probably being unable to cause a renegotiaton so change to the facingMode of your camera cannot affect the other peers, but you do not use this explicitely as I see but replaceTracks. But still you may not being able to trigger a renegotiation. Checkout things that cause renegotiation: https://developer.mozilla.org/en-US/docs/Web/API/RTCRtpSender/replaceTrack#Usage_notes
Changing facingMode setting by applying constraints with applyConstraints may be a solution without using replaceTracks.
A strange idea coming to my mind to dispatch negotiationneeded event yourself, but I would try this after chasing the reason not being able to casue renegotiation itself by replacing track, or changing camera, and everything else.
About another reason: As for the reasons that casues renegotiation, your back camera resolution is most probably higher than the front camera, so it looks like a reason. If you start from the back camera first and then switch to front it might have been a no reason. I am suspicious about your max constraints of width nad height. They might be very lower for the both camera hence resulting in the same size, resoltion and so a no reason according to the list in the linked page above. I suggest removing them.
Also the replaceTracks returns a promise but the map function it is called from does not return anything, hence undefined. You are supposed to use the promises inside the array argument to Promise.all. I would suggest return those promises inside the map function.
I have fixed the issue the problem was with socketId I was sending socketId of current user with different user.
As replace track was not working so I have used removeTrack and addTrack to force negotiation.
Here is my working code
if (connections[socketId]) {
localStream.getVideoTracks()[0].enabled = false;
var track = localStream.getTracks().find(function (track) { return track.kind == videoTrack.kind });
localStream.removeTrack(track);
localStream.addTrack(videoTrack);
connections[tempsocketid].onnegotiationneeded = function () {
console.log('negotiationstarted');
connections[tempsocketid].createOffer().then(function (offer) {
return connections[tempsocketid].setLocalDescription(offer);
}).then(function () {
console.log('negotiation signal sent');
socket.emit('signal', tempsocketid, JSON.stringify({ 'sdp': connections[tempsocketid].localDescription, 'room': roomNumber }), roomNumber);
}).catch(e => console.log(e));
}
localStream.getVideoTracks()[0].enabled = true;
}

Categories