Skip to content

Commit

Permalink
feat: added caption for hls stream
Browse files Browse the repository at this point in the history
  • Loading branch information
amar-1995 authored Dec 5, 2023
1 parent 3485674 commit c4ead84
Show file tree
Hide file tree
Showing 11 changed files with 105 additions and 11 deletions.
14 changes: 14 additions & 0 deletions packages/hls-player/src/controllers/HMSHLSPlayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export class HMSHLSPlayer implements IHMSHLSPlayer, IHMSHLSPlayerEventEmitter {
video.autoplay = true;
return video;
}

/**
* @returns get html video element
*/
Expand Down Expand Up @@ -194,6 +195,19 @@ export class HMSHLSPlayer implements IHMSHLSPlayer, IHMSHLSPlayerEventEmitter {
this._videoEl.currentTime = seekValue;
};

hasCaptions = () => {
return this._hls.subtitleTracks.length > 0;
};

toggleCaption = () => {
// no subtitles, do nothing
if (!this.hasCaptions()) {
return;
}
this._hls.subtitleDisplay = !this._hls.subtitleDisplay;
this.emitEvent(HMSHLSPlayerEvents.CAPTION_ENABLED, this._hls.subtitleDisplay);
};

private playVideo = async () => {
try {
if (this._videoEl.paused) {
Expand Down
1 change: 1 addition & 0 deletions packages/hls-player/src/interfaces/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ type HMSHLSListenerDataMapping = {
[HMSHLSPlayerEvents.TIMED_METADATA_LOADED]: HMSHLSCue;
[HMSHLSPlayerEvents.STATS]: HlsPlayerStats;
[HMSHLSPlayerEvents.PLAYBACK_STATE]: HMSHLSPlaybackState;
[HMSHLSPlayerEvents.CAPTION_ENABLED]: boolean;

[HMSHLSPlayerEvents.ERROR]: HMSHLSException;
[HMSHLSPlayerEvents.CURRENT_TIME]: number;
Expand Down
1 change: 1 addition & 0 deletions packages/hls-player/src/utilies/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export enum HMSHLSPlayerEvents {

MANIFEST_LOADED = 'manifest-loaded',
LAYER_UPDATED = 'layer-updated',
CAPTION_ENABLED = 'caption-enabled',

ERROR = 'error',
PLAYBACK_STATE = 'playback-state',
Expand Down
8 changes: 4 additions & 4 deletions packages/react-icons/assets/ClosedCaptionIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions packages/react-icons/assets/OpenCaptionIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 4 additions & 4 deletions packages/react-icons/src/ClosedCaptionIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import * as React from 'react';
import { SVGProps } from 'react';
const SvgClosedCaptionIcon = (props: SVGProps<SVGSVGElement>) => (
<svg width="24px" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
<rect x={3.625} y={5.625} width={16.75} height={11.75} rx={2.875} stroke="currentColor" strokeWidth={1.25} />
<svg width="24px" height="24px" viewBox="0 0 19 14" fill="currentColor" xmlns="http://www.w3.org/2000/svg" {...props}>
<path
d="M9.438 14.25c-.508 0-.944-.111-1.309-.334a2.233 2.233 0 0 1-.838-.924c-.194-.395-.291-.85-.291-1.364 0-.516.1-.972.298-1.367.199-.397.48-.706.841-.927C8.504 9.111 8.934 9 9.431 9c.413 0 .778.076 1.096.228.32.15.576.363.766.64.19.273.298.593.324.96h-1.146a1.096 1.096 0 0 0-.331-.613c-.172-.166-.403-.248-.692-.248-.245 0-.46.066-.646.198-.186.13-.33.318-.434.563a2.294 2.294 0 0 0-.152.88c0 .347.05.645.152.894.101.247.244.438.427.573.186.132.403.199.653.199.176 0 .334-.034.473-.1a.951.951 0 0 0 .355-.294c.095-.128.16-.284.195-.467h1.146c-.029.36-.135.678-.318.957a1.883 1.883 0 0 1-.748.648c-.316.155-.687.232-1.113.232ZM14.82 14.25c-.507 0-.943-.111-1.308-.334a2.233 2.233 0 0 1-.838-.924c-.194-.395-.291-.85-.291-1.364 0-.516.1-.972.298-1.367.199-.397.48-.706.841-.927.365-.223.795-.334 1.292-.334.413 0 .778.076 1.096.228.32.15.575.363.765.64.19.273.299.593.325.96h-1.146a1.095 1.095 0 0 0-.331-.613c-.172-.166-.403-.248-.692-.248-.245 0-.46.066-.646.198-.186.13-.33.318-.434.563a2.296 2.296 0 0 0-.152.88c0 .347.05.645.152.894.101.247.244.438.427.573.186.132.403.199.653.199.176 0 .334-.034.473-.1a.952.952 0 0 0 .355-.294 1.13 1.13 0 0 0 .195-.467H17c-.029.36-.135.678-.318.957a1.882 1.882 0 0 1-.748.648c-.316.155-.687.232-1.113.232Z"
fill="currentColor"
fillRule="evenodd"
clipRule="evenodd"
d="M14 .333H4.833A4.167 4.167 0 0 0 .667 4.5v5a4.167 4.167 0 0 0 4.166 4.167H14A4.167 4.167 0 0 0 18.166 9.5v-5A4.167 4.167 0 0 0 14 .333ZM4.9 9.545c.426.248.935.372 1.527.372.497 0 .93-.086 1.299-.258.368-.174.659-.414.873-.72.214-.31.337-.664.37-1.064H7.634a1.226 1.226 0 0 1-.228.519 1.1 1.1 0 0 1-.414.327c-.162.074-.346.11-.552.11-.291 0-.545-.073-.761-.22a1.458 1.458 0 0 1-.499-.636c-.118-.277-.178-.608-.178-.993 0-.38.06-.707.178-.979.121-.272.29-.48.506-.625.217-.147.468-.22.754-.22.337 0 .606.091.807.275a1.2 1.2 0 0 1 .387.68H8.97a2.034 2.034 0 0 0-.379-1.066 2.163 2.163 0 0 0-.893-.71 3.052 3.052 0 0 0-1.279-.254c-.58 0-1.081.124-1.507.372a2.52 2.52 0 0 0-.981 1.03c-.232.439-.348.945-.348 1.519 0 .571.114 1.076.34 1.515.23.436.555.779.978 1.026Zm6.281 0c.425.248.934.372 1.526.372.497 0 .93-.086 1.299-.258.368-.174.66-.414.873-.72.214-.31.337-.664.37-1.064h-1.336a1.225 1.225 0 0 1-.228.519 1.1 1.1 0 0 1-.414.327c-.162.074-.346.11-.552.11-.291 0-.545-.073-.761-.22a1.458 1.458 0 0 1-.499-.636c-.118-.277-.178-.608-.178-.993 0-.38.06-.707.178-.979.121-.272.29-.48.506-.625.217-.147.468-.22.754-.22.337 0 .607.091.808.275a1.2 1.2 0 0 1 .386.68h1.337a2.034 2.034 0 0 0-.379-1.066 2.163 2.163 0 0 0-.892-.71 3.052 3.052 0 0 0-1.28-.254c-.579 0-1.081.124-1.506.372-.423.245-.75.588-.982 1.03-.232.439-.348.945-.348 1.519 0 .571.114 1.076.34 1.515.23.436.556.779.978 1.026Z"
/>
</svg>
);
Expand Down
13 changes: 13 additions & 0 deletions packages/react-icons/src/OpenCaptionIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import * as React from 'react';
import { SVGProps } from 'react';
const SvgOpenCaptionIcon = (props: SVGProps<SVGSVGElement>) => (
<svg width="24px" height="24px" viewBox="0 0 18 14" fill="currentColor" xmlns="http://www.w3.org/2000/svg" {...props}>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M4.635.333h8.73a3.968 3.968 0 0 1 3.968 3.969v4.761a3.968 3.968 0 0 1-3.968 3.969h-8.73A3.968 3.968 0 0 1 .667 9.063V4.302A3.968 3.968 0 0 1 4.635.333ZM1.857 4.302a2.778 2.778 0 0 1 2.778-2.778h8.73a2.778 2.778 0 0 1 2.778 2.778v4.761a2.778 2.778 0 0 1-2.778 2.778h-8.73a2.778 2.778 0 0 1-2.778-2.778V4.302Z"
/>
<path d="M6.153 9.46c-.564 0-1.049-.118-1.454-.354a2.41 2.41 0 0 1-.93-.977c-.217-.418-.325-.899-.325-1.443 0-.546.11-1.029.332-1.447a2.4 2.4 0 0 1 .934-.98c.405-.236.884-.354 1.436-.354.458 0 .864.08 1.218.241.355.16.639.385.85.676.21.29.33.629.36 1.016H7.301a1.144 1.144 0 0 0-.368-.648c-.191-.175-.448-.262-.77-.262-.271 0-.51.07-.717.21a1.357 1.357 0 0 0-.482.595c-.113.26-.17.57-.17.932 0 .367.057.682.17.946.113.261.271.463.475.606.206.14.448.21.725.21.196 0 .372-.035.526-.105.157-.073.288-.176.394-.312.105-.135.178-.3.217-.494h1.273c-.032.38-.15.718-.353 1.013-.204.291-.48.52-.832.686-.35.164-.763.245-1.236.245ZM12.134 9.46c-.564 0-1.049-.118-1.454-.354a2.41 2.41 0 0 1-.93-.977c-.217-.418-.325-.899-.325-1.443 0-.546.11-1.029.332-1.447a2.4 2.4 0 0 1 .934-.98c.405-.236.884-.354 1.436-.354.458 0 .864.08 1.218.241.355.16.639.385.85.676.21.29.331.629.36 1.016h-1.273a1.144 1.144 0 0 0-.368-.648c-.191-.175-.448-.262-.769-.262-.272 0-.511.07-.718.21a1.357 1.357 0 0 0-.482.595c-.113.26-.169.57-.169.932 0 .367.056.682.17.946.112.261.27.463.474.606.206.14.448.21.725.21.196 0 .372-.035.526-.105.157-.073.289-.176.394-.312.106-.135.178-.3.217-.494h1.273c-.031.38-.15.718-.353 1.013-.204.291-.48.52-.832.686-.35.164-.762.245-1.236.245Z" />
</svg>
);
export default SvgOpenCaptionIcon;
1 change: 1 addition & 0 deletions packages/react-icons/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ export { default as NoEntryIcon } from './NoEntryIcon';
export { default as NotificationsIcon } from './NotificationsIcon';
export { default as OfferIcon } from './OfferIcon';
export { default as OpenBookIcon } from './OpenBookIcon';
export { default as OpenCaptionIcon } from './OpenCaptionIcon';
export { default as PipIcon } from './PipIcon';
export { default as PadLockOnIcon } from './PadLockOnIcon';
export { default as PaletteIcon } from './PaletteIcon';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';
import { ClosedCaptionIcon, OpenCaptionIcon } from '@100mslive/react-icons';
import { IconButton } from '../../../';

export function HLSCaptionSelector({ isEnabled, onClick }: { isEnabled: boolean; onClick: () => void }) {
return (
<IconButton css={{ p: '$2' }} onClick={() => onClick()}>
{isEnabled ? <ClosedCaptionIcon width="20" height="20px" /> : <OpenCaptionIcon width="20" height="20px" />}
</IconButton>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,44 @@ import { Flex } from '../../../';

export const HMSVideo = forwardRef(({ children, ...props }, videoRef) => {
return (
<Flex data-testid="hms-video" css={{ size: '100%', position: 'relative' }} direction="column" {...props}>
<video style={{ flex: '1 1 0', margin: '0 auto', minHeight: '0' }} ref={videoRef} playsInline />
<Flex
data-testid="hms-video"
css={{
size: '100%',
position: 'relative',
'& video::cue': {
backgroundColor: '#000',
color: 'white',
opacity: 0.75,
textShadow: '0px 0px 4px #000',
whiteSpace: 'pre-line',
fontSize: '$lg',
fontStyle: 'normal',
fontWeight: '$semiBold',
lineHeight: '$sm',
letterSpacing: '0.5px',
},
'& video::-webkit-media-text-track-display': {
backgroundColor: '#000',
opacity: 0.75,
padding: '0 $4',
},
'& video::-webkit-media-text-track-container': {
fontSize: '$space$10 !important',
},
}}
direction="column"
{...props}
>
<video
style={{
flex: '1 1 0',
margin: '0 auto',
minHeight: '0',
}}
ref={videoRef}
playsInline
/>
{children}
</Flex>
);
Expand Down
Loading

0 comments on commit c4ead84

Please sign in to comment.