Merge branch 'develop' into pr-develop
This commit is contained in:
commit
25a6f46ff4
30
.vscode/launch.json
vendored
30
.vscode/launch.json
vendored
|
|
@ -2,7 +2,7 @@
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "Launch SRS",
|
"name": "Launch SRS with conf/console.conf",
|
||||||
"type": "cppdbg",
|
"type": "cppdbg",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceFolder}/trunk/cmake/build/srs",
|
"program": "${workspaceFolder}/trunk/cmake/build/srs",
|
||||||
|
|
@ -29,6 +29,34 @@
|
||||||
"engineLogging": true
|
"engineLogging": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "Launch SRS with conf/rtc.conf",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/trunk/cmake/build/srs",
|
||||||
|
"args": ["-c", "conf/rtc.conf"],
|
||||||
|
"stopAtEntry": false,
|
||||||
|
"cwd": "${workspaceFolder}/trunk",
|
||||||
|
"environment": [],
|
||||||
|
"externalConsole": false,
|
||||||
|
"linux": {
|
||||||
|
"MIMode": "gdb"
|
||||||
|
},
|
||||||
|
"osx": {
|
||||||
|
"MIMode": "lldb"
|
||||||
|
},
|
||||||
|
"setupCommands": [
|
||||||
|
{
|
||||||
|
"description": "Enable pretty-printing for gdb",
|
||||||
|
"text": "-enable-pretty-printing",
|
||||||
|
"ignoreFailures": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"preLaunchTask": "build",
|
||||||
|
"logging": {
|
||||||
|
"engineLogging": true
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Launch srs-proxy",
|
"name": "Launch srs-proxy",
|
||||||
"type": "go",
|
"type": "go",
|
||||||
|
|
|
||||||
|
|
@ -7,16 +7,18 @@ The changelog for SRS.
|
||||||
<a name="v7-changes"></a>
|
<a name="v7-changes"></a>
|
||||||
|
|
||||||
## SRS 7.0 Changelog
|
## SRS 7.0 Changelog
|
||||||
|
* v7.0, 2025-10-30, WebRTC: Use realtime for TWCC timestamp accuracy. v7.0.114
|
||||||
|
* v7.0, 2025-10-30, AI: HLS: Fix crash when segment is not open by adding NULL checks. v7.0.113 (#3431)
|
||||||
* v7.0, 2025-10-29, AI: AAC: Fix mono audio reported as stereo in HTTP API. v7.0.112 (#3556)
|
* v7.0, 2025-10-29, AI: AAC: Fix mono audio reported as stereo in HTTP API. v7.0.112 (#3556)
|
||||||
* v7.0, 2025-10-27, HLS/DASH: Fix dispose to skip unpublish when not enabled, and add forbidden directory protection to SrsPath::unlink. v7.0.111
|
* v7.0, 2025-10-27, HLS/DASH: Skip unpublish if disabled; add protection in SrsPath::unlink. v7.0.111
|
||||||
* v7.0, 2025-10-27, AI: HTTP-FLV: Enforce minimum 10ms sleep to prevent CPU busy-wait when mw_latency=0. v7.0.110 (#3963)
|
* v7.0, 2025-10-27, AI: HTTP-FLV: Add 10 ms sleep to prevent busy-wait when mw_latency=0. v7.0.110 (#3963)
|
||||||
* v7.0, 2025-10-26, AI: Edge: Fix stream names with dots being incorrectly truncated in source URL generation. v7.0.109 (#4011)
|
* v7.0, 2025-10-26, AI: Edge: Fix truncation of stream names containing dots. v7.0.109 (#4011)
|
||||||
* v7.0, 2025-10-26, AI: HTTPS: Handle SSL_ERROR_ZERO_RETURN as graceful connection closure. v7.0.108 (#4036)
|
* v7.0, 2025-10-26, AI: HTTPS: Treat SSL_ERROR_ZERO_RETURN as graceful close. v7.0.108 (#4036)
|
||||||
* v7.0, 2025-10-26, AI: API: Add clients field to on_play/on_stop webhooks and total field to HTTP API. v7.0.107 (#4147)
|
* v7.0, 2025-10-26, AI: API: Add clients to webhooks and total to stats API. v7.0.107 (#4147)
|
||||||
* 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: WebRTC: Fix camera/mic not released after closing. 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: Build: 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-26, AI: HLS: Support hls_master_m3u8_path_relative for reverse proxy. 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-25, AI: API: Remove minimum count=10 limit in stream/client queries. 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: 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-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)
|
* 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)
|
||||||
|
|
|
||||||
|
|
@ -847,6 +847,11 @@ std::string SrsHlsFmp4Muxer::generate_m4s_filename()
|
||||||
return m4s_file;
|
return m4s_file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SrsHlsFmp4Muxer::is_segment_open()
|
||||||
|
{
|
||||||
|
return current_ != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
srs_error_t SrsHlsFmp4Muxer::on_sequence_header()
|
srs_error_t SrsHlsFmp4Muxer::on_sequence_header()
|
||||||
{
|
{
|
||||||
return srs_success;
|
return srs_success;
|
||||||
|
|
@ -854,7 +859,10 @@ srs_error_t SrsHlsFmp4Muxer::on_sequence_header()
|
||||||
|
|
||||||
bool SrsHlsFmp4Muxer::is_segment_overflow()
|
bool SrsHlsFmp4Muxer::is_segment_overflow()
|
||||||
{
|
{
|
||||||
srs_assert(current_);
|
// If segment is not open, it cannot overflow.
|
||||||
|
if (!is_segment_open()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// to prevent very small segment.
|
// to prevent very small segment.
|
||||||
if (current_->duration() < 2 * SRS_HLS_SEGMENT_MIN_DURATION) {
|
if (current_->duration() < 2 * SRS_HLS_SEGMENT_MIN_DURATION) {
|
||||||
|
|
@ -876,7 +884,10 @@ bool SrsHlsFmp4Muxer::wait_keyframe()
|
||||||
|
|
||||||
bool SrsHlsFmp4Muxer::is_segment_absolutely_overflow()
|
bool SrsHlsFmp4Muxer::is_segment_absolutely_overflow()
|
||||||
{
|
{
|
||||||
srs_assert(current_);
|
// If segment is not open, it cannot overflow.
|
||||||
|
if (!is_segment_open()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// to prevent very small segment.
|
// to prevent very small segment.
|
||||||
if (current_->duration() < 2 * SRS_HLS_SEGMENT_MIN_DURATION) {
|
if (current_->duration() < 2 * SRS_HLS_SEGMENT_MIN_DURATION) {
|
||||||
|
|
@ -890,6 +901,10 @@ bool SrsHlsFmp4Muxer::is_segment_absolutely_overflow()
|
||||||
|
|
||||||
void SrsHlsFmp4Muxer::update_duration(uint64_t dts)
|
void SrsHlsFmp4Muxer::update_duration(uint64_t dts)
|
||||||
{
|
{
|
||||||
|
// If segment is not open, ignore the update event.
|
||||||
|
if (!is_segment_open()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
current_->append(dts / 90);
|
current_->append(dts / 90);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1652,7 +1667,11 @@ srs_error_t SrsHlsMuxer::on_sequence_header()
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
srs_assert(current_);
|
// If segment is not open, ignore the sequence header event.
|
||||||
|
if (!is_segment_open()) {
|
||||||
|
srs_warn("sequence header ignored, for segment is not open.");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
// set the current segment to sequence header,
|
// set the current segment to sequence header,
|
||||||
// when close the segement, it will write a discontinuity to m3u8 file.
|
// when close the segement, it will write a discontinuity to m3u8 file.
|
||||||
|
|
@ -1661,9 +1680,17 @@ srs_error_t SrsHlsMuxer::on_sequence_header()
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SrsHlsMuxer::is_segment_open()
|
||||||
|
{
|
||||||
|
return current_ != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
bool SrsHlsMuxer::is_segment_overflow()
|
bool SrsHlsMuxer::is_segment_overflow()
|
||||||
{
|
{
|
||||||
srs_assert(current_);
|
// If segment is not open, it cannot overflow.
|
||||||
|
if (!is_segment_open()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// to prevent very small segment.
|
// to prevent very small segment.
|
||||||
if (current_->duration() < 2 * SRS_HLS_SEGMENT_MIN_DURATION) {
|
if (current_->duration() < 2 * SRS_HLS_SEGMENT_MIN_DURATION) {
|
||||||
|
|
@ -1685,7 +1712,10 @@ bool SrsHlsMuxer::wait_keyframe()
|
||||||
|
|
||||||
bool SrsHlsMuxer::is_segment_absolutely_overflow()
|
bool SrsHlsMuxer::is_segment_absolutely_overflow()
|
||||||
{
|
{
|
||||||
srs_assert(current_);
|
// If segment is not open, it cannot overflow.
|
||||||
|
if (!is_segment_open()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// to prevent very small segment.
|
// to prevent very small segment.
|
||||||
if (current_->duration() < 2 * SRS_HLS_SEGMENT_MIN_DURATION) {
|
if (current_->duration() < 2 * SRS_HLS_SEGMENT_MIN_DURATION) {
|
||||||
|
|
@ -1760,6 +1790,10 @@ srs_error_t SrsHlsMuxer::flush_video(SrsTsMessageCache *cache)
|
||||||
|
|
||||||
void SrsHlsMuxer::update_duration(uint64_t dts)
|
void SrsHlsMuxer::update_duration(uint64_t dts)
|
||||||
{
|
{
|
||||||
|
// If segment is not open, ignore the update event.
|
||||||
|
if (!is_segment_open()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
current_->append(dts / 90);
|
current_->append(dts / 90);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -358,6 +358,7 @@ public:
|
||||||
// clang-format off
|
// clang-format off
|
||||||
SRS_DECLARE_PRIVATE: // clang-format on
|
SRS_DECLARE_PRIVATE: // clang-format on
|
||||||
virtual std::string generate_ts_filename();
|
virtual std::string generate_ts_filename();
|
||||||
|
virtual bool is_segment_open();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual srs_error_t on_sequence_header();
|
virtual srs_error_t on_sequence_header();
|
||||||
|
|
@ -541,6 +542,7 @@ public:
|
||||||
// clang-format off
|
// clang-format off
|
||||||
SRS_DECLARE_PRIVATE: // clang-format on
|
SRS_DECLARE_PRIVATE: // clang-format on
|
||||||
virtual std::string generate_m4s_filename();
|
virtual std::string generate_m4s_filename();
|
||||||
|
virtual bool is_segment_open();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual srs_error_t on_sequence_header();
|
virtual srs_error_t on_sequence_header();
|
||||||
|
|
|
||||||
|
|
@ -1311,8 +1311,11 @@ srs_error_t SrsRtcPublishStream::initialize(ISrsRequest *r, SrsRtcSourceDescript
|
||||||
|
|
||||||
int twcc_id = -1;
|
int twcc_id = -1;
|
||||||
uint32_t media_ssrc = 0;
|
uint32_t media_ssrc = 0;
|
||||||
// because audio_track_desc have not twcc id, for example, h5demo
|
// TWCC is transport-wide, so audio and video share the same extension ID.
|
||||||
// fetch twcc_id from video track description,
|
// We fetch the TWCC ID from video track, which is sufficient because:
|
||||||
|
// 1. Standard WebRTC clients use the same TWCC ID for both audio and video.
|
||||||
|
// 2. The ID is used to parse TWCC extension from all RTP packets (audio+video).
|
||||||
|
// 3. TWCC feedback will include both audio and video packets.
|
||||||
for (int i = 0; i < (int)stream_desc->video_track_descs_.size(); ++i) {
|
for (int i = 0; i < (int)stream_desc->video_track_descs_.size(); ++i) {
|
||||||
SrsRtcTrackDescription *desc = stream_desc->video_track_descs_.at(i);
|
SrsRtcTrackDescription *desc = stream_desc->video_track_descs_.at(i);
|
||||||
twcc_id = desc->get_rtp_extension_id(kTWCCExt);
|
twcc_id = desc->get_rtp_extension_id(kTWCCExt);
|
||||||
|
|
@ -1529,7 +1532,10 @@ srs_error_t SrsRtcPublishStream::on_twcc(uint16_t sn)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
srs_utime_t now = srs_time_now_cached();
|
// To get more accurate timestamp, and avoid deviation caused by coroutine scheduler,
|
||||||
|
// we use realtime for TWCC.
|
||||||
|
srs_utime_t now = srs_time_now_realtime();
|
||||||
|
|
||||||
err = rtcp_twcc_->recv_packet(sn, now);
|
err = rtcp_twcc_->recv_packet(sn, now);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -1581,10 +1587,6 @@ srs_error_t SrsRtcPublishStream::on_rtp_plaintext(char *plaintext, int nb_plaint
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
if (_srs_blackhole->blackhole_) {
|
|
||||||
_srs_blackhole->sendto(plaintext, nb_plaintext);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate packet form cache.
|
// Allocate packet form cache.
|
||||||
SrsRtpPacket *pkt = new SrsRtpPacket();
|
SrsRtpPacket *pkt = new SrsRtpPacket();
|
||||||
|
|
||||||
|
|
@ -2663,6 +2665,10 @@ srs_error_t SrsRtcConnection::send_rtcp(char *data, int nb_data)
|
||||||
|
|
||||||
++_srs_pps_srtcps->sugar_;
|
++_srs_pps_srtcps->sugar_;
|
||||||
|
|
||||||
|
if (_srs_blackhole->blackhole_) {
|
||||||
|
_srs_blackhole->sendto(data, nb_data);
|
||||||
|
}
|
||||||
|
|
||||||
int nb_buf = nb_data;
|
int nb_buf = nb_data;
|
||||||
if ((err = networks_->available()->protect_rtcp(data, &nb_buf)) != srs_success) {
|
if ((err = networks_->available()->protect_rtcp(data, &nb_buf)) != srs_success) {
|
||||||
return srs_error_wrap(err, "protect rtcp");
|
return srs_error_wrap(err, "protect rtcp");
|
||||||
|
|
@ -2818,10 +2824,6 @@ srs_error_t SrsRtcConnection::send_rtcp_fb_pli(uint32_t ssrc, const SrsContextId
|
||||||
nn, pli_epp_->nn_count_, stream.pos());
|
nn, pli_epp_->nn_count_, stream.pos());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_srs_blackhole->blackhole_) {
|
|
||||||
_srs_blackhole->sendto(stream.data(), stream.pos());
|
|
||||||
}
|
|
||||||
|
|
||||||
return send_rtcp(stream.data(), stream.pos());
|
return send_rtcp(stream.data(), stream.pos());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1008,11 +1008,12 @@ srs_error_t SrsOriginHub::on_audio(SrsMediaPacket *shared_audio)
|
||||||
sample_rate = srs_audio_sample_rate_from_number(srs_aac_srates[c->aac_sample_rate_]);
|
sample_rate = srs_audio_sample_rate_from_number(srs_aac_srates[c->aac_sample_rate_]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For AAC, use aac_channels_ from AudioSpecificConfig instead of sound_type_ from FLV tag.
|
// The FLV specification force to be 1(stereo) for AAC codec, see E.4.2 Audio Tags,
|
||||||
// The FLV sound_type field is often incorrect for AAC streams (e.g., FFmpeg sets it to stereo
|
// video_file_format_spec_v10_1.pdf, page 77.
|
||||||
// even for mono streams). The AAC AudioSpecificConfig channelConfiguration is the authoritative
|
// If the SoundFormat indicates AAC, the SoundType should be 1 (stereo) and the
|
||||||
// source: 1=mono, 2=stereo. Map to SrsAudioChannels: 0=mono, 1=stereo.
|
// SoundRate should be 3 (44 kHz).
|
||||||
// For MP3 and other codecs, use sound_type_ from FLV tag.
|
// FFmpeg also follows this specification, that is why it always send fixed channels
|
||||||
|
// and sample rate to SRS.
|
||||||
SrsAudioChannels channels = c->sound_type_;
|
SrsAudioChannels channels = c->sound_type_;
|
||||||
if (format->acodec_->id_ == SrsAudioCodecIdAAC) {
|
if (format->acodec_->id_ == SrsAudioCodecIdAAC) {
|
||||||
channels = (c->aac_channels_ == 1) ? SrsAudioChannelsMono : SrsAudioChannelsStereo;
|
channels = (c->aac_channels_ == 1) ? SrsAudioChannelsMono : SrsAudioChannelsStereo;
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,6 @@
|
||||||
|
|
||||||
#define VERSION_MAJOR 7
|
#define VERSION_MAJOR 7
|
||||||
#define VERSION_MINOR 0
|
#define VERSION_MINOR 0
|
||||||
#define VERSION_REVISION 112
|
#define VERSION_REVISION 114
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
Loading…
Reference in New Issue
Block a user