freeswitch.mxml 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()"
  3. preinitialize="presetup()"
  4. width="250" height="150"
  5. xmlns:local="*">
  6. <mx:Script>
  7. <![CDATA[
  8. import flash.external.*;
  9. import flash.net.NetConnection;
  10. import flash.net.NetStream;
  11. import mx.utils.ObjectUtil;
  12. import mx.core.FlexGlobals;
  13. import flash.system.Security;
  14. import flash.system.SecurityPanel;
  15. import flash.media.*;
  16. import com.adobe.crypto.MD5;
  17. import com.adobe.serialization.json.JSON;
  18. [Bindable]
  19. public var netConnection:NetConnection = null;
  20. private var incomingNetStream:NetStream = null;
  21. private var outgoingNetStream:NetStream = null;
  22. private var mic:Microphone = null;
  23. [Bindable] private var microphoneList:Array;
  24. private var sessionid:String;
  25. private var auth_user:String;
  26. private var auth_domain:String;
  27. private var mic_index:int = -1;
  28. private var attachedUUID:String = "";
  29. [Embed(source="Sound_of_phone_ringing2.mp3")]
  30. [Bindable]
  31. private var soundOfPhoneRinging_MP3:Class;
  32. private var ringChannel:SoundChannel = null;
  33. private var ringUUID:String = "";
  34. private var soundOfPhoneRinging:Sound;
  35. public function presetup():void
  36. {
  37. /* Load config here */
  38. soundOfPhoneRinging = new soundOfPhoneRinging_MP3();
  39. }
  40. /********* JavaScript functions *********/
  41. public function makeCall(number:String, account:String, evt:Object):void {
  42. if (netConnection != null) {
  43. if (incomingNetStream == null) {
  44. setupStreams();
  45. }
  46. netConnection.call("makeCall", null, number, account, evt);
  47. }
  48. }
  49. public function sendDTMF(digits:String, duration:int):void {
  50. if (netConnection != null) {
  51. netConnection.call("sendDTMF", null, digits, duration);
  52. }
  53. }
  54. public function answer(uuid:String):void {
  55. if (ringChannel != null) {
  56. ringChannel.stop();
  57. ringChannel = null;
  58. }
  59. if (incomingNetStream == null) {
  60. setupStreams();
  61. }
  62. if (netConnection != null) {
  63. netConnection.call("answer", null, uuid);
  64. }
  65. }
  66. public function hangup(uuid:String):void {
  67. if (uuid == attachedUUID) {
  68. destroyStreams();
  69. }
  70. if (netConnection != null) {
  71. netConnection.call("hangup", null, uuid);
  72. }
  73. }
  74. public function register(account:String, nickname:String):void {
  75. if (netConnection != null) {
  76. netConnection.call("register", null, account, nickname);
  77. }
  78. }
  79. public function unregister(account:String, nickname:String):void {
  80. if (netConnection != null) {
  81. netConnection.call("unregister", null, account, nickname);
  82. }
  83. }
  84. public function attach(uuid:String):void {
  85. if (netConnection != null) {
  86. netConnection.call("attach", null, uuid);
  87. }
  88. }
  89. public function transfer(uuid:String, number:String):void {
  90. if (netConnection != null) {
  91. netConnection.call("transfer", null, uuid, number);
  92. }
  93. }
  94. public function three_way(uuid1:String, uuid2:String):void {
  95. if (netConnection != null) {
  96. netConnection.call("three_way", null, uuid1, uuid2);
  97. }
  98. }
  99. public function join(uuid1:String, uuid2:String):void {
  100. if (netConnection != null) {
  101. netConnection.call("join", null, uuid1, uuid2);
  102. }
  103. }
  104. public function sendevent(data:Object):void {
  105. if (netConnection != null) {
  106. netConnection.call("sendevent", null, data);
  107. }
  108. }
  109. public function getMic():int {
  110. return mic_index;
  111. }
  112. public function micList():Object {
  113. return JSON.encode(microphoneList);
  114. }
  115. public function setMic(index:int):void {
  116. mic_index = index;
  117. setupMic();
  118. }
  119. public function isMuted():Boolean {
  120. if (mic != null) {
  121. return mic.muted;
  122. } else {
  123. return false;
  124. }
  125. }
  126. public function showPrivacy():void {
  127. Security.showSettings(SecurityPanel.PRIVACY);
  128. }
  129. public function login(username:String, password:String):void {
  130. if (netConnection != null) {
  131. netConnection.call("login", null, username, MD5.hash(sessionid + ":" + username + ":" + password));
  132. }
  133. }
  134. public function logout(account:String):void {
  135. if (netConnection != null) {
  136. netConnection.call("logout", null, account);
  137. }
  138. }
  139. public function setVolume(value:Number):void {
  140. if (incomingNetStream != null) {
  141. var st:SoundTransform = new SoundTransform(value);
  142. incomingNetStream.soundTransform = st;
  143. }
  144. }
  145. public function setMicVolume(value:Number):void {
  146. if (outgoingNetStream != null) {
  147. var st:SoundTransform = new SoundTransform(value);
  148. outgoingNetStream.soundTransform = st;
  149. }
  150. }
  151. /********* FreeSWITCH functions *********/
  152. /* XXX: TODO: Move those in a separate object so a malicious server can't setup streams and spy on the user */
  153. public function connected(sid:String):void{
  154. sessionid = sid;
  155. if (ExternalInterface.available) {
  156. ExternalInterface.call("onConnected", sid);
  157. }
  158. }
  159. public function onHangup(uuid:String, cause:String):void {
  160. if (ringUUID == uuid && ringChannel != null) {
  161. ringChannel.stop();
  162. ringChannel = null;
  163. }
  164. if (ExternalInterface.available) {
  165. ExternalInterface.call("onHangup", uuid, cause);
  166. }
  167. }
  168. public function onLogin(result:String, user:String, domain:String):void {
  169. if (result == "success") {
  170. auth_user = user;
  171. auth_domain = domain;
  172. }
  173. if (ExternalInterface.available) {
  174. ExternalInterface.call("onLogin", result, user, domain);
  175. }
  176. }
  177. public function onLogout(user:String, domain:String):void {
  178. if (ExternalInterface.available) {
  179. ExternalInterface.call("onLogout", user, domain);
  180. }
  181. }
  182. public function onAttach(uuid:String):void {
  183. attachedUUID = uuid;
  184. if (ringChannel != null && uuid != "") {
  185. ringChannel.stop();
  186. ringChannel = null;
  187. }
  188. if (attachedUUID == "") {
  189. destroyStreams();
  190. } else if (incomingNetStream == null || outgoingNetStream == null) {
  191. setupStreams();
  192. }
  193. if (ExternalInterface.available) {
  194. ExternalInterface.call("onAttach", uuid);
  195. }
  196. }
  197. public function onMakeCall(uuid:String, number:String, account:String):void {
  198. if (ExternalInterface.available) {
  199. ExternalInterface.call("onMakeCall", uuid, number, account);
  200. }
  201. }
  202. public function callState(uuid:String, state:String):void {
  203. if (ExternalInterface.available) {
  204. ExternalInterface.call("onCallState", uuid, state);
  205. }
  206. }
  207. public function displayUpdate(uuid:String, name:String, number:String):void {
  208. if (ExternalInterface.available) {
  209. ExternalInterface.call("onDisplayUpdate", uuid, name, number);
  210. }
  211. }
  212. public function incomingCall(uuid:String, name:String, number:String, account:String, evt:Object):void {
  213. if (attachedUUID == "" && ringChannel == null) {
  214. ringUUID = uuid;
  215. ringChannel = soundOfPhoneRinging.play(0, 3);
  216. }
  217. if (evt != null) {
  218. if (evt.hasOwnProperty("rtmp_auto_answer")) {
  219. if (evt.rtmp_auto_answer == "true") {
  220. answer(uuid);
  221. }
  222. }
  223. }
  224. if (ExternalInterface.available) {
  225. ExternalInterface.call("onIncomingCall", uuid, name, number, account, evt);
  226. }
  227. }
  228. public function event(event:Object):void {
  229. if (ExternalInterface.available) {
  230. ExternalInterface.call("onEvent", JSON.encode(event));
  231. }
  232. }
  233. /********* Internal functions *********/
  234. private function onDebug(message:String):void {
  235. //statusTxt.text = (statusTxt.text != "") ? statusTxt.text + "\n" + message : message;
  236. if (ExternalInterface.available) {
  237. ExternalInterface.call("onDebug", message);
  238. }
  239. }
  240. private function init():void
  241. {
  242. NetConnection.defaultObjectEncoding = ObjectEncoding.AMF0;
  243. try {
  244. Security.allowDomain("*");
  245. } catch(e:Error) {
  246. onDebug("Exception: " + e.toString());
  247. }
  248. if (ExternalInterface.available) {
  249. try {
  250. ExternalInterface.marshallExceptions = true;
  251. ExternalInterface.addCallback("login", this.login);
  252. ExternalInterface.addCallback("logout", this.logout);
  253. ExternalInterface.addCallback("makeCall", this.makeCall);
  254. ExternalInterface.addCallback("attach", this.attach);
  255. ExternalInterface.addCallback("answer", this.answer);
  256. ExternalInterface.addCallback("hangup", this.hangup);
  257. ExternalInterface.addCallback("sendDTMF", this.sendDTMF);
  258. ExternalInterface.addCallback("register", this.register);
  259. ExternalInterface.addCallback("unregister", this.unregister);
  260. ExternalInterface.addCallback("transfer", this.transfer);
  261. ExternalInterface.addCallback("three_way", this.three_way);
  262. ExternalInterface.addCallback("getMic", this.getMic);
  263. ExternalInterface.addCallback("micList", this.micList);
  264. ExternalInterface.addCallback("setMic", this.setMic);
  265. ExternalInterface.addCallback("isMuted", this.isMuted);
  266. ExternalInterface.addCallback("showPrivacy", this.showPrivacy);
  267. ExternalInterface.addCallback("connect", this.connect);
  268. ExternalInterface.addCallback("disconnect", this.disconnect);
  269. ExternalInterface.addCallback("join", this.join);
  270. ExternalInterface.addCallback("sendevent", this.sendevent);
  271. ExternalInterface.addCallback("setVolume", this.setVolume);
  272. ExternalInterface.addCallback("setMicVolume", this.setMicVolume);
  273. //txtStatus.text = "Connecting...";
  274. } catch(e:Error) {
  275. //txtStatus.text = e.toString();
  276. onDebug("Exception: " + e.toString());
  277. }
  278. } else {
  279. onDebug("ExternalInterface is disabled");
  280. }
  281. try {
  282. microphoneList = Microphone.names;
  283. setupMic();
  284. connect();
  285. } catch(e:Error) {
  286. onDebug("Exception: " + e.toString());
  287. }
  288. if (ExternalInterface.available) {
  289. ExternalInterface.call("onInit");
  290. }
  291. }
  292. public function connect():void{
  293. if (netConnection != null) {
  294. disconnect();
  295. }
  296. netConnection = new NetConnection();
  297. netConnection.client = this;
  298. netConnection.addEventListener( NetStatusEvent.NET_STATUS , netStatus );
  299. netConnection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
  300. netConnection.connect(FlexGlobals.topLevelApplication.parameters.rtmp_url);
  301. }
  302. public function disconnect():void {
  303. if (netConnection != null) {
  304. netConnection.close();
  305. netConnection = null;
  306. incomingNetStream = null;
  307. outgoingNetStream = null;
  308. }
  309. }
  310. private function destroyStreams():void {
  311. if (outgoingNetStream != null) {
  312. onDebug("Closing media streams")
  313. outgoingNetStream.close();
  314. outgoingNetStream = null;
  315. }
  316. if (incomingNetStream != null) {
  317. incomingNetStream.close();
  318. incomingNetStream = null;
  319. }
  320. }
  321. private function setupMic():void {
  322. try {
  323. mic = Microphone.getMicrophone(mic_index);
  324. mic.addEventListener(ActivityEvent.ACTIVITY, activityHandler);
  325. mic.addEventListener(StatusEvent.STATUS, statusHandler);
  326. mic.codec = SoundCodec.SPEEX;
  327. mic.setUseEchoSuppression(true);
  328. mic.setLoopBack(false);
  329. mic.setSilenceLevel(0,20000);
  330. mic.framesPerPacket = 1;
  331. mic.gain = 55;
  332. mic.rate = 16;
  333. mic_index = mic.index;
  334. if (outgoingNetStream != null) {
  335. outgoingNetStream.close();
  336. outgoingNetStream = new NetStream(netConnection);
  337. outgoingNetStream.addEventListener(NetStatusEvent.NET_STATUS, netStatus);
  338. outgoingNetStream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
  339. outgoingNetStream.attachAudio(mic);
  340. outgoingNetStream.publish("publish", "live");
  341. }
  342. } catch(e:Error) {
  343. onDebug("Couldn't setup microphone: " + e.message);
  344. }
  345. }
  346. private function setupStreams():void {
  347. onDebug("Setup media streams");
  348. if (mic == null || mic.index != mic_index) {
  349. setupMic();
  350. }
  351. incomingNetStream = new NetStream(netConnection);
  352. incomingNetStream.addEventListener(NetStatusEvent.NET_STATUS, netStatus);
  353. incomingNetStream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
  354. incomingNetStream.client = this;
  355. incomingNetStream.bufferTime = 0.2;
  356. incomingNetStream.play("play");
  357. incomingNetStream.receiveAudio(true);
  358. outgoingNetStream = new NetStream(netConnection);
  359. outgoingNetStream.addEventListener(NetStatusEvent.NET_STATUS, netStatus);
  360. outgoingNetStream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
  361. outgoingNetStream.attachAudio(mic);
  362. outgoingNetStream.publish("publish", "live");
  363. }
  364. private function onDisconnected():void {
  365. if (ExternalInterface.available) {
  366. ExternalInterface.call("onDisconnected");
  367. }
  368. }
  369. private function securityErrorHandler(event:SecurityErrorEvent):void {
  370. onDebug("securityErrorHandler: " + event.text);
  371. }
  372. private function asyncErrorHandler(event:AsyncErrorEvent):void {
  373. onDebug("asyncErrorHandler: " + event.text);
  374. }
  375. private function activityHandler(event:ActivityEvent):void {
  376. onDebug("activityHandler: " + event);
  377. }
  378. private function statusHandler(event:StatusEvent):void {
  379. onDebug("statusHandler: " + event);
  380. }
  381. private function netStatus (evt:NetStatusEvent ):void {
  382. onDebug("netStatus: " + evt.info.code);
  383. switch(evt.info.code) {
  384. case "NetConnection.Connect.Success":
  385. //txtStatus.text = "Connected";
  386. break;
  387. case "NetConnection.Connect.Failed":
  388. netConnection = null;
  389. incomingNetStream = null;
  390. outgoingNetStream = null;
  391. //btnCall.label = "Connect";
  392. //txtStatus.text = "Failed";
  393. onDisconnected();
  394. break;
  395. case "NetConnection.Connect.Closed":
  396. netConnection = null;
  397. incomingNetStream = null;
  398. outgoingNetStream = null;
  399. //btnCall.label = "Connect";
  400. //txtStatus.text = "Disconnected";
  401. onDisconnected();
  402. break;
  403. case "NetConnection.Connect.Rejected":
  404. netConnection = null;
  405. incomingNetStream = null;
  406. outgoingNetStream = null;
  407. //btnCall.label = "Connect";
  408. //txtStatus.text = "Rejected";
  409. onDisconnected();
  410. break;
  411. case "NetStream.Play.StreamNotFound":
  412. break;
  413. case "NetStream.Play.Failed":
  414. break;
  415. case "NetStream.Play.Start":
  416. break;
  417. case "NetStream.Play.Stop":
  418. break;
  419. case "NetStream.Buffer.Full":
  420. break;
  421. default:
  422. }
  423. }
  424. ]]>
  425. </mx:Script>
  426. <!--<mx:Panel id="reader" title="Test" width="500">
  427. <mx:TextArea width="500" color="#FF0000" id="statusTxt"/>
  428. </mx:Panel>-->
  429. </mx:Application>