muaz-khan / RTCMultiConnection

RTCMultiConnection is a WebRTC JavaScript library for peer-to-peer applications (screen sharing, audio/video conferencing, file sharing, media streaming etc.)
https://muazkhan.com:9001/
MIT License
2.54k stars 1.38k forks source link

How to use iOS and Android #109

Open msi008 opened 8 years ago

msi008 commented 8 years ago

hi,muaz-khan, google play shareFile app is not link,Where can I download it,i want to work on android and ios communicate

muaz-khan commented 8 years ago

Please check the documentation:

Ndess commented 8 years ago

Hi muaz khan, Very nice work!!

I tested this procedure and I have a problem to display the "video-container" with android 4.4.x and iOS, maybe I missed something.

This is the code that i use for Append the 'Video-Container" to the page

       var videosContainer = document.getElementById('videos-container');
        connection.onstream = function(event) {
            videosContainer.appendChild(event.mediaElement);
            setTimeout(function() {
                event.mediaElement.play();
            }, 5000);
        };

RTCMultiConnection v3.2.97 Results :

Here log of connection when "video-container" is not display:

info - socket.io started Server listening at 0.0.0.0:9001 debug - served static content /socket.io.js debug - client authorized info - handshake authorized YnFiLfE4ZTDL0p1QvZZM debug - setting request GET /socket.io/1/websocket/YnFiLfE4ZTDL0p1QvZZM?userid=emxdostt01kyb9&msgEvent=video-conference-demo&socketCustomEvent=RTCMultiConnection-Custom-Message debug - set heartbeat interval for client YnFiLfE4ZTDL0p1QvZZM debug - client authorized for debug - websocket writing 1:: { userid: 'emxdostt01kyb9', msgEvent: 'video-conference-demo', socketCustomEvent: 'RTCMultiConnection-Custom-Message', t: '1459428999137' } debug - sending data ack packet debug - websocket writing 6:::1+[false,"1"]

Ndess commented 8 years ago

Android 4.4 Log :

"Uncaught TypeError: Cannot call method 'getUserMedia' of undefined", source: file:///android_asset/www/js/index.js (48)
NguyenTungs commented 8 years ago

HI @muaz-khan Emulator Nexus_5X_API_22 Android 5.1.1. alt. Please help me how I can fix it? Thanks!

muaz-khan commented 8 years ago

@NguyenTungs Can you try following app on your Android and see if it works?

To test it:

  1. Open room on android
  2. Join that room here: https://rtcxp.com/fs
NguyenTungs commented 8 years ago

Hi @muaz-khan. Thank you for your answer! i test and very nice work! But In my case it seems to lack a library. Code I'm here! Please tell me where I'm wrong config. Here ios nice work. Thank you!

p/s : I look forward to your answer each day .

file index.html
<!DOCTYPE html>

<html>
    <head>

        <link rel="stylesheet" type="text/css" href="css/index.css">

        <title>Demo for Muaz-Khan</title>

    </head>

    <body>

        <section class="experiment">
            <div class="make-center">
                <input type="text" id="broadcast-id" placeholder="broadcast-id" value="sontung">
                <button id="open-or-join">Open or Join Broadcast</button>
            </div>

            <video id="video-preview" controls loop></video>
        </section>

        <script type="text/javascript" src="https://rtcmulticonnection.herokuapp.com/socket.io/socket.io.js"></script>
        <script type="text/javascript" src="cordova.js"></script>
        <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
        <script type="text/javascript" src="js/index.js"></script>

    </body>
</html>
file index.js
var app = {
    // Application Constructor
    initialize: function() {
        this.bindEvents();
    },

    // Bind Event Listeners
    //
    // Bind any events that are required on startup. Common events are:
    // 'load', 'deviceready', 'offline', and 'online'.
    bindEvents: function() {
        document.addEventListener('deviceready', function() {

          // ......................................................
          // ..................LIB RTC3 HERE.............
          // ......................................................

            // ......................................................
            // ..................RTCMultiConnection Code.............
            // ......................................................

            var enableRecordings = false;

            var connection = new RTCMultiConnection(null, {
                useDefaultDevices: true // if we don't need to force selection of specific devices
            });
            connection.userid = 'NGUYEN-TUNG';

            connection.enableScalableBroadcast = true;

            connection.maxRelayLimitPerUser = 2;

            connection.autoCloseEntireSession = true;

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

            connection.socketMessageEvent = 'scalable-media-broadcast-demo';

            connection.connectSocket(function(socket) {
                socket.on('join-broadcaster', function(hintsToJoinBroadcast) {
                    console.log('join-broadcaster====', hintsToJoinBroadcast);

                    connection.session = hintsToJoinBroadcast.typeOfStreams;
                    connection.sdpConstraints.mandatory = {
                        OfferToReceiveVideo: !!connection.session.video,
                        OfferToReceiveAudio: !!connection.session.audio
                    };

                    console.log(hintsToJoinBroadcast.userid);
                    connection.join(hintsToJoinBroadcast.userid);
                });

            });

            var broadcastId = 'sontung';

            //var demo = document.getElementById('open-or-join');
            $(document).ready(function() {
                $('#open-or-join').on('touchstart', function(e) {
                    console.log(broadcastId);
                    connection.session = {
                        audio: true,
                        video: true,
                        oneway: true
                    };

                    var socket = connection.getSocket();

                    socket.emit('check-broadcast-presence', broadcastId, function(isBroadcastExists) {
                        if (!isBroadcastExists) {
                            // the first person (i.e. real-broadcaster) MUST set his user-id
                            connection.userid = broadcastId;
                        }

                       console.log('check-broadcast-presence', broadcastId, isBroadcastExists);
                       connection.userid = 'NGUYEN-TUNG';
                       socket.emit('join-broadcast', {
                           broadcastId: broadcastId,
                           userid: connection.userid,
                           typeOfStreams: connection.session
                       });

                    });
                });
            });

            var videoPreview = document.getElementById('video-preview');

            connection.onstream = function(event) {

                if (connection.isInitiator && event.type !== 'local') {
                    return;
                }

                if (event.mediaElement) {
                    event.mediaElement.pause();
                    delete event.mediaElement;
                }

                connection.isUpperUserLeft = false;
                videoPreview.src = URL.createObjectURL(event.stream);
                videoPreview.play();

                videoPreview.userid = event.userid;

                if (event.type === 'local') {
                    videoPreview.muted = true;
                }

            }

        });

    },
    // deviceready Event Handler
    //
    // The scope of 'this' is the event. In order to call the 'receivedEvent'
    // function, we must explicitly call 'app.receivedEvent(...);'
    onDeviceReady: function() {
        app.receivedEvent('deviceready');
    },
    // Update DOM on a Received Event
    receivedEvent: function(id) {
        var parentElement = document.getElementById(id);
        var listeningElement = parentElement.querySelector('.listening');
        var receivedElement = parentElement.querySelector('.received');

        listeningElement.setAttribute('style', 'display:none;');
        receivedElement.setAttribute('style', 'display:block;');

        console.log('Received Event: ' + id);
    }
};

app.initialize();
file AndroidManifest.xml
<?xml version='1.0' encoding='utf-8'?>
<manifest android:hardwareAccelerated="true" android:versionCode="1" android:versionName="0.0.1" package="org.mobileApp" xmlns:android="http://schemas.android.com/apk/res/android">
    <supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:resizeable="true" android:smallScreens="true" android:xlargeScreens="true" />
    <uses-permission android:name="android.permission.INTERNET" />
    <application android:hardwareAccelerated="true" android:icon="@drawable/icon" android:label="@string/app_name" android:supportsRtl="true">
        <activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale" android:label="@string/activity_name" android:launchMode="singleTop" android:name="MainActivity" android:theme="@android:style/Theme.DeviceDefault.NoActionBar" android:windowSoftInputMode="adjustResize">
            <intent-filter android:label="@string/launcher_name">
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
    <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23" />
</manifest>
file config.xml
<?xml version='1.0' encoding='utf-8'?>
<widget id="org.mobileApp" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
    <name>mobileApp</name>
    <description>
        A sample Apache Cordova application that responds to the deviceready event.
    </description>
    <author email="dev@cordova.apache.org" href="http://cordova.io">
        Apache Cordova Team
    </author>
    <content src="index.html" />
    <plugin name="cordova-plugin-whitelist" spec="1" />
    <access origin="*" />
    <allow-intent href="http://*/*" />
    <allow-intent href="https://*/*" />
    <allow-intent href="tel:*" />
    <allow-intent href="sms:*" />
    <allow-intent href="mailto:*" />
    <allow-intent href="geo:*" />
    <platform name="android">
        <allow-intent href="market:*" />
    </platform>
    <platform name="ios">
        <allow-intent href="itms:*" />
        <allow-intent href="itms-apps:*" />
        <hook type="after_platform_add" src="hooks/iosrtc-swift-support.js" />
        <config-file target="*-Info.plist" parent="CFBundleURLTypes">
            <array>
                <key>NSAppTransportSecurity</key>
                <dict><key>NSAllowsArbitraryLoads</key><true/></dict>
            </array>
        </config-file>
    </platform>
    <preference name="xwalkVersion" value="16+" />
    <preference name="xwalkCommandLine" value="--disable-pull-to-refresh-effect --allow-file-access-from-files --disable-web-security" />
    <preference name="xwalkMode" value="embedded" />
    <preference name="xwalkMultipleApk" value="true" />
    <preference name="BackgroundColor" value="0xFFFF0000" />
    <preference name="xwalkUserAgent" value="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36" />
    <preference name="AndroidPersistentFileLocation" value="Internal" />
</widget>

Please tell me where I'm wrong config. Here ios nice work. Thank you!

muaz-khan commented 8 years ago

Please make sure to link script-files from local directory:

<script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript" src="js/jquery.min.js"></script>

<script type="text/javascript" src="js/socket.io.js"></script>
 <script type="text/javascript" src="js/index.js"></script>

Your config.xml file must allow requests from your domain:

<content src="index.html" />
<access origin="*" subdomains="true" uri="*" />
<allow-intent href="http://*/*" />
<allow-intent href="https://*/*" />
<allow-intent href="tel:*" />
<allow-intent href="sms:*" />
<allow-intent href="mailto:*" />
<allow-intent href="geo:*" />
<allow-navigation href="https://*/*" />

<platform name="android">
      <allow-navigation href="https://rtcmulticonnection.herokuapp.com/*" />
      <allow-intent href="https://rtcmulticonnection.herokuapp.com/*" />
      <access origin="https://rtcmulticonnection.herokuapp.com" />
</platform>

Make sure you have this plugin installed:

AndroidManifest.xml should look like this:

<?xml version='1.0' encoding='utf-8'?>
<manifest android:hardwareAccelerated="true" android:versionCode="1" android:versionName="0.0.1" package="com.yourname" xmlns:android="http://schemas.android.com/apk/res/android">
    <supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:resizeable="true" android:smallScreens="true" android:xlargeScreens="true" />
    <uses-permission android:name="android.permission.INTERNET" />
    <application android:hardwareAccelerated="true" android:icon="@drawable/icon" android:label="@string/app_name" android:supportsRtl="true">
        <activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale" android:label="@string/activity_name" android:launchMode="singleTop" android:name="MainActivity" android:theme="@android:style/Theme.DeviceDefault.NoActionBar" android:windowSoftInputMode="adjustResize">
            <intent-filter android:label="@string/launcher_name">
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
    <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.MICROPHONE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
</manifest>

Please try above codes, and if possible share errors as well.

Please add following code on TOP of your index.js file:

window.onerror = function(message, source, lineno, colno, error) {
    message += '\n';
    message += 'Line No. ' + lineno;
    message += '\n';
    message += 'Col No. ' + colno;

    if (error) {
        message += '\n';
        message += 'Error. ' + error;
    }

    if (source) {
        message += '\n';
        message += 'Source. ' + source;
    }

    if (message.indexOf('An attempt was made to use an object that is not') !== -1) {
        return;
    }

    alert(message);
};

This will help you debug & fix issues.

You can even extend above error-logs:

console.error = function() {
   window.onerror( JSON.stringify(arguments), '', 0, 0, '');
};

// as well as
console.log = console.info = console.debug = console.warn = function() {
   document.write(JSON.stringify(arguments, null, '<br>') + '<hr>');
};
NguyenTungs commented 8 years ago

Hi @muaz-khan !

The first, thank you for your answer!

Very nice work!

By the way, I asked another question. If applicable Scalable Broadcast for mobile - so we have violated the bandwidth of users?
HuuNguyen312 commented 8 years ago

HI @muaz-khan Device: Xiaomi Redmi Note 2_API_21 Android 5.0.1. capture

danishnazir commented 7 years ago

Hi i want to use my own server instead of https://rtcmulticonnection.herokuapp.com:443/. in Cordova App Currenlty my server script is

// Muaz Khan - www.MuazKhan.com // MIT License - www.WebRTC-Experiment.com/licence // Source Code - https://github.com/muaz-khan/WebRTC-Scalable-Broadcast

var isUseHTTPs = true && !(!!process.env.PORT || !!process.env.IP); var fs = require("fs"); var path = require('path');

var server = require(isUseHTTPs ? 'https' : 'http');

function serverHandler(request, response) { var uri = require('url').parse(request.url).pathname, filename = path.join(process.cwd(), uri);

var isWin = !!process.platform.match(/^win/);

if (fs.statSync(filename).isDirectory()) {
    if(!isWin) filename += '/index.html';
    else filename += '\\index.html';
}

fs.exists(filename, function (exists) {
    if (!exists) {
        response.writeHead(404, {
            "Content-Type": "text/plain"
        });
        response.write('404 Not Found: ' + filename + '\n');
        response.end();
        return;
    }

    fs.readFile(filename, 'binary', function (err, file) {
        if (err) {
            response.writeHead(500, {
                "Content-Type": "text/plain"
            });
            response.write(err + "\n");
            response.end();
            return;
        }

        response.writeHead(200);
        response.write(file, 'binary');
        response.end();
    });
});

}; var app; if (isUseHTTPs) {

var options = {
    key: fs.readFileSync(path.join(__dirname, 'fake-keys/privatekey.pem')),
    cert: fs.readFileSync(path.join(__dirname, 'fake-keys/certificate.pem'))
};
 app = server.createServer(options, serverHandler);

} else app = server.createServer(serverHandler);

app = app.listen(process.env.PORT || 8888, process.env.IP || "192.168.10.11", function() { var addr = app.address(); console.log("Server listening at", addr.address + ":" + addr.port); });

require('./WebRTC-Scalable-Broadcast.js')(app); But when i use app and click button to start stream, nothing happens even server is not receiving request