download and play stream audio in angular 8 - javascript

i need to play sound with user click on the preview icon .
this is my html code :
<audio controls>
<source [src]="fileSource" type="audio/mp3">
</audio>
this this is ts code :
fileSource: any;
ngOnInit(): void {
if (typeof this.data.src === 'number') {
this.getImageFromService();
}
}
createImageFromBlob(image: Blob): void {
const reader = new FileReader();
reader.addEventListener('load', () => {
this.fileSource = reader.result;
}, false);
if (image) {
reader.readAsDataURL(image);
}
}
getImageFromService(): void {
this.isLoading = true;
this.postFileService.downloadFile(this.data.src).subscribe(data => {
this.createImageFromBlob(data);
this.isLoading = false;
}, error => {
this.isLoading = false;
console.log(error);
});
}
and this is my service :
downloadFile(id: number): Observable<Blob> {
const URL = `${this.appConfig.apiEndpoint + '/PostFileContent/DownloadFile/' + id}`;
return this.http.get(URL, { responseType: 'blob' });
}
now my prolem is this :
i need to when click the preview icon T open the modal dialog box and play audio .
when i click on the preview icon the file is downloaded but it not play .
whats the problem ? how can i solve this ???

Following code will work for playing audio automatically file which was retrieved from backend(node.js).
angular.html
<audio controls>
<source type="audio/mpeg" [src]="fileSource" >
</audio>
angualr.ts
// mention your backend url directly here like below
fileSource:any = 'http://localhost:1234/getAudioFile';
node-backend-code
app.use('/getAudioFile',function(req,res,next){
// i stored sample mp3 file in my local directory
var filePath = path1.join(__dirname, './sample.mp3');
var stat = fileSystem.statSync(filePath);
res.writeHead(200, {
'Content-Type': 'audio/mpeg',
'Content-Length': stat.size
});
var readStream = fileSystem.createReadStream(filePath);
// We replaced all the event handlers with a simple call to readStream.pipe()
readStream.pipe(res);
// res.send("this is audio ");
next();
});
Note:: Make sure that you get directly audio file from backend(irrespective of node or java).

Related

Media Source Extension issue on change for new segments

there
I have two videos segments array
video1 = ['v1_1.ts','v1_2.ts','v1_3.ts','v1_4.ts',...]
video2 = ['v2_1.ts','v2_2.ts','v2_3.ts','v2_4.ts',...]
MSE is working perfect with playing video1 segments, but when I try to play video segments 2 nothing happened
I can't even restart playing video1 segments
Can anyone explain, how to start playing new video segments in Media Source Extension
<html>
<head>
<title>Basic Transmuxer Test</title>
</head>
<body>
<div><button onclick="play1()">Restart video</button>
<video controls width="80%"></video>
<script src="https://github.com/videojs/mux.js/releases/latest/download/mux.js"></script>
<script>
// Create array of TS files to play
segments = [
"segment_1.ts",
"segment_2.ts",
"segment_3.ts",
"segment_4.ts"
];
// Replace this value with your files codec info
mime = 'video/mp4; codecs="mp4a.40.2,avc1.64001f"';
let mediaSource = new MediaSource();
mediaSource.addEventListener('error', function(err) {
throw new Error("MSE: " + err.message);
});
let sourceBuffer = null;
let transmuxer = new muxjs.mp4.Transmuxer();
video = document.querySelector('video');
video.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener("sourceopen", appendFirstSegment);
function play1(){
sourceBuffer.abort();
segments = [
"segment_0.ts",
"segment_1.ts",
"segment_2.ts",
"segment_3.ts",
"segment_4.ts",
"segment_5.ts",
"segment_6.ts",
"segment_7.ts",
"segment_8.ts",
"segment_9.ts"
];
appendFirstSegment()
}
function appendFirstSegment(){
if (segments.length == 0){
return;
}
console.log('appendFirstSegment')
if(!sourceBuffer){
sourceBuffer = mediaSource.addSourceBuffer(mime);
sourceBuffer.mode = 'sequence';
}
//mediaSource.duration = 0;
sourceBuffer.addEventListener('updateend', appendNextSegment,false);
transmuxer.off('data');
transmuxer.on('data', (segment) => {
let data = new Uint8Array(segment.initSegment.byteLength + segment.data.byteLength);
data.set(segment.initSegment, 0);
data.set(segment.data, segment.initSegment.byteLength);
console.log(muxjs.mp4.tools.inspect(data));
sourceBuffer.appendBuffer(data);
})
fetch(segments.shift()).then((response)=>{
return response.arrayBuffer();
}).then((response)=>{
transmuxer.push(new Uint8Array(response));
transmuxer.flush();
})
}
function appendNextSegment(){
// reset the 'data' event listener to just append (moof/mdat) boxes to the Source Buffer
transmuxer.off('data');
transmuxer.on('data', (segment) =>{
sourceBuffer.appendBuffer(new Uint8Array(segment.data));
})
if (segments.length == 0){
// notify MSE that we have no more segments to append.
//mediaSource.endOfStream();
}
if(segments.length>0){
fetch(segments.shift()).then((response)=>{
return response.arrayBuffer();
}).then((response)=>{
transmuxer.push(new Uint8Array(response));
transmuxer.flush();
})
}
}
</script>
</body>
</html>

Choosing audio format when saving data locally on a web app

I have a web app getting some audio recording input from the user.
And there is a button to save it locally as an audio file.
The resulting file I am getting is of ogg-opus format. Concretely when I use the file command I get this in the terminal:
MyMac$ file Clip.wav
Clip.wav: Ogg data, Opus audio,
MyMac$
I can check that the recording is all right using VLC.
On the other hand I can't play the file with afplay as is normally possible with an mp3, m4a or wav file.
MyMac$ afplay Clip.wav
Error: AudioFileOpen failed ('typ?')
MyMac$
Here follows my relevant code:
if (navigator.mediaDevices.getUserMedia) {
// getUserMedia is supported.
const constraints = { audio: true };
let chunks = [];
let onSuccess = function(stream) {
const mediaRecorder = new MediaRecorder(stream);
visualize(stream);
........
mediaRecorder.onstop = function(e) {
........
audio.setAttribute('controls', '');
........
audio.controls = true;
const blob = new Blob(chunks, { 'type' : 'audio/wav;codecs=0' });
chunks = [];
........
upload.addEventListener("click",
function(event) {loadToServer(blob)})
........
}
mediaRecorder.ondataavailable = function(e) {
chunks.push(e.data);
}
}
let onError = function(err) {
console.log('The following error occured: ' + err);
}
navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError);
} else {
console.log('getUserMedia not supported on your browser!');
}
I would like to know how to change my code in order to generate a proper wav file or even mp3.
Note:
I have made trials modifying this line of code:
const blob = new Blob(chunks, { 'type' : 'audio/wav;codecs=0' });
in various ways, but is has no effect at all.
In order to specify the mimeType of your recording you need to tell the MediaRecorder which mimeType you prefer before it starts the recording.
- const mediaRecorder = new MediaRecorder(stream);
+ const mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/wav' });
Unfortunately audio/wav is not supported by any browser. You will get an error when trying the snippet above.
Since I needed wav recordings as well I built a library which is meant to add this functionality. It's called extendable-media-recorder because it could be extended with any other (audio) codec you like.
If you don't want to use a third party library and keep the browser using the codec it likes best you can save your file like this in order to get a valid file with the correct suffix.
- const blob = new Blob(chunks, { 'type' : 'audio/wav;codecs=0' });
+ const blob = new Blob(chunks, { 'type' : mediaRecorder.mimeType });
The suffix would then be the portion of the type after the slash and before a possible semicolon.
Here is an example of a full HTML document that uses jspm to load extendable-media-recorder without a bundler.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
</head>
<body>
<button id="start" disabled>start</button>
<button id="stop" disabled>stop</button>
<script type="module">
import { MediaRecorder, register } from 'https://jspm.dev/extendable-media-recorder';
import { connect } from 'https://jspm.dev/extendable-media-recorder-wav-encoder';
const $start = document.getElementById('start');
const $stop = document.getElementById('stop');
await register(await connect());
const chunks = [];
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const mediaRecoder = new MediaRecorder(stream, { mimeType: 'audio/wav' });
mediaRecoder.addEventListener('dataavailable', ({ data }) => {
chunks.push(data);
});
mediaRecoder.addEventListener('stop', ({ data }) => {
const blob = new Blob(chunks, { type : mediaRecoder.mimeType });
console.log(blob);
});
$start.addEventListener('click', () => {
mediaRecoder.start();
$stop.addEventListener('click', () => {
$stop.disabled = true;
mediaRecoder.stop();
});
$start.disabled = true;
$stop.disabled = false;
});
$start.disabled = false;
</script>
</body>
</html>

Get audio file from server endpoint and play in vue app

We have a listing module.
In that there is an audio element for each row.
How can I get the mp3/wav from API and then correctly bind it with src of audio element?
Here is my code:
JS
methods:{
playa(recording_file) => {
try {
const requestOptions = {
method: 'POST',
responseType: 'arraybuffer',
headers: {
'Content-Type': 'application/json',
//'Authorization': 'Bearer ' + localStorage.getItem('jwt')
},
};
const response = axios.post(`api/playrecfile?rec=${recording_file}`)
const mp3 = new Blob([response.data], { type: 'audio/mp3' })
const url = URL.createObjectURL(mp3);//tried window.
return url;
} catch (e) {
console.log('play audio error: ', e)
}
}
}
HTML(cell of a row)(I can see data and checked value of meta also)
<div :class="classes" #click="click(data)" v-else-if="name=='Play'" title='Play'>
<!-- <span><i class="fa fa-play"></i></span> -->
<audio controls :ref="'audio'+data.recording_file" v-if="meta.is_admin==1 && data.recording_filename" :src="playa(data.recording_filename)">
</audio>
<span v-else #click="givealert()">
<i class="fa fa-play"></i>
</span>
</div>
PHP/Laravel
$out = isset($request->out) ? $request->out : "mp3";
header("Content-type: audio/x-$out");
header("Content-disposition: attachment; filename=tuzbd.$out");
header("Access-Control-Allow-Origin: *");
$file = base_path(). "/storage/app/recs/2019/05/03/tuzbd.mp3";
header("Content-length: " . filesize($file));
readfile($file);
return;
I don't use the Vue-JS framework but the logic in regular HTML5 would be:
(1) Give the audio tag an ID (eg: myAudio).
<audio id="myAudio" controls :ref="'audio'+data.recording_file" v-if="meta.is_admin==1 && data.recording_filename" :src="playa(data.recording_filename)">
</audio>
(2) Then directly update the audio tag's source with result of createObjectURL:
Using Vue-JS you want to achieve something like this:
methods:{
playa(recording_file) => {
try
{
const requestOptions = {
method: 'POST',
responseType: 'arraybuffer',
headers: {
'Content-Type': 'application/json',
//'Authorization': 'Bearer ' + localStorage.getItem('jwt')
},
};
var response = axios.post(`api/playrecfile?rec=${recording_file}`)
//# try reading into Blob as BINARY data (eg: raw bytes)
//const mp3 = new Blob([response.data], { type: 'audio/mp3' })
var mp3 = new Blob([response.data], { type: 'application/octet-stream' })
//const = URL.createObjectURL(mp3);//tried window.
//return url; //# don't Return but instead just update the audio tag's source...
//# update file path for Audio tag...
var url = (window.URL || window.webkitURL).createObjectURL( mp3 );
var audioObj = document.getElementById("myAudio");
audioObj.setAttribute("src", url); //# updates the source of the Audio tag
//# If you need to handle MP3 bytes... eg: read/modify/delete some ID3 metadata bytes...
var reader = new FileReader();
reader.readAsDataURL( mp3 );
reader.onloadend = function(evt)
{
if (evt.target.readyState == FileReader.DONE)
{
//# access MP3 bytes here... as arraybuffer
bytes_mp3 = new Uint8Array( evt.target.result ); //define your "var bytes_mp3" globally (var is outside of any function)
}
}
}
catch (e) { console.log('play audio error: ', e) }
}
Where the above FileReader reads the file as a stream of bytes (since audio tag is expecting a file, meaning its just a stream of bytes regardless if data is MP3 or PDF).

How to post/upload recorded video as blob in MVC using HTML5/ Javascript at client side and C# code at controller?

I am building a video surveillance application where the requirement is to save recorded video feeds to the server so that they can be served up to the viewer later. Am using MediaRecorder API to do so, and as the continuous stream would end up in a very large file difficult to be posted all at once, i plan to chop the stream blob into multiple chunks and keep posting periodically. Now the recording event is fired with a toggle switch in html page and then Javascript takes over.
Here is the code that i have so far:
HTML:
some code...
<div class="onoffswitch">
<input type="checkbox" name="onoffswitch" class="onoffswitch-checkbox" id="switch1">
<label class="onoffswitch-label" for="switch1" onclick="toggleVideoFeed();">
<span class="onoffswitch-inner"></span>
<span class="onoffswitch-switch"></span>
</label>
</div>
some code...
JavaScript:
var mediaRecorder;
var pushInterval = 6000;
var id, counter = 0;
// var formData;
function toggleVideoFeed() {
var element = document.getElementById("switch1");
element.onchange = (function (onchange) {
return function (evt) {
// reference to event to pass argument properly
evt = evt || event;
// if an existing event already existed then execute it.
if (onchange) {
onchange(evt);
}
if (evt.target.checked) {
startRecord();
} else {
stopRecord();
};
}
})(element.onchange);
}
var dataAvailable = function (e) {
var formData = new FormData();
var fileName = "blob" + counter + ".mp4";
console.log("data size: ", e.data.size);
var encodeData = new Blob([e.data], { type: 'multipart/form-data' });
formData.append("blob", encodeData, fileName);
var request = new XMLHttpRequest();
request.open("POST", "/Device/Upload", false);
request.send(formData);
counter++;
}
function startRecord() {
navigator.getUserMedia = (navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia);
if (navigator.getUserMedia) {
navigator.getUserMedia(
// constraints
{
video: true,
audio: false
},
// successCallback
function (stream) {
mediaRecorder = new MediaRecorder(stream);
mediaRecorder.start();
mediaRecorder.ondataavailable = dataAvailable;
// setInterval(function () { mediaRecorder.requestData() }, 10000);
},
// errorCallback
function (err) {
console.log("The following error occured: " + err);
}
);
} else {
console.log("getUserMedia not supported");
}
}
function stopRecord() {
mediaRecorder.stop();
}
Controller-C#
[HttpPost]
public JsonResult Upload(HttpPostedFileBase blob)
{
string fileName = blob.FileName;
int i = Request.Files.Count;
blob.SaveAs(#"C:\Users\priya_000\Desktop\Videos\" + fileName);
return Json("success: " + i + fileName);
}
THE PROBLEM:
When i try playing the received .mp4 files as i get them on the server end, i can play just the first file blob0 and the rest although they show similar sizes to the first file (4 mb each) do not contain any video data. Is it possible that the data i receive on the other end is corrupt/ garbled? Or is there something wrong with my code. Please help guys - Have been trying to solve this problem since the last 10 days with no clue how to figure it out.
mp4 files have a header which is put at the beginning of the file. The header contains information used to initialize the decoder and without it the file cannot be played. Try concatenating the files (the first one and the second one) and see if the whole file plays. If yes then the problem is a missing header. If not please send me the two files so I can inspect them and see what exactly is stored in these.
There is no way AFAIK to instruct MediaRecorder to append the header to each blob of video. You have to do it manually.
PS. sorry for the late response.
You can use RecordRTC by Muaz Khan and use the MVC Section to record and save video to the server.

Uploading an audio file obtained via getUserMedia() and Javascript to a server using PHP

I have pieced together a Javascript audio recorder that grabs the user microphone via getUserMedia and records and outputs a .OGG file for download. Note this only works in Firefox, which is fine for me.
Rather than provide a download link I want the file to be uploaded to the server via PHP as soon as it stops recording. I'm not sure how I should be going about doing that. I have tried using a form to grab it from $_FILES but I can't figure out how to pre populate the form with the BLOB to submit.
Here is what I have so far. Any input on how to move this along to a server via PHP would be appreciated!
<html>
<head>
</head>
<body>
<div id="container">
<audio controls autoplay></audio>
<a id="downloadLink" download="mediarecorder.ogg" name="mediarecorder.ogg" href></a>
<p id="data"></p>
<script >
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
var constraints = {audio: true};
var audioElement = document.querySelector('audio');
var dataElement = document.querySelector('#data');
var downloadLink = document.querySelector('a#downloadLink');
function errorCallback(error){
console.log("navigator.getUserMedia error: ", error);
}
var count = 0;
function startRecording(stream) {
log('Starting...');
mediaRecorder = new MediaRecorder(stream);
mediaRecorder.onerror = function(e){
log('Error: ' + e);
};
mediaRecorder.onstart = function(e){
log('Started');
};
mediaRecorder.onstop = function(e){
log('Stopped');
};
mediaRecorder.onwarning = function(e){
log('Warning: ' + e);
};
// parameter is number of milliseconds of data to return in a single Blob
mediaRecorder.start();
window.setTimeout(function(){
mediaRecorder.stop();
}, 2400000);
}
window.onload = function(){
if (typeof MediaRecorder === 'undefined' || !navigator.getUserMedia) {
alert('Sorry! This demo requires Firefox Nightly.');
} else {
window.onkeydown = function(e){
if ( e.keyCode == 82 ) { //R pressed
navigator.getUserMedia(constraints, startRecording, errorCallback);
} else if ( e.keyCode == 83 ) { // S pressed
mediaRecorder.stop();
mediaRecorder.ondataavailable = function(e) {
log('Data available...');
count++;
if (count > 1) {
return;
}
console.log(e);
audioElement.src = window.URL.createObjectURL(e.data);
downloadLink.href = window.URL.createObjectURL(e.data); //Audio BLOB
downloadLink.innerHTML = "Download ogg audio file";
};
}
}
}
};
function log(message){
dataElement.innerHTML = message + '<br>' + dataElement.innerHTML ;
}
</script>
</div>
</body>
</html>
For security reasons in most browsers it is not allowed to pre fill an html upload element. Is the ogg file stored locally (on the client). If it is stored on the webserver an option could be to post the (public available) url to a php script and open it in by using file_get_contents.

Categories

Resources