Write Screen Sharing Application for Your Own WebSite

Do you want to write multi-user screen sharing application for your own website?

Note: This tutorial uses WebRTC for multi-user screen sharing.

First step, download all codes from this directory: github/Chrome-Extensions/desktopCapture

Second step, modify manifest.json file line 17, and replace with either localhost or your real domain name:

{
    "content_scripts": [ {
       "js": [ "content-script.js" ],
       "all_frames": true,
       "run_at": "document_end",
       "matches": ["https://your-domain.com/*"]
    }]
}

Fourth step, either max a zip and deploy new chrome extension to Google App Store, or install directly using "chrome://extensions" page.


Fifth step, download ONE_to_MANY screen sharing demo from this page: RTCMultiConnection/demos/Screen-Sharing.html


Sixth step, modify a few lines in the above demo:

Search for these two lines:

<script src="/dist/RTCMultiConnection.min.js"></script>
<script src="/socket.io/socket.io.js"></script>

Replace above two lines with:

<script src="https://rtcmulticonnection.herokuapp.com//dist/RTCMultiConnection.min.js"></script>
<script src="https://rtcmulticonnection.herokuapp.com//socket.io/socket.io.js"></script>

Now search for this line:

connection.socketURL = '/';

Replace above line with:

connection.socketURL = 'https://rtcmulticonnection.herokuapp.com:443/';

Now you are done.

Seventh and the last step, upload above HTML file on any HTTPs domain.

You can try on LocalHost as well.

Non-LocalHost domains requires HTTPs.

You can upload to Google Drive, DropBox or any free hosting website that supports HTTPs e.g. appspot.com.


How to test screen sharing?

First person shares his screen and about 10 people can join/see/view his screen.

You can open unlimited parallel rooms.

Maximum number of people who can view single screen is 14. We do not support more than 14 viewers/receivers.

There is a separate demo that allows us share screen over more than 14 users: https://rtcmulticonnection.herokuapp.com/demos/Scalable-Screen-Broadcast.html

RecordRTC and Upload to PHP Server

This tutorial explains how to record videos and microphones using RecordRTC; and upload recorded data to your PHP server.

First step, write a simple RecordRTC video recording application.

Hope you didn't miss this youtube tutorial: https://www.youtube.com/watch?v=YrLzTgdJ-Kg

Here is a LIVE jsFiddle demo: https://jsfiddle.net/e32jwtn5/

Source codes for the demo:

<!DOCTYPE html>
<html>
    <head>
        <script src="https://cdn.WebRTC-Experiment.com/RecordRTC.js"></script>
    </head>

    <body>
        <video id="your-video-id" controls="" autoplay=""></video>

        <script type="text/javascript">
            // capture camera and/or microphone
            navigator.mediaDevices.getUserMedia({ video: true, audio: true }).then(function(camera) {

                // preview camera during recording
                document.getElementById('your-video-id').muted = true;
                document.getElementById('your-video-id').srcObject = camera;

                // recording configuration/hints/parameters
                var recordingHints = {
                    type: 'video'
                };

                // initiating the recorder
                var recorder = RecordRTC(camera, recordingHints);

                // starting recording here
                recorder.startRecording();

                // auto stop recording after 5 seconds
                var milliSeconds = 5 * 1000;
                setTimeout(function() {

                    // stop recording
                    recorder.stopRecording(function() {
                        
                        // get recorded blob
                        var blob = recorder.getBlob();

                        // open recorded blob in a new window
                        window.open( URL.createObjectURL(blob) );

                        // release camera
                        document.getElementById('your-video-id').srcObject = null;
                        camera.getTracks().forEach(function(track) {
                            track.stop();
                        });

                        // you can preview recorded data on this page as well
                        document.getElementById('your-video-id').src = URL.createObjectURL(blob);

                    });

                }, milliSeconds);
            });
        </script>
    </body>
</html>

Second step, write a PHP file. Lets name it "save.php".

<?php
// upload directory
$filePath = 'uploads/' . $_POST['video-filename'];

// path to ~/tmp directory
$tempName = $_FILES['video-blob']['tmp_name'];

// move file from ~/tmp to "uploads" directory
if (!move_uploaded_file($tempName, $filePath)) {
    // failure report
    echo 'Problem saving file: '.$tempName;
    die();
}

// success report
echo 'success';
?>

Third & last step, upload recorded blob to PHP.

var formData = new FormData();

// recorded data
formData.append('video-blob', recordedBlob);

// file name
formData.append('video-filename', recordedBlob.name);

// upload using jQuery
$.ajax({
    url: 'save.php', // your server URL
    data: formData,
    cache: false,
    contentType: false,
    processData: false,
    type: 'POST',
    success: function(response) {
        if (response === 'success') {
            alert('successfully uploaded recorded blob');
        } else {
            alert(response);
        }
    }
});

Here is a complete demo, uploading to PHP using jQuery:


<!DOCTYPE html>
<html>
    <head>
        <script src="https://cdn.WebRTC-Experiment.com/RecordRTC.js"></script>
        <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
        <style>
            video {
              max-width: 100%;
              border: 5px solid yellow;
              border-radius: 9px;
            }
            body {
              background: black;
            }
            h1 {
              color: yellow;
            }
        </style>
    </head>

    <body>
        <h1 id="header">RecordRTC Upload to PHP</h1>
        <video id="your-video-id" controls="" autoplay=""></video>

        <script type="text/javascript">
            // capture camera and/or microphone
            navigator.mediaDevices.getUserMedia({ video: true, audio: true }).then(function(camera) {

                // preview camera during recording
                document.getElementById('your-video-id').muted = true;
                document.getElementById('your-video-id').srcObject = camera;

                // recording configuration/hints/parameters
                var recordingHints = {
                    type: 'video'
                };

                // initiating the recorder
                var recorder = RecordRTC(camera, recordingHints);

                // starting recording here
                recorder.startRecording();

                // auto stop recording after 5 seconds
                var milliSeconds = 5 * 1000;
                setTimeout(function() {

                    // stop recording
                    recorder.stopRecording(function() {
                        
                        // get recorded blob
                        var blob = recorder.getBlob();

                        // generating a random file name
                        var fileName = getFileName('webm');

                        // we need to upload "File" --- not "Blob"
                        var fileObject = new File([blob], fileName, {
                            type: 'video/webm'
                        });

                        var formData = new FormData();

                        // recorded data
                        formData.append('video-blob', fileObject);

                        // file name
                        formData.append('video-filename', fileObject.name);

                        document.getElementById('header').innerHTML = 'Uploading to PHP using jQuery.... file size: (' +  bytesToSize(fileObject.size) + ')';

                        // upload using jQuery
                        $.ajax({
                            url: 'https://webrtcweb.com/RecordRTC/', // replace with your own server URL
                            data: formData,
                            cache: false,
                            contentType: false,
                            processData: false,
                            type: 'POST',
                            success: function(response) {
                                if (response === 'success') {
                                    alert('successfully uploaded recorded blob');

                                    // file path on server
                                    var fileDownloadURL = 'https://webrtcweb.com/RecordRTC/uploads/' + fileObject.name;

                                    // preview the uploaded file URL
                                    document.getElementById('header').innerHTML = '<a href="' + fileDownloadURL + '" target="_blank">' + fileDownloadURL + '</a>';

                                    // preview uploaded file in a VIDEO element
                                    document.getElementById('your-video-id').src = fileDownloadURL;

                                    // open uploaded file in a new tab
                                    window.open(fileDownloadURL);
                                } else {
                                    alert(response); // error/failure
                                }
                            }
                        });

                        // release camera
                        document.getElementById('your-video-id').srcObject = null;
                        camera.getTracks().forEach(function(track) {
                            track.stop();
                        });

                    });

                }, milliSeconds);
            });

            // this function is used to generate random file name
            function getFileName(fileExtension) {
                var d = new Date();
                var year = d.getUTCFullYear();
                var month = d.getUTCMonth();
                var date = d.getUTCDate();
                return 'RecordRTC-' + year + month + date + '-' + getRandomString() + '.' + fileExtension;
            }

            function getRandomString() {
                if (window.crypto && window.crypto.getRandomValues && navigator.userAgent.indexOf('Safari') === -1) {
                    var a = window.crypto.getRandomValues(new Uint32Array(3)),
                        token = '';
                    for (var i = 0, l = a.length; i < l; i++) {
                        token += a[i].toString(36);
                    }
                    return token;
                } else {
                    return (Math.random() * new Date().getTime()).toString(36).replace(/\./g, '');
                }
            }
        </script>
    </body>
</html>

Here is a demo uploading to PHP using simple JavaScript (no-jQurery):


<!DOCTYPE html>
<html>
    <head>
        <script src="https://cdn.WebRTC-Experiment.com/RecordRTC.js"></script>
        <style>
            video {
              max-width: 100%;
              border: 5px solid yellow;
              border-radius: 9px;
            }
            body {
              background: black;
            }
            h1 {
              color: yellow;
            }
        </style>
    </head>

    <body>
        <h1 id="header">RecordRTC Upload to PHP</h1>
        <video id="your-video-id" controls="" autoplay=""></video>

        <script type="text/javascript">
            // capture camera and/or microphone
            navigator.mediaDevices.getUserMedia({ video: true, audio: true }).then(function(camera) {

                // preview camera during recording
                document.getElementById('your-video-id').muted = true;
                document.getElementById('your-video-id').srcObject = camera;

                // recording configuration/hints/parameters
                var recordingHints = {
                    type: 'video'
                };

                // initiating the recorder
                var recorder = RecordRTC(camera, recordingHints);

                // starting recording here
                recorder.startRecording();

                // auto stop recording after 5 seconds
                var milliSeconds = 5 * 1000;
                setTimeout(function() {

                    // stop recording
                    recorder.stopRecording(function() {
                        
                        // get recorded blob
                        var blob = recorder.getBlob();

                        // generating a random file name
                        var fileName = getFileName('webm');

                        // we need to upload "File" --- not "Blob"
                        var fileObject = new File([blob], fileName, {
                            type: 'video/webm'
                        });

                        uploadToPHPServer(fileObject, function(response, fileDownloadURL) {
                            if(response !== 'ended') {
                                document.getElementById('header').innerHTML = response; // upload progress
                                return;
                            }

                            document.getElementById('header').innerHTML = '<a href="' + fileDownloadURL + '" target="_blank">' + fileDownloadURL + '</a>';

                            alert('Successfully uploaded recorded blob.');

                            // preview uploaded file
                            document.getElementById('your-video-id').src = fileDownloadURL;

                            // open uploaded file in a new tab
                            window.open(fileDownloadURL);
                        });

                        // release camera
                        document.getElementById('your-video-id').srcObject = null;
                        camera.getTracks().forEach(function(track) {
                            track.stop();
                        });

                    });

                }, milliSeconds);
            });

            function uploadToPHPServer(blob, callback) {
                // create FormData
                var formData = new FormData();
                formData.append('video-filename', blob.name);
                formData.append('video-blob', blob);
                callback('Uploading recorded-file to server.');
                makeXMLHttpRequest('https://webrtcweb.com/RecordRTC/', formData, function(progress) {
                    if (progress !== 'upload-ended') {
                        callback(progress);
                        return;
                    }
                    var initialURL = 'https://webrtcweb.com/RecordRTC/uploads/' + blob.name;
                    callback('ended', initialURL);
                });
            }

            function makeXMLHttpRequest(url, data, callback) {
                var request = new XMLHttpRequest();
                request.onreadystatechange = function() {
                    if (request.readyState == 4 && request.status == 200) {
                        if (request.responseText === 'success') {
                            callback('upload-ended');
                            return;
                        }
                        alert(request.responseText);
                        return;
                    }
                };
                request.upload.onloadstart = function() {
                    callback('PHP upload started...');
                };
                request.upload.onprogress = function(event) {
                    callback('PHP upload Progress ' + Math.round(event.loaded / event.total * 100) + "%");
                };
                request.upload.onload = function() {
                    callback('progress-about-to-end');
                };
                request.upload.onload = function() {
                    callback('PHP upload ended. Getting file URL.');
                };
                request.upload.onerror = function(error) {
                    callback('PHP upload failed.');
                };
                request.upload.onabort = function(error) {
                    callback('PHP upload aborted.');
                };
                request.open('POST', url);
                request.send(data);
            }

            // this function is used to generate random file name
            function getFileName(fileExtension) {
                var d = new Date();
                var year = d.getUTCFullYear();
                var month = d.getUTCMonth();
                var date = d.getUTCDate();
                return 'RecordRTC-' + year + month + date + '-' + getRandomString() + '.' + fileExtension;
            }

            function getRandomString() {
                if (window.crypto && window.crypto.getRandomValues && navigator.userAgent.indexOf('Safari') === -1) {
                    var a = window.crypto.getRandomValues(new Uint32Array(3)),
                        token = '';
                    for (var i = 0, l = a.length; i < l; i++) {
                        token += a[i].toString(36);
                    }
                    return token;
                } else {
                    return (Math.random() * new Date().getTime()).toString(36).replace(/\./g, '');
                }
            }
        </script>
    </body>
</html>

Want to use up-to-dated PHP file uploading code? Download this file:

https://github.com/muaz-khan/RecordRTC/blob/master/RecordRTC-to-PHP/save.php

Having PHP upload issues on your own server? Please check this wiki:

https://github.com/muaz-khan/RecordRTC/wiki/PHP-Upload-Issues

Hints for PHP upload issues:
  • You need to enable read-write access for "uploads" directory
  • You need to allow "save.php" file to move uploaded files from ~/tmp directory to your "./uploads" directory.
  • You need to set "post_max_size" to at least 100 MB
  • You need to set "upload_max_filesize" to at least 100 MB
  • You need to set "max_input_time" to at least 10800 (or at least 2-3 minutes)
  • For detailed information, please check the wiki page

How PHP saves the recorded blob?


First step, PHP reads "video-filename" HTTP_POST parameter. This parameter helps us set uploaded file name.

Second step, PHP checks for "video-blob" HTTP_POST (i.e. $_FILES) parameter. This parameter allows us get uploaded file data.

Third step, "video-blob" parameter has a nested "tmp_name" paremter i.e.

$tmp_name = $_FILES['video-blob']['tmp_name'];

"tmp_name" parameter helps us locate the uploaded file on ~/tmp directory.

Which means that file is already uploaded to ~/tmp directory. We simply need to move file from ~/tmp to our custom location.

That's why we use "move_upload_file" method.

Fourth and last step, use "move_upload_file" method to move uploaded file from ~/tmp to "./uploads" directory.

"move_upload_file" takes two parameters. First parameter is ~/tmp/fileName.webm and second parameter is "./uploads/fileName.webm".

This method fails in following cases:

  • File was not uploaded to ~/tmp directory; reason: max_upload_filesize or upload_timeout issues.
  • "./uploads" directory doesn't allows "save.php" file to move file. i.e. you did not set read-write privileges for "./uploads" directory.

Here is how to set read-write privileges for "./uploads" directory (using PHP):

<?php
// Read and write for owner, nothing for everybody else
chmod("./uploads", 0600);

// Read and write for owner, read for everybody else
chmod("./uploads", 0644);

// Everything for owner, read and execute for others
chmod("./uploads", 0755);

// Everything for owner, read and execute for owner's group
chmod("./uploads", 0750);
?>

However BASH based privileges are preferred/recommended:

[sudo] chmod 755 ./uploads
[sudo] chown -R www-data:www-data ./uploads

You can use "apache:apache" if "www-data:www-data" doesn't works above.

Searching for RecordRTC simple demos? Please check this directory:

https://github.com/muaz-khan/RecordRTC/tree/master/simple-demos

Have issues/bugs/questions, please report here: https://github.com/muaz-khan/RecordRTC/issues/new

Take photo from a webcam using JavaScript

Do you want to capture photos from your web-camera and generate images in any supported format e.g. PNG, JPEG, GIF, WebP etc.?

First method, capture photo using Canvas2D API:

Live demo: https://www.webrtc-experiment.com/takePhoto/

Below example captures photo from an HTML5 Video element:

var yourVideoElement = document.querySelector('video');

// pass your HTML5 Video Element
var photo = takePhoto(yourVideoElement);
window.open(photo);

function takePhoto(video) {
    var canvas = document.createElement('canvas');
    canvas.width = video.videoWidth || video.clientWidth;
    canvas.height = video.videoHeight || video.clientHeight;

    var context = canvas.getContext('2d');
    context.drawImage(video, 0, 0, canvas.width, canvas.height);

    return canvas.toDataURL('image/png');
}

Above code returns PNG. Here is how to get different formats:

var PNG = canvas.toDataURL('image/png');
var JPEG = canvas.toDataURL('image/jpeg');
var GIF = canvas.toDataURL('image/gif');
var WebP = canvas.toDataURL('image/webp', 1);


Second method, capture photo using "ImageCapture" API:

Live Demo: https://www.webrtc-experiment.com/ImageCapture/

You need to pass MediaStreamTrack (aka Video-Track) object:

if (typeof ImageCapture === 'function') {
    var firstVideoTrack = yourCameraStream.getVideoTracks()[0];
    var imageCapture = new ImageCapture(firstVideoTrack);
    imageCapture.takePhoto().then(function(blob) {
        var photo = URL.createObjectURL(blob);
        window.open(photo);
    });
}

Note: ImageCapture API requires Chrome version >= 60.

WebRTC captureStream API

You can use "captureStream" method to generate a realtime media stream from any HTML5 video or canvas-2d element.
var realtimeStream = canvasElement.captureStream(15);

Using captureStream API:

  • You can record WebGL based 3D games; you can also share in realtime with many users using RTCPeerConnection API
  • You can record canvas-2D animation or drawings; you can share in realtime as well using same RTCPeerConnection API
  • You can share your local video files e.g. WebM, Mp4, FLV, TS-M3U8 (hls-live-streaming) or audio files e.g. Wav, Ogg, Mp3 etc. You can record specific portions of these files as well.

How to record WebGL or Canvas2D animations?

You can use RecordRTC to record canvas-2D or 3D animations. You can try a few demos here:
First step, generate a realtime stream from HTML5 canvas element:
var realtimeStream = canvasElement.captureStream(15);
The parameter "15" is named as "frame-rates". We requested 15 fps stream.

Second step, record the resulting stream using RecordRTC or MediaStreamRecorder API:
var realtimeStream = canvasElement.captureStream();

var parameters = {
    mimeType: 'video/webm'
};

var recorder = RecordRTC(realtimeStream, parameters);

recorder.setRecordingDuration(5 * 1000).onRecordingStopped(function() {
    var recordedVideo = recorder.getBlob();
    var file = new File([recordedVideo], 'filename.webm', {
        type: 'video/webm'
    });
    var fileURL = URL.createObjectURL(file);
    window.open(fileURL);
});

recorder.startRecording();
Third and last step, repeatedly draw shapes or animations on canvas 2d surface:
var context = canvasElement.getContext('2d');

(function looper() {
    context.clearRect(0, 0, canvasElement.width, canvasElement.height);
    context.drawImage(video, 0, 0, canvasElement.width, canvasElement.height);

    // draw shapes every 10 milliseconds
    setTimeout(looper, 10);
})();

How to broadcast/share WebGL or Canvas2D animations with other users?

You can "[RTCPeerConnection] addStream" method to share (broadcast) canvas-2D or 3D animations with remote users. You can try this demo:
First step, generate a realtime stream from HTML5 canvas element:
var realtimeStream = canvasElement.captureStream(15);
Second and last step, share with remote users using RTCPeerConnection API:
var peer = new webkitRTCPeerConnection(parameters);

// check this line
peer.addStream(canvasStream);

// now either create offer or answer descriptions
peer.createOffer(successCallback, failureCallback, parameters);

How to share or record microphone audio along with Canvas2D animations?

It is simple: use "addTrack" method to merge tracks.
var microphoneStream = captureUsingNavigatorDotGetUserMediaAPI({
    audio: true
});

// merge audio tracks into canvas stream
microphoneStream.getAudioTracks().forEach(function(track) {
    // check this line
    canvasStream.addTrack(track);
});

// now either record "canvasStream" or share using RTCPeerConnection API
peer.addStream(canvasStream); // microphone+canvas2D

Can I capture stream from an <audio> element?

Simply yes. You can capture audio either from <audio> tag or otherwise <video> element.

Remember: <video> tag also accepts audio-only stream. Your stream do NOT need to have video tracks. Here is how to capture audio stream from a <video> element:
videoElement.src = URL.createObjectURL(microphoneStream);

// capture from <video> tag
var capturedStream = videoElement.captureStream();

// initiate a standalone instance
var audioOnlyStream = new webkitMediaStream();

// merge only audio tracks
capturedStream.getAudioTracks().forEach(function(track) {
    audioOnlyStream.addTrack(track);
});

// either record "audioOnlyStream" or share using RTCPeerConnection API
peer.addStream(audioOnlyStream);

Unable to use "captureStream" API?

You may need to enable following chrome-flag; then relaunch the chrome browser:
chrome://flags/#enable-experimental-web-platform-features

References: