Skip to content

Instantly share code, notes, and snippets.

@m-naeem66622
Created September 12, 2023 17:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save m-naeem66622/156f47d4fe5357c527defd0b773d686f to your computer and use it in GitHub Desktop.
Save m-naeem66622/156f47d4fe5357c527defd0b773d686f to your computer and use it in GitHub Desktop.
// Import modules
import React, { useEffect, useRef, useState } from "react";
// Define a custom hook for using media source buffers
const useMediaSourceBuffer = (url, mimeType) => {
// Create a ref for the media source object
const mediaSourceRef = useRef();
// Create a ref for the source buffer object
const sourceBufferRef = useRef();
// Create a state for the media source ready state
const [readyState, setReadyState] = useState("");
// Create a state for the source buffer updating flag
const [updating, setUpdating] = useState(false);
// Create a state for the queue of chunks to be appended to the source buffer
const [queue, setQueue] = useState([]);
// Initialize the media source object and attach it to the URL
useEffect(() => {
// Create a new media source object
mediaSourceRef.current = new MediaSource();
// Set the URL to be a blob URL created from the media source object
url.current = URL.createObjectURL(mediaSourceRef.current);
// Add an event listener for when the media source is open
mediaSourceRef.current.addEventListener("sourceopen", () => {
// Set the ready state to open
setReadyState(mediaSourceRef.current.readyState);
// Create a new source buffer object with the given mime type
sourceBufferRef.current =
mediaSourceRef.current.addSourceBuffer(mimeType);
// Add an event listener for when the source buffer is updating
sourceBufferRef.current.addEventListener("updatestart", () => {
// Set the updating flag to true
setUpdating(true);
});
// Add an event listener for when the source buffer is updated
sourceBufferRef.current.addEventListener("updateend", () => {
// Set the updating flag to false
setUpdating(false);
// If there are chunks in the queue, shift the first one and append it to the source buffer
if (queue.length > 0) {
sourceBufferRef.current.appendBuffer(queue.shift());
}
});
});
// Return a cleanup function to revoke the blob URL and close the media source
return () => {
URL.revokeObjectURL(url.current);
mediaSourceRef.current.endOfStream();
};
}, [url, mimeType]);
// Define a function to append a chunk to the source buffer or the queue
const appendChunk = (chunk) => {
// If the source buffer is not updating and the media source is open, append the chunk to the source buffer
if (!updating && readyState === "open") {
sourceBufferRef.current.appendBuffer(chunk);
} else {
// Otherwise, push the chunk to the queue
setQueue((prevQueue) => [...prevQueue, chunk]);
}
};
// Return the append chunk function
return appendChunk;
};
// Define a custom hook for fetching audio chunks from a server
const useFetchAudioChunks = (url, appendChunk) => {
// Create a state for the fetch controller
const [controller, setController] = useState(null);
// Create a state for the fetch signal
const [signal, setSignal] = useState(null);
// Create a state for the fetch reader
const [reader, setReader] = useState(null);
// Create a state for the fetch done flag
const [done, setDone] = useState(false);
// Fetch audio chunks from the server and append them to the media source buffer
useEffect(() => {
// If the URL is not defined, return
if (!url) return;
// Create a new abort controller and signal
const newController = new AbortController();
const newSignal = newController.signal;
// Set the controller and signal states
setController(newController);
setSignal(newSignal);
// Define an async function to fetch and process audio chunks
const fetchAndProcessChunks = async () => {
try {
// Fetch the audio file from the server with the signal and range headers
const response = await fetch(url, {
signal,
headers: {
Range: "bytes=0-", // Change this according to your desired range
},
});
// If the response is not ok, throw an error
if (!response.ok) {
throw new Error(`Fetch error: ${response.status}`);
}
// Get the reader from the response body
const newReader = response.body.getReader();
// Set the reader state
setReader(newReader);
// Define a recursive function to read and append chunks
const readAndAppendChunks = async () => {
// Read a chunk from the reader
const { value, done } = await reader.read();
// If done is true, set the done state to true and return
if (done) {
setDone(true);
return;
}
// If value is defined, append it to the media source buffer using the append chunk function
if (value) {
appendChunk(value);
}
// Call the function again until done is true
readAndAppendChunks();
};
// Call the function for the first time
readAndAppendChunks();
} catch (error) {
// If the error is not an abort error, log it to the console
if (error.name !== "AbortError") {
console.error(error);
}
}
};
// Call the async function
fetchAndProcessChunks();
// Return a cleanup function to abort the fetch and cancel the reader
return () => {
controller.abort();
reader && reader.cancel();
};
}, [url, signal, reader, appendChunk]);
// Return the done flag
return done;
};
// Define a custom hook for using an HTML5 audio element with a media source buffer URL
const useAudioElement = (url, done) => {
// Create a ref for the audio element
const audioRef = useRef();
// Create a state for the audio duration
const [duration, setDuration] = useState(0);
// Create a state for the audio current time
const [currentTime, setCurrentTime] = useState(0);
// Create a state for the audio paused flag
const [paused, setPaused] = useState(true);
// Initialize and update the audio element with the URL and done flag
useEffect(() => {}, []); // Incomplete from here need guidance to complete it
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment