Skip to content

Commit 3335830

Browse files
winlinvipduiniuluantanqinchundonglinlin
committed
HLS: Support reload HLS asynchronously. v5.0.172 (ossrs#3782)
When reloading HLS, it directly operates unpublish and publish. At this time, if HLS is pushed, an exception may occur. The reason is that these two coroutines operated on the HLS object at the same time, causing a null pointer. Solution: Use asynchronous reload. During reload, only set variables and let the message processing coroutine implement the reload. --------- Co-authored-by: Haibo Chen <495810242@qq.com> Co-authored-by: chundonglinlin <chundonglinlin@163.com>
1 parent 1730fc9 commit 3335830

6 files changed

+110
-60
lines changed

trunk/doc/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ The changelog for SRS.
77
<a name="v5-changes"></a>
88

99
## SRS 5.0 Changelog
10+
* v5.0, 2023-08-25, Merge [#3782](https://github.com/ossrs/srs/pull/3782): HLS: Support reload HLS asynchronously. v5.0.172 (#3782)
1011
* v5.0, 2023-08-22, Merge [#3775](https://github.com/ossrs/srs/pull/3775): Bugfix: Log format output type does not match. v5.0.171 (#3699)
1112
* v5.0, 2023-08-02, HLS: Ignore empty NALU to avoid error. v5.0.170
1213
* v5.0, 2023-07-26, Merge [#3699](https://github.com/ossrs/srs/pull/3699): Bugfix: Eliminate the redundant declaration of the _srs_rtc_manager variable. v5.0.168 (#3699)

trunk/src/app/srs_app_hls.cpp

+61-9
Original file line numberDiff line numberDiff line change
@@ -1106,6 +1106,7 @@ SrsHls::SrsHls()
11061106

11071107
enabled = false;
11081108
disposable = false;
1109+
async_reload_ = reloading_ = false;
11091110
last_update_time = 0;
11101111
hls_dts_directly = false;
11111112

@@ -1125,6 +1126,53 @@ SrsHls::~SrsHls()
11251126
srs_freep(pprint);
11261127
}
11271128

1129+
void SrsHls::async_reload()
1130+
{
1131+
async_reload_ = true;
1132+
}
1133+
1134+
srs_error_t SrsHls::reload()
1135+
{
1136+
srs_error_t err = srs_success;
1137+
1138+
// Ignore if not active.
1139+
if (!enabled) return err;
1140+
1141+
int reloading = 0, reloaded = 0, refreshed = 0;
1142+
err = do_reload(&reloading, &reloaded, &refreshed);
1143+
srs_trace("async reload hls %s, reloading=%d, reloaded=%d, refreshed=%d",
1144+
req->get_stream_url().c_str(), reloading, reloaded, refreshed);
1145+
1146+
return err;
1147+
}
1148+
1149+
srs_error_t SrsHls::do_reload(int *reloading, int *reloaded, int *refreshed)
1150+
{
1151+
srs_error_t err = srs_success;
1152+
1153+
if (!async_reload_ || reloading_) return err;
1154+
reloading_ = true;
1155+
*reloading = 1;
1156+
1157+
on_unpublish();
1158+
if ((err = on_publish()) != srs_success) {
1159+
return srs_error_wrap(err, "hls publish failed");
1160+
}
1161+
*reloaded = 1;
1162+
1163+
// Before feed the sequence header, must reset the reloading.
1164+
reloading_ = false;
1165+
async_reload_ = false;
1166+
1167+
// After reloading, we must request the sequence header again.
1168+
if ((err = hub->on_hls_request_sh()) != srs_success) {
1169+
return srs_error_wrap(err, "hls request sh");
1170+
}
1171+
*refreshed = 1;
1172+
1173+
return err;
1174+
}
1175+
11281176
void SrsHls::dispose()
11291177
{
11301178
if (enabled) {
@@ -1152,7 +1200,11 @@ srs_error_t SrsHls::cycle()
11521200
if (!req) {
11531201
return err;
11541202
}
1155-
1203+
1204+
// When reloading, we must wait for it done.
1205+
if (async_reload_) return err;
1206+
1207+
// If not unpublishing and not reloading, try to dispose HLS stream.
11561208
srs_utime_t hls_dispose = _srs_config->get_hls_dispose(req->vhost);
11571209
if (hls_dispose <= 0) {
11581210
return err;
@@ -1240,10 +1292,10 @@ void SrsHls::on_unpublish()
12401292
srs_error_t SrsHls::on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* format)
12411293
{
12421294
srs_error_t err = srs_success;
1243-
1244-
if (!enabled) {
1245-
return err;
1246-
}
1295+
1296+
// If not able to transmux to HLS, ignore.
1297+
if (!enabled) return err;
1298+
if (async_reload_) return reload();
12471299

12481300
// Ignore if no format->acodec, it means the codec is not parsed, or unknown codec.
12491301
// @issue https://github.com/ossrs/srs/issues/1506#issuecomment-562079474
@@ -1322,10 +1374,10 @@ srs_error_t SrsHls::on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* forma
13221374
srs_error_t SrsHls::on_video(SrsSharedPtrMessage* shared_video, SrsFormat* format)
13231375
{
13241376
srs_error_t err = srs_success;
1325-
1326-
if (!enabled) {
1327-
return err;
1328-
}
1377+
1378+
// If not able to transmux to HLS, ignore.
1379+
if (!enabled) return err;
1380+
if (async_reload_) return reload();
13291381

13301382
// Ignore if no format->vcodec, it means the codec is not parsed, or unknown codec.
13311383
// @issue https://github.com/ossrs/srs/issues/1506#issuecomment-562079474

trunk/src/app/srs_app_hls.hpp

+11
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,14 @@ class SrsHls
271271
SrsHlsController* controller;
272272
private:
273273
SrsRequest* req;
274+
// Whether the HLS is enabled.
274275
bool enabled;
276+
// Whether the HLS stream is able to be disposed.
275277
bool disposable;
278+
// Whether requires HLS to do reload asynchronously.
279+
bool async_reload_;
280+
bool reloading_;
281+
// To detect heartbeat and dipose it if configured.
276282
srs_utime_t last_update_time;
277283
private:
278284
// If the diff=dts-previous_audio_dts is about 23,
@@ -289,6 +295,11 @@ class SrsHls
289295
public:
290296
SrsHls();
291297
virtual ~SrsHls();
298+
public:
299+
virtual void async_reload();
300+
private:
301+
srs_error_t reload();
302+
srs_error_t do_reload(int *reloading, int *reloaded, int *refreshed);
292303
public:
293304
virtual void dispose();
294305
virtual srs_error_t cycle();

trunk/src/app/srs_app_source.cpp

+34-50
Original file line numberDiff line numberDiff line change
@@ -1217,6 +1217,27 @@ srs_error_t SrsOriginHub::on_dvr_request_sh()
12171217
return err;
12181218
}
12191219

1220+
srs_error_t SrsOriginHub::on_hls_request_sh()
1221+
{
1222+
srs_error_t err = srs_success;
1223+
1224+
SrsSharedPtrMessage* cache_sh_video = source->meta->vsh();
1225+
if (cache_sh_video) {
1226+
if ((err = hls->on_video(cache_sh_video, source->meta->vsh_format())) != srs_success) {
1227+
return srs_error_wrap(err, "hls video");
1228+
}
1229+
}
1230+
1231+
SrsSharedPtrMessage* cache_sh_audio = source->meta->ash();
1232+
if (cache_sh_audio) {
1233+
if ((err = hls->on_audio(cache_sh_audio, source->meta->ash_format())) != srs_success) {
1234+
return srs_error_wrap(err, "hls audio");
1235+
}
1236+
}
1237+
1238+
return err;
1239+
}
1240+
12201241
srs_error_t SrsOriginHub::on_reload_vhost_forward(string vhost)
12211242
{
12221243
srs_error_t err = srs_success;
@@ -1225,7 +1246,7 @@ srs_error_t SrsOriginHub::on_reload_vhost_forward(string vhost)
12251246
return err;
12261247
}
12271248

1228-
// TODO: FIXME: maybe should ignore when publish already stopped?
1249+
// TODO: FIXME: Must do async reload, see SrsHls::async_reload.
12291250

12301251
// forwarders
12311252
destroy_forwarders();
@@ -1251,7 +1272,9 @@ srs_error_t SrsOriginHub::on_reload_vhost_dash(string vhost)
12511272
if (req_->vhost != vhost) {
12521273
return err;
12531274
}
1254-
1275+
1276+
// TODO: FIXME: Must do async reload, see SrsHls::async_reload.
1277+
12551278
dash->on_unpublish();
12561279

12571280
// Don't start DASH when source is not active.
@@ -1295,47 +1318,8 @@ srs_error_t SrsOriginHub::on_reload_vhost_hls(string vhost)
12951318
if (req_->vhost != vhost) {
12961319
return err;
12971320
}
1298-
1299-
// TODO: FIXME: maybe should ignore when publish already stopped?
1300-
1301-
hls->on_unpublish();
1302-
1303-
// Don't start HLS when source is not active.
1304-
if (!is_active) {
1305-
return err;
1306-
}
1307-
1308-
if ((err = hls->on_publish()) != srs_success) {
1309-
return srs_error_wrap(err, "hls publish failed");
1310-
}
1311-
srs_trace("vhost %s hls reload success", vhost.c_str());
13121321

1313-
SrsRtmpFormat* format = source->format_;
1314-
1315-
// when publish, don't need to fetch sequence header, which is old and maybe corrupt.
1316-
// when reload, we must fetch the sequence header from source cache.
1317-
// notice the source to get the cached sequence header.
1318-
// when reload to start hls, hls will never get the sequence header in stream,
1319-
// use the SrsLiveSource.on_hls_start to push the sequence header to HLS.
1320-
SrsSharedPtrMessage* cache_sh_video = source->meta->vsh();
1321-
if (cache_sh_video) {
1322-
if ((err = format->on_video(cache_sh_video)) != srs_success) {
1323-
return srs_error_wrap(err, "format on_video");
1324-
}
1325-
if ((err = hls->on_video(cache_sh_video, format)) != srs_success) {
1326-
return srs_error_wrap(err, "hls on_video");
1327-
}
1328-
}
1329-
1330-
SrsSharedPtrMessage* cache_sh_audio = source->meta->ash();
1331-
if (cache_sh_audio) {
1332-
if ((err = format->on_audio(cache_sh_audio)) != srs_success) {
1333-
return srs_error_wrap(err, "format on_audio");
1334-
}
1335-
if ((err = hls->on_audio(cache_sh_audio, format)) != srs_success) {
1336-
return srs_error_wrap(err, "hls on_audio");
1337-
}
1338-
}
1322+
hls->async_reload();
13391323

13401324
return err;
13411325
}
@@ -1347,8 +1331,8 @@ srs_error_t SrsOriginHub::on_reload_vhost_hds(string vhost)
13471331
if (req_->vhost != vhost) {
13481332
return err;
13491333
}
1350-
1351-
// TODO: FIXME: maybe should ignore when publish already stopped?
1334+
1335+
// TODO: FIXME: Must do async reload, see SrsHls::async_reload.
13521336

13531337
#ifdef SRS_HDS
13541338
hds->on_unpublish();
@@ -1374,8 +1358,8 @@ srs_error_t SrsOriginHub::on_reload_vhost_dvr(string vhost)
13741358
if (req_->vhost != vhost) {
13751359
return err;
13761360
}
1377-
1378-
// TODO: FIXME: maybe should ignore when publish already stopped?
1361+
1362+
// TODO: FIXME: Must do async reload, see SrsHls::async_reload.
13791363

13801364
// cleanup dvr
13811365
dvr->on_unpublish();
@@ -1411,8 +1395,8 @@ srs_error_t SrsOriginHub::on_reload_vhost_transcode(string vhost)
14111395
if (req_->vhost != vhost) {
14121396
return err;
14131397
}
1414-
1415-
// TODO: FIXME: maybe should ignore when publish already stopped?
1398+
1399+
// TODO: FIXME: Must do async reload, see SrsHls::async_reload.
14161400

14171401
encoder->on_unpublish();
14181402

@@ -1436,8 +1420,8 @@ srs_error_t SrsOriginHub::on_reload_vhost_exec(string vhost)
14361420
if (req_->vhost != vhost) {
14371421
return err;
14381422
}
1439-
1440-
// TODO: FIXME: maybe should ignore when publish already stopped?
1423+
1424+
// TODO: FIXME: Must do async reload, see SrsHls::async_reload.
14411425

14421426
ng_exec->on_unpublish();
14431427

trunk/src/app/srs_app_source.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,8 @@ class SrsOriginHub : public ISrsReloadHandler
367367
virtual srs_error_t on_forwarder_start(SrsForwarder* forwarder);
368368
// For the SrsDvr to callback to request the sequence headers.
369369
virtual srs_error_t on_dvr_request_sh();
370+
// For the SrsHls to callback to request the sequence headers.
371+
virtual srs_error_t on_hls_request_sh();
370372
// Interface ISrsReloadHandler
371373
public:
372374
virtual srs_error_t on_reload_vhost_forward(std::string vhost);

trunk/src/core/srs_core_version5.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@
99

1010
#define VERSION_MAJOR 5
1111
#define VERSION_MINOR 0
12-
#define VERSION_REVISION 171
12+
#define VERSION_REVISION 172
1313

1414
#endif

0 commit comments

Comments
 (0)