Browse Source

Jingle reintegration, first preview

pull/277/head
Timothée Jaussoin 9 years ago
parent
commit
b83e9eb372
  1. 2
      app/assets/js/movim_utils.js
  2. 10
      app/assets/js/movim_websocket.js
  3. 2
      app/controllers/VisioController.php
  4. 15
      app/models/caps/Caps.php
  5. 5
      app/models/contact/Contact.php
  6. 8
      app/models/contact/ContactDAO.php
  7. 1
      app/views/chat.tpl
  8. 2
      app/views/conf.tpl
  9. 2
      app/views/contact.tpl
  10. 2
      app/views/group.tpl
  11. 2
      app/views/help.tpl
  12. 2
      app/views/news.tpl
  13. 1
      app/views/page.tpl
  14. 34
      app/views/visio.tpl
  15. 7
      app/widgets/Contact/_contact.tpl
  16. 2
      app/widgets/Menu/_menu_add.tpl
  17. 2
      app/widgets/System/system.tpl
  18. 137
      app/widgets/Visio/Visio.php
  19. 34
      app/widgets/Visio/visio.css
  20. 348
      app/widgets/Visio/visio.js
  21. 26
      app/widgets/Visio/visio.tpl
  22. 13
      app/widgets/VisioLink/VisioLink.php
  23. 15
      app/widgets/VisioLink/visiolink.js
  24. 0
      app/widgets/VisioLink/visiolink.tpl
  25. 2
      composer.json
  26. 51
      composer.lock
  27. 89
      lib/JingletoSDP.php
  28. 262
      lib/SDPtoJingle.php
  29. 7
      src/Movim/Bootstrap.php
  30. 1
      src/Movim/Controller/Base.php
  31. 4
      src/Movim/Controller/Front.php
  32. 39
      src/Movim/Daemon/Session.php
  33. 4
      themes/material/css/color.css

2
app/assets/js/movim_utils.js

@ -219,7 +219,7 @@ var MovimUtils = {
element.classList.add(classname);
}
},
removeClass: function(element,classname) {
removeClass: function(element, classname) {
if (MovimUtils.hasClass(element, classname)) {
element = MovimUtils.getNode(element);
element.classList.remove(classname);

10
app/assets/js/movim_websocket.js

@ -27,6 +27,7 @@ var MovimWebsocket = {
registered: new Array(),
attempts: 1,
pong: false,
blocked: false,
launchAttached : function() {
// We hide the Websocket error
@ -56,7 +57,7 @@ var MovimWebsocket = {
this.connection.close();
}
this.connection = new WebSocket(uri);
this.connection = new WebSocket(uri + '?path=' + MovimUtils.urlParts().page);
this.connection.onopen = function(e) {
console.log("Connection established!");
@ -80,9 +81,16 @@ var MovimWebsocket = {
}
if(obj.func == 'pong') {
console.log('pong');
MovimWebsocket.pong = true;
}
if(obj.func == 'block') {
console.log('block');
MovimWebsocket.clearAttached();
MovimUtils.addClass('body', 'disabled');
}
MovimWebsocket.handle(obj);
}

2
app/controllers/VisioController.php

@ -4,8 +4,8 @@ use Movim\Controller\Base;
class VisioController extends Base
{
function load() {
$this->unique = true;
$this->session_only = true;
$this->raw = true;
}
function dispatch() {

15
app/models/caps/Caps.php

@ -2,14 +2,16 @@
namespace modl;
class Caps extends Model {
class Caps extends Model
{
public $node;
public $category;
public $type;
public $name;
public $features;
public function __construct() {
public function __construct()
{
$this->_struct = '
{
"node" :
@ -27,7 +29,8 @@ class Caps extends Model {
parent::__construct();
}
public function set($query, $node = false) {
public function set($query, $node = false)
{
if(!$node)
$this->node = (string)$query->query->attributes()->node;
else
@ -55,4 +58,10 @@ class Caps extends Model {
$this->features = serialize($fet);
}
}
public function isJingle()
{
$features = unserialize($this->features);
return (in_array('http://jabber.org/protocol/jingle', $features));
}
}

5
app/models/contact/Contact.php

@ -599,6 +599,11 @@ class RosterContact extends Contact
$this->mucrole = $p->mucrole;
}
public function getFullResource()
{
return $this->jid.'/'.$this->resource;
}
public function getCaps()
{
if(!empty($this->node)

8
app/models/contact/ContactDAO.php

@ -360,9 +360,9 @@ class ContactDAO extends SQL {
$this->prepare(
'Contact',
array(
[
'jid' => '%'.$search.'%'
)
]
);
return $this->run('Contact');
}
@ -583,10 +583,10 @@ class ContactDAO extends SQL {
$this->prepare(
'RosterLink',
array(
[
'session' => $this->_user,
'jid' => $jid
)
]
);
if($item)

1
app/views/chat.tpl

@ -1,4 +1,5 @@
<?php $this->widget('Search');?>
<?php $this->widget('VisioLink');?>
<?php $this->widget('Stickers');?>
<nav class="color dark">

2
app/views/conf.tpl

@ -1,4 +1,6 @@
<?php $this->widget('Search');?>
<?php $this->widget('VisioLink');?>
<?php $this->widget('Notification');?>
<nav class="color dark">
<?php $this->widget('Presence');?>

2
app/views/contact.tpl

@ -1,4 +1,6 @@
<?php $this->widget('Notification');?>
<?php $this->widget('Search');?>
<?php $this->widget('VisioLink');?>
<nav class="color dark">
<?php $this->widget('Presence');?>

2
app/views/group.tpl

@ -1,4 +1,6 @@
<?php $this->widget('Search');?>
<?php $this->widget('Notification');?>
<?php $this->widget('VisioLink');?>
<?php $this->widget('Upload'); ?>
<nav class="color dark">

2
app/views/help.tpl

@ -1,4 +1,6 @@
<?php $this->widget('Search');?>
<?php $this->widget('VisioLink');?>
<?php $this->widget('Notification');?>
<nav class="color dark">
<?php $this->widget('Presence');?>

2
app/views/news.tpl

@ -1,4 +1,6 @@
<?php $this->widget('Init');?>
<?php $this->widget('VisioLink');?>
<?php $this->widget('Notification');?>
<?php $this->widget('Upload');?>
<?php $this->widget('Search');?>

1
app/views/page.tpl

@ -67,7 +67,6 @@
</div>
<?php $this->widget('Dialog');?>
<?php $this->widget('Drawer');?>
<?php $this->widget('Notification');?>
<?php $this->content();?>
<script type="text/javascript">if(typeof movim_onload == 'function') { movim_onload(); }</script>
</body>

34
app/views/visio.tpl

@ -1,33 +1 @@
<?php /* -*- mode: html -*- */
?><!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, user-scalable=no";>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<?php
$this->addCss('css/animations.css');
$this->addCss('css/forms.css');
$this->addCss('css/fonts.css');
$this->addCss('css/style.css');
$this->widget('System');
$this->addScript('movim_hash.js');
$this->addScript('movim_utils.js');
$this->addScript('movim_base.js');
$this->addScript('movim_tpl.js');
$this->addScript('movim_websocket.js');
$this->scripts();
$this->addCss('css/font-awesome.css');
?>
<title><?php echo __('page.visio');?></title>
</head>
<body>
<?php $this->widget('Visio', false);?>
<script type="text/javascript">
movim_onload();
</script>
</body>
</html>
<?php $this->widget('Visio');?>

7
app/widgets/Contact/_contact.tpl

@ -8,7 +8,7 @@
style="background-color: rgba(62,81,181,1);"
{/if}
>
<a onclick="Contact_ajaxChat('{$contact->jid|echapJS}')" class="button action color red">
<a onclick="Contact_ajaxChat('{$contact->jid|echapJS}')" class="button action color">
<i class="zmdi zmdi-comment-text-alt"></i>
</a>
@ -69,6 +69,11 @@
">
</i>
</span>
{if="$caps->isJingle()"}
<span class="control icon active" onclick="VisioLink.openVisio('{$contactr->getFullResource()}');">
<i class="zmdi zmdi-phone"></i>
</span>
{/if}
<p class="normal line">
{$caps->name}
{if="isset($clienttype[$caps->type])"}

2
app/widgets/Menu/_menu_add.tpl

@ -1,3 +1,3 @@
<a onclick="Publish_ajaxCreate('{$to}', 'urn:xmpp:microblog:0'); MovimTpl.showPanel();" class="button action color red" title="{$c->__('menu.add_post')}">
<a onclick="Publish_ajaxCreate('{$to}', 'urn:xmpp:microblog:0'); MovimTpl.showPanel();" class="button action color" title="{$c->__('menu.add_post')}">
<i class="zmdi zmdi-edit"></i>
</a>

2
app/widgets/System/system.tpl

@ -1,5 +1,5 @@
<script type="text/javascript">
if(typeof Android === 'undefined') {
if(typeof navigator.registerProtocolHandler == 'function') {
navigator.registerProtocolHandler('xmpp',
'{$c->route("share")}/%s',
'Movim');

137
app/widgets/Visio/Visio.php

@ -0,0 +1,137 @@
<?php
use Moxl\Xec\Action\Jingle\SessionInitiate;
use Moxl\Xec\Action\Jingle\SessionTerminate;
class Visio extends \Movim\Widget\Base
{
function load()
{
$this->addcss('visio.css');
$this->addjs('visio.js');
$this->registerEvent('jingle_sessioninitiate', 'onSDP');
$this->registerEvent('jingle_transportinfo', 'onCandidate');
$this->registerEvent('jingle_sessionaccept', 'onAccept');
$this->registerEvent('jingle_sessionterminate', 'onTerminate');
}
function onSDP($data)
{
list($stanza, $from) = $data;
$jts = new JingletoSDP($stanza);
$s = Session::start();
$s->set('sdp', $jts->generate());
RPC::call('VisioLink.openVisio', $from);
}
function ajaxGetSDP()
{
$s = Session::start();
if($s->get('sdp')) {
RPC::call('Visio.onSDP', $s->get('sdp'), 'offer');
$s->remove('sdp');
}
}
function onAccept($stanza)
{
$jts = new JingletoSDP($stanza);
RPC::call('Visio.onSDP', $jts->generate(), 'answer');
}
function onCandidate($stanza)
{
$jts = new JingletoSDP($stanza);
$sdp = $jts->generate();
$s = Session::start();
$candidates = $s->get('candidates');
if(!$candidates) $candidates = [];
array_push($candidates, [$sdp, $jts->name, substr($jts->name, -1, 1)]);
$s->set('candidates', $candidates);
}
function ajaxGetCandidates()
{
$s = Session::start();
$candidates = $s->get('candidates');
if(is_array($candidates)) {
foreach($candidates as $candidate) {
RPC::call('Visio.onCandidate', $candidate[0], $candidate[1], $candidate[2]);
}
}
$s->remove('candidates');
}
function onTerminate($stanza)
{
RPC::call('Visio.onTerminate');
}
function ajaxInitiate($sdp, $to)
{
$stj = new SDPtoJingle(
$sdp->sdp,
$this->user->getLogin(),
$to,
'session-initiate');
$si = new SessionInitiate;
$si->setTo($to)
->setOffer($stj->generate())
->request();
}
function ajaxAccept($sdp, $to)
{
$stj = new SDPtoJingle(
$sdp->sdp,
$this->user->getLogin(),
$to,
'session-accept');
$si = new SessionInitiate;
$si->setTo($to)
->setOffer($stj->generate())
->request();
}
function ajaxCandidate($sdp, $to)
{
$stj = new SDPtoJingle(
'a='.$sdp->candidate,
$this->user->getLogin(),
$to,
'transport-info',
$sdp->sdpMid,
$sdp->sdpMLineIndex);
$si = new SessionInitiate;
$si->setTo($to)
->setOffer($stj->generate())
->request();
}
function ajaxTerminate($to)
{
$s = Session::start();
$st = new SessionTerminate;
$st->setTo($to)
->setJingleSid($s->get('jingleSid'))
->request();
}
function display()
{
}
}

34
app/widgets/Visio/visio.css

@ -0,0 +1,34 @@
#visio video {
width: 100%;
height: 100%;
background-color: #111;
}
#visio .level,
#visio video#video {
position: fixed;
right: 0;
bottom: 0;
width: 25rem;
height: auto;
}
@media screen and (max-width: 800px) {
#visio .level,
#visio video#video {
width: 15rem;
}
}
#visio header {
top: 2.5rem;
}
#visio .button.action {
right: calc(50% - 3.5rem);
}
#visio .level {
background-color: rgba(255, 255, 255, 0.1);
height: 0.5rem;
}

348
app/widgets/Visio/visio.js

@ -0,0 +1,348 @@
function logError(error) {
console.log(error.name + ': ' + error.message);
}
var Visio = {
pc: null,
constraints: null,
audioContext: null,
max_level_L: 0,
old_level_L: 0,
from: null,
type: null,
start: false,
setFrom: function(from) {
Visio.from = from;
},
/*
* Jingle and WebRTC
*/
handleSuccess: function(stream) {
Visio.pc.addStream(stream);
Visio.toggleMainButton();
Visio_ajaxGetSDP();
//MovimUtils.removeClass('#visio', 'disabled');
// Video
var videoTracks = stream.getVideoTracks();
console.log('Got stream with constraints:', constraints);
console.log('Using video device: ' + videoTracks[0].label);
stream.oninactive = function() {
console.log('Stream inactive');
};
window.stream = stream; // make variable available to browser console
document.getElementById('video').srcObject = stream;
// Audio
var microphone = Visio.audioContext.createMediaStreamSource(stream);
var javascriptNode = Visio.audioContext.createScriptProcessor(2048, 1, 1);
var cnvs = document.querySelector('#visio .level');
var cnvs_cntxt = cnvs.getContext("2d");
microphone.connect(javascriptNode);
javascriptNode.connect(Visio.audioContext.destination);
javascriptNode.onaudioprocess = function(event){
var inpt_L = event.inputBuffer.getChannelData(0);
var instant_L = 0.0;
var sum_L = 0.0;
for(var i = 0; i < inpt_L.length; ++i) {
sum_L += inpt_L[i] * inpt_L[i];
}
instant_L = Math.sqrt(sum_L / inpt_L.length);
Visio.max_level_L = Math.max(Visio.max_level_L, instant_L);
instant_L = Math.max( instant_L, Visio.old_level_L -0.008 );
Visio.old_level_L = instant_L;
cnvs_cntxt.clearRect(0, 0, cnvs.width, cnvs.height);
cnvs_cntxt.fillStyle = 'white';
cnvs_cntxt.fillRect(0, 0,(cnvs.width)*(instant_L/Visio.max_level_L),(cnvs.height)); // x,y,w,h
}
},
onSDP: function(sdp, type) {
Visio.type = type;
console.log('SDP');
console.log(sdp);
Visio.pc.setRemoteDescription(
new RTCSessionDescription({'sdp': sdp + "\n", 'type': type}),
function () {
Visio_ajaxGetCandidates();
// if we received an offer, we need to answer
if (Visio.pc.remoteDescription.type == 'offer')
Visio.pc.createAnswer(Visio.localDescCreated, logError);
},
logError
);
},
localDescCreated: function(desc) {
Visio.pc.setLocalDescription(desc, function () {
Visio_ajaxAccept(Visio.pc.localDescription, Visio.from);
}, logError);
},
onCandidate: function(candidate, mid, mlineindex) {
console.log('candidate');
console.log(candidate);
Visio_ajaxGetCandidates();
if(mid == '') mlineindex = 1;
if(Visio.pc.remoteDescription == null) return;
candidate = new RTCIceCandidate(
{
'candidate': candidate,
'sdpMid': mid,
'sdpMLineIndex' : mlineindex
});
Visio.pc.addIceCandidate(candidate);
},
onTerminate: function() {
console.log('terminate');
Visio.pc.getRemoteStreams().forEach(function(stream) {
stream.getTracks().forEach(function(track) {
track.stop();
});
});
document.getElementById('video').srcObject = null;
document.getElementById('remote_video').srcObject = null;
Visio.pc.close();
if(window.opener) {
window.close();
}
},
init: function(start) {
Visio.start = start;
Visio.toggleMainButton();
Visio.setFrom(MovimUtils.urlParts().params.join('/'));
var configuration = {
'iceServers': [
{urls: ['stun:stun01.sipphone.com',
'stun:stun.ekiga.net',
'stun:stun.fwdnet.net',
'stun:stun.ideasip.com',
'stun:stun.iptel.org',
'stun:stun.rixtelecom.se',
'stun:stun.schlund.de',
'stun:stun.l.google.com:19302',
'stun:stun1.l.google.com:19302',
'stun:stun2.l.google.com:19302',
'stun:stun3.l.google.com:19302',
'stun:stun4.l.google.com:19302',
'stun:stunserver.org',
'stun:stun.softjoys.com',
'stun:stun.voiparound.com',
'stun:stun.voipbuster.com',
'stun:stun.voipstunt.com',
'stun:stun.voxgratia.org',
'stun:stun.xten.com']}
]
};
// WebRTC
if(typeof webkitRTCPeerConnection == 'function') {
Visio.pc = new webkitRTCPeerConnection(configuration);
} else {
Visio.pc = new RTCPeerConnection(configuration);
}
Visio.pc.onicecandidate = function (evt) {
Visio.toggleMainButton();
if (evt.candidate) {
Visio_ajaxCandidate(evt.candidate, Visio.from);
}
};
Visio.pc.oniceconnectionstatechange = function () {
Visio.toggleMainButton();
};
Visio.pc.onicegatheringstatechange = function () {
Visio.toggleMainButton();
};
Visio.pc.ontrack = function (evt) {
document.getElementById('remote_video').src = URL.createObjectURL(evt.streams[0]);
};
Visio.audioContext = new AudioContext();
Visio.constraints = window.constraints = {
audio: true,
video: true
};
Visio.toggleMainButton();
navigator.mediaDevices.getUserMedia(constraints).
then(Visio.handleSuccess).catch(Visio.handleError);
},
/*
* Actions
*/
hello: function() {
Visio.pc.createOffer(function (desc) {
Visio.pc.setLocalDescription(desc, function () {
Visio_ajaxInitiate(Visio.pc.localDescription, Visio.from);
}, logError);
}, logError);
},
goodbye: function() {
Visio.onTerminate();
Visio_ajaxTerminate(Visio.from);
},
/*
* UI Status
*/
toggleMainButton: function() {
button = document.getElementById('main');
if(button) {
i = button.querySelector('i');
MovimUtils.removeClass(button, 'red');
MovimUtils.removeClass(button, 'green');
MovimUtils.removeClass(button, 'blue');
MovimUtils.removeClass(button, 'gray');
MovimUtils.addClass(button, 'disabled');
if(Visio.pc) {
if(Visio.pc.getLocalStreams().length > 0) {
MovimUtils.removeClass(button, 'disabled');
}
if(Visio.pc.iceConnectionState == 'new') {
if(Visio.pc.iceGatheringState == 'gathering') {
MovimUtils.addClass(button, 'blue');
i.className = 'zmdi zmdi-phone-setting';
button.onclick = function() { Visio.goodbye(); };
} else if(Visio.pc.iceGatheringState == 'complete') {
MovimUtils.addClass(button, 'blue');
i.className = 'zmdi zmdi-phone-paused';
button.onclick = function() { Visio.goodbye(); };
} else {
MovimUtils.addClass(button, 'green');
i.className = 'zmdi zmdi-phone';
button.onclick = function() { Visio.hello(); };
}
} else if(Visio.pc.iceConnectionState == 'closed') {
MovimUtils.addClass(button, 'gray');
i.className = 'zmdi zmdi-rotate-left';
button.onclick = function() { MovimUtils.reloadThis(); };
} else if(Visio.pc.iceConnectionState == 'connected'
|| Visio.pc.iceConnectionState == 'complete'
|| Visio.pc.iceConnectionState == 'failed') {
MovimUtils.addClass(button, 'red');
i.className = 'zmdi zmdi-phone-end';
button.onclick = function() { Visio.goodbye(); };
}
}
}
},
toggleFullScreen: function() {
var button = document.querySelector('#toggle_fullscreen i');
if (!document.fullscreenElement
&& !document.msFullscreenElement
&& !document.mozFullScreenElement
&& !document.webkitFullscreenElement) {
if (document.body.requestFullscreen) {
document.body.requestFullscreen();
} else if (document.body.msRequestFullscreen) {
document.body.msRequestFullscreen();
} else if (document.body.mozRequestFullScreen) {
document.body.mozRequestFullScreen();
} else if (document.body.webkitRequestFullscreen) {
document.body.webkitRequestFullscreen();
}
button.className = 'zmdi zmdi-fullscreen-exit';
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.webkitCancelFullScreen) {
document.webkitCancelFullScreen();
}
button.className = 'zmdi zmdi-fullscreen';
}
},
toggleAudio: function() {
var button = document.querySelector('#toggle_audio i');
if(Visio.pc.getLocalStreams()[0].getAudioTracks()[0].enabled) {
Visio.pc.getLocalStreams()[0].getAudioTracks()[0].enabled = 0;
button.className = 'zmdi zmdi-volume-off';
} else {
Visio.pc.getLocalStreams()[0].getAudioTracks()[0].enabled = 1;
button.className = 'zmdi zmdi-volume-up';
}
},
toggleVideo: function() {
var button = document.querySelector('#toggle_video i');
if(Visio.pc.getLocalStreams()[0].getVideoTracks()[0].enabled) {
Visio.pc.getLocalStreams()[0].getVideoTracks()[0].enabled = 0;
button.className = 'zmdi zmdi-eye-off';
} else {
Visio.pc.getLocalStreams()[0].getVideoTracks()[0].enabled = 1;
button.className = 'zmdi zmdi-eye';
}
},
}
//movim_add_onload(function() {
MovimWebsocket.attach(function() {
Visio.init();
});
window.onbeforeunload = function() {
Visio.goodbye();
}

26
app/widgets/Visio/visio.tpl

@ -0,0 +1,26 @@
<div id="visio" class="">
<header class="fixed">
<ul class="list">
<li>
<span id="toggle_fullscreen" class="control icon color transparent active" onclick="Visio.toggleFullScreen()">
<i class="zmdi zmdi-fullscreen"></i>
</span>
<span id="toggle_audio" class="control icon color transparent active" onclick="Visio.toggleAudio()">
<i class="zmdi zmdi-volume-up"></i>
</span>
<span id="toggle_video" class="control icon color transparent active" onclick="Visio.toggleVideo()">
<i class="zmdi zmdi-eye"></i>
</span>
</li>
</ul>
</header>
<video id="video" autoplay muted></video>
<canvas class="level"></canvas>
<video id="remote_video" autoplay></video>
<canvas class="level"></canvas>
<div class="controls">
<a id="main" class="button action color green">
<i class="zmdi zmdi-phone"></i>
</a>
</div>
</div>

13
app/widgets/VisioLink/VisioLink.php

@ -0,0 +1,13 @@
<?php
class VisioLink extends \Movim\Widget\Base
{
function load()
{
$this->addjs('visiolink.js');
}
function display()
{
}
}

15
app/widgets/VisioLink/visiolink.js

@ -0,0 +1,15 @@
var VisioLink = {
candidates: [],
reset: function() {
VisioLink.window = null;
},
openVisio: function(from) {
VisioLink.window = window.open('?visio/' + from, '', 'width=600,height=400,status=0,titlebar=0,toolbar=0,menubar=0');
},
setFrom: function(from) {
VisioLink.from = from;
}
}

0
app/widgets/VisioLink/visiolink.tpl

2
composer.json

@ -17,7 +17,7 @@
"movim/modl": "dev-master",
"movim/sasl2": "dev-master",
"movim/moxl": "dev-master#c10b5348b3009e51bb755f47ebf4fdbca65bebc8",
"movim/moxl": "dev-master#cb486211cc06dbf1abfd625c2f1399f2caadcf86",
"embed/embed": "dev-master",
"heyupdate/emoji": "0.2.*@dev",

51
composer.lock

@ -4,8 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "71330327afbe2878c925fa6c5e7e585f",
"content-hash": "c80ff9387b9bbcd5a8340e596aa3f77c",
"hash": "1cf03c908f92f0272a981f74f9bb7fb1",
"content-hash": "def0b401d37d7eca252d75ad1fd0924b",
"packages": [
{
"name": "cboden/ratchet",
@ -57,16 +57,16 @@
},
{
"name": "clue/buzz-react",
"version": "v1.0.1",
"version": "v1.1.0",
"source": {
"type": "git",
"url": "https://github.com/clue/php-buzz-react.git",
"reference": "0b2bdeefaf4e09aed5bd122909589e3573afb5f4"
"reference": "693c96d35f0cd0e4f0e1a51b976433a91792eff9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/clue/php-buzz-react/zipball/0b2bdeefaf4e09aed5bd122909589e3573afb5f4",
"reference": "0b2bdeefaf4e09aed5bd122909589e3573afb5f4",
"url": "https://api.github.com/repos/clue/php-buzz-react/zipball/693c96d35f0cd0e4f0e1a51b976433a91792eff9",
"reference": "693c96d35f0cd0e4f0e1a51b976433a91792eff9",
"shasum": ""
},
"require": {
@ -108,7 +108,7 @@
"http client",
"reactphp"
],
"time": "2016-08-12 11:50:24"
"time": "2016-10-21 10:29:37"
},
{
"name": "cocur/slugify",
@ -180,16 +180,17 @@
"source": {
"type": "git",
"url": "https://github.com/oscarotero/Embed.git",
"reference": "90a6fd4515e816162d00481a2a2fc42af8740e38"
"reference": "753c886f2ced7240137003382b055fc4b795cdf2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/oscarotero/Embed/zipball/90a6fd4515e816162d00481a2a2fc42af8740e38",
"reference": "90a6fd4515e816162d00481a2a2fc42af8740e38",
"url": "https://api.github.com/repos/oscarotero/Embed/zipball/753c886f2ced7240137003382b055fc4b795cdf2",
"reference": "753c886f2ced7240137003382b055fc4b795cdf2",
"shasum": ""
},
"require": {
"ext-curl": "*",
"ext-mbstring": "*",
"php": ">=5.4.0"
},
"require-dev": {
@ -227,7 +228,7 @@
"opengraph",
"twitter cards"
],
"time": "2016-10-07 18:29:01"
"time": "2016-10-14 16:27:33"
},
{
"name": "evenement/evenement",
@ -942,12 +943,12 @@
"source": {
"type": "git",
"url": "https://github.com/movim/moxl.git",
"reference": "c10b5348b3009e51bb755f47ebf4fdbca65bebc8"
"reference": "cb486211cc06dbf1abfd625c2f1399f2caadcf86"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/movim/moxl/zipball/c10b5348b3009e51bb755f47ebf4fdbca65bebc8",
"reference": "c10b5348b3009e51bb755f47ebf4fdbca65bebc8",
"url": "https://api.github.com/repos/movim/moxl/zipball/cb486211cc06dbf1abfd625c2f1399f2caadcf86",
"reference": "cb486211cc06dbf1abfd625c2f1399f2caadcf86",
"shasum": ""
},
"require": {
@ -982,7 +983,7 @@
"php",
"xmpp"
],
"time": "2016-10-07 20:09:48"
"time": "2016-10-23 20:43:18"
},
{
"name": "movim/sasl2",
@ -1037,16 +1038,16 @@
},
{
"name": "paragonie/random_compat",
"version": "v2.0.2",
"version": "v2.0.3",
"source": {
"type": "git",
"url": "https://github.com/paragonie/random_compat.git",
"reference": "088c04e2f261c33bed6ca5245491cfca69195ccf"
"reference": "c0125896dbb151380ab47e96c621741e79623beb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/088c04e2f261c33bed6ca5245491cfca69195ccf",
"reference": "088c04e2f261c33bed6ca5245491cfca69195ccf",
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/c0125896dbb151380ab47e96c621741e79623beb",
"reference": "c0125896dbb151380ab47e96c621741e79623beb",
"shasum": ""
},
"require": {
@ -1081,7 +1082,7 @@
"pseudorandom",
"random"
],
"time": "2016-04-03 06:00:07"
"time": "2016-10-17 15:23:22"
},
{
"name": "pear/net_dns2",
@ -1540,16 +1541,16 @@
},
{
"name": "react/http-client",
"version": "v0.4.12",
"version": "v0.4.13",
"source": {
"type": "git",
"url": "https://github.com/reactphp/http-client.git",
"reference": "f2b902a0e5bc062ffb2ddd9032776bed9ed5d9f0"
"reference": "07fa19d83d9d3af4a6899c120fd4d41380d4a04e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/reactphp/http-client/zipball/f2b902a0e5bc062ffb2ddd9032776bed9ed5d9f0",
"reference": "f2b902a0e5bc062ffb2ddd9032776bed9ed5d9f0",
"url": "https://api.github.com/repos/reactphp/http-client/zipball/07fa19d83d9d3af4a6899c120fd4d41380d4a04e",
"reference": "07fa19d83d9d3af4a6899c120fd4d41380d4a04e",
"shasum": ""
},
"require": {
@ -1576,7 +1577,7 @@
"keywords": [
"http"
],
"time": "2016-10-06 13:08:24"
"time": "2016-10-19 20:19:11"
},
{
"name": "react/promise",

89
lib/JingletoSDP.php

@ -1,6 +1,7 @@
<?php
class JingletoSDP {
class JingletoSDP
{
private $sdp = '';
private $jingle;
@ -8,6 +9,7 @@ class JingletoSDP {
// Only used for ICE Candidate (Jingle transport-info)
public $media;
public $name;
private $values = array(
'session_sdp_id' => 1,
@ -17,10 +19,12 @@ class JingletoSDP {
'unicast_address' => '0.0.0.0'
);
function __construct($jingle) {
function __construct($jingle)
{
$this->jingle = $jingle;
if(isset($this->jingle->attributes()->sid)) {
if(isset($this->jingle->attributes()->sid))
{
$sid = (string)$this->jingle->attributes()->sid;
//$sid = substr(base_convert($sid, 30, 10), 0, 6);
@ -33,20 +37,15 @@ class JingletoSDP {
$this->action = (string)$this->jingle->attributes()->action;
}
function getSessionId(){
function getSessionId()
{
$s = Session::start();
/*if($sid = $s->get('jingleSid')){
return $sid;
}
else{
$sessid = $this->jingle->attributes()->sid;
return substr(base_convert($sessid, 30, 10), 0, 6);
}*/
return substr(base_convert($s->get('jingleSid'), 30, 10), 0, 6);
}
function generate() {
function generate()
{
if($this->jingle->attributes()->initiator) {
$username = explode('@', (string)$this->jingle->attributes()->initiator);
$username = $username[0];
@ -68,15 +67,15 @@ class JingletoSDP {
$this->values['unicast_address'];
$sdp_session_name =
's=SIP Call'; // Use the sessid ?
's=-'; // Use the sessid ?
$sdp_timing =
't=0 0';
$sdp_medias = '';
foreach($this->jingle->children() as $content) {
$media_header_ids = array();
foreach($this->jingle->children() as $content) {
$media_header_ids = [];
$media_header_first_port = null;
$media_header_last_ip = null;
@ -84,23 +83,27 @@ class JingletoSDP {
// http://xmpp.org/extensions/xep-0338.html
if((string)$content->getName() == 'group') {
$sdp_media .=
$sdp_medias .=
"\r\na=group:".
(string)$content->attributes()->semantics;
foreach($content->children() as $content) {
$sdp_media .= " ".(string)$content->attributes()->name;
$sdp_medias .= " ".(string)$content->attributes()->name;
}
continue;
}
if($content->getName() != 'content')
break;
if(isset($content->transport->attributes()->ufrag))
$sdp_media .= "\r\na=ice-ufrag:".$content->transport->attributes()->ufrag;
$this->name = (string)$content->attributes()->name;
if(isset($content->transport->attributes()->pwd))
$sdp_media .= "\r\na=ice-pwd:".$content->transport->attributes()->pwd;
if(isset($content->transport->attributes()->ufrag))
$sdp_media .= "\r\na=ice-ufrag:".$content->transport->attributes()->ufrag;
if(isset($content->description)) {
foreach($content->description->children() as $payload) {
switch($payload->getName()) {
@ -123,8 +126,8 @@ class JingletoSDP {
if(isset($payload->crypto)) {
$sdp_media .=
"\r\na=crypto:".
$payload->crypto->attributes()->tag.' '.
$payload->crypto->attributes()->{'crypto-suite'}.' '.
$payload->crypto->attributes()->tag.' '.
$payload->crypto->attributes()->{'crypto-suite'}.' '.
$payload->crypto->attributes()->{'key-params'};
// TODO session params ?
@ -133,7 +136,7 @@ class JingletoSDP {
if(isset($payload->{'zrtp-hash'})) {
$sdp_media .=
"\r\na=zrtp-hash:".
$payload->{'zrtp-hash'}->attributes()->version.' '.
$payload->{'zrtp-hash'}->attributes()->version.' '.
(string)$payload->{'zrtp-hash'};
}
break;
@ -202,14 +205,14 @@ class JingletoSDP {
break;
/*case 'source':
case 'source':
foreach($payload->children() as $s) {
$sdp_media .=
"\r\na=ssrc:".$payload->attributes()->id.' '.
$s->attributes()->name.':'.
$s->attributes()->value;
}
break;*/
break;
}
// TODO sendrecv ?
}
@ -241,7 +244,7 @@ class JingletoSDP {
if(isset($content->transport->fingerprint->attributes()->setup)) {
$sdp_media .=
"\r\na=setup:".
$content->transport->fingerprint->attributes()->setup;
$content->transport->fingerprint->attributes()->setup;
}
break;
@ -279,6 +282,7 @@ class JingletoSDP {
if($media_header_first_port == null)
$media_header_first_port = $payload->attributes()->port;
}
if(isset($payload->attributes()->generation)) {
$sdp_media .=
' generation '.$payload->attributes()->generation.
@ -287,7 +291,7 @@ class JingletoSDP {
}
$media_header_last_ip = $payload->attributes()->ip;
break;
}
}
@ -298,12 +302,12 @@ class JingletoSDP {
if($media_header_last_ip == null)
$media_header_last_ip = '0.0.0.0';
if(isset($content->description))
if(isset($content->description)) {
$this->media = (string)$content->description->attributes()->media;
else
$this->media = (string)$content->attributes()->name;
if($this->action != 'transport-info') {
$this->mlineindex = ($this->media == 'audio') ? 0 : 1;
}
if($this->action != 'transport-info') {
$sdp_media_header =
"\r\nm=".$this->media.
' '.$media_header_first_port.' ';
@ -312,19 +316,22 @@ class JingletoSDP {
$sdp_media_header .= 'DTLS/SCTP';
} elseif(isset($content->description->crypto)
|| isset($content->transport->fingerprint)) {
$sdp_media_header .= 'RTP/SAVPF';
$sdp_media_header .= 'UDP/TLS/RTP/SAVPF';
} else {
$sdp_media_header .= 'RTP/AVP';
$sdp_media_header .= 'UDP/TLS/RTP/AVP';
}
$sdp_media_header = $sdp_media_header.' '.implode(' ', $media_header_ids);
$sdp_medias .=
$sdp_media_header.
"\r\nc=IN IP4 ".$media_header_last_ip.
$sdp_media;
//"\r\na=sendrecv";
if(!empty($this->name)) {
$sdp_medias .= "\r\na=mid:".$this->name;
}
} else {
$sdp_medias = $sdp_media;
}
@ -336,9 +343,9 @@ class JingletoSDP {
$this->sdp .= "\r\n".$sdp_session_name;
$this->sdp .= "\r\n".$sdp_timing;
}
$this->sdp .= $sdp_medias;
return $this->sdp."\r\n";
return trim($this->sdp."\r\n");
}
}

262
lib/SDPtoJingle.php

@ -3,16 +3,21 @@ class SDPtoJingle {
private $sdp;
private $arr;
private $jingle;
private $content = null;
private $transport = null;
private $action;
private $mid;
private $mlineindex;
// Move the global fingerprint into each medias
private $global_fingerprint = array();
private $regex = array(
private $global_fingerprint = [];
private $fmtp_cache = [];
private $rtcp_fb_cache = [];
private $regex = [
'candidate' => "/^a=candidate:(\w{1,32}) (\d{1,5}) (udp|tcp) (\d{1,10}) ([a-zA-Z0-9:\.]{1,45}) (\d{1,5}) (typ) (host|srflx|prflx|relay)( (raddr) ([a-zA-Z0-9:\.]{1,45}) (rport) (\d{1,5}))?( (generation) (\d) (network) (\d) (id) ([a-zA-Z0-9]{1,45}))?/i", //à partir de generation les attr sont spécifiques à XMPP..autant l'enlever de la REGEX et les traiter à part? En théorie ils peuvent être dans n'importe quel ordre.
'sess_id' => "/^o=(\S+) (\d+)/i",
'group' => "/^a=group:(\S+) (.+)/i",
@ -32,23 +37,33 @@ class SDPtoJingle {
'setup' => "/^a=setup:(\S+)/i",
'extmap' => "/^a=extmap:([^\s\/]+)(\/([^\s\/]+))? (\S+)/i",
'sctpmap' => "/^a=sctpmap:(\d+) (\S+) (\d+)/i",
'mid' => "/^a=mid:(\S+)/i",
'bandwidth' => "/^b=(\w+):(\d+)/i",
'media' => "/^m=(audio|video|application|data)/i"
);
function __construct($sdp, $initiator, $responder, $action) {
];
function __construct($sdp, $initiator, $responder = false, $action = false, $mid = false, $mlineindex = false)
{
$this->sdp = $sdp;
$this->arr = explode("\n", $this->sdp);
if($mid) $this->mid = $mid;
if($mlineindex) $this->mlineindex = $mlineindex;
$this->jingle = new SimpleXMLElement('<jingle></jingle>');
$this->jingle->addAttribute('xmlns', 'urn:xmpp:jingle:1');
$this->jingle->addAttribute('action',$action);
$this->jingle->addAttribute('initiator',$initiator);
$this->jingle->addAttribute('responder',$responder);
if($action)
$this->jingle->addAttribute('action',$action);
if($responder)
$this->jingle->addAttribute('responder',$responder);
$this->action = $action;
}
function getSessionId(){
private function getSessionId()
{
$s = Session::start();
if($sid = $s->get('jingleSid')){
return $sid;
@ -60,22 +75,72 @@ class SDPtoJingle {
}
}
function generate() {
private function initContent($force = false)
{
if($this->content == null
|| $force) {
$this->content = $this->jingle->addChild('content');
$this->transport = $this->content->addChild('transport');
$this->transport->addAttribute('xmlns', "urn:xmpp:jingle:transports:ice-udp:1");
$this->content->addAttribute('creator', 'initiator'); // FIXME
}
}
private function addFmtpParameters($payloadtype, $params)
{
foreach($params as $value) {
$p = explode('=', trim($value));
if($p[0] == 'stereo' && $p[1] == '1') {
$parameter = $payloadtype->addChild('parameter');
$parameter->addAttribute('value', 'sprop-stereo');
$parameter->addAttribute('value', '1');
}
$parameter = $payloadtype->addChild('parameter');
if(count($p) == 1) {
$parameter->addAttribute('value', $p[0]);
} else {
$parameter->addAttribute('name', $p[0]);
$parameter->addAttribute('value', $p[1]);
}
}
}
private function addRtcpFbParameters($payloadtype, $params)
{
foreach($params as $matches) {
$rtcpfp = $payloadtype->addChild('rtcp-fb');
$rtcpfp->addAttribute('xmlns', "urn:xmpp:jingle:apps:rtp:rtcp-fb:0");
$rtcpfp->addAttribute('id', $matches[1]);
$rtcpfp->addAttribute('type', $matches[2]);
if(isset($matches[4]))
$rtcpfp->addAttribute('subtype', $matches[4]);
}
}
public function addName($name = false)
{
if($name) {
$this->content->addAttribute('name', $name);
} elseif($this->mid) {
$this->content->addAttribute('name', $this->mid);
}
}
function generate()
{
foreach($this->arr as $l) {
foreach($this->regex as $key => $r) {
if(preg_match($r, $l, $matches)) {
switch($key) {
switch($key) {
case 'sess_id':
$this->jingle->addAttribute('sid', $this->getSessionId());
break;
case 'media':
$this->content = $this->jingle->addChild('content');
$this->transport = $this->content->addChild('transport');
$this->transport->addAttribute('xmlns', "urn:xmpp:jingle:transports:ice-udp:1");
$this->initContent(true);
$this->content->addAttribute('creator', 'initiator'); // TODO à fixer !
$this->content->addAttribute('name', $matches[1]);
// The description node
if($this->action != 'transport-info') {
$description = $this->content->addChild('description');
@ -85,76 +150,87 @@ class SDPtoJingle {
if(!empty($this->global_fingerprint)) {
$fingerprint = $this->transport->addChild('fingerprint', $this->global_fingerprint['fingerprint']);
$this->transport->addAttribute('pwd', $this->global_fingerprint['pwd']);
$this->transport->addAttribute('ufrag', $this->global_fingerprint['ufrag']);
//$this->transport->addAttribute('pwd', $this->global_fingerprint['pwd']);
//$this->transport->addAttribute('ufrag', $this->global_fingerprint['ufrag']);
$fingerprint->addAttribute('xmlns', "urn:xmpp:jingle:apps:dtls:0");
$fingerprint->addAttribute('hash', $this->global_fingerprint['hash']);
}
break;
case 'mid':
$this->addName($matches[1]);
break;
case 'bandwidth':
$bandwidth = $description->addChild('bandwidth');
$bandwidth->addAttribute('type', $matches[1]);
$bandwidth->addAttribute('value', $matches[2]);
break;
case 'rtpmap':
$payloadtype = $description->addChild('payload-type');
$payloadtype->addAttribute('id', $matches[1]);
$payloadtype->addAttribute('name', $matches[3]);
if(isset($matches[4]))
$payloadtype->addAttribute('clockrate', $matches[5]);
if(isset($matches[7]))
$payloadtype->addAttribute('channels', $matches[7]);
if(isset($this->fmtp_cache[$matches[1]])) {
$this->addFmtpParameters($payloadtype, $this->fmtp_cache[$matches[1]]);
unset($this->fmtp_cache[$matches[1]]);
}
if(isset($this->rtcp_fb_cache[$matches[1]])) {
$this->addRtcpFbParameters($payloadtype, $this->rtcp_fb_cache[$matches[1]]);
unset($this->rtcp_fb_cache[$matches[1]]);
}
break;
// http://xmpp.org/extensions/xep-0167.html#format
case 'fmtp':
// This work only if fmtp is added just after
// the correspondant rtpmap
if($matches[1] == $payloadtype->attributes()->id) {
$params = explode(';', $matches[2]);
foreach($params as $value) {
$p = explode('=', trim($value));
$parameter = $payloadtype->addChild('parameter');
if(count($p) == 1) {
$parameter->addAttribute('value', $p[0]);
} else {
$parameter->addAttribute('name', $p[0]);
$parameter->addAttribute('value', $p[1]);
}
}
// If fmtp is added just after the correspondant rtpmap
$params = explode(';', $matches[2]);
if(isset($payloadtype)
&& $matches[1] == $payloadtype->attributes()->id) {
$this->addFmtpParameters($payloadtype, $params);
// If not we cache it
} else {
$this->fmtp_cache[$matches[1]] = $params;
}
break;
// http://xmpp.org/extensions/xep-0293.html
case 'rtcp_fb':
if($matches[1] == '*') {
$rtcpfp = $description->addChild('rtcp-fb');
} else {
$rtcpfp = $payloadtype->addChild('rtcp-fb');
$this->addRtcpFbParameters($description, [$matches]);
} else {
if(isset($payloadtype)
&& $matches[1] == $payloadtype->attributes()->id) {
$this->addRtcpFbParameters($payloadtype, [$matches]);
} else {
if(!isset($this->rtcp_fb_cache[$matches[1]])) {
$this->rtcp_fb_cache[$matches[1]] = [];
}
array_push($this->rtcp_fb_cache[$matches[1]], $matches);
}
}
$rtcpfp->addAttribute('xmlns', "urn:xmpp:jingle:apps:rtp:rtcp-fb:0");
$rtcpfp->addAttribute('id', $matches[1]);
$rtcpfp->addAttribute('type', $matches[2]);
if(isset($matches[4]))
$rtcpfp->addAttribute('subtype', $matches[4]);
break;
case 'rtcp_fb_trr_int':
$rtcpfp = $payloadtype->addChild('rtcp-fb-trr-int');
$rtcpfp->addAttribute('xmlns', "urn:xmpp:jingle:apps:rtp:rtcp-fb:0");
$rtcpfp->addAttribute('id', $matches[1]);
$rtcpfp->addAttribute('value', $matches[2]);
break;
// http://xmpp.org/extensions/xep-0167.html#srtp
case 'crypto':
$encryption = $description->addChild('encryption');
@ -165,14 +241,14 @@ class SDPtoJingle {
if(isset($matches[5]))
$crypto->addAttribute('session-params', $matches[5]);
break;
// http://xmpp.org/extensions/xep-0262.html
case 'zrtp_hash':
$zrtphash = $encryption->addChild('zrtp-hash', $matches[2]);
$zrtphash->addAttribute('xmlns', "urn:xmpp:jingle:apps:rtp:zrtp:1");
$zrtphash->addAttribute('version', $matches[1]);
break;
case 'rtcp_mux':
$description->addChild('rtcp-mux');
break;
@ -186,24 +262,24 @@ class SDPtoJingle {
if(isset($matches[3]) && $matches[3] != '')
$rtphdrext->addAttribute('senders', $matches[3]);
break;
// http://xmpp.org/extensions/inbox/jingle-source.html
// http://xmpp.org/extensions/xep-0339.html
case 'ssrc':
if(!$description->source) {
$ssrc = $description->addChild('source');
$ssrc->addAttribute('xmlns', "urn:xmpp:jingle:apps:rtp:ssma:0");
$ssrc->addAttribute('id', $matches[1]);
}
$param = $ssrc->addChild('parameter');
$param->addAttribute('name', $matches[2]);
$param->addAttribute('value', $matches[4]);
break;
case 'ptime':
$description->addAttribute('ptime', $matches[1]);
break;
case 'maxptime':
$description->addAttribute('maxptime', $matches[1]);
break;
@ -221,7 +297,7 @@ class SDPtoJingle {
$content->addAttribute('name', trim($value));
}
break;
// http://xmpp.org/extensions/xep-0320.html
case 'fingerprint':
if($this->content == null) {
@ -232,7 +308,7 @@ class SDPtoJingle {
$fingerprint->addAttribute('xmlns', "urn:xmpp:jingle:apps:dtls:0");
$fingerprint->addAttribute('hash', $matches[1]);
}
break;
// http://xmpp.org/extensions/inbox/jingle-dtls.html
@ -243,65 +319,61 @@ class SDPtoJingle {
$sctpmap->addAttribute('protocol', $matches[2]);
$sctpmap->addAttribute('streams', $matches[3]);
break;
// http://xmpp.org/extensions/xep-0320.html
case 'setup':
if($this->content != null) {
$fingerprint->addAttribute('setup', $matches[1]);
}
break;
case 'pwd':
if($this->content == null) {
$this->global_fingerprint['pwd'] = $matches[1];
} else {
$this->transport->addAttribute('pwd', $matches[1]);
}
case 'pwd':
$this->transport->addAttribute('pwd', $matches[1]);
break;
case 'ufrag':
if($this->content == null) {
$this->global_fingerprint['ufrag'] = $matches[1];
} else {
$this->transport->addAttribute('ufrag', $matches[1]);
}
$this->transport->addAttribute('ufrag', $matches[1]);
break;
case 'candidate':
$this->initContent();
$this->addName();
$generation = "0";
$network = "0";
$id = generateKey(10);
if($key = array_search("generation", $matches))
$generation = $matches[($key+1)];
if($key = array_search("network", $matches))
$network = $matches[($key+1)];
if($key = array_search("id", $matches))
$id = $matches[($key+1)];
if(isset($matches[11]) && isset($matches[13])) {
$reladdr = $matches[11];
$relport = $matches[13];
} else {
$reladdr = $relport = null;
}
$candidate = $this->transport->addChild('candidate');
$candidate->addAttribute('component' , $matches[2]);
$candidate->addAttribute('foundation', $matches[1]);
$candidate->addAttribute('generation', $generation);
$candidate->addAttribute('id' , $id);
//$candidate->addAttribute('generation', $generation);
//$candidate->addAttribute('id' , $id);
$candidate->addAttribute('ip' , $matches[5]);
$candidate->addAttribute('network' , $network);
//$candidate->addAttribute('network' , $network);
$candidate->addAttribute('port' , $matches[6]);
$candidate->addAttribute('priority' , $matches[4]);
$candidate->addAttribute('protocol' , $matches[3]);
$candidate->addAttribute('type' , $matches[8]);
if($reladdr) {
$candidate->addAttribute('rel-addr' , $reladdr);
$candidate->addAttribute('rel-port' , $relport);
@ -312,12 +384,6 @@ class SDPtoJingle {
}
}
// We reindent properly the Jingle package
$xml = $this->jingle->asXML();
$doc = new \DOMDocument();
$doc->loadXML($xml);
$doc->formatOutput = true;
return substr($doc->saveXML() , strpos($doc->saveXML(), "\n")+1 );
return dom_import_simplexml($this->jingle);
}
}

7
src/Movim/Bootstrap.php

@ -190,8 +190,8 @@ class Bootstrap
require_once(LIB_PATH . "XMPPtoForm.php");
// SDPtoJingle and JingletoSDP lib :)
//require_once(LIB_PATH . "SDPtoJingle.php");
//require_once(LIB_PATH . "JingletoSDP.php");
require_once(LIB_PATH . "SDPtoJingle.php");
require_once(LIB_PATH . "JingletoSDP.php");
}
private function loadHelpers()
@ -313,7 +313,8 @@ class Bootstrap
return["Account","AccountNext","Ack","AdHoc","Avatar","Bookmark","Chat",
"Chats","Config","Contact","Dialog","Drawer","Group","Groups","Header",
"Init","Login","LoginAnonymous","Menu","Notifs","Post","Presence",
"Publish","Rooms","Roster","Stickers","Upload","Vcard4"];
"Publish","Rooms","Roster","Stickers","Upload","Vcard4", "Visio",
"VisioLink"];
}
/**

1
src/Movim/Controller/Base.php

@ -5,6 +5,7 @@ use Movim\Template\Builder;
class Base {
public $name = 'main'; // The name of the current page
public $unique = false; // Only one WS for this page
protected $session_only = false;// The page is protected by a session ?
protected $raw = false; // Display only the content ?
protected $public = false; // It's a public page

4
src/Movim/Controller/Front.php

@ -11,7 +11,7 @@ class Front extends Base
$this->runRequest($r->find());
}
private function loadController($request) {
public function loadController($request) {
$class_name = ucfirst($request).'Controller';
if(file_exists(APP_PATH . 'controllers/'.$class_name.'.php')) {
$controller_path = APP_PATH . 'controllers/'.$class_name.'.php';
@ -36,7 +36,7 @@ class Front extends Base
$sess = \Sessionx::start();
$sess->refreshCookie();
if(is_callable(array($c, 'load'))) {
if(is_callable([$c, 'load'])) {
$c->name = $request;
$c->load();
$c->checkSession();

39
src/Movim/Daemon/Session.php

@ -3,6 +3,7 @@ namespace Movim\Daemon;
use Ratchet\ConnectionInterface;
use React\EventLoop\Timer\Timer;
use Movim\Controller\Front;
class Session {
protected $clients;
@ -17,6 +18,9 @@ class Session {
protected $buffer;
private $state;
private $front;
private $uniques = [];
public function __construct($loop, $sid, $baseuri)
{
$this->sid = $sid;
@ -25,11 +29,32 @@ class Session {
$this->clients = new \SplObjectStorage;
$this->register($loop, $this);
$this->front = new Front;
$this->timestamp = time();
}
public function attach($loop, ConnectionInterface $conn)
{
$name = $conn->WebSocket->request->getQuery()->toArray()['path'];
if(!empty($name)) {
$page = $this->front->loadController($name);
$page->load();
if($page->unique) {
if(isset($this->uniques[$name])) {
$obj = new \StdClass;
$obj->func = 'block';
$msg = base64_encode(gzcompress(json_encode($obj), 9));
$conn->send($msg);
return;
} else {
$this->uniques[$name] = 1;
}
}
}
$this->clients->attach($conn);
if($this->countClients() > 0) {
@ -41,6 +66,16 @@ class Session {
public function detach($loop, ConnectionInterface $conn)
{
$name = $conn->WebSocket->request->getQuery()->toArray()['path'];
if($this->clients->contains($conn)
&& !empty($name)
&& isset($this->uniques[$name])) {
unset($this->uniques[$name]);
} else {
return;
}
$this->clients->detach($conn);
if($this->countClients() == 0) {
@ -68,10 +103,10 @@ class Session {
$this->process = new \React\ChildProcess\Process(
'exec php linker.php ' . $this->sid,
null,
array(
[
'sid' => $this->sid,
'baseuri' => $this->baseuri
)
]
);
$this->process->start($loop);

4
themes/material/css/color.css

@ -30,7 +30,7 @@ main > header a,
}
.button.color,
.button.action.color,
.color,
ul li span.counter,
form > div .radio > input[type="radio"]:checked + label {
border-color: #FF5722;
@ -69,7 +69,7 @@ span.icon.status.away:after,
.color.brown { color: white; background-color: #795548; border-color: #795548 }
.color.gray { color: white; background-color: #9E9E9E; border-color: #9E9E9E }
.color.black { color: white; background-color: #000; border-color: #000 }
.color.transparent { color: white; background-color: rgba(0, 0, 0, 0); }
form > div > input:focus:invalid,
form > div > input:focus:required {

Loading…
Cancel
Save