/react-cast

⚛️ Context-based Cast Library for React (Supports Chromecast and Airplay)

Primary LanguageTypeScriptGNU General Public License v3.0GPL-3.0

logo

react-cast

Note: This library is highly unfinished and should not be considered for production.

Context-based Chromecast Library for React

# add dependency
yarn add @jakehwll/react-cast

Features

Features

  • Send to Chromecast via browser.
  • Send URL to Chromecast to play.
  • Control playback with play(), pause(), stop().
  • (Partially implemented) Get audio and control with volume and setVolume.
  • (Partially implemented) Get currentTime and control with seek()
  • Watches events for updates on chromecast device.

Planned Features

  • Queues support.
  • Live playback support.
  • Advertisements support.
  • androidReceiverCompatible support.
  • autoJoinPolicy/receiveApplicationId support.

Usage

To use react-cast you need to wrap all your elements with a <ReactCast /> element.

This will provide both the CastPlayerContext and PlayerHandlerContext to be used by your app.

  • CastPlayerContext stores things like the chromecast session and players current playerState.
  • PlayerHandlerContext stores things like the play() and pause() functions along with the currentTime, duration, isMuted etc.
<ReactCast>{/** Logic goes here. **/}</ReactCast>

useContext(PlayerHandlerContext)

useContext(PlayerHandlerContext) will return an object with..

Casting

  • useCast() Starts the cast session between sender and receiver.
  • useMedia(value) Begins the playback of a piece of media to the receiver.
import { PlayerHandlerContext } from 'react-cast/contexts/player'

const Casting = () => {
  const { useCast, useMedia } = useContext(PlayerHandlerContext)
  return (
    <>
      {/** Initiate a connection between sender and receiver. **/}
      <button type='button' onClick={() => useCast()}>
        Cast
      </button>
      {/** Send some media from the sender to the receiver to render. **/}
      <button
        type='button'
        onClick={() =>
          useMedia({
            url: 'https://commondatastorage.googleapis.com/gtv-videos-bucketbig_buck_bunny_1080p.mp4',
            contentType: 'video/mp4',
          })
        }
      >
        Media
      </button>
    </>
  )
}

Playback

  • play() Begins/resumes playback of a already casted video.
  • pause() Pauses playback of a already casted video.
  • stop() Stop and removes all the currently casted videos.
import { PlayerHandlerContext } from 'react-cast/contexts/player'

const Playback = () => {
  const { play, pause, stop } = useContext(PlayerHandlerContext)
  return (
    <>
      <button type='button' onClick={() => play()}>
        Play
      </button>
      <button type='button' onClick={() => pause()}>
        Pause
      </button>
      <button type='button' onClick={() => stop()}>
        Stop
      </button>
    </>
  )
}

Playback Controls

  • isPlaying Whether the player is currently playing back content or not.
  • isBuffering Whether the player is currently buffering/loading the content.
  • isIdle Whether player has content to render or not.
import { PlayerHandlerContext } from 'react-cast/contexts/player'

const PlaybackControls = () => {
  const { play, pause, isPlaying, isBuffering, isIdle } = useContext(PlayerHandlerContext)

  if ( isIdle ): return <>{/** NO ICON **/}</>
  else if ( isBuffering ): return <>{/** BUFFERING ICON **/}</>
  else:
    { isPlaying ?
      <button type="button" onClick={() => pause()}>{/** PAUSE ICON **/}</button> :
      <button type="button" onClick={() => play()}>{/** PLAY ICON **/}</button> }
}

Audio

  • setVolume(val) Sets the players volume to a range between 0.0 and 1.0.
  • mute() Completely mutes the output of the player.
  • unmute() Complete unmutes the output of the player. (Issue)
  • isMuted A boolean value as to whether the current output is muted or not.
import { PlayerHandlerContext } from 'react-cast/contexts/player'

const Volume = () => {
  const { mute, unmute, setVolume } = useContext(PlayerHandlerContext)
  return (
    <>
      <button type='button' onClick={() => mute()}>
        Mute
      </button>
      <button type='button' onClick={() => unmute()}>
        Unmute
      </button>
      <input
        type='range'
        defaultValue={100}
        min={0}
        max={100}
        onChange={(event) => {
          setVolume(parseInt(event.target.value) / 100)
        }}
      />
    </>
  )
}

Seeking

  • currentTime The current playhead of the player (Issue)
  • duration The complete duration length of the current loaded media.
  • seekTo(val: number) Jumps the player to the provided val index.
const Seeker = () => {
  return (
    <>
      <span>{currentTime}</span>
      <input
        type='range'
        value={currentTime ?? 0}
        min={0}
        max={duration ?? 0}
        onChange={(event) => {
          seekTo(parseInt(event.target.value))
        }}
      />
      <span>{duration}</span>
    </>
  )
}

useContext(CastPlayerContext)

useContext(CastPlayerContext) will return an object with..

Sessions

  • session The current chrome.cast.Session if one is defined.
const { session } = useContext(CastPlayerContext)
const Session = () => {
  return (
    <>
      <span>
        Are we currently casting? {(session !== undefined).toString()}
      </span>
    </>
  )
}

States

Note: This is mostly for internal tracking of the state, if you're looking to create a UI please see the example in Playback

  • playerState The current state of the player, valid elements are contained in VALID_STATES
  • setPlayerState Takes a string from VALID_STATES
import { CastPlayerContext } from 'react-cast/contexts/cast'

const State = () => {
  const { playerState } = useContext(CastPlayerContext)

  return (
    <>
      Current player state: {playerState}
      <ul>
        <li>Idle? {(playerState === 'IDLE').toString()}</li>
        <li>Buffering? {(playerState === 'BUFFERING').toString()}</li>
        <li>Loaded? {(playerState === 'LOADED').toString()}</li>
        <li>Playing? {(playerState === 'PLAYING').toString()}</li>
        <li>Paused? {(playerState === 'PAUSED').toString()}</li>
      </ul>
    </>
  )
}

Media Info

{
  /** TODO **/
}

Development

The easiest way to get started is by running the following commands.

# install dependencies
yarn install
# build code
yarn build

Contributing

Checkout our Contributing guidelines.