Skip to content

Commit 25ee193

Browse files
committed
[Proposal] Solution 1: PlaybackObserver is moved in src
Root issue ---------- While working on code refactoring for better taking into account the new potentially multithread nature of the RxPlayer code (with some files only running in a WebWorker environment and others only running in a main thread environment), we recently refactored our file hierarchy (#1365) to better reflect that new situation. The idea is to make RxPlayer developpers more aware of what code is intended to run where. In that work, we had a remaining issue concerning the `PlaybackObserver`. This is the part of the code that is monitoring and advertising playback conditions to the rest of the RxPlayer code. Most core RxPlayer modules rely on it, in both main thread and WebWorker environments. The root issue is that the `PlaybackObserver` is a class and thus cannot be easily transmitted in-between environments (as the main thread and WebWorker only exchanges between one another through `postMessage` calls, which follows some rules preventing from doing that). As such, and only on a multithreaded scenario, the RxPlayer is serializing in some way the constructed source PlaybackObserver in the main thread to reconstruct one (the `WorkerPlaybackObserver`) on the worker. Because a whole complex PlaybackObserver-compatible structure has to both be constructed in the main thread and in the worker (yet only the main thread can act as the "true" source one, because the media element can only be accessed in main thread), we were asking ourselves where should we put the common utils (required by both the main thread and worker) needed to construct one (like the `ObservationPosition` class and the `generateReadOnlyObserver` util). Solution 1 ---------- This is a first solution proposal, which moves the `PlaybackObserver` directory outside of the `main_thread` and `core` directories. Instead, its code is now directly in `src/playback_observer`. This solution takes inspiration from the `src/mse` directory, which also exports both: 1. files intended to be imported when MSE API are present in the current environment (when in main thread or when in a WebWorker with the MSE-in-worker feature) and 2. files intended to be imported in environments without MSE. For example the `src/mse/main_media_source_interface.ts` should __ONLY__ be imported in environments with MSE capabilities. If you do not, you should import `src/mse/worker_media_source_interface.ts`. Likewise, I here added a `src/playback_observer/media_element_playback_observer.ts` file exporting a `MediaElementPlaybackObserver` structure (new name of the `PlaybackObserver`) which can only be imported in environements where the media element is available (so, only on main thread) and a `src/playback_observer/worker_playback_observer.ts` file which should only be imported in other environments. Doing this allows to easily share common utils, in a `src/playback_observer/utils` directory, without involving the rest of the RxPlayer code. Result ------ I'm quite happy with the result, though I get it may seem weird to have a complex core frequently-running logic part directly in `src` (and not in `main_thread` or `core` as was the norm) - though it is also the case of directories like `mse` or `transports`. RxPlayer code very rarely imported files inside other directories (which it does here with paths like `../playback_observer/media_element_playback_observer`) as a way to push better modularization. Though here it may seem like a feature because its unusual-ness forces the developper to double check if this is the right file that is imported.
1 parent 1d732f4 commit 25ee193

40 files changed

+726
-661
lines changed

src/core/adaptive/adaptive_representation_selector.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,17 @@
1616

1717
import config from "../../config";
1818
import log from "../../log";
19-
import type {
20-
IObservationPosition,
21-
IReadOnlyPlaybackObserver,
22-
} from "../../main_thread/types";
2319
import type {
2420
IAdaptation,
2521
IManifest,
2622
IPeriod,
2723
IRepresentation,
2824
ISegment,
2925
} from "../../manifest";
26+
import type {
27+
ObservationPosition,
28+
IReadOnlyPlaybackObserver,
29+
} from "../../playback_observer";
3030
import isNullOrUndefined from "../../utils/is_null_or_undefined";
3131
import noop from "../../utils/noop";
3232
import type { IRange } from "../../utils/ranges";
@@ -604,7 +604,7 @@ export interface IRepresentationEstimatorPlaybackObservation {
604604
* Information on the current media position in seconds at the time of a
605605
* Playback Observation.
606606
*/
607-
position : IObservationPosition;
607+
position : ObservationPosition;
608608
/**
609609
* Last "playback rate" set by the user. This is the ideal "playback rate" at
610610
* which the media should play.

src/core/main/common/DecipherabilityFreezeDetector.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*/
1616

1717
import log from "../../../log";
18-
import type { IFreezingStatus, IRebufferingStatus } from "../../../main_thread/types";
18+
import type { IFreezingStatus, IRebufferingStatus } from "../../../playback_observer";
1919
import getMonotonicTimeStamp from "../../../utils/monotonic_timestamp";
2020
import type SegmentSinksStore from "../../segment_sinks";
2121

src/core/main/common/content_time_boundaries_observer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ import type {
1919
IBufferType,
2020
} from "../../../core/types";
2121
import { MediaError } from "../../../errors";
22-
import type { IReadOnlyPlaybackObserver } from "../../../main_thread/types";
2322
import type {
2423
IManifest,
2524
IAdaptation,
2625
IRepresentationIndex,
2726
IPeriod,
2827
} from "../../../manifest";
28+
import type { IReadOnlyPlaybackObserver } from "../../../playback_observer";
2929
import type { IPlayerError } from "../../../public_types";
3030
import EventEmitter from "../../../utils/event_emitter";
3131
import isNullOrUndefined from "../../../utils/is_null_or_undefined";

src/core/main/common/create_content_time_boundaries_observer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ import type {
33
IStreamOrchestratorPlaybackObservation,
44
} from "../../../core/types";
55
import log from "../../../log";
6-
import type { IReadOnlyPlaybackObserver } from "../../../main_thread/types";
76
import type {
87
IManifest,
98
IPeriod,
109
} from "../../../manifest";
1110
import type { IMediaSourceInterface } from "../../../mse";
11+
import type { IReadOnlyPlaybackObserver } from "../../../playback_observer";
1212
import type { IPlayerError } from "../../../public_types";
1313
import type { CancellationSignal } from "../../../utils/task_canceller";
1414
import ContentTimeBoundariesObserver from "./content_time_boundaries_observer";

src/core/main/index.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/core/main/worker/worker_main.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ import {
55
} from "../../../errors";
66
import features from "../../../features";
77
import log from "../../../log";
8-
// XXX TODO
9-
import { ObservationPosition } from "../../../main_thread/api/playback_observer";
108
import Manifest, {
119
Adaptation,
1210
Period,
@@ -24,6 +22,11 @@ import {
2422
WorkerMessageType,
2523
} from "../../../multithread_types";
2624
import DashWasmParser from "../../../parsers/manifest/dash/wasm-parser";
25+
import { ObservationPosition } from "../../../playback_observer";
26+
import type {
27+
IWorkerPlaybackObservation,
28+
} from "../../../playback_observer/worker_playback_observer";
29+
import WorkerPlaybackObserver from "../../../playback_observer/worker_playback_observer";
2730
import type { IPlayerError, ITrackType } from "../../../public_types";
2831
import createDashPipelines from "../../../transports/dash";
2932
import arrayFind from "../../../utils/array_find";
@@ -60,10 +63,6 @@ import {
6063
import sendMessage, {
6164
formatErrorForSender,
6265
} from "./send_message";
63-
import type {
64-
ICorePlaybackObservation,
65-
} from "./worker_playback_observer";
66-
import WorkerPlaybackObserver from "./worker_playback_observer";
6766

6867
export default function initializeWorkerMain() {
6968
/**
@@ -97,7 +96,7 @@ export default function initializeWorkerMain() {
9796
/**
9897
* When set, emit playback observation made on the main thread.
9998
*/
100-
let playbackObservationRef : SharedReference<ICorePlaybackObservation> | null = null;
99+
let playbackObservationRef : SharedReference<IWorkerPlaybackObservation> | null = null;
101100

102101
onmessage = function (e: MessageEvent<IMainThreadMessage>) {
103102
log.debug("Worker: received message", e.data.type);
@@ -161,7 +160,7 @@ export default function initializeWorkerMain() {
161160

162161
const currentCanceller = new TaskCanceller();
163162
const currentContentObservationRef = new SharedReference<
164-
ICorePlaybackObservation
163+
IWorkerPlaybackObservation
165164
>(objectAssign(msg.value.initialObservation, {
166165
position: new ObservationPosition(...msg.value.initialObservation.position),
167166
}));
@@ -475,7 +474,7 @@ interface IBufferingInitializationInformation {
475474
function loadOrReloadPreparedContent(
476475
val : IBufferingInitializationInformation,
477476
contentPreparer : ContentPreparer,
478-
playbackObservationRef : IReadOnlySharedReference<ICorePlaybackObservation>,
477+
playbackObservationRef : IReadOnlySharedReference<IWorkerPlaybackObservation>,
479478
parentCancelSignal : CancellationSignal
480479
) {
481480
const currentLoadCanceller = new TaskCanceller();
@@ -544,6 +543,7 @@ function loadOrReloadPreparedContent(
544543

545544
const playbackObserver = new WorkerPlaybackObserver(playbackObservationRef,
546545
contentId,
546+
sendMessage,
547547
currentLoadCanceller.signal);
548548

549549
const contentTimeBoundariesObserver = createContentTimeBoundariesObserver(

src/core/main/worker/worker_playback_observer.ts

Lines changed: 0 additions & 90 deletions
This file was deleted.

src/core/segment_sinks/garbage_collector.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*/
1616

1717
import log from "../../log";
18-
import type { IReadOnlyPlaybackObserver } from "../../main_thread/types";
18+
import type { IReadOnlyPlaybackObserver } from "../../playback_observer";
1919
import isNullOrUndefined from "../../utils/is_null_or_undefined";
2020
import type { IRange } from "../../utils/ranges";
2121
import { getInnerAndOuterRanges } from "../../utils/ranges";

src/core/stream/adaptation/get_representations_switch_strategy.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,8 @@
1515
*/
1616

1717
import config from "../../../config";
18-
import type { IReadOnlyPlaybackObserver } from "../../../main_thread/types";
19-
import type {
20-
IAdaptation,
21-
IPeriod,
22-
} from "../../../manifest";
18+
import type { IAdaptation, IPeriod } from "../../../manifest";
19+
import type { IReadOnlyPlaybackObserver } from "../../../playback_observer";
2320
import arrayIncludes from "../../../utils/array_includes";
2421
import type {
2522
IRange } from "../../../utils/ranges";

src/core/stream/adaptation/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import type { IReadOnlyPlaybackObserver } from "../../../main_thread/types";
21
import type {
32
IManifest,
43
IAdaptation,
54
IPeriod,
65
IRepresentation,
76
} from "../../../manifest";
7+
import type { IReadOnlyPlaybackObserver } from "../../../playback_observer";
88
import type {
99
IAudioTrackSwitchingMode,
1010
IVideoTrackSwitchingMode,

0 commit comments

Comments
 (0)