@webav/av-canvas
Version:
Combine Text, Image, Video, Audio, UserMedia, DisplayMedia to generate MediaStream. With [AVRcorder](../av-recorder/README.md) you can output MP4 streams and save them as local files or push them to the server.
751 lines (750 loc) • 24.1 kB
JavaScript
var St = Object.defineProperty;
var ut = (e) => {
throw TypeError(e);
};
var bt = (e, t, n) => t in e ? St(e, t, { enumerable: !0, configurable: !0, writable: !0, value: n }) : e[t] = n;
var U = (e, t, n) => bt(e, typeof t != "symbol" ? t + "" : t, n), at = (e, t, n) => t.has(e) || ut("Cannot " + n);
var r = (e, t, n) => (at(e, t, "read from private field"), n ? n.call(e) : t.get(e)), y = (e, t, n) => t.has(e) ? ut("Cannot add the same private member more than once") : t instanceof WeakSet ? t.add(e) : t.set(e, n), M = (e, t, n, i) => (at(e, t, "write to private field"), i ? i.call(e, n) : t.set(e, n), n), I = (e, t, n) => (at(e, t, "access private method"), n);
import { Rect as O, Log as _, MediaStreamClip as xt, Combinator as gt, OffscreenSprite as vt } from "@webav/av-cliper";
import { EventTool as ht, workerTimer as Ct } from "@webav/internal-utils";
const Mt = [
"t",
"b",
"l",
"r",
"lt",
"lb",
"rt",
"rb",
"rotate"
];
function V(e) {
return document.createElement(e);
}
function At(e) {
let t = 16;
const n = new ResizeObserver((o) => {
const s = o[0];
s != null && (t = 10 / (s.contentRect.width / e.width));
});
n.observe(e);
function i(o) {
const { w: s, h } = o, a = t, c = a / 2, l = s / 2, d = h / 2, u = a * 1.5, f = u / 2;
return {
...o.fixedAspectRatio ? {} : {
t: new O(-c, -d - c, a, a, o),
b: new O(-c, d - c, a, a, o),
l: new O(-l - c, -c, a, a, o),
r: new O(l - c, -c, a, a, o)
},
lt: new O(-l - c, -d - c, a, a, o),
lb: new O(-l - c, d - c, a, a, o),
rt: new O(l - c, -d - c, a, a, o),
rb: new O(l - c, d - c, a, a, o),
rotate: new O(-f, -d - a * 2 - f, u, u, o)
};
}
return {
rectCtrlsGetter: i,
destroy: () => {
n.disconnect();
}
};
}
var q = /* @__PURE__ */ ((e) => (e.ActiveSpriteChange = "activeSpriteChange", e.AddSprite = "addSprite", e))(q || {}), T, X, F, B;
class Tt {
constructor() {
y(this, T, []);
y(this, X, null);
y(this, F, new ht());
U(this, "on", r(this, F).on);
y(this, B, 0);
}
get activeSprite() {
return r(this, X);
}
set activeSprite(t) {
t !== r(this, X) && (M(this, X, t), r(this, F).emit("activeSpriteChange", t));
}
async addSprite(t) {
await t.ready, r(this, T).push(t), M(this, T, r(this, T).sort((n, i) => n.zIndex - i.zIndex)), t.on("propsChange", (n) => {
n.zIndex != null && M(this, T, r(this, T).sort((i, o) => i.zIndex - o.zIndex));
}), r(this, F).emit("addSprite", t);
}
removeSprite(t) {
r(this, X) === t && (this.activeSprite = null), M(this, T, r(this, T).filter((n) => n !== t)), t.destroy();
}
getSprites(t = { time: !0 }) {
return r(this, T).filter(
(n) => n.visible && (t.time ? r(this, B) >= n.time.offset && r(this, B) <= n.time.offset + n.time.duration : !0)
);
}
updateRenderTime(t) {
M(this, B, t);
const n = this.activeSprite;
n != null && (t < n.time.offset || t > n.time.offset + n.time.duration) && (this.activeSprite = null);
}
destroy() {
r(this, F).destroy(), r(this, T).forEach((t) => t.destroy()), M(this, T, []);
}
}
T = new WeakMap(), X = new WeakMap(), F = new WeakMap(), B = new WeakMap();
function zt(e, t, n, i) {
const o = {
w: t.clientWidth / t.width,
h: t.clientHeight / t.height
}, s = new ResizeObserver(() => {
o.w = t.clientWidth / t.width, o.h = t.clientHeight / t.height, n.activeSprite != null && ct(
n.activeSprite,
a,
c,
o,
i
);
});
s.observe(t);
let h = () => {
};
const { rectEl: a, ctrlsEl: c } = kt(e), l = n.on(q.ActiveSpriteChange, (d) => {
if (h(), d == null) {
a.style.display = "none";
return;
}
ct(d, a, c, o, i), h = d.on("propsChange", () => {
ct(d, a, c, o, i);
}), a.style.display = "";
});
return () => {
s.disconnect(), l(), a.remove(), h();
};
}
function kt(e) {
const t = V("div");
t.style.cssText = `
position: absolute;
pointer-events: none;
border: 1px solid #eee;
box-sizing: border-box;
display: none;
`;
const n = Object.fromEntries(
Mt.map((i) => {
const o = V("div");
return o.style.cssText = `
display: none;
position: absolute;
border: 1px solid #3ee; border-radius: 50%;
box-sizing: border-box;
background-color: #fff;
`, [i, o];
})
);
return Object.values(n).forEach((i) => t.appendChild(i)), e.appendChild(t), {
rectEl: t,
ctrlsEl: n
};
}
function ct(e, t, n, i, o) {
const { x: s, y: h, w: a, h: c, angle: l } = e.rect;
Object.assign(t.style, {
left: `${s * i.w}px`,
top: `${h * i.h}px`,
width: `${a * i.w}px`,
height: `${c * i.h}px`,
rotate: `${l}rad`
}), Object.entries(o(e.rect)).forEach(([d, { x: u, y: f, w, h: b }]) => {
Object.assign(n[d].style, {
display: "block",
left: "50%",
top: "50%",
width: `${w * i.w}px`,
height: `${b * i.h}px`,
// border 1px, 所以要 -1
transform: `translate(${u * i.w}px, ${f * i.h}px)`
});
});
}
function Lt(e, t, n) {
const i = {
w: e.clientWidth / e.width,
h: e.clientHeight / e.height
}, o = new ResizeObserver(() => {
i.w = e.clientWidth / e.width, i.h = e.clientHeight / e.height;
});
o.observe(e);
const s = (h) => {
if (h.button !== 0) return;
const { offsetX: a, offsetY: c } = h, l = a / i.w, d = c / i.h;
if (t.activeSprite != null) {
const [u] = Object.entries(n(t.activeSprite.rect)).find(
([, f]) => f.checkHit(l, d)
) ?? [];
if (u != null) return;
}
t.activeSprite = t.getSprites().reverse().find((u) => u.visible && u.rect.checkHit(l, d)) ?? null;
};
return e.addEventListener("pointerdown", s), () => {
o.disconnect(), e.removeEventListener("pointerdown", s);
};
}
function Ot(e, t, n, i) {
const o = {
w: e.clientWidth / e.width,
h: e.clientHeight / e.height
}, s = new ResizeObserver(() => {
o.w = e.clientWidth / e.width, o.h = e.clientHeight / e.height;
});
s.observe(e);
let h = 0, a = 0, c = null;
const l = Dt(e, n);
let d = null;
const u = (b) => {
if (b.button !== 0 || t.activeSprite == null) return;
d = t.activeSprite;
const { offsetX: A, offsetY: v, clientX: m, clientY: p } = b;
It({
rect: d.rect,
offsetX: A,
offsetY: v,
clientX: m,
clientY: p,
cvsRatio: o,
cvsEl: e,
rectCtrlsGetter: i
}) || (c = d.rect.clone(), l.magneticEffect(d.rect.x, d.rect.y, d.rect), h = m, a = p, window.addEventListener("pointermove", f), window.addEventListener("pointerup", w));
}, f = (b) => {
if (d == null || c == null) return;
const { clientX: A, clientY: v } = b;
let m = c.x + (A - h) / o.w, p = c.y + (v - a) / o.h;
pt(
d.rect,
e,
l.magneticEffect(m, p, d.rect)
);
};
e.addEventListener("pointerdown", u);
const w = () => {
l.hide(), window.removeEventListener("pointermove", f), window.removeEventListener("pointerup", w);
};
return () => {
s.disconnect(), l.destroy(), w(), e.removeEventListener("pointerdown", u);
};
}
function Wt({
sprRect: e,
startX: t,
startY: n,
ctrlKey: i,
cvsRatio: o,
cvsEl: s
}) {
const h = e.clone(), a = (l) => {
const { clientX: d, clientY: u } = l, f = (d - t) / o.w, w = (u - n) / o.h, b = i.length === 1 ? Rt : Ht, { x: A, y: v, w: m, h: p } = h, D = Math.atan2(p, m), { incW: K, incH: tt, incS: j, rotateAngle: dt } = b({
deltaX: f,
deltaY: w,
angle: e.angle,
ctrlKey: i,
diagonalAngle: D
}), C = 10;
let L = m, Y = p, et = h.fixedScaleCenter ? K * 2 : K, it = h.fixedScaleCenter ? tt * 2 : tt, H = j;
const lt = Math.sqrt(p ** 2 + m ** 2), ft = Math.sqrt((C * (p / m)) ** 2 + C ** 2);
switch (i) {
case "l":
L = Math.max(m + et, C), H = Math.min(j, m - C);
break;
case "r":
L = Math.max(m + et, C), H = Math.max(j, C - m);
break;
case "b":
Y = Math.max(p + it, C), H = Math.min(j, p - C);
break;
case "t":
Y = Math.max(p + it, C), H = Math.max(j, C - p);
break;
case "lt":
case "lb":
L = Math.max(m + et, C), Y = L === C ? p / m * L : p + it, H = Math.min(j, lt - ft);
break;
case "rt":
case "rb":
L = Math.max(m + et, C), Y = L === C ? p / m * L : p + it, H = Math.max(j, ft - lt);
break;
}
let ot = A, st = v;
if (h.fixedScaleCenter)
ot = A + m / 2 - L / 2, st = v + p / 2 - Y / 2;
else {
const mt = H / 2 * Math.cos(dt) + A + m / 2, yt = H / 2 * Math.sin(dt) + v + p / 2;
ot = mt - L / 2, st = yt - Y / 2;
}
pt(e, s, {
x: ot,
y: st,
w: L,
h: Y
});
}, c = () => {
window.removeEventListener("pointermove", a), window.removeEventListener("pointerup", c);
};
window.addEventListener("pointermove", a), window.addEventListener("pointerup", c);
}
function Rt({
deltaX: e,
deltaY: t,
angle: n,
ctrlKey: i
}) {
let o = 0, s = 0, h = 0, a = n;
return i === "l" || i === "r" ? (o = e * Math.cos(n) + t * Math.sin(n), s = o * (i === "l" ? -1 : 1)) : (i === "t" || i === "b") && (a = n - Math.PI / 2, o = e * Math.cos(a) + t * Math.sin(a), h = o * (i === "b" ? -1 : 1)), { incW: s, incH: h, incS: o, rotateAngle: a };
}
function Ht({
deltaX: e,
deltaY: t,
angle: n,
ctrlKey: i,
diagonalAngle: o
}) {
const s = (i === "lt" || i === "rb" ? 1 : -1) * o + n, h = e * Math.cos(s) + t * Math.sin(s), a = i === "lt" || i === "lb" ? -1 : 1, c = h * Math.cos(o) * a, l = h * Math.sin(o) * a;
return { incW: c, incH: l, incS: h, rotateAngle: s };
}
function It({
rect: e,
cvsRatio: t,
offsetX: n,
offsetY: i,
clientX: o,
clientY: s,
cvsEl: h,
rectCtrlsGetter: a
}) {
const c = n / t.w, l = i / t.h, [d] = Object.entries(a(e)).find(
([, u]) => u.checkHit(c, l)
) ?? [];
return d == null ? !1 : (d === "rotate" ? $t(e, Pt(e.center, t, h)) : Wt({
sprRect: e,
ctrlKey: d,
startX: o,
startY: s,
cvsRatio: t,
cvsEl: h
}), !0);
}
function $t(e, t) {
const n = ({ clientX: o, clientY: s }) => {
const h = o - t.x, a = s - t.y, c = Math.atan2(a, h) + Math.PI / 2;
e.angle = c;
}, i = () => {
window.removeEventListener("pointermove", n), window.removeEventListener("pointerup", i);
};
window.addEventListener("pointermove", n), window.addEventListener("pointerup", i);
}
function Pt(e, t, n) {
const i = e.x * t.w, o = e.y * t.h, { left: s, top: h } = n.getBoundingClientRect();
return {
x: i + s,
y: o + h
};
}
function pt(e, t, n) {
const i = { x: e.x, y: e.y, w: e.w, h: e.h, ...n }, o = t.width * 0.05, s = t.height * 0.05;
i.x < -i.w + o ? i.x = -i.w + o : i.x > t.width - o && (i.x = t.width - o), i.y < -i.h + s ? i.y = -i.h + s : i.y > t.height - s && (i.y = t.height - s), e.x = i.x, e.y = i.y, e.w = i.w, e.h = i.h;
}
function Dt(e, t) {
const n = "display: none; position: absolute;", i = { w: 0, h: 0, x: 0, y: 0 }, o = {
vertMiddle: {
...i,
h: 100,
x: 50,
ref: { prop: "x", val: ({ w: c }) => (e.width - c) / 2 }
},
horMiddle: {
...i,
w: 100,
y: 50,
ref: { prop: "y", val: ({ h: c }) => (e.height - c) / 2 }
},
top: {
...i,
w: 100,
ref: { prop: "y", val: () => 0 }
},
bottom: {
...i,
w: 100,
y: 100,
ref: { prop: "y", val: ({ h: c }) => e.height - c }
},
left: {
...i,
h: 100,
ref: { prop: "x", val: () => 0 }
},
right: {
...i,
h: 100,
x: 100,
ref: { prop: "x", val: ({ w: c }) => e.width - c }
}
}, s = V("div");
s.style.cssText = `
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
pointer-events: none;
box-sizing: border-box;
`;
const h = Object.fromEntries(
Object.entries(o).map(([c, { w: l, h: d, x: u, y: f }]) => {
const w = V("div");
return w.style.cssText = `
${n}
border-${l > 0 ? "top" : "left"}: 1px solid #3ee;
top: ${f}%; left: ${u}%;
${u === 100 ? "margin-left: -1px" : ""};
${f === 100 ? "margin-top: -1px" : ""};
width: ${l}%; height: ${d}%;
`, s.appendChild(w), [c, w];
})
);
t.appendChild(s);
const a = 6 / (900 / e.width);
return {
magneticEffect(c, l, d) {
const u = { x: c, y: l };
let f, w = { x: !1, y: !1 };
for (f in o) {
const { prop: b, val: A } = o[f].ref;
if (w[b]) continue;
const v = A(d);
Math.abs(d[b] - v) <= a && Math.abs(d[b] - (b === "x" ? c : l)) <= a ? (u[b] = v, h[f].style.display = "block", w[b] = !0) : h[f].style.display = "none";
}
return u;
},
hide() {
Object.values(h).forEach((c) => c.style.display = "none");
},
destroy() {
s.remove();
}
};
}
function jt(e, t, n) {
const i = {
w: e.clientWidth / e.width,
h: e.clientHeight / e.height
}, o = new ResizeObserver(() => {
i.w = e.clientWidth / e.width, i.h = e.clientHeight / e.height;
});
o.observe(e);
const s = e.style;
let h = t.activeSprite;
t.on(q.ActiveSpriteChange, (w) => {
h = w, w == null && (s.cursor = "");
});
let a = !1;
const c = ({ offsetX: w, offsetY: b }) => {
a = !0;
const A = w / i.w, v = b / i.h;
(h == null ? void 0 : h.rect.checkHit(A, v)) === !0 && s.cursor === "" && (s.cursor = "move");
}, l = () => {
a = !1;
}, d = [
"ns-resize",
"nesw-resize",
"ew-resize",
"nwse-resize",
"ns-resize",
"nesw-resize",
"ew-resize",
"nwse-resize"
], u = { t: 0, rt: 1, r: 2, rb: 3, b: 4, lb: 5, l: 6, lt: 7 }, f = (w) => {
if (h == null || a) return;
const { offsetX: b, offsetY: A } = w, v = b / i.w, m = A / i.h, [p] = Object.entries(n(h.rect)).find(
([, D]) => D.checkHit(v, m)
) ?? [];
if (p != null) {
if (p === "rotate") {
s.cursor = "crosshair";
return;
}
const D = h.rect.angle, K = D < 0 ? D + 2 * Math.PI : D, tt = (u[p] + Math.floor((K + Math.PI / 8) / (Math.PI / 4))) % 8;
s.cursor = d[tt];
return;
}
if (h.rect.checkHit(v, m)) {
s.cursor = "move";
return;
}
s.cursor = "";
};
return e.addEventListener("pointermove", f), e.addEventListener("pointerdown", c), window.addEventListener("pointerup", l), () => {
o.disconnect(), e.removeEventListener("pointermove", f), e.removeEventListener("pointerdown", c), window.removeEventListener("pointerup", l);
};
}
const Yt = {
sampleRate: 48e3,
channelCount: 2,
codec: "mp4a.40.2"
};
function Xt(e) {
const t = V("canvas");
return t.style.cssText = `
width: 100%;
height: 100%;
display: block;
touch-action: none;
`, t.width = e.width, t.height = e.height, t;
}
var x, S, N, E, G, J, W, Q, R, k, nt, rt, g, $, P, wt, z, Z;
class _t {
/**
* 创建 `AVCanvas` 类的实例。
* @param attchEl - 要添加画布的元素。
* @param opts - 画布的选项
* @param opts.bgColor - 画布的背景颜色。
* @param opts.width - 画布的宽度。
* @param opts.height - 画布的高度。
*/
constructor(t, n) {
y(this, k);
y(this, x);
y(this, S);
y(this, N);
y(this, E, !1);
y(this, G, []);
y(this, J);
y(this, W, new ht());
U(this, "on", r(this, W).on);
y(this, Q);
y(this, R, 0);
y(this, g, new AudioContext());
y(this, $, r(this, g).createMediaStreamDestination());
y(this, P, /* @__PURE__ */ new Set());
y(this, z, {
start: 0,
end: 0,
// paused state when step equal 0
step: 0,
// step: (1000 / 30) * 1000,
audioPlayAt: 0
});
y(this, Z, /* @__PURE__ */ new WeakMap());
/**
* 添加 {@link VisibleSprite}
* @param args {@link VisibleSprite}
* @example
* const sprite = new VisibleSprite(
* new ImgClip({
* type: 'image/gif',
* stream: (await fetch('https://xx.gif')).body!,
* }),
* );
*/
U(this, "addSprite", async (t) => {
r(this, g).state === "suspended" && r(this, g).resume().catch(_.error);
const n = t.getClip();
if (n instanceof xt && n.audioTrack != null) {
const i = r(this, g).createMediaStreamSource(
new MediaStream([n.audioTrack])
);
i.connect(r(this, $)), r(this, Z).set(t, i);
}
await r(this, S).addSprite(t);
});
/**
* 删除 {@link VisibleSprite}
* @param args
* @returns
* @example
* const sprite = new VisibleSprite();
* avCvs.removeSprite(sprite);
*/
U(this, "removeSprite", (t) => {
var n;
(n = r(this, Z).get(t)) == null || n.disconnect(), r(this, S).removeSprite(t);
});
M(this, Q, n), M(this, x, Xt(n));
const i = r(this, x).getContext("2d", { alpha: !1 });
if (i == null) throw Error("canvas context is null");
M(this, N, i);
const o = V("div");
o.style.cssText = "width: 100%; height: 100%; position: relative; overflow: hidden;", o.appendChild(r(this, x)), t.appendChild(o), Nt(r(this, g)).connect(r(this, $)), M(this, S, new Tt());
const { rectCtrlsGetter: s, destroy: h } = At(
r(this, x)
);
r(this, G).push(
h,
// 鼠标样式、控制 sprite 依赖 activeSprite,
// activeSprite 需要在他们之前监听到 mousedown 事件 (代码顺序需要靠前)
Lt(r(this, x), r(this, S), s),
jt(r(this, x), r(this, S), s),
Ot(
r(this, x),
r(this, S),
o,
s
),
zt(o, r(this, x), r(this, S), s),
r(this, S).on(q.AddSprite, (u) => {
const { rect: f } = u;
f.x === 0 && f.y === 0 && (f.x = (r(this, x).width - f.w) / 2, f.y = (r(this, x).height - f.h) / 2);
}),
ht.forwardEvent(r(this, S), r(this, W), [
q.ActiveSpriteChange
])
);
let a = r(this, R), c = performance.now(), l = 0;
const d = 1e3 / 30;
M(this, J, Ct(() => {
(performance.now() - c) / (d * l) < 1 || (l += 1, r(this, N).fillStyle = n.bgColor, r(this, N).fillRect(0, 0, r(this, x).width, r(this, x).height), I(this, k, wt).call(this), a !== r(this, R) && (a = r(this, R), r(this, W).emit("timeupdate", Math.round(a))));
}, d));
}
/**
* 每 33ms 更新一次画布,绘制已添加的 Sprite
* @param opts - 播放选项
* @param opts.start - 开始播放的时间(单位:微秒)
* @param [opts.end] - 结束播放的时间(单位:微秒)。如果未指定,则播放到最后一个 Sprite 的结束时间
* @param [opts.playbackRate] - 播放速率。1 表示正常速度,2 表示两倍速度,0.5 表示半速等。如果未指定,则默认为 1
* @throws 如果开始时间大于等于结束时间或小于 0,则抛出错误
*/
play(t) {
const n = r(this, S).getSprites({ time: !1 }).map((o) => o.time.offset + o.time.duration), i = t.end ?? (n.length > 0 ? Math.max(...n) : 1 / 0);
if (t.start >= i || t.start < 0)
throw Error(
`Invalid time parameter, ${JSON.stringify({ start: t.start, end: i })}`
);
I(this, k, nt).call(this, t.start), r(this, S).getSprites({ time: !1 }).forEach((o) => {
const { offset: s, duration: h } = o.time, a = r(this, R) - s;
o.preFrame(a > 0 && a < h ? a : 0);
}), r(this, z).start = t.start, r(this, z).end = i, r(this, z).step = (t.playbackRate ?? 1) * (1e3 / 30) * 1e3, r(this, g).resume(), r(this, z).audioPlayAt = 0, r(this, W).emit("playing"), _.info("AVCanvs play by:", r(this, z));
}
/**
* 暂停播放,画布内容不再更新
*/
pause() {
I(this, k, rt).call(this);
}
/**
* 预览 `AVCanvas` 指定时间的图像帧
*/
previewFrame(t) {
I(this, k, nt).call(this, t), I(this, k, rt).call(this);
}
/**
* 获取当前帧的截图图像 返回的是一个base64
*/
captureImage() {
return r(this, x).toDataURL();
}
get activeSprite() {
return r(this, S).activeSprite;
}
set activeSprite(t) {
r(this, S).activeSprite = t;
}
/**
* 销毁实例
*/
destroy() {
var t;
r(this, E) || (M(this, E, !0), r(this, g).close(), r(this, $).disconnect(), r(this, W).destroy(), r(this, J).call(this), (t = r(this, x).parentElement) == null || t.remove(), r(this, G).forEach((n) => n()), r(this, P).clear(), r(this, S).destroy());
}
/**
* 合成所有素材的图像与音频,返回实时媒体流 `MediaStream`
*
* 可用于 WebRTC 推流,或由 {@link [AVRecorder](../../av-recorder/classes/AVRecorder.html)} 录制生成视频文件
*
* @see [直播录制](https://webav-tech.github.io/WebAV/demo/4_2-recorder-avcanvas)
*
*/
captureStream() {
r(this, g).state === "suspended" && r(this, g).resume().catch(_.error);
const t = new MediaStream(
r(this, x).captureStream().getTracks().concat(r(this, $).stream.getTracks())
);
return _.info(
"AVCanvas.captureStream, tracks:",
t.getTracks().map((n) => n.kind)
), t;
}
/**
* 创建一个视频合成器 {@link [Combinator](../../av-cliper/classes/Combinator.html)} 实例,用于将当前画布添加的 Sprite 导出为视频文件流
*
* @param opts - 创建 Combinator 的可选参数
* @throws 如果没有添加素材,会抛出错误
*
* @example
* avCvs.createCombinator().output() // => ReadableStream
*
* @see [视频剪辑](https://webav-tech.github.io/WebAV/demo/6_4-video-editor)
*/
async createCombinator(t = {}) {
_.info("AVCanvas.createCombinator, opts:", t);
const n = new gt({ ...r(this, Q), ...t }), i = r(this, S).getSprites({ time: !1 });
if (i.length === 0) throw Error("No sprite added");
for (const o of i) {
const s = new vt(o.getClip());
s.time = { ...o.time }, o.copyStateTo(s), await n.addSprite(s);
}
return n;
}
}
x = new WeakMap(), S = new WeakMap(), N = new WeakMap(), E = new WeakMap(), G = new WeakMap(), J = new WeakMap(), W = new WeakMap(), Q = new WeakMap(), R = new WeakMap(), k = new WeakSet(), nt = function(t) {
M(this, R, t), r(this, S).updateRenderTime(t);
}, rt = function() {
const t = r(this, z).step !== 0;
r(this, z).step = 0, t && (r(this, W).emit("paused"), r(this, g).suspend());
for (const n of r(this, P))
n.stop(), n.disconnect();
r(this, P).clear();
}, g = new WeakMap(), $ = new WeakMap(), P = new WeakMap(), wt = function() {
var c;
const t = r(this, N);
let n = r(this, R);
const { start: i, end: o, step: s, audioPlayAt: h } = r(this, z);
s !== 0 && n >= i && n < o ? n += s : I(this, k, rt).call(this), I(this, k, nt).call(this, n);
const a = [];
for (const l of r(this, S).getSprites()) {
t.save();
const { audio: d } = l.render(t, n - l.time.offset);
t.restore(), a.push(d);
}
if (t.resetTransform(), s !== 0) {
const l = Math.max(r(this, g).currentTime, h), d = Ft(
a,
r(this, g)
);
let u = 0;
for (const f of d)
f.start(l), f.connect(r(this, g).destination), f.connect(r(this, $)), r(this, P).add(f), f.onended = () => {
f.disconnect(), r(this, P).delete(f);
}, u = Math.max(u, ((c = f.buffer) == null ? void 0 : c.duration) ?? 0);
r(this, z).audioPlayAt = l + u;
}
}, z = new WeakMap(), Z = new WeakMap();
function Ft(e, t) {
const n = [];
if (e.length === 0) return n;
for (const [i, o] of e) {
if (i == null || i.length <= 0) continue;
const s = t.createBuffer(
2,
i.length,
Yt.sampleRate
);
s.copyToChannel(i, 0), s.copyToChannel(o ?? i, 1);
const h = t.createBufferSource();
h.buffer = s, n.push(h);
}
return n;
}
function Nt(e) {
const t = e.createOscillator(), n = new Float32Array([0, 0]), i = new Float32Array([0, 0]), o = e.createPeriodicWave(n, i, {
disableNormalization: !0
});
return t.setPeriodicWave(o), t.start(), t;
}
export {
_t as AVCanvas
};
//# sourceMappingURL=av-canvas.js.map