Skip to content

Commit

Permalink
v0.20.0
Browse files Browse the repository at this point in the history
micro-optimization:
===================

* when all of the following are true:
  - the HLS manifest for a live stream is proxied
  - prefetch is enabled
  - the cache is empty
* rather than:
  - immediately initiating (up to "--max-segments") parallel downloads to populate the cache,
    while the video player waits for the 1st video segment to become available
* modify the order of downloads such that:
  - the 1st video segment in the manifest is immediately downloaded
  - once this 1st video segment is available,
    then all of the remaining (up to "--max-segments") in the manifest begin to download in parallel

reason for change:
==================

* this should reduce the latency when a live video first starts playing,
  since the 1st video segment downloads more quickly using all available bandwidth
* when a batch of downloads occur in parallel,
  the available bandwidth is shared (more or less) equally;
  all downloads occur at a reduced rate, and complete at about the same time

cross-reference:
================

* related discussion in issue #15
  • Loading branch information
warren-bank committed Oct 8, 2022
1 parent 37a4850 commit 75dab3f
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 6 deletions.
25 changes: 22 additions & 3 deletions hls-proxy/proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,29 @@ const proxy = function({server, host, is_secure, req_headers, req_options, hooks
// only used with prefetch
const perform_prefetch = (cache_segments)
? (urls, dont_touch_access) => {
urls.forEach((matching_url, index) => {
prefetch_segment(m3u8_url, matching_url, referer_url, dont_touch_access)
if (!urls || !Array.isArray(urls) || !urls.length)
return

urls[index] = undefined
let promise

if (is_vod || has_cache(m3u8_url)) {
promise = Promise.resolve()
}
else {
const matching_url = urls[0]
urls[0] = undefined

promise = prefetch_segment(m3u8_url, matching_url, referer_url, dont_touch_access)
}

promise.then(() => {
urls.forEach((matching_url, index) => {
if (matching_url) {
prefetch_segment(m3u8_url, matching_url, referer_url, dont_touch_access)

urls[index] = undefined
}
})
})
}
: null
Expand Down
8 changes: 6 additions & 2 deletions hls-proxy/segment_cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,9 @@ module.exports = function({should_prefetch_url, debug, debug_level, request, get
}

const prefetch_segment = function(m3u8_url, url, referer_url, dont_touch_access) {
if (! should_prefetch_url(url)) return
let promise = Promise.resolve()

if (! should_prefetch_url(url)) return promise

if (cache[m3u8_url] === undefined) {
// initialize a new data structure
Expand All @@ -165,7 +167,7 @@ module.exports = function({should_prefetch_url, debug, debug_level, request, get
ts[index] = {key: get_privatekey_from_url(url), databuffer: false}

let options = get_request_options(url, referer_url)
request(options, '', {binary: true, stream: false})
promise = request(options, '', {binary: true, stream: false})
.then(({response}) => {
debug(1, `prefetch (complete, ${response.length} bytes):`, debug_url)

Expand Down Expand Up @@ -201,6 +203,8 @@ module.exports = function({should_prefetch_url, debug, debug_level, request, get
if (index !== undefined) ts_garbage_collect(m3u8_url, index, 1)
})
}

return promise
}

const get_segment = function(url) {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@warren-bank/hls-proxy",
"description": "Node.js server to proxy HLS video streams",
"version": "0.19.0",
"version": "0.20.0",
"scripts": {
"start": "node hls-proxy/bin/hlsd.js",
"sudo": "sudo node hls-proxy/bin/hlsd.js"
Expand Down

0 comments on commit 75dab3f

Please sign in to comment.