one2one.html 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>SRS</title>
  5. <meta charset="utf-8">
  6. <style>
  7. body{
  8. padding-top: 30px;
  9. }
  10. </style>
  11. <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
  12. <script type="text/javascript" src="js/jquery-1.12.2.min.js"></script>
  13. <script type="text/javascript" src="js/adapter-7.4.0.min.js"></script>
  14. <script type="text/javascript" src="js/srs.sdk.js"></script>
  15. <script type="text/javascript" src="js/srs.sig.js"></script>
  16. </head>
  17. <body>
  18. <img src='https://ossrs.net/gif/v1/sls.gif?site=ossrs.net&path=/player/one2one'/>
  19. <div class="navbar navbar-fixed-top">
  20. <div class="navbar-inner">
  21. <div class="container">
  22. <a class="brand" href="https://github.com/ossrs/srs">SRS</a>
  23. <div class="nav-collapse collapse">
  24. <ul class="nav srs_nav">
  25. <li class="active"><a href="one2one.html">一对一通话</a></li>
  26. <li><a href="room.html">多人通话</a></li>
  27. <li class="srs_ignore">
  28. <a href="https://github.com/ossrs/signaling">
  29. <img alt="GitHub Repo stars" src="img/shields-io-signaling.svg">
  30. </a>
  31. </li>
  32. </ul>
  33. </div>
  34. </div>
  35. </div>
  36. </div>
  37. <div class="container">
  38. <div class="form-inline">
  39. SRS:
  40. <input type="text" id="txt_host" class="input-medium" value="">
  41. Room:
  42. <input type="text" id="txt_room" class="input-small" value="live">
  43. Display:
  44. <input type="text" id="txt_display" class="input-small" value="">
  45. <button class="btn btn-primary" id="btn_start">开始通话</button>
  46. </div>
  47. <div class="row">
  48. <div class="span4 hide" id="publisher">
  49. <label></label>
  50. <video id="rtc_media_publisher" width="310" autoplay muted controls></video>
  51. <label></label>
  52. <span id='self'></span>
  53. </div>
  54. <div class="span6 hide" id="player">
  55. <label></label>
  56. <video id="rtc_media_player" width="310" autoplay muted controls></video>
  57. <label></label>
  58. <span id='peer'></span>
  59. <a href="javascript:control_refresh_peer()">Refresh</a>
  60. <input type="text" id="txt_alert" class="input-medium" value="">
  61. <a href="javascript:control_alert_peer()">Alert</a>
  62. </div>
  63. </div>
  64. <label></label>
  65. <div class="accordion hide srs_merge">
  66. <div class="accordion-group">
  67. <div class="accordion-heading">
  68. <a href="javascript:void(0)" class="accordion-toggle">FFmpeg合流转直播</a>
  69. </div>
  70. <div class="accordion-body collapse in">
  71. <div class="accordion-inner" style="overflow:auto">
  72. ffmpeg -f flv -i rtmp://<span class="ff_host"></span>/<span class="ff_app"></span>/<span class="ff_first"></span> -f flv -i rtmp://<span class="ff_host"></span>/<span class="ff_app"></span>/<span class="ff_second"></span> \ <br/>
  73. &nbsp;&nbsp;&nbsp;&nbsp; -filter_complex "[1:v]scale=w=96:h=72[ckout];[0:v][ckout]overlay=x=W-w-10:y=H-h-10[out]" -map "[out]" \ <br/>
  74. &nbsp;&nbsp;&nbsp;&nbsp; -c:v libx264 -profile:v high -preset medium \ <br/>
  75. &nbsp;&nbsp;&nbsp;&nbsp; -filter_complex amix -c:a aac \ <br/>
  76. &nbsp;&nbsp;&nbsp;&nbsp; -f flv -y
  77. <span id="ff_output">
  78. rtmp://<span class="ff_host"></span>/<span class="ff_app"></span>/merge
  79. </span>
  80. <span id="ff_wxvideo"></span>
  81. && <br/>
  82. echo "ok"
  83. </div>
  84. <div class="accordion-inner">
  85. <a href="#" id="ff_preview" target="_blank" class="accordion-toggle">
  86. 预览:rtmp://<span class="ff_host"></span>/<span class="ff_app"></span>/merge
  87. </a>
  88. </div>
  89. </div>
  90. </div>
  91. </div>
  92. <label></label>
  93. <div class="accordion hide srs_merge">
  94. <div class="accordion-group">
  95. <div class="accordion-heading">
  96. <a href="javascript:void(0)" class="accordion-toggle">
  97. 视频号推流信息
  98. </a>
  99. </div>
  100. <div class="accordion-body collapse in">
  101. <div class="accordion-inner">
  102. 推流地址 <input type="text" id="txt_wx_video_tcurl" class="input-xxlarge">
  103. </div>
  104. <div class="accordion-inner">
  105. 推流密钥 <input type="text" id="txt_wx_video_stream" class="input-xxlarge">
  106. </div>
  107. <div class="accordion-inner">
  108. <button class="btn btn-primary" id="btn_apply">应用</button>
  109. </div>
  110. </div>
  111. </div>
  112. </div>
  113. </div>
  114. <footer class="footer">
  115. <div class="container">
  116. <p>&copy; SRS 2020</p>
  117. </div>
  118. </footer>
  119. <script type="text/javascript">
  120. var sig = null;
  121. var publisher = null;
  122. var player = null;
  123. var control_refresh_peer = null;
  124. var control_alert_peer = null;
  125. $(function(){
  126. console.log('?wss=x to specify the websocket schema, ws or wss');
  127. console.log('?wsh=x to specify the websocket server ip');
  128. console.log('?wsp=x to specify the websocket server port');
  129. console.log('?host=x to specify the SRS server');
  130. console.log('?room=x to specify the room to join');
  131. console.log('?display=x to specify your nick name');
  132. var startDemo = async function () {
  133. var host = $('#txt_host').val();
  134. var room = $('#txt_room').val();
  135. var display = $('#txt_display').val();
  136. // Connect to signaling first.
  137. if (sig) {
  138. sig.close();
  139. }
  140. sig = new SrsRtcSignalingAsync();
  141. sig.onmessage = function (msg) {
  142. console.log('Notify: ', msg);
  143. if (msg.event === 'leave') {
  144. $('#player').hide();
  145. }
  146. if (msg.event === 'publish') {
  147. if (msg.peer && msg.peer.publishing && msg.peer.display !== display) {
  148. startPlay(host, room, msg.peer.display);
  149. }
  150. }
  151. if (msg.event === 'control') {
  152. if (msg.param === 'refresh') {
  153. setTimeout(function () {
  154. window.location.reload();
  155. }, 500);
  156. } else if (msg.param === 'alert') {
  157. alert('From ' + msg.peer.display + ': ' + msg.data);
  158. }
  159. }
  160. if (msg.participants.length >= 2) {
  161. $('.srs_merge').show();
  162. } else {
  163. $('.srs_merge').hide();
  164. }
  165. };
  166. await sig.connect(conf.wsSchema, conf.wsHost, room, display);
  167. control_refresh_peer = async function () {
  168. let r1 = await sig.send({action:'control', room:room, display:display, call:'refresh'});
  169. console.log('Signaling: control peer to refresh ok', r1);
  170. };
  171. control_alert_peer = async function () {
  172. let r1 = await sig.send({action:'control', room:room, display:display, call:'alert', data:$('#txt_alert').val()});
  173. console.log('Signaling: control peer to alert ok', r1);
  174. };
  175. let r0 = await sig.send({action:'join', room:room, display:display});
  176. console.log('Signaling: join ok', r0);
  177. // For one to one demo, alert and ignore when room is full.
  178. if (r0.participants.length > 2) {
  179. alert('Room is full, already ' + (r0.participants.length - 1) + ' participants');
  180. sig.close();
  181. return;
  182. }
  183. // Start publish media if signaling is ok.
  184. await startPublish(host, room, display);
  185. let r1 = await sig.send({action:'publish', room:room, display:display});
  186. console.log('Signaling: publish ok', r1);
  187. // Play the stream already in room.
  188. r0.participants.forEach(function(participant) {
  189. if (participant.display === display || !participant.publishing) return;
  190. startPlay(host, room, participant.display);
  191. });
  192. if (r0.participants.length >= 2) {
  193. $('.srs_merge').show();
  194. }
  195. };
  196. var startPublish = function (host, room, display) {
  197. $(".ff_first").each(function(i,e) {
  198. $(e).text(display);
  199. });
  200. var url = 'webrtc://' + host + '/' + room + '/' + display + conf.query;
  201. $('#rtc_media_publisher').show();
  202. $('#publisher').show();
  203. if (publisher) {
  204. publisher.close();
  205. }
  206. publisher = new SrsRtcPublisherAsync();
  207. $('#rtc_media_publisher').prop('srcObject', publisher.stream);
  208. return publisher.publish(url).then(function(session){
  209. $('#self').text('Self: ' + url);
  210. }).catch(function (reason) {
  211. publisher.close();
  212. $('#rtc_media_publisher').hide();
  213. console.error(reason);
  214. });
  215. };
  216. var startPlay = function (host, room, display) {
  217. $(".ff_second").each(function(i,e) {
  218. $(e).text(display);
  219. });
  220. var url = 'webrtc://' + host + '/' + room + '/' + display + conf.query;
  221. $('#rtc_media_player').show();
  222. $('#player').show();
  223. if (player) {
  224. player.close();
  225. }
  226. player = new SrsRtcPlayerAsync();
  227. $('#rtc_media_player').prop('srcObject', player.stream);
  228. player.play(url).then(function(session){
  229. $('#peer').text('Peer: ' + display);
  230. $('#rtc_media_player').prop('muted', false);
  231. }).catch(function (reason) {
  232. player.close();
  233. $('#rtc_media_player').hide();
  234. console.error(reason);
  235. });
  236. };
  237. // Pass-by to SRS url.
  238. let conf = SrsRtcSignalingParse(window.location);
  239. $('#txt_host').val(conf.host);
  240. conf.room && $('#txt_room').val(conf.room);
  241. $('#txt_display').val(conf.display);
  242. $(".ff_host").each(function(i,e) {
  243. $(e).text(conf.host);
  244. });
  245. $(".ff_app").each(function(i,e) {
  246. $(e).text($('#txt_room').val());
  247. });
  248. $('#ff_preview').attr('href', 'http://ossrs.net/players/srs_player.html?app=' + $('#txt_room').val() + '&stream=merge.flv&server=' + conf.host + '&vhost=' + conf.host + '&autostart=true');
  249. // Update href for all navs.
  250. $('ul.srs_nav').children('li').not('.srs_ignore').children('a').each(function (i, e) {
  251. $(e).attr('href', $(e).attr('href') + conf.rawQuery);
  252. });
  253. $('#btn_apply').click(function () {
  254. if ($('#txt_wx_video_tcurl').val() !== '' && $('#txt_wx_video_stream').val() !== '') {
  255. $('#ff_wxvideo').text('"' + $('#txt_wx_video_tcurl').val() + $('#txt_wx_video_stream').val() + '"').show();
  256. $('#ff_output').hide();
  257. $('#ff_preview').parent().hide();
  258. } else {
  259. $('#ff_wxvideo').hide();
  260. $('#ff_output').show();
  261. $('#ff_preview').parent().show();
  262. }
  263. });
  264. $("#btn_start").click(startDemo);
  265. // Never play util windows loaded @see https://github.com/ossrs/srs/issues/2732
  266. if (conf.autostart) {
  267. window.addEventListener("load", function(){ startDemo(); });
  268. }
  269. });
  270. </script>
  271. </body>
  272. </html>