safari recorded video speed up issue in angular 8 - javascript

I have implemented the WebRTC in my angular project to record the video. And after the save we can send it to the attachment. This is working fine in windows OS properly, but in mac safari, the video is speed up and 30-sec video becomes 3 sec only. this occurs only in safari.
Here on start the video.
mediaDevices.getUserMedia({ video: true, audio: true })
.then(webcamStream => {
this.webcamStream = webcamStream;
})
The MediaRecorder code:
this.recorder = new MediaRecorder(this.webcamStream, {mimeType: 'video/mp4'});
this.recorder.onstart = () =>
this.zone.run(() => {
this.behaviorService.isRecording(true);
});
this.recorder.onstop = this.onRecorderStopped;
this.recorder.ondataavailable = (event) =>
this.zone.run(() => {
this.data = [...this.data, event.data];
});
this.recorder.start();
When video is stopped then it save in video/webm;codecs=h264 this mimeType.
I have also tried with video/mp4 but it also not working
Can I get any solution that works in both OS?

Safari is notoriously broken with respect to .getUserMedia() and the MediaRecorder class.
Can i get the any solution which works in both OS?
Not yet. Pester Apple. In the meantime use Chrome on MacOS: it works.
There may be some tricks to recommend to make this better. But you didn't show us your MediaRecorder code: that's where the stream is compressed.

Related

MediaRecorder.start() failing without errors on Ios Chrome and Safari. Working on desktop chrome / ff

I have a mobile website that takes a few pictures (environment cam) and records a short video (user cam). On desktop, everything works fine. On mobile, the camera feed is shown on both chrome and Safari. Taking pictures also works, but when I try to start recording, the page does not execute any javascript code after mediarecorder.start(1000). This means instructions are not shown and the vid never stops recording.
Code:
async function start()
{
var constraints = { video: { width: { ideal: 4096 }, height: { ideal: 2160 }, facingMode: 'user'}};
cameraStream = await navigator.mediaDevices.getUserMedia(constraints);
video.srcObject = cameraStream; video.play();
mediaRecorder = new MediaRecorder(cameraStream,{ mimeType: 'video/webm' });
mediaRecorder.addEventListener('dataavailable', function(e) {
chunks.push(e.data);
});
}
function startRecording()
{
console.log("starting recording")
takePicture();
console.log("Selfie taken")
outline.style.display = 'none';
button.style.display = 'none';
text.innerText = "Volg de instructies op het scherm.";
//WORKS FINE TILL HERE
mediaRecorder.start(1000);
//BELOW THIS IS NEVER EXECUTED
console.log("setting timeout");
setTimeout(step,2000);
}
As said, it works on desktop, but not on iOS chrome or Safari.
Chrome and Safari on iOS are unfortunately more or less the same. Apple only allows their own browser engine on iOS and Chrome plays by those rules.
The MediaRecorder in Safari doesn't support 'video/webm' which is why I guess there is already an error thrown when you construct the MediaRecorder. Consequently the mediaRecorder variable is undefined when you try to call start() later on.
It probably works if you let Safari (or Chrome on iOS) pick the mimeType itself by omitting the configuration.
mediaRecorder = new MediaRecorder(cameraStream);

Node JS partial video streaming to safari

I'm trying to stream a video directly to a browser using node.js as the backend. I would like the video to be streamed from a specific time and would also like it to be partially streamed since it is a pretty large file. Right now I am doing this with fluent-ffmpeg, like this:
const ffmpeg = require('fluent-ffmpeg');
app.get('/clock/', (req, res) => {
const videoPath = 'video.mp4';
const now = new Date();
ffmpeg(videoPath)
.videoCodec('libx264')
.withAudioCodec('aac')
.setStartTime(`${(now.getHours() - 10) % 24}:${now.getMinutes() - 1}:${now.getSeconds()}`)
.format('mp4')
.outputOptions(['-frag_duration 100','-movflags frag_keyframe+faststart','-pix_fmt yuv420p'])
.on('end', () => {
console.log("File has been converted succesfully");
})
.on('error', (err) => {
if (err.message.toLowerCase().includes('output stream closed')) return;
console.log('An error occoured', err);
})
.pipe(res, { end: true });
});
This will work with Chrome, but Safari just doesn't want to stream it.
I know that the reason why it doesn't work on Safari is that Safari needs the range header. I've therefore tried to do that, but:
I can't get it to work with fluent-ffmpeg.
When I try to do it the "normal" way, without fluent-ffmpeg, it needs to load the whole video file before it plays.
The video doesn't need to start at the specific timestamp. It would be nice tho, but I have a workaround for that if it's not possible :)
So my question is: How can I get the code above to work with Safari. And if that is impossible: How can I code something that doesn't need to be loaded fully, before it can be played in Safari browsers, aka. partial video streaming.

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.

Audio recording is empty on safari ios

I've used RecordRTC in order to record audio and send it to a speech-to-text API.
Somehow, it all works perfectly fine except for using Safari IOS.
While using Safari IOS, the recording which I'm retrieving as base64 string,
is somehow returned empty from the recorder object.
Previous questions asked about it were answered to use another library,
yet the docs for RecordRTC specifically says it fully supports Safari IOS.
Could you please help me figuring out the problem and finding a workaround?
My code:
async initMic() {
let stream = await navigator.mediaDevices.getUserMedia({video: false, audio: true});
mic = new RecordRTCPromisesHandler(stream, {
type: 'audio',
mimeType: 'audio/wav',
recorderType: RecordRTC.StereoAudioRecorder,
sampleRate: 48000,
numberOfAudioChannels: 1,
});
},
async sendRecording() {
let vm = this;
mic.stopRecording(function() {
mic.getDataURL(function(dataURL) {
vm.$store.dispatch('UpdateAudioBase64', dataURL.replace('data:audio/wav;base64,', ''));
mic.reset();
vm.$emit('send-recording');
});
});
},
** The string 'replace' function is meant to remove the base64 header
before sending it to speech-to-text API (API's needs).
Thank You!
If not mistaken, apple fu... messed up again with their dumb policy,
problem is you can't do a lot of things(like setting up recorder)
without USER trigger them,
so you should wrap your recorder in click event listener,
user click button, then your mic = new RecordRTCPromisesHandler(stream, {... etc
fires and recording starts.
check this example https://github.com/muaz-khan/RecordRTC/blob/master/simple-demos/audio-recording.html
here this trick works
btw your code works in mac safari?

iOS Safari: audio only recording noise

I'm developing an application that allows voice recording in the web browser. This is working fine on most browsers but I have some issues with iOS Safari.
Below you can find an extract of the code, it is not complete but it gives an idea of what's going on.
//Triggered when the user clicks on a button that start the recording
function startRecording() {
//Create new audio context
let audioContext = new (window.AudioContext || window.webkitAudioContext);
//Hack polyfill media recorder to re-use the audioContex
window.NewMediaRecorder.changeAudioContext(audioContext);
navigator.mediaDevices.enumerateDevices().then(function (devices) {
console.log('loaded audio devices');
console.log(devices);
devices = devices.filter((d) => d.kind === 'audioinput');
console.log(devices);
console.log('chosen device: ' + devices[0].deviceId);
navigator.mediaDevices.getUserMedia({
audio: {
deviceId : {
exact : devices[0].deviceId
}
}
}).then(function (stream) {
console.log(stream);
let recorder = new NewMediaRecorder(stream);
recorder.addEventListener('dataavailable', function (e) {
document.getElementById('ctrlAudio').src = URL.createObjectURL(e.data);
});
recorder.start();
console.log('stop listening after 15 seconds');
setTimeout(function () {
console.log('15 seconds passed');
console.log("Force stop listening");
recorder.stop();
recorder.stream.getTracks()[0].stop();
}, 15000);
});
});
}
For the record, I'm using audio recorder polyfill (https://ai.github.io/audio-recorder-polyfill/) in order to achieve recording, as MediaRecorder is not yet available on Safari.
The recorder works fine on all navigators (this including OS X Safari), yet on iOS Safari it only records noice. If I set the volume of my speakers at maximal level I can hear myself speak, but it is from "very far away".
All the online dictaphones/recorders that I found have the same issue, they always recording noise. (Tested with an iPhone 5S, 5SE and X, all up to date).
I'm a bit desperate because I already did a lot of research, but I didn't find any solution for this issue.
As required, the AudioContext is created on a user event (in this case a touch on a button).
I even tried to change the gain of but that didn't help.
Trying to access the audio without setting a media device isn't helping.
navigator.mediaDevices.getUserMedia({audio: true})

Categories

Resources