Skip to content

Commit

Permalink
Merge pull request #1182 from canalplus/feat/updatecontenturls
Browse files Browse the repository at this point in the history
Add `updateContentUrls` API
  • Loading branch information
peaBerberian committed Dec 21, 2022
2 parents 5428d33 + d5c3a36 commit 642425d
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 3 deletions.
4 changes: 4 additions & 0 deletions doc/api/Content_Information/.docConfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
"path": "./getUrl.md",
"displayName": "getUrl"
},
{
"path": "./updateContentUrls.md",
"displayName": "updateContentUrls"
},
{
"path": "./isLive.md",
"displayName": "isLive"
Expand Down
61 changes: 61 additions & 0 deletions doc/api/Content_Information/updateContentUrls.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# updateContentUrls

## Description

Update URL of the content currently being played (e.g. of DASH's MPD),
optionally also allowing to request an immediate refresh of it.

This method can for example be called when you would prefer that the content and
its associated resources to be reached through another URL than what has been
used until now.

Note that if a request through one of the given URL lead to a HTTP redirect, the
RxPlayer will generally prefer the redirected URL over the URL explicitely
communicated (to prevent more HTTP redirect).

<div class="warning">
In <i>DirectFile</i> mode (see <a
href="../Loading_a_Content.md#transport">loadVideo options</a>),
this method has no effect.
</div>

## Syntax

```js
player.updateContentUrls(urls);
// or
player.updateContentUrls(urls, params);
```

- **arguments**:

1. _urls_ `Array.<string>|under`: URLs to reach that content / Manifest
from the most prioritized URL to the least prioritized URL.

2. _params_ `Object|undefined`: Optional parameters linked to this URL
change.

Can contain the following properties:

- _refresh_ `boolean`: If `true` the resource in question (e.g.
DASH's MPD) will be refreshed immediately.

## Examples

```js
// Update with only one URL
player.updateContentUrls(["http://my.new.url"]);

// Update with multiple URLs
player.updateContentUrls([
"http://more.prioritized.url",
"http://less.prioritized.url",
]);

// Set no URL (only is useful in some very specific situations, like for content
// with no Manifest refresh or when a `manifestLoader` is set).
player.updateContentUrls(undefined);

// Update and ask to refresh immediately
player.updateContentUrls(["http://my.new.url"], { refresh: true });
```
3 changes: 3 additions & 0 deletions doc/reference/API_Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,9 @@ properties, methods, events and so on.
- [`getUrl`](../api/Content_Information/getUrl.md):
Get URL of the currently-played content.

- [`updateContentUrls`](../api/Content_Information/updateContentUrls.md):
Update URL(s) of the content currently being played.

- [`isLive`](../api/Content_Information/isLive.md):
Returns `true` if the content is a "live" content.

Expand Down
22 changes: 22 additions & 0 deletions src/core/api/public_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -777,6 +777,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
contentId: generateContentId(),
originalUrl: url,
currentContentCanceller,
initializer,
isDirectFile,
segmentBuffersStore: null,
thumbnails: null,
Expand Down Expand Up @@ -1129,6 +1130,25 @@ class Player extends EventEmitter<IPublicAPIEvent> {
return undefined;
}

/**
* Update URL of the content currently being played (e.g. DASH's MPD).
* @param {Array.<string>|undefined} urls - URLs to reach that content /
* Manifest from the most prioritized URL to the least prioritized URL.
* @param {Object|undefined} [params]
* @param {boolean} params.refresh - If `true` the resource in question
* (e.g. DASH's MPD) will be refreshed immediately.
*/
public updateContentUrls(
urls : string[] | undefined,
params? : { refresh?: boolean } | undefined
) : void {
if (this._priv_contentInfos === null) {
throw new Error("No content loaded");
}
const refreshNow = params?.refresh === true;
this._priv_contentInfos.initializer.updateContentUrls(urls, refreshNow);
}

/**
* Returns the video duration, in seconds.
* NaN if no video is playing.
Expand Down Expand Up @@ -2851,6 +2871,8 @@ interface IPublicApiContentInfos {
contentId : string;
/** Original URL set to load the content. */
originalUrl : string | undefined;
/** `ContentInitializer` used to load the content. */
initializer : ContentInitializer;
/** TaskCanceller triggered when it's time to stop the current content. */
currentContentCanceller : TaskCanceller;
/**
Expand Down
38 changes: 35 additions & 3 deletions src/core/fetchers/manifest/manifest_fetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ export default class ManifestFetcher extends EventEmitter<IManifestFetcherEvent>
private _isRefreshPending;
/** Number of consecutive times the Manifest parsing has been done in `unsafeMode`. */
private _consecutiveUnsafeMode;
/**
* If set to a string or `undefined`, the given URL should be prioritized on
* the next Manifest fetching operation, it can then be reset to `null`.
*/
private _prioritizedContentUrl : string | undefined | null;

/**
* Construct a new ManifestFetcher.
Expand All @@ -104,6 +109,7 @@ export default class ManifestFetcher extends EventEmitter<IManifestFetcherEvent>
this._isStarted = false;
this._isRefreshPending = false;
this._consecutiveUnsafeMode = 0;
this._prioritizedContentUrl = null;
}

/**
Expand Down Expand Up @@ -156,6 +162,24 @@ export default class ManifestFetcher extends EventEmitter<IManifestFetcherEvent>
.catch((err : unknown) => this._onFatalError(err));
}

/**
* Update URL of the fetched Manifest.
* @param {Array.<string> | undefined} urls - New Manifest URLs by order of
* priority or `undefined` if there's now no URL.
* @param {boolean} refreshNow - If set to `true`, the next Manifest refresh
* will be triggered immediately.
*/
public updateContentUrls(urls : string[] | undefined, refreshNow : boolean) : void {
this._prioritizedContentUrl = urls?.[0] ?? undefined;
if (refreshNow) {
this.scheduleManualRefresh({
enablePartialRefresh: false,
delay: 0,
canUseUnsafeMode: false,
});
}
}

/**
* (re-)Load the Manifest.
* This method does not yet parse it, parsing will then be available through
Expand Down Expand Up @@ -560,9 +584,17 @@ export default class ManifestFetcher extends EventEmitter<IManifestFetcherEvent>
unsafeMode : boolean; }
) {
const manifestUpdateUrl = manifest.updateUrl;
const fullRefresh = !enablePartialRefresh || manifestUpdateUrl === undefined;
const refreshURL = fullRefresh ? manifest.getUrl() :
manifestUpdateUrl;
let fullRefresh : boolean;
let refreshURL : string | undefined;
if (this._prioritizedContentUrl !== null) {
fullRefresh = true;
refreshURL = this._prioritizedContentUrl;
this._prioritizedContentUrl = null;
} else {
fullRefresh = !enablePartialRefresh || manifestUpdateUrl === undefined;
refreshURL = fullRefresh ? manifest.getUrl() :
manifestUpdateUrl;
}
const externalClockOffset = manifest.clockOffset;

if (unsafeMode) {
Expand Down
4 changes: 4 additions & 0 deletions src/core/init/directfile_content_initializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ export default class DirectFileContentInitializer extends ContentInitializer {
}, { emitCurrentValue: true, clearSignal: cancelSignal });
}

public updateContentUrls(_urls : string[] | undefined, _refreshNow : boolean) : void {
throw new Error("Cannot update content URL of directfile contents");
}

public dispose(): void {
this._initCanceller.cancel();
}
Expand Down
11 changes: 11 additions & 0 deletions src/core/init/media_source_content_initializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,17 @@ export default class MediaSourceContentInitializer extends ContentInitializer {
});
}

/**
* Update URL of the Manifest.
* @param {Array.<string>|undefined} urls - URLs to reach that Manifest from
* the most prioritized URL to the least prioritized URL.
* @param {boolean} refreshNow - If `true` the resource in question (e.g.
* DASH's MPD) will be refreshed immediately.
*/
public updateContentUrls(urls : string[] | undefined, refreshNow : boolean) : void {
this._manifestFetcher.updateContentUrls(urls, refreshNow);
}

public dispose(): void {
this._initCanceller.cancel();
}
Expand Down
12 changes: 12 additions & 0 deletions src/core/init/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,18 @@ export abstract class ContentInitializer extends EventEmitter<IContentInitialize
playbackObserver : PlaybackObserver
) : void;

/**
* Update URL of the content currently being played (e.g. DASH's MPD).
* @param {Array.<string>|undefined} urls - URLs to reach that content /
* Manifest from the most prioritized URL to the least prioritized URL.
* @param {boolean} refreshNow - If `true` the resource in question (e.g.
* DASH's MPD) will be refreshed immediately.
*/
public abstract updateContentUrls(
urls : string[] | undefined,
refreshNow : boolean
) : void;

/**
* Stop playing the content linked to this `ContentInitializer` on the
* `HTMLMediaElement` linked to it and dispose of every resources taken while
Expand Down

0 comments on commit 642425d

Please sign in to comment.