Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support WHIP and WHEP player. v5.0.147 and v6.0.35 #3460

Merged
merged 8 commits into from
Mar 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions trunk/doc/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ The changelog for SRS.

## SRS 6.0 Changelog

* v6.0, 2023-03-20, Merge [#3460](https://github.com/ossrs/srs/pull/3460): WebRTC: Support WHIP/WHEP players. v6.0.35 (#3460)
* v6.0, 2023-03-07, Merge [#3441](https://github.com/ossrs/srs/pull/3441): HEVC: webrtc support hevc on safari. v6.0.34 (#3441)
* v6.0, 2023-03-07, Merge [#3446](https://github.com/ossrs/srs/pull/3446): WebRTC: Warning if no ideal profile. v6.0.33 (#3446)
* v6.0, 2023-03-06, Merge [#3445](https://github.com/ossrs/srs/pull/3445): Support configure for generic linux. v6.0.32 (#3445)
Expand Down Expand Up @@ -48,6 +49,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)
Expand Down
1 change: 1 addition & 0 deletions trunk/doc/Features.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ The features of SRS.
- [x] Other: [Experimental] Support pushing MPEG-TS over UDP, please read [bug #250](https://github.com/ossrs/srs/issues/250). v2.0.111+
- [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)). v2.0.163+
- [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: 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).
- [ ] System: Support JT808 and JT1708 for transport, [#3420](https://github.com/ossrs/srs/issues/3420).
Expand Down
42 changes: 42 additions & 0 deletions trunk/research/players/js/srs.page.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand All @@ -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/'));
}
147 changes: 143 additions & 4 deletions trunk/research/players/js/srs.sdk.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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.
winlinvip marked this conversation as resolved.
Show resolved Hide resolved
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) {
Expand Down
5 changes: 3 additions & 2 deletions trunk/research/players/rtc_player.html
Original file line number Diff line number Diff line change
Expand Up @@ -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>-->
Expand Down Expand Up @@ -105,8 +107,7 @@
$('#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>
Expand Down
2 changes: 2 additions & 0 deletions trunk/research/players/rtc_publisher.html
Original file line number Diff line number Diff line change
Expand Up @@ -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>-->
Expand Down
2 changes: 2 additions & 0 deletions trunk/research/players/srs_player.html
Original file line number Diff line number Diff line change
Expand Up @@ -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>-->
Expand Down
Loading