HLS playback enhancements
This commit is contained in:
@@ -54,7 +54,7 @@ export function Player() {
|
|||||||
const lcStation = activeStation.toLowerCase();
|
const lcStation = activeStation.toLowerCase();
|
||||||
const streamUrl = `https://stream.codey.lol/hls/${lcStation}/${lcStation}.m3u8?t=${Date.now()}`;
|
const streamUrl = `https://stream.codey.lol/hls/${lcStation}/${lcStation}.m3u8?t=${Date.now()}`;
|
||||||
|
|
||||||
// Cleanup existing stream
|
// Cleanup
|
||||||
if (hlsRef.current) {
|
if (hlsRef.current) {
|
||||||
hlsRef.current.destroy();
|
hlsRef.current.destroy();
|
||||||
hlsRef.current = null;
|
hlsRef.current = null;
|
||||||
@@ -64,37 +64,78 @@ export function Player() {
|
|||||||
if (!audio) return;
|
if (!audio) return;
|
||||||
|
|
||||||
if (audio.canPlayType("application/vnd.apple.mpegurl")) {
|
if (audio.canPlayType("application/vnd.apple.mpegurl")) {
|
||||||
// Native support (Safari)
|
|
||||||
audio.src = streamUrl;
|
audio.src = streamUrl;
|
||||||
|
audio.load();
|
||||||
audio.play().then(() => setIsPlaying(true)).catch(console.error);
|
audio.play().then(() => setIsPlaying(true)).catch(console.error);
|
||||||
} else if (Hls.isSupported()) {
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Hls.isSupported()) {
|
||||||
|
console.error("HLS not supported");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const hls = new Hls({
|
const hls = new Hls({
|
||||||
maxBufferLength: 30,
|
maxBufferLength: 30,
|
||||||
maxMaxBufferLength: 60,
|
maxMaxBufferLength: 60,
|
||||||
abrEwmaFastLive: 2.0,
|
|
||||||
abrEwmaSlowLive: 6.0,
|
|
||||||
abrBandWidthFactor: 0.95, // Bias toward higher quality
|
|
||||||
autoStartLoad: true,
|
autoStartLoad: true,
|
||||||
startLevel: -1, // adaptive start
|
startLevel: -1,
|
||||||
});
|
});
|
||||||
|
|
||||||
hls.loadSource(streamUrl);
|
|
||||||
hls.attachMedia(audio);
|
hls.attachMedia(audio);
|
||||||
|
|
||||||
hls.on(Hls.Events.ERROR, (_, data) => {
|
hls.on(Hls.Events.MEDIA_ATTACHED, () => {
|
||||||
|
hls.loadSource(streamUrl);
|
||||||
|
});
|
||||||
|
|
||||||
|
hls.on(Hls.Events.MANIFEST_PARSED, () => {
|
||||||
|
audio.play().then(() => setIsPlaying(true)).catch(console.error);
|
||||||
|
});
|
||||||
|
|
||||||
|
hls.on(Hls.Events.ERROR, (event, data) => {
|
||||||
|
console.warn("HLS error:", data);
|
||||||
|
|
||||||
if (data.fatal) {
|
if (data.fatal) {
|
||||||
console.error("HLS fatal error:", data);
|
switch (data.type) {
|
||||||
|
case Hls.ErrorTypes.NETWORK_ERROR:
|
||||||
|
case Hls.ErrorTypes.MEDIA_ERROR:
|
||||||
|
case Hls.ErrorTypes.OTHER_ERROR:
|
||||||
|
console.error("Fatal HLS error, attempting recovery…");
|
||||||
|
try {
|
||||||
hls.destroy();
|
hls.destroy();
|
||||||
|
hlsRef.current = null;
|
||||||
|
setIsPlaying(false);
|
||||||
|
// Delay before trying to reconnect
|
||||||
|
setTimeout(() => {
|
||||||
|
playStream();
|
||||||
|
}, 3000);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("HLS recovery failed:", e);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
hls.destroy();
|
||||||
|
hlsRef.current = null;
|
||||||
|
setIsPlaying(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
hlsRef.current = hls;
|
hlsRef.current = hls;
|
||||||
audio.play().then(() => setIsPlaying(true)).catch(console.error);
|
|
||||||
} else {
|
|
||||||
console.error("HLS not supported");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
const audio = audioRef.current;
|
||||||
|
if (audio && isPlaying && audio.readyState < 2) {
|
||||||
|
console.warn("Playback seems stalled. Reloading stream.");
|
||||||
|
playStream();
|
||||||
|
}
|
||||||
|
}, 15000); // Check every 15 seconds
|
||||||
|
|
||||||
|
return () => clearInterval(interval);
|
||||||
|
}, [isPlaying]);
|
||||||
|
|
||||||
const togglePlayback = () => {
|
const togglePlayback = () => {
|
||||||
const audio = audioRef.current;
|
const audio = audioRef.current;
|
||||||
if (!audio) return;
|
if (!audio) return;
|
||||||
|
Reference in New Issue
Block a user