"use client"; import { useEffect, useState, useCallback, useRef } from "react"; export function useCast() { const [castAvailable, setCastAvailable] = useState(false); const [isCasting, setIsCasting] = useState(false); const [castDeviceName, setCastDeviceName] = useState(null); const initialized = useRef(false); useEffect(() => { if (initialized.current) return; initialized.current = true; const init = () => { const ctx = cast.framework.CastContext.getInstance(); ctx.setOptions({ receiverApplicationId: chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID, autoJoinPolicy: chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED, }); ctx.addEventListener( cast.framework.CastContextEventType.CAST_STATE_CHANGED, (e) => { const casting = e.castState === cast.framework.CastState.CONNECTED; setIsCasting(casting); setCastDeviceName( casting ? (ctx.getCurrentSession()?.getCastDevice().friendlyName ?? null) : null ); setCastAvailable(e.castState !== cast.framework.CastState.NO_DEVICES_AVAILABLE); }, ); const state = ctx.getCastState(); setCastAvailable(state !== cast.framework.CastState.NO_DEVICES_AVAILABLE); setIsCasting(state === cast.framework.CastState.CONNECTED); }; if (window.cast?.framework) { init(); } else { window.__onGCastApiAvailable = (isAvailable: boolean) => { if (isAvailable) init(); }; } }, []); const requestCast = useCallback(async (streamUrl: string) => { if (!window.cast?.framework) return; const ctx = cast.framework.CastContext.getInstance(); let session = ctx.getCurrentSession(); if (!session) { const err = await ctx.requestSession(); if (err) return; session = ctx.getCurrentSession(); } if (!session) return; const mediaInfo = new chrome.cast.media.MediaInfo(streamUrl, "application/x-mpegURL"); await session.loadMedia(new chrome.cast.media.LoadRequest(mediaInfo)); }, []); const stopCasting = useCallback(() => { window.cast?.framework.CastContext.getInstance().endCurrentSession(true); }, []); return { castAvailable, isCasting, castDeviceName, requestCast, stopCasting }; }