9 changed files with 268 additions and 49 deletions
@ -0,0 +1,110 @@
@@ -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 @@
@@ -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 @@
@@ -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