Video Player Local Storage - javascript

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.

Related

Twilio DataTrack API stop?

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())

Show an image stream to client in blazor server without javascript?

Right now i have the following lines of code:
private async Task SetImageUsingStreamingAsync()
{
var imageStream = await GetImageStreamAsync();
var dotnetImageStream = new DotNetStreamReference(imageStream);
await JSRuntime.InvokeVoidAsync("setImageUsingStreaming",
"image1", dotnetImageStream);
}
Above snippet gets a Stream, and repackages that stream into DotNetStreamReferance, and then passes that DotNetStreamReferance to a JS function:
async function setImageUsingStreaming(imageElementId, imageStream) {
const arrayBuffer = await imageStream.arrayBuffer();
const blob = new Blob([arrayBuffer]);
const url = URL.createObjectURL(blob);
document.getElementById(imageElementId).src = url;
}
which populates an html element by ID. This is all fine, and works, but if i want to have a loadingscreen while i get the streams from the DB things get messy:
if(isloading)
{
show loadingscreen
}
else
{
foreach(string in listofstrings)
{
<img id="somename"></img>
}
}
the img element does not "show up", and causes an error in the js snippet if the bool isloading is not changed to false BEFORE populating the images on the site. Which kind of defeats the purpose with a loadingscreen.
Is there a smarter way of doing this? Preferably without using javascript, since i dont really know that language and cannot modify it to my needs.
The above code is a direct reference from .net documentation on blazor(not the loading part, but the stream to image part): https://learn.microsoft.com/en-us/aspnet/core/blazor/images?view=aspnetcore-6.0
if (isloading)
{
// show loadingscreen
}
else
{
// Populate a list with image elements...
List imageElements = new List();
foreach(string in listofstrings)
{
Element image = new Element("img");
image.Id = "somename";
imageElements.Add(image);
}
// ...and append the list to the DOM using RenderElementsAsync
// to ensure that it is rendered only when the list is fully
// populated.
await JSRuntime.InvokeAsync("setImageUsingStreaming", imageElements, dotnetImageStream);
}
The idea is to populate an in-memory list of elements, and then append the list to the DOM in one go, by rendering it asynchronously using RenderElementsAsync.
Note: In your original code, you should invoke the JavaScript function setImageUsingStreaming() asynchronously. That is, you should use InvokeAsync instead of InvokeVoidAsync.
Let me know if this helps...
I figured it based on Yogi's answer in the comment section of my post:
there is absolutely no need to use JS here, i dont know why the blazor docs prefer it that way.
a simple sample on how i did:
private async Task PopulateImageFromStream(Stream stream)
{
MemoryStream ms = new MemoryStream();
stream.CopyTo(ms);
byte[] byteArray = ms.ToArray();
var b64String = Convert.ToBase64String(byteArray);
string imageURL = "data:image/png;base64," + b64String;
}
}
add the imageURL to an array, or simply declare it globaly to get it in HTML:
<img src="#imageURL">

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;
}

How to transfer data from one file to another?

I am having two files such as,
employee-rates-controller.ts:
private load() {
return this.entityService
.load(this.$scope.projectRevisionUid)
.then(resp => {
localStorage.removeItem('employeerates');
this.$scope.employeeRates = resp.employeeRates;
return this.refreshCostRate(...resp.employeeRates)
.then(() =>
localStorage.setItem(
'employeerates',
JSON.stringify(this.$scope.employeeRates)
)
)
.then(() => this.refreshBillRate(...resp.employeeRates))
.then(() => resp.employeeRates.forEach(erm => this.calculate(erm)))
.then(() => DatepickerUtil.reinitializeDatepickers(this.$scope));
})
}
And in another file,
getEmployeeRates.ts:
const employeerates = JSON.parse(
localStorage.getItem('employeerates')
);
if (employeerates && employeerates.length != null) {
employeerates.forEach((element: any) => {
if (
this.employee.getUid() === element.user.personUid &&
element.internalRate
) {
this.cost_rate_uom = element.internalRate * this.uom_factor;
this.cost_rate_per_hour =
this.cost_rate_uom / this.uom_factor;
this.cost_rate.setValue(this.ap4_cost_rate_per_hour);
}
});
}
Here you can see,
In first ts file,
localStorage.setItem('employeerates',JSON.stringify(this.$scope.employeeRates))
And in second ts file receiving the data,
const employeerates = JSON.parse(localStorage.getItem('employeerates'));
I couldn't not find any problem if i add very few employees but when i keep on adding employee which means storing them into localstorage, i am getting the error at certain point of time when the data size was huge and it blocks the entire process.
The error was,
QuotaExceededError: Failed to execute 'setItem' on 'Storage': Setting
the value of 'employeerates' exceeded the quota.
So i would like to get some good solution in transferring any large data from one file to another without using the localstorage..
As the application is made in Angularjs and Typescript combination, i couldn't find out right solution as i am new to this scenario.
Edit:
Instead of first TS file, i am also able to get the value in this file.
employeeratemodel.ts:
export class EmployeeRateModel {
public uid: string;
.
.
.
public internalRate: number; // Getting the value here
}
How to fetch this value inside the second ts getEmployeeRates.ts: file..
My try:
import { EmployeeRateModel } from '../component/employee-rates/model/employee-rate.model';
constructor() {
const data = new EmployeeRateModel();
console.log(data) // {} // Gives empty object.. I need to fetch the internalRate from it..
}
Here if i get the data then it will be ease for me to get the internalRate which is needed for calculation, but as everything returns empty, this also fails for me..
Kindly help me to fix it in appropriate way, stucked for long..
use IndexedDB, it is a large-scale, NoSQL storage system. It lets you store just about anything in the user's browser and it has a huge limit based on the client computer approx 20% of total storage.
NPM Package Angular IndexedDB
Chrome's Local Storage default size is 10 Mb (https://en.wikipedia.org/wiki/Web_storage), so clearing your chrome's local storage could help you, if your data is larger than the limits, you may need to find alternatives like storing on blob storage and accessing the contents from blob itself.
For the reference, you can handle the error if you want using the code below.
try {
var counter = 1;
var stringData = "AddLocalStorageTillItIsFull";
for (var i = 0; i <= counter; counter + 1) {
stringData += stringData;
localStorage.setItem("localStorageData", stringData);
console.log(stringData);
console.log(counter);
}
}
catch (e) {
// When local storage is full, it goes hits this carch block
console.log("Local Storage is full, Please clear local storage data to add more");
}

Categories