diff --git a/trunk/doc/CHANGELOG.md b/trunk/doc/CHANGELOG.md index a82d3f70b..9ce73d2d3 100644 --- a/trunk/doc/CHANGELOG.md +++ b/trunk/doc/CHANGELOG.md @@ -7,9 +7,10 @@ The changelog for SRS. ## SRS 7.0 Changelog -* v7.0, 2025-10-26, Build: Improve dependency checking to report all missing dependencies at once. v7.0.105 (#4293) -* v7.0, 2025-10-26, HLS: Support hls_master_m3u8_path_relative for reverse proxy compatibility. v7.0.104 (#4338) -* v7.0, 2025-10-25, API: Remove minimum limit of 10 for count parameter in /api/v1/streams and /api/v1/clients. v7.0.103 (#4358) +* v7.0, 2025-10-26, AI: WebRTC: Fix camera/microphone not released after closing publisher. v7.0.106 (#4261) +* v7.0, 2025-10-26, AI: Build: Improve dependency checking to report all missing dependencies at once. v7.0.105 (#4293) +* v7.0, 2025-10-26, AI: HLS: Support hls_master_m3u8_path_relative for reverse proxy compatibility. v7.0.104 (#4338) +* v7.0, 2025-10-25, AI: API: Remove minimum limit of 10 for count parameter in /api/v1/streams and /api/v1/clients. v7.0.103 (#4358) * v7.0, 2025-10-22, AI: Only support AAC/MP3/Opus audio codec. v7.0.102 (#4516) * v7.0, 2025-10-22, AI: Fix AAC audio sample rate reporting in API. v7.0.101 (#4518) * v7.0, 2025-10-20, Merge [#4537](https://github.com/ossrs/srs/pull/4537): Forward: Reject RTMPS destinations with clear error message. v7.0.100 (#4537) diff --git a/trunk/research/players/js/srs.sdk.js b/trunk/research/players/js/srs.sdk.js index 7d49ddc79..4dadb445d 100644 --- a/trunk/research/players/js/srs.sdk.js +++ b/trunk/research/players/js/srs.sdk.js @@ -28,6 +28,9 @@ function SrsRtcPublisherAsync() { } }; + // Store media stream to stop tracks when closing. + self.userStream = null; + // @see https://github.com/rtcdn/rtcdn-draft // @url The WebRTC url to play with, for example: // webrtc://r.ossrs.net/live/livestream @@ -60,10 +63,10 @@ function SrsRtcPublisherAsync() { 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); + self.userStream = 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.userStream.getTracks().forEach(function (track) { self.pc.addTrack(track); // Notify about local track when stream is ok. @@ -104,6 +107,14 @@ function SrsRtcPublisherAsync() { self.close = function () { self.pc && self.pc.close(); self.pc = null; + + // Stop all media tracks to release camera/microphone. + if (self.userStream) { + self.userStream.getTracks().forEach(function (track) { + track.stop(); + }); + self.userStream = null; + } }; // The callback when got local stream. @@ -523,6 +534,10 @@ function SrsRtcWhipWhepAsync() { } }; + // Store media streams to stop tracks when closing. + self.displayStream = null; + self.userStream = null; + // 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 @@ -557,11 +572,11 @@ function SrsRtcWhipWhepAsync() { } if (useScreen) { - const displayStream = await navigator.mediaDevices.getDisplayMedia({ + self.displayStream = await navigator.mediaDevices.getDisplayMedia({ video: true }); // @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addStream#Migrating_to_addTrack - displayStream.getTracks().forEach(function (track) { + self.displayStream.getTracks().forEach(function (track) { self.pc.addTrack(track); // Notify about local track when stream is ok. self.ontrack && self.ontrack({track: track}); @@ -569,9 +584,9 @@ function SrsRtcWhipWhepAsync() { } if (useCamera || hasAudio) { - const userStream = await navigator.mediaDevices.getUserMedia(self.constraints); + self.userStream = await navigator.mediaDevices.getUserMedia(self.constraints); - userStream.getTracks().forEach(function (track) { + self.userStream.getTracks().forEach(function (track) { self.pc.addTrack(track); // Notify about local track when stream is ok. self.ontrack && self.ontrack({track: track}); @@ -643,6 +658,20 @@ function SrsRtcWhipWhepAsync() { self.close = function () { self.pc && self.pc.close(); self.pc = null; + + // Stop all media tracks to release camera/microphone. + if (self.displayStream) { + self.displayStream.getTracks().forEach(function (track) { + track.stop(); + }); + self.displayStream = null; + } + if (self.userStream) { + self.userStream.getTracks().forEach(function (track) { + track.stop(); + }); + self.userStream = null; + } }; // The callback when got local stream. diff --git a/trunk/research/players/whep.html b/trunk/research/players/whep.html index b4a5b24da..103412e59 100644 --- a/trunk/research/players/whep.html +++ b/trunk/research/players/whep.html @@ -53,6 +53,7 @@ URL: +
@@ -130,6 +131,9 @@ $(function(){ }).then(function(session){ $('#sessionid').html(session.sessionid); $('#simulator-drop').attr('href', session.simulator + '?drop=1&username=' + session.sessionid); + // Enable stop button after successful play + $('#btn_stop').prop('disabled', false); + $('#btn_play').prop('disabled', true); }).catch(function (reason) { sdk.close(); $('#rtc_media_player').hide(); @@ -137,11 +141,28 @@ $(function(){ }); }; + var stopPlay = function() { + if (sdk) { + sdk.close(); + + if (statsTimer) { + clearInterval(statsTimer); + statsTimer = null; + } + + $('#btn_stop').prop('disabled', true); + $('#btn_play').prop('disabled', false); + $('#sessionid').html('(stopped)'); + $('#rtc_media_player').hide(); + } + }; + $('#rtc_media_player').hide(); var query = parse_query_string(); srs_init_whep("#txt_url", query); $("#btn_play").click(startPlay); + $("#btn_stop").click(stopPlay); // Never play util windows loaded @see https://github.com/ossrs/srs/issues/2732 if (query.autostart === 'true') { $('#rtc_media_player').prop('muted', true); diff --git a/trunk/research/players/whip.html b/trunk/research/players/whip.html index 36c27ada3..407d3af84 100644 --- a/trunk/research/players/whip.html +++ b/trunk/research/players/whip.html @@ -53,6 +53,7 @@ URL: + @@ -138,6 +139,9 @@ $(function(){ }).then(function(session){ $('#sessionid').html(session.sessionid); $('#simulator-drop').attr('href', session.simulator + '?drop=1&username=' + session.sessionid); + // Enable stop button after successful publish + $('#btn_stop').prop('disabled', false); + $('#btn_publish').prop('disabled', true); }).catch(function (reason) { // Throw by sdk. if (reason instanceof SrsError) { @@ -164,11 +168,29 @@ $(function(){ }); }; + var stopPublish = function() { + if (sdk) { + sdk.close(); + + if (statsTimer) { + clearInterval(statsTimer); + statsTimer = null; + } + + $('#btn_stop').prop('disabled', true); + $('#btn_publish').prop('disabled', false); + $('#sessionid').html('(stopped)'); + $('#rtc_media_player').hide(); + console.log('PeerConnection closed. Check if camera indicator is still on!'); + } + }; + $('#rtc_media_player').hide(); var query = parse_query_string(); srs_init_whip("#txt_url", query); $("#btn_publish").click(startPublish); + $("#btn_stop").click(stopPublish); // Never play util windows loaded @see https://github.com/ossrs/srs/issues/2732 if (query.autostart === 'true') { window.addEventListener("load", function(){ startPublish(); }); diff --git a/trunk/src/core/srs_core_version7.hpp b/trunk/src/core/srs_core_version7.hpp index e74c5d5dd..23b1ffe90 100644 --- a/trunk/src/core/srs_core_version7.hpp +++ b/trunk/src/core/srs_core_version7.hpp @@ -9,6 +9,6 @@ #define VERSION_MAJOR 7 #define VERSION_MINOR 0 -#define VERSION_REVISION 105 +#define VERSION_REVISION 106 #endif \ No newline at end of file