mirror of
				https://github.com/ossrs/srs.git
				synced 2025-03-09 15:49:59 +00:00 
			
		
		
		
	Support WHIP and WHEP player. v5.0.147 and v6.0.35 (#3460)
PICK c001acaae9
Co-authored-by: chundonglinlin <chundonglinlin@163.com>
Co-authored-by: panda <542638787@qq.com>
			
			
This commit is contained in:
		
							parent
							
								
									2f1d0ccd34
								
							
						
					
					
						commit
						dfef94411f
					
				
					 11 changed files with 455 additions and 9 deletions
				
			
		|  | @ -8,6 +8,7 @@ The changelog for SRS. | |||
| 
 | ||||
| ## SRS 5.0 Changelog | ||||
| 
 | ||||
| * v5.0, 2023-03-20, Merge [#3460](https://github.com/ossrs/srs/pull/3460): WebRTC: Support WHIP/WHEP players. v5.0.147 (#3460) | ||||
| * v5.0, 2023-03-07, Merge [#3446](https://github.com/ossrs/srs/pull/3446): WebRTC: Warning if no ideal profile. v5.0.146 (#3446) | ||||
| * v5.0, 2023-03-06, Merge [#3445](https://github.com/ossrs/srs/pull/3445): Support configure for generic linux. v5.0.145 (#3445) | ||||
| * v5.0, 2023-03-04, Merge [#3105](https://github.com/ossrs/srs/pull/3105): Kickoff publisher when stream is idle, which means no players. v5.0.144 (#3105) | ||||
|  |  | |||
|  | @ -67,8 +67,10 @@ The features of SRS. | |||
| - [x] Other: [Experimental] Support pushing MPEG-TS over UDP, please read [bug #250](https://github.com/ossrs/srs/issues/250). | ||||
| - [x] Other: [Experimental] Support pushing FLV over HTTP POST, please read wiki([CN](https://ossrs.net/lts/zh-cn/docs/v4/doc/streamer#push-http-flv-to-srs), [EN](https://ossrs.io/lts/en-us/docs/v4/doc/streamer#push-http-flv-to-srs)). | ||||
| - [x] Other: [Experimental] Support push stream by GB28181, [#3176](https://github.com/ossrs/srs/issues/3176). v5.0.74+ | ||||
| - [x] Other: Support WHIP/WHEP player, [#3460](https://github.com/ossrs/srs/pull/3460). v5.0.147+ | ||||
| - [ ] System: Support Windows/Cygwin 64bits, [#2532](https://github.com/ossrs/srs/issues/2532). | ||||
| - [ ] System: Support H.265 over RTMP and HLS, [#465](https://github.com/ossrs/srs/issues/465). | ||||
| - [ ] System: Proxy to extend origin servers, [#3138](https://github.com/ossrs/srs/issues/3138). | ||||
| - [ ] System: Support source cleanup for idle streams, [#413](https://github.com/ossrs/srs/issues/413). | ||||
| - [ ] Live: Support HLS variant, [#463](https://github.com/ossrs/srs/issues/463). | ||||
| - [ ] RTC: Support IETF-QUIC for WebRTC Cluster, [#2091](https://github.com/ossrs/srs/issues/2091). | ||||
|  |  | |||
|  | @ -17,6 +17,8 @@ function update_nav() { | |||
|     $("#nav_srs_player").attr("href", "srs_player.html" + window.location.search); | ||||
|     $("#nav_rtc_player").attr("href", "rtc_player.html" + window.location.search); | ||||
|     $("#nav_rtc_publisher").attr("href", "rtc_publisher.html" + window.location.search); | ||||
|     $("#nav_whip").attr("href", "whip.html" + window.location.search); | ||||
|     $("#nav_whep").attr("href", "whep.html" + window.location.search); | ||||
|     $("#nav_srs_publisher").attr("href", "srs_publisher.html" + window.location.search); | ||||
|     $("#nav_srs_chat").attr("href", "srs_chat.html" + window.location.search); | ||||
|     $("#nav_srs_bwt").attr("href", "srs_bwt.html" + window.location.search); | ||||
|  | @ -116,6 +118,38 @@ function build_default_rtc_url(query) { | |||
|     return uri; | ||||
| }; | ||||
| 
 | ||||
| function build_default_whip_whep_url(query, apiPath) { | ||||
|     // The format for query string to overwrite configs of server.
 | ||||
|     console.log('?eip=x.x.x.x to overwrite candidate. 覆盖服务器candidate(外网IP)配置'); | ||||
|     console.log('?api=x to overwrite WebRTC API(1985).'); | ||||
|     console.log('?schema=http|https to overwrite WebRTC API protocol.'); | ||||
| 
 | ||||
|     var server = (!query.server)? window.location.hostname:query.server; | ||||
|     var vhost = (!query.vhost)? window.location.hostname:query.vhost; | ||||
|     var app = (!query.app)? "live":query.app; | ||||
|     var stream = (!query.stream)? "livestream":query.stream; | ||||
|     var api = ':' + (query.api || (window.location.protocol === 'http:' ? '1985' : '1990')); | ||||
| 
 | ||||
|     var queries = []; | ||||
|     if (server !== vhost && vhost !== "__defaultVhost__") { | ||||
|         queries.push("vhost=" + vhost); | ||||
|     } | ||||
|     if (query.schema && window.location.protocol !== query.schema + ':') { | ||||
|         queries.push('schema=' + query.schema); | ||||
|     } | ||||
|     queries = user_extra_params(query, queries, true); | ||||
| 
 | ||||
|     var uri = window.location.protocol + "//" + server + api + apiPath + "?app=" + app + "&stream=" + stream + "&" + queries.join('&'); | ||||
|     while (uri.lastIndexOf("?") === uri.length - 1) { | ||||
|         uri = uri.slice(0, uri.length - 1); | ||||
|     } | ||||
|     while (uri.lastIndexOf("&") === uri.length - 1) { | ||||
|         uri = uri.slice(0, uri.length - 1); | ||||
|     } | ||||
| 
 | ||||
|     return uri; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
| * initialize the page. | ||||
| * @param flv_url the div id contains the flv stream url to play | ||||
|  | @ -136,3 +170,11 @@ function srs_init_rtc(id, query) { | |||
|     update_nav(); | ||||
|     $(id).val(build_default_rtc_url(query)); | ||||
| } | ||||
| function srs_init_whip(id, query) { | ||||
|     update_nav(); | ||||
|     $(id).val(build_default_whip_whep_url(query, '/rtc/v1/whip/')); | ||||
| } | ||||
| function srs_init_whep(id, query) { | ||||
|     update_nav(); | ||||
|     $(id).val(build_default_whip_whep_url(query, '/rtc/v1/whip-play/')); | ||||
| } | ||||
|  |  | |||
|  | @ -134,14 +134,14 @@ function SrsRtcPublisherAsync() { | |||
|                 api += '/'; | ||||
|             } | ||||
| 
 | ||||
|             apiUrl = schema + '//' + urlObject.server + ':' + port + api; | ||||
|             var apiUrl = schema + '//' + urlObject.server + ':' + port + api; | ||||
|             for (var key in urlObject.user_query) { | ||||
|                 if (key !== 'api' && key !== 'play') { | ||||
|                     apiUrl += '&' + key + '=' + urlObject.user_query[key]; | ||||
|                 } | ||||
|             } | ||||
|             // Replace /rtc/v1/play/&k=v to /rtc/v1/play/?k=v
 | ||||
|             var apiUrl = apiUrl.replace(api + '&', api + '?'); | ||||
|             apiUrl = apiUrl.replace(api + '&', api + '?'); | ||||
| 
 | ||||
|             var streamUrl = urlObject.url; | ||||
| 
 | ||||
|  | @ -369,14 +369,14 @@ function SrsRtcPlayerAsync() { | |||
|                 api += '/'; | ||||
|             } | ||||
| 
 | ||||
|             apiUrl = schema + '//' + urlObject.server + ':' + port + api; | ||||
|             var apiUrl = schema + '//' + urlObject.server + ':' + port + api; | ||||
|             for (var key in urlObject.user_query) { | ||||
|                 if (key !== 'api' && key !== 'play') { | ||||
|                     apiUrl += '&' + key + '=' + urlObject.user_query[key]; | ||||
|                 } | ||||
|             } | ||||
|             // Replace /rtc/v1/play/&k=v to /rtc/v1/play/?k=v
 | ||||
|             var apiUrl = apiUrl.replace(api + '&', api + '?'); | ||||
|             apiUrl = apiUrl.replace(api + '&', api + '?'); | ||||
| 
 | ||||
|             var streamUrl = urlObject.url; | ||||
| 
 | ||||
|  | @ -510,6 +510,145 @@ function SrsRtcPlayerAsync() { | |||
|     return self; | ||||
| } | ||||
| 
 | ||||
| // Depends on adapter-7.4.0.min.js from https://github.com/webrtc/adapter
 | ||||
| // Async-awat-prmise based SRS RTC Publisher by WHIP.
 | ||||
| function SrsRtcWhipWhepAsync() { | ||||
|     var self = {}; | ||||
| 
 | ||||
|     // https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
 | ||||
|     self.constraints = { | ||||
|         audio: true, | ||||
|         video: { | ||||
|             width: {ideal: 320, max: 576} | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     // See https://datatracker.ietf.org/doc/draft-ietf-wish-whip/
 | ||||
|     // @url The WebRTC url to publish with, for example:
 | ||||
|     //      http://localhost:1985/rtc/v1/whip/?app=live&stream=livestream
 | ||||
|     self.publish = async function (url) { | ||||
|         if (url.indexOf('/whip/') === -1) throw new Error(`invalid WHIP url ${url}`); | ||||
| 
 | ||||
|         self.pc.addTransceiver("audio", {direction: "sendonly"}); | ||||
|         self.pc.addTransceiver("video", {direction: "sendonly"}); | ||||
| 
 | ||||
|         if (!navigator.mediaDevices && window.location.protocol === 'http:' && window.location.hostname !== 'localhost') { | ||||
|             throw new SrsError('HttpsRequiredError', `Please use HTTPS or localhost to publish, read https://github.com/ossrs/srs/issues/2762#issuecomment-983147576`); | ||||
|         } | ||||
|         var stream = await navigator.mediaDevices.getUserMedia(self.constraints); | ||||
| 
 | ||||
|         // @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addStream#Migrating_to_addTrack
 | ||||
|         stream.getTracks().forEach(function (track) { | ||||
|             self.pc.addTrack(track); | ||||
| 
 | ||||
|             // Notify about local track when stream is ok.
 | ||||
|             self.ontrack && self.ontrack({track: track}); | ||||
|         }); | ||||
| 
 | ||||
|         var offer = await self.pc.createOffer(); | ||||
|         await self.pc.setLocalDescription(offer); | ||||
|         const answer = await new Promise(function (resolve, reject) { | ||||
|             console.log("Generated offer: ", offer); | ||||
| 
 | ||||
|             const xhr = new XMLHttpRequest(); | ||||
|             xhr.onload = function() { | ||||
|                 if (xhr.readyState !== xhr.DONE) return; | ||||
|                 if (xhr.status !== 200) return reject(xhr); | ||||
|                 const data = xhr.responseText; | ||||
|                 console.log("Got answer: ", data); | ||||
|                 return data.code ? reject(xhr) : resolve(data); | ||||
|             } | ||||
|             xhr.open('POST', url, true); | ||||
|             xhr.setRequestHeader('Content-type', 'application/sdp'); | ||||
|             xhr.send(offer.sdp); | ||||
|         }); | ||||
|         await self.pc.setRemoteDescription( | ||||
|             new RTCSessionDescription({type: 'answer', sdp: answer}) | ||||
|         ); | ||||
| 
 | ||||
|         return self.__internal.parseId(url, offer.sdp, answer); | ||||
|     }; | ||||
| 
 | ||||
|     // See https://datatracker.ietf.org/doc/draft-ietf-wish-whip/
 | ||||
|     // @url The WebRTC url to play with, for example:
 | ||||
|     //      http://localhost:1985/rtc/v1/whip-play/?app=live&stream=livestream
 | ||||
|     self.play = async function(url) { | ||||
|         if (url.indexOf('/whip-play/') === -1 && url.indexOf('/whep/') === -1) throw new Error(`invalid WHEP url ${url}`); | ||||
| 
 | ||||
|         self.pc.addTransceiver("audio", {direction: "recvonly"}); | ||||
|         self.pc.addTransceiver("video", {direction: "recvonly"}); | ||||
| 
 | ||||
|         var offer = await self.pc.createOffer(); | ||||
|         await self.pc.setLocalDescription(offer); | ||||
|         const answer = await new Promise(function(resolve, reject) { | ||||
|             console.log("Generated offer: ", offer); | ||||
| 
 | ||||
|             const xhr = new XMLHttpRequest(); | ||||
|             xhr.onload = function() { | ||||
|                 if (xhr.readyState !== xhr.DONE) return; | ||||
|                 if (xhr.status !== 200) return reject(xhr); | ||||
|                 const data = xhr.responseText; | ||||
|                 console.log("Got answer: ", data); | ||||
|                 return data.code ? reject(xhr) : resolve(data); | ||||
|             } | ||||
|             xhr.open('POST', url, true); | ||||
|             xhr.setRequestHeader('Content-type', 'application/sdp'); | ||||
|             xhr.send(offer.sdp); | ||||
|         }); | ||||
|         await self.pc.setRemoteDescription( | ||||
|             new RTCSessionDescription({type: 'answer', sdp: answer}) | ||||
|         ); | ||||
| 
 | ||||
|         return self.__internal.parseId(url, offer.sdp, answer); | ||||
|     }; | ||||
| 
 | ||||
|     // Close the publisher.
 | ||||
|     self.close = function () { | ||||
|         self.pc && self.pc.close(); | ||||
|         self.pc = null; | ||||
|     }; | ||||
| 
 | ||||
|     // The callback when got local stream.
 | ||||
|     // @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addStream#Migrating_to_addTrack
 | ||||
|     self.ontrack = function (event) { | ||||
|         // Add track to stream of SDK.
 | ||||
|         self.stream.addTrack(event.track); | ||||
|     }; | ||||
| 
 | ||||
|     self.pc = new RTCPeerConnection(null); | ||||
| 
 | ||||
|     // To keep api consistent between player and publisher.
 | ||||
|     // @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addStream#Migrating_to_addTrack
 | ||||
|     // @see https://webrtc.org/getting-started/media-devices
 | ||||
|     self.stream = new MediaStream(); | ||||
| 
 | ||||
|     // Internal APIs.
 | ||||
|     self.__internal = { | ||||
|         parseId: (url, offer, answer) => { | ||||
|             let sessionid = offer.substr(offer.indexOf('a=ice-ufrag:') + 'a=ice-ufrag:'.length); | ||||
|             sessionid = sessionid.substr(0, sessionid.indexOf('\n') - 1) + ':'; | ||||
|             sessionid += answer.substr(answer.indexOf('a=ice-ufrag:') + 'a=ice-ufrag:'.length); | ||||
|             sessionid = sessionid.substr(0, sessionid.indexOf('\n')); | ||||
| 
 | ||||
|             const a = document.createElement("a"); | ||||
|             a.href = url; | ||||
|             return { | ||||
|                 sessionid: sessionid, // Should be ice-ufrag of answer:offer.
 | ||||
|                 simulator: a.protocol + '//' + a.host + '/rtc/v1/nack/', | ||||
|             }; | ||||
|         }, | ||||
|     }; | ||||
| 
 | ||||
|     // https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/ontrack
 | ||||
|     self.pc.ontrack = function(event) { | ||||
|         if (self.ontrack) { | ||||
|             self.ontrack(event); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     return self; | ||||
| } | ||||
| 
 | ||||
| // Format the codec of RTCRtpSender, kind(audio/video) is optional filter.
 | ||||
| // https://developer.mozilla.org/en-US/docs/Web/Media/Formats/WebRTC_codecs#getting_the_supported_codecs
 | ||||
| function SrsRtcFormatSenders(senders, kind) { | ||||
|  |  | |||
|  | @ -26,6 +26,8 @@ | |||
|                     <li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li> | ||||
|                     <li class="active"><a id="nav_rtc_player" href="rtc_player.html">RTC播放器</a></li> | ||||
|                     <li><a id="nav_rtc_publisher" href="rtc_publisher.html">RTC推流</a></li> | ||||
|                     <li><a id="nav_whip" href="whip.html">WHIP</a></li> | ||||
|                     <li><a id="nav_whep" href="whip.html">WHEP</a></li> | ||||
|                     <li><a  href="http://ossrs.net/srs.release/releases/app.html">iOS/Andriod</a></li> | ||||
|                     <!--<li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>--> | ||||
|                     <!--<li><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>--> | ||||
|  | @ -105,8 +107,7 @@ $(function(){ | |||
|         $('#rtc_media_player').prop('muted', true); | ||||
|         console.warn('For autostart, we should mute it, see https://www.jianshu.com/p/c3c6944eed5a ' + | ||||
|             'or https://developers.google.com/web/updates/2017/09/autoplay-policy-changes#audiovideo_elements'); | ||||
| 
 | ||||
|         startPlay(); | ||||
|         window.addEventListener("load", function(){ startPlay(); }); | ||||
|     } | ||||
| }); | ||||
| </script> | ||||
|  |  | |||
|  | @ -26,6 +26,8 @@ | |||
|                     <li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li> | ||||
|                     <li><a id="nav_rtc_player" href="rtc_player.html">RTC播放器</a></li> | ||||
|                     <li class="active"><a id="nav_rtc_publisher" href="rtc_publisher.html">RTC推流</a></li> | ||||
|                     <li><a id="nav_whip" href="whip.html">WHIP</a></li> | ||||
|                     <li><a id="nav_whep" href="whip.html">WHEP</a></li> | ||||
|                     <li><a  href="http://ossrs.net/srs.release/releases/app.html">iOS/Andriod</a></li> | ||||
|                     <!--<li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>--> | ||||
|                     <!--<li><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>--> | ||||
|  |  | |||
|  | @ -21,6 +21,8 @@ | |||
|                     <li class="active"><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li> | ||||
|                     <li><a id="nav_rtc_player" href="rtc_player.html">RTC播放器</a></li> | ||||
|                     <li><a id="nav_rtc_publisher" href="rtc_publisher.html">RTC推流</a></li> | ||||
|                     <li><a id="nav_whip" href="whip.html">WHIP</a></li> | ||||
|                     <li><a id="nav_whep" href="whip.html">WHEP</a></li> | ||||
|                     <li><a  href="http://ossrs.net/srs.release/releases/app.html">iOS/Andriod</a></li> | ||||
|                     <!--<li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>--> | ||||
|                     <!--<li><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>--> | ||||
|  |  | |||
							
								
								
									
										114
									
								
								trunk/research/players/whep.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								trunk/research/players/whep.html
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,114 @@ | |||
| <!DOCTYPE html> | ||||
| <html> | ||||
| <head> | ||||
|     <title>SRS</title> | ||||
|     <meta charset="utf-8"> | ||||
|     <style> | ||||
|         body{ | ||||
|             padding-top: 30px; | ||||
|         } | ||||
|     </style> | ||||
|     <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/> | ||||
|     <script type="text/javascript" src="js/jquery-1.10.2.min.js"></script> | ||||
|     <script type="text/javascript" src="js/adapter-7.4.0.min.js"></script> | ||||
|     <script type="text/javascript" src="js/srs.sdk.js"></script> | ||||
|     <script type="text/javascript" src="js/winlin.utility.js"></script> | ||||
|     <script type="text/javascript" src="js/srs.page.js"></script> | ||||
| </head> | ||||
| <body> | ||||
| <img src='//ossrs.net/gif/v1/sls.gif?site=ossrs.net&path=/player/rtcpublisher'/> | ||||
| <div class="navbar navbar-fixed-top"> | ||||
|     <div class="navbar-inner"> | ||||
|         <div class="container"> | ||||
|             <a id="srs_index" class="brand" href="https://github.com/ossrs/srs">SRS</a> | ||||
|             <div class="nav-collapse collapse"> | ||||
|                 <ul class="nav"> | ||||
|                     <li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li> | ||||
|                     <li><a id="nav_rtc_player" href="rtc_player.html">RTC播放器</a></li> | ||||
|                     <li><a id="nav_rtc_publisher" href="rtc_publisher.html">RTC推流</a></li> | ||||
|                     <li><a id="nav_whip" href="whip.html">WHIP</a></li> | ||||
|                     <li class="active"><a id="nav_whep" href="whip.html">WHEP</a></li> | ||||
|                     <li><a  href="http://ossrs.net/srs.release/releases/app.html">iOS/Andriod</a></li> | ||||
|                     <!--<li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>--> | ||||
|                     <!--<li><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>--> | ||||
|                     <!--<li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>--> | ||||
|                     <!--<li><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>--> | ||||
|                     <!--<li><a id="nav_gb28181" href="srs_gb28181.html">GB28181</a></li>--> | ||||
|                     <li> | ||||
|                         <a href="https://github.com/ossrs/srs"> | ||||
|                             <img alt="GitHub Repo stars" src="https://img.shields.io/github/stars/ossrs/srs?style=social"> | ||||
|                         </a> | ||||
|                     </li> | ||||
|                 </ul> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
| <div class="container"> | ||||
|     <div class="form-inline"> | ||||
|         URL: | ||||
|         <input type="text" id="txt_url" class="input-xxlarge" value=""> | ||||
|         <button class="btn btn-primary" id="btn_play">Play</button> | ||||
|     </div> | ||||
| 
 | ||||
|     <label></label> | ||||
|     <video id="rtc_media_player" width="320" autoplay muted></video> | ||||
| 
 | ||||
|     <label></label> | ||||
|     SessionID: <span id='sessionid'></span> | ||||
| 
 | ||||
|     <label></label> | ||||
|     Simulator: <a href='#' id='simulator-drop'>Drop</a> | ||||
| 
 | ||||
|     <footer> | ||||
|         <p></p> | ||||
|         <p><a href="https://github.com/ossrs/srs">SRS Team © 2020</a></p> | ||||
|     </footer> | ||||
| </div> | ||||
| <script type="text/javascript"> | ||||
| $(function(){ | ||||
|     var sdk = null; // Global handler to do cleanup when republishing. | ||||
|     var startPlay = function() { | ||||
|         $('#rtc_media_player').show(); | ||||
| 
 | ||||
|         // Close PC when user replay. | ||||
|         if (sdk) { | ||||
|             sdk.close(); | ||||
|         } | ||||
|         sdk = new SrsRtcWhipWhepAsync(); | ||||
| 
 | ||||
|         // User should set the stream when publish is done, @see https://webrtc.org/getting-started/media-devices | ||||
|         // However SRS SDK provides a consist API like https://webrtc.org/getting-started/remote-streams | ||||
|         $('#rtc_media_player').prop('srcObject', sdk.stream); | ||||
|         // Optional callback, SDK will add track to stream. | ||||
|         // sdk.ontrack = function (event) { console.log('Got track', event); sdk.stream.addTrack(event.track); }; | ||||
| 
 | ||||
|         // For example: webrtc://r.ossrs.net/live/livestream | ||||
|         var url = $("#txt_url").val(); | ||||
|         sdk.play(url).then(function(session){ | ||||
|             $('#sessionid').html(session.sessionid); | ||||
|             $('#simulator-drop').attr('href', session.simulator + '?drop=1&username=' + session.sessionid); | ||||
|         }).catch(function (reason) { | ||||
|             sdk.close(); | ||||
|             $('#rtc_media_player').hide(); | ||||
|             console.error(reason); | ||||
|         }); | ||||
|     }; | ||||
| 
 | ||||
|     $('#rtc_media_player').hide(); | ||||
|     var query = parse_query_string(); | ||||
|     srs_init_whep("#txt_url", query); | ||||
| 
 | ||||
|     $("#btn_play").click(startPlay); | ||||
|     // Never play util windows loaded @see https://github.com/ossrs/srs/issues/2732 | ||||
|     if (query.autostart === 'true') { | ||||
|         $('#rtc_media_player').prop('muted', true); | ||||
|         console.warn('For autostart, we should mute it, see https://www.jianshu.com/p/c3c6944eed5a ' + | ||||
|             'or https://developers.google.com/web/updates/2017/09/autoplay-policy-changes#audiovideo_elements'); | ||||
|         window.addEventListener("load", function(){ startPlay(); }); | ||||
|     } | ||||
| }); | ||||
| </script> | ||||
| </body> | ||||
| </html> | ||||
| 
 | ||||
							
								
								
									
										142
									
								
								trunk/research/players/whip.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								trunk/research/players/whip.html
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,142 @@ | |||
| <!DOCTYPE html> | ||||
| <html> | ||||
| <head> | ||||
|     <title>SRS</title> | ||||
|     <meta charset="utf-8"> | ||||
|     <style> | ||||
|         body{ | ||||
|             padding-top: 30px; | ||||
|         } | ||||
|     </style> | ||||
|     <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/> | ||||
|     <script type="text/javascript" src="js/jquery-1.10.2.min.js"></script> | ||||
|     <script type="text/javascript" src="js/adapter-7.4.0.min.js"></script> | ||||
|     <script type="text/javascript" src="js/srs.sdk.js"></script> | ||||
|     <script type="text/javascript" src="js/winlin.utility.js"></script> | ||||
|     <script type="text/javascript" src="js/srs.page.js"></script> | ||||
| </head> | ||||
| <body> | ||||
| <img src='//ossrs.net/gif/v1/sls.gif?site=ossrs.net&path=/player/rtcpublisher'/> | ||||
| <div class="navbar navbar-fixed-top"> | ||||
|     <div class="navbar-inner"> | ||||
|         <div class="container"> | ||||
|             <a id="srs_index" class="brand" href="https://github.com/ossrs/srs">SRS</a> | ||||
|             <div class="nav-collapse collapse"> | ||||
|                 <ul class="nav"> | ||||
|                     <li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li> | ||||
|                     <li><a id="nav_rtc_player" href="rtc_player.html">RTC播放器</a></li> | ||||
|                     <li><a id="nav_rtc_publisher" href="rtc_publisher.html">RTC推流</a></li> | ||||
|                     <li class="active"><a id="nav_whip" href="whip.html">WHIP</a></li> | ||||
|                     <li><a id="nav_whep" href="whip.html">WHEP</a></li> | ||||
|                     <li><a  href="http://ossrs.net/srs.release/releases/app.html">iOS/Andriod</a></li> | ||||
|                     <!--<li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>--> | ||||
|                     <!--<li><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>--> | ||||
|                     <!--<li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>--> | ||||
|                     <!--<li><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>--> | ||||
|                     <!--<li><a id="nav_gb28181" href="srs_gb28181.html">GB28181</a></li>--> | ||||
|                     <li> | ||||
|                         <a href="https://github.com/ossrs/srs"> | ||||
|                             <img alt="GitHub Repo stars" src="https://img.shields.io/github/stars/ossrs/srs?style=social"> | ||||
|                         </a> | ||||
|                     </li> | ||||
|                 </ul> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
| <div class="container"> | ||||
|     <div class="form-inline"> | ||||
|         URL: | ||||
|         <input type="text" id="txt_url" class="input-xxlarge" value=""> | ||||
|         <button class="btn btn-primary" id="btn_publish">Publish</button> | ||||
|     </div> | ||||
| 
 | ||||
|     <label></label> | ||||
|     <video id="rtc_media_player" width="320" autoplay muted></video> | ||||
| 
 | ||||
|     <label></label> | ||||
|     SessionID: <span id='sessionid'></span> | ||||
| 
 | ||||
|     <label></label> | ||||
|     Audio: <span id='acodecs'></span><br/> | ||||
|     Video: <span id='vcodecs'></span> | ||||
| 
 | ||||
|     <label></label> | ||||
|     Simulator: <a href='#' id='simulator-drop'>Drop</a> | ||||
| 
 | ||||
|     <footer> | ||||
|         <p></p> | ||||
|         <p><a href="https://github.com/ossrs/srs">SRS Team © 2020</a></p> | ||||
|     </footer> | ||||
| </div> | ||||
| <script type="text/javascript"> | ||||
| $(function(){ | ||||
|     var sdk = null; // Global handler to do cleanup when republishing. | ||||
|     var startPublish = function() { | ||||
|         $('#rtc_media_player').show(); | ||||
| 
 | ||||
|         // Close PC when user replay. | ||||
|         if (sdk) { | ||||
|             sdk.close(); | ||||
|         } | ||||
|         sdk = new SrsRtcWhipWhepAsync(); | ||||
| 
 | ||||
|         // User should set the stream when publish is done, @see https://webrtc.org/getting-started/media-devices | ||||
|         // However SRS SDK provides a consist API like https://webrtc.org/getting-started/remote-streams | ||||
|         $('#rtc_media_player').prop('srcObject', sdk.stream); | ||||
|         // Optional callback, SDK will add track to stream. | ||||
|         // sdk.ontrack = function (event) { console.log('Got track', event); sdk.stream.addTrack(event.track); }; | ||||
| 
 | ||||
|         // https://developer.mozilla.org/en-US/docs/Web/Media/Formats/WebRTC_codecs#getting_the_supported_codecs | ||||
|         sdk.pc.onicegatheringstatechange = function (event) { | ||||
|             if (sdk.pc.iceGatheringState === "complete") { | ||||
|                 $('#acodecs').html(SrsRtcFormatSenders(sdk.pc.getSenders(), "audio")); | ||||
|                 $('#vcodecs').html(SrsRtcFormatSenders(sdk.pc.getSenders(), "video")); | ||||
|             } | ||||
|         }; | ||||
| 
 | ||||
|         // For example: webrtc://r.ossrs.net/live/livestream | ||||
|         var url = $("#txt_url").val(); | ||||
|         sdk.publish(url).then(function(session){ | ||||
|             $('#sessionid').html(session.sessionid); | ||||
|             $('#simulator-drop').attr('href', session.simulator + '?drop=1&username=' + session.sessionid); | ||||
|         }).catch(function (reason) { | ||||
|             // Throw by sdk. | ||||
|             if (reason instanceof SrsError) { | ||||
|                 if (reason.name === 'HttpsRequiredError') { | ||||
|                     alert(`WebRTC推流必须是HTTPS或者localhost:${reason.name} ${reason.message}`); | ||||
|                 } else { | ||||
|                     alert(`${reason.name} ${reason.message}`); | ||||
|                 } | ||||
|             } | ||||
|             // See https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia#exceptions | ||||
|             if (reason instanceof DOMException) { | ||||
|                 if (reason.name === 'NotFoundError') { | ||||
|                     alert(`找不到麦克风和摄像头设备:getUserMedia ${reason.name} ${reason.message}`); | ||||
|                 } else if (reason.name === 'NotAllowedError') { | ||||
|                     alert(`你禁止了网页访问摄像头和麦克风:getUserMedia ${reason.name} ${reason.message}`); | ||||
|                 } else if (['AbortError', 'NotAllowedError', 'NotFoundError', 'NotReadableError', 'OverconstrainedError', 'SecurityError', 'TypeError'].includes(reason.name)) { | ||||
|                     alert(`getUserMedia ${reason.name} ${reason.message}`); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             sdk.close(); | ||||
|             $('#rtc_media_player').hide(); | ||||
|             console.error(reason); | ||||
|         }); | ||||
|     }; | ||||
| 
 | ||||
|     $('#rtc_media_player').hide(); | ||||
|     var query = parse_query_string(); | ||||
|     srs_init_whip("#txt_url", query); | ||||
| 
 | ||||
|     $("#btn_publish").click(startPublish); | ||||
|     // Never play util windows loaded @see https://github.com/ossrs/srs/issues/2732 | ||||
|     if (query.autostart === 'true') { | ||||
|         window.addEventListener("load", function(){ startPublish(); }); | ||||
|     } | ||||
| }); | ||||
| </script> | ||||
| </body> | ||||
| </html> | ||||
| 
 | ||||
|  | @ -638,6 +638,7 @@ srs_error_t SrsGoApiRtcWhip::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessa | |||
|     ruc.req_->vhost = ruc.req_->host; | ||||
|     ruc.req_->app = app.empty() ? "live" : app; | ||||
|     ruc.req_->stream = stream.empty() ? "livestream" : stream; | ||||
|     ruc.req_->param = r->query(); | ||||
| 
 | ||||
|     // discovery vhost, resolve the vhost from config
 | ||||
|     SrsConfDirective* parsed_vhost = _srs_config->get_vhost(ruc.req_->vhost); | ||||
|  | @ -645,9 +646,9 @@ srs_error_t SrsGoApiRtcWhip::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessa | |||
|         ruc.req_->vhost = parsed_vhost->arg0(); | ||||
|     } | ||||
| 
 | ||||
|     srs_trace("RTC whip %s %s, clientip=%s, app=%s, stream=%s, offer=%dB, eip=%s, codec=%s", | ||||
|     srs_trace("RTC whip %s %s, clientip=%s, app=%s, stream=%s, offer=%dB, eip=%s, codec=%s, param=%s", | ||||
|         action.c_str(), ruc.req_->get_stream_url().c_str(), clientip.c_str(), ruc.req_->app.c_str(), ruc.req_->stream.c_str(), | ||||
|         remote_sdp_str.length(), eip.c_str(), codec.c_str() | ||||
|         remote_sdp_str.length(), eip.c_str(), codec.c_str(), ruc.req_->param.c_str() | ||||
|     ); | ||||
| 
 | ||||
|     ruc.eip_ = eip; | ||||
|  |  | |||
|  | @ -9,6 +9,6 @@ | |||
| 
 | ||||
| #define VERSION_MAJOR       5 | ||||
| #define VERSION_MINOR       0 | ||||
| #define VERSION_REVISION    146 | ||||
| #define VERSION_REVISION    147 | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue