tts.js 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. // We make use of this 'server' variable to provide the address of the
  2. // REST Janus API. By default, in this example we assume that Janus is
  3. // co-located with the web server hosting the HTML pages but listening
  4. // on a different port (8088, the default for HTTP in Janus), which is
  5. // why we make use of the 'window.location.hostname' base address. Since
  6. // Janus can also do HTTPS, and considering we don't really want to make
  7. // use of HTTP for Janus if your demos are served on HTTPS, we also rely
  8. // on the 'window.location.protocol' prefix to build the variable, in
  9. // particular to also change the port used to contact Janus (8088 for
  10. // HTTP and 8089 for HTTPS, if enabled).
  11. // In case you place Janus behind an Apache frontend (as we did on the
  12. // online demos at http://janus.conf.meetecho.com) you can just use a
  13. // relative path for the variable, e.g.:
  14. //
  15. // var server = "/janus";
  16. //
  17. // which will take care of this on its own.
  18. //
  19. //
  20. // If you want to use the WebSockets frontend to Janus, instead, you'll
  21. // have to pass a different kind of address, e.g.:
  22. //
  23. // var server = "ws://" + window.location.hostname + ":8188";
  24. //
  25. // Of course this assumes that support for WebSockets has been built in
  26. // when compiling the server. WebSockets support has not been tested
  27. // as much as the REST API, so handle with care!
  28. //
  29. //
  30. // If you have multiple options available, and want to let the library
  31. // autodetect the best way to contact your server (or pool of servers),
  32. // you can also pass an array of servers, e.g., to provide alternative
  33. // means of access (e.g., try WebSockets first and, if that fails, fall
  34. // back to plain HTTP) or just have failover servers:
  35. //
  36. // var server = [
  37. // "ws://" + window.location.hostname + ":8188",
  38. // "/janus"
  39. // ];
  40. //
  41. // This will tell the library to try connecting to each of the servers
  42. // in the presented order. The first working server will be used for
  43. // the whole session.
  44. //
  45. var server = null;
  46. if (window.location.protocol === 'http:')
  47. //server = "http://" + window.location.hostname + ":9020/janus";
  48. // yujianbo
  49. server = "https://" + "10.80.21.211" + ":9022/janus";
  50. else
  51. //server = "https://" + window.location.hostname + ":9022/janus";
  52. // -yujianbo
  53. server = "https://" + "10.80.21.211" + ":9022/janus";
  54. var janus = null;
  55. var tts = null;
  56. var opaqueId = "tts-" + Janus.randomString(12);
  57. var spinner = null;
  58. $(document).ready(function () {
  59. // Initialize the library (all console debuggers enabled)
  60. Janus.init({
  61. debug: "all", callback: function () {
  62. // Use a button to start the demo
  63. $('#start').on('click', function () {
  64. // Make sure the browser supports WebRTC
  65. if (!Janus.isWebrtcSupported()) {
  66. bootbox.alert("No WebRTC support... ");
  67. return;
  68. }
  69. if ($('#tts_url').val().length == 0) {
  70. bootbox.alert("Please input tts url... ");
  71. return;
  72. }
  73. $(this).attr('disabled', true).unbind('click');
  74. // Create session
  75. janus = new Janus(
  76. {
  77. server: window.EZUITalk.opt.rtcUrl,
  78. // No "iceServers" is provided, meaning janus.js will use a default STUN server
  79. // Here are some examples of how an iceServers field may look like to support TURN
  80. // iceServers: [{urls: "turn:yourturnserver.com:3478", username: "janususer", credential: "januspwd"}],
  81. // iceServers: [{urls: "turn:yourturnserver.com:443?transport=tcp", username: "janususer", credential: "januspwd"}],
  82. // iceServers: [{urls: "turns:yourturnserver.com:443?transport=tcp", username: "janususer", credential: "januspwd"}],
  83. // Should the Janus API require authentication, you can specify either the API secret or user token here too
  84. // token: "mytoken",
  85. // or
  86. // apisecret: "serversecret",
  87. success: function () {
  88. // Attach to tts plugin
  89. janus.attach(
  90. {
  91. plugin: "rtcgw.plugin.tts",
  92. opaqueId: opaqueId,
  93. success: function (pluginHandle) {
  94. $('#details').remove();
  95. tts = pluginHandle;
  96. Janus.log("Plugin attached! (" + tts.getPlugin() + ", id=" + tts.getId() + ")");
  97. // Negotiate WebRTC
  98. //var url = "tts://61.130.6.23:8664/talk://D13781761:0:1:cas.ys7.com:6500?97fbd2a75fa94b7682c994d3d1fac8ca:ut.5porslgu79e9r7ca48z32k8abgl3rp58-77bhb6i7xr-1kmumtg-jkhy7pvfr:0:3"
  99. //var url = "tts://10.86.15.209:8664/talk://D13781761:0:1:cas.ys7.com:6500?32db2578ba7c4a84be22ecc0bcd0f8db:ut.5lqpkhim5m7cdk2y5w60g7hm9vd7i3v0-3d2pwhxe2t-11wx2ge-sh4yazbll:0:3"
  100. //var url = "tts://10.86.15.209:8664/talk://D13781761:0:1:cas.ys7.com:6500"
  101. //test12.ys.com
  102. //var url = "tts://10.86.15.209:8664/talk://D08197169:0:1:cas.ys7.com:6500"
  103. //test10.ys.com
  104. //var url = "tts://10.86.29.210:8664/talk://D08197169:0:1:cas.ys7.com:6500"
  105. var url = $('#tts_url').val();
  106. var body = {
  107. "request": "start",
  108. "url": url,
  109. "codec": "opus",
  110. "dir": "sendrecv",
  111. "audio_debug": 1
  112. };
  113. //tts.send({"message": body});
  114. Janus.debug("Trying a createOffer too (audio/video sendrecv)");
  115. tts.createOffer(
  116. {
  117. // No media provided: by default, it's sendrecv for audio and video
  118. media: {audio: true, video: false, data: false}, // Audio only
  119. // If you want to test simulcasting (Chrome and Firefox only), then
  120. // pass a ?simulcast=true when opening this demo page: it will turn
  121. // the following 'simulcast' property to pass to janus.js to true
  122. simulcast: false,
  123. simulcast2: false,
  124. success: function (jsep) {
  125. Janus.debug("Got SDP!");
  126. Janus.debug(jsep);
  127. tts.send({"message": body, "jsep": jsep});
  128. },
  129. error: function (error) {
  130. Janus.error("WebRTC error:", error);
  131. // bootbox.alert("WebRTC error... " + JSON.stringify(error));
  132. }
  133. });
  134. // $('#start').removeAttr('disabled').html("Stop")
  135. // .click(function() {
  136. // $(this).attr('disabled', true);
  137. // janus.destroy();
  138. // });
  139. },
  140. error: function (error) {
  141. console.error(" -- Error attaching plugin...", error);
  142. bootbox.alert("Error attaching plugin... " + error);
  143. },
  144. consentDialog: function (on) {
  145. Janus.debug("Consent dialog should be " + (on ? "on" : "off") + " now");
  146. if (on) {
  147. // Darken screen and show hint
  148. // $.blockUI({
  149. // message: '<div><img src="up_arrow.png"/></div>',
  150. // css: {
  151. // border: 'none',
  152. // padding: '15px',
  153. // backgroundColor: 'transparent',
  154. // color: '#aaa',
  155. // top: '10px',
  156. // left: (navigator.mozGetUserMedia ? '-100px' : '300px')
  157. // } });
  158. } else {
  159. // Restore screen
  160. // $.unblockUI();
  161. }
  162. },
  163. iceState: function (state) {
  164. Janus.log("ICE state changed to " + state);
  165. },
  166. mediaState: function (medium, on) {
  167. Janus.log("Janus " + (on ? "started" : "stopped") + " receiving our " + medium);
  168. },
  169. webrtcState: function (on) {
  170. Janus.log("Janus says our WebRTC PeerConnection is " + (on ? "up" : "down") + " now");
  171. $("#audioleft").parent().unblock();
  172. },
  173. slowLink: function (uplink, lost) {
  174. Janus.warn("Janus reports problems " + (uplink ? "sending" : "receiving") +
  175. " packets on this PeerConnection (" + lost + " lost packets)");
  176. },
  177. onmessage: function (msg, jsep) {
  178. Janus.debug(" ::: Got a message :::");
  179. Janus.debug(msg);
  180. if (jsep !== undefined && jsep !== null) {
  181. Janus.debug("Handling SDP as well...");
  182. Janus.debug(jsep);
  183. tts.handleRemoteJsep({jsep: jsep});
  184. }
  185. var result = msg["result"];
  186. if (result !== null && result !== undefined) {
  187. if (result === "done") {
  188. // The plugin closed
  189. bootbox.alert("The TTS Test is over");
  190. if (spinner !== null && spinner !== undefined)
  191. spinner.stop();
  192. spinner = null;
  193. $('#myaudio').remove();
  194. //$('#waitingvideo').remove();
  195. $('#peeraudio').remove();
  196. return;
  197. }
  198. // Any loss?
  199. var status = result["status"];
  200. if (status === "slow_link") {
  201. //~ var bitrate = result["bitrate"];
  202. //~ toastr.warning("The bitrate has been cut to " + (bitrate/1000) + "kbps", "Packet loss?", {timeOut: 2000});
  203. toastr.warning("Janus apparently missed many packets we sent, maybe we should reduce the bitrate", "Packet loss?", {timeOut: 2000});
  204. }
  205. }
  206. },
  207. onlocalstream: function (stream) {
  208. Janus.debug(" ::: Got a local stream :::");
  209. Janus.debug(stream);
  210. if ($('#myaudio').length === 0) {
  211. $('#audios').removeClass('hide').show();
  212. $('#audioleft').append('<audio id="myaudio" autoplay controls muted>Your browser does not support audio tag</audio>');
  213. }
  214. Janus.attachMediaStream($('#myaudio').get(0), stream);
  215. //$("#myaudio").get(0).muted = "muted";
  216. if (tts.webrtcStuff.pc.iceConnectionState !== "completed" &&
  217. tts.webrtcStuff.pc.iceConnectionState !== "connected") {
  218. // $("#audioleft").parent().block({
  219. // message: '<b>Publishing...</b>',
  220. // css: {
  221. // border: 'none',
  222. // backgroundColor: 'transparent',
  223. // color: 'white'
  224. // }
  225. // });
  226. // No remote video yet
  227. //$('#audioright').append('<video class="rounded centered" id="waitingvideo" width=320 height=240 />');
  228. if (spinner == null) {
  229. var target = document.getElementById('audioright');
  230. //spinner = new Spinner({top:100}).spin(target);
  231. } else {
  232. spinner.spin();
  233. }
  234. }
  235. var audioTracks = stream.getAudioTracks();
  236. if (audioTracks === null || audioTracks === undefined || audioTracks.length === 0) {
  237. $('#myaudio').hide();
  238. } else {
  239. $('#myaudio').removeClass('hide').show();
  240. }
  241. },
  242. onremotestream: function (stream) {
  243. Janus.debug(" ::: Got a remote stream :::");
  244. Janus.debug(stream);
  245. if ($('#peeraudio').length === 0) {
  246. $('#audios').removeClass('hide').show();
  247. $('#audioright').append('<audio id="peeraudio" autoplay controls>Your browser does not support audio tag</audio>');
  248. // Show the video, hide the spinner and show the resolution when we get a playing event
  249. $("#peeraudio").bind("playing", function () {
  250. //$('#waitingvideo').remove();
  251. $('#peeraudio').removeClass('hide').show();
  252. if (spinner !== null && spinner !== undefined)
  253. spinner.stop();
  254. spinner = null;
  255. });
  256. }
  257. Janus.attachMediaStream($('#peeraudio').get(0), stream);
  258. var audioTracks = stream.getAudioTracks();
  259. if (audioTracks === null || audioTracks === undefined || audioTracks.length === 0) {
  260. $('#peeraudio').hide();
  261. } else {
  262. $('#peeraudio').removeClass('hide').show();
  263. }
  264. },
  265. ondataopen: function (data) {
  266. Janus.log("The DataChannel is available!");
  267. },
  268. ondata: function (data) {
  269. Janus.debug("We got data from the DataChannel! " + data);
  270. },
  271. oncleanup: function () {
  272. Janus.log(" ::: Got a cleanup notification :::");
  273. if (spinner !== null && spinner !== undefined)
  274. spinner.stop();
  275. spinner = null;
  276. $('#myaudio').remove();
  277. //$('#waitingvideo').remove();
  278. $("#audioleft").parent().unblock();
  279. $('#peeraudio').remove();
  280. }
  281. });
  282. },
  283. error: function (error) {
  284. Janus.error(error);
  285. bootbox.alert(error, function () {
  286. // window.location.reload();
  287. });
  288. },
  289. destroyed: function () {
  290. // window.location.reload();
  291. }
  292. });
  293. });
  294. window.stopTalk = function () {
  295. janus.destroy();
  296. }
  297. EZUITalkStopTalk = function () {
  298. janus.destroy();
  299. }
  300. // debugger;
  301. window.startTalk = startTalk;
  302. function startTalk() {
  303. // Make sure the browser supports WebRTC
  304. if (!Janus.isWebrtcSupported()) {
  305. bootbox.alert("No WebRTC support... ");
  306. return;
  307. }
  308. // if($('#tts_url').val().length == 0){
  309. // bootbox.alert("Please input tts url... ");
  310. // return;
  311. // }
  312. $(this).attr('disabled', true).unbind('click');
  313. // Create session
  314. janus = new Janus(
  315. {
  316. server: window.EZUITalk.opt.rtcUrl,
  317. // No "iceServers" is provided, meaning janus.js will use a default STUN server
  318. // Here are some examples of how an iceServers field may look like to support TURN
  319. // iceServers: [{urls: "turn:yourturnserver.com:3478", username: "janususer", credential: "januspwd"}],
  320. // iceServers: [{urls: "turn:yourturnserver.com:443?transport=tcp", username: "janususer", credential: "januspwd"}],
  321. // iceServers: [{urls: "turns:yourturnserver.com:443?transport=tcp", username: "janususer", credential: "januspwd"}],
  322. // Should the Janus API require authentication, you can specify either the API secret or user token here too
  323. // token: "mytoken",
  324. // or
  325. // apisecret: "serversecret",
  326. success: function () {
  327. // Attach to tts plugin
  328. janus.attach(
  329. {
  330. plugin: "rtcgw.plugin.tts",
  331. opaqueId: opaqueId,
  332. success: function (pluginHandle) {
  333. $('#details').remove();
  334. tts = pluginHandle;
  335. Janus.log("Plugin attached! (" + tts.getPlugin() + ", id=" + tts.getId() + ")");
  336. // Negotiate WebRTC
  337. //var url = "tts://61.130.6.23:8664/talk://D13781761:0:1:cas.ys7.com:6500?97fbd2a75fa94b7682c994d3d1fac8ca:ut.5porslgu79e9r7ca48z32k8abgl3rp58-77bhb6i7xr-1kmumtg-jkhy7pvfr:0:3"
  338. //var url = "tts://10.86.15.209:8664/talk://D13781761:0:1:cas.ys7.com:6500?32db2578ba7c4a84be22ecc0bcd0f8db:ut.5lqpkhim5m7cdk2y5w60g7hm9vd7i3v0-3d2pwhxe2t-11wx2ge-sh4yazbll:0:3"
  339. //var url = "tts://10.86.15.209:8664/talk://D13781761:0:1:cas.ys7.com:6500"
  340. //test12.ys.com
  341. //var url = "tts://10.86.15.209:8664/talk://D08197169:0:1:cas.ys7.com:6500"
  342. //test10.ys.com
  343. //var url = "tts://10.86.29.210:8664/talk://D08197169:0:1:cas.ys7.com:6500"
  344. var url = window.EZUITalk.opt.talkLink;
  345. console.log("ttsUlr", url);
  346. var body = {
  347. "request": "start",
  348. "url": url,
  349. "codec": "opus",
  350. "dir": "sendrecv",
  351. "audio_debug": 1
  352. };
  353. //tts.send({"message": body});
  354. Janus.debug("Trying a createOffer too (audio/video sendrecv)");
  355. tts.createOffer(
  356. {
  357. // No media provided: by default, it's sendrecv for audio and video
  358. media: {audio: true, video: false, data: false}, // Audio only
  359. // If you want to test simulcasting (Chrome and Firefox only), then
  360. // pass a ?simulcast=true when opening this demo page: it will turn
  361. // the following 'simulcast' property to pass to janus.js to true
  362. simulcast: false,
  363. simulcast2: false,
  364. success: function (jsep) {
  365. Janus.debug("Got SDP!");
  366. Janus.debug(jsep);
  367. tts.send({"message": body, "jsep": jsep});
  368. },
  369. error: function (error) {
  370. Janus.error("WebRTC error:", error);
  371. // bootbox.alert("WebRTC error... " + JSON.stringify(error));
  372. }
  373. });
  374. // $('#start').removeAttr('disabled').html("Stop")
  375. // .click(function() {
  376. // $(this).attr('disabled', true);
  377. // janus.destroy();
  378. // });
  379. },
  380. error: function (error) {
  381. console.error(" -- Error attaching plugin...", error);
  382. bootbox.alert("Error attaching plugin... " + error);
  383. },
  384. consentDialog: function (on) {
  385. Janus.debug("Consent dialog should be " + (on ? "on" : "off") + " now");
  386. if (on) {
  387. // Darken screen and show hint
  388. // $.blockUI({
  389. // message: '<div><img src="up_arrow.png"/></div>',
  390. // css: {
  391. // border: 'none',
  392. // padding: '15px',
  393. // backgroundColor: 'transparent',
  394. // color: '#aaa',
  395. // top: '10px',
  396. // left: (navigator.mozGetUserMedia ? '-100px' : '300px')
  397. // } });
  398. } else {
  399. // Restore screen
  400. // $.unblockUI();
  401. }
  402. },
  403. iceState: function (state) {
  404. Janus.log("ICE state changed to " + state);
  405. },
  406. mediaState: function (medium, on) {
  407. Janus.log("Janus " + (on ? "started" : "stopped") + " receiving our " + medium);
  408. },
  409. webrtcState: function (on) {
  410. Janus.log("Janus says our WebRTC PeerConnection is " + (on ? "up" : "down") + " now");
  411. // $("#audioleft").parent().unblock();
  412. },
  413. slowLink: function (uplink, lost) {
  414. Janus.warn("Janus reports problems " + (uplink ? "sending" : "receiving") +
  415. " packets on this PeerConnection (" + lost + " lost packets)");
  416. },
  417. onmessage: function (msg, jsep) {
  418. Janus.debug(" ::: Got a message :::");
  419. Janus.debug(msg);
  420. if (jsep !== undefined && jsep !== null) {
  421. Janus.debug("Handling SDP as well...");
  422. Janus.debug(jsep);
  423. tts.handleRemoteJsep({jsep: jsep});
  424. }
  425. var result = msg["result"];
  426. if (result !== null && result !== undefined) {
  427. if (result === "done") {
  428. // The plugin closed
  429. bootbox.alert("The TTS Test is over");
  430. if (spinner !== null && spinner !== undefined)
  431. spinner.stop();
  432. spinner = null;
  433. $('#myaudio').remove();
  434. //$('#waitingvideo').remove();
  435. $('#peeraudio').remove();
  436. return;
  437. }
  438. // Any loss?
  439. var status = result["status"];
  440. if (status === "slow_link") {
  441. //~ var bitrate = result["bitrate"];
  442. //~ toastr.warning("The bitrate has been cut to " + (bitrate/1000) + "kbps", "Packet loss?", {timeOut: 2000});
  443. toastr.warning("Janus apparently missed many packets we sent, maybe we should reduce the bitrate", "Packet loss?", {timeOut: 2000});
  444. }
  445. }
  446. },
  447. onlocalstream: function (stream) {
  448. Janus.debug(" ::: Got a local stream :::");
  449. Janus.debug(stream);
  450. if ($('#myaudio').length === 0) {
  451. $('#audios').removeClass('hide').show();
  452. $('#audioleft').append('<audio id="myaudio" autoplay controls muted>Your browser does not support audio tag</audio>');
  453. }
  454. Janus.attachMediaStream($('#myaudio').get(0), stream);
  455. //$("#myaudio").get(0).muted = "muted";
  456. if (tts.webrtcStuff.pc.iceConnectionState !== "completed" &&
  457. tts.webrtcStuff.pc.iceConnectionState !== "connected") {
  458. // $("#audioleft").parent().block({
  459. // message: '<b>Publishing...</b>',
  460. // css: {
  461. // border: 'none',
  462. // backgroundColor: 'transparent',
  463. // color: 'white'
  464. // }
  465. // });
  466. // No remote video yet
  467. //$('#audioright').append('<video class="rounded centered" id="waitingvideo" width=320 height=240 />');
  468. if (spinner == null) {
  469. var target = document.getElementById('audioright');
  470. //spinner = new Spinner({top:100}).spin(target);
  471. } else {
  472. spinner.spin();
  473. }
  474. }
  475. var audioTracks = stream.getAudioTracks();
  476. if (audioTracks === null || audioTracks === undefined || audioTracks.length === 0) {
  477. $('#myaudio').hide();
  478. } else {
  479. $('#myaudio').removeClass('hide').show();
  480. }
  481. },
  482. onremotestream: function (stream) {
  483. Janus.debug(" ::: Got a remote stream :::");
  484. Janus.debug(stream);
  485. if ($('#peeraudio').length === 0) {
  486. $('#audios').removeClass('hide').show();
  487. $('#audioright').append('<audio id="peeraudio" autoplay controls>Your browser does not support audio tag</audio>');
  488. // Show the video, hide the spinner and show the resolution when we get a playing event
  489. $("#peeraudio").bind("playing", function () {
  490. //$('#waitingvideo').remove();
  491. $('#peeraudio').removeClass('hide').show();
  492. if (spinner !== null && spinner !== undefined)
  493. spinner.stop();
  494. spinner = null;
  495. });
  496. }
  497. Janus.attachMediaStream($('#peeraudio').get(0), stream);
  498. var audioTracks = stream.getAudioTracks();
  499. if (audioTracks === null || audioTracks === undefined || audioTracks.length === 0) {
  500. $('#peeraudio').hide();
  501. } else {
  502. $('#peeraudio').removeClass('hide').show();
  503. }
  504. },
  505. ondataopen: function (data) {
  506. Janus.log("The DataChannel is available!");
  507. },
  508. ondata: function (data) {
  509. Janus.debug("We got data from the DataChannel! " + data);
  510. },
  511. oncleanup: function () {
  512. Janus.log(" ::: Got a cleanup notification :::");
  513. if (spinner !== null && spinner !== undefined)
  514. spinner.stop();
  515. spinner = null;
  516. $('#myaudio').remove();
  517. //$('#waitingvideo').remove();
  518. $("#audioleft").parent().unblock();
  519. $('#peeraudio').remove();
  520. }
  521. });
  522. },
  523. error: function (error) {
  524. Janus.error(error);
  525. console.log("error", error)
  526. },
  527. destroyed: function () {
  528. // window.location.reload();
  529. }
  530. });
  531. }
  532. }
  533. });
  534. });
  535. function checkEnter(event) {
  536. var theCode = event.keyCode ? event.keyCode : event.which ? event.which : event.charCode;
  537. if (theCode == 13) {
  538. sendData();
  539. return false;
  540. } else {
  541. return true;
  542. }
  543. }
  544. // Helper to parse query string
  545. function getQueryStringValue(name) {
  546. name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
  547. var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
  548. results = regex.exec(location.search);
  549. return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
  550. }