Created
September 12, 2023 17:35
-
-
Save m-naeem66622/156f47d4fe5357c527defd0b773d686f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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