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

DE-6596: VU meter component #15

Merged
merged 8 commits into from
Oct 13, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@
(or `PrestoContext`), in which case it is not necessary to pass the `player` argument anymore.
* `HoverContainer` no longer accepts props `listenToHover` and `notTrackFullWidth`.

## New Features

* VU Meter component.

## Fixes

* Fixes to `BaseThemeOverlay`:
Expand Down
43 changes: 28 additions & 15 deletions src/Player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ export type PlayerInitializer = (presto: clpp.Player) => void
*/
type Action = () => Promise<void>

type Range = {
start: number
end: number
}

/**
* Player states
*/
Expand Down Expand Up @@ -334,7 +339,7 @@ export class Player {
*
* @private
*/
private _config: clpp.LoadConfig | null = null
private _config: clpp.PlayerConfiguration | null = null

/**
* Indicate that the config was loaded
Expand Down Expand Up @@ -395,15 +400,20 @@ export class Player {
this.pp_.on(clpp.events.VIDEO_TRACK_CHANGED, handlePlayerTracksChanged('video'))
this.pp_.on(clpp.events.TEXT_TRACK_CHANGED, handlePlayerTracksChanged('text'))

this.pp_.on(clpp.events.STATE_CHANGED, (event: clpp.Event) => {
const e = event as clpp.StateChangeEvent
this.pp_.on(clpp.events.STATE_CHANGED, (event: any) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const e = event
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
const currentState = toState(e.detail.currentState)
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
const previousState = toState(e.detail.previousState)

this.emitUIEvent('statechanged', {
currentState,
previousState,
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
reason: e.detail.reason,
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
timeSinceLastStateChangeMS: e.detail.timeSinceLastStateChangeMS,
})

Expand Down Expand Up @@ -448,9 +458,9 @@ export class Player {
})
})

this.pp_.on(clpp.events.BITRATE_CHANGED, (e: clpp.Event) => {
this.pp_.on(clpp.events.BITRATE_CHANGED, (e: any) => {
const tm = this.trackManager

if (tm) {
this.playingVideoTrack = fromPrestoTrack(tm, e.detail.rendition as clpp.Rendition, 'video')
} else {
Expand Down Expand Up @@ -530,12 +540,12 @@ export class Player {
return this.pp_ ? this.pp_.isLive() : false
}

get seekRange(): { start: number; end: number } {
return this.pp_ ? this.pp_.getSeekRange() : { start: 0, end: 0 }
get seekRange(): Range {
return this.pp_ ? this.pp_.getSeekRange() as Range : { start: 0, end: 0 }
}

get volume(): number {
return this.pp_ ? this.pp_.getVolume() : 1
return this.pp_ ? this.pp_.getVolume() ?? 0 : 1
}

set volume(volume: number) {
Expand All @@ -548,7 +558,7 @@ export class Player {
}

get muted() {
return this.pp_ ? this.pp_.isMuted() : false
return this.pp_ ? this.pp_.isMuted() ?? false : false
}

set muted(muted: boolean) {
Expand Down Expand Up @@ -596,7 +606,7 @@ export class Player {
}
}

load(config?: clpp.LoadConfig, autoload = false) {
load(config?: clpp.PlayerConfiguration, autoload = false) {
if (config) {
this._config = config
return this.action(async () => {
Expand Down Expand Up @@ -705,9 +715,8 @@ export class Player {

async presto(): Promise<clpp.Player> {
await this._actionQueuePromise
// @ts-ignore I am not sure if this.pp_ is
// always defined here or if it can possibly be null...
return this.pp_
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
return (this.pp_ as clpp.Player)
}

/**
Expand Down Expand Up @@ -788,7 +797,8 @@ export class Player {

set videoTracks(value: Track[]) {
value = value.filter(v => {
// @ts-ignore type conflicet between Track and Rendition
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore type conflict between Track and Rendition
return v.ppTrack && v.ppTrack.height && v.ppTrack.width
})
if (value.length > 0 && !value.find(t => t.id === 'abr')) {
Expand Down Expand Up @@ -828,18 +838,21 @@ export class Player {
} else {
track.selected = true
if (track.type === 'audio') {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
fingerartur marked this conversation as resolved.
Show resolved Hide resolved
// @ts-ignore Rendition is not assignable to Track
// there is a type conflict
tm.setAudioTrack(track.ppTrack)
this.audioTrack = getActiveTrack(tm, 'audio')
this.audioTracks = getTracks(tm, 'audio')
} else if (track.type === 'text') {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore Rendition is not assignable to Track
// there is a type conflict
tm.setTextTrack(track.ppTrack)
this.textTrack = getActiveTrack(tm, 'text')
this.textTracks = getTracks(tm, 'text')
} else if (track.type === 'video') {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore Track is not assignable to Rendition
// there is a miss match between the types
tm.setVideoRendition(track.ppTrack, true)
Expand Down
4 changes: 2 additions & 2 deletions src/components/MuteButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ export const MuteButton = (props: MuteButtonProps) => {
const enabled = usePrestoEnabledState()

usePrestoCoreEvent('volumechange', (e, presto) => {
setMuted(presto.isMuted())
setMuted(presto.isMuted() ?? false)
thasso marked this conversation as resolved.
Show resolved Hide resolved
})
usePrestoCoreEvent('loadedmetadata', (e, presto) => {
setMuted(presto.isMuted())
setMuted(presto.isMuted() ?? false)
})

function toggle(e: React.MouseEvent) {
Expand Down
2 changes: 1 addition & 1 deletion src/components/PlayerSurface.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export interface PlayerProps extends BaseComponentProps {
* The PRESTOplay player configuration to load and play a video
* https://demo.castlabs.com/#/docs?q=clpp#PlayerConfiguration
*/
config?: clpp.LoadConfig
config?: clpp.PlayerConfiguration
/**
* The PRESTOplay player configuration to initialize the player
* https://demo.castlabs.com/#/docs?q=clpp#PlayerConfiguration
Expand Down
2 changes: 1 addition & 1 deletion src/components/Thumbnail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export interface ThumbnailProps extends BaseComponentProps {
*/
const usePlugin = () => {
const { presto } = useContext(PrestoContext)
return presto.getPlugin(clpp.thumbnails.ThumbnailsPlugin.Id) as clpp.ThumbnailsPlugin | null
return presto.getPlugin(clpp.thumbnails.ThumbnailsPlugin.Id) as clpp.thumbnails.ThumbnailsPlugin | null
}

const DEFAULT_STYLE = { height: 130 }
Expand Down
4 changes: 3 additions & 1 deletion src/components/VolumeBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ export const VolumeBar = (props: VolumeBarProps) => {
const presto = await player.presto()
const current = presto.isMuted() ? 0 : presto.getVolume()
let targetPosition = current


if (targetPosition == null || current == null) {return}

if (e.key === 'ArrowLeft') {
targetPosition = Math.max(0, current + (-0.1))
e.preventDefault()
Expand Down
33 changes: 33 additions & 0 deletions src/components/VuMeter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React, { useCallback, useContext, useEffect, useRef } from 'react'

import { PrestoContext } from '../context/PrestoContext'
import { VolumeMeterService, VuMeterConfig } from '../services/volumeMeterService'

import type { BaseComponentProps } from './types'

export type Props = BaseComponentProps & {
config?: VuMeterConfig
width: number
height: number
}

/**
* Volume Unit Meter
*/
export const VuMeter = (props: Props) => {
const ctx = useContext(PrestoContext)
const serviceRef = useRef(new VolumeMeterService(ctx.presto))

const onRef = useCallback((canvas: HTMLCanvasElement) => {
serviceRef.current.configure(canvas, props.config ?? {})
serviceRef.current.mount()
}, [])

useEffect(() => {
return () => {
serviceRef.current.unmount()
}
}, [])

return <canvas ref={onRef} style={props.style} className={props.className} width={props.width} height={props.height}/>
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,6 @@ export * from './components/TrackSelectionList'
export * from './components/VerticalBar'
export * from './components/VolumeBar'
export * from './components/PlayPauseIndicator'
export * from './components/VuMeter'

export * from './context/PrestoContext'
4 changes: 2 additions & 2 deletions src/react.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { PrestoContext } from './context/PrestoContext'
import { EventListener, EventType } from './EventEmitter'
import { Player, State, UIEvents } from './Player'

export type ClppEventHandler = (e: clpp.Event, presto: clpp.Player) => void
fingerartur marked this conversation as resolved.
Show resolved Hide resolved
export type ClppEventHandler = (e: any, presto: clpp.Player) => void

/**
* This is a React hook that can be used to listen to presto play events.
Expand All @@ -28,7 +28,7 @@ export function usePrestoCoreEvent(
const presto = useContext(PrestoContext).presto ?? presto_

useEffect(() => {
const handleEvent = (event: clpp.Event) => {
const handleEvent = (event: any) => {
handler(event, presto)
}

Expand Down
Loading