diff --git a/bower.json b/bower.json index 2bdd57ce5..58a55e943 100644 --- a/bower.json +++ b/bower.json @@ -1,7 +1,7 @@ { "name": "skylinkjs", "description": "WebRTC real-time video conversation library", - "version": "0.6.0", + "version": "0.6.3", "homepage": "https://temasys.github.io/", "author": { "name": "Temasys Communications Pte. Ltd.", diff --git a/demo/README.md b/demo/README.md index 163ee87ec..088fb32a2 100644 --- a/demo/README.md +++ b/demo/README.md @@ -98,7 +98,6 @@ In this demo, you can find an example of the overview of all types of stream set ##### Events used `peerJoined`, `peerLeft`, `incomingStream`, `mediaAccessSuccess`, `incomingMessage` - ### demo/video-call In this demo, you can find an example of how you can create a simple video call with Skylink. @@ -106,4 +105,16 @@ In this demo, you can find an example of how you can create a simple video call `init()`, `joinRoom()`, `on()`, `getPeerInfo()` ##### Events used -`mediaAccessSuccess`, `incomingStream`, `streamEnded`, `peerLeft` \ No newline at end of file +`mediaAccessSuccess`, `incomingStream`, `streamEnded`, `peerLeft` + +### demo/privileged +In this demo, you can find an example of how to utilize the privileged key concept for different types of clients. + +##### Functionalities covered +`getPeers()`, `introducePeer()` + +##### Events used +`getPeersStateChange`, `introduceStateChange` + +##### How to use +First, open the index page of the privileged demo. Each button there when being clicked will open another browser tab for the corresponding type of user, with corresponding functionalities available. For example privileged users have getPeers() and introduce() options while the rest do not. To introduce two peers, enter the peer ID of each peer to the textbox then hit "Introduce". \ No newline at end of file diff --git a/demo/app/js/main.js b/demo/app/js/main.js index ea0dd44b1..de5498f33 100644 --- a/demo/app/js/main.js +++ b/demo/app/js/main.js @@ -13,7 +13,7 @@ var _peerId = null; var selectedPeers = []; -//Demo.Skylink.setLogLevel(4); +Demo.Skylink.setLogLevel(4); Demo.Methods.displayFileItemHTML = function (content) { @@ -468,12 +468,7 @@ Demo.Skylink.init(config, function (error, success) { Demo.Skylink.joinRoom({ userData: displayName, audio: { stereo: true }, - video: { - resolution: { - width: 1280, - height: 720 - } - } + video: true }); } }); diff --git a/demo/index.html b/demo/index.html index 7ea1a54f2..223f0c151 100644 --- a/demo/index.html +++ b/demo/index.html @@ -284,12 +284,41 @@

Gridster Webrtc

- View Demo + View Demo

- +
+
+

Privileged use case

+
+
+

+ This demo presents the use of privileged concept +

+
+ +
+
Difficulty
+
+
+ Hard +
+
+
+ +

+ View Demo +

+
+
diff --git a/demo/privileged/auto-priv/css/favicon.ico b/demo/privileged/auto-priv/css/favicon.ico new file mode 100644 index 000000000..96865c994 Binary files /dev/null and b/demo/privileged/auto-priv/css/favicon.ico differ diff --git a/demo/privileged/auto-priv/css/style.css b/demo/privileged/auto-priv/css/style.css new file mode 100644 index 000000000..e9ad46a6c --- /dev/null +++ b/demo/privileged/auto-priv/css/style.css @@ -0,0 +1,136 @@ +.navbar-white { + background:#fff; +} +#get_user_media_btn, +#join_room_btn, +#leave_room_btn, +#presence_panel, +#file_panel, +#file_list_panel { + display:none; +} +.circle { + color:red; + border:solid 1px; + border-radius:50%; + padding:5px; + margin-bottom:7px; + font-size:10px; +} +.table { + font-size:12px; + word-break:break-word; +} +.table td:first-child { + font-weight:bold; + width:38%; +} +.table.upload-table td:first-child { + font-weight:normal; + width:85%; +} +#credential_panel { + margin-bottom:0; + border-left:0; + border-right:0; + box-shadow:none; + border-radius:0; +} +#credential_panel .panel-body { + padding-bottom:0; +} +#credential_panel .panel-body .form-group { + text-align:left; +} +#credential_panel .panel-body .form-group .title, +#credential_panel .panel-body .form-group .control-group { + display:inline-block; + vertical-align:top; +} +#credential_panel .panel-body .form-group .title { + margin-top:0; + float:left; +} +#credential_panel .panel-body .form-group .title span { + display:block; + margin-bottom:5px; +} +#credential_panel .panel-body .form-group .control-group { +} +video, object { + background:#444; + border:solid 2px #fff; + padding:0!important; +} +video#local_video, +object#local_video { + right:15px; + position:absolute; + z-index:9999; +} +#file_body { + max-height:200px; + overflow-y:auto; +} +#chat_panel { + margin:15px 0 45px; +} +#chat_body { + max-height:200px; + overflow-y:auto; +} +.list-group-item-heading em { + float:right; + font-style:normal; + color:#888; +} +.chat-item { + border:0; + padding:0 0 15px 0; +} +.chat-item img { + width: 250px; +} +#chat_input { + display:block; + width:100%; +} +.control_settings .col { + margin: 7px 0; +} +#leave_room_btn { + margin-left:12px; +} +.control_settings .btn-group { + width: 100%; +} +footer { + background:#f5f5f5; + padding:12px 0 0; + border-top:solid 1px #e0e0e0; +} +.selected-users em { + font-style: normal; + font-size: 12px; + margin-right: 12px; +} +@media screen and (max-width:1999px){ + #credential_panel .panel-body { + margin-bottom:15px; + } + #credential_panel .panel-body button { + margin-left:14px; + } +} +@media screen and (max-width:991px){ + video, object { + display:block; + width:100%; + } + video#local_video, + object#local_video { + right:0; + position:static; + display:block + } +} \ No newline at end of file diff --git a/demo/privileged/auto-priv/img/default.png b/demo/privileged/auto-priv/img/default.png new file mode 100644 index 000000000..d99a885dc Binary files /dev/null and b/demo/privileged/auto-priv/img/default.png differ diff --git a/demo/privileged/auto-priv/img/no_profile.jpg b/demo/privileged/auto-priv/img/no_profile.jpg new file mode 100644 index 000000000..a4982376f Binary files /dev/null and b/demo/privileged/auto-priv/img/no_profile.jpg differ diff --git a/demo/privileged/auto-priv/index.html b/demo/privileged/auto-priv/index.html new file mode 100644 index 000000000..6d0751b7f --- /dev/null +++ b/demo/privileged/auto-priv/index.html @@ -0,0 +1,237 @@ + + + + Temasys: My Room Example + + + + + + + + + + +
+ +
+ +
+
+
+
+
+
Connection Information
+
+ + + + + + + + + + + + + + + + + + + + + + + +
App ID
User IDNot in Room
Channel status-
Room Lock Status-
Media stream status + + +
+
+
+
+
Connected Peers
+
+ + +
+
+
+
+
File Transfers
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + + + +
+
+
+
+
Targeted peers to message / file transfer to
+

Peers: All

+

+
+
+
+
+ + + + +
+
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+

+ © Temasys Communications Pte Ltd 2014. All Rights Reserved. +

+
+
+ + + + + diff --git a/demo/privileged/auto-priv/js/main.js b/demo/privileged/auto-priv/js/main.js new file mode 100644 index 000000000..283f8d535 --- /dev/null +++ b/demo/privileged/auto-priv/js/main.js @@ -0,0 +1,700 @@ +/******************************************************** + API Settings +*********************************************************/ +var Demo = Demo || {}; +Demo.FILE_SIZE_LIMIT = 1024 * 1024 * 200; +Demo.Peers = 0; +Demo.Files = []; +Demo.Streams = []; +Demo.Methods = {}; +Demo.Skylink = new Skylink(); + +var _peerId = null; + +var selectedPeers = []; + +//Demo.Skylink.setLogLevel(4); + + +Demo.Methods.displayFileItemHTML = function (content) { + return '

' + content.name + '' + content.size + ' B

' + + ((content.isUpload) ? ('' + + '' + + '
' + + ' Upload Status
') : ('
' + + '
Downloading...
')) + + '

Download file

'; +}; + +Demo.Methods.displayChatItemHTML = function (peerId, timestamp, content, isPrivate) { + var Hours, Minutes, Seconds; + if (timestamp.getHours() < 10) + Hours = '0' + timestamp.getHours(); + else + Hours = timestamp.getHours(); + if (timestamp.getMinutes() < 10) + Minutes = '0' + timestamp.getMinutes(); + else + Minutes = timestamp.getMinutes(); + if (timestamp.getSeconds() < 10) + Seconds = '0' + timestamp.getSeconds(); + else + Seconds = timestamp.getSeconds(); + + return '
' + + '

' + '' + peerId + '' + + '' + Hours + + ':' + Minutes + ':' + Seconds + + '

' + '

' + + (isPrivate ? '[pvt msg] ' : '') + content + + (isPrivate ? '' : '') + '

'; +}; + +Demo.Methods.displayChatMessage = function (peerId, content, isPrivate) { + var timestamp = new Date(); + var isFile = typeof content === 'object'; + + //console.info(isFile); + var element = (isFile) ? '#file_log' : '#chat_log'; + var element_body = (isFile) ? '#file_body' : '#chat_body'; + if (isFile) { + content = Demo.Methods.displayFileItemHTML(content); + } + + $(element).append(Demo.Methods.displayChatItemHTML(peerId, timestamp, content, isPrivate)); + $(element_body).animate({ + scrollTop: $('#chat_body').get(0).scrollHeight + }, 500); +}; + +/******************************************************** + Skylink Events +*********************************************************/ +//--------------------------------------------------- +Demo.Skylink.on('incomingData', function (data, transferId, peerId, transferInfo, isSelf) { + if (transferInfo.dataType !== 'blob') { + console.info('incomingData', data, transferId, peerId, transferInfo, isSelf); + //displayChatItemHTML = function (peerId, timestamp, content, isPrivate) + Demo.Methods.displayChatMessage(peerId, '', false); + } +}); +Demo.Skylink.on('incomingDataRequest', function (transferId, peerId, transferInfo, isSelf) { + if (!isSelf && transferInfo.dataType !== 'blob') { + Demo.Skylink.respondBlobRequest(peerId, transferId, true); + } +}) +Demo.Skylink.on('dataTransferState', function (state, transferId, peerId, transferInfo, error){ + transferInfo = transferInfo || {}; + + if (transferInfo.dataType !== 'blob') { + return; + } + + switch (state) { + case Demo.Skylink.DATA_TRANSFER_STATE.UPLOAD_REQUEST : + var result = confirm('Accept file "' + transferInfo.name + + '" from ' + peerId + '?\n\n[size: ' + transferInfo.size + ']'); + Demo.Skylink.respondBlobRequest(peerId, transferId, result); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.UPLOAD_STARTED : + var displayName = Demo.Skylink.getUserData(); + transferInfo.transferId = transferId; + transferInfo.isUpload = true; + transferInfo.data = URL.createObjectURL(transferInfo.data); + Demo.Methods.displayChatMessage(displayName, transferInfo); + Demo.Methods.displayChatMessage(displayName, 'File sent: ' + transferInfo.name); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.DOWNLOAD_STARTED : + var displayName = Demo.Skylink.getPeerInfo(transferInfo.senderPeerId).userData; + transferInfo.transferId = transferId; + transferInfo.data = '#'; + transferInfo.isUpload = false; + Demo.Methods.displayChatMessage(displayName, transferInfo); + Demo.Methods.displayChatMessage(displayName, 'File sent: ' + transferInfo.name); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.UPLOADING : + var displayName = Demo.Skylink.getPeerInfo(peerId).userData; + if ($('#' + transferId).find('.' + peerId).width() < 1) { + $('#' + transferId).append('' + displayName + + '' + transferInfo.percentage + '%'); + } else { + $('#' + transferId).find('.' + peerId).html(transferInfo.percentage + '%'); + } + break; + case Demo.Skylink.DATA_TRANSFER_STATE.DOWNLOADING : + $('#' + transferId).attr('aria-valuenow', transferInfo.percentage); + $('#' + transferId).css('width', transferInfo.percentage + '%'); + $('#' + transferId).find('span').html(transferInfo.percentage + ' %'); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.UPLOAD_COMPLETED : + var displayName = Demo.Skylink.getPeerInfo(peerId).userData; + Demo.Methods.displayChatMessage(displayName, 'File received: ' + transferInfo.name); + $('#' + transferId).find('.' + peerId).html('✓'); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.DOWNLOAD_COMPLETED : + // If completed, display download button + var displayName = Demo.Skylink.getPeerInfo(peerId).userData; + $('#' + transferId).parent().remove(); + $('#' + transferId + '_btn').attr('href', URL.createObjectURL(transferInfo.data)); + $('#' + transferId + '_btn').css('display', 'block'); + Demo.Methods.displayChatMessage(displayName, 'File received: ' + transferInfo.name); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.REJECTED : + alert('User "' + peerId + '" has rejected your file'); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.ERROR : + alert(error.transferType + ' failed. Reason: \n' + + error.message); + $('#' + transferId).parent().removeClass('progress-bar-info'); + $('#' + transferId).parent().addClass('progress-bar-danger'); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.CANCEL : + alert(error.transferType + ' canceled. Reason: \n' + + error.message); + $('#' + transferId).parent().removeClass('progress-bar-info'); + $('#' + transferId).parent().addClass('progress-bar-danger'); + } +}); +//--------------------------------------------------- +Demo.Skylink.on('incomingMessage', function (message, peerId, peerInfo, isSelf) { + Demo.Methods.displayChatMessage((isSelf) ? 'You' : peerInfo.userData, + ((message.isDataChannel) ? 'P2P' : 'Socket') + ' -> ' + message.targetPeerId + ': ' + + message.content, message.isPrivate); +}); +//--------------------------------------------------- +Demo.Skylink.on('peerRestart', function (peerId, peerInfo, isSelf){ + if (!isSelf) { + $('#user' + peerId + ' .video').css('color', + (peerInfo.mediaStatus.videoMuted) ? 'red' : 'green'); + $('#user' + peerId + ' .audio').css('color', + (peerInfo.mediaStatus.audioMuted) ? 'red' : 'green'); + $('#user' + peerId + ' .name').html(peerInfo.userData); + } +}); +//--------------------------------------------------- +Demo.Skylink.on('peerJoined', function (peerId, peerInfo, isSelf){ + if (isSelf) { + $('#display_user_id').html(peerId); + $('#isAudioMuted').css('color', + (peerInfo.mediaStatus.audioMuted) ? 'red' : 'green'); + $('#isVideoMuted').css('color', + (peerInfo.mediaStatus.videoMuted) ? 'red' : 'green'); + $('#leave_room_btn').show(); + $('#presence_panel').show(); + $('#chat_input').removeAttr('disabled'); + // If not supportive of File, FileReader, Blob quit + if (window.File && window.FileReader && window.FileList && window.Blob) { + $('#file_panel').show(); + $('#file_list_panel').show(); + } + } else { + _peerId = peerId; + Demo.Methods.displayChatMessage('System', 'Peer ' + peerId + ' joined the room'); + var newListEntry = '' + + '' + peerInfo.userData + '
' + + ''; + var titleList = [ + 'Joined Room', 'Handshake: Welcome', 'Handshake: Offer', + 'Handshake: Answer', 'Candidate Generation state', 'ICE Connection state', + 'Peer Connection state', 'Data Channel Connection state', + 'MediaStream: Video', 'MediaStream: Audio' + ]; + var glyphiconList = [ + 'glyphicon-log-in', 'glyphicon-hand-right', 'glyphicon-hand-left', + 'glyphicon-thumbs-up', 'glyphicon-flash', 'glyphicon-magnet', + 'glyphicon-user', 'glyphicon-transfer', 'glyphicon-facetime-video video', + 'glyphicon-volume-up audio' + ]; + for( var i = 0; i < 10; i++) { + newListEntry += '   '; + } + newListEntry += ''; + $('#presence_list').append(newListEntry); + $('#user' + peerId + ' .0').css('color','green'); + $('#user' + peerId + ' .video').css('color', + (peerInfo.mediaStatus.videoMuted) ? 'red' : 'green'); + $('#user' + peerId + ' .audio').css('color', + (peerInfo.mediaStatus.audioMuted) ? 'red' : 'green'); + } +}); +//--------------------------------------------------- +Demo.Skylink.on('incomingStream', function (peerId, stream, isSelf, peerInfo){ + if (!isSelf) { + Demo.Peers += 1; + } + var peerVideo; + + if ($('#video' + peerId).length === 0) { + peerVideo = document.createElement('video'); + peerVideo.id = 'video' + peerId; + peerVideo.className = 'col-md-6'; + if (window.webrtcDetectedBrowser !== 'IE') { + peerVideo.autoplay = 'autoplay'; + } + + // mutes user's video + if (isSelf && window.webrtcDetectedBrowser !== 'IE') { + peerVideo.muted = 'muted'; + } + $('#peer_video_list').append(peerVideo); + } else { + peerVideo = document.getElementById('video' + peerId); + } + + attachMediaStream(peerVideo, stream); + Demo.Streams[peerId] = Demo.Streams[peerId] || {}; + Demo.Streams[peerId][stream.id] = peerVideo.src; +}); +//--------------------------------------------------- +Demo.Skylink.on('mediaAccessSuccess', function (stream){ + Demo.Methods.displayChatMessage('System', 'Audio and video access is allowed.'); +}); +//--------------------------------------------------- +Demo.Skylink.on('mediaAccessError', function (error){ + alert((typeof error === 'object') ? error.message : error); + Demo.Methods.displayChatMessage('System', 'Failed to join room as video and audio stream is required.'); +}); +//--------------------------------------------------- +Demo.Skylink.on('readyStateChange', function (state, error){ + if (state === Demo.Skylink.READY_STATE_CHANGE.ERROR) { + for (var errorCode in Demo.Skylink.READY_STATE_CHANGE_ERROR) { + if (Demo.Skylink.READY_STATE_CHANGE_ERROR[errorCode] === + error.errorCode) { + alert('An error occurred parsing and retrieving server code.\n' + + 'Error was: ' + errorCode); + break; + } + } + } + $('#channel_status').show(); +}); +//--------------------------------------------------- +Demo.Skylink.on('peerLeft', function (peerId, peerInfo, isSelf){ + //console.info('peerLeft', peerId, peerInfo, isSelf); + Demo.Methods.displayChatMessage('System', 'Peer ' + peerId + ' has left the room'); + Demo.Peers -= 1; + $('#video' + peerId).remove(); + $('#user' + peerId).remove(); + delete Demo.Streams[peerId]; + var index = selectedPeers.indexOf(peerId); + + if (index > -1) { + selectedPeers.splice(index, 1); + } +}); +//--------------------------------------------------- +Demo.Skylink.on('handshakeProgress', function (state, peerId) { + var stage = 0; + switch( state ){ + case Demo.Skylink.HANDSHAKE_PROGRESS.WELCOME: + stage = 1; + break; + case Demo.Skylink.HANDSHAKE_PROGRESS.OFFER: + stage = 2; + break; + case Demo.Skylink.HANDSHAKE_PROGRESS.ANSWER: + stage = 3; + break; + } + for (var i=0; i<=stage; i++) { + $('#user' + peerId + ' .' + i ).css('color', 'green'); + } +}); +//--------------------------------------------------- +Demo.Skylink.on('candidateGenerationState', function (state, peerId) { + var color = 'orange'; + switch( state ){ + case Demo.Skylink.CANDIDATE_GENERATION_STATE.COMPLETED: + color = 'green'; break; + } + $('#user' + peerId + ' .4' ).css('color', color); +}); +//--------------------------------------------------- +Demo.Skylink.on('iceConnectionState', function (state, peerId) { + var color = 'orange'; + switch(state){ + case Demo.Skylink.ICE_CONNECTION_STATE.STARTING: + case Demo.Skylink.ICE_CONNECTION_STATE.CLOSED: + case Demo.Skylink.ICE_CONNECTION_STATE.FAILED: + color = 'red'; + break; + case Demo.Skylink.ICE_CONNECTION_STATE.CHECKING: + case Demo.Skylink.ICE_CONNECTION_STATE.DISCONNECTED: + color = 'orange'; + break; + case Demo.Skylink.ICE_CONNECTION_STATE.CONNECTED: + case Demo.Skylink.ICE_CONNECTION_STATE.COMPLETED: + color = 'green'; + break; + default: + console.error('ICE State:', state, peerId); + } + $('#user' + peerId + ' .5' ).css('color', color); + + if (state === Demo.Skylink.ICE_CONNECTION_STATE.CHECKING){ + setTimeout(function(){ + if ($('#user' + peerId + ' .5' ).css('color') === 'orange') { + $('#user' + peerId).remove(); + } + }, 30000); + } +}); +//--------------------------------------------------- +Demo.Skylink.on('peerConnectionState', function (state, peerId) { + var color = 'red'; + switch(state){ + case Demo.Skylink.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER: + case Demo.Skylink.PEER_CONNECTION_STATE.HAVE_REMOTE_PRANSWER: + case Demo.Skylink.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER: + case Demo.Skylink.PEER_CONNECTION_STATE.HAVE_LOCAL_PRANSWER: + color = 'orange'; + break; + case Demo.Skylink.PEER_CONNECTION_STATE.CLOSED: + color = 'red'; + break; + case Demo.Skylink.PEER_CONNECTION_STATE.STABLE: + color = 'green'; + break; + } + $('#user' + peerId + ' .6' ).css('color', color); +}); +//--------------------------------------------------- +Demo.Skylink.on('dataChannelState', function (state, peerId) { + var color = 'red'; + switch (state) { + case Demo.Skylink.DATA_CHANNEL_STATE.ERROR: + color = 'red'; + break; + case Demo.Skylink.DATA_CHANNEL_STATE.CONNECTING: + color = 'orange'; + break; + case Demo.Skylink.DATA_CHANNEL_STATE.OPEN: + color = 'green'; + break; + } + $('#user' + peerId + ' .7' ).css('color', color); +}); +//--------------------------------------------------- +Demo.Skylink.on('peerUpdated', function (peerId, peerInfo, isSelf) { + if (isSelf) { + $('#isAudioMuted').css('color', + (peerInfo.mediaStatus.audioMuted) ? 'red' : 'green'); + $('#isVideoMuted').css('color', + (peerInfo.mediaStatus.videoMuted) ? 'red' : 'green'); + } else { + $('#user' + peerId + ' .video').css('color', + (peerInfo.mediaStatus.videoMuted) ? 'red' : 'green'); + $('#user' + peerId + ' .audio').css('color', + (peerInfo.mediaStatus.audioMuted) ? 'red' : 'green'); + $('#user' + peerId + ' .name').html(peerInfo.userData); + } + + if ($('#video' + peerId).find('video').length > 0) { + if (peerInfo.mediaStatus.videoMuted) { + $('#video' + peerId)[0].src = ''; + } else { + $('#video' + peerId)[0].src = Demo.Streams[peerId]; + } + } +}); +//--------------------------------------------------- +Demo.Skylink.on('roomLock', function (isLocked, peerId, peerInfo, isSelf) { + $('#display_room_status').html((isLocked) ? 'Locked' : 'Not Locked'); +}); +//--------------------------------------------------- +Demo.Skylink.on('channelOpen', function () { + $('#channel').css('color','green'); + $('#channel').html('Active'); +}); +//--------------------------------------------------- +Demo.Skylink.on('channelClose', function () { + $('#leave_room_btn').hide(); + $('#channel').css('color','red'); + $('#channel').html('Closed'); +}); +//--------------------------------------------------- +Demo.Skylink.on('channelMessage', function (){ + $('#channel').css('color','00FF00'); + $('#channel').html('Connecting...'); + setTimeout(function () { + $('#channel').css('color','green'); + $('#channel').html('Active'); + }, 1000); +}); +//--------------------------------------------------- +Demo.Skylink.on('channelError', function (error) { + Demo.Methods.displayChatMessage('System', 'Channel Error:
' + (error.message || error)); +}); +//--------------------------------------------------- +Demo.Skylink.on('mediaAccessError', function (error) { + alert((error.message || error)); +}); + +Demo.Skylink.on('serverPeerJoined', function (serverPeerId, serverPeerType) { + console.info('serverPeerJoined', serverPeerId, serverPeerType); +}); + +Demo.Skylink.on('serverPeerLeft', function (serverPeerId, serverPeerType) { + console.info('serverPeerLeft', serverPeerId, serverPeerType); +}); + +Demo.Skylink.on('peerJoined', function (peerId, peerInfo, isSelf) { + console.info('peerJoined', peerId, peerInfo, isSelf); +}); + +Demo.Skylink.on('peerLeft', function (peerId, peerInfo, isSelf) { + console.info('peerLeft', peerId, peerInfo, isSelf); +}); + +Demo.Skylink.on('peerRestart', function (peerId, peerInfo, isSelf) { + console.info('peerRestart', peerId, peerInfo, isSelf); +}); + +Demo.Skylink.on('serverPeerRestart', function (serverPeerId, serverPeerType) { + console.info('serverPeerRestart', serverPeerId, serverPeerType); +}); + +//------------- join room --------------------------- +var displayName = 'name_' + 'user_' + Math.floor((Math.random() * 1000) + 1); + +Demo.Skylink.init(config, function (error, success) { + if (success) { + Demo.Skylink.joinRoom({ + userData: displayName, + audio: { stereo: true }, + video: { + resolution: { + width: 1280, + height: 720 + } + } + }); + } +}); + +/******************************************************** + DOM Events +*********************************************************/ +$(document).ready(function () { + //--------------------------------------------------- + $('#display_app_id').html(config.apiKey); + //--------------------------------------------------- + $('#chat_input').keyup(function(e) { + e.preventDefault(); + if (e.keyCode === 13) { + if ($('#send_data_channel').prop('checked')) { + if (selectedPeers.length > 0) { + Demo.Skylink.sendP2PMessage($('#chat_input').val(), selectedPeers); + } else { + Demo.Skylink.sendP2PMessage($('#chat_input').val()); + } + } else { + if (selectedPeers.length > 0) { + Demo.Skylink.sendMessage($('#chat_input').val(), selectedPeers); + } else { + Demo.Skylink.sendMessage($('#chat_input').val()); + } + } + $('#chat_input').val(''); + } + }); + //--------------------------------------------------- + $('#file_input').change(function() { + Demo.Files = $(this)[0].files; + }); + //--------------------------------------------------- + $('#dataURL_input').change(function() { + Demo.DataURL = $(this)[0].files; + }); + //--------------------------------------------------- + $('#send_file_btn').click(function() { + if(!Demo.Files) { + alert('No files selected'); + return; + } else { + if(Demo.Files.length > 0) { + $(Demo.Files)[0].disabled = true; + console.log('Button temporarily disabled to prevent crash'); + } + } + for(var i=0; i < Demo.Files.length; i++) { + var file = Demo.Files[i]; + if(file.size <= Demo.FILE_SIZE_LIMIT) { + if (selectedPeers.length > 0) { + Demo.Skylink.sendBlobData(file, selectedPeers); + } else { + Demo.Skylink.sendBlobData(file); + } + $('#file_input').val(''); + } else { + alert('File "' + file.name + '"" exceeded the limit of 200MB.\n' + + 'We only currently support files up to 200MB for this demo.'); + } + } + $('#send_file_btn')[0].disabled = false; + }); + //--------------------------------------------------- + $('#send_dataURL_btn').click(function() { + if(!Demo.DataURL) { + alert('No files selected'); + return; + } else { + if(Demo.Files.length > 0) { + $(Demo.Files)[0].disabled = true; + console.log('Button temporarily disabled to prevent crash'); + } + } + + for(var i=0; i < Demo.DataURL.length; i++) { + var file = Demo.DataURL[i]; + + var fr = new FileReader(); + + fr.onload = function () { + if(file.size <= 1024 * 1024 * 2) { + if (selectedPeers.length > 0) { + Demo.Skylink.sendURLData(fr.result, selectedPeers); + } else { + Demo.Skylink.sendURLData(fr.result); + } + $('#dataURL_input').val(''); + } else { + alert('File "' + file.name + '"" exceeded the limit of 2MB.\n' + + 'We only currently support files up to 2MB for this demo.'); + } + }; + + fr.readAsDataURL(file); + } + $('#send_dataURL_btn')[0].disabled = false; + }); + //--------------------------------------------------- + $('#update_user_info_btn').click(function () { + Demo.Skylink.setUserData($('#display_user_info').val()); + }); + //--------------------------------------------------- + $('#lock_btn').click(function () { + Demo.Skylink.lockRoom(); + }); + //--------------------------------------------------- + $('#unlock_btn').click(function () { + Demo.Skylink.unlockRoom(); + }); + //--------------------------------------------------- + $('#enable_audio_btn').click(function () { + Demo.Skylink.enableAudio(); + }); + //--------------------------------------------------- + $('#disable_audio_btn').click(function () { + Demo.Skylink.disableAudio(); + }); + //--------------------------------------------------- + $('#stop_stream_btn').click(function () { + Demo.Skylink.stopStream(); + }); + //--------------------------------------------------- + $('#enable_video_btn').click(function () { + Demo.Skylink.enableVideo(); + }); + //--------------------------------------------------- + $('#disable_video_btn').click(function () { + Demo.Skylink.disableVideo(); + }); + //--------------------------------------------------- + $('#leave_room_btn').click(function () { + Demo.Skylink.leaveRoom(); + }); + $('#restart_btn').click(function () { + Demo.Skylink.refreshConnection(); + }); + $('#message_btn').click(function () { + for(var i=0; i<20; i++){ + Demo.Skylink.sendMessage('message'+i); + } + }); + $('#get_btn').click(function () { + var displayName = Demo.Skylink.getUserData(); + if ($('#show_all').prop('checked')){ + Demo.Skylink.getPeers(true, function(error, success){ + if (error){ + alert('An error occurred while retrieving peer list',error); + } + else{ + + var timestamp = new Date(); + $('#chat_log').append(Demo.Methods.displayChatItemHTML(displayName, timestamp, JSON.stringify(success), true)); + $('#chat_body').animate({ + scrollTop: $('#chat_body').get(0).scrollHeight + }, 500); + + } + }); + } + else{ + Demo.Skylink.getPeers(function(error, success){ + if (error){ + alert('An error occurred while retrieving peer list',error); + } + else{ + + var timestamp = new Date(); + $('#chat_log').append(Demo.Methods.displayChatItemHTML(displayName, timestamp, JSON.stringify(success), true)); + $('#chat_body').animate({ + scrollTop: $('#chat_body').get(0).scrollHeight + }, 500); + + } + }); + } + }); + $('#introduce_btn').click(function () { + Demo.Skylink.introducePeer($('#peer1').val(), $('#peer2').val()); + }); + $('#share_screen_btn').click(function () { + Demo.Skylink.shareScreen(function (data, error) { + console.info(data, error); + }); + }); + $('#stop_screen_btn').click(function () { + Demo.Skylink.stopScreen(); + }); + + window.selectTargetPeer = function(dom) { + var peerId = $(dom).attr('target'); + var panelDom = $('#selected_users_panel'); + + if (!dom.checked) { + $('#' + peerId + '-selected-user').remove(); + + var index = selectedPeers.indexOf(peerId); + + if (index > -1) { + selectedPeers.splice(index, 1); + } + + if ($(panelDom).find('.selected-users em').length === 0) { + $(panelDom).find('.all').show(); + } + } else { + $(panelDom).find('.selected-users').append('Peer ' + peerId + ''); + $(panelDom).find('.all').show(); + selectedPeers.push(peerId); + } + } + + $('#clear-selected-users').click(function () { + $('#selected_users_panel .selected-users').html(''); + $('.select-user').each(function () { + $(this)[0].checked = false + }); + $('#selected_users_panel .all').show(); + selectedPeers = []; + }) +}); diff --git a/demo/privileged/auto-unpriv/css/favicon.ico b/demo/privileged/auto-unpriv/css/favicon.ico new file mode 100644 index 000000000..96865c994 Binary files /dev/null and b/demo/privileged/auto-unpriv/css/favicon.ico differ diff --git a/demo/privileged/auto-unpriv/css/style.css b/demo/privileged/auto-unpriv/css/style.css new file mode 100644 index 000000000..e9ad46a6c --- /dev/null +++ b/demo/privileged/auto-unpriv/css/style.css @@ -0,0 +1,136 @@ +.navbar-white { + background:#fff; +} +#get_user_media_btn, +#join_room_btn, +#leave_room_btn, +#presence_panel, +#file_panel, +#file_list_panel { + display:none; +} +.circle { + color:red; + border:solid 1px; + border-radius:50%; + padding:5px; + margin-bottom:7px; + font-size:10px; +} +.table { + font-size:12px; + word-break:break-word; +} +.table td:first-child { + font-weight:bold; + width:38%; +} +.table.upload-table td:first-child { + font-weight:normal; + width:85%; +} +#credential_panel { + margin-bottom:0; + border-left:0; + border-right:0; + box-shadow:none; + border-radius:0; +} +#credential_panel .panel-body { + padding-bottom:0; +} +#credential_panel .panel-body .form-group { + text-align:left; +} +#credential_panel .panel-body .form-group .title, +#credential_panel .panel-body .form-group .control-group { + display:inline-block; + vertical-align:top; +} +#credential_panel .panel-body .form-group .title { + margin-top:0; + float:left; +} +#credential_panel .panel-body .form-group .title span { + display:block; + margin-bottom:5px; +} +#credential_panel .panel-body .form-group .control-group { +} +video, object { + background:#444; + border:solid 2px #fff; + padding:0!important; +} +video#local_video, +object#local_video { + right:15px; + position:absolute; + z-index:9999; +} +#file_body { + max-height:200px; + overflow-y:auto; +} +#chat_panel { + margin:15px 0 45px; +} +#chat_body { + max-height:200px; + overflow-y:auto; +} +.list-group-item-heading em { + float:right; + font-style:normal; + color:#888; +} +.chat-item { + border:0; + padding:0 0 15px 0; +} +.chat-item img { + width: 250px; +} +#chat_input { + display:block; + width:100%; +} +.control_settings .col { + margin: 7px 0; +} +#leave_room_btn { + margin-left:12px; +} +.control_settings .btn-group { + width: 100%; +} +footer { + background:#f5f5f5; + padding:12px 0 0; + border-top:solid 1px #e0e0e0; +} +.selected-users em { + font-style: normal; + font-size: 12px; + margin-right: 12px; +} +@media screen and (max-width:1999px){ + #credential_panel .panel-body { + margin-bottom:15px; + } + #credential_panel .panel-body button { + margin-left:14px; + } +} +@media screen and (max-width:991px){ + video, object { + display:block; + width:100%; + } + video#local_video, + object#local_video { + right:0; + position:static; + display:block + } +} \ No newline at end of file diff --git a/demo/privileged/auto-unpriv/img/default.png b/demo/privileged/auto-unpriv/img/default.png new file mode 100644 index 000000000..d99a885dc Binary files /dev/null and b/demo/privileged/auto-unpriv/img/default.png differ diff --git a/demo/privileged/auto-unpriv/img/no_profile.jpg b/demo/privileged/auto-unpriv/img/no_profile.jpg new file mode 100644 index 000000000..a4982376f Binary files /dev/null and b/demo/privileged/auto-unpriv/img/no_profile.jpg differ diff --git a/demo/privileged/auto-unpriv/index.html b/demo/privileged/auto-unpriv/index.html new file mode 100644 index 000000000..58ac8ba7d --- /dev/null +++ b/demo/privileged/auto-unpriv/index.html @@ -0,0 +1,221 @@ + + + + Temasys: My Room Example + + + + + + + + + + +
+ +
+ +
+
+
+
+
+
Connection Information
+
+ + + + + + + + + + + + + + + + + + + + + + + +
App ID
User IDNot in Room
Channel status-
Room Lock Status-
Media stream status + + +
+
+
+
+
Connected Peers
+
+ + +
+
+
+
+
File Transfers
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + +
+ + +
+
+
+
+ + + + + + + +
+
+
+
+
Targeted peers to message / file transfer to
+

Peers: All

+

+
+
+
+
+ + + + +
+
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+
+

+ © Temasys Communications Pte Ltd 2014. All Rights Reserved. +

+
+
+ + + + + diff --git a/demo/privileged/auto-unpriv/js/main.js b/demo/privileged/auto-unpriv/js/main.js new file mode 100644 index 000000000..ea0dd44b1 --- /dev/null +++ b/demo/privileged/auto-unpriv/js/main.js @@ -0,0 +1,662 @@ +/******************************************************** + API Settings +*********************************************************/ +var Demo = Demo || {}; +Demo.FILE_SIZE_LIMIT = 1024 * 1024 * 200; +Demo.Peers = 0; +Demo.Files = []; +Demo.Streams = []; +Demo.Methods = {}; +Demo.Skylink = new Skylink(); + +var _peerId = null; + +var selectedPeers = []; + +//Demo.Skylink.setLogLevel(4); + + +Demo.Methods.displayFileItemHTML = function (content) { + return '

' + content.name + '' + content.size + ' B

' + + ((content.isUpload) ? ('' + + '' + + '
' + + ' Upload Status
') : ('
' + + '
Downloading...
')) + + '

Download file

'; +}; + +Demo.Methods.displayChatItemHTML = function (peerId, timestamp, content, isPrivate) { + var Hours, Minutes, Seconds; + if (timestamp.getHours() < 10) + Hours = '0' + timestamp.getHours(); + else + Hours = timestamp.getHours(); + if (timestamp.getMinutes() < 10) + Minutes = '0' + timestamp.getMinutes(); + else + Minutes = timestamp.getMinutes(); + if (timestamp.getSeconds() < 10) + Seconds = '0' + timestamp.getSeconds(); + else + Seconds = timestamp.getSeconds(); + + return '
' + + '

' + '' + peerId + '' + + '' + Hours + + ':' + Minutes + ':' + Seconds + + '

' + '

' + + (isPrivate ? '[pvt msg] ' : '') + content + + (isPrivate ? '' : '') + '

'; +}; + +Demo.Methods.displayChatMessage = function (peerId, content, isPrivate) { + var timestamp = new Date(); + var isFile = typeof content === 'object'; + + //console.info(isFile); + var element = (isFile) ? '#file_log' : '#chat_log'; + var element_body = (isFile) ? '#file_body' : '#chat_body'; + if (isFile) { + content = Demo.Methods.displayFileItemHTML(content); + } + + $(element).append(Demo.Methods.displayChatItemHTML(peerId, timestamp, content, isPrivate)); + $(element_body).animate({ + scrollTop: $('#chat_body').get(0).scrollHeight + }, 500); +}; + +/******************************************************** + Skylink Events +*********************************************************/ +//--------------------------------------------------- +Demo.Skylink.on('incomingData', function (data, transferId, peerId, transferInfo, isSelf) { + if (transferInfo.dataType !== 'blob') { + console.info('incomingData', data, transferId, peerId, transferInfo, isSelf); + //displayChatItemHTML = function (peerId, timestamp, content, isPrivate) + Demo.Methods.displayChatMessage(peerId, '', false); + } +}); +Demo.Skylink.on('incomingDataRequest', function (transferId, peerId, transferInfo, isSelf) { + if (!isSelf && transferInfo.dataType !== 'blob') { + Demo.Skylink.respondBlobRequest(peerId, transferId, true); + } +}) +Demo.Skylink.on('dataTransferState', function (state, transferId, peerId, transferInfo, error){ + transferInfo = transferInfo || {}; + + if (transferInfo.dataType !== 'blob') { + return; + } + + switch (state) { + case Demo.Skylink.DATA_TRANSFER_STATE.UPLOAD_REQUEST : + var result = confirm('Accept file "' + transferInfo.name + + '" from ' + peerId + '?\n\n[size: ' + transferInfo.size + ']'); + Demo.Skylink.respondBlobRequest(peerId, transferId, result); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.UPLOAD_STARTED : + var displayName = Demo.Skylink.getUserData(); + transferInfo.transferId = transferId; + transferInfo.isUpload = true; + transferInfo.data = URL.createObjectURL(transferInfo.data); + Demo.Methods.displayChatMessage(displayName, transferInfo); + Demo.Methods.displayChatMessage(displayName, 'File sent: ' + transferInfo.name); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.DOWNLOAD_STARTED : + var displayName = Demo.Skylink.getPeerInfo(transferInfo.senderPeerId).userData; + transferInfo.transferId = transferId; + transferInfo.data = '#'; + transferInfo.isUpload = false; + Demo.Methods.displayChatMessage(displayName, transferInfo); + Demo.Methods.displayChatMessage(displayName, 'File sent: ' + transferInfo.name); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.UPLOADING : + var displayName = Demo.Skylink.getPeerInfo(peerId).userData; + if ($('#' + transferId).find('.' + peerId).width() < 1) { + $('#' + transferId).append('' + displayName + + '' + transferInfo.percentage + '%'); + } else { + $('#' + transferId).find('.' + peerId).html(transferInfo.percentage + '%'); + } + break; + case Demo.Skylink.DATA_TRANSFER_STATE.DOWNLOADING : + $('#' + transferId).attr('aria-valuenow', transferInfo.percentage); + $('#' + transferId).css('width', transferInfo.percentage + '%'); + $('#' + transferId).find('span').html(transferInfo.percentage + ' %'); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.UPLOAD_COMPLETED : + var displayName = Demo.Skylink.getPeerInfo(peerId).userData; + Demo.Methods.displayChatMessage(displayName, 'File received: ' + transferInfo.name); + $('#' + transferId).find('.' + peerId).html('✓'); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.DOWNLOAD_COMPLETED : + // If completed, display download button + var displayName = Demo.Skylink.getPeerInfo(peerId).userData; + $('#' + transferId).parent().remove(); + $('#' + transferId + '_btn').attr('href', URL.createObjectURL(transferInfo.data)); + $('#' + transferId + '_btn').css('display', 'block'); + Demo.Methods.displayChatMessage(displayName, 'File received: ' + transferInfo.name); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.REJECTED : + alert('User "' + peerId + '" has rejected your file'); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.ERROR : + alert(error.transferType + ' failed. Reason: \n' + + error.message); + $('#' + transferId).parent().removeClass('progress-bar-info'); + $('#' + transferId).parent().addClass('progress-bar-danger'); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.CANCEL : + alert(error.transferType + ' canceled. Reason: \n' + + error.message); + $('#' + transferId).parent().removeClass('progress-bar-info'); + $('#' + transferId).parent().addClass('progress-bar-danger'); + } +}); +//--------------------------------------------------- +Demo.Skylink.on('incomingMessage', function (message, peerId, peerInfo, isSelf) { + Demo.Methods.displayChatMessage((isSelf) ? 'You' : peerInfo.userData, + ((message.isDataChannel) ? 'P2P' : 'Socket') + ' -> ' + message.targetPeerId + ': ' + + message.content, message.isPrivate); +}); +//--------------------------------------------------- +Demo.Skylink.on('peerRestart', function (peerId, peerInfo, isSelf){ + if (!isSelf) { + $('#user' + peerId + ' .video').css('color', + (peerInfo.mediaStatus.videoMuted) ? 'red' : 'green'); + $('#user' + peerId + ' .audio').css('color', + (peerInfo.mediaStatus.audioMuted) ? 'red' : 'green'); + $('#user' + peerId + ' .name').html(peerInfo.userData); + } +}); +//--------------------------------------------------- +Demo.Skylink.on('peerJoined', function (peerId, peerInfo, isSelf){ + if (isSelf) { + $('#display_user_id').html(peerId); + $('#isAudioMuted').css('color', + (peerInfo.mediaStatus.audioMuted) ? 'red' : 'green'); + $('#isVideoMuted').css('color', + (peerInfo.mediaStatus.videoMuted) ? 'red' : 'green'); + $('#leave_room_btn').show(); + $('#presence_panel').show(); + $('#chat_input').removeAttr('disabled'); + // If not supportive of File, FileReader, Blob quit + if (window.File && window.FileReader && window.FileList && window.Blob) { + $('#file_panel').show(); + $('#file_list_panel').show(); + } + } else { + _peerId = peerId; + Demo.Methods.displayChatMessage('System', 'Peer ' + peerId + ' joined the room'); + var newListEntry = '' + + '' + peerInfo.userData + '
' + + ''; + var titleList = [ + 'Joined Room', 'Handshake: Welcome', 'Handshake: Offer', + 'Handshake: Answer', 'Candidate Generation state', 'ICE Connection state', + 'Peer Connection state', 'Data Channel Connection state', + 'MediaStream: Video', 'MediaStream: Audio' + ]; + var glyphiconList = [ + 'glyphicon-log-in', 'glyphicon-hand-right', 'glyphicon-hand-left', + 'glyphicon-thumbs-up', 'glyphicon-flash', 'glyphicon-magnet', + 'glyphicon-user', 'glyphicon-transfer', 'glyphicon-facetime-video video', + 'glyphicon-volume-up audio' + ]; + for( var i = 0; i < 10; i++) { + newListEntry += '   '; + } + newListEntry += ''; + $('#presence_list').append(newListEntry); + $('#user' + peerId + ' .0').css('color','green'); + $('#user' + peerId + ' .video').css('color', + (peerInfo.mediaStatus.videoMuted) ? 'red' : 'green'); + $('#user' + peerId + ' .audio').css('color', + (peerInfo.mediaStatus.audioMuted) ? 'red' : 'green'); + } +}); +//--------------------------------------------------- +Demo.Skylink.on('incomingStream', function (peerId, stream, isSelf, peerInfo){ + if (!isSelf) { + Demo.Peers += 1; + } + var peerVideo; + + if ($('#video' + peerId).length === 0) { + peerVideo = document.createElement('video'); + peerVideo.id = 'video' + peerId; + peerVideo.className = 'col-md-6'; + if (window.webrtcDetectedBrowser !== 'IE') { + peerVideo.autoplay = 'autoplay'; + } + + // mutes user's video + if (isSelf && window.webrtcDetectedBrowser !== 'IE') { + peerVideo.muted = 'muted'; + } + $('#peer_video_list').append(peerVideo); + } else { + peerVideo = document.getElementById('video' + peerId); + } + + attachMediaStream(peerVideo, stream); + Demo.Streams[peerId] = Demo.Streams[peerId] || {}; + Demo.Streams[peerId][stream.id] = peerVideo.src; +}); +//--------------------------------------------------- +Demo.Skylink.on('mediaAccessSuccess', function (stream){ + Demo.Methods.displayChatMessage('System', 'Audio and video access is allowed.'); +}); +//--------------------------------------------------- +Demo.Skylink.on('mediaAccessError', function (error){ + alert((typeof error === 'object') ? error.message : error); + Demo.Methods.displayChatMessage('System', 'Failed to join room as video and audio stream is required.'); +}); +//--------------------------------------------------- +Demo.Skylink.on('readyStateChange', function (state, error){ + if (state === Demo.Skylink.READY_STATE_CHANGE.ERROR) { + for (var errorCode in Demo.Skylink.READY_STATE_CHANGE_ERROR) { + if (Demo.Skylink.READY_STATE_CHANGE_ERROR[errorCode] === + error.errorCode) { + alert('An error occurred parsing and retrieving server code.\n' + + 'Error was: ' + errorCode); + break; + } + } + } + $('#channel_status').show(); +}); +//--------------------------------------------------- +Demo.Skylink.on('peerLeft', function (peerId, peerInfo, isSelf){ + //console.info('peerLeft', peerId, peerInfo, isSelf); + Demo.Methods.displayChatMessage('System', 'Peer ' + peerId + ' has left the room'); + Demo.Peers -= 1; + $('#video' + peerId).remove(); + $('#user' + peerId).remove(); + delete Demo.Streams[peerId]; + var index = selectedPeers.indexOf(peerId); + + if (index > -1) { + selectedPeers.splice(index, 1); + } +}); +//--------------------------------------------------- +Demo.Skylink.on('handshakeProgress', function (state, peerId) { + var stage = 0; + switch( state ){ + case Demo.Skylink.HANDSHAKE_PROGRESS.WELCOME: + stage = 1; + break; + case Demo.Skylink.HANDSHAKE_PROGRESS.OFFER: + stage = 2; + break; + case Demo.Skylink.HANDSHAKE_PROGRESS.ANSWER: + stage = 3; + break; + } + for (var i=0; i<=stage; i++) { + $('#user' + peerId + ' .' + i ).css('color', 'green'); + } +}); +//--------------------------------------------------- +Demo.Skylink.on('candidateGenerationState', function (state, peerId) { + var color = 'orange'; + switch( state ){ + case Demo.Skylink.CANDIDATE_GENERATION_STATE.COMPLETED: + color = 'green'; break; + } + $('#user' + peerId + ' .4' ).css('color', color); +}); +//--------------------------------------------------- +Demo.Skylink.on('iceConnectionState', function (state, peerId) { + var color = 'orange'; + switch(state){ + case Demo.Skylink.ICE_CONNECTION_STATE.STARTING: + case Demo.Skylink.ICE_CONNECTION_STATE.CLOSED: + case Demo.Skylink.ICE_CONNECTION_STATE.FAILED: + color = 'red'; + break; + case Demo.Skylink.ICE_CONNECTION_STATE.CHECKING: + case Demo.Skylink.ICE_CONNECTION_STATE.DISCONNECTED: + color = 'orange'; + break; + case Demo.Skylink.ICE_CONNECTION_STATE.CONNECTED: + case Demo.Skylink.ICE_CONNECTION_STATE.COMPLETED: + color = 'green'; + break; + default: + console.error('ICE State:', state, peerId); + } + $('#user' + peerId + ' .5' ).css('color', color); + + if (state === Demo.Skylink.ICE_CONNECTION_STATE.CHECKING){ + setTimeout(function(){ + if ($('#user' + peerId + ' .5' ).css('color') === 'orange') { + $('#user' + peerId).remove(); + } + }, 30000); + } +}); +//--------------------------------------------------- +Demo.Skylink.on('peerConnectionState', function (state, peerId) { + var color = 'red'; + switch(state){ + case Demo.Skylink.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER: + case Demo.Skylink.PEER_CONNECTION_STATE.HAVE_REMOTE_PRANSWER: + case Demo.Skylink.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER: + case Demo.Skylink.PEER_CONNECTION_STATE.HAVE_LOCAL_PRANSWER: + color = 'orange'; + break; + case Demo.Skylink.PEER_CONNECTION_STATE.CLOSED: + color = 'red'; + break; + case Demo.Skylink.PEER_CONNECTION_STATE.STABLE: + color = 'green'; + break; + } + $('#user' + peerId + ' .6' ).css('color', color); +}); +//--------------------------------------------------- +Demo.Skylink.on('dataChannelState', function (state, peerId) { + var color = 'red'; + switch (state) { + case Demo.Skylink.DATA_CHANNEL_STATE.ERROR: + color = 'red'; + break; + case Demo.Skylink.DATA_CHANNEL_STATE.CONNECTING: + color = 'orange'; + break; + case Demo.Skylink.DATA_CHANNEL_STATE.OPEN: + color = 'green'; + break; + } + $('#user' + peerId + ' .7' ).css('color', color); +}); +//--------------------------------------------------- +Demo.Skylink.on('peerUpdated', function (peerId, peerInfo, isSelf) { + if (isSelf) { + $('#isAudioMuted').css('color', + (peerInfo.mediaStatus.audioMuted) ? 'red' : 'green'); + $('#isVideoMuted').css('color', + (peerInfo.mediaStatus.videoMuted) ? 'red' : 'green'); + } else { + $('#user' + peerId + ' .video').css('color', + (peerInfo.mediaStatus.videoMuted) ? 'red' : 'green'); + $('#user' + peerId + ' .audio').css('color', + (peerInfo.mediaStatus.audioMuted) ? 'red' : 'green'); + $('#user' + peerId + ' .name').html(peerInfo.userData); + } + + if ($('#video' + peerId).find('video').length > 0) { + if (peerInfo.mediaStatus.videoMuted) { + $('#video' + peerId)[0].src = ''; + } else { + $('#video' + peerId)[0].src = Demo.Streams[peerId]; + } + } +}); +//--------------------------------------------------- +Demo.Skylink.on('roomLock', function (isLocked, peerId, peerInfo, isSelf) { + $('#display_room_status').html((isLocked) ? 'Locked' : 'Not Locked'); +}); +//--------------------------------------------------- +Demo.Skylink.on('channelOpen', function () { + $('#channel').css('color','green'); + $('#channel').html('Active'); +}); +//--------------------------------------------------- +Demo.Skylink.on('channelClose', function () { + $('#leave_room_btn').hide(); + $('#channel').css('color','red'); + $('#channel').html('Closed'); +}); +//--------------------------------------------------- +Demo.Skylink.on('channelMessage', function (){ + $('#channel').css('color','00FF00'); + $('#channel').html('Connecting...'); + setTimeout(function () { + $('#channel').css('color','green'); + $('#channel').html('Active'); + }, 1000); +}); +//--------------------------------------------------- +Demo.Skylink.on('channelError', function (error) { + Demo.Methods.displayChatMessage('System', 'Channel Error:
' + (error.message || error)); +}); +//--------------------------------------------------- +Demo.Skylink.on('mediaAccessError', function (error) { + alert((error.message || error)); +}); + +Demo.Skylink.on('serverPeerJoined', function (serverPeerId, serverPeerType) { + console.info('serverPeerJoined', serverPeerId, serverPeerType); +}); + +Demo.Skylink.on('serverPeerLeft', function (serverPeerId, serverPeerType) { + console.info('serverPeerLeft', serverPeerId, serverPeerType); +}); + +Demo.Skylink.on('peerJoined', function (peerId, peerInfo, isSelf) { + console.info('peerJoined', peerId, peerInfo, isSelf); +}); + +Demo.Skylink.on('peerLeft', function (peerId, peerInfo, isSelf) { + console.info('peerLeft', peerId, peerInfo, isSelf); +}); + +Demo.Skylink.on('peerRestart', function (peerId, peerInfo, isSelf) { + console.info('peerRestart', peerId, peerInfo, isSelf); +}); + +Demo.Skylink.on('serverPeerRestart', function (serverPeerId, serverPeerType) { + console.info('serverPeerRestart', serverPeerId, serverPeerType); +}); + +//------------- join room --------------------------- +var displayName = 'name_' + 'user_' + Math.floor((Math.random() * 1000) + 1); + +Demo.Skylink.init(config, function (error, success) { + if (success) { + Demo.Skylink.joinRoom({ + userData: displayName, + audio: { stereo: true }, + video: { + resolution: { + width: 1280, + height: 720 + } + } + }); + } +}); + +/******************************************************** + DOM Events +*********************************************************/ +$(document).ready(function () { + //--------------------------------------------------- + $('#display_app_id').html(config.apiKey); + //--------------------------------------------------- + $('#chat_input').keyup(function(e) { + e.preventDefault(); + if (e.keyCode === 13) { + if ($('#send_data_channel').prop('checked')) { + if (selectedPeers.length > 0) { + Demo.Skylink.sendP2PMessage($('#chat_input').val(), selectedPeers); + } else { + Demo.Skylink.sendP2PMessage($('#chat_input').val()); + } + } else { + if (selectedPeers.length > 0) { + Demo.Skylink.sendMessage($('#chat_input').val(), selectedPeers); + } else { + Demo.Skylink.sendMessage($('#chat_input').val()); + } + } + $('#chat_input').val(''); + } + }); + //--------------------------------------------------- + $('#file_input').change(function() { + Demo.Files = $(this)[0].files; + }); + //--------------------------------------------------- + $('#dataURL_input').change(function() { + Demo.DataURL = $(this)[0].files; + }); + //--------------------------------------------------- + $('#send_file_btn').click(function() { + if(!Demo.Files) { + alert('No files selected'); + return; + } else { + if(Demo.Files.length > 0) { + $(Demo.Files)[0].disabled = true; + console.log('Button temporarily disabled to prevent crash'); + } + } + for(var i=0; i < Demo.Files.length; i++) { + var file = Demo.Files[i]; + if(file.size <= Demo.FILE_SIZE_LIMIT) { + if (selectedPeers.length > 0) { + Demo.Skylink.sendBlobData(file, selectedPeers); + } else { + Demo.Skylink.sendBlobData(file); + } + $('#file_input').val(''); + } else { + alert('File "' + file.name + '"" exceeded the limit of 200MB.\n' + + 'We only currently support files up to 200MB for this demo.'); + } + } + $('#send_file_btn')[0].disabled = false; + }); + //--------------------------------------------------- + $('#send_dataURL_btn').click(function() { + if(!Demo.DataURL) { + alert('No files selected'); + return; + } else { + if(Demo.Files.length > 0) { + $(Demo.Files)[0].disabled = true; + console.log('Button temporarily disabled to prevent crash'); + } + } + + for(var i=0; i < Demo.DataURL.length; i++) { + var file = Demo.DataURL[i]; + + var fr = new FileReader(); + + fr.onload = function () { + if(file.size <= 1024 * 1024 * 2) { + if (selectedPeers.length > 0) { + Demo.Skylink.sendURLData(fr.result, selectedPeers); + } else { + Demo.Skylink.sendURLData(fr.result); + } + $('#dataURL_input').val(''); + } else { + alert('File "' + file.name + '"" exceeded the limit of 2MB.\n' + + 'We only currently support files up to 2MB for this demo.'); + } + }; + + fr.readAsDataURL(file); + } + $('#send_dataURL_btn')[0].disabled = false; + }); + //--------------------------------------------------- + $('#update_user_info_btn').click(function () { + Demo.Skylink.setUserData($('#display_user_info').val()); + }); + //--------------------------------------------------- + $('#lock_btn').click(function () { + Demo.Skylink.lockRoom(); + }); + //--------------------------------------------------- + $('#unlock_btn').click(function () { + Demo.Skylink.unlockRoom(); + }); + //--------------------------------------------------- + $('#enable_audio_btn').click(function () { + Demo.Skylink.enableAudio(); + }); + //--------------------------------------------------- + $('#disable_audio_btn').click(function () { + Demo.Skylink.disableAudio(); + }); + //--------------------------------------------------- + $('#stop_stream_btn').click(function () { + Demo.Skylink.stopStream(); + }); + //--------------------------------------------------- + $('#enable_video_btn').click(function () { + Demo.Skylink.enableVideo(); + }); + //--------------------------------------------------- + $('#disable_video_btn').click(function () { + Demo.Skylink.disableVideo(); + }); + //--------------------------------------------------- + $('#leave_room_btn').click(function () { + Demo.Skylink.leaveRoom(); + }); + $('#restart_btn').click(function () { + Demo.Skylink.refreshConnection(); + }); + $('#message_btn').click(function () { + for(var i=0; i<20; i++){ + Demo.Skylink.sendMessage('message'+i); + } + }); + $('#share_screen_btn').click(function () { + Demo.Skylink.shareScreen(function (data, error) { + console.info(data, error); + }); + }); + $('#stop_screen_btn').click(function () { + Demo.Skylink.stopScreen(); + }); + + window.selectTargetPeer = function(dom) { + var peerId = $(dom).attr('target'); + var panelDom = $('#selected_users_panel'); + + if (!dom.checked) { + $('#' + peerId + '-selected-user').remove(); + + var index = selectedPeers.indexOf(peerId); + + if (index > -1) { + selectedPeers.splice(index, 1); + } + + if ($(panelDom).find('.selected-users em').length === 0) { + $(panelDom).find('.all').show(); + } + } else { + $(panelDom).find('.selected-users').append('Peer ' + peerId + ''); + $(panelDom).find('.all').show(); + selectedPeers.push(peerId); + } + } + + $('#clear-selected-users').click(function () { + $('#selected_users_panel .selected-users').html(''); + $('.select-user').each(function () { + $(this)[0].checked = false + }); + $('#selected_users_panel .all').show(); + selectedPeers = []; + }) +}); diff --git a/demo/privileged/index.html b/demo/privileged/index.html new file mode 100644 index 000000000..ba1facae5 --- /dev/null +++ b/demo/privileged/index.html @@ -0,0 +1,30 @@ + + + + Privileged use case example + + + + +
+ TEMASYS PRIVILEGED USE CASE DEMO +
+
+
+ Click on the buttons below to open the corresponding type of peer in a new tab +
+
+ + + + +
+
+

+ © Temasys Communications Pte Ltd 2014. All Rights Reserved. +

+
+
+ + + \ No newline at end of file diff --git a/demo/privileged/main.js b/demo/privileged/main.js new file mode 100644 index 000000000..7aa008b2d --- /dev/null +++ b/demo/privileged/main.js @@ -0,0 +1,19 @@ +$(document).ready(function(){ + + $('#auto-pr').click(function(){ + window.open("http://localhost:8081/demo/privileged/auto-priv","_blank"); + }); + + $('#auto-unpr').click(function(){ + window.open("http://localhost:8081/demo/privileged/auto-unpriv","_blank"); + }); + + $('#unauto-pr').click(function(){ + window.open("http://localhost:8081/demo/privileged/unauto-priv","_blank"); + }); + + $('#unauto-unpr').click(function(){ + window.open("http://localhost:8081/demo/privileged/unauto-unpriv","_blank"); + }); + +}); \ No newline at end of file diff --git a/demo/privileged/unauto-priv/css/favicon.ico b/demo/privileged/unauto-priv/css/favicon.ico new file mode 100644 index 000000000..96865c994 Binary files /dev/null and b/demo/privileged/unauto-priv/css/favicon.ico differ diff --git a/demo/privileged/unauto-priv/css/style.css b/demo/privileged/unauto-priv/css/style.css new file mode 100644 index 000000000..e9ad46a6c --- /dev/null +++ b/demo/privileged/unauto-priv/css/style.css @@ -0,0 +1,136 @@ +.navbar-white { + background:#fff; +} +#get_user_media_btn, +#join_room_btn, +#leave_room_btn, +#presence_panel, +#file_panel, +#file_list_panel { + display:none; +} +.circle { + color:red; + border:solid 1px; + border-radius:50%; + padding:5px; + margin-bottom:7px; + font-size:10px; +} +.table { + font-size:12px; + word-break:break-word; +} +.table td:first-child { + font-weight:bold; + width:38%; +} +.table.upload-table td:first-child { + font-weight:normal; + width:85%; +} +#credential_panel { + margin-bottom:0; + border-left:0; + border-right:0; + box-shadow:none; + border-radius:0; +} +#credential_panel .panel-body { + padding-bottom:0; +} +#credential_panel .panel-body .form-group { + text-align:left; +} +#credential_panel .panel-body .form-group .title, +#credential_panel .panel-body .form-group .control-group { + display:inline-block; + vertical-align:top; +} +#credential_panel .panel-body .form-group .title { + margin-top:0; + float:left; +} +#credential_panel .panel-body .form-group .title span { + display:block; + margin-bottom:5px; +} +#credential_panel .panel-body .form-group .control-group { +} +video, object { + background:#444; + border:solid 2px #fff; + padding:0!important; +} +video#local_video, +object#local_video { + right:15px; + position:absolute; + z-index:9999; +} +#file_body { + max-height:200px; + overflow-y:auto; +} +#chat_panel { + margin:15px 0 45px; +} +#chat_body { + max-height:200px; + overflow-y:auto; +} +.list-group-item-heading em { + float:right; + font-style:normal; + color:#888; +} +.chat-item { + border:0; + padding:0 0 15px 0; +} +.chat-item img { + width: 250px; +} +#chat_input { + display:block; + width:100%; +} +.control_settings .col { + margin: 7px 0; +} +#leave_room_btn { + margin-left:12px; +} +.control_settings .btn-group { + width: 100%; +} +footer { + background:#f5f5f5; + padding:12px 0 0; + border-top:solid 1px #e0e0e0; +} +.selected-users em { + font-style: normal; + font-size: 12px; + margin-right: 12px; +} +@media screen and (max-width:1999px){ + #credential_panel .panel-body { + margin-bottom:15px; + } + #credential_panel .panel-body button { + margin-left:14px; + } +} +@media screen and (max-width:991px){ + video, object { + display:block; + width:100%; + } + video#local_video, + object#local_video { + right:0; + position:static; + display:block + } +} \ No newline at end of file diff --git a/demo/privileged/unauto-priv/img/default.png b/demo/privileged/unauto-priv/img/default.png new file mode 100644 index 000000000..d99a885dc Binary files /dev/null and b/demo/privileged/unauto-priv/img/default.png differ diff --git a/demo/privileged/unauto-priv/img/no_profile.jpg b/demo/privileged/unauto-priv/img/no_profile.jpg new file mode 100644 index 000000000..a4982376f Binary files /dev/null and b/demo/privileged/unauto-priv/img/no_profile.jpg differ diff --git a/demo/privileged/unauto-priv/index.html b/demo/privileged/unauto-priv/index.html new file mode 100644 index 000000000..6d0751b7f --- /dev/null +++ b/demo/privileged/unauto-priv/index.html @@ -0,0 +1,237 @@ + + + + Temasys: My Room Example + + + + + + + + + + +
+ +
+ +
+
+
+
+
+
Connection Information
+
+ + + + + + + + + + + + + + + + + + + + + + + +
App ID
User IDNot in Room
Channel status-
Room Lock Status-
Media stream status + + +
+
+
+
+
Connected Peers
+
+ + +
+
+
+
+
File Transfers
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + + + +
+
+
+
+
Targeted peers to message / file transfer to
+

Peers: All

+

+
+
+
+
+ + + + +
+
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+

+ © Temasys Communications Pte Ltd 2014. All Rights Reserved. +

+
+
+ + + + + diff --git a/demo/privileged/unauto-priv/js/main.js b/demo/privileged/unauto-priv/js/main.js new file mode 100644 index 000000000..283f8d535 --- /dev/null +++ b/demo/privileged/unauto-priv/js/main.js @@ -0,0 +1,700 @@ +/******************************************************** + API Settings +*********************************************************/ +var Demo = Demo || {}; +Demo.FILE_SIZE_LIMIT = 1024 * 1024 * 200; +Demo.Peers = 0; +Demo.Files = []; +Demo.Streams = []; +Demo.Methods = {}; +Demo.Skylink = new Skylink(); + +var _peerId = null; + +var selectedPeers = []; + +//Demo.Skylink.setLogLevel(4); + + +Demo.Methods.displayFileItemHTML = function (content) { + return '

' + content.name + '' + content.size + ' B

' + + ((content.isUpload) ? ('' + + '' + + '
' + + ' Upload Status
') : ('
' + + '
Downloading...
')) + + '

Download file

'; +}; + +Demo.Methods.displayChatItemHTML = function (peerId, timestamp, content, isPrivate) { + var Hours, Minutes, Seconds; + if (timestamp.getHours() < 10) + Hours = '0' + timestamp.getHours(); + else + Hours = timestamp.getHours(); + if (timestamp.getMinutes() < 10) + Minutes = '0' + timestamp.getMinutes(); + else + Minutes = timestamp.getMinutes(); + if (timestamp.getSeconds() < 10) + Seconds = '0' + timestamp.getSeconds(); + else + Seconds = timestamp.getSeconds(); + + return '
' + + '

' + '' + peerId + '' + + '' + Hours + + ':' + Minutes + ':' + Seconds + + '

' + '

' + + (isPrivate ? '[pvt msg] ' : '') + content + + (isPrivate ? '' : '') + '

'; +}; + +Demo.Methods.displayChatMessage = function (peerId, content, isPrivate) { + var timestamp = new Date(); + var isFile = typeof content === 'object'; + + //console.info(isFile); + var element = (isFile) ? '#file_log' : '#chat_log'; + var element_body = (isFile) ? '#file_body' : '#chat_body'; + if (isFile) { + content = Demo.Methods.displayFileItemHTML(content); + } + + $(element).append(Demo.Methods.displayChatItemHTML(peerId, timestamp, content, isPrivate)); + $(element_body).animate({ + scrollTop: $('#chat_body').get(0).scrollHeight + }, 500); +}; + +/******************************************************** + Skylink Events +*********************************************************/ +//--------------------------------------------------- +Demo.Skylink.on('incomingData', function (data, transferId, peerId, transferInfo, isSelf) { + if (transferInfo.dataType !== 'blob') { + console.info('incomingData', data, transferId, peerId, transferInfo, isSelf); + //displayChatItemHTML = function (peerId, timestamp, content, isPrivate) + Demo.Methods.displayChatMessage(peerId, '', false); + } +}); +Demo.Skylink.on('incomingDataRequest', function (transferId, peerId, transferInfo, isSelf) { + if (!isSelf && transferInfo.dataType !== 'blob') { + Demo.Skylink.respondBlobRequest(peerId, transferId, true); + } +}) +Demo.Skylink.on('dataTransferState', function (state, transferId, peerId, transferInfo, error){ + transferInfo = transferInfo || {}; + + if (transferInfo.dataType !== 'blob') { + return; + } + + switch (state) { + case Demo.Skylink.DATA_TRANSFER_STATE.UPLOAD_REQUEST : + var result = confirm('Accept file "' + transferInfo.name + + '" from ' + peerId + '?\n\n[size: ' + transferInfo.size + ']'); + Demo.Skylink.respondBlobRequest(peerId, transferId, result); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.UPLOAD_STARTED : + var displayName = Demo.Skylink.getUserData(); + transferInfo.transferId = transferId; + transferInfo.isUpload = true; + transferInfo.data = URL.createObjectURL(transferInfo.data); + Demo.Methods.displayChatMessage(displayName, transferInfo); + Demo.Methods.displayChatMessage(displayName, 'File sent: ' + transferInfo.name); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.DOWNLOAD_STARTED : + var displayName = Demo.Skylink.getPeerInfo(transferInfo.senderPeerId).userData; + transferInfo.transferId = transferId; + transferInfo.data = '#'; + transferInfo.isUpload = false; + Demo.Methods.displayChatMessage(displayName, transferInfo); + Demo.Methods.displayChatMessage(displayName, 'File sent: ' + transferInfo.name); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.UPLOADING : + var displayName = Demo.Skylink.getPeerInfo(peerId).userData; + if ($('#' + transferId).find('.' + peerId).width() < 1) { + $('#' + transferId).append('' + displayName + + '' + transferInfo.percentage + '%'); + } else { + $('#' + transferId).find('.' + peerId).html(transferInfo.percentage + '%'); + } + break; + case Demo.Skylink.DATA_TRANSFER_STATE.DOWNLOADING : + $('#' + transferId).attr('aria-valuenow', transferInfo.percentage); + $('#' + transferId).css('width', transferInfo.percentage + '%'); + $('#' + transferId).find('span').html(transferInfo.percentage + ' %'); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.UPLOAD_COMPLETED : + var displayName = Demo.Skylink.getPeerInfo(peerId).userData; + Demo.Methods.displayChatMessage(displayName, 'File received: ' + transferInfo.name); + $('#' + transferId).find('.' + peerId).html('✓'); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.DOWNLOAD_COMPLETED : + // If completed, display download button + var displayName = Demo.Skylink.getPeerInfo(peerId).userData; + $('#' + transferId).parent().remove(); + $('#' + transferId + '_btn').attr('href', URL.createObjectURL(transferInfo.data)); + $('#' + transferId + '_btn').css('display', 'block'); + Demo.Methods.displayChatMessage(displayName, 'File received: ' + transferInfo.name); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.REJECTED : + alert('User "' + peerId + '" has rejected your file'); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.ERROR : + alert(error.transferType + ' failed. Reason: \n' + + error.message); + $('#' + transferId).parent().removeClass('progress-bar-info'); + $('#' + transferId).parent().addClass('progress-bar-danger'); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.CANCEL : + alert(error.transferType + ' canceled. Reason: \n' + + error.message); + $('#' + transferId).parent().removeClass('progress-bar-info'); + $('#' + transferId).parent().addClass('progress-bar-danger'); + } +}); +//--------------------------------------------------- +Demo.Skylink.on('incomingMessage', function (message, peerId, peerInfo, isSelf) { + Demo.Methods.displayChatMessage((isSelf) ? 'You' : peerInfo.userData, + ((message.isDataChannel) ? 'P2P' : 'Socket') + ' -> ' + message.targetPeerId + ': ' + + message.content, message.isPrivate); +}); +//--------------------------------------------------- +Demo.Skylink.on('peerRestart', function (peerId, peerInfo, isSelf){ + if (!isSelf) { + $('#user' + peerId + ' .video').css('color', + (peerInfo.mediaStatus.videoMuted) ? 'red' : 'green'); + $('#user' + peerId + ' .audio').css('color', + (peerInfo.mediaStatus.audioMuted) ? 'red' : 'green'); + $('#user' + peerId + ' .name').html(peerInfo.userData); + } +}); +//--------------------------------------------------- +Demo.Skylink.on('peerJoined', function (peerId, peerInfo, isSelf){ + if (isSelf) { + $('#display_user_id').html(peerId); + $('#isAudioMuted').css('color', + (peerInfo.mediaStatus.audioMuted) ? 'red' : 'green'); + $('#isVideoMuted').css('color', + (peerInfo.mediaStatus.videoMuted) ? 'red' : 'green'); + $('#leave_room_btn').show(); + $('#presence_panel').show(); + $('#chat_input').removeAttr('disabled'); + // If not supportive of File, FileReader, Blob quit + if (window.File && window.FileReader && window.FileList && window.Blob) { + $('#file_panel').show(); + $('#file_list_panel').show(); + } + } else { + _peerId = peerId; + Demo.Methods.displayChatMessage('System', 'Peer ' + peerId + ' joined the room'); + var newListEntry = '' + + '' + peerInfo.userData + '
' + + ''; + var titleList = [ + 'Joined Room', 'Handshake: Welcome', 'Handshake: Offer', + 'Handshake: Answer', 'Candidate Generation state', 'ICE Connection state', + 'Peer Connection state', 'Data Channel Connection state', + 'MediaStream: Video', 'MediaStream: Audio' + ]; + var glyphiconList = [ + 'glyphicon-log-in', 'glyphicon-hand-right', 'glyphicon-hand-left', + 'glyphicon-thumbs-up', 'glyphicon-flash', 'glyphicon-magnet', + 'glyphicon-user', 'glyphicon-transfer', 'glyphicon-facetime-video video', + 'glyphicon-volume-up audio' + ]; + for( var i = 0; i < 10; i++) { + newListEntry += '   '; + } + newListEntry += ''; + $('#presence_list').append(newListEntry); + $('#user' + peerId + ' .0').css('color','green'); + $('#user' + peerId + ' .video').css('color', + (peerInfo.mediaStatus.videoMuted) ? 'red' : 'green'); + $('#user' + peerId + ' .audio').css('color', + (peerInfo.mediaStatus.audioMuted) ? 'red' : 'green'); + } +}); +//--------------------------------------------------- +Demo.Skylink.on('incomingStream', function (peerId, stream, isSelf, peerInfo){ + if (!isSelf) { + Demo.Peers += 1; + } + var peerVideo; + + if ($('#video' + peerId).length === 0) { + peerVideo = document.createElement('video'); + peerVideo.id = 'video' + peerId; + peerVideo.className = 'col-md-6'; + if (window.webrtcDetectedBrowser !== 'IE') { + peerVideo.autoplay = 'autoplay'; + } + + // mutes user's video + if (isSelf && window.webrtcDetectedBrowser !== 'IE') { + peerVideo.muted = 'muted'; + } + $('#peer_video_list').append(peerVideo); + } else { + peerVideo = document.getElementById('video' + peerId); + } + + attachMediaStream(peerVideo, stream); + Demo.Streams[peerId] = Demo.Streams[peerId] || {}; + Demo.Streams[peerId][stream.id] = peerVideo.src; +}); +//--------------------------------------------------- +Demo.Skylink.on('mediaAccessSuccess', function (stream){ + Demo.Methods.displayChatMessage('System', 'Audio and video access is allowed.'); +}); +//--------------------------------------------------- +Demo.Skylink.on('mediaAccessError', function (error){ + alert((typeof error === 'object') ? error.message : error); + Demo.Methods.displayChatMessage('System', 'Failed to join room as video and audio stream is required.'); +}); +//--------------------------------------------------- +Demo.Skylink.on('readyStateChange', function (state, error){ + if (state === Demo.Skylink.READY_STATE_CHANGE.ERROR) { + for (var errorCode in Demo.Skylink.READY_STATE_CHANGE_ERROR) { + if (Demo.Skylink.READY_STATE_CHANGE_ERROR[errorCode] === + error.errorCode) { + alert('An error occurred parsing and retrieving server code.\n' + + 'Error was: ' + errorCode); + break; + } + } + } + $('#channel_status').show(); +}); +//--------------------------------------------------- +Demo.Skylink.on('peerLeft', function (peerId, peerInfo, isSelf){ + //console.info('peerLeft', peerId, peerInfo, isSelf); + Demo.Methods.displayChatMessage('System', 'Peer ' + peerId + ' has left the room'); + Demo.Peers -= 1; + $('#video' + peerId).remove(); + $('#user' + peerId).remove(); + delete Demo.Streams[peerId]; + var index = selectedPeers.indexOf(peerId); + + if (index > -1) { + selectedPeers.splice(index, 1); + } +}); +//--------------------------------------------------- +Demo.Skylink.on('handshakeProgress', function (state, peerId) { + var stage = 0; + switch( state ){ + case Demo.Skylink.HANDSHAKE_PROGRESS.WELCOME: + stage = 1; + break; + case Demo.Skylink.HANDSHAKE_PROGRESS.OFFER: + stage = 2; + break; + case Demo.Skylink.HANDSHAKE_PROGRESS.ANSWER: + stage = 3; + break; + } + for (var i=0; i<=stage; i++) { + $('#user' + peerId + ' .' + i ).css('color', 'green'); + } +}); +//--------------------------------------------------- +Demo.Skylink.on('candidateGenerationState', function (state, peerId) { + var color = 'orange'; + switch( state ){ + case Demo.Skylink.CANDIDATE_GENERATION_STATE.COMPLETED: + color = 'green'; break; + } + $('#user' + peerId + ' .4' ).css('color', color); +}); +//--------------------------------------------------- +Demo.Skylink.on('iceConnectionState', function (state, peerId) { + var color = 'orange'; + switch(state){ + case Demo.Skylink.ICE_CONNECTION_STATE.STARTING: + case Demo.Skylink.ICE_CONNECTION_STATE.CLOSED: + case Demo.Skylink.ICE_CONNECTION_STATE.FAILED: + color = 'red'; + break; + case Demo.Skylink.ICE_CONNECTION_STATE.CHECKING: + case Demo.Skylink.ICE_CONNECTION_STATE.DISCONNECTED: + color = 'orange'; + break; + case Demo.Skylink.ICE_CONNECTION_STATE.CONNECTED: + case Demo.Skylink.ICE_CONNECTION_STATE.COMPLETED: + color = 'green'; + break; + default: + console.error('ICE State:', state, peerId); + } + $('#user' + peerId + ' .5' ).css('color', color); + + if (state === Demo.Skylink.ICE_CONNECTION_STATE.CHECKING){ + setTimeout(function(){ + if ($('#user' + peerId + ' .5' ).css('color') === 'orange') { + $('#user' + peerId).remove(); + } + }, 30000); + } +}); +//--------------------------------------------------- +Demo.Skylink.on('peerConnectionState', function (state, peerId) { + var color = 'red'; + switch(state){ + case Demo.Skylink.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER: + case Demo.Skylink.PEER_CONNECTION_STATE.HAVE_REMOTE_PRANSWER: + case Demo.Skylink.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER: + case Demo.Skylink.PEER_CONNECTION_STATE.HAVE_LOCAL_PRANSWER: + color = 'orange'; + break; + case Demo.Skylink.PEER_CONNECTION_STATE.CLOSED: + color = 'red'; + break; + case Demo.Skylink.PEER_CONNECTION_STATE.STABLE: + color = 'green'; + break; + } + $('#user' + peerId + ' .6' ).css('color', color); +}); +//--------------------------------------------------- +Demo.Skylink.on('dataChannelState', function (state, peerId) { + var color = 'red'; + switch (state) { + case Demo.Skylink.DATA_CHANNEL_STATE.ERROR: + color = 'red'; + break; + case Demo.Skylink.DATA_CHANNEL_STATE.CONNECTING: + color = 'orange'; + break; + case Demo.Skylink.DATA_CHANNEL_STATE.OPEN: + color = 'green'; + break; + } + $('#user' + peerId + ' .7' ).css('color', color); +}); +//--------------------------------------------------- +Demo.Skylink.on('peerUpdated', function (peerId, peerInfo, isSelf) { + if (isSelf) { + $('#isAudioMuted').css('color', + (peerInfo.mediaStatus.audioMuted) ? 'red' : 'green'); + $('#isVideoMuted').css('color', + (peerInfo.mediaStatus.videoMuted) ? 'red' : 'green'); + } else { + $('#user' + peerId + ' .video').css('color', + (peerInfo.mediaStatus.videoMuted) ? 'red' : 'green'); + $('#user' + peerId + ' .audio').css('color', + (peerInfo.mediaStatus.audioMuted) ? 'red' : 'green'); + $('#user' + peerId + ' .name').html(peerInfo.userData); + } + + if ($('#video' + peerId).find('video').length > 0) { + if (peerInfo.mediaStatus.videoMuted) { + $('#video' + peerId)[0].src = ''; + } else { + $('#video' + peerId)[0].src = Demo.Streams[peerId]; + } + } +}); +//--------------------------------------------------- +Demo.Skylink.on('roomLock', function (isLocked, peerId, peerInfo, isSelf) { + $('#display_room_status').html((isLocked) ? 'Locked' : 'Not Locked'); +}); +//--------------------------------------------------- +Demo.Skylink.on('channelOpen', function () { + $('#channel').css('color','green'); + $('#channel').html('Active'); +}); +//--------------------------------------------------- +Demo.Skylink.on('channelClose', function () { + $('#leave_room_btn').hide(); + $('#channel').css('color','red'); + $('#channel').html('Closed'); +}); +//--------------------------------------------------- +Demo.Skylink.on('channelMessage', function (){ + $('#channel').css('color','00FF00'); + $('#channel').html('Connecting...'); + setTimeout(function () { + $('#channel').css('color','green'); + $('#channel').html('Active'); + }, 1000); +}); +//--------------------------------------------------- +Demo.Skylink.on('channelError', function (error) { + Demo.Methods.displayChatMessage('System', 'Channel Error:
' + (error.message || error)); +}); +//--------------------------------------------------- +Demo.Skylink.on('mediaAccessError', function (error) { + alert((error.message || error)); +}); + +Demo.Skylink.on('serverPeerJoined', function (serverPeerId, serverPeerType) { + console.info('serverPeerJoined', serverPeerId, serverPeerType); +}); + +Demo.Skylink.on('serverPeerLeft', function (serverPeerId, serverPeerType) { + console.info('serverPeerLeft', serverPeerId, serverPeerType); +}); + +Demo.Skylink.on('peerJoined', function (peerId, peerInfo, isSelf) { + console.info('peerJoined', peerId, peerInfo, isSelf); +}); + +Demo.Skylink.on('peerLeft', function (peerId, peerInfo, isSelf) { + console.info('peerLeft', peerId, peerInfo, isSelf); +}); + +Demo.Skylink.on('peerRestart', function (peerId, peerInfo, isSelf) { + console.info('peerRestart', peerId, peerInfo, isSelf); +}); + +Demo.Skylink.on('serverPeerRestart', function (serverPeerId, serverPeerType) { + console.info('serverPeerRestart', serverPeerId, serverPeerType); +}); + +//------------- join room --------------------------- +var displayName = 'name_' + 'user_' + Math.floor((Math.random() * 1000) + 1); + +Demo.Skylink.init(config, function (error, success) { + if (success) { + Demo.Skylink.joinRoom({ + userData: displayName, + audio: { stereo: true }, + video: { + resolution: { + width: 1280, + height: 720 + } + } + }); + } +}); + +/******************************************************** + DOM Events +*********************************************************/ +$(document).ready(function () { + //--------------------------------------------------- + $('#display_app_id').html(config.apiKey); + //--------------------------------------------------- + $('#chat_input').keyup(function(e) { + e.preventDefault(); + if (e.keyCode === 13) { + if ($('#send_data_channel').prop('checked')) { + if (selectedPeers.length > 0) { + Demo.Skylink.sendP2PMessage($('#chat_input').val(), selectedPeers); + } else { + Demo.Skylink.sendP2PMessage($('#chat_input').val()); + } + } else { + if (selectedPeers.length > 0) { + Demo.Skylink.sendMessage($('#chat_input').val(), selectedPeers); + } else { + Demo.Skylink.sendMessage($('#chat_input').val()); + } + } + $('#chat_input').val(''); + } + }); + //--------------------------------------------------- + $('#file_input').change(function() { + Demo.Files = $(this)[0].files; + }); + //--------------------------------------------------- + $('#dataURL_input').change(function() { + Demo.DataURL = $(this)[0].files; + }); + //--------------------------------------------------- + $('#send_file_btn').click(function() { + if(!Demo.Files) { + alert('No files selected'); + return; + } else { + if(Demo.Files.length > 0) { + $(Demo.Files)[0].disabled = true; + console.log('Button temporarily disabled to prevent crash'); + } + } + for(var i=0; i < Demo.Files.length; i++) { + var file = Demo.Files[i]; + if(file.size <= Demo.FILE_SIZE_LIMIT) { + if (selectedPeers.length > 0) { + Demo.Skylink.sendBlobData(file, selectedPeers); + } else { + Demo.Skylink.sendBlobData(file); + } + $('#file_input').val(''); + } else { + alert('File "' + file.name + '"" exceeded the limit of 200MB.\n' + + 'We only currently support files up to 200MB for this demo.'); + } + } + $('#send_file_btn')[0].disabled = false; + }); + //--------------------------------------------------- + $('#send_dataURL_btn').click(function() { + if(!Demo.DataURL) { + alert('No files selected'); + return; + } else { + if(Demo.Files.length > 0) { + $(Demo.Files)[0].disabled = true; + console.log('Button temporarily disabled to prevent crash'); + } + } + + for(var i=0; i < Demo.DataURL.length; i++) { + var file = Demo.DataURL[i]; + + var fr = new FileReader(); + + fr.onload = function () { + if(file.size <= 1024 * 1024 * 2) { + if (selectedPeers.length > 0) { + Demo.Skylink.sendURLData(fr.result, selectedPeers); + } else { + Demo.Skylink.sendURLData(fr.result); + } + $('#dataURL_input').val(''); + } else { + alert('File "' + file.name + '"" exceeded the limit of 2MB.\n' + + 'We only currently support files up to 2MB for this demo.'); + } + }; + + fr.readAsDataURL(file); + } + $('#send_dataURL_btn')[0].disabled = false; + }); + //--------------------------------------------------- + $('#update_user_info_btn').click(function () { + Demo.Skylink.setUserData($('#display_user_info').val()); + }); + //--------------------------------------------------- + $('#lock_btn').click(function () { + Demo.Skylink.lockRoom(); + }); + //--------------------------------------------------- + $('#unlock_btn').click(function () { + Demo.Skylink.unlockRoom(); + }); + //--------------------------------------------------- + $('#enable_audio_btn').click(function () { + Demo.Skylink.enableAudio(); + }); + //--------------------------------------------------- + $('#disable_audio_btn').click(function () { + Demo.Skylink.disableAudio(); + }); + //--------------------------------------------------- + $('#stop_stream_btn').click(function () { + Demo.Skylink.stopStream(); + }); + //--------------------------------------------------- + $('#enable_video_btn').click(function () { + Demo.Skylink.enableVideo(); + }); + //--------------------------------------------------- + $('#disable_video_btn').click(function () { + Demo.Skylink.disableVideo(); + }); + //--------------------------------------------------- + $('#leave_room_btn').click(function () { + Demo.Skylink.leaveRoom(); + }); + $('#restart_btn').click(function () { + Demo.Skylink.refreshConnection(); + }); + $('#message_btn').click(function () { + for(var i=0; i<20; i++){ + Demo.Skylink.sendMessage('message'+i); + } + }); + $('#get_btn').click(function () { + var displayName = Demo.Skylink.getUserData(); + if ($('#show_all').prop('checked')){ + Demo.Skylink.getPeers(true, function(error, success){ + if (error){ + alert('An error occurred while retrieving peer list',error); + } + else{ + + var timestamp = new Date(); + $('#chat_log').append(Demo.Methods.displayChatItemHTML(displayName, timestamp, JSON.stringify(success), true)); + $('#chat_body').animate({ + scrollTop: $('#chat_body').get(0).scrollHeight + }, 500); + + } + }); + } + else{ + Demo.Skylink.getPeers(function(error, success){ + if (error){ + alert('An error occurred while retrieving peer list',error); + } + else{ + + var timestamp = new Date(); + $('#chat_log').append(Demo.Methods.displayChatItemHTML(displayName, timestamp, JSON.stringify(success), true)); + $('#chat_body').animate({ + scrollTop: $('#chat_body').get(0).scrollHeight + }, 500); + + } + }); + } + }); + $('#introduce_btn').click(function () { + Demo.Skylink.introducePeer($('#peer1').val(), $('#peer2').val()); + }); + $('#share_screen_btn').click(function () { + Demo.Skylink.shareScreen(function (data, error) { + console.info(data, error); + }); + }); + $('#stop_screen_btn').click(function () { + Demo.Skylink.stopScreen(); + }); + + window.selectTargetPeer = function(dom) { + var peerId = $(dom).attr('target'); + var panelDom = $('#selected_users_panel'); + + if (!dom.checked) { + $('#' + peerId + '-selected-user').remove(); + + var index = selectedPeers.indexOf(peerId); + + if (index > -1) { + selectedPeers.splice(index, 1); + } + + if ($(panelDom).find('.selected-users em').length === 0) { + $(panelDom).find('.all').show(); + } + } else { + $(panelDom).find('.selected-users').append('Peer ' + peerId + ''); + $(panelDom).find('.all').show(); + selectedPeers.push(peerId); + } + } + + $('#clear-selected-users').click(function () { + $('#selected_users_panel .selected-users').html(''); + $('.select-user').each(function () { + $(this)[0].checked = false + }); + $('#selected_users_panel .all').show(); + selectedPeers = []; + }) +}); diff --git a/demo/privileged/unauto-unpriv/css/favicon.ico b/demo/privileged/unauto-unpriv/css/favicon.ico new file mode 100644 index 000000000..96865c994 Binary files /dev/null and b/demo/privileged/unauto-unpriv/css/favicon.ico differ diff --git a/demo/privileged/unauto-unpriv/css/style.css b/demo/privileged/unauto-unpriv/css/style.css new file mode 100644 index 000000000..e9ad46a6c --- /dev/null +++ b/demo/privileged/unauto-unpriv/css/style.css @@ -0,0 +1,136 @@ +.navbar-white { + background:#fff; +} +#get_user_media_btn, +#join_room_btn, +#leave_room_btn, +#presence_panel, +#file_panel, +#file_list_panel { + display:none; +} +.circle { + color:red; + border:solid 1px; + border-radius:50%; + padding:5px; + margin-bottom:7px; + font-size:10px; +} +.table { + font-size:12px; + word-break:break-word; +} +.table td:first-child { + font-weight:bold; + width:38%; +} +.table.upload-table td:first-child { + font-weight:normal; + width:85%; +} +#credential_panel { + margin-bottom:0; + border-left:0; + border-right:0; + box-shadow:none; + border-radius:0; +} +#credential_panel .panel-body { + padding-bottom:0; +} +#credential_panel .panel-body .form-group { + text-align:left; +} +#credential_panel .panel-body .form-group .title, +#credential_panel .panel-body .form-group .control-group { + display:inline-block; + vertical-align:top; +} +#credential_panel .panel-body .form-group .title { + margin-top:0; + float:left; +} +#credential_panel .panel-body .form-group .title span { + display:block; + margin-bottom:5px; +} +#credential_panel .panel-body .form-group .control-group { +} +video, object { + background:#444; + border:solid 2px #fff; + padding:0!important; +} +video#local_video, +object#local_video { + right:15px; + position:absolute; + z-index:9999; +} +#file_body { + max-height:200px; + overflow-y:auto; +} +#chat_panel { + margin:15px 0 45px; +} +#chat_body { + max-height:200px; + overflow-y:auto; +} +.list-group-item-heading em { + float:right; + font-style:normal; + color:#888; +} +.chat-item { + border:0; + padding:0 0 15px 0; +} +.chat-item img { + width: 250px; +} +#chat_input { + display:block; + width:100%; +} +.control_settings .col { + margin: 7px 0; +} +#leave_room_btn { + margin-left:12px; +} +.control_settings .btn-group { + width: 100%; +} +footer { + background:#f5f5f5; + padding:12px 0 0; + border-top:solid 1px #e0e0e0; +} +.selected-users em { + font-style: normal; + font-size: 12px; + margin-right: 12px; +} +@media screen and (max-width:1999px){ + #credential_panel .panel-body { + margin-bottom:15px; + } + #credential_panel .panel-body button { + margin-left:14px; + } +} +@media screen and (max-width:991px){ + video, object { + display:block; + width:100%; + } + video#local_video, + object#local_video { + right:0; + position:static; + display:block + } +} \ No newline at end of file diff --git a/demo/privileged/unauto-unpriv/img/default.png b/demo/privileged/unauto-unpriv/img/default.png new file mode 100644 index 000000000..d99a885dc Binary files /dev/null and b/demo/privileged/unauto-unpriv/img/default.png differ diff --git a/demo/privileged/unauto-unpriv/img/no_profile.jpg b/demo/privileged/unauto-unpriv/img/no_profile.jpg new file mode 100644 index 000000000..a4982376f Binary files /dev/null and b/demo/privileged/unauto-unpriv/img/no_profile.jpg differ diff --git a/demo/privileged/unauto-unpriv/index.html b/demo/privileged/unauto-unpriv/index.html new file mode 100644 index 000000000..58ac8ba7d --- /dev/null +++ b/demo/privileged/unauto-unpriv/index.html @@ -0,0 +1,221 @@ + + + + Temasys: My Room Example + + + + + + + + + + +
+ +
+ +
+
+
+
+
+
Connection Information
+
+ + + + + + + + + + + + + + + + + + + + + + + +
App ID
User IDNot in Room
Channel status-
Room Lock Status-
Media stream status + + +
+
+
+
+
Connected Peers
+
+ + +
+
+
+
+
File Transfers
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + +
+ + +
+
+
+
+ + + + + + + +
+
+
+
+
Targeted peers to message / file transfer to
+

Peers: All

+

+
+
+
+
+ + + + +
+
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+
+

+ © Temasys Communications Pte Ltd 2014. All Rights Reserved. +

+
+
+ + + + + diff --git a/demo/privileged/unauto-unpriv/js/main.js b/demo/privileged/unauto-unpriv/js/main.js new file mode 100644 index 000000000..ea0dd44b1 --- /dev/null +++ b/demo/privileged/unauto-unpriv/js/main.js @@ -0,0 +1,662 @@ +/******************************************************** + API Settings +*********************************************************/ +var Demo = Demo || {}; +Demo.FILE_SIZE_LIMIT = 1024 * 1024 * 200; +Demo.Peers = 0; +Demo.Files = []; +Demo.Streams = []; +Demo.Methods = {}; +Demo.Skylink = new Skylink(); + +var _peerId = null; + +var selectedPeers = []; + +//Demo.Skylink.setLogLevel(4); + + +Demo.Methods.displayFileItemHTML = function (content) { + return '

' + content.name + '' + content.size + ' B

' + + ((content.isUpload) ? ('' + + '' + + '
' + + ' Upload Status
') : ('
' + + '
Downloading...
')) + + '

Download file

'; +}; + +Demo.Methods.displayChatItemHTML = function (peerId, timestamp, content, isPrivate) { + var Hours, Minutes, Seconds; + if (timestamp.getHours() < 10) + Hours = '0' + timestamp.getHours(); + else + Hours = timestamp.getHours(); + if (timestamp.getMinutes() < 10) + Minutes = '0' + timestamp.getMinutes(); + else + Minutes = timestamp.getMinutes(); + if (timestamp.getSeconds() < 10) + Seconds = '0' + timestamp.getSeconds(); + else + Seconds = timestamp.getSeconds(); + + return '
' + + '

' + '' + peerId + '' + + '' + Hours + + ':' + Minutes + ':' + Seconds + + '

' + '

' + + (isPrivate ? '[pvt msg] ' : '') + content + + (isPrivate ? '' : '') + '

'; +}; + +Demo.Methods.displayChatMessage = function (peerId, content, isPrivate) { + var timestamp = new Date(); + var isFile = typeof content === 'object'; + + //console.info(isFile); + var element = (isFile) ? '#file_log' : '#chat_log'; + var element_body = (isFile) ? '#file_body' : '#chat_body'; + if (isFile) { + content = Demo.Methods.displayFileItemHTML(content); + } + + $(element).append(Demo.Methods.displayChatItemHTML(peerId, timestamp, content, isPrivate)); + $(element_body).animate({ + scrollTop: $('#chat_body').get(0).scrollHeight + }, 500); +}; + +/******************************************************** + Skylink Events +*********************************************************/ +//--------------------------------------------------- +Demo.Skylink.on('incomingData', function (data, transferId, peerId, transferInfo, isSelf) { + if (transferInfo.dataType !== 'blob') { + console.info('incomingData', data, transferId, peerId, transferInfo, isSelf); + //displayChatItemHTML = function (peerId, timestamp, content, isPrivate) + Demo.Methods.displayChatMessage(peerId, '', false); + } +}); +Demo.Skylink.on('incomingDataRequest', function (transferId, peerId, transferInfo, isSelf) { + if (!isSelf && transferInfo.dataType !== 'blob') { + Demo.Skylink.respondBlobRequest(peerId, transferId, true); + } +}) +Demo.Skylink.on('dataTransferState', function (state, transferId, peerId, transferInfo, error){ + transferInfo = transferInfo || {}; + + if (transferInfo.dataType !== 'blob') { + return; + } + + switch (state) { + case Demo.Skylink.DATA_TRANSFER_STATE.UPLOAD_REQUEST : + var result = confirm('Accept file "' + transferInfo.name + + '" from ' + peerId + '?\n\n[size: ' + transferInfo.size + ']'); + Demo.Skylink.respondBlobRequest(peerId, transferId, result); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.UPLOAD_STARTED : + var displayName = Demo.Skylink.getUserData(); + transferInfo.transferId = transferId; + transferInfo.isUpload = true; + transferInfo.data = URL.createObjectURL(transferInfo.data); + Demo.Methods.displayChatMessage(displayName, transferInfo); + Demo.Methods.displayChatMessage(displayName, 'File sent: ' + transferInfo.name); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.DOWNLOAD_STARTED : + var displayName = Demo.Skylink.getPeerInfo(transferInfo.senderPeerId).userData; + transferInfo.transferId = transferId; + transferInfo.data = '#'; + transferInfo.isUpload = false; + Demo.Methods.displayChatMessage(displayName, transferInfo); + Demo.Methods.displayChatMessage(displayName, 'File sent: ' + transferInfo.name); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.UPLOADING : + var displayName = Demo.Skylink.getPeerInfo(peerId).userData; + if ($('#' + transferId).find('.' + peerId).width() < 1) { + $('#' + transferId).append('' + displayName + + '' + transferInfo.percentage + '%'); + } else { + $('#' + transferId).find('.' + peerId).html(transferInfo.percentage + '%'); + } + break; + case Demo.Skylink.DATA_TRANSFER_STATE.DOWNLOADING : + $('#' + transferId).attr('aria-valuenow', transferInfo.percentage); + $('#' + transferId).css('width', transferInfo.percentage + '%'); + $('#' + transferId).find('span').html(transferInfo.percentage + ' %'); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.UPLOAD_COMPLETED : + var displayName = Demo.Skylink.getPeerInfo(peerId).userData; + Demo.Methods.displayChatMessage(displayName, 'File received: ' + transferInfo.name); + $('#' + transferId).find('.' + peerId).html('✓'); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.DOWNLOAD_COMPLETED : + // If completed, display download button + var displayName = Demo.Skylink.getPeerInfo(peerId).userData; + $('#' + transferId).parent().remove(); + $('#' + transferId + '_btn').attr('href', URL.createObjectURL(transferInfo.data)); + $('#' + transferId + '_btn').css('display', 'block'); + Demo.Methods.displayChatMessage(displayName, 'File received: ' + transferInfo.name); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.REJECTED : + alert('User "' + peerId + '" has rejected your file'); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.ERROR : + alert(error.transferType + ' failed. Reason: \n' + + error.message); + $('#' + transferId).parent().removeClass('progress-bar-info'); + $('#' + transferId).parent().addClass('progress-bar-danger'); + break; + case Demo.Skylink.DATA_TRANSFER_STATE.CANCEL : + alert(error.transferType + ' canceled. Reason: \n' + + error.message); + $('#' + transferId).parent().removeClass('progress-bar-info'); + $('#' + transferId).parent().addClass('progress-bar-danger'); + } +}); +//--------------------------------------------------- +Demo.Skylink.on('incomingMessage', function (message, peerId, peerInfo, isSelf) { + Demo.Methods.displayChatMessage((isSelf) ? 'You' : peerInfo.userData, + ((message.isDataChannel) ? 'P2P' : 'Socket') + ' -> ' + message.targetPeerId + ': ' + + message.content, message.isPrivate); +}); +//--------------------------------------------------- +Demo.Skylink.on('peerRestart', function (peerId, peerInfo, isSelf){ + if (!isSelf) { + $('#user' + peerId + ' .video').css('color', + (peerInfo.mediaStatus.videoMuted) ? 'red' : 'green'); + $('#user' + peerId + ' .audio').css('color', + (peerInfo.mediaStatus.audioMuted) ? 'red' : 'green'); + $('#user' + peerId + ' .name').html(peerInfo.userData); + } +}); +//--------------------------------------------------- +Demo.Skylink.on('peerJoined', function (peerId, peerInfo, isSelf){ + if (isSelf) { + $('#display_user_id').html(peerId); + $('#isAudioMuted').css('color', + (peerInfo.mediaStatus.audioMuted) ? 'red' : 'green'); + $('#isVideoMuted').css('color', + (peerInfo.mediaStatus.videoMuted) ? 'red' : 'green'); + $('#leave_room_btn').show(); + $('#presence_panel').show(); + $('#chat_input').removeAttr('disabled'); + // If not supportive of File, FileReader, Blob quit + if (window.File && window.FileReader && window.FileList && window.Blob) { + $('#file_panel').show(); + $('#file_list_panel').show(); + } + } else { + _peerId = peerId; + Demo.Methods.displayChatMessage('System', 'Peer ' + peerId + ' joined the room'); + var newListEntry = '' + + '' + peerInfo.userData + '
' + + ''; + var titleList = [ + 'Joined Room', 'Handshake: Welcome', 'Handshake: Offer', + 'Handshake: Answer', 'Candidate Generation state', 'ICE Connection state', + 'Peer Connection state', 'Data Channel Connection state', + 'MediaStream: Video', 'MediaStream: Audio' + ]; + var glyphiconList = [ + 'glyphicon-log-in', 'glyphicon-hand-right', 'glyphicon-hand-left', + 'glyphicon-thumbs-up', 'glyphicon-flash', 'glyphicon-magnet', + 'glyphicon-user', 'glyphicon-transfer', 'glyphicon-facetime-video video', + 'glyphicon-volume-up audio' + ]; + for( var i = 0; i < 10; i++) { + newListEntry += '   '; + } + newListEntry += ''; + $('#presence_list').append(newListEntry); + $('#user' + peerId + ' .0').css('color','green'); + $('#user' + peerId + ' .video').css('color', + (peerInfo.mediaStatus.videoMuted) ? 'red' : 'green'); + $('#user' + peerId + ' .audio').css('color', + (peerInfo.mediaStatus.audioMuted) ? 'red' : 'green'); + } +}); +//--------------------------------------------------- +Demo.Skylink.on('incomingStream', function (peerId, stream, isSelf, peerInfo){ + if (!isSelf) { + Demo.Peers += 1; + } + var peerVideo; + + if ($('#video' + peerId).length === 0) { + peerVideo = document.createElement('video'); + peerVideo.id = 'video' + peerId; + peerVideo.className = 'col-md-6'; + if (window.webrtcDetectedBrowser !== 'IE') { + peerVideo.autoplay = 'autoplay'; + } + + // mutes user's video + if (isSelf && window.webrtcDetectedBrowser !== 'IE') { + peerVideo.muted = 'muted'; + } + $('#peer_video_list').append(peerVideo); + } else { + peerVideo = document.getElementById('video' + peerId); + } + + attachMediaStream(peerVideo, stream); + Demo.Streams[peerId] = Demo.Streams[peerId] || {}; + Demo.Streams[peerId][stream.id] = peerVideo.src; +}); +//--------------------------------------------------- +Demo.Skylink.on('mediaAccessSuccess', function (stream){ + Demo.Methods.displayChatMessage('System', 'Audio and video access is allowed.'); +}); +//--------------------------------------------------- +Demo.Skylink.on('mediaAccessError', function (error){ + alert((typeof error === 'object') ? error.message : error); + Demo.Methods.displayChatMessage('System', 'Failed to join room as video and audio stream is required.'); +}); +//--------------------------------------------------- +Demo.Skylink.on('readyStateChange', function (state, error){ + if (state === Demo.Skylink.READY_STATE_CHANGE.ERROR) { + for (var errorCode in Demo.Skylink.READY_STATE_CHANGE_ERROR) { + if (Demo.Skylink.READY_STATE_CHANGE_ERROR[errorCode] === + error.errorCode) { + alert('An error occurred parsing and retrieving server code.\n' + + 'Error was: ' + errorCode); + break; + } + } + } + $('#channel_status').show(); +}); +//--------------------------------------------------- +Demo.Skylink.on('peerLeft', function (peerId, peerInfo, isSelf){ + //console.info('peerLeft', peerId, peerInfo, isSelf); + Demo.Methods.displayChatMessage('System', 'Peer ' + peerId + ' has left the room'); + Demo.Peers -= 1; + $('#video' + peerId).remove(); + $('#user' + peerId).remove(); + delete Demo.Streams[peerId]; + var index = selectedPeers.indexOf(peerId); + + if (index > -1) { + selectedPeers.splice(index, 1); + } +}); +//--------------------------------------------------- +Demo.Skylink.on('handshakeProgress', function (state, peerId) { + var stage = 0; + switch( state ){ + case Demo.Skylink.HANDSHAKE_PROGRESS.WELCOME: + stage = 1; + break; + case Demo.Skylink.HANDSHAKE_PROGRESS.OFFER: + stage = 2; + break; + case Demo.Skylink.HANDSHAKE_PROGRESS.ANSWER: + stage = 3; + break; + } + for (var i=0; i<=stage; i++) { + $('#user' + peerId + ' .' + i ).css('color', 'green'); + } +}); +//--------------------------------------------------- +Demo.Skylink.on('candidateGenerationState', function (state, peerId) { + var color = 'orange'; + switch( state ){ + case Demo.Skylink.CANDIDATE_GENERATION_STATE.COMPLETED: + color = 'green'; break; + } + $('#user' + peerId + ' .4' ).css('color', color); +}); +//--------------------------------------------------- +Demo.Skylink.on('iceConnectionState', function (state, peerId) { + var color = 'orange'; + switch(state){ + case Demo.Skylink.ICE_CONNECTION_STATE.STARTING: + case Demo.Skylink.ICE_CONNECTION_STATE.CLOSED: + case Demo.Skylink.ICE_CONNECTION_STATE.FAILED: + color = 'red'; + break; + case Demo.Skylink.ICE_CONNECTION_STATE.CHECKING: + case Demo.Skylink.ICE_CONNECTION_STATE.DISCONNECTED: + color = 'orange'; + break; + case Demo.Skylink.ICE_CONNECTION_STATE.CONNECTED: + case Demo.Skylink.ICE_CONNECTION_STATE.COMPLETED: + color = 'green'; + break; + default: + console.error('ICE State:', state, peerId); + } + $('#user' + peerId + ' .5' ).css('color', color); + + if (state === Demo.Skylink.ICE_CONNECTION_STATE.CHECKING){ + setTimeout(function(){ + if ($('#user' + peerId + ' .5' ).css('color') === 'orange') { + $('#user' + peerId).remove(); + } + }, 30000); + } +}); +//--------------------------------------------------- +Demo.Skylink.on('peerConnectionState', function (state, peerId) { + var color = 'red'; + switch(state){ + case Demo.Skylink.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER: + case Demo.Skylink.PEER_CONNECTION_STATE.HAVE_REMOTE_PRANSWER: + case Demo.Skylink.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER: + case Demo.Skylink.PEER_CONNECTION_STATE.HAVE_LOCAL_PRANSWER: + color = 'orange'; + break; + case Demo.Skylink.PEER_CONNECTION_STATE.CLOSED: + color = 'red'; + break; + case Demo.Skylink.PEER_CONNECTION_STATE.STABLE: + color = 'green'; + break; + } + $('#user' + peerId + ' .6' ).css('color', color); +}); +//--------------------------------------------------- +Demo.Skylink.on('dataChannelState', function (state, peerId) { + var color = 'red'; + switch (state) { + case Demo.Skylink.DATA_CHANNEL_STATE.ERROR: + color = 'red'; + break; + case Demo.Skylink.DATA_CHANNEL_STATE.CONNECTING: + color = 'orange'; + break; + case Demo.Skylink.DATA_CHANNEL_STATE.OPEN: + color = 'green'; + break; + } + $('#user' + peerId + ' .7' ).css('color', color); +}); +//--------------------------------------------------- +Demo.Skylink.on('peerUpdated', function (peerId, peerInfo, isSelf) { + if (isSelf) { + $('#isAudioMuted').css('color', + (peerInfo.mediaStatus.audioMuted) ? 'red' : 'green'); + $('#isVideoMuted').css('color', + (peerInfo.mediaStatus.videoMuted) ? 'red' : 'green'); + } else { + $('#user' + peerId + ' .video').css('color', + (peerInfo.mediaStatus.videoMuted) ? 'red' : 'green'); + $('#user' + peerId + ' .audio').css('color', + (peerInfo.mediaStatus.audioMuted) ? 'red' : 'green'); + $('#user' + peerId + ' .name').html(peerInfo.userData); + } + + if ($('#video' + peerId).find('video').length > 0) { + if (peerInfo.mediaStatus.videoMuted) { + $('#video' + peerId)[0].src = ''; + } else { + $('#video' + peerId)[0].src = Demo.Streams[peerId]; + } + } +}); +//--------------------------------------------------- +Demo.Skylink.on('roomLock', function (isLocked, peerId, peerInfo, isSelf) { + $('#display_room_status').html((isLocked) ? 'Locked' : 'Not Locked'); +}); +//--------------------------------------------------- +Demo.Skylink.on('channelOpen', function () { + $('#channel').css('color','green'); + $('#channel').html('Active'); +}); +//--------------------------------------------------- +Demo.Skylink.on('channelClose', function () { + $('#leave_room_btn').hide(); + $('#channel').css('color','red'); + $('#channel').html('Closed'); +}); +//--------------------------------------------------- +Demo.Skylink.on('channelMessage', function (){ + $('#channel').css('color','00FF00'); + $('#channel').html('Connecting...'); + setTimeout(function () { + $('#channel').css('color','green'); + $('#channel').html('Active'); + }, 1000); +}); +//--------------------------------------------------- +Demo.Skylink.on('channelError', function (error) { + Demo.Methods.displayChatMessage('System', 'Channel Error:
' + (error.message || error)); +}); +//--------------------------------------------------- +Demo.Skylink.on('mediaAccessError', function (error) { + alert((error.message || error)); +}); + +Demo.Skylink.on('serverPeerJoined', function (serverPeerId, serverPeerType) { + console.info('serverPeerJoined', serverPeerId, serverPeerType); +}); + +Demo.Skylink.on('serverPeerLeft', function (serverPeerId, serverPeerType) { + console.info('serverPeerLeft', serverPeerId, serverPeerType); +}); + +Demo.Skylink.on('peerJoined', function (peerId, peerInfo, isSelf) { + console.info('peerJoined', peerId, peerInfo, isSelf); +}); + +Demo.Skylink.on('peerLeft', function (peerId, peerInfo, isSelf) { + console.info('peerLeft', peerId, peerInfo, isSelf); +}); + +Demo.Skylink.on('peerRestart', function (peerId, peerInfo, isSelf) { + console.info('peerRestart', peerId, peerInfo, isSelf); +}); + +Demo.Skylink.on('serverPeerRestart', function (serverPeerId, serverPeerType) { + console.info('serverPeerRestart', serverPeerId, serverPeerType); +}); + +//------------- join room --------------------------- +var displayName = 'name_' + 'user_' + Math.floor((Math.random() * 1000) + 1); + +Demo.Skylink.init(config, function (error, success) { + if (success) { + Demo.Skylink.joinRoom({ + userData: displayName, + audio: { stereo: true }, + video: { + resolution: { + width: 1280, + height: 720 + } + } + }); + } +}); + +/******************************************************** + DOM Events +*********************************************************/ +$(document).ready(function () { + //--------------------------------------------------- + $('#display_app_id').html(config.apiKey); + //--------------------------------------------------- + $('#chat_input').keyup(function(e) { + e.preventDefault(); + if (e.keyCode === 13) { + if ($('#send_data_channel').prop('checked')) { + if (selectedPeers.length > 0) { + Demo.Skylink.sendP2PMessage($('#chat_input').val(), selectedPeers); + } else { + Demo.Skylink.sendP2PMessage($('#chat_input').val()); + } + } else { + if (selectedPeers.length > 0) { + Demo.Skylink.sendMessage($('#chat_input').val(), selectedPeers); + } else { + Demo.Skylink.sendMessage($('#chat_input').val()); + } + } + $('#chat_input').val(''); + } + }); + //--------------------------------------------------- + $('#file_input').change(function() { + Demo.Files = $(this)[0].files; + }); + //--------------------------------------------------- + $('#dataURL_input').change(function() { + Demo.DataURL = $(this)[0].files; + }); + //--------------------------------------------------- + $('#send_file_btn').click(function() { + if(!Demo.Files) { + alert('No files selected'); + return; + } else { + if(Demo.Files.length > 0) { + $(Demo.Files)[0].disabled = true; + console.log('Button temporarily disabled to prevent crash'); + } + } + for(var i=0; i < Demo.Files.length; i++) { + var file = Demo.Files[i]; + if(file.size <= Demo.FILE_SIZE_LIMIT) { + if (selectedPeers.length > 0) { + Demo.Skylink.sendBlobData(file, selectedPeers); + } else { + Demo.Skylink.sendBlobData(file); + } + $('#file_input').val(''); + } else { + alert('File "' + file.name + '"" exceeded the limit of 200MB.\n' + + 'We only currently support files up to 200MB for this demo.'); + } + } + $('#send_file_btn')[0].disabled = false; + }); + //--------------------------------------------------- + $('#send_dataURL_btn').click(function() { + if(!Demo.DataURL) { + alert('No files selected'); + return; + } else { + if(Demo.Files.length > 0) { + $(Demo.Files)[0].disabled = true; + console.log('Button temporarily disabled to prevent crash'); + } + } + + for(var i=0; i < Demo.DataURL.length; i++) { + var file = Demo.DataURL[i]; + + var fr = new FileReader(); + + fr.onload = function () { + if(file.size <= 1024 * 1024 * 2) { + if (selectedPeers.length > 0) { + Demo.Skylink.sendURLData(fr.result, selectedPeers); + } else { + Demo.Skylink.sendURLData(fr.result); + } + $('#dataURL_input').val(''); + } else { + alert('File "' + file.name + '"" exceeded the limit of 2MB.\n' + + 'We only currently support files up to 2MB for this demo.'); + } + }; + + fr.readAsDataURL(file); + } + $('#send_dataURL_btn')[0].disabled = false; + }); + //--------------------------------------------------- + $('#update_user_info_btn').click(function () { + Demo.Skylink.setUserData($('#display_user_info').val()); + }); + //--------------------------------------------------- + $('#lock_btn').click(function () { + Demo.Skylink.lockRoom(); + }); + //--------------------------------------------------- + $('#unlock_btn').click(function () { + Demo.Skylink.unlockRoom(); + }); + //--------------------------------------------------- + $('#enable_audio_btn').click(function () { + Demo.Skylink.enableAudio(); + }); + //--------------------------------------------------- + $('#disable_audio_btn').click(function () { + Demo.Skylink.disableAudio(); + }); + //--------------------------------------------------- + $('#stop_stream_btn').click(function () { + Demo.Skylink.stopStream(); + }); + //--------------------------------------------------- + $('#enable_video_btn').click(function () { + Demo.Skylink.enableVideo(); + }); + //--------------------------------------------------- + $('#disable_video_btn').click(function () { + Demo.Skylink.disableVideo(); + }); + //--------------------------------------------------- + $('#leave_room_btn').click(function () { + Demo.Skylink.leaveRoom(); + }); + $('#restart_btn').click(function () { + Demo.Skylink.refreshConnection(); + }); + $('#message_btn').click(function () { + for(var i=0; i<20; i++){ + Demo.Skylink.sendMessage('message'+i); + } + }); + $('#share_screen_btn').click(function () { + Demo.Skylink.shareScreen(function (data, error) { + console.info(data, error); + }); + }); + $('#stop_screen_btn').click(function () { + Demo.Skylink.stopScreen(); + }); + + window.selectTargetPeer = function(dom) { + var peerId = $(dom).attr('target'); + var panelDom = $('#selected_users_panel'); + + if (!dom.checked) { + $('#' + peerId + '-selected-user').remove(); + + var index = selectedPeers.indexOf(peerId); + + if (index > -1) { + selectedPeers.splice(index, 1); + } + + if ($(panelDom).find('.selected-users em').length === 0) { + $(panelDom).find('.all').show(); + } + } else { + $(panelDom).find('.selected-users').append('Peer ' + peerId + ''); + $(panelDom).find('.all').show(); + selectedPeers.push(peerId); + } + } + + $('#clear-selected-users').click(function () { + $('#selected_users_panel .selected-users').html(''); + $('.select-user').each(function () { + $(this)[0].checked = false + }); + $('#selected_users_panel .all').show(); + selectedPeers = []; + }) +}); diff --git a/doc-style/assets/css/style.css b/doc-style/assets/css/style.css index c5bbc1bfe..ba8e7a3da 100644 --- a/doc-style/assets/css/style.css +++ b/doc-style/assets/css/style.css @@ -276,6 +276,89 @@ h3 code { #doc-type-select.scroll-fix-navbar { top: 115px; } +.btn-navbar { + padding: 5px 7px!important; + margin: 10px 0 8px; + margin-left: 15px; + color: #fff!important; + background: none; + border-color: #fff; +} +.btn-navbar:hover { + background: #fff; + color: #000; +} +blockquote { + padding: 0!important; + border: 0!important; + margin: 28px; + font-size: 1em; +} + +blockquote em { + margin: 10px 0 5px; + display: block; + font-size: .9em; + margin-left: -18px; + font-style: normal; + opacity: .85; +} + +blockquote h6 { + font-weight: 600; + margin-left: -28px; +} + +blockquote ol { + padding: 0; + list-style-position: inside; + font-size: .9em; +} + +blockquote ol li { + margin: 5px 0; +} + +blockquote ol li span { + padding: 1px 5px; + border: solid 1px #888; + border-radius: 5px; + font-size: .8em; + margin-left: 17px; + margin-top: 5px; + display: inline-block; +} + +blockquote ol li span:first-child { + margin-left: 5px; + margin-top: 0; +} + +blockquote ol li small { + margin: 3px 0; + margin-left: 23px; + font-size: .9em; +} + +blockquote ol li section { + display: block; + margin: 10px 0 10px; + margin-left: 25px; + font-size: .9em; + font-style: normal; + color: #888; +} + +blockquote ol li section ul { + padding: 0; +} + +blockquote:before, +blockquote:after, +blockquote small:before, +blockquote small:after { + content: ""!important; +} @media (max-width: 991px) { .section-doc-group .col-md-3 { display: none; diff --git a/doc-style/layouts/main.handlebars b/doc-style/layouts/main.handlebars index 35fe080a2..a8259626c 100644 --- a/doc-style/layouts/main.handlebars +++ b/doc-style/layouts/main.handlebars @@ -2,7 +2,7 @@ - {{htmlTitle}} + SkylinkJS {{projectVersion}} diff --git a/doc-style/partials/method.handlebars b/doc-style/partials/method.handlebars index 66a18ecba..b439f9309 100644 --- a/doc-style/partials/method.handlebars +++ b/doc-style/partials/method.handlebars @@ -105,9 +105,15 @@ {{/if}} - {{#if since}} -      Available since {{since}} - {{/if}} + + {{#if since}} +      Available since {{since}} + {{/if}} + + {{#if partof}} +    |   Part of » {{partof}} + {{/if}} +
diff --git a/doc-style/partials/sidebar.handlebars b/doc-style/partials/sidebar.handlebars index 261368f75..a7b585b65 100644 --- a/doc-style/partials/sidebar.handlebars +++ b/doc-style/partials/sidebar.handlebars @@ -1,12 +1,18 @@ @@ -32,19 +32,25 @@ - JSVersion: 0.6.2 + JSVersion: 0.6.3