From 84fcf5351270a68a9481a8e4f7574b7039d6fdcb Mon Sep 17 00:00:00 2001 From: Jeff Williams Date: Thu, 30 Oct 2008 21:20:29 +0000 Subject: [PATCH] Significant improvement to Jingle logging messages, and a new SmackLogger that allows for use of java.commons.logging. Improvements to Jingle processing to keep up with recent changes in the XEPs as we approach approval of the standard. (There will be more changes as the standard changes.) Fixes to the way STUN gets used, and a new JSTUN library (including performance and reliability changes we added to it). git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/trunk@10852 b35dd754-fafc-0310-a699-88a17e54d16e --- build/build.xml | 2 +- jingle/extension/build/build.xml | 2 +- jingle/extension/build/merge/jstun-0.7.2.jar | Bin 0 -> 66682 bytes jingle/extension/build/merge/jstun.jar | Bin 76890 -> 0 bytes .../smackx/jingle/JingleManager.java | 81 ++++---- .../smackx/jingle/JingleNegotiator.java | 12 +- .../smackx/jingle/JingleSession.java | 69 +++++-- .../jingle/JingleSessionStateEnded.java | 9 +- .../smackx/jingle/SmackLogger.java | 192 ++++++++++++++++++ .../smackx/jingle/media/MediaNegotiator.java | 20 +- .../smackx/jingle/mediaimpl/JMFInit.java | 27 ++- .../jingle/mediaimpl/jmf/AudioChannel.java | 39 ++-- .../mediaimpl/jmf/AudioMediaSession.java | 16 +- .../jingle/mediaimpl/jmf/AudioReceiver.java | 55 +++-- .../jingle/mediaimpl/jmf/JmfMediaManager.java | 17 +- .../mediaimpl/jspeex/AudioMediaSession.java | 37 ++-- .../mediaimpl/jspeex/SpeexMediaManager.java | 17 +- .../mediaimpl/sshare/ScreenShareSession.java | 31 +-- .../sshare/api/ImageTransmitter.java | 16 +- .../sshare/api/OctTreeQuantizer.java | 21 +- .../smackx/jingle/nat/HttpServer.java | 22 +- .../smackx/jingle/nat/ICECandidate.java | 10 +- .../smackx/jingle/nat/ICEResolver.java | 109 ++++++---- .../smackx/jingle/nat/RTPBridge.java | 48 +++-- .../jivesoftware/smackx/jingle/nat/STUN.java | 17 +- .../smackx/jingle/nat/STUNResolver.java | 28 +-- .../smackx/jingle/nat/TcpUdpBridgeClient.java | 14 +- .../smackx/jingle/nat/TcpUdpBridgeServer.java | 20 +- .../smackx/jingle/nat/TransportCandidate.java | 39 ++-- .../jingle/nat/TransportNegotiator.java | 42 ++-- .../smackx/jingle/nat/TransportResolver.java | 21 +- .../jivesoftware/smackx/packet/Jingle.java | 4 +- .../packet/JingleContentDescription.java | 2 +- .../smackx/packet/JingleContentInfo.java | 2 +- .../smackx/packet/JingleDescription.java | 15 +- .../smackx/packet/JingleError.java | 2 +- .../smackx/packet/JingleTransport.java | 2 +- .../provider/JingleTransportProvider.java | 2 +- .../smackx/jingle/nat/STUNResolverTest.java | 26 ++- .../smackx/provider/JingleProviderTest.java | 4 +- 40 files changed, 755 insertions(+), 337 deletions(-) create mode 100644 jingle/extension/build/merge/jstun-0.7.2.jar delete mode 100644 jingle/extension/build/merge/jstun.jar create mode 100644 jingle/extension/source/org/jivesoftware/smackx/jingle/SmackLogger.java diff --git a/build/build.xml b/build/build.xml index fd44fa384..d0bad0552 100644 --- a/build/build.xml +++ b/build/build.xml @@ -199,7 +199,7 @@ - + diff --git a/jingle/extension/build/build.xml b/jingle/extension/build/build.xml index f7e950a54..c6539e935 100644 --- a/jingle/extension/build/build.xml +++ b/jingle/extension/build/build.xml @@ -85,7 +85,7 @@ - + diff --git a/jingle/extension/build/merge/jstun-0.7.2.jar b/jingle/extension/build/merge/jstun-0.7.2.jar new file mode 100644 index 0000000000000000000000000000000000000000..df7e883fd28b9756fcfff096deff59eed5dbad59 GIT binary patch literal 66682 zcmb5W18`+)*DaimZQHhO+v(W0opfy5$&Nbg*h$Ck*tYF-baP&P_nf-_`QL9>ZB@-x zwbzv8?#!@pjjfIxxd#8idoq~ygJ-baCe6#o?p38eHH z%BALv+Wr};{{;vL_4EBdp>jgilk*g$OfC6IWa-t>D^mD+V@@%bjFamWfZ2|>ZXY_yCRINAUEx`2FsF){s{fIlwhXMmNVo1weq-^3yQDbC8-#ntX_qOt!U z(S|NAPL@WlF8}ju{+Sy$>PuoKP#_=yI)KfhsyU27$@$W~R$rl3La8!{|I>bK&ru273LvY7+xI5c^`d0tOA z`=VzN=9LU9Rert{&K+KaUKyP!mX7S@dQb2javkzMZmhpPFWNHzb;Ql9>-61YwlPjc za`LP8!LhAHJ7Pu~LN*&=4%)J{8yk>DPGcHjvc#+4?~d{pm?c@Y;0z=O_@K^$^UomC zRcX)H4NqE6;ah}*opkICT=(MwdHH7$H}c!t4~d??$k;m&boD8N70`TrU*-4dvJ=e zN>92^_b$l?uqzDvrg@0Ks27?N4K)=RXz|TAGY`V+Y|m5cSSe}Q>|`Y_B{!)QOL)vW z@hy0gH8MX?i!~+d?0C&2vH>hSwXA|$?-;@}8)%lr;G5R0NXfr-nMp+r&~mahlakx! z^@wOzQ{#fLkRM#vMyRxy@5ptS0<_^^M%DWP0c0q7TU`OBC1j0)gqR;^0ep%ab^sSP@dE7HS|Y5JiO!*qi+onlh+{;dTcy#v!Z%e zSTc6tTuHsIc*vgHUn?Ce4iScm<2H-G)bY9ceE6tAKgv{)dc{?vHnX>CaFD-=eY=9haf0e$m@_D)Y`voe<0>){jiNl-FD`Hn$N;J5g@-Cu^*eV|yNy z3-2q%MfniayWj?8?v8y!hrZX@69iOfy>WZGYol!Ug(Oju7FLYjY`j&2m87gRS z0bs?c*yoy3K><=BWlani&oGb4oN!Y3_L%-7uiYmHbtB&m#ho#ntSfQysr_PC46oEr#x9XpE~7C#TOP&_kJzUh_zlV;lDBqFrnTE3 z{~`~+K!yH8@~L`PF2%II)t2;UvR(#Si7%jZ5 z0C4ei3sk5*57eRMDNyM2e%y>R{oQFw1Gl|7fq$3Ef7TxJq*4xzu$H#zB!@-TEbqKT#Q78 znL`Pcjgn#$QxmQT!J*0^#Y0s4Yq5LMm%cOI_+j=0$H$TKnn7lzIAyHD1`XJr7nUsO z^r?pYsu{JK<{3k>8m)nK&m>BhtzrtkLCaxrL4}L@S$1yY;H|dGID*WeE}hw0vK+ef zG8o@($_aZ6m{3F7O)9YCvHPXWw%8aGlQ}m3nrfEP%3pEH?v4w+q&{yG<};Ld>Rg5% zD+9VX>hmxxSWTqs%of`H8<&o3#^^RrrsD(~Z7hLt1Tlj;!;h;rMfw;0HJHfWvMVo) zSa9-{syMs~bK7+`k>@lrXqUvGtL#{KVN}87X|)ulYlu$ejm|Gd*XgHdeG!1BDEoF2 znNL&jA{<{<{53EOvzbsMlbEpHpv*W+^pTF`UU7IsvYFQCNCWy+WWf}mK&x@|-tp>PdL#vK{4Gje1P7j^36wWgu=PCOxKvM`US)04B4^;EhK`B zIi?)CLf56vN%DyQ%^s#B4IGND)(vYs;@hDdNhVwttDEFQHd?Y4I-T<)WJPw~(sGjB z4uKtl2&*xVCF`spl0J{6(2OPU)QU{I6sRN!@iAYGFQ}UoLVnx=rWB$)v5tVH6G+$> z*u>}=pjIKsp6dWkFt=C4p2rtRG?rtKhR#)yCq!f{;%f`MT3I{|$$nFf&0Htwl0 zzVvP=WglI5356xxTbbPb^a?a*0rCG!6P0N{HQo3LmVGcFAhN#&i>Rxut>?cmqN=Sj zD~S5ugfSBe1ctN^2nQ}HLq@u!begS|pN61jfoCW=*P4+^lCML0`7x(tIJXV)RERrS zg2n?&%+0%Zmb?0R&gEUV>F=`)!WcErO3qXaz?roya?pg+$RTaO+-#YRWu(~b&lR~>rq<(yl)m1Bq$gM>)Ie5TxUy#kVsspw{p&qFBk$V?N&jc7@SPLNX$ow z2H?(;GlmF!ce2)+7qXIC|F>y=IXrk+uiH2Vsm=7-WpE%`D8M;P*WJ4cO z9nX6@wR|}vj1gUz0cS@o)Z>VTqB*C_hiCBb>;|xw(Z<2li;lHHix#&fBP@YRMtIil zySU2}D)JSX!tI&k8bx{+gu266-gyOXS9iqnPFh{V4U0US%q@b$buv^&Sfu@!IYI}z z0Qs?4Mz85Z2WQ78ia(P?i8OnYz$ZZj!U6$N{q21(=Hz7WBw}x3`tRmc+ZlBp{XO$I z;{p~1Gc4G75Nd^TxF{wT^1wkjJYJAA-eC+h0<@T=UWz-zC2pNB;##L;^YXXJaa3w5 zLN50XRs7s^ue*O70>7r8w>zehtkN`d*>U5;%IWX(MvX@VfsYUFZ|feVU?iLggM6Hp zJE|~EyA2U6>`&G`DmTAft$&Wmnd}yqb|sfXI#NP&2-TdC}2a%27?pBWe5hlZo&+F(?`Q@ zAc89sNS+ji+?WozEX~%L>y~$hH`li_AZh zT?l4>OFfr!u+t(D|L4x!21#Ln~k#Jze`Z=US8VHW8X70AIr z)eZw-xN5hzK}QlN>tZJUHH%s(2wjQ;+!FzpC{b}yOm3B(DYzbK>&_EVcowXC93e5- zwwpP2HkP0IUaX9HJ;b>aTY9fS26sGar_mmDM7@+j@=G@5Op}(PvwmCrbmiD}#v7GC zw={o!!?weT$5wz7=G0qbeB@RbsH zGNW*q&^jed0?S4f^p?0rHBt5-AF$RZU9`a0DZS z%d@uM3L>Xv`a`vg`c(nVY`D5VyUx=3R)Gw1UPI;f38V53nCQ$-$lqQLYMV+mxcS3U4xsk-SVK3Y(!SufVjm7?8BL zo4}vEW=XhPPWjccUQE&bxCp|ot^+@2=kzpBM@F!eA|4Q`h?MPv zHpuudcgwS|vCAw!5LVc1p0t+Ner)W|ECdQEkU3?1ML@VB0p9aOD-$Bn!iOsMZoDdv zyv6dTOa3XtE&Ut+7_=-IX67T&t4KeAK3U1vkPgU^p*fJ}X;xy=KGzXvs@ep&@-`o1v-{g)R1>qo?q3p#hYK+zNHZoqpqYHk$`Td_du!z9*Z|%*&b0f!{_Gg_*vuTvzQ0!5rjSl5 zx}AB#SzFL%JRvYL?jfwwJM&eVh1tv?SsSM_97A3~){WRhUV#x;qf2xmO7bg)(|#j+ zy+7}&wy|18zS*y?B;u%>Z_^pLu)mzX^#agXAKag^p0#yApXxQK5U_6>?kvXfg4e(W ztqF{BEIYy)VwOJF{sxsdz@|XjPA<2z*XeO`ea$aw>i5DKJiZ1ZfvsKOA4P6R+CaF1 zwae~@Z#odd)v{X`I>D@aJ3AdLt>b{+ZH={Fdg#nqnbrQAm`iE;a$4I z_Hb8w!qax|_C`{)dT+Bo*hTipQ#XI?_GaXMqisX*Gql}H`B~Nb24^itK^I@$il=x5 zTKzsQ3hRKvGU%ya@}6Yu5Oea8w$<6fIK`89u=BPf5QX;|rvK29S2~;i#vdBKQ`QI_ z&8rNVqChdrVBPj^S|ORui?a%GMUdddA-xXtIEYg?LtbB7^@IGFK~C14zNFToeYM-8j#_ZRq$u z&TVXBen(bSd`)+agXc@fxudxV!%fdF1&uzRFYf`<-;=T)*cARSP_Aj*R zg=eIx0d3h=0oLo`uAC_MMm^An;=6{B~HKA`Vkbspf5#VxJGr=PrF-Uc)D&$ zFJ`DjvfYRPAf)Y!vS!@~34u|Km%G0ag56)oLxO7jQAt`}x@Lt;UU9MBR28m$+AjYi zLjH3>KME^D;_`_QOL!n4g}?39{)rN0Q)dTzJ7?2>N{c2c_O4FGrvF;xE1R0xm>Rp7 znut5u+y1+w(^Ns#Kz;XWvRfhF5nU6s<-j!y?r9-KVhfCn4a6P@*;*K9o#K>LX!BM@ zuBX7Rrx>IiWL6sy(Ywi4L;7xU?CqyYy?Jiw0Lp3w#nybu_n3W|dz<5I_bBl3?u*c^ zrK6G1dreL1C_E?yR;n88s8tDv7mi%4ZVQ@ z=mTZ1&XuVQ(w=|LLrvM7xrC6A`hhKfkCS~2R1^^j67HwkfTbZj6F}>e1cudl=E3uw@ zrp_j_G$+ShIUgJj&+} zRE-e6bLddm&T`myWlV#6<|<&i9CO;^y5toruJ7xf5J2vIy?B?& z2{!#M3zHB1HrP77XWRM@p1>$GxS?PI?HaW{j3?zm4eYK#4(6`;E4*rpCwvXIGw>{{ z*(7g|Z})QM)VMkALC>>rN@8v1t8F}zkF2lX2u6&;^ex+hx!U$mz*cA1m6cR;GG?z( z{1$5Pct8~vSzQd$f={-9)?IM3dIsMNq7YzG2<7@y7LU3@gU6k%k)TE>C`1Ptklh4+ z;3x>&8hM?+Jfhp@b_d!Q67O#iO%CTCyM+(rq7$JzA!nM^<&i^2M(C;*=~hPq!kU%na&5dD0U2hSItwmlBr<-%+^$J#uCzz59CI$$<_Q_7YUzmj0$9$#c;o6>m15Es@!lySPZfTqL(K|c-!@Nlwpbz;B5?tEm6Huv7KxC_bpQ zq(kXMC!X-lc_6loPw|vp^3ZVUL;*Sy+B6DZLr-|VpGGXk8D77snyhoC+LXn;QadSg zWF!^KiggZ0@Fyee@{+;4#3Ur|2o%CjGWF?WBEipB2kS!I!%~Y=N;>HC$0?%Lm?SrJS4R;p3ia$ zY6i1cL@bG_howgaWeM>o3N`*sGDi#Ry{b4^<;Z(bpZ=aI!eK#%-RtO3| zzsVvg6bhh`wCO}e${EFxnnt9ouu#gLsWxo^Cv+hatsmWKaWA83WbG3zw~GD_@#i)W z`;JnZ91;kq83hQ4@$U)lQ>QjGHx>H#w%flL?5nj0syUh;#q#=cj!nxR5nVuXiO#s0 zNL>SEgH%2#Rq~cF6R1{Eq=;LhO&d?v!~}9+ntG8Ql6|95rYw8o7S z-3s-J_eFtsrA-!=cBm{95#PE=mP7ADAM*)!yUmQ}hf)9BPS7p0SKYpxVauh!Afm)= z#2rpj6VYKqB75{3bRv7S8+IZDNKeJ#)eu~y8+d^=eNFu2!vF?^S5L%Y5H^HBPsC9W zIt1$eu0m}5ULLj%n9GGL{0@!2mtfq!7dBjsyDvlp{b8&=m;}>TjQr)>NItTCP(C_+ zg-^ke3gFjN)AyEe&08!xSH{%*6^49HLfOgJjzoDdJ5X2(mLAA?i&tRT>epgug+e}3 zB0OEV{Te1#vIAIX=4!mfgz=+yk2tA;WYwVaNZU&=HxwSheJsvwIpf$24DGp2cUAPUCaK+T`AO- zYJE)S_a>AIQvV4Y)Ux+5yv9YyUZL6N22%WRsKh(Nn5I;ojCyY(Ix%vX-8NNBn9O>f z8*TmjVYrE_QFpn7aJbtgdP$kDOR}#E9&F`6q;oJnXFPo`gcFZr+|RqaEQr2L=Td$9 zS1-}}D0WVU3%9Wy+g-4zft-o{5DimOXfSE`d1`SSB_#?D^_m!Os(Z79!agS0d49C# zaf3YZ*>5TtZf`3NsTq8#C(?H6f>j^trG=~;YMs@T5zWrQ)S_fN*V=$z0Ji8H4_(a1 ztqVrIsP-5FJD(rQyY39b_lXVQ1kDP~CyWz9;amvK?(hADm64 z>vhJiurFwv8jfOH2&%7&197Un4DJHz*C<&2Yl8%@u15URN+W!;UZZ$sVul(eyQ;)$UqfrOi)Q z#IWjrlBCIUHP$qE6t`^`@hMUqSHtYOKXt|nFk-lJnJ*tO>h%+-y;4OB?2@7RBc;8U z8_cuqHx-=@q@J1V&&)|7Xn0j}_ti0{ay}&nra*Cg^o^J)Ez!boV4Onln!d^j-K}V7 z)EE$3xZ`26df9?mf5dfG8Jz04f{Gio^Rt?euAo3g-P$~?i@SyUc2hb~^FUbCPTQ{K zvDC4)&a88VJbPZe21jmPR2pV@Wv&GAJZEB0e1+n^th#KFi{dgtSfW*O*Jp<5;Lbs< z9h_nQ&%tk{j&2vPYwG!I?>Y-OSo)7GNcC_J7pg74>fW?{r&BYv zaeHtWv`k4_>D14}!!h)YAl1QB`8mss#ybAmpZq;-N-sICL^JbJZKsNi4a1b3Ico+A zBQ4EBFvKc++{jX|uCb^qA~91=U$5?7>*2Vltz&Rea~tYJpQ-+?h}b?|%u%SJVL+vM z)CL_xK&cHj@?qTu%q@kJ?J}?9%X+iO>6+gjn2CP|6qD_VGMviSjrNF=dGR)BIf(P< zv7JSClX5~b^vS#93EhpMNt4+5*=5l}`)n>yJ!5S)nS8uj^-Gvv+KrwEkh1RGSL^*G zzjC%{KuxFibT6{=o;*p0sBWG|L{@&aH{zmkC5TN5agmg=pE(7OO8y8#h?*8bbqlG% z@#c&SZ07^hrlhLNqzq?|Ewm9H<4sPYFGwwhELfO!$)P#7L?$(hKzc-VvAc5t2gFR~ zcPy3TSW2vu>IMW>3kogjb!^O{(QrPojt)VW1H(HHuug>3AUt{@2q;)))EAm>^ML)d zPwrOO!ayX1gj9r5{UQ{Y|80s26rIyKlhC|QIGzOu9Ti!XN)m-tK`|u%Syh=|i(RY6 z6^~l#)KU{v&BB1O@N0xPt09|0sT^+v`|LI5xqi?a?>L2Ld1LxA)TRx?Bhhp3tfAff((aq#hAbY(0(i)rcMA1BN}W z^wp>xYXi4~sUbS7{<2s!H(q>6el#e)IH`ppeocu@wMXnzVKI06Zm>ou@XX*6Qvt?D z*?aenUY!J2R5!Zv6JMTT0(Z&vIwc+OB7)YWa090uD?8?zT!=61T5X+2tpIC*dO4sT z=J}V@okVxW-SgTdbpX|i6t9l~1759-uNMMwYB7h`=`FCys;dGPg~)?%Mj*+cP0Bn1)& z%0pTqy67mXPALh+1j55;(OF0;Cgt-B{R+H5Lq(aRvxv#B3baFSsCC;0`S8V6!*Cee zC~s^;$Qi1b+-6IgG+GC%-1LTTR$ph2OQ z&q*6lGA&acV{F^z&^+3yj{8MD9#2o&oEgy)0QI#8m9<8{a$lanh!fs<7Jt8qZvt4L zr;c-^KaTl)SN7Feb_$LB6)f~jjQq@${8(R-S`Aax%D`zL+6kmlGO|5GFRw0L+amsf zR+T#aH~)%C)%TXT4yWo@`=a4n$2WgsxmJNSCf{Xz%7)&u#R_;=%2uga zH?p$(on+M49r3gBdfQm!t0}x@iRrUkt)>Uzf7lN#PdD3_KNI}9=OEzwp-%tloZ9+) z{^7d%AHUE)eL(-??2-FR&mrbvZ0g`*X>a$><|8MbM*&y}HDpo@-w{j*QI=Nr%tus% zNiu+l>3f7(qtG!#I;}{mW<5*AI~@%QjQ=-*Q4e=tw86mx{;qMZLo>b2Tz#N3mDa5sX~d4C~^#>YQTA_;<x-k+23jJU;Z^=aqIg#ZGQ|6e6R%Fe~q$;{B$l=QFZ zQT25A_g0mfrSqyPDqkep>9V?&sijO?vq^1^STH>;JQ0zcg;pt*5;7y*IORiBg@KGv zYS!^jzzM9Wfx+(#|Nb=jOJ8(bVGsh$F_yz|&&v(>wC1Ntji2vd4B$6S^LO3QX}+>C zns3RYYt#%nXlz-fl3&(}i5X;j>KX(-cXgBAh6)Be2M8uS(*z*jmUN@mlQ913AY<(7 zpko~CATeO^x81^l13A6u38-Y4KP|9nW{a*wX@zS=6)R|7jo4e51u5&%x%I`O=U8{s zPMlwt)?InIKzW?1e_T}>YF__&e(q0Sb0ERI=4|bBR#ZHOeUnw^i}+;wOdb)iKUBRL zpLH`7Ya>yVlaI2nF_CvN@$;9KO|$7yJKd-%Z$2(UP)&7@G_VtR%v4ma)o^97AtF75 zYh6Rr8^P<=lz$Qe*h;duoMx1XFB_~D_HTQ4EjlNbLAO-uRhrmPZv<~muip`?XAUBZ zFax>tmF_a*8oc@&mkn;FE&CVjmi>xI91pBM`rjQ`+oh@+@SGlT_Kg^vG0Q>Onp<~6 z@x$bIPSkoaa6Z<@NZ$`9=iiFrGY3T4!|~2Jlxno5w}eQLkESbZQ4h*S zv&b^aGNWQf!jgqjg<6JUg=&K17`x=fx<^m=R$)Dg!n3&df4Z$A|7*L`|Cd60pAl@DchJnIBp(o=_xpL`cftn<@VbMPH zXs1k!h2`&ewP+DK!DjMb#$1^^@{X8ODEf}u+mJby^hW2CytFBrhy4pqgyAjlJ#A{a z;4-~$DA;TfHg8LXO<`5iL*$L4=m-L{xD19N-tU3n0-S$$tv26=KdhU$U{n;RNc!pJ zl;dcgh~yr4hl^R-#FflRI{i%=meP^BN>mSOOwmX&f~cUs2AM>C@uET59J#Mvy3^d1 zP9lZd+%%c{#~c_<#hh3%y(U*Nz4pOnkqVRUc{x7Gq3VmV*F(iIre~>DKc-7L@nDTg zqs0*`QcMmRphpQH8+|L{_^|Copm{1eHo(x%I;410s)STtw>RGHbRQ@I3qpl z_>)J<^y!rlN_CAh)!3UdQIs6ijIUz7BzB)O+DZOfOZsvlr<7Q>UevbefupH#e&p?W z_u*ZI>HwG8YTYZj=^ZtISJe<-1YdM~fu!DKmzUdlFVT_Db*qmie zx5_qbKp={zUK1)JsSY3si*|L3saSV77E{5H-~_5Hc6dTi7;$Cpuqg zYh>AXnLjg(_L*V9|5e>qG<0&dv@`!JhboOog9st|qSbGuTgb|S+T(*_xB!q9QGk)r zl9hrjE^>;ncx1gy+9clS6apaxy5o?o2lsb`u9e3MH-PVdKfD4P;6%Zf)F=v8ed8{$ zF)0$AN=r~G=;G%ip28}agKMl6UhRT3%2-`nwPb(5krVE!YN*2#ww=d`;@JilezBVr zmwu^g?Q zOAK0)e$>Gx@$q~D(}9jHf7=Z!=xEGt9iT?BeC^+sAP$^`*|nflP&I14$y!neDE71B z_V#?RAh~_Wznd9iVZFl%eii;79;K{iiFUypbC~>L&l`Y0n?CYVCl0M}#5#vTLG#35L-CS_FEPOjtdpcPZS771Sc z5=sAR<*j|=3u#|_a5-0czR(aIr6PtWw4bTRFbeb8tQw;!&!0OozT2K1q;7a*($%W> zY~byrswLH+M88CDSo^kqI4zQN4fI=*Kl3ox52Kl1S!PZd79XJZH_fd8&IhREtPFXh zsbs^D1hWmhZuPJYT?3b_z-Y%A&s_9=Xt$bo5FV_sNZeC*T3o$2cq}>wXVE!N&XUA5 zz?d(+coyMB<_BC-yvNDeuZQxSdIrA+9rk>ptoGD1Rf-=`pvWu@_mSzz_oNEd5zYDUiNDxWX%uJpeb zHh{njbQA19t^G>XnnjO@aOmbVt}GwtSCwqqgh#+&?6ohlp>Cv zHfNbJ#Z z*GwD#owFLn2CDxi1OiyAaWet9-gPL2r;mc}nC)C$f%?#I^@6X4PvV@U0G-#(C!oA-kVtR{@9YxQ-8+G|2k7 zx6t-rI?0a1gO<>0&0~h(0XP7wcn0{{gfPDA-d7tQxb*TjcQs5uMAIQlgwOl5+x9*4 z6t|lJ%CVpSQRBX?#601P^3Q@-S06J295oP_r?qbARJd`&jc%?rW(RGmu5LU$HW2sg z;@GwTa5vbFsCwXv4|(D3E;2^<4q<6Oh3;4L;LtnYb{hLGR7f3OJ6_oA+Rz_6<0RTxzqL^N5A}GCg9m`?BV5d zbT=|HxeX2BHQCr+MyqH#IdG#5)%E5X13b-fTbAuF9t&5ICKr28nS2ez`5A%*M;~~- z=PnSAtmO57c~|i*!;dzih_a

*!)mXuL}}dBicy(du*d2rz&TfiCjS;bOG5M`kFd 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 literal 0 HcmV?d00001 diff --git a/jingle/extension/build/merge/jstun.jar b/jingle/extension/build/merge/jstun.jar deleted file mode 100644 index 1b8ac75199e8809e0ee2149fec6b04a59603e46b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 76890 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

Jah({J^nRKERjN!1A7%V7I*j zQB=sO;p6#r!_$$^iaqLn>5b_~cA=lPgx#jue42&s)9l& zp0hq8fu4Plqgui@wre)FY2EJRbDGSX0KAlJ2Y`Zf{6K`kHF16|wjpc!AY^5v#trU~4AY_}D>+>lZ z1j1EsSS`rgKQ^tLD3T-BfhQNZ{x&)y`R_KZ{(Bx&+}h-?)TR-Mnu;i*DE(i%ja}5h zdz9r`d(M%x)%0_7$aUoLt%a22!jr;=kMRA5VaG;7UD-ac=;Vk~4?}czFnwrU@tjLdH`ad8rZCyP}vS*+S{rng(ccRq1K^XON&zcR25LX0ezYC07jdl(A%?i!S>V6S84~n=2S8?u~NB zSy}Fhn?f)QOFmSPZ^gyE3(rndm=@(UGqxj79Xw)i{HQE#IR)0MGJW#WafJR@XH_qr zg@Lo=V^rz*`2JR60>%#3uMuoXF&@SbXg-2rZR5}N_iG0 z`DeM)uttE{KeF=}?`hSjvgf8Ci+c`a z?RBTj?pqt0m-(NO8*2qbnUy&X$3>;oYhKl;T9MH*GmcZq_PN`$f=UaE6anwDvAkwmh)RL(u7&h_Gl=)2>%Y8@RF@d%0_yIVp=5$8VJqMtHaIFTCQ=*gQRlIWH^twX=<5jrtieEGsIb*>O1ygGeWv{20$kxVv1C@HSz(GAVc^7RtON z*!qgegbGf*)40hCmuUd8-L8b|udZv>v|(vtRit&!A%-BD#4{=|p|@+oKIZywa;xXb zE`+a;!l(_oQ5U8OB>)5)f|NN1K@jwq_-AA?TaIR)OBN`toyVuOG44h!PkX81$?Wfk zTMUL~AC`1Ys#(oOjSt=|vO1Iu?*z#PZ%1)GNtuR zxL2c2Om4;ud17wX!lgpgJDu*K=ggjZC^809(2@p&$$W+!ZM}BxQzUU`>A5;kx=Mxl zEeCauaOn-b*sFW>sjUsOmTa$%(JBEKi{+84pAd@Rt;m}E>I#{41OS$s*pLzVmGWIV zal)8k_GkoX`e=k<&}h+px0Xun_Bf}+O&JqDZ{z~WDe2#MA-bqi2;D#TFjxpZMs z=d7VAvJXRQ^wFls@6x_;J_1j}3zB7d@@it8pA-id>;gtYXDb1g!;cD=Eyi-K32`EX z*5>0A^+W~DX|=vdnw`D5_P{vNH%QEo6*vq+6W$z-Xh(|9yW0~MXB62mGB$MS!cbSS z90LG6BNjnkLAQOFgSc&TBAG1dI*!q2J+mAe<5lAqGaIf2w@Hmh@#Ed@8_RNQ1aTJ= zJY14Zna0S~b>KBe&rK+9YOP2T06x?_wYC0VsJTLnRq=;?^b(>n^ZnE~LDk{M#t84! zuaP7fqqgPf!}d%UWT|<4sM~=5eNP<}oX-}OPnSe;WV%n5kn2MoWNKP`Rtt+TeEu?l z=p8kxS3+gTwh+GL*CT2~zAypm{g(;3?|_fP^wnlQ)R~)VFV~CRLpHi%p{Th*o2Ht( zsmci|;*=k@`_0DoeW5Xi;*+Bki`?|@nl|o`9�gdd0-rg|DjFE)xmx%9Fd6bM2m% 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 diff --git a/jingle/extension/source/org/jivesoftware/smackx/jingle/JingleManager.java b/jingle/extension/source/org/jivesoftware/smackx/jingle/JingleManager.java index 724580d89..7ff46a719 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/jingle/JingleManager.java +++ b/jingle/extension/source/org/jivesoftware/smackx/jingle/JingleManager.java @@ -20,7 +20,15 @@ package org.jivesoftware.smackx.jingle; -import org.jivesoftware.smack.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.jivesoftware.smack.ConnectionCreationListener; +import org.jivesoftware.smack.PacketListener; +import org.jivesoftware.smack.RosterListener; +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.filter.PacketFilter; import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.Packet; @@ -34,16 +42,13 @@ import org.jivesoftware.smackx.jingle.listeners.JingleSessionListener; import org.jivesoftware.smackx.jingle.listeners.JingleSessionRequestListener; import org.jivesoftware.smackx.jingle.media.JingleMediaManager; import org.jivesoftware.smackx.jingle.media.PayloadType; +import org.jivesoftware.smackx.jingle.nat.BasicTransportManager; import org.jivesoftware.smackx.jingle.nat.TransportCandidate; import org.jivesoftware.smackx.jingle.nat.TransportResolver; import org.jivesoftware.smackx.packet.DiscoverInfo; import org.jivesoftware.smackx.packet.Jingle; import org.jivesoftware.smackx.provider.JingleProvider; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - /** * Jingle is a session establishment protocol defined in (XEP-0166). * It defines a framework for negotiating and managing out-of-band ( data that is send and receive through other connection than XMPP connection) data sessions over XMPP. @@ -179,7 +184,9 @@ import java.util.List; */ public class JingleManager implements JingleSessionListener { - // non-static + private static final SmackLogger LOGGER = SmackLogger.getLogger(JingleManager.class); + + // non-static final List jingleSessions = new ArrayList(); @@ -195,21 +202,7 @@ public class JingleManager implements JingleSessionListener { // The Media Managers private List jingleMediaManagers; - static { - ProviderManager providerManager = ProviderManager.getInstance(); - providerManager.addIQProvider("jingle", "http://www.xmpp.org/extensions/xep-0166.html#ns", new JingleProvider()); - - // Enable the Jingle support on every established connection - // The ServiceDiscoveryManager class should have been already - // initialized - XMPPConnection.addConnectionCreationListener(new ConnectionCreationListener() { - public void connectionCreated(XMPPConnection connection) { - JingleManager.setServiceEnabled(connection, true); - } - }); - } - - /** + /** * Default constructor with a defined XMPPConnection, Transport Resolver and a Media Manager * If a fully implemented JingleMediaSession is entered, JingleManager manage Jingle signalling and jmf * @@ -252,32 +245,28 @@ public class JingleManager implements JingleSessionListener { } + /** - * Default constructor with a defined XMPPConnection. - * A default JingleTransportmanager based on BasicResolver will be used in this JingleManager transport. - * - * @param connection XMPP Connection to be used - */ - // public JingleManager(XMPPConnection connection) { - // this(connection, new JingleTransportManager() { - // protected TransportResolver createResolver(JingleSession session) { - // return new BasicResolver(); - // } - // }); - // } - /** - * Default constructor with a defined XMPPConnection and a defined Resolver. - * A default JingleTransportmanager based on BasicResolver will be used in this JingleManager transport. - * - * @param connection XMPP Connection to be used + * Setup the jingle system to let the remote clients know we support Jingle. + * (This used to be a static part of construction. The problem is a remote client might + * attempt a Jingle connection to us after we've created an XMPPConnection, but before we've + * setup an instance of a JingleManager. We will appear to not support Jingle. With the new + * method you just call it once and all new connections will report Jingle support.) */ - // public JingleManager(XMPPConnection connection, final TransportResolver resolver) { - // this(connection, new JingleTransportManager() { - // protected TransportResolver createResolver(JingleSession session) { - // return resolver; - // } - // }); - // } + public static void setJingleServiceEnabled() { + ProviderManager providerManager = ProviderManager.getInstance(); + providerManager.addIQProvider("jingle", "urn:xmpp:tmp:jingle", new JingleProvider()); + + // Enable the Jingle support on every established connection + // The ServiceDiscoveryManager class should have been already + // initialized + XMPPConnection.addConnectionCreationListener(new ConnectionCreationListener() { + public void connectionCreated(XMPPConnection connection) { + JingleManager.setServiceEnabled(connection, true); + } + }); + } + /** * Enables or disables the Jingle support on a given connection. *

@@ -429,7 +418,7 @@ public class JingleManager implements JingleSessionListener { jingleSession.removeListener(this); jingleSessions.remove(jingleSession); jingleSession.close(); - System.err.println("Declined:" + reason); + LOGGER.error("Declined:" + reason); } public void sessionRedirected(String redirection, JingleSession jingleSession) { diff --git a/jingle/extension/source/org/jivesoftware/smackx/jingle/JingleNegotiator.java b/jingle/extension/source/org/jivesoftware/smackx/jingle/JingleNegotiator.java index 88f020227..ee8c98cb1 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/jingle/JingleNegotiator.java +++ b/jingle/extension/source/org/jivesoftware/smackx/jingle/JingleNegotiator.java @@ -19,14 +19,14 @@ */ package org.jivesoftware.smackx.jingle; +import java.util.ArrayList; +import java.util.List; + import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smackx.jingle.listeners.JingleListener; -import java.util.ArrayList; -import java.util.List; - /** * Basic Jingle negotiator. *

@@ -43,7 +43,9 @@ import java.util.List; */ public abstract class JingleNegotiator { - //private XMPPConnection connection; // The connection associated + private static final SmackLogger LOGGER = SmackLogger.getLogger(JingleNegotiator.class); + + //private XMPPConnection connection; // The connection associated protected JingleSession session; @@ -78,7 +80,7 @@ public abstract class JingleNegotiator { JingleNegotiatorState stateWas = state; - System.out.println("Negotiator state change: " + stateWas + "->" + stateIs + "(" + this.getClass().getSimpleName() + ")"); + LOGGER.debug("Negotiator state change: " + stateWas + "->" + stateIs + "(" + this.getClass().getSimpleName() + ")"); switch (stateIs) { case PENDING: diff --git a/jingle/extension/source/org/jivesoftware/smackx/jingle/JingleSession.java b/jingle/extension/source/org/jivesoftware/smackx/jingle/JingleSession.java index 9bbeb158b..5efae61e5 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/jingle/JingleSession.java +++ b/jingle/extension/source/org/jivesoftware/smackx/jingle/JingleSession.java @@ -52,6 +52,12 @@ package org.jivesoftware.smackx.jingle; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; + import org.jivesoftware.smack.ConnectionListener; import org.jivesoftware.smack.PacketListener; import org.jivesoftware.smack.XMPPConnection; @@ -65,7 +71,11 @@ import org.jivesoftware.smackx.jingle.listeners.JingleListener; import org.jivesoftware.smackx.jingle.listeners.JingleMediaListener; import org.jivesoftware.smackx.jingle.listeners.JingleSessionListener; import org.jivesoftware.smackx.jingle.listeners.JingleTransportListener; -import org.jivesoftware.smackx.jingle.media.*; +import org.jivesoftware.smackx.jingle.media.JingleMediaManager; +import org.jivesoftware.smackx.jingle.media.JingleMediaSession; +import org.jivesoftware.smackx.jingle.media.MediaNegotiator; +import org.jivesoftware.smackx.jingle.media.MediaReceivedListener; +import org.jivesoftware.smackx.jingle.media.PayloadType; import org.jivesoftware.smackx.jingle.nat.JingleTransportManager; import org.jivesoftware.smackx.jingle.nat.TransportCandidate; import org.jivesoftware.smackx.jingle.nat.TransportNegotiator; @@ -73,8 +83,6 @@ import org.jivesoftware.smackx.jingle.nat.TransportResolver; import org.jivesoftware.smackx.packet.Jingle; import org.jivesoftware.smackx.packet.JingleError; -import java.util.*; - /** * An abstract Jingle session.

This class contains some basic properties of * every Jingle session. However, the concrete implementation can be found in @@ -85,7 +93,9 @@ import java.util.*; */ public class JingleSession extends JingleNegotiator implements MediaReceivedListener { - // static + private static final SmackLogger LOGGER = SmackLogger.getLogger(JingleSession.class); + + // static private static final HashMap sessions = new HashMap(); private static final Random randomGenerator = new Random(); @@ -98,6 +108,8 @@ public class JingleSession extends JingleNegotiator implements MediaReceivedList private String sid; // A unique id that identifies this session + ConnectionListener connectionListener; + PacketListener packetListener; PacketFilter packetFilter; @@ -264,7 +276,7 @@ public class JingleSession extends JingleNegotiator implements MediaReceivedList public void setSessionState(JingleSessionState stateIs) { - System.out.println("Session state change: " + sessionState + "->" + stateIs); + LOGGER.debug("Session state change: " + sessionState + "->" + stateIs); stateIs.enter(); sessionState = stateIs; } @@ -307,7 +319,7 @@ public class JingleSession extends JingleNegotiator implements MediaReceivedList String responseId = null; - System.out.println("Packet: " + iq.toXML()); + LOGGER.debug("Packet: " + iq.toXML()); try { @@ -505,7 +517,8 @@ public class JingleSession extends JingleNegotiator implements MediaReceivedList } // The the packet. - getConnection().sendPacket(jout); + if ((getConnection() != null) && (getConnection().isConnected())) + getConnection().sendPacket(jout); } return jout; } @@ -689,7 +702,7 @@ public class JingleSession extends JingleNegotiator implements MediaReceivedList */ private void installConnectionListeners(final XMPPConnection connection) { if (connection != null) { - connection.addConnectionListener(new ConnectionListener() { + connectionListener = new ConnectionListener() { public void connectionClosed() { unregisterInstanceFor(connection); } @@ -706,9 +719,18 @@ public class JingleSession extends JingleNegotiator implements MediaReceivedList public void reconnectionFailed(Exception exception) { } - }); + }; + connection.addConnectionListener(connectionListener); } } + + private void removeConnectionListener() { + if (connectionListener != null) { + getConnection().removeConnectionListener(connectionListener); + + LOGGER.debug("JINGLE SESSION: REMOVE CONNECTION LISTENER"); + } + } /** * Remove the packet listener used for processing packet. @@ -717,7 +739,7 @@ public class JingleSession extends JingleNegotiator implements MediaReceivedList if (packetListener != null) { getConnection().removePacketListener(packetListener); - System.out.println("REMOVE PACKET LISTENER"); + LOGGER.debug("JINGLE SESSION: REMOVE PACKET LISTENER"); } } @@ -728,7 +750,7 @@ public class JingleSession extends JingleNegotiator implements MediaReceivedList protected void updatePacketListener() { removePacketListener(); - System.out.println("UpdatePacketListener"); + LOGGER.debug("UpdatePacketListener"); packetListener = new PacketListener() { public void processPacket(Packet packet) { @@ -763,21 +785,21 @@ public class JingleSession extends JingleNegotiator implements MediaReceivedList String sid = jin.getSid(); if (sid == null || !sid.equals(getSid())) { - System.out.println("Ignored Jingle(SID) " + sid + "|" + getSid() + " :" + iq.toXML()); + LOGGER.debug("Ignored Jingle(SID) " + sid + "|" + getSid() + " :" + iq.toXML()); return false; } String ini = jin.getInitiator(); if (!ini.equals(getInitiator())) { - System.out.println("Ignored Jingle(INI): " + iq.toXML()); + LOGGER.debug("Ignored Jingle(INI): " + iq.toXML()); return false; } } else { // We accept some non-Jingle IQ packets: ERRORs and ACKs if (iq.getType().equals(IQ.Type.SET)) { - System.out.println("Ignored Jingle(TYPE): " + iq.toXML()); + LOGGER.debug("Ignored Jingle(TYPE): " + iq.toXML()); return false; } else if (iq.getType().equals(IQ.Type.GET)) { - System.out.println("Ignored Jingle(TYPE): " + iq.toXML()); + LOGGER.debug("Ignored Jingle(TYPE): " + iq.toXML()); return false; } } @@ -882,12 +904,17 @@ public class JingleSession extends JingleNegotiator implements MediaReceivedList public void transportEstablished(TransportCandidate local, TransportCandidate remote) { if (isFullyEstablished()) { - for (ContentNegotiator contentNegotiator : contentNegotiators) { + + // Indicate that this session is active. + setSessionState(JingleSessionStateActive.getInstance()); + + for (ContentNegotiator contentNegotiator : contentNegotiators) { if (contentNegotiator.getNegotiatorState() == JingleNegotiatorState.SUCCEEDED) contentNegotiator.triggerContentEstablished(); } if (getSessionState().equals(JingleSessionStatePending.getInstance())) { + Jingle jout = new Jingle(JingleActionEnum.SESSION_ACCEPT); // Build up a response packet from each media manager. @@ -1028,7 +1055,7 @@ public class JingleSession extends JingleNegotiator implements MediaReceivedList public void terminate(String reason) throws XMPPException { if (isClosed()) return; - System.out.println("Terminate " + reason); + LOGGER.debug("Terminate " + reason); Jingle jout = new Jingle(JingleActionEnum.SESSION_TERMINATE); jout.setType(IQ.Type.SET); sendPacket(jout); @@ -1055,7 +1082,9 @@ public class JingleSession extends JingleNegotiator implements MediaReceivedList contentNegotiator.close(); } removePacketListener(); - System.out.println("Negotiation Closed: " + getConnection().getUser() + " " + sid); + removeConnectionListener(); + getConnection().removeConnectionListener(connectionListener); + LOGGER.debug("Negotiation Closed: " + getConnection().getUser() + " " + sid); super.close(); } @@ -1114,7 +1143,7 @@ public class JingleSession extends JingleNegotiator implements MediaReceivedList IQ iqError = createIQ(ID, to, from, IQ.Type.ERROR); iqError.setError(error); - System.out.println("Created Error Packet:" + iqError.toXML()); + LOGGER.debug("Created Error Packet:" + iqError.toXML()); return iqError; } @@ -1145,7 +1174,7 @@ public class JingleSession extends JingleNegotiator implements MediaReceivedList // NO! Let the normal state machinery do all of the sending. // getConnection().sendPacket(perror); - System.err.println("Error sent: " + errorPacket.toXML()); + LOGGER.error("Error sent: " + errorPacket.toXML()); } return errorPacket; } diff --git a/jingle/extension/source/org/jivesoftware/smackx/jingle/JingleSessionStateEnded.java b/jingle/extension/source/org/jivesoftware/smackx/jingle/JingleSessionStateEnded.java index 0c34b13c2..3fd1f0850 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/jingle/JingleSessionStateEnded.java +++ b/jingle/extension/source/org/jivesoftware/smackx/jingle/JingleSessionStateEnded.java @@ -9,7 +9,10 @@ import org.jivesoftware.smackx.packet.JingleError; * @see JingleSessionState */ public class JingleSessionStateEnded extends JingleSessionState { - private static JingleSessionStateEnded INSTANCE = null; + + private static final SmackLogger LOGGER = SmackLogger.getLogger(JingleSessionStateEnded.class); + + private static JingleSessionStateEnded INSTANCE = null; protected JingleSessionStateEnded() { // Prevent instantiation of the class. @@ -28,8 +31,8 @@ public class JingleSessionStateEnded extends JingleSessionState { } public void enter() { - System.out.println("Session Ended"); - System.out.println("-------------------------------------------------------------------"); + LOGGER.debug("Session Ended"); + LOGGER.debug("-------------------------------------------------------------------"); } diff --git a/jingle/extension/source/org/jivesoftware/smackx/jingle/SmackLogger.java b/jingle/extension/source/org/jivesoftware/smackx/jingle/SmackLogger.java new file mode 100644 index 000000000..4ef16946f --- /dev/null +++ b/jingle/extension/source/org/jivesoftware/smackx/jingle/SmackLogger.java @@ -0,0 +1,192 @@ +/** + * $RCSfile$ + * $Revision: 7071 $ + * $Date: 2007-02-11 16:59:05 -0800 (Sun, 11 Feb 2007) $ + * + * Copyright 2003-2007 Jive Software. + * + * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jivesoftware.smackx.jingle; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.apache.commons.logging.Log; + +// -------------------------------------------------------------------------- +/** + * SmackLogger attempts to use Apache commons-logging if it's available. + * + * When you request an instance of SmackLogger we make an attempt to create an instance of org.apache.commons.logging.Log. + * If we are able to make an instance of Log then we dispatch all log requests to commons-logging. + * If we are not able to make an instance of Log then we dispatch all log requests to System.out/err. + * + * @author jeffw + */ +public class SmackLogger { + + private Log commonsLogger; + + // -------------------------------------------------------------------------- + /** + * This static method is the only way to get an instance of a SmackLogger. + * @param classToLog This is the class that wants to log. (This gives commons-logging a means to control log-level by class.) + * @return An instance of a SmackLogger for the class that wants logging. + */ + public static SmackLogger getLogger(Class classToLog) { + return new SmackLogger(classToLog); + } + + // -------------------------------------------------------------------------- + /** + * This is private to make it impossible to instantiate a new SmackLogger outside of the getLogger() static method. + * @param classToLog This is the class that wants to log. (This gives commons-logging a means to control log-level by class.) + */ + public SmackLogger(Class classToLog) { + setupSmackLogger(classToLog); + } + + // -------------------------------------------------------------------------- + /** + * The actual attempt to create an instance of commons-logging Log. + * @param classToLog + * @return + */ + private void setupSmackLogger(Class classToLog) { + try { + Class logFactoryClass = SmackLogger.class.getClassLoader().loadClass("org.apache.commons.logging.LogFactory"); + Method method = logFactoryClass.getMethod("getLog", Class.class); + //Constructor constructor = Log.class.getConstructor(new Class[] { Object.class }); + commonsLogger = (Log) method.invoke(null, classToLog); + + // We don't care to do anything about exceptions. + // If we can't create a commons-logger then just use our simple one. + } catch (ClassNotFoundException e) { + } catch (SecurityException e) { + } catch (NoSuchMethodException e) { + } catch (IllegalArgumentException e) { + } catch (IllegalAccessException e) { + } catch (InvocationTargetException e) { + } + } + + // -------------------------------------------------------------------------- + /** + * Wrapper for commons-logging error(Object msg, Exception exception) + * @param inDebugMsg + */ + public void error(String inErrorMsg, Exception inException) { + if (commonsLogger != null) { + commonsLogger.error(inErrorMsg, inException); + } else { + System.err.println(inErrorMsg); + inException.printStackTrace(System.err); + } + } + + // -------------------------------------------------------------------------- + /** + * Wrapper for commons-logging error(Object msg) + * @param inDebugMsg + */ + public void error(String inErrorMsg) { + if (commonsLogger != null) { + commonsLogger.error(inErrorMsg); + } else { + System.err.println(inErrorMsg); + } + } + + // -------------------------------------------------------------------------- + /** + * Wrapper for commons-logging debug(Object msg) + * @param inDebugMsg + */ + public void debug(String inDebugMsg, Exception inException) { + if (commonsLogger != null) { + commonsLogger.debug(inDebugMsg, inException); + } else { + System.out.println(inDebugMsg); + inException.printStackTrace(System.out); + } + } + + // -------------------------------------------------------------------------- + /** + * Wrapper for commons-logging debug(Object msg) + * @param inDebugMsg + */ + public void debug(String inDebugMsg) { + if (commonsLogger != null) { + commonsLogger.debug(inDebugMsg); + } else { + System.out.println(inDebugMsg); + } + } + + // -------------------------------------------------------------------------- + /** + * Wrapper for commons-logging warn(Object msg) + * @param inDebugMsg + */ + public void warn(String inDebugMsg, Exception inException) { + if (commonsLogger != null) { + commonsLogger.warn(inDebugMsg, inException); + } else { + System.out.println(inDebugMsg); + inException.printStackTrace(System.out); + } + } + + // -------------------------------------------------------------------------- + /** + * Wrapper for commons-logging warn(Object msg) + * @param inDebugMsg + */ + public void warn(String inDebugMsg) { + if (commonsLogger != null) { + commonsLogger.warn(inDebugMsg); + } else { + System.out.println(inDebugMsg); + } + } + + // -------------------------------------------------------------------------- + /** + * Wrapper for commons-logging info(Object msg) + * @param inDebugMsg + */ + public void info(String inDebugMsg, Exception inException) { + if (commonsLogger != null) { + commonsLogger.info(inDebugMsg, inException); + } else { + System.out.println(inDebugMsg); + inException.printStackTrace(System.out); + } + } + + // -------------------------------------------------------------------------- + /** + * Wrapper for commons-logging info(Object msg) + * @param inDebugMsg + */ + public void info(String inDebugMsg) { + if (commonsLogger != null) { + commonsLogger.info(inDebugMsg); + } else { + System.out.println(inDebugMsg); + } + } + +} diff --git a/jingle/extension/source/org/jivesoftware/smackx/jingle/media/MediaNegotiator.java b/jingle/extension/source/org/jivesoftware/smackx/jingle/media/MediaNegotiator.java index e4bed6e98..7bcbb50b2 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/jingle/media/MediaNegotiator.java +++ b/jingle/extension/source/org/jivesoftware/smackx/jingle/media/MediaNegotiator.java @@ -19,9 +19,18 @@ */ package org.jivesoftware.smackx.jingle.media; +import java.util.ArrayList; +import java.util.List; + import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.packet.IQ; -import org.jivesoftware.smackx.jingle.*; +import org.jivesoftware.smackx.jingle.ContentNegotiator; +import org.jivesoftware.smackx.jingle.JingleActionEnum; +import org.jivesoftware.smackx.jingle.JingleException; +import org.jivesoftware.smackx.jingle.JingleNegotiator; +import org.jivesoftware.smackx.jingle.JingleNegotiatorState; +import org.jivesoftware.smackx.jingle.JingleSession; +import org.jivesoftware.smackx.jingle.SmackLogger; import org.jivesoftware.smackx.jingle.listeners.JingleListener; import org.jivesoftware.smackx.jingle.listeners.JingleMediaListener; import org.jivesoftware.smackx.packet.Jingle; @@ -29,9 +38,6 @@ import org.jivesoftware.smackx.packet.JingleContent; import org.jivesoftware.smackx.packet.JingleDescription; import org.jivesoftware.smackx.packet.JingleError; -import java.util.ArrayList; -import java.util.List; - /** * Manager for jmf descriptor negotiation.

This class is responsible * for managing the descriptor negotiation process, handling all the xmpp @@ -42,7 +48,9 @@ import java.util.List; */ public class MediaNegotiator extends JingleNegotiator { - //private JingleSession session; // The session this negotiation + private static final SmackLogger LOGGER = SmackLogger.getLogger(MediaNegotiator.class); + + //private JingleSession session; // The session this negotiation private final JingleMediaManager mediaManager; @@ -211,7 +219,7 @@ public class MediaNegotiator extends JingleNegotiator { setNegotiatorState(JingleNegotiatorState.SUCCEEDED); triggerMediaEstablished(getBestCommonAudioPt()); - System.err.println("Media choice:" + getBestCommonAudioPt().getName()); + LOGGER.error("Media choice:" + getBestCommonAudioPt().getName()); response = session.createAck(jingle); } diff --git a/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/JMFInit.java b/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/JMFInit.java index bdc3545fa..5a7571af3 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/JMFInit.java +++ b/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/JMFInit.java @@ -1,18 +1,25 @@ package org.jivesoftware.smackx.jingle.mediaimpl; -import com.sun.media.util.Registry; -import com.sun.media.ExclusiveUse; - -import javax.media.format.AudioFormat; -import javax.media.Renderer; -import javax.media.PlugInManager; -import javax.media.Format; -import java.awt.*; +import java.awt.Frame; +import java.awt.TextArea; +import java.awt.Toolkit; import java.util.Vector; +import javax.media.Format; +import javax.media.PlugInManager; +import javax.media.Renderer; +import javax.media.format.AudioFormat; + +import org.jivesoftware.smackx.jingle.SmackLogger; + +import com.sun.media.ExclusiveUse; +import com.sun.media.util.Registry; + public class JMFInit extends Frame implements Runnable { - private String tempDir = "/tmp"; + private static final SmackLogger LOGGER = SmackLogger.getLogger(JMFInit.class); + + private String tempDir = "/tmp"; private boolean done = false; @@ -248,7 +255,7 @@ public class JMFInit extends Frame implements Runnable { } private void message(String mesg) { - System.out.println(mesg); + LOGGER.debug(mesg); } private void createGUI() { diff --git a/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioChannel.java b/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioChannel.java index 963e39ddb..74ca63ede 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioChannel.java +++ b/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioChannel.java @@ -19,9 +19,22 @@ */ package org.jivesoftware.smackx.jingle.mediaimpl.jmf; -import org.jivesoftware.smackx.jingle.media.JingleMediaSession; +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; -import javax.media.*; +import javax.media.Codec; +import javax.media.Controller; +import javax.media.ControllerClosedEvent; +import javax.media.ControllerEvent; +import javax.media.ControllerListener; +import javax.media.Format; +import javax.media.MediaLocator; +import javax.media.NoProcessorException; +import javax.media.Processor; +import javax.media.UnsupportedPlugInException; import javax.media.control.BufferControl; import javax.media.control.PacketSizeControl; import javax.media.control.TrackControl; @@ -34,11 +47,9 @@ import javax.media.rtp.InvalidSessionAddressException; import javax.media.rtp.RTPManager; import javax.media.rtp.SendStream; import javax.media.rtp.SessionAddress; -import java.io.IOException; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.List; + +import org.jivesoftware.smackx.jingle.SmackLogger; +import org.jivesoftware.smackx.jingle.media.JingleMediaSession; /** * An Easy to use Audio Channel implemented using JMF. @@ -60,7 +71,9 @@ import java.util.List; */ public class AudioChannel { - private MediaLocator locator; + private static final SmackLogger LOGGER = SmackLogger.getLogger(AudioChannel.class); + + private MediaLocator locator; private String localIpAddress; private String remoteIpAddress; private int localPort; @@ -239,8 +252,8 @@ public class AudioChannel { } if (chosen != null) { tracks[i].setFormat(chosen); - System.err.println("Track " + i + " is set to transmit as:"); - System.err.println(" " + chosen); + LOGGER.error("Track " + i + " is set to transmit as:"); + LOGGER.error(" " + chosen); if (tracks[i].getFormat() instanceof AudioFormat) { int packetRate = 20; @@ -375,7 +388,7 @@ public class AudioChannel { rtpMgrs[i].addTarget(destAddr); - System.err.println("Created RTP session at " + localPort + " to: " + remoteIpAddress + " " + port); + LOGGER.error("Created RTP session at " + localPort + " to: " + remoteIpAddress + " " + port); sendStream = rtpMgrs[i].createSendStream(dataOutput, i); @@ -404,11 +417,11 @@ public class AudioChannel { try { if (active) { sendStream.start(); - System.out.println("START"); + LOGGER.debug("START"); } else { sendStream.stop(); - System.out.println("STOP"); + LOGGER.debug("STOP"); } } catch (IOException e) { diff --git a/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioMediaSession.java b/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioMediaSession.java index 5238f51ec..33453b735 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioMediaSession.java +++ b/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioMediaSession.java @@ -20,15 +20,17 @@ package org.jivesoftware.smackx.jingle.mediaimpl.jmf; +import java.io.IOException; +import java.net.ServerSocket; + +import javax.media.MediaLocator; + import org.jivesoftware.smackx.jingle.JingleSession; +import org.jivesoftware.smackx.jingle.SmackLogger; import org.jivesoftware.smackx.jingle.media.JingleMediaSession; import org.jivesoftware.smackx.jingle.media.PayloadType; import org.jivesoftware.smackx.jingle.nat.TransportCandidate; -import javax.media.MediaLocator; -import java.io.IOException; -import java.net.ServerSocket; - /** * This Class implements a complete JingleMediaSession. * It sould be used to transmit and receive audio captured from the Mic. @@ -41,7 +43,9 @@ import java.net.ServerSocket; */ public class AudioMediaSession extends JingleMediaSession { - private AudioChannel audioChannel; + private static final SmackLogger LOGGER = SmackLogger.getLogger(AudioMediaSession.class); + + private AudioChannel audioChannel; /** * Creates a org.jivesoftware.jingleaudio.jmf.AudioMediaSession with defined payload type, remote and local candidates @@ -73,7 +77,7 @@ public class AudioMediaSession extends JingleMediaSession { localPort = getFreePort(); remotePort = this.getLocal().getSymmetric().getPort(); - System.out.println(this.getLocal().getConnection() + " " + ip + ": " + localPort + "->" + remotePort); + LOGGER.debug(this.getLocal().getConnection() + " " + ip + ": " + localPort + "->" + remotePort); } else { diff --git a/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioReceiver.java b/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioReceiver.java index b8b7c0618..e62455b7c 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioReceiver.java +++ b/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioReceiver.java @@ -20,12 +20,27 @@ package org.jivesoftware.smackx.jingle.mediaimpl.jmf; -import org.jivesoftware.smackx.jingle.media.JingleMediaSession; - -import javax.media.*; +import javax.media.ControllerErrorEvent; +import javax.media.ControllerEvent; +import javax.media.ControllerListener; +import javax.media.Player; +import javax.media.RealizeCompleteEvent; import javax.media.protocol.DataSource; -import javax.media.rtp.*; -import javax.media.rtp.event.*; +import javax.media.rtp.Participant; +import javax.media.rtp.RTPControl; +import javax.media.rtp.ReceiveStream; +import javax.media.rtp.ReceiveStreamListener; +import javax.media.rtp.SessionListener; +import javax.media.rtp.event.ByeEvent; +import javax.media.rtp.event.NewParticipantEvent; +import javax.media.rtp.event.NewReceiveStreamEvent; +import javax.media.rtp.event.ReceiveStreamEvent; +import javax.media.rtp.event.RemotePayloadChangeEvent; +import javax.media.rtp.event.SessionEvent; +import javax.media.rtp.event.StreamMappedEvent; + +import org.jivesoftware.smackx.jingle.SmackLogger; +import org.jivesoftware.smackx.jingle.media.JingleMediaSession; /** * This class implements receive methods and listeners to be used in AudioChannel @@ -35,7 +50,9 @@ import javax.media.rtp.event.*; public class AudioReceiver implements ReceiveStreamListener, SessionListener, ControllerListener { - boolean dataReceived = false; + private static final SmackLogger LOGGER = SmackLogger.getLogger(AudioReceiver.class); + + boolean dataReceived = false; Object dataSync; JingleMediaSession jingleMediaSession; @@ -51,7 +68,7 @@ public class AudioReceiver implements ReceiveStreamListener, SessionListener, public synchronized void update(SessionEvent evt) { if (evt instanceof NewParticipantEvent) { Participant p = ((NewParticipantEvent) evt).getParticipant(); - System.err.println(" - A new participant had just joined: " + p.getCNAME()); + LOGGER.error(" - A new participant had just joined: " + p.getCNAME()); } } @@ -64,8 +81,8 @@ public class AudioReceiver implements ReceiveStreamListener, SessionListener, ReceiveStream stream = evt.getReceiveStream(); // could be null. if (evt instanceof RemotePayloadChangeEvent) { - System.err.println(" - Received an RTP PayloadChangeEvent."); - System.err.println("Sorry, cannot handle payload change."); + LOGGER.error(" - Received an RTP PayloadChangeEvent."); + LOGGER.error("Sorry, cannot handle payload change."); } else if (evt instanceof NewReceiveStreamEvent) { @@ -77,15 +94,15 @@ public class AudioReceiver implements ReceiveStreamListener, SessionListener, // Find out the formats. RTPControl ctl = (RTPControl) ds.getControl("javax.jmf.rtp.RTPControl"); if (ctl != null) { - System.err.println(" - Recevied new RTP stream: " + ctl.getFormat()); + LOGGER.error(" - Recevied new RTP stream: " + ctl.getFormat()); } else - System.err.println(" - Recevied new RTP stream"); + LOGGER.error(" - Recevied new RTP stream"); if (participant == null) - System.err.println(" The sender of this stream had yet to be identified."); + LOGGER.error(" The sender of this stream had yet to be identified."); else { - System.err.println(" The stream comes from: " + participant.getCNAME()); + LOGGER.error(" The stream comes from: " + participant.getCNAME()); } // create a player by passing datasource to the Media Manager @@ -105,7 +122,7 @@ public class AudioReceiver implements ReceiveStreamListener, SessionListener, } catch (Exception e) { - System.err.println("NewReceiveStreamEvent exception " + e.getMessage()); + LOGGER.error("NewReceiveStreamEvent exception " + e.getMessage()); return; } @@ -116,15 +133,15 @@ public class AudioReceiver implements ReceiveStreamListener, SessionListener, DataSource ds = stream.getDataSource(); // Find out the formats. RTPControl ctl = (RTPControl) ds.getControl("javax.jmf.rtp.RTPControl"); - System.err.println(" - The previously unidentified stream "); + LOGGER.error(" - The previously unidentified stream "); if (ctl != null) - System.err.println(" " + ctl.getFormat()); - System.err.println(" had now been identified as sent by: " + participant.getCNAME()); + LOGGER.error(" " + ctl.getFormat()); + LOGGER.error(" had now been identified as sent by: " + participant.getCNAME()); } } else if (evt instanceof ByeEvent) { - System.err.println(" - Got \"bye\" from: " + participant.getCNAME()); + LOGGER.error(" - Got \"bye\" from: " + participant.getCNAME()); } @@ -147,7 +164,7 @@ public class AudioReceiver implements ReceiveStreamListener, SessionListener, if (ce instanceof ControllerErrorEvent) { p.removeControllerListener(this); - System.err.println("Receiver internal error: " + ce); + LOGGER.error("Receiver internal error: " + ce); } } diff --git a/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/jmf/JmfMediaManager.java b/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/jmf/JmfMediaManager.java index 762c17ea5..38f1ce60b 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/jmf/JmfMediaManager.java +++ b/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/jmf/JmfMediaManager.java @@ -20,7 +20,13 @@ package org.jivesoftware.smackx.jingle.mediaimpl.jmf; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + import org.jivesoftware.smackx.jingle.JingleSession; +import org.jivesoftware.smackx.jingle.SmackLogger; import org.jivesoftware.smackx.jingle.media.JingleMediaManager; import org.jivesoftware.smackx.jingle.media.JingleMediaSession; import org.jivesoftware.smackx.jingle.media.PayloadType; @@ -28,11 +34,6 @@ import org.jivesoftware.smackx.jingle.mediaimpl.JMFInit; import org.jivesoftware.smackx.jingle.nat.JingleTransportManager; import org.jivesoftware.smackx.jingle.nat.TransportCandidate; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - /** * Implements a jingleMediaManager using JMF based API. * It supports GSM and G723 codecs. @@ -42,7 +43,9 @@ import java.util.List; */ public class JmfMediaManager extends JingleMediaManager { - public static final String MEDIA_NAME = "JMF"; + private static final SmackLogger LOGGER = SmackLogger.getLogger(JmfMediaManager.class); + + public static final String MEDIA_NAME = "JMF"; private List payloads = new ArrayList(); @@ -142,7 +145,7 @@ public class JmfMediaManager extends JingleMediaManager { jmfProperties.createNewFile(); } catch (IOException ex) { - System.out.println("Failed to create jmf.properties"); + LOGGER.debug("Failed to create jmf.properties"); ex.printStackTrace(); } } diff --git a/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/jspeex/AudioMediaSession.java b/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/jspeex/AudioMediaSession.java index 28e43ca9c..af4fe7092 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/jspeex/AudioMediaSession.java +++ b/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/jspeex/AudioMediaSession.java @@ -20,25 +20,28 @@ package org.jivesoftware.smackx.jingle.mediaimpl.jspeex; -import mil.jfcom.cie.media.session.MediaSession; -import mil.jfcom.cie.media.session.MediaSessionListener; -import mil.jfcom.cie.media.session.StreamPlayer; -import mil.jfcom.cie.media.srtp.packetizer.SpeexFormat; -import org.jivesoftware.smackx.jingle.JingleSession; -import org.jivesoftware.smackx.jingle.media.JingleMediaSession; -import org.jivesoftware.smackx.jingle.media.PayloadType; -import org.jivesoftware.smackx.jingle.nat.TransportCandidate; - -import javax.media.NoProcessorException; -import javax.media.format.UnsupportedFormatException; -import javax.media.rtp.rtcp.SenderReport; -import javax.media.rtp.rtcp.SourceDescription; import java.io.IOException; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.ServerSocket; import java.security.GeneralSecurityException; +import javax.media.NoProcessorException; +import javax.media.format.UnsupportedFormatException; +import javax.media.rtp.rtcp.SenderReport; +import javax.media.rtp.rtcp.SourceDescription; + +import mil.jfcom.cie.media.session.MediaSession; +import mil.jfcom.cie.media.session.MediaSessionListener; +import mil.jfcom.cie.media.session.StreamPlayer; +import mil.jfcom.cie.media.srtp.packetizer.SpeexFormat; + +import org.jivesoftware.smackx.jingle.JingleSession; +import org.jivesoftware.smackx.jingle.SmackLogger; +import org.jivesoftware.smackx.jingle.media.JingleMediaSession; +import org.jivesoftware.smackx.jingle.media.PayloadType; +import org.jivesoftware.smackx.jingle.nat.TransportCandidate; + /** * This Class implements a complete JingleMediaSession. * It sould be used to transmit and receive audio captured from the Mic. @@ -52,7 +55,9 @@ import java.security.GeneralSecurityException; public class AudioMediaSession extends JingleMediaSession implements MediaSessionListener { - private MediaSession mediaSession; + private static final SmackLogger LOGGER = SmackLogger.getLogger(AudioMediaSession.class); + + private MediaSession mediaSession; /** * Create a Session using Speex Codec @@ -123,7 +128,7 @@ public class AudioMediaSession extends JingleMediaSession implements MediaSessio localPort = getFreePort(); remotePort = this.getLocal().getSymmetric().getPort(); - System.out.println(this.getLocal().getConnection() + " " + ip + ": " + localPort + "->" + remotePort); + LOGGER.debug(this.getLocal().getConnection() + " " + ip + ": " + localPort + "->" + remotePort); } else { @@ -155,7 +160,7 @@ public class AudioMediaSession extends JingleMediaSession implements MediaSessio */ public void startTrasmit() { try { - System.out.println("start"); + LOGGER.debug("start"); mediaSession.start(true); this.mediaReceived(""); } diff --git a/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/jspeex/SpeexMediaManager.java b/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/jspeex/SpeexMediaManager.java index 527cbf750..49b3a3abf 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/jspeex/SpeexMediaManager.java +++ b/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/jspeex/SpeexMediaManager.java @@ -19,7 +19,13 @@ */ package org.jivesoftware.smackx.jingle.mediaimpl.jspeex; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + import org.jivesoftware.smackx.jingle.JingleSession; +import org.jivesoftware.smackx.jingle.SmackLogger; import org.jivesoftware.smackx.jingle.media.JingleMediaManager; import org.jivesoftware.smackx.jingle.media.JingleMediaSession; import org.jivesoftware.smackx.jingle.media.PayloadType; @@ -27,11 +33,6 @@ import org.jivesoftware.smackx.jingle.mediaimpl.JMFInit; import org.jivesoftware.smackx.jingle.nat.JingleTransportManager; import org.jivesoftware.smackx.jingle.nat.TransportCandidate; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - /** * Implements a jingleMediaManager using JMF based API and JSpeex. * It supports Speex codec. @@ -41,7 +42,9 @@ import java.util.List; */ public class SpeexMediaManager extends JingleMediaManager { - public static final String MEDIA_NAME = "Speex"; + private static final SmackLogger LOGGER = SmackLogger.getLogger(SpeexMediaManager.class); + + public static final String MEDIA_NAME = "Speex"; private List payloads = new ArrayList(); @@ -106,7 +109,7 @@ public class SpeexMediaManager extends JingleMediaManager { jmfProperties.createNewFile(); } catch (IOException ex) { - System.out.println("Failed to create jmf.properties"); + LOGGER.debug("Failed to create jmf.properties"); ex.printStackTrace(); } } diff --git a/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/sshare/ScreenShareSession.java b/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/sshare/ScreenShareSession.java index 7fadac11c..3b253c842 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/sshare/ScreenShareSession.java +++ b/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/sshare/ScreenShareSession.java @@ -19,17 +19,7 @@ */ package org.jivesoftware.smackx.jingle.mediaimpl.sshare; -import org.jivesoftware.smackx.jingle.JingleSession; -import org.jivesoftware.smackx.jingle.media.JingleMediaSession; -import org.jivesoftware.smackx.jingle.media.PayloadType; -import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageDecoder; -import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageEncoder; -import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageReceiver; -import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageTransmitter; -import org.jivesoftware.smackx.jingle.nat.TransportCandidate; - -import javax.swing.*; -import java.awt.*; +import java.awt.Rectangle; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.IOException; @@ -38,6 +28,19 @@ import java.net.InetAddress; import java.net.ServerSocket; import java.net.UnknownHostException; +import javax.swing.JFrame; +import javax.swing.JPanel; + +import org.jivesoftware.smackx.jingle.JingleSession; +import org.jivesoftware.smackx.jingle.SmackLogger; +import org.jivesoftware.smackx.jingle.media.JingleMediaSession; +import org.jivesoftware.smackx.jingle.media.PayloadType; +import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageDecoder; +import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageEncoder; +import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageReceiver; +import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageTransmitter; +import org.jivesoftware.smackx.jingle.nat.TransportCandidate; + /** * This Class implements a complete JingleMediaSession. * It sould be used to transmit and receive captured images from the Display. @@ -49,7 +52,9 @@ import java.net.UnknownHostException; */ public class ScreenShareSession extends JingleMediaSession { - private ImageTransmitter transmitter = null; + private static final SmackLogger LOGGER = SmackLogger.getLogger(ScreenShareSession.class); + + private ImageTransmitter transmitter = null; private ImageReceiver receiver = null; private int width = 600; private int height = 600; @@ -102,7 +107,7 @@ public class ScreenShareSession extends JingleMediaSession { try { receiver = new ImageReceiver(InetAddress.getByName("0.0.0.0"), getRemote().getPort(), getLocal().getPort(), width, height); - System.out.println("Receiving on:" + receiver.getLocalPort()); + LOGGER.debug("Receiving on:" + receiver.getLocalPort()); } catch (UnknownHostException e) { e.printStackTrace(); } diff --git a/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageTransmitter.java b/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageTransmitter.java index b7884a58e..a4cf8374f 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageTransmitter.java +++ b/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageTransmitter.java @@ -1,6 +1,8 @@ package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api; -import java.awt.*; +import java.awt.AWTException; +import java.awt.Rectangle; +import java.awt.Robot; import java.awt.image.BufferedImage; import java.awt.image.PixelGrabber; import java.io.ByteArrayOutputStream; @@ -10,6 +12,8 @@ import java.net.DatagramSocket; import java.net.InetAddress; import java.util.Arrays; +import org.jivesoftware.smackx.jingle.SmackLogger; + /** * UDP Image Receiver. * It uses PNG Tiles into UDP packets. @@ -18,7 +22,9 @@ import java.util.Arrays; */ public class ImageTransmitter implements Runnable { - private Robot robot; + private static final SmackLogger LOGGER = SmackLogger.getLogger(ImageTransmitter.class); + + private Robot robot; private InetAddress localHost; private InetAddress remoteHost; private int localPort; @@ -80,7 +86,7 @@ public class ImageTransmitter implements Runnable { if (++keyframe > KEYFRAME) { keyframe = 0; } - System.out.println("KEYFRAME:" + keyframe); + LOGGER.debug("KEYFRAME:" + keyframe); for (int i = 0; i < maxI; i++) { for (int j = 0; j < maxJ; j++) { @@ -110,7 +116,7 @@ public class ImageTransmitter implements Runnable { byte[] bytesOut = baos.toByteArray(); if (bytesOut.length > 1000) - System.err.println(bytesOut.length); + LOGGER.error("Bytes out > 1000. Equals " + bytesOut.length); p.setData(bytesOut); p.setAddress(remoteHost); @@ -142,7 +148,7 @@ public class ImageTransmitter implements Runnable { } trace = (System.currentTimeMillis() - trace); - System.out.println("Loop Time:" + trace); + LOGGER.debug("Loop Time:" + trace); if (trace < 500) { try { diff --git a/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/OctTreeQuantizer.java b/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/OctTreeQuantizer.java index 9d33eb187..1b8fa9d3c 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/OctTreeQuantizer.java +++ b/jingle/extension/source/org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/OctTreeQuantizer.java @@ -19,6 +19,8 @@ package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api; import java.io.PrintStream; import java.util.Vector; +import org.jivesoftware.smackx.jingle.SmackLogger; + /** * An image Quantizer based on the Octree algorithm. This is a very basic implementation * at present and could be much improved by picking the nodes to reduce more carefully @@ -26,6 +28,8 @@ import java.util.Vector; */ public class OctTreeQuantizer implements Quantizer { + private static final SmackLogger LOGGER = SmackLogger.getLogger(OctTreeQuantizer.class); + /** * The greatest depth the tree is allowed to reach */ @@ -50,12 +54,13 @@ public class OctTreeQuantizer implements Quantizer { * A debugging method which prints the tree out. */ public void list(PrintStream s, int level) { + String indentStr = ""; for (int i = 0; i < level; i++) - System.out.print(' '); + indentStr += " "; if (count == 0) - System.out.println(index+": count="+count); + LOGGER.debug(indentStr + index + ": count=" + count); else - System.out.println(index+": count="+count+" red="+(totalRed/count)+" green="+(totalGreen/count)+" blue="+(totalBlue/count)); + LOGGER.debug(indentStr + index + ": count=" + count + " red=" + (totalRed/count) + " green=" + (totalGreen / count) + " blue=" + (totalBlue / count)); for (int i = 0; i < 8; i++) if (leaf[i] != null) leaf[i].list(s, level+2); @@ -133,7 +138,7 @@ public class OctTreeQuantizer implements Quantizer { else node = child; } - System.out.println("getIndexForColor failed"); + LOGGER.debug("getIndexForColor failed"); return 0; } @@ -144,7 +149,7 @@ public class OctTreeQuantizer implements Quantizer { OctTreeNode node = root; -// System.out.println("insertColor="+Integer.toHexString(rgb)); +// LOGGER.debug("insertColor="+Integer.toHexString(rgb)); for (int level = 0; level <= MAX_LEVEL; level++) { OctTreeNode child; int bit = 0x80 >> level; @@ -190,7 +195,7 @@ public class OctTreeQuantizer implements Quantizer { } else node = child; } - System.out.println("insertColor failed"); + LOGGER.debug("insertColor failed"); } private void reduceTree(int numColors) { @@ -204,7 +209,7 @@ public class OctTreeQuantizer implements Quantizer { OctTreeNode child = node.leaf[i]; if (child != null) { if (!child.isLeaf) - System.out.println("not a leaf!"); + LOGGER.debug("not a leaf!"); node.count += child.count; node.totalRed += child.totalRed; node.totalGreen += child.totalGreen; @@ -225,7 +230,7 @@ public class OctTreeQuantizer implements Quantizer { } } - System.out.println("Unable to reduce the OctTree"); + LOGGER.debug("Unable to reduce the OctTree"); } /** diff --git a/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/HttpServer.java b/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/HttpServer.java index 24b1f785c..4d57a7c9d 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/HttpServer.java +++ b/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/HttpServer.java @@ -52,28 +52,36 @@ package org.jivesoftware.smackx.jingle.nat; -import java.io.*; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.StringTokenizer; +import org.jivesoftware.smackx.jingle.SmackLogger; + /** * A very Simple HTTP Server */ public class HttpServer { - public HttpServer(int port) { + private static final SmackLogger LOGGER = SmackLogger.getLogger(HttpServer.class); + + public HttpServer(int port) { ServerSocket server_socket; try { server_socket = new ServerSocket(port); - System.out.println("httpServer running on port " + + LOGGER.debug("httpServer running on port " + server_socket.getLocalPort()); while (true) { Socket socket = server_socket.accept(); - System.out.println("New connection accepted " + + LOGGER.debug("New connection accepted " + socket.getInetAddress() + ":" + socket.getPort()); @@ -86,13 +94,13 @@ public class HttpServer { thread.start(); } catch (Exception e) { - System.out.println(e); + LOGGER.debug("", e); } } } catch (IOException e) { - System.out.println(e); + LOGGER.debug("", e); } } @@ -129,7 +137,7 @@ public class HttpServer { while (true) { String headerLine = br.readLine(); - System.out.println(headerLine); + LOGGER.debug(headerLine); if (headerLine.equals(CRLF) || headerLine.equals("")) break; StringTokenizer s = new StringTokenizer(headerLine); diff --git a/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/ICECandidate.java b/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/ICECandidate.java index d916f58b4..432fe00d5 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/ICECandidate.java +++ b/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/ICECandidate.java @@ -55,6 +55,8 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.util.List; +import org.jivesoftware.smackx.jingle.SmackLogger; + /** * ICE Transport candidate. *

@@ -65,7 +67,9 @@ import java.util.List; */ public class ICECandidate extends TransportCandidate implements Comparable { - private String id; // An identification + private static final SmackLogger LOGGER = SmackLogger.getLogger(ICECandidate.class); + + private String id; // An identification private String username; @@ -273,7 +277,7 @@ public class ICECandidate extends TransportCandidate implements Comparable { public void testFinished(TestResult testResult, TransportCandidate candidate) { if (testResult.isReachable() && checkingCandidate.equals(candidate)) { result.setResult(true); - System.out.println("RESULT>>>OK:" + candidate.getIp() + ":" + candidate.getPort()); + LOGGER.debug("Candidate reachable: " + candidate.getIp() + ":" + candidate.getPort() + " from " + getIp() +":" + getPort()); } } }; @@ -299,7 +303,7 @@ public class ICECandidate extends TransportCandidate implements Comparable { for (int i = 0; i < 10 && !result.isReachable(); i++) try { - System.err.println("ICE Candidate retry #" + i); + LOGGER.error("ICE Candidate retry #" + i); Thread.sleep(400); } catch (InterruptedException e) { diff --git a/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/ICEResolver.java b/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/ICEResolver.java index a08fcbca6..2624e7173 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/ICEResolver.java +++ b/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/ICEResolver.java @@ -20,20 +20,24 @@ package org.jivesoftware.smackx.jingle.nat; -import de.javawi.jstun.test.demo.ice.Candidate; -import de.javawi.jstun.test.demo.ice.ICENegociator; -import de.javawi.jstun.util.UtilityException; -import org.jivesoftware.smack.XMPPConnection; -import org.jivesoftware.smack.XMPPException; -import org.jivesoftware.smackx.jingle.JingleSession; - import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.net.UnknownHostException; import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; import java.util.Random; +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.XMPPException; +import org.jivesoftware.smackx.jingle.JingleSession; +import org.jivesoftware.smackx.jingle.SmackLogger; + +import de.javawi.jstun.test.demo.ice.Candidate; +import de.javawi.jstun.test.demo.ice.ICENegociator; +import de.javawi.jstun.util.UtilityException; + /** * ICE Resolver for Jingle transport method that results in sending data between two entities using the Interactive Connectivity Establishment (ICE) methodology. (XEP-0176) * The goal of this resolver is to make possible to establish and manage out-of-band connections between two XMPP entities, even if they are behind Network Address Translators (NATs) or firewalls. @@ -43,12 +47,15 @@ import java.util.Random; */ public class ICEResolver extends TransportResolver { - XMPPConnection connection; + private static final SmackLogger LOGGER = SmackLogger.getLogger(ICEResolver.class); + + XMPPConnection connection; Random random = new Random(); long sid; - String server = "stun.xten.net"; - int port = 3478; - ICENegociator iceNegociator = null; + String server; + int port; + static Map negociatorsMap = new HashMap(); + //ICENegociator iceNegociator = null; public ICEResolver(XMPPConnection connection, String server, int port) { super(); @@ -60,13 +67,21 @@ public class ICEResolver extends TransportResolver { public void initialize() throws XMPPException { if (!isResolving() && !isResolved()) { - System.out.println("Initialized"); + LOGGER.debug("Initialized"); - iceNegociator = new ICENegociator((short) 1, server, port); - // gather candidates - iceNegociator.gatherCandidateAddresses(); - // priorize candidates - iceNegociator.prioritizeCandidates(); + // Negotiation with a STUN server for a set of interfaces is quite slow, but the results + // never change over then instance of a JVM. To increase connection performance considerably + // we now cache established/initialized negotiators for each STUN server, so that subsequent uses + // of the STUN server are much, much faster. + if (negociatorsMap.get(server) == null) { + ICENegociator iceNegociator = new ICENegociator(server, port, (short) 1); + negociatorsMap.put(server, iceNegociator); + + // gather candidates + iceNegociator.gatherCandidateAddresses(); + // priorize candidates + iceNegociator.prioritizeCandidates(); + } } this.setInitialized(); @@ -91,6 +106,8 @@ public class ICEResolver extends TransportResolver { this.clear(); + // Create a transport candidate for each ICE negotiator candidate we have. + ICENegociator iceNegociator = negociatorsMap.get(server); for (Candidate candidate : iceNegociator.getSortedCandidates()) try { Candidate.CandidateType type = candidate.getCandidateType(); @@ -104,7 +121,26 @@ public class ICEResolver extends TransportResolver { else iceType = ICECandidate.Type.host; - TransportCandidate transportCandidate = new ICECandidate(candidate.getAddress().getInetAddress().getHostAddress(), 1, candidate.getNetwork(), String.valueOf(Math.abs(random.nextLong())), candidate.getPort(), "1", candidate.getPriority(), iceType); + // JBW/GW - 17JUL08: Figure out the zero-based NIC number for this candidate. + short nicNum = 0; + try { + Enumeration nics = NetworkInterface.getNetworkInterfaces(); + short i = 0; + NetworkInterface nic = NetworkInterface.getByInetAddress(candidate.getAddress().getInetAddress()); + while(nics.hasMoreElements()) { + NetworkInterface checkNIC = nics.nextElement(); + if (checkNIC.equals(nic)) { + nicNum = i; + break; + } + i++; + } + } catch (SocketException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + TransportCandidate transportCandidate = new ICECandidate(candidate.getAddress().getInetAddress().getHostAddress(), 1, nicNum, String.valueOf(Math.abs(random.nextLong())), candidate.getPort(), "1", candidate.getPriority(), iceType); transportCandidate.setLocalIp(candidate.getBase().getAddress().getInetAddress().getHostAddress()); transportCandidate.setPort(getFreePort()); try { @@ -115,7 +151,7 @@ public class ICEResolver extends TransportResolver { } this.addCandidate(transportCandidate); - System.out.println("C: " + candidate.getAddress().getInetAddress() + "|" + candidate.getBase().getAddress().getInetAddress() + " p:" + candidate.getPriority()); + LOGGER.debug("Candidate addr: " + candidate.getAddress().getInetAddress() + "|" + candidate.getBase().getAddress().getInetAddress() + " Priority:" + candidate.getPriority()); } catch (UtilityException e) { @@ -128,16 +164,19 @@ public class ICEResolver extends TransportResolver { // Get a Relay Candidate from XMPP Server if (RTPBridge.serviceAvailable(connection)) { - try { +// try { String localIp; int network; - - if (iceNegociator.getPublicCandidate() != null) { - localIp = iceNegociator.getPublicCandidate().getBase().getAddress().getInetAddress().getHostAddress(); - network = iceNegociator.getPublicCandidate().getNetwork(); - } - else { + + + // JBW/GW - 17JUL08: ICENegotiator.getPublicCandidate() always returned null in JSTUN 1.7.0, and now the API doesn't exist in JSTUN 1.7.1 +// if (iceNegociator.getPublicCandidate() != null) { +// localIp = iceNegociator.getPublicCandidate().getBase().getAddress().getInetAddress().getHostAddress(); +// network = iceNegociator.getPublicCandidate().getNetwork(); +// } +// else { + { localIp = BridgedResolver.getLocalHost(); network = 0; } @@ -168,17 +207,19 @@ public class ICEResolver extends TransportResolver { addCandidate(localCandidate); - } - catch (UtilityException e) { - e.printStackTrace(); - } - catch (UnknownHostException e) { - e.printStackTrace(); - } +// } +// catch (UtilityException e) { +// e.printStackTrace(); +// } +// catch (UnknownHostException e) { +// e.printStackTrace(); +// } // Get Public Candidate From XMPP Server - if (iceNegociator.getPublicCandidate() == null) { + // JBW/GW - 17JUL08 - ICENegotiator.getPublicCandidate() always returned null in JSTUN 1.7.0, and now it doesn't exist in JSTUN 1.7.1 + // if (iceNegociator.getPublicCandidate() == null) { + if (true) { String publicIp = RTPBridge.getPublicIP(connection); diff --git a/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/RTPBridge.java b/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/RTPBridge.java index 144a54551..8edd3abf7 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/RTPBridge.java +++ b/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/RTPBridge.java @@ -20,6 +20,12 @@ package org.jivesoftware.smackx.jingle.nat; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Enumeration; +import java.util.Iterator; + import org.jivesoftware.smack.PacketCollector; import org.jivesoftware.smack.SmackConfiguration; import org.jivesoftware.smack.XMPPConnection; @@ -29,15 +35,10 @@ import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.provider.IQProvider; import org.jivesoftware.smack.provider.ProviderManager; import org.jivesoftware.smackx.ServiceDiscoveryManager; -import org.jivesoftware.smackx.packet.DiscoverItems; +import org.jivesoftware.smackx.jingle.SmackLogger; +import org.jivesoftware.smackx.packet.DiscoverInfo; import org.xmlpull.v1.XmlPullParser; -import java.net.InetAddress; -import java.net.NetworkInterface; -import java.net.SocketException; -import java.util.Enumeration; -import java.util.Iterator; - /** * RTPBridge IQ Packet used to request and retrieve a RTPBridge Candidates that can be used for a Jingle Media Transmission between two parties that are behind NAT. * This Jingle Bridge has all the needed information to establish a full UDP Channel (Send and Receive) between two parties. @@ -51,7 +52,9 @@ import java.util.Iterator; */ public class RTPBridge extends IQ { - private String sid; + private static final SmackLogger LOGGER = SmackLogger.getLogger(RTPBridge.class); + + private String sid; private String pass; private String ip; private String name; @@ -424,20 +427,29 @@ public class RTPBridge extends IQ { return false; } - System.out.println("Service listing"); + LOGGER.debug("Service listing"); ServiceDiscoveryManager disco = ServiceDiscoveryManager .getInstanceFor(xmppConnection); try { - DiscoverItems items = disco.discoverItems(xmppConnection.getServiceName()); - Iterator iter = items.getItems(); +// DiscoverItems items = disco.discoverItems(xmppConnection.getServiceName()); +// Iterator iter = items.getItems(); +// while (iter.hasNext()) { +// DiscoverItems.Item item = (DiscoverItems.Item) iter.next(); +// if (item.getEntityID().startsWith("rtpbridge.")) { +// return true; +// } +// } + + DiscoverInfo discoInfo = disco.discoverInfo(xmppConnection.getServiceName()); + Iterator iter = discoInfo.getIdentities(); while (iter.hasNext()) { - DiscoverItems.Item item = (DiscoverItems.Item) iter.next(); - if (item.getEntityID().startsWith("rtpbridge.")) { - return true; - } + DiscoverInfo.Identity identity = (DiscoverInfo.Identity) iter.next(); + if ((identity.getName() != null) && (identity.getName().startsWith("rtpbridge"))) { + return true; + } } - } + } catch (XMPPException e) { e.printStackTrace(); } @@ -467,7 +479,7 @@ public class RTPBridge extends IQ { rtpPacket.setHostA(localCandidate.getIp()); rtpPacket.setHostB(proxyCandidate.getIp()); - // System.out.println("Relayed to: " + candidate.getIp() + ":" + candidate.getPort()); + // LOGGER.debug("Relayed to: " + candidate.getIp() + ":" + candidate.getPort()); PacketCollector collector = xmppConnection .createPacketCollector(new PacketIDFilter(rtpPacket.getPacketID())); @@ -499,7 +511,7 @@ public class RTPBridge extends IQ { rtpPacket.setTo(RTPBridge.NAME + "." + xmppConnection.getServiceName()); rtpPacket.setType(Type.SET); - // System.out.println("Relayed to: " + candidate.getIp() + ":" + candidate.getPort()); + // LOGGER.debug("Relayed to: " + candidate.getIp() + ":" + candidate.getPort()); PacketCollector collector = xmppConnection .createPacketCollector(new PacketIDFilter(rtpPacket.getPacketID())); diff --git a/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/STUN.java b/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/STUN.java index caab19c1a..e0d24a70c 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/STUN.java +++ b/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/STUN.java @@ -19,6 +19,10 @@ */ package org.jivesoftware.smackx.jingle.nat; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + import org.jivesoftware.smack.PacketCollector; import org.jivesoftware.smack.SmackConfiguration; import org.jivesoftware.smack.XMPPConnection; @@ -28,14 +32,11 @@ import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.provider.IQProvider; import org.jivesoftware.smack.provider.ProviderManager; import org.jivesoftware.smackx.ServiceDiscoveryManager; +import org.jivesoftware.smackx.jingle.SmackLogger; import org.jivesoftware.smackx.packet.DiscoverInfo; import org.jivesoftware.smackx.packet.DiscoverItems; import org.xmlpull.v1.XmlPullParser; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - /** * STUN IQ Packet used to request and retrieve a STUN server and port to make p2p connections easier. STUN is usually used by Jingle Media Transmission between two parties that are behind NAT. *

@@ -47,7 +48,9 @@ import java.util.List; */ public class STUN extends IQ { - private List servers = new ArrayList(); + private static final SmackLogger LOGGER = SmackLogger.getLogger(STUN.class); + + private List servers = new ArrayList(); private String publicIp = null; @@ -220,7 +223,7 @@ public class STUN extends IQ { return false; } - System.out.println("Service listing"); + LOGGER.debug("Service listing"); ServiceDiscoveryManager disco = ServiceDiscoveryManager .getInstanceFor(xmppConnection); @@ -240,7 +243,7 @@ public class STUN extends IQ { return true; } - System.out.println(item.getName()+"-"+info.getType()); + LOGGER.debug(item.getName()+"-"+info.getType()); } } diff --git a/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/STUNResolver.java b/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/STUNResolver.java index f4e4d90a2..a3d2c24b7 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/STUNResolver.java +++ b/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/STUNResolver.java @@ -19,15 +19,6 @@ */ package org.jivesoftware.smackx.jingle.nat; -import de.javawi.jstun.test.BindingLifetimeTest; -import de.javawi.jstun.test.DiscoveryInfo; -import de.javawi.jstun.test.DiscoveryTest; -import org.jivesoftware.smack.XMPPException; -import org.jivesoftware.smackx.jingle.JingleSession; -import org.xmlpull.mxp1.MXParser; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - import java.io.IOException; import java.net.InetAddress; import java.net.NetworkInterface; @@ -36,6 +27,17 @@ import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; +import org.jivesoftware.smack.XMPPException; +import org.jivesoftware.smackx.jingle.JingleSession; +import org.jivesoftware.smackx.jingle.SmackLogger; +import org.xmlpull.mxp1.MXParser; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import de.javawi.jstun.test.BindingLifetimeTest; +import de.javawi.jstun.test.DiscoveryInfo; +import de.javawi.jstun.test.DiscoveryTest; + /** * Transport resolver using the JSTUN library, to discover public IP and use it as a candidate. * @@ -45,7 +47,9 @@ import java.util.Enumeration; */ public class STUNResolver extends TransportResolver { - // The filename where the STUN servers are stored. + private static final SmackLogger LOGGER = SmackLogger.getLogger(STUNResolver.class); + + // The filename where the STUN servers are stored. public final static String STUNSERVERS_FILENAME = "META-INF/stun-config.xml"; // Fallback values when we don't have any STUN server to use... @@ -282,7 +286,7 @@ public class STUNResolver extends TransportResolver { resolvedPublicIP, getFreePort()); candidate.setLocalIp(resolvedLocalIP); - System.out.println("RESOLVING : " + resolvedPublicIP + ":" + candidate.getPort()); + LOGGER.debug("RESOLVING : " + resolvedPublicIP + ":" + candidate.getPort()); addCandidate(candidate); @@ -296,7 +300,7 @@ public class STUNResolver extends TransportResolver { * @throws XMPPException */ public void initialize() throws XMPPException { - System.out.println("Initialized"); + LOGGER.debug("Initialized"); if (!isResolving()&&!isResolved()) { // Get the best STUN server available if (currentServer.isNull()) { diff --git a/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/TcpUdpBridgeClient.java b/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/TcpUdpBridgeClient.java index 0ede283c2..85576f423 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/TcpUdpBridgeClient.java +++ b/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/TcpUdpBridgeClient.java @@ -59,6 +59,8 @@ import java.net.DatagramSocket; import java.net.InetAddress; import java.net.Socket; +import org.jivesoftware.smackx.jingle.SmackLogger; + /** * A Simple and Experimental Bridge. * It Creates a TCP Socket That Connects to another TCP Socket Listener and forwards every packets received to an UDP Listener. @@ -66,7 +68,9 @@ import java.net.Socket; */ public class TcpUdpBridgeClient { - private String remoteTcpHost = null; + private static final SmackLogger LOGGER = SmackLogger.getLogger(TcpUdpBridgeClient.class); + + private String remoteTcpHost = null; private String remoteUdpHost = null; private int remoteTcpPort = -1; private int remoteUdpPort = -1; @@ -85,7 +89,7 @@ public class TcpUdpBridgeClient { localTcpSocket = new Socket(remoteTcpHost, remoteTcpPort); localUdpSocket = new DatagramSocket(0); localUdpPort = localUdpSocket.getLocalPort(); - System.out.println("UDP: " + localUdpSocket.getLocalPort()); + LOGGER.debug("UDP: " + localUdpSocket.getLocalPort()); } catch (IOException e) { e.printStackTrace(); @@ -110,11 +114,11 @@ public class TcpUdpBridgeClient { localUdpSocket.receive(p); if (p.getLength() == 0) continue; - System.out.println("UDP Client Received and Sending to TCP Server:"+new String(p.getData(),0,p.getLength(),"UTF-8")); + LOGGER.debug("UDP Client Received and Sending to TCP Server:"+new String(p.getData(),0,p.getLength(),"UTF-8")); out.write(p.getData(), 0, p.getLength()); out.flush(); - System.out.println("Client Flush"); + LOGGER.debug("Client Flush"); } @@ -141,7 +145,7 @@ public class TcpUdpBridgeClient { int s = in.read(b); //if (s == -1) continue; - System.out.println("TCP Client:" +new String(b,0,s,"UTF-8")); + LOGGER.debug("TCP Client:" +new String(b,0,s,"UTF-8")); DatagramPacket udpPacket = new DatagramPacket(b, s); diff --git a/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/TcpUdpBridgeServer.java b/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/TcpUdpBridgeServer.java index 3f32b6fce..651208be8 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/TcpUdpBridgeServer.java +++ b/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/TcpUdpBridgeServer.java @@ -1,9 +1,15 @@ package org.jivesoftware.smackx.jingle.nat; -import java.net.*; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; + +import org.jivesoftware.smackx.jingle.SmackLogger; /** * A Simple and Experimental Bridge. @@ -12,7 +18,9 @@ import java.io.OutputStream; */ public class TcpUdpBridgeServer { - private String remoteTcpHost = null; + private static final SmackLogger LOGGER = SmackLogger.getLogger(TcpUdpBridgeServer.class); + + private String remoteTcpHost = null; private String remoteUdpHost = null; private int remoteTcpPort = -1; private int remoteUdpPort = -1; @@ -32,7 +40,7 @@ public class TcpUdpBridgeServer { serverTcpSocket = new ServerSocket(remoteTcpPort); localUdpSocket = new DatagramSocket(0); localUdpPort = localUdpSocket.getLocalPort(); - System.out.println("UDP: " + localUdpSocket.getLocalPort()); + LOGGER.debug("UDP: " + localUdpSocket.getLocalPort()); } catch (IOException e) { e.printStackTrace(); @@ -56,11 +64,11 @@ public class TcpUdpBridgeServer { localUdpSocket.receive(p); if (p.getLength() == 0) continue; - System.out.println("UDP Server Received and Sending to TCP Client:" + new String(p.getData(), 0, p.getLength(), "UTF-8")); + LOGGER.debug("UDP Server Received and Sending to TCP Client:" + new String(p.getData(), 0, p.getLength(), "UTF-8")); out.write(p.getData(), 0, p.getLength()); out.flush(); - System.out.println("Server Flush"); + LOGGER.debug("Server Flush"); } } @@ -87,7 +95,7 @@ public class TcpUdpBridgeServer { int s = in.read(b); //if (s == -1) continue; - System.out.println("TCP Server:" + new String(b, 0, s, "UTF-8")); + LOGGER.debug("TCP Server:" + new String(b, 0, s, "UTF-8")); DatagramPacket udpPacket = new DatagramPacket(b, s); diff --git a/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/TransportCandidate.java b/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/TransportCandidate.java index 352da084e..ffefed860 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/TransportCandidate.java +++ b/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/TransportCandidate.java @@ -52,16 +52,21 @@ package org.jivesoftware.smackx.jingle.nat; -import org.jivesoftware.smack.XMPPConnection; -import org.jivesoftware.smackx.jingle.JingleSession; - import java.io.IOException; import java.io.UnsupportedEncodingException; -import java.net.*; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketException; +import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smackx.jingle.JingleSession; +import org.jivesoftware.smackx.jingle.SmackLogger; + /** * Transport candidate. *

@@ -73,7 +78,9 @@ import java.util.List; */ public abstract class TransportCandidate { - private String name; + private static final SmackLogger LOGGER = SmackLogger.getLogger(TransportCandidate.class); + + private String name; private String ip; // IP address @@ -680,14 +687,14 @@ public abstract class TransportCandidate { public void run() { try { - System.out.println("Listening for ECHO: " + socket.getLocalAddress().getHostAddress() + ":" + socket.getLocalPort()); + LOGGER.debug("Listening for ECHO: " + socket.getLocalAddress().getHostAddress() + ":" + socket.getLocalPort()); while (true) { DatagramPacket packet = new DatagramPacket(new byte[150], 150); socket.receive(packet); - //System.out.println("ECHO Packet Received in: " + socket.getLocalAddress().getHostAddress() + ":" + socket.getLocalPort() + " From: " + packet.getAddress().getHostAddress() + ":" + packet.getPort()); + //LOGGER.debug("ECHO Packet Received in: " + socket.getLocalAddress().getHostAddress() + ":" + socket.getLocalPort() + " From: " + packet.getAddress().getHostAddress() + ":" + packet.getPort()); boolean accept = false; @@ -766,7 +773,7 @@ public abstract class TransportCandidate { resultListener.testFinished(testResult, candidate); } - public void testASync(final TransportCandidate candidate, final String password) { + public void testASync(final TransportCandidate transportCandidate, final String password) { Thread thread = new Thread(new Runnable() { @@ -776,19 +783,21 @@ public abstract class TransportCandidate { public boolean datagramReceived(DatagramPacket datagramPacket) { try { - System.out.println("Content Received: " + new String(datagramPacket.getData(), "UTF-8")); + LOGGER.debug("ECHO Received to: " + candidate.getIp() + ":" + candidate.getPort() + " data: " + new String(datagramPacket.getData(), "UTF-8")); String str[] = new String(datagramPacket.getData(), "UTF-8").split(";"); String pass = str[0]; String addr[] = str[1].split(":"); String ip = addr[0]; String pt = addr[1]; - if (pass.equals(password) && candidate.getIp().indexOf(ip) != -1 && candidate.getPort() == Integer.parseInt(pt)) { - System.out.println("Result OK:" + candidate.getIp() + ":" + candidate.getPort()); + if (pass.equals(password) + && transportCandidate.getIp().indexOf(ip) != -1 + && transportCandidate.getPort() == Integer.parseInt(pt)) { + LOGGER.debug("ECHO OK: " + candidate.getIp() + ":" + candidate.getPort() + " <-> " + transportCandidate.getIp() + ":" + transportCandidate.getPort()); TestResult testResult = new TestResult(); testResult.setResult(true); ended = true; - fireTestResult(testResult, candidate); + fireTestResult(testResult, transportCandidate); return true; } @@ -797,7 +806,7 @@ public abstract class TransportCandidate { e.printStackTrace(); } - System.out.println("Result Wrong Data:" + datagramPacket.getAddress().getHostAddress() + ":" + datagramPacket.getPort()); + LOGGER.debug("ECHO Wrong Data: " + datagramPacket.getAddress().getHostAddress() + ":" + datagramPacket.getPort()); return false; } }; @@ -815,12 +824,12 @@ public abstract class TransportCandidate { DatagramPacket packet = new DatagramPacket(content, content.length); try { - packet.setAddress(InetAddress.getByName(candidate.getIp())); + packet.setAddress(InetAddress.getByName(transportCandidate.getIp())); } catch (UnknownHostException e) { e.printStackTrace(); } - packet.setPort(candidate.getPort()); + packet.setPort(transportCandidate.getPort()); long delay = 200; diff --git a/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/TransportNegotiator.java b/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/TransportNegotiator.java index 03cf90b2c..25c207d43 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/TransportNegotiator.java +++ b/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/TransportNegotiator.java @@ -20,9 +20,20 @@ package org.jivesoftware.smackx.jingle.nat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.packet.IQ; -import org.jivesoftware.smackx.jingle.*; +import org.jivesoftware.smackx.jingle.ContentNegotiator; +import org.jivesoftware.smackx.jingle.JingleActionEnum; +import org.jivesoftware.smackx.jingle.JingleException; +import org.jivesoftware.smackx.jingle.JingleNegotiator; +import org.jivesoftware.smackx.jingle.JingleNegotiatorState; +import org.jivesoftware.smackx.jingle.JingleSession; +import org.jivesoftware.smackx.jingle.SmackLogger; import org.jivesoftware.smackx.jingle.listeners.JingleListener; import org.jivesoftware.smackx.jingle.listeners.JingleTransportListener; import org.jivesoftware.smackx.packet.Jingle; @@ -30,11 +41,6 @@ import org.jivesoftware.smackx.packet.JingleContent; import org.jivesoftware.smackx.packet.JingleTransport; import org.jivesoftware.smackx.packet.JingleTransport.JingleTransportCandidate; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - /** * Transport negotiator. *

@@ -46,7 +52,9 @@ import java.util.List; */ public abstract class TransportNegotiator extends JingleNegotiator { - // The time we give to the candidates check before we accept or decline the + private static final SmackLogger LOGGER = SmackLogger.getLogger(TransportNegotiator.class); + + // The time we give to the candidates check before we accept or decline the // transport (in milliseconds) public final static int CANDIDATES_ACCEPT_PERIOD = 4000; @@ -134,7 +142,7 @@ public abstract class TransportNegotiator extends JingleNegotiator { return; } } - //System.out.println("BEST: " + bestLocalCandidate.getIp()); + //LOGGER.debug("BEST: " + bestLocalCandidate.getIp()); throw new XMPPException("Local transport candidate has not be offered."); } @@ -434,7 +442,7 @@ public abstract class TransportNegotiator extends JingleNegotiator { // Add the candidate to the list if (remoteCandidate != null) { synchronized (validRemoteCandidates) { - System.out.println("ADDED Valid Cand: " + remoteCandidate.getIp() + ":" + remoteCandidate.getPort()); + LOGGER.debug("Added valid candidate: " + remoteCandidate.getIp() + ":" + remoteCandidate.getPort()); validRemoteCandidates.add(remoteCandidate); } } @@ -562,7 +570,7 @@ public abstract class TransportNegotiator extends JingleNegotiator { if (!(resolver.isResolving() || resolver.isResolved())) { // Resolve our IP and port - System.out.println("RESOLVER CALLED"); + LOGGER.debug("RESOLVER CALLED"); resolver.resolve(session); } } @@ -727,14 +735,14 @@ public abstract class TransportNegotiator extends JingleNegotiator { if (!accepted.isEmpty()) { for (TransportCandidate cand : accepted) { - System.out.println("Cand: " + cand.getIp()); + LOGGER.debug("Remote acccepted candidate addr: " + cand.getIp()); } TransportCandidate cand = (TransportCandidate) accepted.get(0); setAcceptedLocalCandidate(cand); if (isEstablished()) { - System.out.println("SET ACTIVE"); + LOGGER.debug(cand.getIp() + " is set active"); //setNegotiatorState(JingleNegotiatorState.SUCCEEDED); } } @@ -748,7 +756,7 @@ public abstract class TransportNegotiator extends JingleNegotiator { private IQ receiveSessionAcceptAction(Jingle jingle) { IQ response = null; - System.out.println("Transport stabilished"); + LOGGER.debug("Transport stabilished"); //triggerTransportEstablished(getAcceptedLocalCandidate(), getBestRemoteCandidate()); //setNegotiatorState(JingleNegotiatorState.SUCCEEDED); @@ -767,7 +775,7 @@ public abstract class TransportNegotiator extends JingleNegotiator { for (JingleListener li : listeners) { if (li instanceof JingleTransportListener) { JingleTransportListener mli = (JingleTransportListener) li; - System.out.println("triggerTransportEstablished " + local.getLocalIp() + ":" + local.getPort() + "|" + LOGGER.debug("triggerTransportEstablished " + local.getLocalIp() + ":" + local.getPort() + " <-> " + remote.getIp() + ":" + remote.getPort()); mli.transportEstablished(local, remote); } @@ -827,10 +835,10 @@ public abstract class TransportNegotiator extends JingleNegotiator { // Hopefully, we only have one validRemoteCandidate ArrayList cands = getValidRemoteCandidatesList(); if (!cands.isEmpty()) { - System.out.println("RAW CAND"); + LOGGER.debug("RAW CAND"); return (TransportCandidate) cands.get(0); } else { - System.out.println("No Remote Candidate"); + LOGGER.debug("No Remote Candidate"); return null; } } @@ -893,7 +901,7 @@ public abstract class TransportNegotiator extends JingleNegotiator { } if (result != null && result.getType().equals("relay")) - System.out.println("Relay Type"); + LOGGER.debug("Relay Type"); return result; } diff --git a/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/TransportResolver.java b/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/TransportResolver.java index 6937bcb6f..747675a9b 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/TransportResolver.java +++ b/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/TransportResolver.java @@ -52,9 +52,6 @@ package org.jivesoftware.smackx.jingle.nat; -import org.jivesoftware.smack.XMPPException; -import org.jivesoftware.smackx.jingle.JingleSession; - import java.io.IOException; import java.net.ServerSocket; import java.util.ArrayList; @@ -62,6 +59,10 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; +import org.jivesoftware.smack.XMPPException; +import org.jivesoftware.smackx.jingle.JingleSession; +import org.jivesoftware.smackx.jingle.SmackLogger; + /** * A TransportResolver is used for obtaining a list of valid transport * candidates. A transport candidate is composed by an IP address and a port number. @@ -72,7 +73,9 @@ import java.util.List; */ public abstract class TransportResolver { - public enum Type { + private static final SmackLogger LOGGER = SmackLogger.getLogger(TransportResolver.class); + + public enum Type { rawupd, ice } @@ -247,7 +250,7 @@ public abstract class TransportResolver { TransportResolverListener trl = (TransportResolverListener) iter.next(); if (trl instanceof TransportResolverListener.Resolver) { TransportResolverListener.Resolver li = (TransportResolverListener.Resolver) trl; - System.out.println("triggerCandidateAdded : " + cand.getLocalIp()); + LOGGER.debug("triggerCandidateAdded : " + cand.getLocalIp()); li.candidateAdded(cand); } } @@ -331,7 +334,7 @@ public abstract class TransportResolver { Collections.sort(cands); // Return the last candidate result = (TransportCandidate) cands.get(cands.size() - 1); - System.out.println("Result: " + result.getIp()); + LOGGER.debug("Result: " + result.getIp()); } return result; @@ -383,12 +386,12 @@ public abstract class TransportResolver { public void initializeAndWait() throws XMPPException { this.initialize(); try { - System.out.print("Initializing..."); + LOGGER.debug("Initializing transport resolver..."); while (!this.isInitialized()) { - System.out.print("."); + LOGGER.debug("Resolver init still pending"); Thread.sleep(1000); } - System.out.print("Resolved\n"); + LOGGER.debug("Transport resolved\n"); } catch (Exception e) { e.printStackTrace(); diff --git a/jingle/extension/source/org/jivesoftware/smackx/packet/Jingle.java b/jingle/extension/source/org/jivesoftware/smackx/packet/Jingle.java index d731847ca..b20fcaa8b 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/packet/Jingle.java +++ b/jingle/extension/source/org/jivesoftware/smackx/packet/Jingle.java @@ -44,7 +44,7 @@ public class Jingle extends IQ { // static - public static final String NAMESPACE = "http://www.xmpp.org/extensions/xep-0166.html#ns"; + public static final String NAMESPACE = "urn:xmpp:tmp:jingle"; public static final String NODENAME = "jingle"; @@ -190,8 +190,6 @@ public class Jingle extends IQ { /** * Returns the XML namespace of the extension sub-packet root element. - * According the specification the namespace is always - * "http://www.xmpp.org/extensions/xep-0166.html#ns" * * @return the XML namespace of the packet extension. */ diff --git a/jingle/extension/source/org/jivesoftware/smackx/packet/JingleContentDescription.java b/jingle/extension/source/org/jivesoftware/smackx/packet/JingleContentDescription.java index 86020117c..5c58f9cb5 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/packet/JingleContentDescription.java +++ b/jingle/extension/source/org/jivesoftware/smackx/packet/JingleContentDescription.java @@ -172,7 +172,7 @@ public abstract class JingleContentDescription implements PacketExtension { */ public static class Audio extends JingleContentDescription { - public static final String NAMESPACE = "http://jabber.org/protocol/jingle/description/audio"; + public static final String NAMESPACE = "urn:xmpp:tmp:jingle:apps:rtp"; public Audio() { super(); diff --git a/jingle/extension/source/org/jivesoftware/smackx/packet/JingleContentInfo.java b/jingle/extension/source/org/jivesoftware/smackx/packet/JingleContentInfo.java index 60ca87660..af3241d38 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/packet/JingleContentInfo.java +++ b/jingle/extension/source/org/jivesoftware/smackx/packet/JingleContentInfo.java @@ -96,7 +96,7 @@ public class JingleContentInfo implements PacketExtension { */ public static class Audio extends JingleContentInfo { - public static final String NAMESPACE = "http://www.xmpp.org/extensions/xep-0167.html#ns-info"; + public static final String NAMESPACE = "urn:xmpp:tmp:jingle:apps:rtp"; public Audio(final ContentInfo mi) { super(mi); diff --git a/jingle/extension/source/org/jivesoftware/smackx/packet/JingleDescription.java b/jingle/extension/source/org/jivesoftware/smackx/packet/JingleDescription.java index 5c82d9480..212cd503d 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/packet/JingleDescription.java +++ b/jingle/extension/source/org/jivesoftware/smackx/packet/JingleDescription.java @@ -19,14 +19,15 @@ */ package org.jivesoftware.smackx.packet; -import org.jivesoftware.smack.packet.PacketExtension; -import org.jivesoftware.smackx.jingle.media.PayloadType; - import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; +import org.jivesoftware.smack.packet.PacketExtension; +import org.jivesoftware.smackx.jingle.SmackLogger; +import org.jivesoftware.smackx.jingle.media.PayloadType; + /** * Jingle content description. * @@ -34,7 +35,9 @@ import java.util.List; */ public abstract class JingleDescription implements PacketExtension { - // static + private static final SmackLogger LOGGER = SmackLogger.getLogger(JingleDescription.class); + + // static public static final String NODENAME = "description"; @@ -73,7 +76,7 @@ public abstract class JingleDescription implements PacketExtension { public void addPayloadType(final PayloadType pt) { synchronized (payloads) { if (pt == null) { - System.err.println("Null payload type"); + LOGGER.error("Null payload type"); } else { payloads.add(pt); } @@ -176,7 +179,7 @@ public abstract class JingleDescription implements PacketExtension { */ public static class Audio extends JingleDescription { - public static final String NAMESPACE = "http://www.xmpp.org/extensions/xep-0167.html#ns"; + public static final String NAMESPACE = "urn:xmpp:tmp:jingle:apps:rtp"; public Audio() { super(); diff --git a/jingle/extension/source/org/jivesoftware/smackx/packet/JingleError.java b/jingle/extension/source/org/jivesoftware/smackx/packet/JingleError.java index 9067a7ea5..79ab27d59 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/packet/JingleError.java +++ b/jingle/extension/source/org/jivesoftware/smackx/packet/JingleError.java @@ -27,7 +27,7 @@ import org.xmlpull.v1.XmlPullParser; public class JingleError implements PacketExtension { - public static String NAMESPACE = "http://www.xmpp.org/extensions/xep-0166.html#ns-errors"; + public static String NAMESPACE = "urn:xmpp:tmp:jingle:errors"; public static final JingleError OUT_OF_ORDER = new JingleError("out-of-order"); diff --git a/jingle/extension/source/org/jivesoftware/smackx/packet/JingleTransport.java b/jingle/extension/source/org/jivesoftware/smackx/packet/JingleTransport.java index f80d1f83f..38eca2b94 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/packet/JingleTransport.java +++ b/jingle/extension/source/org/jivesoftware/smackx/packet/JingleTransport.java @@ -270,7 +270,7 @@ public class JingleTransport implements PacketExtension { * RTP-ICE profile */ public static class Ice extends JingleTransport { - public static final String NAMESPACE = "http://www.xmpp.org/extensions/xep-0176.html#ns-udp"; + public static final String NAMESPACE = "urn:xmpp:tmp:jingle:transports:ice-udp"; public Ice() { super(); diff --git a/jingle/extension/source/org/jivesoftware/smackx/provider/JingleTransportProvider.java b/jingle/extension/source/org/jivesoftware/smackx/provider/JingleTransportProvider.java index 52029eda9..ea1048f7f 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/provider/JingleTransportProvider.java +++ b/jingle/extension/source/org/jivesoftware/smackx/provider/JingleTransportProvider.java @@ -234,7 +234,7 @@ public abstract class JingleTransportProvider implements PacketExtensionProvider String name = parser.getAttributeValue("", "name"); String port = parser.getAttributeValue("", "port"); - //System.out.println(); + //LOGGER.debug(); if (generation != null) { try { diff --git a/jingle/extension/test/org/jivesoftware/smackx/jingle/nat/STUNResolverTest.java b/jingle/extension/test/org/jivesoftware/smackx/jingle/nat/STUNResolverTest.java index 72f95b03c..65e7c7331 100644 --- a/jingle/extension/test/org/jivesoftware/smackx/jingle/nat/STUNResolverTest.java +++ b/jingle/extension/test/org/jivesoftware/smackx/jingle/nat/STUNResolverTest.java @@ -14,8 +14,11 @@ import org.jivesoftware.smackx.jingle.media.JingleMediaManager; import org.jivesoftware.smackx.jingle.media.PayloadType; import org.jivesoftware.smackx.jingle.mediaimpl.test.TestMediaManager; +import java.net.NetworkInterface; +import java.net.SocketException; import java.net.UnknownHostException; import java.util.ArrayList; +import java.util.Enumeration; import java.util.List; /** @@ -129,10 +132,28 @@ public class STUNResolverTest extends SmackTestCase { cc.prioritizeCandidates(); // get SortedCandidates - for (Candidate candidate : cc.getSortedCandidates()) + for (Candidate candidate : cc.getSortedCandidates()) { + short nicNum = 0; + try { + Enumeration nics = NetworkInterface.getNetworkInterfaces(); + short tempNic = 0; + NetworkInterface nic = NetworkInterface.getByInetAddress(candidate.getAddress().getInetAddress()); + while(nics.hasMoreElements()) { + NetworkInterface checkNIC = nics.nextElement(); + if (checkNIC.equals(nic)) { + nicNum = tempNic; + break; + } + i++; + } + } catch (SocketException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + try { TransportCandidate transportCandidate = new ICECandidate(candidate.getAddress().getInetAddress() - .getHostAddress(), 1, candidate.getNetwork(), "1", candidate.getPort(), "1", candidate.getPriority(), + .getHostAddress(), 1, nicNum, "1", candidate.getPort(), "1", candidate.getPriority(), ICECandidate.Type.prflx); transportCandidate.setLocalIp(candidate.getBase().getAddress().getInetAddress().getHostAddress()); System.out.println("C: " + candidate.getAddress().getInetAddress() + "|" @@ -142,6 +163,7 @@ public class STUNResolverTest extends SmackTestCase { } catch (UnknownHostException e) { e.printStackTrace(); } + } Candidate candidate = cc.getSortedCandidates().get(0); String temp = "C: " + candidate.getAddress().getInetAddress() + "|" + candidate.getBase().getAddress().getInetAddress() + " p:" + candidate.getPriority(); diff --git a/jingle/extension/test/org/jivesoftware/smackx/provider/JingleProviderTest.java b/jingle/extension/test/org/jivesoftware/smackx/provider/JingleProviderTest.java index a54732410..64a7267dc 100644 --- a/jingle/extension/test/org/jivesoftware/smackx/provider/JingleProviderTest.java +++ b/jingle/extension/test/org/jivesoftware/smackx/provider/JingleProviderTest.java @@ -36,11 +36,11 @@ public class JingleProviderTest extends SmackTestCase { // Create a dummy packet for testing... IQfake iqSent = new IQfake ( - " " + - " " + + " " + "