Apple has introduced Low Latency HLS spec back in 2019 and has officially released the final version of the spec in the fall of 2020, along with making the playback available on iOS and Mac.
Nimble Streamer now has full support for Apple LL HLS in addition to "legacy" RFC8216 HLS. You can read about major advantages on LL HLS digest page. This article describes the setup process of Nimble Streamer.
We assume you already have Nimble Streamer installed on one of your servers,or upgraded to the latest version and you have full access there.
You watch a short version of this article in our video tutorial below.
However we highly recommend reading this article to use this feature efficiently.
LL HLS uses HTTP/2 via SSL as a transport protocol. So you need to enable it before performing any further setup.
1. HTTP/2 setup
1.1 First, install the latest Nimble Streamer or upgrade your existing instance.
1.2 Now set up the SSL certificate for Nimble Streamer. This is an important steps so please make sure SSL is working before moving forward.
LiteSpeed HPACK library: Nimble Streamer uses LS-HPACK library for encoding and decoding HTTP headers using HPACK compression mechanism. Softvelum team would like to say thank you to LiteSpeed team, we appreciate their effort and technical expertise.
Dec 24 17:43:09 nimble[5500]: [nimble-access.log] 192.18.1.2 - - "GET /livell/stream/playlist.m3u8 HTTP/2" 200 84 1114 372 "-" "AppleCoreMedia/1.0.0.17C54 (iPhone; U; CPU OS 13_3 like Mac OS X; en_us)"You can see HTTP/2 there which means it's working. In other cases it will have HTTP/1.1 and this will mean you need to check what's wrong.
2. Live streaming setup
Please make sure you have a correctly set up live stream (like regular-latency HLS, RTMP or SLDP) before trying to use LL HLS.
Once you have a live stream set up in WMSPanel, go to Nimble Streamer top menu and select Live streams settings. You will see Global setting tab for selected server. You may create application-specific setting as well if it's needed for your streaming scenario.
- HLS - this type is recommended for audio-only LL streams. It's optimized for audio delivery and it has a reduced chunk size. This allows significantly saving bandwidth for audio streams. The ID3 tags are also inserted in each audio part.
- fMP4 (CMAF) - fragmented MP4 for video+audio, audio-only and video-only modes. We highly recommend using this type of container for video+audio and video-only cases as it allows utilizing all advantages of LL HLS.
- HLS (MPEGTS) - this type supports both video+audio, audio-only and video-only modes, however we do not recommend it for LL HLS. It brings a lot overhead which diminishes all advantages and increases the latency. Also it does not support HEVC unlike fMP4. We've added this type support as a fix for a bug of iOS 12 which implemented previous LL HLS spec. So even though you can use it with LL, Apple does not recommend using it and Nimble Streamer team does not as well.
- We recommend using part duration of 2000ms with chunk duration of 6 seconds. The expected latency will be about 6 seconds in this case. This duration provides optimal bandwidth and latency as well as good playback buffer.
- The minimum recommended part duration of 1000ms. The expected latency will be about 4-5 seconds in this case. This duration gives better latency but less playback buffer and more bandwidth consumption as well as server resources' usage.
- The smallest duration value allowed by the web UI is 500 ms because it's the minimum that makes sense in terms of low latency delivery. The latency will be around 2 seconds in this case. This duration gives very low playback buffer, severe bandwidth consumption and server resources' usage. Use it only if you have a managed network and latency is crucial for your case.
- Part size smaller than 500ms does not make any practical sense because of the overhead in delivery and processing chain. Even though Nimble is able to produce smaller parts, we just don't want our customers to deal with potential bottlenecks in other areas.
- You may align key frame interval with chunk size. E.g. for 6 seconds chunk and 1000ms part duration the valid key frame intervals would be 1, 2, 3 seconds. For same chunk size and part duration of 2000, the valid key frame intervals will be 1, 2, 3, 6 seconds.
- Key frame interval can be set on your encoder side. Nimble Live Transcoder allows setting it as well.
Once LL HLS is enabled, you need to re-start the input stream so Nimble Streamer could start producing LL HLS output stream.
3. Workflow and playlists
Now as the set up has been made, you can use the player to consume the stream using the usual playback URL. The main playlist will have proper chunklists which will have a content according to LL-HLS spec. Here is an example of such chunk list (obtained via video.m3u8).
#EXTM3U
#EXT-X-VERSION:7
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-MAP:URI="audio.fmp4?nimblesessionid=1"
#EXT-X-TARGETDURATION:7
#EXT-X-MEDIA-SEQUENCE:1
#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES,PART-HOLD-BACK=1.536
#EXT-X-PART-INF:PART-TARGET=0.512
#EXT-X-PROGRAM-DATE-TIME:2019-12-23T02:29:02.609Z
#EXTINF:5.995,
a_6_6016_1.fmp4?nimblesessionid=1
#EXT-X-PART:DURATION=0.512,URI="a_6_12011_2_0.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_12011_2_1.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_12011_2_2.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_12011_2_3.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_12011_2_4.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_12011_2_5.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_12011_2_6.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_12011_2_7.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_12011_2_8.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_12011_2_9.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_12011_2_10.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.363,URI="a_6_12011_2_11.fmp4?nimblesessionid=1"
#EXT-X-PROGRAM-DATE-TIME:2019-12-23T02:29:08.604Z
#EXTINF:5.995,
a_6_12011_2.fmp4?nimblesessionid=1
#EXT-X-PART:DURATION=0.512,URI="a_6_18006_3_0.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_18006_3_1.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_18006_3_2.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_18006_3_3.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_18006_3_4.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_18006_3_5.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_18006_3_6.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_18006_3_7.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_18006_3_8.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_18006_3_9.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_18006_3_10.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.362,URI="a_6_18006_3_11.fmp4?nimblesessionid=1"
#EXT-X-PROGRAM-DATE-TIME:2019-12-23T02:29:14.599Z
#EXTINF:5.994,
a_6_18006_3.fmp4?nimblesessionid=1
#EXT-X-PART:DURATION=0.512,URI="a_6_24000_4_0.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_24000_4_1.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_24000_4_2.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_24000_4_3.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_24000_4_4.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_24000_4_5.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_24000_4_6.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_24000_4_7.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_24000_4_8.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_24000_4_9.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_24000_4_10.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.384,URI="a_6_24000_4_11.fmp4?nimblesessionid=1"
#EXT-X-PROGRAM-DATE-TIME:2019-12-23T02:29:20.593Z
#EXTINF:6.016,
a_6_24000_4.fmp4?nimblesessionid=1
#EXT-X-PRELOAD-HINT:TYPE=PART,URI="a_6_30000_5_0.fmp4?nimblesessionid=1"
Parts in chunklist. Comparing to regular HLS, you see a lot of lines representing parts like this:
#EXT-X-PART:DURATION=0.512,URI="a_6_24000_4_0.fmp4?nimblesessionid=1"The full chunk which contain these parts will be described after all parts' lines:
a_6_24000_4.fmp4?nimblesessionid=1All parts within chunks are numerated starting from zero. So "a_6_18006_3_0.fmp4" mean its the first part of chunk number 3.
Part length. This attribute declares a designated size of upcoming parts:
#EXT-X-PART-INF:PART-TARGET=0.512
Can block reload. Check this line:
#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES,PART-HOLD-BACK=1.536The "CAN-BLOCK-RELOAD" declares that media server allows holding playlist request.
Hold playlist request. LL-HLS allows requesting the server to hold sending out the playlist until a specific chunk and/or part is available for the stream.
So a player may request some part which is going to be available within a few seconds from now, then Nimble Streamer will check if that part is available. Once the requested part is ready, Nimble will return a playlist.
Check this request example:
curl -k "https://localhost:8443/livell/stream/chunks.m3u8?nimblesessionid=1&_HLS_msn=59&_HLS_part=5"The highlighted _HLS_msn=59 and _HLS_part=5 parameters indicate that the server must hold the request until Nimble Streamer has part number 5 of chunk number 59 or later and then it could return a playlist. You can use only _HLS_msn=59 parameter, in this case the playlist will be sent out only once full chunk is available.
The resulting chunklist will look like this:
#EXTM3U
#EXT-X-VERSION:7
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-MAP:URI="audio.fmp4?nimblesessionid=1"
#EXT-X-TARGETDURATION:7
#EXT-X-MEDIA-SEQUENCE:55
#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES,PART-HOLD-BACK=1.536
#EXT-X-PART-INF:PART-TARGET=0.512
#EXT-X-PROGRAM-DATE-TIME:2019-12-23T02:34:26.599Z
#EXTINF:5.994,
a_6_330006_55.fmp4?nimblesessionid=1
#EXT-X-PROGRAM-DATE-TIME:2019-12-23T02:34:32.593Z
#EXTINF:6.016,
a_6_336000_56.fmp4?nimblesessionid=1
#EXT-X-PART:DURATION=0.512,URI="a_6_342016_57_0.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_342016_57_1.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_342016_57_2.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_342016_57_3.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_342016_57_4.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_342016_57_5.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_342016_57_6.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_342016_57_7.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_342016_57_8.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_342016_57_9.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_342016_57_10.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.363,URI="a_6_342016_57_11.fmp4?nimblesessionid=1"
#EXT-X-PROGRAM-DATE-TIME:2019-12-23T02:34:38.609Z
#EXTINF:5.995,
a_6_342016_57.fmp4?nimblesessionid=1
#EXT-X-PART:DURATION=0.512,URI="a_6_348011_58_0.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_348011_58_1.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_348011_58_2.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_348011_58_3.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_348011_58_4.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_348011_58_5.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_348011_58_6.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_348011_58_7.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_348011_58_8.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_348011_58_9.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_348011_58_10.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.363,URI="a_6_348011_58_11.fmp4?nimblesessionid=1"
#EXT-X-PROGRAM-DATE-TIME:2019-12-23T02:34:44.604Z
#EXTINF:5.995,
a_6_348011_58.fmp4?nimblesessionid=1
#EXT-X-PART:DURATION=0.512,URI="a_6_354006_59_0.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_354006_59_1.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_354006_59_2.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_354006_59_3.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_354006_59_4.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_354006_59_5.fmp4?nimblesessionid=1"
#EXT-X-PRELOAD-HINT:TYPE=PART,URI="a_6_354006_59_6.fmp4?nimblesessionid=1"
#EXT-X-PRELOAD-HINT:TYPE=PART,URI="a_6_354006_59_6.fmp4?nimblesessionid=1"
4. Playback
Low Latency HLS is now supported in all Apple devices that are capable of HLS playback. So you can use an iPhone with iOS 14 to play this HLS even in your browser. We also have support for LL HLS in Larix Player for iOS which uses platform playback component.
5. Known issues and troubleshooting
#EXTM3U#EXT-X-VERSION:7#EXT-X-INDEPENDENT-SEGMENTS#EXT-X-MAP:URI="video.fmp4?nimblesessionid=249"#EXT-X-TARGETDURATION:6#EXT-X-MEDIA-SEQUENCE:1296#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES,PART-HOLD-BACK=3#EXT-X-PART-INF:PART-TARGET=1#EXT-X-PROGRAM-DATE-TIME:2020-12-14T01:39:14.406Z#EXTINF:6,v_80_7777992_1296.fmp4?nimblesessionid=249#EXT-X-PROGRAM-DATE-TIME:2020-12-14T01:39:20.406Z#EXTINF:6,v_80_7783992_1297.fmp4?nimblesessionid=249#EXT-X-PROGRAM-DATE-TIME:2020-12-14T01:39:26.406Z#EXTINF:6,v_80_7789992_1298.fmp4?nimblesessionid=249#EXT-X-PROGRAM-DATE-TIME:2020-12-14T01:39:32.406Z#EXTINF:6,v_80_7795992_1299.fmp4?nimblesessionid=249#EXT-X-PART:DURATION=1,URI="v_80_7801992_1300_0.fmp4?nimblesessionid=249",INDEPENDENT=YES#EXT-X-PART:DURATION=1,URI="v_80_7801992_1300_1.fmp4?nimblesessionid=249"#EXT-X-PART:DURATION=1,URI="v_80_7801992_1300_2.fmp4?nimblesessionid=249"#EXT-X-PART:DURATION=1,URI="v_80_7801992_1300_3.fmp4?nimblesessionid=249",INDEPENDENT=YES#EXT-X-PART:DURATION=1,URI="v_80_7801992_1300_4.fmp4?nimblesessionid=249"#EXT-X-PART:DURATION=1,URI="v_80_7801992_1300_5.fmp4?nimblesessionid=249"#EXT-X-PROGRAM-DATE-TIME:2020-12-14T01:39:38.406Z#EXTINF:6,v_80_7801992_1300.fmp4?nimblesessionid=249#EXT-X-PART:DURATION=1,URI="v_80_7807992_1301_0.fmp4?nimblesessionid=249",INDEPENDENT=YES#EXT-X-PART:DURATION=1,URI="v_80_7807992_1301_1.fmp4?nimblesessionid=249"#EXT-X-PART:DURATION=1,URI="v_80_7807992_1301_2.fmp4?nimblesessionid=249"#EXT-X-PART:DURATION=1,URI="v_80_7807992_1301_3.fmp4?nimblesessionid=249",INDEPENDENT=YES#EXT-X-PART:DURATION=1,URI="v_80_7807992_1301_4.fmp4?nimblesessionid=249"#EXT-X-PART:DURATION=1,URI="v_80_7807992_1301_5.fmp4?nimblesessionid=249"#EXT-X-PROGRAM-DATE-TIME:2020-12-14T01:39:44.406Z#EXTINF:6,v_80_7807992_1301.fmp4?nimblesessionid=249#EXT-X-PART:DURATION=1,URI="v_80_7813992_1302_0.fmp4?nimblesessionid=249",INDEPENDENT=YES#EXT-X-PRELOAD-HINT:TYPE=PART,URI="v_80_7813992_1302_1.fmp4?nimblesessionid=249"
#EXTM3U#EXT-X-VERSION:7#EXT-X-INDEPENDENT-SEGMENTS#EXT-X-MAP:URI="video.fmp4?nimblesessionid=57"#EXT-X-TARGETDURATION:11#EXT-X-MEDIA-SEQUENCE:9873#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES,PART-HOLD-BACK=3.003#EXT-X-PART-INF:PART-TARGET=1.001#EXT-X-PROGRAM-DATE-TIME:2020-12-14T01:28:36.050Z#EXTINF:5.338,v_26_60085735_9873.fmp4?nimblesessionid=57#EXT-X-PART:DURATION=1.001,URI="v_26_60091073_9874_0.fmp4?nimblesessionid=57",INDEPENDENT=YES#EXT-X-PART:DURATION=1.001,URI="v_26_60091073_9874_1.fmp4?nimblesessionid=57"#EXT-X-PART:DURATION=1.001,URI="v_26_60091073_9874_2.fmp4?nimblesessionid=57"#EXT-X-PART:DURATION=1.001,URI="v_26_60091073_9874_3.fmp4?nimblesessionid=57"#EXT-X-PART:DURATION=0.333,URI="v_26_60091073_9874_4.fmp4?nimblesessionid=57"#EXT-X-PROGRAM-DATE-TIME:2020-12-14T01:28:41.223Z#EXTINF:4.338,v_26_60091073_9874.fmp4?nimblesessionid=57#EXT-X-PART:DURATION=1.001,URI="v_26_60095411_9875_0.fmp4?nimblesessionid=57",INDEPENDENT=YES#EXT-X-PART:DURATION=1.001,URI="v_26_60095411_9875_1.fmp4?nimblesessionid=57"#EXT-X-PART:DURATION=1.001,URI="v_26_60095411_9875_2.fmp4?nimblesessionid=57"#EXT-X-PART:DURATION=1.001,URI="v_26_60095411_9875_3.fmp4?nimblesessionid=57"#EXT-X-PART:DURATION=1.001,URI="v_26_60095411_9875_4.fmp4?nimblesessionid=57"#EXT-X-PROGRAM-DATE-TIME:2020-12-14T01:28:45.740Z#EXTINF:5.005,v_26_60095411_9875.fmp4?nimblesessionid=57#EXT-X-PART:DURATION=1.001,URI="v_26_60100416_9876_0.fmp4?nimblesessionid=57",INDEPENDENT=YES#EXT-X-PART:DURATION=1.001,URI="v_26_60100416_9876_1.fmp4?nimblesessionid=57"#EXT-X-PART:DURATION=1.001,URI="v_26_60100416_9876_2.fmp4?nimblesessionid=57"#EXT-X-PART:DURATION=1.001,URI="v_26_60100416_9876_3.fmp4?nimblesessionid=57"#EXT-X-PART:DURATION=1.001,URI="v_26_60100416_9876_4.fmp4?nimblesessionid=57"#EXT-X-PART:DURATION=1.001,URI="v_26_60100416_9876_5.fmp4?nimblesessionid=57"#EXT-X-PART:DURATION=1.001,URI="v_26_60100416_9876_6.fmp4?nimblesessionid=57"#EXT-X-PART:DURATION=1.001,URI="v_26_60100416_9876_7.fmp4?nimblesessionid=57"#EXT-X-PART:DURATION=1.001,URI="v_26_60100416_9876_8.fmp4?nimblesessionid=57"#EXT-X-PART:DURATION=1.001,URI="v_26_60100416_9876_9.fmp4?nimblesessionid=57"#EXT-X-PROGRAM-DATE-TIME:2020-12-14T01:28:50.745Z#EXTINF:10.01,v_26_60100416_9876.fmp4?nimblesessionid=57#EXT-X-PRELOAD-HINT:TYPE=PART,URI="v_26_60110426_9877_0.fmp4?nimblesessionid=57"
5.2. Interleaving compensation
Related materials
Watch Converting NDI to Apple Low Latency HLS video which demonstrates hot to get NDI source input and produce LLHLS output with proper latency.
No comments:
Post a Comment
If you face any specific issue or want to ask some question to our team,
PLEASE USE OUR HELPDESK
This will give much faster and precise response.
Thank you.
Note: Only a member of this blog may post a comment.