AI: HLS: Support hls_master_m3u8_path_relative for reverse proxy compatibility. v7.0.104 (#4338)
This commit is contained in:
parent
b7828e1fba
commit
6590871ca8
17
trunk/3rdparty/srs-docs/doc/hls.md
vendored
17
trunk/3rdparty/srs-docs/doc/hls.md
vendored
|
|
@ -426,6 +426,23 @@ Then configure `hls_path` or create a soft link to the directory.
|
|||
|
||||
To deploy an HLS distribution cluster and edge distribution cluster for your own CDN to handle a large number of viewers, please refer to [Nginx for HLS](./nginx-for-hls.md).
|
||||
|
||||
## HLS with Reverse Proxy
|
||||
|
||||
When deploying SRS behind a reverse proxy with path rewriting, you may encounter issues where HLS master playlists use absolute paths (e.g., `/live/livestream.m3u8?hls_ctx=xxx`), which can break playback when the proxy rewrites request paths. For example, if the external URL is `http://proxy/srs/live/stream.m3u8` but gets rewritten to `http://origin/live/stream.m3u8`, the absolute path in the master playlist will drop the `/srs` prefix, causing a 404 error.
|
||||
|
||||
SRS (v7.0.104+) provides the `hls_master_m3u8_path_relative` option to use relative paths in master playlists for reverse proxy compatibility:
|
||||
|
||||
```bash
|
||||
vhost __defaultVhost__ {
|
||||
hls {
|
||||
enabled on;
|
||||
hls_master_m3u8_path_relative on; # Use relative path for reverse proxy
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
When enabled, the master playlist uses relative paths (e.g., `livestream.m3u8?hls_ctx=xxx`) instead of absolute paths, allowing the player to correctly resolve URLs through the reverse proxy. This is useful for deployments with Nginx, Apache, HAProxy, API gateways, or multi-tenant systems with path-based routing. The default is `off` for backward compatibility.
|
||||
|
||||
## HLS Low Latency
|
||||
|
||||
How to reduce HLS latency? The key is to reduce the number of slices and the number of TS files in the m3u8. SRS's default configuration is 10 seconds per slice and 60 seconds per m3u8, resulting in a latency of about 30 seconds. Some players start requesting slices from the middle position, so there will be a delay of 3 slices.
|
||||
|
|
|
|||
|
|
@ -1478,6 +1478,16 @@ vhost hls.srs.com {
|
|||
# Overwrite by env SRS_VHOST_HLS_HLS_TS_CTX for all vhosts.
|
||||
# Default: on
|
||||
hls_ts_ctx on;
|
||||
# Whether use relative path for media playlist URL in HLS master playlist.
|
||||
# When on, the master playlist uses relative path like "livestream.m3u8?hls_ctx=xxx".
|
||||
# When off, the master playlist uses absolute path like "/live/livestream.m3u8?hls_ctx=xxx".
|
||||
# Relative path is useful for reverse proxy scenarios with path rewriting.
|
||||
# For example, if external URL is "http://proxy/srs/live/stream.m3u8" and it's rewritten to
|
||||
# "http://origin/live/stream.m3u8", relative path ensures the player can correctly resolve
|
||||
# the media playlist URL.
|
||||
# Overwrite by env SRS_VHOST_HLS_HLS_MASTER_M3U8_PATH_RELATIVE for all vhosts.
|
||||
# Default: off
|
||||
hls_master_m3u8_path_relative off;
|
||||
|
||||
# whether using AES encryption.
|
||||
# Overwrite by env SRS_VHOST_HLS_HLS_KEYS for all vhosts.
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ The changelog for SRS.
|
|||
<a name="v7-changes"></a>
|
||||
|
||||
## SRS 7.0 Changelog
|
||||
* 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-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)
|
||||
|
|
|
|||
|
|
@ -2290,7 +2290,7 @@ srs_error_t SrsConfig::check_normal_config()
|
|||
} else if (n == "hls") {
|
||||
for (int j = 0; j < (int)conf->directives_.size(); j++) {
|
||||
string m = conf->at(j)->name_;
|
||||
if (m != "enabled" && m != "hls_entry_prefix" && m != "hls_path" && m != "hls_fragment" && m != "hls_window" && m != "hls_on_error" && m != "hls_storage" && m != "hls_mount" && m != "hls_td_ratio" && m != "hls_aof_ratio" && m != "hls_acodec" && m != "hls_vcodec" && m != "hls_m3u8_file" && m != "hls_ts_file" && m != "hls_ts_floor" && m != "hls_cleanup" && m != "hls_nb_notify" && m != "hls_wait_keyframe" && m != "hls_dispose" && m != "hls_keys" && m != "hls_fragments_per_key" && m != "hls_key_file" && m != "hls_key_file_path" && m != "hls_key_url" && m != "hls_dts_directly" && m != "hls_ctx" && m != "hls_ts_ctx" && m != "hls_use_fmp4" && m != "hls_fmp4_file" && m != "hls_init_file" && m != "hls_recover") {
|
||||
if (m != "enabled" && m != "hls_entry_prefix" && m != "hls_path" && m != "hls_fragment" && m != "hls_window" && m != "hls_on_error" && m != "hls_storage" && m != "hls_mount" && m != "hls_td_ratio" && m != "hls_aof_ratio" && m != "hls_acodec" && m != "hls_vcodec" && m != "hls_m3u8_file" && m != "hls_ts_file" && m != "hls_ts_floor" && m != "hls_cleanup" && m != "hls_nb_notify" && m != "hls_wait_keyframe" && m != "hls_dispose" && m != "hls_keys" && m != "hls_fragments_per_key" && m != "hls_key_file" && m != "hls_key_file_path" && m != "hls_key_url" && m != "hls_dts_directly" && m != "hls_ctx" && m != "hls_ts_ctx" && m != "hls_use_fmp4" && m != "hls_fmp4_file" && m != "hls_init_file" && m != "hls_recover" && m != "hls_master_m3u8_path_relative") {
|
||||
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal vhost.hls.%s of %s", m.c_str(), vhost->arg0().c_str());
|
||||
}
|
||||
|
||||
|
|
@ -6692,6 +6692,25 @@ string SrsConfig::get_hls_key_url(std::string vhost)
|
|||
return conf->arg0();
|
||||
}
|
||||
|
||||
bool SrsConfig::get_hls_master_m3u8_path_relative(string vhost)
|
||||
{
|
||||
SRS_OVERWRITE_BY_ENV_BOOL("srs.vhost.hls.hls_master_m3u8_path_relative"); // SRS_VHOST_HLS_HLS_MASTER_M3U8_PATH_RELATIVE
|
||||
|
||||
static bool DEFAULT = false;
|
||||
|
||||
SrsConfDirective *conf = get_hls(vhost);
|
||||
if (!conf) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
conf = conf->get("hls_master_m3u8_path_relative");
|
||||
if (!conf || conf->arg0().empty()) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
return SRS_CONF_PREFER_FALSE(conf->arg0());
|
||||
}
|
||||
|
||||
bool SrsConfig::get_hls_recover(string vhost)
|
||||
{
|
||||
SRS_OVERWRITE_BY_ENV_BOOL2("srs.vhost.hls.hls_recover"); // SRS_VHOST_HLS_HLS_RECOVER
|
||||
|
|
|
|||
|
|
@ -519,6 +519,7 @@ public:
|
|||
virtual bool get_vhost_hls_dts_directly(std::string vhost) = 0;
|
||||
virtual bool get_hls_ctx_enabled(std::string vhost) = 0;
|
||||
virtual bool get_hls_ts_ctx_enabled(std::string vhost) = 0;
|
||||
virtual bool get_hls_master_m3u8_path_relative(std::string vhost) = 0;
|
||||
virtual bool get_hls_recover(std::string vhost) = 0;
|
||||
virtual bool get_dash_enabled(std::string vhost) = 0;
|
||||
virtual bool get_dash_enabled(SrsConfDirective *vhost) = 0;
|
||||
|
|
@ -1366,6 +1367,11 @@ public:
|
|||
// Whether enable session for ts file.
|
||||
// The ts file including .ts file for MPEG-ts segment, .m4s file and init.mp4 file for fmp4 segment.
|
||||
virtual bool get_hls_ts_ctx_enabled(std::string vhost);
|
||||
// Whether use relative path for media playlist URL in HLS master playlist.
|
||||
// When on, uses relative path (e.g., "livestream.m3u8?hls_ctx=xxx").
|
||||
// When off, uses absolute path (e.g., "/live/livestream.m3u8?hls_ctx=xxx").
|
||||
// Default is off for backward compatibility.
|
||||
virtual bool get_hls_master_m3u8_path_relative(std::string vhost);
|
||||
// Toggles HLS recover mode.
|
||||
// In this mode HLS sequence number is started from where it stopped last time.
|
||||
// Old fragments are kept. Default is on.
|
||||
|
|
|
|||
|
|
@ -178,10 +178,21 @@ srs_error_t SrsHlsStream::serve_new_session(ISrsHttpResponseWriter *w, ISrsHttpM
|
|||
return srs_error_wrap(err, "HLS: http_hooks_on_play");
|
||||
}
|
||||
|
||||
// Determine the media playlist URL path in master playlist based on configuration.
|
||||
// When hls_master_m3u8_path_relative is on, use relative path (just filename) for better
|
||||
// compatibility with reverse proxies that do path rewriting.
|
||||
// For example, convert "/live/livestream.m3u8" to "livestream.m3u8"
|
||||
// When off (default), use absolute path for backward compatibility.
|
||||
std::string media_playlist_url = hr->path();
|
||||
if (_srs_config->get_hls_master_m3u8_path_relative(req->vhost_)) {
|
||||
SrsPath path;
|
||||
media_playlist_url = path.filepath_base(hr->path());
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "#EXTM3U" << SRS_CONSTS_LF;
|
||||
ss << "#EXT-X-STREAM-INF:BANDWIDTH=1,AVERAGE-BANDWIDTH=1" << SRS_CONSTS_LF;
|
||||
ss << hr->path() << "?" << SRS_CONTEXT_IN_HLS << "=" << ctx;
|
||||
ss << media_playlist_url << "?" << SRS_CONTEXT_IN_HLS << "=" << ctx;
|
||||
if (!hr->query().empty() && hr->query_get(SRS_CONTEXT_IN_HLS).empty()) {
|
||||
ss << "&" << hr->query();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,6 @@
|
|||
|
||||
#define VERSION_MAJOR 7
|
||||
#define VERSION_MINOR 0
|
||||
#define VERSION_REVISION 103
|
||||
#define VERSION_REVISION 104
|
||||
|
||||
#endif
|
||||
|
|
@ -842,6 +842,11 @@ bool MockAppConfig::get_hls_ts_ctx_enabled(std::string vhost)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool MockAppConfig::get_hls_master_m3u8_path_relative(std::string vhost)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MockAppConfig::get_hls_recover(std::string vhost)
|
||||
{
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -456,6 +456,7 @@ public:
|
|||
virtual bool get_vhost_hls_dts_directly(std::string vhost);
|
||||
virtual bool get_hls_ctx_enabled(std::string vhost);
|
||||
virtual bool get_hls_ts_ctx_enabled(std::string vhost);
|
||||
virtual bool get_hls_master_m3u8_path_relative(std::string vhost);
|
||||
virtual bool get_hls_recover(std::string vhost);
|
||||
virtual bool get_forward_enabled(std::string vhost);
|
||||
virtual SrsConfDirective *get_forwards(std::string vhost);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user