UNPKG

6.62 kBJavaScriptView Raw
1"use strict";
2var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3 if (k2 === undefined) k2 = k;
4 Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5}) : (function(o, m, k, k2) {
6 if (k2 === undefined) k2 = k;
7 o[k2] = m[k];
8}));
9var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10 Object.defineProperty(o, "default", { enumerable: true, value: v });
11}) : function(o, v) {
12 o["default"] = v;
13});
14var __importStar = (this && this.__importStar) || function (mod) {
15 if (mod && mod.__esModule) return mod;
16 var result = {};
17 if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18 __setModuleDefault(result, mod);
19 return result;
20};
21Object.defineProperty(exports, "__esModule", { value: true });
22exports.useSharedAudio = exports.SharedAudioContextProvider = exports.SharedAudioContext = void 0;
23const jsx_runtime_1 = require("react/jsx-runtime");
24const react_1 = __importStar(require("react"));
25const EMPTY_AUDIO = 'data:audio/mp3;base64,/+MYxAAJcAV8AAgAABn//////+/gQ5BAMA+D4Pg+BAQBAEAwD4Pg+D4EBAEAQDAPg++hYBH///hUFQVBUFREDQNHmf///////+MYxBUGkAGIMAAAAP/29Xt6lUxBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV/+MYxDUAAANIAAAAAFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV';
26exports.SharedAudioContext = (0, react_1.createContext)(null);
27const SharedAudioContextProvider = ({ children, numberOfAudioTags }) => {
28 const [audios, setAudios] = (0, react_1.useState)([]);
29 const [initialNumberOfAudioTags] = (0, react_1.useState)(numberOfAudioTags);
30 if (numberOfAudioTags !== initialNumberOfAudioTags) {
31 throw new Error('The number of shared audio tags has changed dynamically. Once you have set this property, you cannot change it afterwards.');
32 }
33 const refs = (0, react_1.useMemo)(() => {
34 return new Array(numberOfAudioTags).fill(true).map(() => {
35 return { id: Math.random(), ref: (0, react_1.createRef)() };
36 });
37 }, [numberOfAudioTags]);
38 const takenAudios = (0, react_1.useRef)(new Array(numberOfAudioTags).fill(false));
39 const registerAudio = (0, react_1.useCallback)((aud) => {
40 const firstFreeAudio = takenAudios.current.findIndex((a) => a === false);
41 if (firstFreeAudio === -1) {
42 throw new Error(`Tried to simultaneously mount ${numberOfAudioTags + 1} <Audio /> tags at the same time. With the current settings, the maximum amount of <Audio /> tags is limited to ${numberOfAudioTags} at the same time. Remotion pre-mounts silent audio tags to help avoid browser autoplay restrictions. See https://remotion.dev/docs/player/autoplay#use-the-numberofsharedaudiotags-property for more information on how to increase this limit.`);
43 }
44 const { id, ref } = refs[firstFreeAudio];
45 const cloned = [...takenAudios.current];
46 cloned[firstFreeAudio] = id;
47 takenAudios.current = cloned;
48 const newElem = {
49 props: aud,
50 id,
51 el: ref,
52 };
53 // We need a timeout because this state setting is triggered by another state being set, causing React to throw an error.
54 // By setting a timeout, we are bypassing the error and allowing the state
55 // to be updated in the next tick.
56 // This can lead to a tiny delay of audio playback, improvement ideas are welcome.
57 setTimeout(() => {
58 setAudios((prevAudios) => [...prevAudios, newElem]);
59 }, 4);
60 return newElem;
61 }, [numberOfAudioTags, refs]);
62 const unregisterAudio = (0, react_1.useCallback)((id) => {
63 const cloned = [...takenAudios.current];
64 const index = refs.findIndex((r) => r.id === id);
65 if (index === -1) {
66 throw new TypeError('Error occured in ');
67 }
68 cloned[index] = false;
69 takenAudios.current = cloned;
70 setAudios((prevAudios) => {
71 return prevAudios.filter((a) => a.id !== id);
72 });
73 }, [refs]);
74 const updateAudio = (0, react_1.useCallback)((id, aud) => {
75 setAudios((prevAudios) => {
76 return prevAudios.map((prevA) => {
77 if (prevA.id === id) {
78 return {
79 ...prevA,
80 props: aud,
81 };
82 }
83 return prevA;
84 });
85 });
86 }, []);
87 const playAllAudios = (0, react_1.useCallback)(() => {
88 refs.forEach((ref) => {
89 var _a;
90 (_a = ref.ref.current) === null || _a === void 0 ? void 0 : _a.play();
91 });
92 }, [refs]);
93 const value = (0, react_1.useMemo)(() => {
94 return {
95 registerAudio,
96 unregisterAudio,
97 updateAudio,
98 playAllAudios,
99 numberOfAudioTags,
100 };
101 }, [
102 numberOfAudioTags,
103 playAllAudios,
104 registerAudio,
105 unregisterAudio,
106 updateAudio,
107 ]);
108 return ((0, jsx_runtime_1.jsxs)(exports.SharedAudioContext.Provider, { value: value, children: [refs.map(({ id, ref }) => {
109 const data = audios.find((a) => a.id === id);
110 if (data === undefined) {
111 return (0, jsx_runtime_1.jsx)("audio", { ref: ref, src: EMPTY_AUDIO }, id);
112 }
113 if (!data) {
114 throw new TypeError('Expected audio data to be there');
115 }
116 return (0, jsx_runtime_1.jsx)("audio", { ref: ref, ...data.props }, id);
117 }), children] }, void 0));
118};
119exports.SharedAudioContextProvider = SharedAudioContextProvider;
120const useSharedAudio = (aud) => {
121 const ctx = (0, react_1.useContext)(exports.SharedAudioContext);
122 const [elem] = (0, react_1.useState)(() => {
123 if (ctx && ctx.numberOfAudioTags > 0) {
124 return ctx.registerAudio(aud);
125 }
126 return {
127 el: react_1.default.createRef(),
128 id: Math.random(),
129 props: aud,
130 };
131 });
132 (0, react_1.useEffect)(() => {
133 return () => {
134 if (ctx && ctx.numberOfAudioTags > 0) {
135 ctx.unregisterAudio(elem.id);
136 }
137 };
138 }, [ctx, elem.id]);
139 (0, react_1.useEffect)(() => {
140 if (ctx && ctx.numberOfAudioTags > 0) {
141 ctx.updateAudio(elem.id, aud);
142 }
143 }, [aud, ctx, elem.id]);
144 return elem;
145};
146exports.useSharedAudio = useSharedAudio;