Skip to content

Commit

Permalink
馃毀 Implement basic shaka player adapter
Browse files Browse the repository at this point in the history
  • Loading branch information
moisout committed Jan 18, 2024
1 parent 700ff76 commit d8ae639
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 53 deletions.
11 changes: 3 additions & 8 deletions client/composables/videoplayer/videoState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,6 @@ export const useVideoState = (
adapterInstance.value.onPlaybackTimeUpdated(() => {
updateTimeAndDuration();
});
adapterInstance.value.onStreamActivated(() => {
updateTimeAndDuration();
updateQualityLists();
adapterInstance.value.setVolume(volumeStorage.value);
});
adapterInstance.value.onStreamTeardownComplete(() => {
updateTimeAndDuration();
});
adapterInstance.value.onBufferLevelUpdated(() => {
videoState.bufferLevel = adapterInstance.value?.getBufferLevel() ?? 0;
});
Expand All @@ -84,6 +76,9 @@ export const useVideoState = (
});
adapterInstance.value.onCanPlay(() => {
videoState.buffering = false;
updateTimeAndDuration();
updateQualityLists();
adapterInstance.value.setVolume(volumeStorage.value);
});
adapterInstance.value.onVolumeChanged(() => {
videoState.volume = adapterInstance.value?.getVolume() ?? 1;
Expand Down
3 changes: 0 additions & 3 deletions client/utils/videoplayer/adapters/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ export interface VideoplaybackAdapterResponse {
onPlaybackStarted: (callback: EventListenerCallback) => void;
onPlaybackPaused: (callback: EventListenerCallback) => void;
onPlaybackTimeUpdated: (callback: EventListenerCallback) => void;
onStreamActivated: (callback: EventListenerCallback) => void;
onStreamDeactivated: (callback: EventListenerCallback) => void;
onStreamTeardownComplete: (callback: EventListenerCallback) => void;
onTextTracksAdded: (callback: EventListenerCallback) => void;
onBufferLevelUpdated: (callback: EventListenerCallback) => void;
onCanPlay: (callback: EventListenerCallback) => void;
Expand Down
116 changes: 76 additions & 40 deletions client/utils/videoplayer/adapters/shakaAdapter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { MediaInfo } from 'dashjs';
import type { EventListenerCallback, VideoplaybackAdapter } from './adapter';

export const shakaAdapter: VideoplaybackAdapter = async options => {
Expand All @@ -21,13 +20,42 @@ export const shakaAdapter: VideoplaybackAdapter = async options => {
shakaPlayer.addEventListener(event, callback);
};

const registerMultipleCallbacks = (events: string[]) => (callback: EventListenerCallback) => {
events.forEach(event => {
eventStorage.set(event, callback);
shakaPlayer.addEventListener(event, callback);
});
};

const registerNativeCallback =
(event: keyof HTMLVideoElementEventMap) => (callback: EventListenerCallback) => {
eventStorage.set(event, callback);
videoRef.value.addEventListener(event, callback);
};

const unregisterCallback = (event: string) => {
const callback = eventStorage.get(event);
if (callback) {
shakaPlayer.removeEventListener(event, callback);
}
};

const unregisterMultipleCallbacks = (events: string[]) => {
events.forEach(event => {
const callback = eventStorage.get(event);
if (callback) {
shakaPlayer.removeEventListener(event, callback);
}
});
}

const unregisterNativeCallback = (event: string) => {
const callback = eventStorage.get(event);
if (callback) {
videoRef.value.removeEventListener(event, callback);
}
};

const onError = registerCallback('error');
const onMessage = registerCallback('message');
const onOpen = registerCallback('open');
Expand All @@ -45,52 +73,61 @@ export const shakaAdapter: VideoplaybackAdapter = async options => {
});

// Register callbacks
const onPlaybackStarted = registerCallback('dashjs.MediaPlayer.events.PLAYBACK_STARTED');
const onPlaybackPaused = registerCallback('dashjs.MediaPlayer.events.PLAYBACK_PAUSED');
const onPlaybackTimeUpdated = registerCallback('dashjs.MediaPlayer.events.PLAYBACK_TIME_UPDATED');
const onStreamActivated = registerCallback('dashjs.MediaPlayer.events.STREAM_ACTIVATED');
const onStreamDeactivated = registerCallback('dashjs.MediaPlayer.events.STREAM_DEACTIVATED');
const onStreamTeardownComplete = registerCallback(
'dashjs.MediaPlayer.events.STREAM_TEARDOWN_COMPLETE'
);
const onTextTracksAdded = registerCallback('dashjs.MediaPlayer.events.TEXT_TRACKS_ADDED');
const onBufferLevelUpdated = registerCallback('dashjs.MediaPlayer.events.BUFFER_LEVEL_UPDATED');
const onCanPlay = registerCallback('dashjs.MediaPlayer.events.CAN_PLAY');
const onWaiting = registerCallback('dashjs.MediaPlayer.events.PLAYBACK_WAITING');
const onVolumeChanged = registerCallback('dashjs.MediaPlayer.events.PLAYBACK_VOLUME_CHANGED');
const onPlaybackRateChanged = registerCallback('dashjs.MediaPlayer.events.PLAYBACK_RATE_CHANGED');
const onPlaybackStarted = registerNativeCallback('playing');
const onPlaybackPaused = registerNativeCallback('pause');
const onPlaybackTimeUpdated = registerNativeCallback('timeupdate');
const onTextTracksAdded = registerCallback('textchanged');
const onBufferLevelUpdated = registerMultipleCallbacks(['segmentappended', 'onstatechange']);
const onCanPlay = registerNativeCallback('canplay');
// https://nightly-dot-shaka-player-demo.appspot.com/docs/api/shaka.Player.html#.event:BufferingEvent
const onWaiting = registerCallback('buffering');
const onVolumeChanged = registerNativeCallback('volumechange');
const onPlaybackRateChanged = registerCallback('ratechange');
const onQualityChanged = registerCallback('mediaqualitychanged');

const onVideoQualityChanged = (callback: EventListenerCallback) => {
onQualityChanged(e => {
console.log(e);
if (e.mediaType === 'video') {
callback(e.newQuality);
}
});
};

const onAudioQualityChanged = (callback: EventListenerCallback) => {
onQualityChanged(e => {
console.log(e);

if (e.mediaType === 'audio') {
callback(e);
}
});
};

await shakaPlayer.attach(videoRef.value);

const destroy = () => {
// unregisterCallback(dashjs.MediaPlayer.events.PLAYBACK_STARTED);
// unregisterCallback(dashjs.MediaPlayer.events.PLAYBACK_PAUSED);
// unregisterCallback(dashjs.MediaPlayer.events.PLAYBACK_TIME_UPDATED);
// unregisterCallback(dashjs.MediaPlayer.events.STREAM_ACTIVATED);
// unregisterCallback(dashjs.MediaPlayer.events.STREAM_DEACTIVATED);
// unregisterCallback(dashjs.MediaPlayer.events.STREAM_TEARDOWN_COMPLETE);
// unregisterCallback(dashjs.MediaPlayer.events.TEXT_TRACKS_ADDED);
// unregisterCallback(dashjs.MediaPlayer.events.BUFFER_LEVEL_UPDATED);
// unregisterCallback(dashjs.MediaPlayer.events.CAN_PLAY);
// unregisterCallback(dashjs.MediaPlayer.events.PLAYBACK_WAITING);
// unregisterCallback(dashjs.MediaPlayer.events.PLAYBACK_VOLUME_CHANGED);
// unregisterCallback(dashjs.MediaPlayer.events.PLAYBACK_RATE_CHANGED);
unregisterNativeCallback('playing');
unregisterNativeCallback('pause');
unregisterNativeCallback('timeupdate');
unregisterCallback('textchanged');
unregisterMultipleCallbacks(['segmentappended', 'onstatechange']);
unregisterNativeCallback('canplay');
unregisterCallback('buffering');
unregisterNativeCallback('volumechange');
unregisterCallback('ratechange');
unregisterCallback('mediaqualitychanged');

shakaPlayer.destroy();
};

// Getters
const getBufferLevel = () => {
const bufferLevel = 0;
// if (typeof mediaPlayer.getDashMetrics === 'function') {
// const dashMetrics = mediaPlayer.getDashMetrics();
// if (dashMetrics) {
// bufferLevel = dashMetrics.getCurrentBufferLevel('video');
// if (!bufferLevel) {
// bufferLevel = dashMetrics.getCurrentBufferLevel('audio');
// }
// }
// }
let bufferLevel = 0;
const bufferedInfo = shakaPlayer.getBufferedInfo();
if (bufferedInfo) {
bufferLevel = bufferedInfo.total.sort((a, b) => a.end - b.end).reverse()[0].end;
}
return bufferLevel;
};
const getVideoQualityList = () => {
Expand Down Expand Up @@ -160,15 +197,14 @@ export const shakaAdapter: VideoplaybackAdapter = async options => {
onPlaybackStarted,
onPlaybackPaused,
onPlaybackTimeUpdated,
onStreamActivated,
onStreamDeactivated,
onStreamTeardownComplete,
onTextTracksAdded,
onBufferLevelUpdated,
onPlaybackRateChanged,
onCanPlay,
onWaiting,
onVolumeChanged,
onVideoQualityChanged,
onAudioQualityChanged,

getTime,
getDuration,
Expand Down
2 changes: 0 additions & 2 deletions server/src/core/videos/videos.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,6 @@ export class VideosService {
const client = await innertubeClient();
const videoInfo = await client.getInfo(id);

fs.writeFileSync(`/home/maurice/src/viewtube/${id}.json`, JSON.stringify(videoInfo, null, 2));

const dashManifest = await videoInfo.toDash((url: URL) => {
url.searchParams.append('__host', url.host);
return url;
Expand Down

0 comments on commit d8ae639

Please sign in to comment.