WebRTC-Experiment icon indicating copy to clipboard operation
WebRTC-Experiment copied to clipboard

RecordRTC and best way and how to save on server

Open RussellParrott opened this issue 11 years ago • 40 comments

Hi Mauz Have been playing with your experiments - they are great and very interesting. Please excuse me but I am not a java script person at all - my limitation is a small (very) bit of jQuery - php etc. I have no problem with so if you have already answered this question I apologise.

So I run the RecordRTC "file/s" on my server I can record video and I can stop, I can then view that video (in terms of your demo page), but how do I/can I send/save the file which I assume is a temp file(?) to the server.

The demo page shows this:

/* stop recording video and save recorded file to disk */ recorder.stopVideo(function(recordedFileURL) { window.open(recordedFileURL); });

but is that actually saving the file because my basic understanding is that just opens another window.

Lets say I run the demo on page "record.php" and I have a folder "recordings" how do I get the file into recordings and save it?

Cheers

RussellParrott avatar Jun 13 '13 11:06 RussellParrott

See this answer.

  1. Get Blob object instead of DataURL
  2. POST it over the server using FormData object

RecordRTC will be fixed in next commits. You can change this line to use blobURL instead of blobURL2:

getBlob: function () {
    return blobURL;
}

And POST it like this:

blob = recorder.getBlob();

formData = new FormData();
formData.append('key', blob);

xhr.send(formData);

muaz-khan avatar Jun 13 '13 12:06 muaz-khan

Hi Mauz, thanks for that, as said java not strong point so I guess formData.append('key', blobURL); key is the "field" name? xhr.send() is "submitting the form"? do I then use say a php script to move the file the same way as an upload? Sorry for being thick - Oh and where is it being sent to? I can't see a reference to the page/folder?

RussellParrott avatar Jun 13 '13 12:06 RussellParrott

Did this ever get resolved? Would be nice to see a demo working with this posting to PHP. HELP please.

Brettk80 avatar Aug 02 '13 04:08 Brettk80

Hi Muaz. Sorry for the tweet, I didn't see this bug manager. I tried the following :

blob = recorder.getBlob();

formData = new FormData();
formData.append('audio-result', blob, 'audioresult');

function reqListener () {
  console.log(this.responseText);
};

var xhr = new XMLHttpRequest();
xhr.onload = reqListener;
xhr.open("POST", "save.php", true);
xhr.send(formData);

And my save.php just var_dump($_POST). Works well with a string (formData.append('audio-result', 'test string', 'audioresult');) but not with the blob. It seems to be empty. Any idea what's wrong ?

Thank you for your time and for this lib.

raphaelyancey avatar Aug 26 '13 13:08 raphaelyancey

@raphaelyancey, check this demo. Here is PHP code

<?php
foreach(array('video', 'audio') as $type) {
    if (isset($_FILES["${type}-blob"])) {

        $fileName = $_POST["${type}-filename"];
        $uploadDirectory = "uploads/$fileName";

        if (!move_uploaded_file($_FILES["${type}-blob"]["tmp_name"], $uploadDirectory)) {
            echo("problem moving uploaded file");
        }

        echo($uploadDirectory);
    }
}
?>

And JavaScript code:

var fileType = 'video'; // or "audio"
var fileName = 'ABCDEF.webm';  // or "wav"

var formData = new FormData();
formData.append(fileType + '-filename', fileName);
formData.append(fileType + '-blob', blob);

xhr('save.php', formData, function (fileURL) {
    window.open(fileURL);
});

function xhr(url, data, callback) {
    var request = new XMLHttpRequest();
    request.onreadystatechange = function () {
        if (request.readyState == 4 && request.status == 200) {
            callback(location.href + request.responseText);
        }
    };
    request.open('POST', url);
    request.send(data);
}

Try the demo: https://www.webrtc-experiment.com/RecordRTC/PHP/

muaz-khan avatar Aug 28 '13 05:08 muaz-khan

It works like a charm, thank you @muaz-khan

raphaelyancey avatar Aug 28 '13 08:08 raphaelyancey

Hi, I'm using this: blob = recorder.getBlob(); to get Blob data, but blob alway is 'undefined', when log mediaRecorder.recordedBlob have the recorded blob data.

What's wrong in here ?

mrpeo avatar Sep 11 '14 09:09 mrpeo

recordRTC.stopRecording(function() {
    var blob = recordRTC.getBlob(); // it'll NEVER be undefined
});

You need to use stopRecording method's callback.

muaz-khan avatar Sep 16 '14 16:09 muaz-khan

where is the file save before uploading the server?

Thanks

abhisirohi72 avatar Nov 18 '15 05:11 abhisirohi72

I am using this in Spring MVC application and not able to obtain blob from post request. How to do it it Servlets / Spring MVC way.

JayashJagtap avatar Jul 18 '17 22:07 JayashJagtap

Whenever i click on start recording, it says RecordRTC is not defined. How can i solve this error? do i have to define it somewhere?

umeryounus1994 avatar Dec 20 '17 16:12 umeryounus1994

Hello Assalam-u-Alaikum Muaz i really really appreciate your work i learn alot from you and i applied many thing in real world applications now can you please tell me how i can record a video which drop on server without browser open and video record should save in selected storage device

sunnykhan1621 avatar Jan 16 '18 09:01 sunnykhan1621

Hi Muaz A/s, Thanks a lot to provide great solutions for developers, can we implement this in django/python?

Kashif-Anwar avatar Feb 24 '18 05:02 Kashif-Anwar

Hi Muaz,

it's not working on iphone, is it not compatible with ios or I'm missing something?

Thanks!

umairm638 avatar Mar 06 '18 09:03 umairm638

IOS doesnt support webrtc without it being within an app. No browser support.

On Mar 6, 2018 2:32 AM, "umairm638" [email protected] wrote:

Hi Muaz,

it's not working on iphone, is it not compatible with ios or I'm missing something?

Thanks!

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/muaz-khan/WebRTC-Experiment/issues/48#issuecomment-370719570, or mute the thread https://github.com/notifications/unsubscribe-auth/ABBTlkSEMTolvNQ6ZfufadR1dBCFlgFxks5tblfDgaJpZM4Au2xH .

Brettk80 avatar Mar 06 '18 14:03 Brettk80

Hi Mauz, Is there any reference to upload recording using JAVA spring MVC.

Thanks, Amit

amitrathi1982 avatar May 03 '18 10:05 amitrathi1982

Hi Amit,

 First you have to send blob to your controller and create a file like

mp4, then you can do whatever you want, you can send blob with ajax I have done this with django (python) but doesn't matter, see only javascript:

function captureCamera(callback) { navigator.mediaDevices.getUserMedia({ audio: true, video: true }).then(function(camera) { callback(camera); }).catch(function(error) { alert('Unable to capture your camera. Please check console logs.'); console.error(error); }); } function stopRecordingCallback() { //video.play(); recorder.camera.stop(); //recorder.destroy(); //recorder = null; } var recorder; // globally accessible document.getElementById('btn-start-recording').onclick = function() { this.disabled = true; captureCamera(function(camera) { setSrcObject(camera, video); video.play(); recorder = RecordRTC(camera, { type: 'video', }); recorder.startRecording(); // release camera on stopRecording recorder.camera = camera; document.getElementById('btn-stop-recording').disabled = false; }); }; document.getElementById('btn-stop-recording').onclick = function() { this.disabled = true; recorder.stopRecording(stopRecordingCallback); document.getElementById('btn-play-recording').disabled = false; document.getElementById('btn-upload').disabled = false; };

$("#btn-upload").on("click", function(){ this.disabled = true; document.getElementById('btn-play-recording').disabled = true; if(!recorder || !recorder.getBlob()) return; var blob = recorder.getBlob(); uploadBlob(blob); })

//ajax calling function uploadBlob(blob) { var formData = new FormData(); formData.append('video-blob', blob); formData.append('video-filename', 'demo.mp4'); $.ajax({ url: "{{SITE_URL}}/upload-video/", type: "POST", data: formData, processData: false, contentType: false, success: function(response) { $('#select_recordtype').modal('toggle'); $('#hiddenUrl').val(response.toString()); $('.recorder_box').hide(); var video = $('', { id: 'video', src: response, type: 'video/mp4', controls: true }); video.appendTo($('.selected_video')); $('.selected_video').show(); //alert('Successfully uploaded.'); //$("#record_now").hide().css('display','none'); //$("#pre-video").show().css('display','block'); }, error: function(jqXHR, textStatus, errorMessage) { alert('Error:' + JSON.stringify(errorMessage)); } }); }

and in controller only you have to create file:

#file creater @csrf_exempt def create_file(request):

if request.method == 'POST':
    filename = request.POST.get('video-filename', '')
    file = request.FILES.get('video-blob', '')
    if file:
            if not os.path.exists('static/video-msg/'):
                    os.mkdir('static/video-msg/')

            with open('static/video-msg/' + filename, 'wb+') as

destination: for chunk in file.chunks(): destination.write(chunk) return HttpResponse('Created!') else: return HttpResponse("Blob getting Error")

else:
    return HttpResponse("No Request given")

Best Regards,

Kashif AnwarSoftware Engineer Mobile: +919718577858

On Thu, May 3, 2018 at 3:36 PM, amitrathi1982 [email protected] wrote:

Hi Mauz, Is there any reference to upload recording using JAVA spring MVC.

Thanks, Amit

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/muaz-khan/WebRTC-Experiment/issues/48#issuecomment-386247686, or mute the thread https://github.com/notifications/unsubscribe-auth/AWnstDQ5258jFK2Bfp2rHsq9NV50cXF0ks5tutbCgaJpZM4Au2xH .

Kashif-Anwar avatar May 04 '18 05:05 Kashif-Anwar

Dear Kashif, Thanks a lot for your response. It is working now.

Now I am getting one popup when starting recording: Please enable this command line flag: "--enable-usermedia-screen-capturing" Can you please help me how can I resolve it? Is there anything which can be downloaded automatically if required as page loads or handle programmatically.

Thanks a lot once more for your kind support.

amitrathi1982 avatar May 04 '18 09:05 amitrathi1982

Have you include RecordRTC.js?

Since var recorder is using this js, if so then error shouldn't happen, if you are getting some other please see something else going wrong, check you camera permission.

On Fri 4 May, 2018, 3:13 PM amitrathi1982, [email protected] wrote:

Dear Kashif, Thanks a lot for your response. It is working now.

Now I am getting one popup when starting recording: Please enable this command line flag: "--enable-usermedia-screen-capturing" Can you please help me how can I resolve it? Is there anything which can be downloaded automatically if required as page loads or handle programmatically.

Thanks a lot once more for your kind support.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/muaz-khan/WebRTC-Experiment/issues/48#issuecomment-386552316, or mute the thread https://github.com/notifications/unsubscribe-auth/AWnstM6F8kffcmj3JbpQ2Qryfi9rAsHOks5tvCKvgaJpZM4Au2xH .

Kashif-Anwar avatar May 05 '18 18:05 Kashif-Anwar

Hi Kashif, Thanks for the response. Actually my requirement is to capture a particular window (say mozila/chrome or where this application is running) only with audio. It will also be good if I can capture only that Tab of browser window (If it can happen). So I did below steps:

  1. I am using "https://www.webrtc-experiment.com/RecordRTC/" demo and chosen "Microphone+Screen".
  2. I have downloaded this HTML at my local and downloaded all the ".JS" (including RecordRTC.js and other dependent JS) to my local from CDN URL.
  3. I ran this sample from localhost, On mozila it is working fine. But in chrome it is showing that popup. "Please enable this command line flag: "--enable-usermedia-screen-capturing" and showing "onMediaCapturingFailed: {name: "NotAllowedError", message: "Invalid state", constraint: undefined, toString: ƒ}" in browser console. Although in demo it is workiing fine (https://www.webrtc-experiment.com/RecordRTC/). So my stuck point is should I enable/add some security bypass code or something else. Please help me here.

Another point is: When I am doing it on mozila it show one popup to choose which window I want to record/share. Is there any setting/option where I can set default window to select automatically the window where application is running (current window).

Point 3: After stopping recording when I play this recording in new tab, it shows one URL: "http://localhost:8080/0eb129a1-1fd6-44a0-b78a-1071689ef5f5". My expectation here is, can we upload this video on server (As stream) directly even before stoping.

Thanks a lot Kasif once again.

amitrathi1982 avatar May 06 '18 04:05 amitrathi1982

@amitrathi1982 To fix screen capturing issues on localhost or on any https domain:

  1. Download this chrome plugin source code, modify manifest.json for matches attribute only to set your own domain's permissions. Now open chrome://extensions/ and click "Load unpacked extension" button to locate the extension directory.
  2. Otherwise use getScreenId.js. Which requires this plugin installation. However please make sure to run getScreenId only on localhost or on a real HTTPs domain. Don't run getScreenId on jsfiddle or inside-iframes. Iframes are not supported.

Here is a simple demo explains how to use getScreenId with RecordRTC.

Regarding "upload in realtime": the best solution is use a media-server where you will open RTCPeerConnection connections with the server.

RecordRTC accepts timeSlice and ondataavailable options that allows you get blobs instantly and upload to server after fixed intervals. Here is a simple demo. However your server must merge all files into a single file after recording finishes. Here is a similar demo using ffmpeg on server-side using nodejs. You can check a socketio demo as well.

muaz-khan avatar May 06 '18 05:05 muaz-khan

Dear Mauz, Thanks for clarification. I am using below code to get screenId:

getScreenId(function (error, sourceId, screen_constraints) { // error == null || 'permission-denied' || 'not-installed' || 'installed-disabled' || 'not-chrome' // sourceId == null || 'string' || 'firefox'

if(navigator.userAgent.indexOf('Edge') !== -1 && (!!navigator.msSaveOrOpenBlob || !!navigator.msSaveBlob)) {
    navigator.getDisplayMedia(screen_constraints).then(stream => {
        document.querySelector('video').srcObject = stream;
    }, error => {
        alert('Please make sure to use Edge 17 or higher.');
    });
    return;
}

navigator.mediaDevices.getUserMedia(screen_constraints).then(function (stream) {
    document.querySelector('video').srcObject = stream;

    // share this "MediaStream" object using RTCPeerConnection API
}).catch(function (error) {
    console.error(error);
});

}, 'pass second argument only if you want to capture speakers as well');

It is capturing screen successfully but audio (Microphone) is not being captured. I read above that to capture, we need to pass 2nd paramater (pass second argument only if you want to capture speakers as well). So which type of this parameter will be . Is that booelan "true" or else. I passed "true" but audio not captured.

Full function where I merged above code is given here: I know you might be busy in some important task, but please get few moment and take a look:

function captureAudioPlusScreen(config) { // Firefox screen capturing addon is open-sourced here: https://github.com/muaz-khan/Firefox-Extensions // Google Chrome screen capturing extension is open-sourced here: https://github.com/muaz-khan/Chrome-Extensions/tree/master/desktopCapture console.log("captureAudioPlusScreen function called.."); if(DetectRTC.browser.name === 'Firefox' || isLocalHost()) { **getScreenId(function (error, sourceId, screen_constraints) { // error == null || 'permission-denied' || 'not-installed' || 'installed-disabled' || 'not-chrome' // sourceId == null || 'string' || 'firefox'

	                    console.log("sourceId-->"+sourceId + " : "+screen_constraints);
	
	                    if(sourceId && sourceId != 'firefox') {
	                        screen_constraints = {
	                            video: {
	                                mandatory: {
	                                    chromeMediaSource: 'screen',
	                                    maxWidth: 1920,
	                                    maxHeight: 1080,
	                                    minAspectRatio: 1.77
	                                }
	                            }
	                        };
	
	                        if (error === 'permission-denied') 
	                        	return alert('Permission is denied.');
	                        if (error === 'not-chrome') 
	                        	return alert('Please use chrome.');
	
	                        if (!error && sourceId) {
	                            screen_constraints.video.mandatory.chromeMediaSource = 'desktop';
	                            screen_constraints.video.mandatory.chromeMediaSourceId = sourceId;
	                        }
	                    }
	
	                    navigator.getUserMedia = navigator.mozGetUserMedia || navigator.webkitGetUserMedia;
	                    navigator.getUserMedia(screen_constraints, function (stream) {
	                    	console.log(" document.querySelector('video').src--"+ document.querySelector('video').src);
	                    	
	                    	  config.onMediaCaptured(stream);

	                            addStreamStopListener(stream, function() {
	                                config.onMediaStopped();
	                            });
	                      //  document.querySelector('video').src = stream;
	
	                        // share this "MediaStream" object using RTCPeerConnection API
	                    }, function (error) {
	                      console.error('getScreenId error', error);		
	                      alert('Failed to capture your screen. Please check Chrome console logs for further information.');
	                    });
	                },'pass second argument only if you want to capture speakers as well');                             
            }**

            window.postMessage('get-sourceId', '*');
        }

amitrathi1982 avatar May 07 '18 10:05 amitrathi1982

Hello Mauz, Thanks for your help. Now I am able to save audio and video using getScreenId.js.

I am using timeSlice option and set 20 seconds to upload data to server in chunks. Code: options.ondataavailable = function(blob) { button.blobs.push(blob); uploadBlob(blob, new Date().getTime()); };

In this case only first is opening in VLC player and subsequent files are not opening. Even first file size is around is 800KB and after that around 600 KB. Can you please guide here what I am missing.

To send file on server, code is: //ajax calling function uploadBlob(blob, fileName) { var formData = new FormData(); formData.append('video-blob', blob); formData.append('video-filename', "Demo_"+fileName+".mp4"); $.ajax({ url: "http://localhost:8080/services/recording/upload.html", type: "POST", data: formData, processData: false, contentType: false, success: function(response) { button.blobs.pop(blob); console.log("After length-"+button.blobs.length); }, error: function(jqXHR, textStatus, errorMessage) { alert('Error:' + JSON.stringify(errorMessage)); } }); }

amitrathi1982 avatar May 08 '18 11:05 amitrathi1982

@amitrathi1982 are you able to capture speakers? You may need to use CDN link or getScreenId script from this repo: https://github.com/muaz-khan/getScreenId

BTW, you need to merge all files using ffmpeg. Or maybe you can try this on nodejs server:

// i donno if this works on nodejs
var file = new Blob(arrayOfAllPieces, {
     type: 'video/webm'
});
// write file to disk using fs.write

Did you check these demos?

  • https://github.com/muaz-khan/RecordRTC/tree/master/RecordRTC-to-Nodejs
  • https://github.com/muaz-khan/RecordRTC/tree/master/PHP-and-FFmpeg

muaz-khan avatar May 08 '18 17:05 muaz-khan

Hi Mauz, Good morning! After merging, only first file (first 20 second recording) has audio and other (after 20 second) are silent.. Details are here: As I mentioned above I am using timeSlice option and set 20 seconds to upload data to server in chunks. So there is around 3 files for 1 minute recording. When I run directly only first file opened but not others. Now I merged all the recordings and after merging a single file is created and it runs successfully. But here is the issue in audio of subsequent files. After merging, only first file (first 20 second recording) has audio and other (after 20 second) are silent. Is there issue in sending recording file. I am missing something in subsequent files while sending to server?

Thanks again Mauz.

amitrathi1982 avatar May 09 '18 04:05 amitrathi1982

Hi Muaz, Sorry for wrong name in last posts

I am using time slice and every blob object as separate file. I believe that first blob object has some extra information that's why it is opening in VLC after saving and subsequent blob objects does not have that information. That's why subsequent blob objects are less in size. Am I correct? Please confirm and suggest some solution. I need your help.

Using below function: options.ondataavailable = function(blob) { button.blobs.push(blob); uploadLatestBlobToServer(blob); };

When I am uploading whole recording in single shot, then it is fine:

button.recordRTC.stopRecording(function(url) { if(button.blobs && button.blobs.length) { var blob = new File(button.blobs, getFileName(fileExtension), { type: mimeType }); //Upload this blob as last recording file when recording ends. button.recordRTC.getBlob = function() { return blob; }; uploadBlob(blob); } } });

Thanks a lot.

amitrathi1982 avatar May 10 '18 06:05 amitrathi1982

Hello Muaz, Everyone, Can you please help me in merging resulted multiple .mp4 files in to one. Right now I am using FFMPEG by below commands: Step1: Convert all files one by one in to intermediate file- 1. ffmpeg -i E:\recordings\Demo_1525840692968.mp4 -qscale:v 1 intermediate1.mpg 2. ffmpeg -i E:\recordings\Demo_1525840703000.mp4 -qscale:v 1 intermediate2.mpg 3. ffmpeg -i E:\recordings\Demo_1525840707080.mp4 -qscale:v 1 intermediate3.mpg Step 2: Merge intermediate files to one single "mpg" format file- ffmpeg -i concat:"intermediate1.mpg|intermediate2.mpg|intermediate3.mpg" -c copy intermediate_all.mpg Step 3: Convert last merged "mpg" format file to .mp4 ffmpeg -i intermediate_all.mpg -qscale:v 2 output.mp4

Can you please suggest single command to merge these or less steps. I used below command too. It show merged but when play, only first file merged and play.

Thanks, Amit

amitrathi1982 avatar May 11 '18 12:05 amitrathi1982

@amitrathi1982 Please move this thread to RecordRTC git so that I can easily track & comment:

  • https://github.com/muaz-khan/RecordRTC/issues

muaz-khan avatar May 11 '18 12:05 muaz-khan

BTW, one last comment. You can replace RecordRTC code with this lib and it will play complete recording after when it is merged:

  • https://github.com/streamproc/MediaStreamRecorder

PS. I need to test RecordRTC-timeSlice myself before making a comment about it. I'll add a similar demo to RecordRTC git as well. [timeSlice+ffmpeg]

muaz-khan avatar May 11 '18 12:05 muaz-khan

Thanks a lot Muaz. I will try it. Your views always valuable for me. Thanks once again.

amitrathi1982 avatar May 11 '18 13:05 amitrathi1982