Skip to content

Commit

Permalink
Feature/managed media source (#4319)
Browse files Browse the repository at this point in the history
* Starting point for some tests with ManagedMediaSource. No way to check the implementation at this point, no debug device available.

* Fix a mediasource selection bug and add logging output

* Add missing checks to enable playback on iOS Safari

* Only try to add event listener for "startstreaming" and "endstreaming" if we are using the ManagedMediaSource

* Sort function list
  • Loading branch information
dsilhavy committed Nov 22, 2023
1 parent cb75b77 commit 2b957f8
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 7 deletions.
12 changes: 12 additions & 0 deletions src/streaming/MediaPlayerEvents.js
Expand Up @@ -438,6 +438,18 @@ class MediaPlayerEvents extends EventsBase {
* @event MediaPlayerEvents#INBAND_PRFT
*/
this.INBAND_PRFT = 'inbandPrft';

/**
* The streaming attribute of the Managed Media Source is true
* @type {string}
*/
this.MANAGED_MEDIA_SOURCE_START_STREAMING = 'managedMediaSourceStartStreaming';

/**
* The streaming attribute of the Managed Media Source is false
* @type {string}
*/
this.MANAGED_MEDIA_SOURCE_END_STREAMING = 'managedMediaSourceEndStreaming';
}
}

Expand Down
31 changes: 27 additions & 4 deletions src/streaming/controllers/MediaSourceController.js
Expand Up @@ -30,15 +30,19 @@
*/
import FactoryMaker from '../../core/FactoryMaker';
import Debug from '../../core/Debug';
import EventBus from '../../core/EventBus';
import MediaPlayerEvents from '../MediaPlayerEvents';

function MediaSourceController() {

let instance,
mediaSource,
settings,
mediaSourceType,
logger;

const context = this.context;
const eventBus = EventBus(context).getInstance();

function setup() {
logger = Debug(context).getInstance().getLogger(instance);
Expand All @@ -48,11 +52,20 @@ function MediaSourceController() {

let hasWebKit = ('WebKitMediaSource' in window);
let hasMediaSource = ('MediaSource' in window);

if (hasMediaSource) {
let hasManagedMediaSource = ('ManagedMediaSource' in window);

if (hasManagedMediaSource) {
// eslint-disable-next-line no-undef
mediaSource = new ManagedMediaSource();
mediaSourceType = 'managedMediaSource';
logger.info(`Created ManagedMediaSource`)
} else if (hasMediaSource) {
mediaSource = new MediaSource();
mediaSourceType = 'mediaSource';
logger.info(`Created MediaSource`)
} else if (hasWebKit) {
mediaSource = new WebKitMediaSource();
logger.info(`Created WebkitMediaSource`)
}

return mediaSource;
Expand All @@ -64,6 +77,16 @@ function MediaSourceController() {

videoModel.setSource(objectURL);

if (mediaSourceType === 'managedMediaSource') {
videoModel.setDisableRemotePlayback(true);
mediaSource.addEventListener('startstreaming', () => {
eventBus.trigger(MediaPlayerEvents.MANAGED_MEDIA_SOURCE_START_STREAMING)
})
mediaSource.addEventListener('endstreaming', () => {
eventBus.trigger(MediaPlayerEvents.MANAGED_MEDIA_SOURCE_END_STREAMING)
})
}

return objectURL;
}

Expand Down Expand Up @@ -139,13 +162,13 @@ function MediaSourceController() {
}

instance = {
createMediaSource,
attachMediaSource,
createMediaSource,
detachMediaSource,
setConfig,
setDuration,
setSeekable,
signalEndOfStream,
setConfig
};

setup();
Expand Down
18 changes: 17 additions & 1 deletion src/streaming/controllers/ScheduleController.js
Expand Up @@ -64,6 +64,7 @@ function ScheduleController(config) {
lastInitializedQuality,
switchTrack,
initSegmentRequired,
managedMediaSourceAllowsRequest,
checkPlaybackQuality;

function setup() {
Expand All @@ -79,6 +80,16 @@ function ScheduleController(config) {
eventBus.on(MediaPlayerEvents.PLAYBACK_STARTED, _onPlaybackStarted, instance);
eventBus.on(MediaPlayerEvents.PLAYBACK_RATE_CHANGED, _onPlaybackRateChanged, instance);
eventBus.on(MediaPlayerEvents.PLAYBACK_TIME_UPDATED, _onPlaybackTimeUpdated, instance);
eventBus.on(MediaPlayerEvents.MANAGED_MEDIA_SOURCE_START_STREAMING, _onManagedMediaSourceStartStreaming, instance);
eventBus.on(MediaPlayerEvents.MANAGED_MEDIA_SOURCE_END_STREAMING, _onManagedMediaSourceEndStreaming, instance);
}

function _onManagedMediaSourceStartStreaming() {
managedMediaSourceAllowsRequest = true;
}

function _onManagedMediaSourceEndStreaming() {
managedMediaSourceAllowsRequest = false;
}

function getType() {
Expand Down Expand Up @@ -207,6 +218,9 @@ function ScheduleController(config) {
*/
function _shouldScheduleNextRequest() {
try {
if (!managedMediaSourceAllowsRequest) {
return false;
}
const currentRepresentationInfo = representationController.getCurrentRepresentationInfo();
return currentRepresentationInfo && (isNaN(lastInitializedQuality) || switchTrack || hasTopQualityChanged() || _shouldBuffer());
} catch (e) {
Expand Down Expand Up @@ -367,7 +381,6 @@ function ScheduleController(config) {
}



function _onURLResolutionFailed() {
fragmentModel.abortRequests();
clearScheduleTimer();
Expand Down Expand Up @@ -415,13 +428,16 @@ function ScheduleController(config) {
topQualityIndex = NaN;
switchTrack = false;
initSegmentRequired = false;
managedMediaSourceAllowsRequest = true;
}

function reset() {
eventBus.off(Events.URL_RESOLUTION_FAILED, _onURLResolutionFailed, instance);
eventBus.off(MediaPlayerEvents.PLAYBACK_STARTED, _onPlaybackStarted, instance);
eventBus.off(MediaPlayerEvents.PLAYBACK_RATE_CHANGED, _onPlaybackRateChanged, instance);
eventBus.off(MediaPlayerEvents.PLAYBACK_TIME_UPDATED, _onPlaybackTimeUpdated, instance);
eventBus.off(MediaPlayerEvents.MANAGED_MEDIA_SOURCE_START_STREAMING, _onManagedMediaSourceStartStreaming, instance);
eventBus.off(MediaPlayerEvents.MANAGED_MEDIA_SOURCE_END_STREAMING, _onManagedMediaSourceEndStreaming, instance);

clearScheduleTimer();
_completeQualityChange(false);
Expand Down
7 changes: 7 additions & 0 deletions src/streaming/models/VideoModel.js
Expand Up @@ -191,6 +191,12 @@ function VideoModel() {
}
}

function setDisableRemotePlayback(value) {
if (element) {
element.disableRemotePlayback = value;
}
}

function getSource() {
return element ? element.src : null;
}
Expand Down Expand Up @@ -498,6 +504,7 @@ function VideoModel() {
setTTMLRenderingDiv,
setVttRenderingDiv,
waitForReadyState,
setDisableRemotePlayback,
};

setup();
Expand Down
9 changes: 7 additions & 2 deletions src/streaming/utils/Capabilities.js
Expand Up @@ -44,10 +44,11 @@ const codecCompatibilityTable = [
];

export function supportsMediaSource() {
let hasManagedMediaSource = ('ManagedMediaSource' in window)
let hasWebKit = ('WebKitMediaSource' in window);
let hasMediaSource = ('MediaSource' in window);

return (hasWebKit || hasMediaSource);
return (hasManagedMediaSource || hasWebKit || hasMediaSource);
}

function Capabilities() {
Expand Down Expand Up @@ -137,7 +138,11 @@ function Capabilities() {
codec += ';width="' + config.width + '";height="' + config.height + '"';
}

if ('MediaSource' in window && MediaSource.isTypeSupported(codec)) {
// eslint-disable-next-line no-undef
if ('ManagedMediaSource' in window && ManagedMediaSource.isTypeSupported(codec)) {
resolve(true);
return;
} else if ('MediaSource' in window && MediaSource.isTypeSupported(codec)) {
resolve(true);
return;
} else if ('WebKitMediaSource' in window && WebKitMediaSource.isTypeSupported(codec)) {
Expand Down

0 comments on commit 2b957f8

Please sign in to comment.