9 changed files with 268 additions and 49 deletions
@ -0,0 +1,110 @@ |
|||||||
|
/// <reference types="chromecast-caf-sender"/>
|
||||||
|
|
||||||
|
import { isChromecastAvailable } from "@/setup/chromecast"; |
||||||
|
import { useEffect, useRef, useState } from "react"; |
||||||
|
|
||||||
|
export function useChromecastAvailable() { |
||||||
|
const [available, setAvailable] = useState<boolean | null>(null); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
isChromecastAvailable((bool) => setAvailable(bool)); |
||||||
|
}, []); |
||||||
|
|
||||||
|
return available; |
||||||
|
} |
||||||
|
|
||||||
|
export function useChromecast() { |
||||||
|
const available = useChromecastAvailable(); |
||||||
|
const instance = useRef<cast.framework.CastContext | null>(null); |
||||||
|
const remotePlayerController = |
||||||
|
useRef<cast.framework.RemotePlayerController | null>(null); |
||||||
|
|
||||||
|
function startCast() { |
||||||
|
const movieMeta = new chrome.cast.media.MovieMediaMetadata(); |
||||||
|
movieMeta.title = "Big Buck Bunny"; |
||||||
|
|
||||||
|
const mediaInfo = new chrome.cast.media.MediaInfo("hello", "video/mp4"); |
||||||
|
(mediaInfo as any).contentUrl = |
||||||
|
"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"; |
||||||
|
mediaInfo.streamType = chrome.cast.media.StreamType.BUFFERED; |
||||||
|
mediaInfo.metadata = movieMeta; |
||||||
|
|
||||||
|
const request = new chrome.cast.media.LoadRequest(mediaInfo); |
||||||
|
request.autoplay = true; |
||||||
|
|
||||||
|
const session = instance.current?.getCurrentSession(); |
||||||
|
console.log("testing", session); |
||||||
|
if (!session) return; |
||||||
|
|
||||||
|
session |
||||||
|
.loadMedia(request) |
||||||
|
.then(() => { |
||||||
|
console.log("Media is loaded"); |
||||||
|
}) |
||||||
|
.catch((e: any) => { |
||||||
|
console.error(e); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
function stopCast() { |
||||||
|
const session = instance.current?.getCurrentSession(); |
||||||
|
if (!session) return; |
||||||
|
|
||||||
|
const controller = remotePlayerController.current; |
||||||
|
if (!controller) return; |
||||||
|
controller.stop(); |
||||||
|
} |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
if (!available) return; |
||||||
|
|
||||||
|
// setup instance if not already
|
||||||
|
if (!instance.current) { |
||||||
|
const ins = cast.framework.CastContext.getInstance(); |
||||||
|
ins.setOptions({ |
||||||
|
receiverApplicationId: chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID, |
||||||
|
autoJoinPolicy: chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED, |
||||||
|
}); |
||||||
|
instance.current = ins; |
||||||
|
} |
||||||
|
|
||||||
|
// setup player if not already
|
||||||
|
if (!remotePlayerController.current) { |
||||||
|
const player = new cast.framework.RemotePlayer(); |
||||||
|
const controller = new cast.framework.RemotePlayerController(player); |
||||||
|
remotePlayerController.current = controller; |
||||||
|
} |
||||||
|
|
||||||
|
// setup event listener
|
||||||
|
function listenToEvents(e: cast.framework.RemotePlayerChangedEvent) { |
||||||
|
console.log("chromecast event", e); |
||||||
|
} |
||||||
|
function connectionChanged(e: cast.framework.RemotePlayerChangedEvent) { |
||||||
|
console.log("chromecast event connection changed", e); |
||||||
|
} |
||||||
|
remotePlayerController.current.addEventListener( |
||||||
|
cast.framework.RemotePlayerEventType.PLAYER_STATE_CHANGED, |
||||||
|
listenToEvents |
||||||
|
); |
||||||
|
remotePlayerController.current.addEventListener( |
||||||
|
cast.framework.RemotePlayerEventType.IS_CONNECTED_CHANGED, |
||||||
|
connectionChanged |
||||||
|
); |
||||||
|
|
||||||
|
return () => { |
||||||
|
remotePlayerController.current?.removeEventListener( |
||||||
|
cast.framework.RemotePlayerEventType.PLAYER_STATE_CHANGED, |
||||||
|
listenToEvents |
||||||
|
); |
||||||
|
remotePlayerController.current?.removeEventListener( |
||||||
|
cast.framework.RemotePlayerEventType.IS_CONNECTED_CHANGED, |
||||||
|
connectionChanged |
||||||
|
); |
||||||
|
}; |
||||||
|
}, [available]); |
||||||
|
|
||||||
|
return { |
||||||
|
startCast, |
||||||
|
stopCast, |
||||||
|
}; |
||||||
|
} |
@ -0,0 +1,30 @@ |
|||||||
|
const CHROMECAST_SENDER_SDK = |
||||||
|
"https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"; |
||||||
|
|
||||||
|
const callbacks: ((available: boolean) => void)[] = []; |
||||||
|
let _available: boolean | null = null; |
||||||
|
|
||||||
|
function init(available: boolean) { |
||||||
|
_available = available; |
||||||
|
callbacks.forEach((cb) => cb(available)); |
||||||
|
} |
||||||
|
|
||||||
|
export function isChromecastAvailable(cb: (available: boolean) => void) { |
||||||
|
if (_available !== null) return cb(_available); |
||||||
|
callbacks.push(cb); |
||||||
|
} |
||||||
|
|
||||||
|
export function initializeChromecast() { |
||||||
|
window.__onGCastApiAvailable = (isAvailable) => { |
||||||
|
init(isAvailable); |
||||||
|
}; |
||||||
|
|
||||||
|
// add script if doesnt exist yet
|
||||||
|
const exists = !!document.getElementById("chromecast-script"); |
||||||
|
if (!exists) { |
||||||
|
const script = document.createElement("script"); |
||||||
|
script.setAttribute("src", CHROMECAST_SENDER_SDK); |
||||||
|
script.setAttribute("id", "chromecast-script"); |
||||||
|
document.body.appendChild(script); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,35 @@ |
|||||||
|
import { |
||||||
|
useChromecast, |
||||||
|
useChromecastAvailable, |
||||||
|
} from "@/hooks/useChromecastAvailable"; |
||||||
|
import { useEffect, useRef } from "react"; |
||||||
|
|
||||||
|
function ChromeCastButton() { |
||||||
|
const ref = useRef<HTMLDivElement>(null); |
||||||
|
const available = useChromecastAvailable(); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
if (!available) return; |
||||||
|
const tag = document.createElement("google-cast-launcher"); |
||||||
|
tag.setAttribute("id", "castbutton"); |
||||||
|
ref.current?.appendChild(tag); |
||||||
|
}, [available]); |
||||||
|
|
||||||
|
return <div ref={ref} />; |
||||||
|
} |
||||||
|
|
||||||
|
export function TestView() { |
||||||
|
const { startCast, stopCast } = useChromecast(); |
||||||
|
|
||||||
|
return ( |
||||||
|
<div> |
||||||
|
<ChromeCastButton /> |
||||||
|
<button type="button" onClick={startCast}> |
||||||
|
Start casting |
||||||
|
</button> |
||||||
|
<button type="button" onClick={stopCast}> |
||||||
|
StopCasting |
||||||
|
</button> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
Loading…
Reference in new issue