6.
How
Use signaling to exchange endpoint details
Signaling is the backend
Directly connect, if possible
Relay server used if nothing else works
7. #!/OPT/PERL
FUNCTION APPENDDIV(DATA)
VAR DIV
USE
USE
MOJOLICIOUS ::LITE;
JSON;
{
= DOCUMENT.CREA TEELEMENT('DIV');
= DATA;
FUNCTION RETURNSDP()
{
APPENDDIV("ANSWERER: SEND SDP");
DIV.INNER HTML
SOCKET.SEND({
SENDER: 'ANSWERER',
VAR CHATOUTPUT
'/' => SUB {
MY $SELF = SHIFT;
= DOCUMENT.GE TELEME NTBYID('CHA T-OUTPUT');
SDP: ANSWERER.LOCALDES CRIP TION
CHATOUTP UT.INS ERTBEFORE(DIV, CHATOUTPUT.FIRS TCHILD);
GET
});
}
DIV.TABINDE X
$SELF->RENDER("INDE X");
= 0;
DIV.FOCUS();
};
IF (ISFIREFOX)
}
{
ANSWERER.SETRE MOTE D ESCRIP TION(NEW MOZRTCS ESS ION DE SCRIP TION(OFFER SDP), FUNCTION()
ANSWERER.CREATE ANSWE R(FUNCTION
MY
'/WSCHANNEL/:TYPE' => SUB {
$SELF = SHIFT;
MY
$TYPE = $SELF->PARAM("TYPE ");
VAR ICESERVERS
WEBSOCKET
ICESERVERS:
={
$SELF->APP->LOG->DEBUG("W EBSOCKET
OPENED:
}, ONERROR,
});
$ID = MOJO::IOLOOP->RECURRING(4 => SUB {
("OFFERER" EQ $TYPE) {
IF (- F "/TMP/SDP.ANSWERER") {
$SELF->APP->LOG->DEBUG("SENDING SDP: TO OFFERER FROM ANSWERER");
MY $TXT = MOJO::UTIL::SLURP("/TMP/SDP.ANSWERE R");
MY $REF = JSON::FROM_JSON($TX T);
$SELF->SEND({JSON => $REF});
UNLINK ("/TMP/SDP.ANSWERER");
MOJO::UTIL::SPURT(SCA LAR LOCALTIME(TIME), "/TMP/SDP.OFFERER.SENT");
}
OPTIONAL:
={
[{DTLSSRTPK EYA GREEMENT:
{RTPDA TAC HA NNE LS:
TRUE
}]
={
[],
{
OFFERTORECE IVE AUDIO:
OFFERTORECE IVE V IDEO:
VAR MEDIACONS TRA INTS
VAR CHATINPUT
IF (E.KEYCODE
APPENDDIV(THIS.VALUE);
FUNCTION SETCHANNEL EV ENTS ( CHANNEL, CHANNELNA MEF OR CONSOLEOUTP UT)
CHANNEL.ONERROR
FALSE
= ONERROR;
OFFERER
MOZRTCPE ERC ONNECTION(ICES ERV ERS, OPTIONA L RTPD A TA CHANNELS );
= NEW
WEBKITRTCPEE RC ONNECTION(ICESE RV ERS, OPTIONAL R TPD A TA CHA NNELS );
= FUNCTION () {
CONSOLE.LOG("CHANNEL: ONOPEN");
}
DOCUMENT.GETELE ME NTB Y ID('CHA T- INP UT').DIS ABLED
ELSE
{
OFFERER
= FALSE;
};
}
}
= OFFERER.CREATED A TA CHANNEL('RTCD A TA CHANNEL', {
RELIABLE : TRUE
{
VAR URL;
IF
});
("OFFERER" == TYPE) {
URL = "<%= URL_FOR('/WSCHANNEL/OFFERE R')->TO_AB S->SCHEME('WS') %>";
}
CONNECTION
FROM OFFERER");
= OFFERERDATAC HANNEL;
ELSE
CONSOLE.LOG("CONSOLE : OFFERER");
{
URL =
"<%= URL_FOR('/WSCHANNEL/ANSWERER')->TO_ ABS->SCHE ME('WS') %>";
}
SETCHANNEL EVE NTS (OFFERER DA TAC HANNEL, 'OFFERER');
CONSOLE.LOG("CONNECTING:
SOCKET
= FUNCTION (EVENT) {
CONSOLE.LOG("ONICECANDIDA TE : OFFERER");
IF (EVENT.CANDIDA TE ) SENDCANDIDA TE (EVE NT.CANDIDA TE );
IF (!EVENT.CANDIDA TE ) RETURNSDP();
FROM OFFERER");
" + URL);
= NEW W EBSOCKET(URL);
= FUNCTION () {
" + URL);
SOCKET.ONOPEN
APPENDDIV("CONNECTED:
};
SOCKET.ONMESSA GE
= FUNCTION (E) {
= JSON.PARSE(E.DATA);
" + DATA.SENDER);
{
== 'OFFERER') {
APPENDDIV("RECV: SDP : OFFERER");
CREATEANSWER(DA TA. SDP);
};
VAR DATA
CONSOLE.LOG("ONMESSA GE :
FUNCTION SENDCANDIDA TE ()
{
IF (DATA.SDP)
APPENDDIV("OFFERER: SEND CANDIDA TE ");
IF (DATA.SENDER
SOCKET.SEND({
SENDER: 'OFFERER',
}
CANDIDATE : EVENT.CANDIDA TE
}
}
});
ELSE
});
}
$SELF->ON(MESSAGE => SUB {
MY ($SELF, $MSG) = @_;
FUNCTION RETURNSDP()
{
APPENDDIV("RECV: SDP : ANSWERER");
IF (ISFIREFOX)
{
APPENDDIV("OFFERER: SEND SDP");
SOCKET.SEND({
SENDER: 'OFFERER',
SDP: OFFERER.LOCALDE SCRIP TION
});
$TYPE");
($$RET{SENDER} && "OFFERER" EQ $$RET{SENDER} && $$RET{SDP}) {
MOJO::UTIL::SPURT($MSG, "/TMP/SDP.OFFERER");
ELSE
OFFERER.CREATE OFFER(FUNCTION
}
(SESSIONDES CRIP TION) {
OFFERER.SETLOCA LD ESCRIP TION(SE SS ION DES CRIP TION);
}, ONERROR, MEDIA CONS TRA INTS);
FUNCTION ONERROR( ERR)
{
CONSOLE.LOG(ERR);
}
FUNCTION CREATEANSWER(OFFER SDP)
{
{
ANSWERER = NEW MOZRTCP EER CONNE CTION( ICE SERVE RS ,
IF (ISFIREFOX)
OPTIONAL R TP DA TAC HANNE LS );
}
ELSE
{
= NEW WEBKITRTCP EER CONNE CTION(ICE SERVE RS,
ANSWERERDATA CHA NNE L
OPTIONAL RTP DA TAC HANNELS );
IF
= ANSWERER.CREA TED A TA CHANNEL('RTCD A TA CHANNEL', {
RELIABLE : TRUE
});
SETCHANNEL EVE NTS (ANSWERE RD A TA CHANNEL, 'ANSWERER');
CONNECTION
$CODE.");
= ANSWERERDATA CHANNEL;
CONSOLE.LOG("CONSOLE : ANSWER");
ANSWERER.ONICECANDIDA TE
= FUNCTION (EVENT) {
CONSOLE.LOG("ONICECANDIDA TE : ANSWERER");
};
IF (EVENT.CANDIDA TE ) SENDCANDIDA TE ();
IF
(!EVENT.CANDIDA TE )
RETURNSDP();
APP->START;
};
__DATA__
FUNCTION SENDCANDIDA TE ()
}
SOCKET.PUSH
SOCKET.SEND
SOCKET.SEND({
});
= SOCKET.SEND;
= FUNCTION (DATA ) {
" + DATA .SENDER);
CONSOLE.LOG("SEND:
SENDER: 'ANSWERER',
CANDIDATE : EVENT.CANDIDA TE
}
("ANSWERER" === DATA.SENDER && DATA.CANDIDA TE) {
APPENDDIV("RECV: CANDIDA TE : ANSWERER");
IF (ISFIREFOX) {
OFFERER.ADDICECANDIDA TE (NEW MOZRTCICECA NDIDA TE ({
SDPMLINEINDE X: DATA .CANDIDA TE .SDP ML INEINDE X,
CANDIDATE: DATA.CANDIDA TE .CANDIDA TE
}));
}
ELSE {
OFFERER.ADDICECANDIDA TE (NEW RTCICECA NDIDA TE ({
SDPMLINEINDE X: DATA .CANDIDA TE .SDP ML INEINDE X,
CANDIDATE: DATA.CANDIDA TE .CANDIDA TE
}));
}
};
{
APPENDDIV("ANSWERER: SEND CANDIDA TE");
@@ INDEX.HTML.EP
("OFFERER" === DATA.SENDER && DATA.CANDIDA TE) {
APPENDDIV("RECV: CANDIDA TE : OFFERER");
IF (ISFIREFOX) {
ANSWERER.ADDICECANDIDA TE (NEW MOZRTCICE CANDIDA TE ({
SDPMLINEINDE X: DATA .CANDIDA TE .SDP ML INEINDE X,
CANDIDATE: DATA.CANDIDA TE .CANDIDA TE
}));
}
ELSE {
ANSWERER.ADDICECANDIDA TE (NEW RTCICECANDIDA TE ({
SDPMLINEINDE X: DATA .CANDIDA TE .SDP ML INEINDE X,
CANDIDATE: DATA.CANDIDA TE .CANDIDA TE
}));
}
}
ANSWERER
}
});
CLOSED WITH STATUS
RTCSES S IOND ESCRIP TION(DA TA.SDP));
}
}
}
($$RET{SENDER} && $$RET{CANDIDA TE}) {
FOREACH MY $SUFFIX (QW (001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 END)) {
IF ("END" EQ $SUFFIX) {
$SELF->APP->LOG->DEBUG("W E ARE OUT OF CANDIDA TE SUFFIXES.");
LAST;
}
MY $F = "/TMP/CANDIDA TE .$$RE T{SENDER}.$SUFFIX";
IF (-F $F) {
NEXT;
}
MOJO::UTIL::SPURT($MS G, $F);
LAST;
}
{
OFFERER.SETREMOTE DE SCRIP TION(NEW
}
IF
($$RET{SENDER} && "ANSWERER" EQ $$RET{SENDER} && $$RET{SDP}) {
MOJO::UTIL::SPURT($MSG, "/TMP/SDP.ANSWERER");
}
{
OFFERER.SETREMOTE DE SCRIP TION(NEW MOZRTCSE SS IOND ES CRIP TION(DA TA.SDP));
}
}
}
<SCRIPT>
VAR ISFIREFOX = !!NAVIGATOR.MOZGE T USER ME DIA;
VAR CONNECTION;
+ EVENT.DATA);
SOCKET.PUSH(JSON.S TRINGIFY (DA TA));
};
}
</SCRIPT>
Code – 350 lines!!
= '';
THIS.FOCUS();
};
CHANNEL.ONOPEN
OFFERERDATA CHANNEL
$SELF->ON(FINISH => SUB {
MY ($SELF, $CODE, $REASON) = @_;
$SELF->APP->LOG->DEBUG("W EBSOCKET
MOJO::IOLOOP->REMOVE($ID);
UNLINK ("/TMP/SDP.$TYPE ");
});
A MESSAGE :'
</SCRIPT>
{
= NEW
OFFERER.ONICECANDIDA TE
IF
THIS.VALUE
+ 'RECEIVED
{
IF (ISFIREFOX)
}
IF
= FUNCTION (EVENT) {
CONSOLE.LOG("CHANNEL: ONMESSAGE ");
APPENDDIV(CHANNEL NAMEF OR CONSOLEOUTP UT
};
}
IF
CONSOLE.LOG(CONNECTION);
CONNECTION.SEND(THIS.VALUE);
CHANNEL.ONMESSAGE
VAR OFFERER, ANSWERER, ANSWERERDA TA CHA NNE L, OFFERERDA TA CHA NNEL;
ELSE
TYPE:
{
}
};
ANSWERER");
= DOCUMENT.GE TELE MENTB YID('CHA T-INPUT');
= FUNCTION(E) {
!== 13 || !THIS.VALUE) RETURN;
CHATINPUT.ONKE YP RES S
}
FALSE,
FUNCTION CONNECTS IGNALER( TYP E )
(- F "/TMP/SDP.OFFERER.SENT") {
FOREACH MY $F (GLOB("/TMP/CANDIDA TE .OFFERE R.*")) {
$SELF->APP->LOG->DEBUG("SENDING $F: TO ANSWERER
MY $TXT = MOJO::UTIL::SLURP($F);
MY $REF = JSON::FROM_JSON($ TXT);
$SELF->SEND({JSON => $REF});
UNLINK($F);
}
UNLINK ("/TMP/SDP.OFFE RER.SE NT");
{
MANDATORY :
}
$SELF->APP->LOG->DEBUG("MSG: $MSG:
MY $RET = JSON::FROM_JSON($MS G);
FUNCTION()
MEDIACONS TRA INTS );
}
OPTIONAL:
FOREACH MY
{
(- F "/TMP/SDP.OFFERER") {
MY $TXT = MOJO::UTIL::SLURP("/TMP/SDP.OFFERER");
MY $REF = JSON::FROM_JSON($TX T);
$SELF->APP->LOG->DEBUG("SENDING SDP: TO ANSWERER
$SELF->SEND({JSON => $REF});
UNLINK ("/TMP/SDP.OFFE RER ");
RTCS ESS ION DES CRIP TION(OFFER SDP),
(SESSIONDESCRIP TION) {
ANSWERER.SETLOCA LDE SCRIP TION(SE SS ION DES CRIP TION);
}, ONERROR,
}, ONERROR);
FUNCTION CREATEOFFE R()
$F (GLOB("/TMP/CANDIDA TE.ANSWERE R.*")) {
$SELF->APP->LOG->DEBUG("SENDING $F: TO OFFERER FROM
MY $TXT = MOJO::UTIL::SLURP($F);
MY $REF = JSON::FROM_JSON($TX T);
$SELF->SEND({JSON => $REF});
UNLINK ($F);
ANSWERER.CREATE ANSWE R(FUNCTION
TRUE},
};
IF
IF
{
ANSWERER.SETRE MOTE D ESCRIP TION(NEW
VAR OPTIONA L RTPD A TA CHANNELS
IF
MEDIACONS TRA INTS );
}
ELSE
$TYPE");
# INCREASE INACTIV ITY TIMEOUT FOR CONNECTION A BIT
MOJO::IOLOOP->STREAM($SELF->TX->CONNE CTION)->TIME OUT(300);
MY
(SESSIONDESCRIP TION) {
ANSWERER.SETLOCA LDE SCRIP TION(SE SS ION DES CRIP TION);
[{
URL: 'STUN:23.21.150.121'
}]
};
{
HAS WORKED IN CHROME.<BR />
CREATE OFFER SHOULD BE CLICKED BY THE "OFFERER".<BR />
<BUTTON ID="CONNECT-OFFE RER ">CONNECT AS OFFERER</BUTTON>
<BUTTON ID="CONNECT-ANSWERE R">CONNECT AS ANSWERER</BUTTON><BR />
<BUTTON ID="CREATE-OFFER">C REA TE OFFER</BUTTON>
<INPUT TYPE="TE XT" ID="CHAT-INPUT" STYLE="FONT-S IZE: 1.2EM;" PLACEHOLDER="CHA T
<DIV ID="CHAT-OUTPUT"></DIV>
<SCRIPT>
DOCUMENT.GE TE LE MENTB YID('CONNE CT-OFFERE R').ONCLICK = FUNCTION () {
THIS.DISAB LED = TRUE;
CONNECTS IGNALE R("OFFERE R");
};
DOCUMENT.GE TE LE MENTB YID('CONNE CT-ANSWE RER').ONCLICK = FUNCTION () {
THIS.DISAB LED = TRUE;
CONNECTS IGNALE R("ANSWE RER ");
};
DOCUMENT.GE TE LE MENTB YID('CREA TE-OFFE R').ONCLICK = FUNCTION () {
CREATEOFFER();
};
MESSAGE " DISABLED>
9.
$ perl datachannel.pl daemon
Luanch two instances of chrome; perhaps
stable and canary
Click answerer in one window; offerer in the
other; then click Create Offer in offerer window
Chat session should initiate
Run me