feat(#480): added quality selector to hls player (#178)

keep-around/af30b88d367751c9e05a735e4a0467a96238ef47
Mirlan 5 years ago committed by GitHub
parent affac606b4
commit 64966e942e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      package.json
  2. 2
      src/features/StreamPlayer/hooks/index.tsx
  3. 73
      src/features/StreamPlayer/hooks/useVideoQuality.tsx
  4. 10
      src/features/StreamPlayer/index.tsx

@ -16,6 +16,7 @@
"@reach/combobox": "^0.10.4", "@reach/combobox": "^0.10.4",
"date-fns": "^2.14.0", "date-fns": "^2.14.0",
"history": "^4.10.1", "history": "^4.10.1",
"hls.js": "^0.14.15",
"lodash": "^4.17.15", "lodash": "^4.17.15",
"node-sass": "^4.14.1", "node-sass": "^4.14.1",
"react": "^16.13.1", "react": "^16.13.1",
@ -43,6 +44,7 @@
"@testing-library/react": "^9.3.2", "@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2", "@testing-library/user-event": "^7.1.2",
"@types/history": "^4.7.6", "@types/history": "^4.7.6",
"@types/hls.js": "^0.13.2",
"@types/jest": "^24.0.0", "@types/jest": "^24.0.0",
"@types/lodash": "^4.14.154", "@types/lodash": "^4.14.154",
"@types/node": "^12.0.0", "@types/node": "^12.0.0",

@ -9,6 +9,7 @@ import ReactPlayer from 'react-player'
import once from 'lodash/once' import once from 'lodash/once'
import throttle from 'lodash/throttle' import throttle from 'lodash/throttle'
import { useVideoQuality } from './useVideoQuality'
import { useFullscreen } from './useFullscreen' import { useFullscreen } from './useFullscreen'
import { useVolume } from './useVolume' import { useVolume } from './useVolume'
@ -107,5 +108,6 @@ export const useVideoPlayer = ({
wrapperRef, wrapperRef,
...useFullscreen(wrapperRef), ...useFullscreen(wrapperRef),
...useVolume(), ...useVolume(),
...useVideoQuality(playerRef),
} }
} }

@ -0,0 +1,73 @@
import type { RefObject } from 'react'
import {
useMemo,
useState,
useEffect,
useCallback,
} from 'react'
import ReactPlayer from 'react-player'
import Hls from 'hls.js'
import map from 'lodash/map'
import find from 'lodash/find'
import uniqBy from 'lodash/uniqBy'
import orderBy from 'lodash/orderBy'
const getVideoQualities = (hls: Hls | null) => {
const qualities = map(hls?.levels, (level, i) => ({
level: i,
quality: String(level.height),
}))
const sorted = orderBy(
qualities,
Number,
'desc',
)
return uniqBy(sorted, 'quality')
}
export const useVideoQuality = (ref: RefObject<ReactPlayer>) => {
const hls = ref.current?.getInternalPlayer('hls') as Hls | null
const videoQualities = useMemo(() => getVideoQualities(hls), [hls])
const [selectedQuality, setSelectedQuality] = useState('')
useEffect(() => {
const initialQuality = find(videoQualities, { level: hls?.currentLevel })
if (initialQuality) {
setSelectedQuality(initialQuality.quality)
}
}, [hls, videoQualities])
// подписываемся на изменение качества,
// тк плеер может сам подбирать качество пользователю
// на основе скорости интернета
useEffect(() => {
if (!hls) return undefined
const listener = (event: string, { level }: Hls.levelSwitchedData) => {
const item = find(videoQualities, { level })
if (item) {
setSelectedQuality(item.quality)
}
}
hls.on(Hls.Events.LEVEL_SWITCHED, listener)
return () => {
hls.off(Hls.Events.LEVEL_SWITCHED, listener)
}
}, [hls, videoQualities])
const onQualitySelect = useCallback((quality: string) => {
const item = find(videoQualities, { quality })
if (hls && item) {
hls.currentLevel = item.level
}
}, [hls, videoQualities])
return {
onQualitySelect,
selectedQuality,
videoQualities: map(videoQualities, 'quality'),
}
}

@ -1,5 +1,7 @@
import React from 'react' import React from 'react'
import { Settings } from 'features/MultiSourcePlayer/components/Settings'
import { streamConfig, progressCallbackInterval } from './config' import { streamConfig, progressCallbackInterval } from './config'
import type { Props } from './hooks' import type { Props } from './hooks'
import { useVideoPlayer } from './hooks' import { useVideoPlayer } from './hooks'
@ -24,14 +26,17 @@ export const StreamPlayer = (props: Props) => {
onFullscreenClick, onFullscreenClick,
onPlayerClick, onPlayerClick,
onProgressChange, onProgressChange,
onQualitySelect,
onVolumeChange, onVolumeChange,
onVolumeClick, onVolumeClick,
playedProgress, playedProgress,
playerRef, playerRef,
playing, playing,
selectedQuality,
setProgress, setProgress,
startPlaying, startPlaying,
togglePlaying, togglePlaying,
videoQualities,
volume, volume,
wrapperRef, wrapperRef,
} = useVideoPlayer(props) } = useVideoPlayer(props)
@ -73,6 +78,11 @@ export const StreamPlayer = (props: Props) => {
playedProgress={playedProgress} playedProgress={playedProgress}
loadedProgress={loadedProgress} loadedProgress={loadedProgress}
/> />
<Settings
onSelect={onQualitySelect}
selectedQuality={selectedQuality}
videoQualities={videoQualities}
/>
<Fullscreen onClick={onFullscreenClick} isFullscreen={isFullscreen} /> <Fullscreen onClick={onFullscreenClick} isFullscreen={isFullscreen} />
</Controls> </Controls>
</PlayerWrapper> </PlayerWrapper>

Loading…
Cancel
Save