UNPKG

bitmovin-player-ui

Version:
150 lines (127 loc) 4.96 kB
import { SeekBar, SeekBarConfig, SeekPreviewEventArgs } from './SeekBar'; import { UIInstanceManager } from '../../UIManager'; import { PlayerAPI } from 'bitmovin-player'; import { VolumeTransition } from '../../utils/VolumeController'; import { i18n } from '../../localization/i18n'; import { BrowserUtils } from '../../utils/BrowserUtils'; /** * Configuration interface for the {@link VolumeSlider} component. * * @category Configs */ export interface VolumeSliderConfig extends SeekBarConfig { /** * Specifies if the volume slider should be automatically hidden when volume control is prohibited by the * browser or platform. This currently only applies to iOS. * Default: true */ hideIfVolumeControlProhibited?: boolean; /** * Specifies if the volume slider should be automatically hidden on mobile devices. * Default: true */ hideOnMobile?: boolean; } /** * A simple volume slider component to adjust the player's volume setting. * * @category Components */ export class VolumeSlider extends SeekBar { private volumeTransition: VolumeTransition; constructor(config: VolumeSliderConfig = {}) { super(config); this.config = this.mergeConfig( config, <VolumeSliderConfig>{ cssClass: 'ui-volumeslider', hideIfVolumeControlProhibited: true, hideOnMobile: true, ariaLabel: i18n.getLocalizer('settings.audio.volume'), tabIndex: 0, }, this.config, ); } private setVolumeAriaSliderValues(value: number) { this.getDomElement().attr('aria-valuenow', Math.ceil(value).toString()); this.getDomElement().attr( 'aria-valuetext', `${i18n.performLocalization(i18n.getLocalizer('seekBar.value'))}: ${Math.ceil(value)}`, ); } configure(player: PlayerAPI, uimanager: UIInstanceManager): void { super.configure(player, uimanager, false); this.setAriaSliderMinMax('0', '100'); const config = <VolumeSliderConfig>this.getConfig(); const volumeController = uimanager.getConfig().volumeController; if ( (config.hideOnMobile && BrowserUtils.isMobile) || (config.hideIfVolumeControlProhibited && !this.detectVolumeControlAvailability()) ) { this.hide(); // We can just return from here, because the user will never interact with the control and any configured // functionality would only eat resources for no reason. return; } volumeController.onChanged.subscribe((_, args) => { if (args.muted) { this.setVolumeAriaSliderValues(0); this.setPlaybackPosition(0); } else { this.setPlaybackPosition(args.volume); this.setVolumeAriaSliderValues(args.volume); } }); this.onSeek.subscribe(() => { this.volumeTransition = volumeController.startTransition(); }); this.onSeekPreview.subscribeRateLimited(this.updateVolumeWhileScrubbing, 50); this.onSeeked.subscribe((sender, percentage) => { if (this.volumeTransition) { this.volumeTransition.finish(percentage); } }); // Update the volume slider marker when the player resized, a source is loaded, // or the UI is configured. Check the seekbar for a detailed description. player.on(player.exports.PlayerEvent.PlayerResized, () => { this.refreshPlaybackPosition(); }); uimanager.onConfigured.subscribe(() => { this.refreshPlaybackPosition(); }); uimanager.getConfig().events.onUpdated.subscribe(() => { this.refreshPlaybackPosition(); }); uimanager.onComponentShow.subscribe(() => { this.refreshPlaybackPosition(); }); uimanager.onComponentHide.subscribe(() => { this.refreshPlaybackPosition(); }); // Init volume bar volumeController.onChangedEvent(); } private updateVolumeWhileScrubbing = (sender: VolumeSlider, args: SeekPreviewEventArgs) => { if (args.scrubbing && this.volumeTransition) { this.volumeTransition.update(args.position); } }; private detectVolumeControlAvailability(): boolean { /* * "On iOS devices, the audio level is always under the user’s physical control. The volume property is not * settable in JavaScript. Reading the volume property always returns 1." * https://developer.apple.com/library/content/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/Device-SpecificConsiderations/Device-SpecificConsiderations.html */ // as muted autoplay gets paused as soon as we unmute it, we may not touch the volume of the actual player so we // probe a dummy audio element const dummyVideoElement = document.createElement('video'); // try setting the volume to 0.7 and if it's still 1 we are on a volume control restricted device dummyVideoElement.volume = 0.7; return dummyVideoElement.volume !== 1; } release(): void { super.release(); this.onSeekPreview.unsubscribe(this.updateVolumeWhileScrubbing); } }