Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(FEC-9523): add attach detach implemention #21

Merged
merged 15 commits into from
Dec 30, 2019
47 changes: 24 additions & 23 deletions src/flash.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,23 +33,16 @@ class Flash extends FakeEventTarget implements IEngine {
*/
_api: ?FlashHLSAdapter = null;

/**
* The src
* @type {string}
* @private
*/
_src: ?string = null;

/**
* The player config object.
* @type {Object}
* @type {?Object}
* @private
*/
_config: ?Object = null;
_config: ?Object;

/**
* Promise when load finished
* @type {Promise<*>}
* @type {?Promise<*>}
* @private
*/
_loadPromise: ?Promise<*> = null;
Expand All @@ -70,13 +63,11 @@ class Flash extends FakeEventTarget implements IEngine {

/**
* The event manager of the engine.
* @type {EventManager}
* @type {?EventManager}
* @private
*/
_eventManager: EventManager = null;

_srcToLoad: ?string = null;

/**
* The state of player mute
* @type {boolean}
Expand Down Expand Up @@ -185,9 +176,17 @@ class Flash extends FakeEventTarget implements IEngine {
this._init(source, config);
}

attachMediaSource(): void {}
attachMediaSource(): void {
if (this._api) {
this._api.attachMediaSource();
}
}

detachMediaSource(): void {}
detachMediaSource(): void {
if (this._api) {
this._api.detachMediaSource();
}
}

hideTextTrack(): void {}

Expand All @@ -204,20 +203,18 @@ class Flash extends FakeEventTarget implements IEngine {
this._api = new FlashHLSAdapter(source, config, this._el);
this._api.attach();
this._addBindings();
this._srcToLoad = source.url;
}
}

reset(): void {
if (this._api) {
this._api.reset();
}
this._src = null;

this._config = null;
this._muted = this.defaultMuted;
Yuvalke marked this conversation as resolved.
Show resolved Hide resolved
this._volume = NaN;
this._volumeBeforeMute = NaN;
this._srcToLoad = null;
}

/**
Expand Down Expand Up @@ -303,8 +300,11 @@ class Flash extends FakeEventTarget implements IEngine {
EventType.SEEKING,
EventType.SEEKED,
EventType.ENDED,
EventType.TEXT_CUE_CHANGED,
EventType.VIDEO_TRACK_CHANGED,
EventType.AUDIO_TRACK_CHANGED,
EventType.ABORT,
EventType.EMPTIED,
EventType.DURATION_CHANGE
];
events.forEach(eventName => {
Expand Down Expand Up @@ -384,7 +384,9 @@ class Flash extends FakeEventTarget implements IEngine {
* @returns {void}
*/
set src(source: string): void {
this._src = source;
if (this._api) {
this._api.src = source;
}
}

/**
Expand All @@ -393,15 +395,15 @@ class Flash extends FakeEventTarget implements IEngine {
* @public
*/
get src(): string {
if (this._src) {
return this._src;
if (this._api) {
return this._api.src;
}
return '';
}

/**
* Load media.
* @param {number} startTime - Optional time to start the video from.
* @param {?number} startTime - Optional time to start the video from.
* @public
* @returns {Promise<Object>} - The loaded data
*/
Expand All @@ -410,7 +412,6 @@ class Flash extends FakeEventTarget implements IEngine {
Flash._logger.warn('Missing API - Flash is not ready');
return Promise.reject('Flash is not ready');
}
this._src = this._srcToLoad;
this._loadPromise = this._api.load(startTime);
return this._loadPromise;
}
Expand Down
169 changes: 124 additions & 45 deletions src/flashhls-adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import DefaultConfig from './default-config';
class FlashHLSAdapter extends FakeEventTarget {
_config: Object;
_el: HTMLDivElement;
_api: FlashAPI;
_api: ?FlashAPI;
_src: PKMediaSourceObject;
_startTime: number;
_firstPlay: boolean = true;
Expand All @@ -18,10 +18,24 @@ class FlashHLSAdapter extends FakeEventTarget {
duration: ?number;
buffer: ?number;
watched: ?number;
currentTime: ?number;
currentTime: number;
_apiLoadPromise: Promise<*>;
_apiLoadResolve: any;

/**
* The last time detach occurred
* @type {number}
* @private
*/
_lastTimeDetach: number = NaN;

/**
* The start time after attach
* @type {number}
* @private
*/
_startTimeAttach: number = NaN;

static getFlashCode(swf: string, flashVars: Object, params: Object, attributes: Object): string {
const objTag = '<object type="application/x-shockwave-flash" ';
let flashVarsString = '';
Expand Down Expand Up @@ -92,6 +106,17 @@ class FlashHLSAdapter extends FakeEventTarget {
if (this._el && this._el.parentNode) {
this._el.innerHTML = '';
}
this._startTimeAttach = NaN;
this._lastTimeDetach = NaN;
this._api = null;
//simulate the event sequence like video tag
Yuvalke marked this conversation as resolved.
Show resolved Hide resolved
this._trigger(EventType.ABORT);
this._trigger(EventType.EMPTIED);
//to hide the text tracks simulate event like happened in hls.js
this._trigger(EventType.TEXT_CUE_CHANGED, {cues: []});

this.currentTime = NaN;
this._trigger(EventType.TIME_UPDATE);
}

attach(): HTMLDivElement {
Expand All @@ -107,8 +132,10 @@ class FlashHLSAdapter extends FakeEventTarget {
if (this._initialVolume != null) {
this.volume(this._initialVolume);
}
if (this._config.debug) {
if (this._api && this._config.debug) {
this._api.playerSetLogDebug(true);
}
if (this._api && this._config.debug) {
this._api.playerSetLogDebug2(true);
}
this._apiLoadResolve();
Expand Down Expand Up @@ -147,39 +174,41 @@ class FlashHLSAdapter extends FakeEventTarget {
this._trigger(EventType.ERROR, error);
},
manifest: (duration, levels_) => {
let audioTracks = this._api.getAudioTrackList();
const parsedAudioTracks = [];
if (audioTracks) {
for (let i = 0; i < audioTracks.length; i++) {
const settings = {
id: audioTracks[i].id,
active: audioTracks[i].isDefault,
label: audioTracks[i].title,
language: audioTracks[i].title, //TODO: Get language?!?
if (this._api) {
let audioTracks = this._api.getAudioTrackList();
const parsedAudioTracks = [];
if (audioTracks) {
for (let i = 0; i < audioTracks.length; i++) {
const settings = {
id: audioTracks[i].id,
active: audioTracks[i].isDefault,
label: audioTracks[i].title,
language: audioTracks[i].title, //TODO: Get language?!?
index: i
};
parsedAudioTracks.push(new AudioTrack(settings));
}
}

let videoTracks = [];
for (let i = 0; i < levels_.length; i++) {
// Create video tracks
let settings = {
active: 0 === i,
bandwidth: levels_[i].bitrate,
width: levels_[i].width,
height: levels_[i].height,
language: '',
index: i
};
parsedAudioTracks.push(new AudioTrack(settings));
videoTracks.push(new VideoTrack(settings));
}
if (this._resolveLoad) {
this._resolveLoad({tracks: videoTracks.concat(parsedAudioTracks)});
this._resolveLoad = null;
}
this._trigger(EventType.TRACKS_CHANGED, {tracks: videoTracks.concat(parsedAudioTracks)});
}

let videoTracks = [];
for (let i = 0; i < levels_.length; i++) {
// Create video tracks
let settings = {
active: 0 === i,
bandwidth: levels_[i].bitrate,
width: levels_[i].width,
height: levels_[i].height,
language: '',
index: i
};
videoTracks.push(new VideoTrack(settings));
}
if (this._resolveLoad) {
this._resolveLoad({tracks: videoTracks.concat(parsedAudioTracks)});
this._resolveLoad = null;
}
this._trigger(EventType.TRACKS_CHANGED, {tracks: videoTracks.concat(parsedAudioTracks)});
},
seekState: newState => {
if (this._firstPlay) {
Expand Down Expand Up @@ -227,25 +256,28 @@ class FlashHLSAdapter extends FakeEventTarget {
load(startTime: ?number): Promise<Object> {
this._loadPromise = new Promise(resolve => {
this._resolveLoad = resolve;
if (startTime) {
this._startTime = startTime;
}
this._startTime = this._startTimeAttach || startTime || -1;
this._startTimeAttach = NaN;
this._apiLoadPromise.then(() => {
this._api.load(this._src.url);
if (this._api) {
this._api.load(this._src.url);
}
});
});
return this._loadPromise;
}

play() {
this._apiLoadPromise.then(() => {
if (this._firstPlay) {
this.ended = false;
this._api.play(this._startTime ? this._startTime : -1);
} else {
this._api.resume();
if (this._api) {
if (this._firstPlay) {
this.ended = false;
this._api.play(this._startTime);
} else {
this._api.resume();
}
this._trigger(EventType.PLAY);
}
this._trigger(EventType.PLAY);
});
}

Expand Down Expand Up @@ -287,10 +319,10 @@ class FlashHLSAdapter extends FakeEventTarget {
}

selectVideoTrack(videoTrack: VideoTrack): void {
if (this.isABR()) {
this._trigger(EventType.ABR_MODE_CHANGED, {mode: 'manual'});
}
if (this._api) {
if (this.isABR()) {
this._trigger(EventType.ABR_MODE_CHANGED, {mode: 'manual'});
}
this._api.setCurrentLevel(videoTrack.index);
this._trigger(EventType.VIDEO_TRACK_CHANGED, {selectedVideoTrack: videoTrack});
}
Expand Down Expand Up @@ -335,6 +367,53 @@ class FlashHLSAdapter extends FakeEventTarget {
this.duration = null;
this.buffer = null;
this.watched = null;
this._startTimeAttach = NaN;
this._lastTimeDetach = NaN;
}

/**
* attach media - return the media source to handle the video tag
* @public
* @returns {void}
*/
attachMediaSource(): void {
this.attach();
this._startTimeAttach = this._lastTimeDetach;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clean this._startTimeAttach on destroy (change media)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

this._lastTimeDetach = NaN;
}
/**
* detach media - will remove the media source from handling the video
* @public
* @returns {void}
*/
detachMediaSource(): void {
const currentTime = this.currentTime;
this.destroy();
this._lastTimeDetach = currentTime;
this._firstPlay = true;
this._loadPromise = null;
}

/**
* Set a source.
* @param {string} source - Source to set.
* @public
* @returns {void}
*/
set src(source: string): void {
this._src.url = source;
}

/**
* Get the source url.
* @returns {string} - The source url.
* @public
*/
get src(): string {
if (this._loadPromise && this._src.url) {
return this._src.url;
}
return '';
}
}

Expand Down