import {
all as l,
call as e,
race as a,
fork as c,
put as i,
takeLatest as n,
takeLeading as o,
take as r,
select as d,
spawn as t,
delay as y,
getContext as s,
} from "redux-saga/effects"
import { getCallApi as m, getCoreBackend as f } from "../../backend"
import { apiCall as u } from "../../api/core"
import { apiSubscribeSaga as g } from "../lib"
import { getChanged as S } from "../lib/array"
import { taskErrorSaga as I } from "../error"
import { NOTIFICATION_CODE as p, userCustomNotification as h } from "../notification"
import { getScreenConstraints as b, setVideoDevice as C, updateDevices as A } from "../media"
import {
getCallPeerVideoCount as v,
getCallPeersCount as L,
getIsCallsV2Supported as O,
getDmCallsV2Enabled as V,
getCallId as w,
getScreenSharingDisabled as x,
getActiveCallMemberIds as D,
getActiveCalls as E,
getCallKnownMemberCount as M,
} from "./call.reducer"
import {
callJoinCmd as k,
callLeave as _,
callCancel as T,
callJoinedEvt as j,
callSharedScreenUpdate as N,
updateCallRemoteMedia as R,
removeCallRemoteMedia as F,
setCallShareScreenDialogOpened as K,
callOpenShareScreenDialog as B,
callCloseShareScreenDialog as q,
showCallAutoEndPopup as z,
resetCallAutoEndTimer as G,
updateCallAutoEndCountdown as H,
decreaseCallPeersCount as J,
removeCallPeersCount as P,
increaseCallPeersCount as Q,
setCallPeers as U,
callResetIncomingDMCall as W,
setActiveCalls as X,
addCallMemberId as Y,
removeCallMemberId as Z,
} from "./call.action"
import {
getMyScreenStreamId as $,
getMyVideoLimits as ll,
getMyVideoMuted as el,
getMySharedScreen as al,
} from "./call-settings.reducer"
import {
setMySharedScreen as cl,
setMyVideoLimits as il,
setMyVideoMuted as nl,
setMyVideoAllowed as ol,
updateMyCameraStreamCmd as rl,
} from "./call-settings.action"
import { callRemoteStreamManager as dl, cleanupMyStreams as tl } from "./call-stream.saga"
import { getMyDeviceId as yl, isDeviceInCall as sl } from "./utils"
import { callPresenceSaga as ml } from "./call-presence.saga"
import { getRoomVersion as fl } from "../room/room.selector"
import { setRoomVersion as ul, setRoomInfo as gl } from "../room/room.action"
import {
STREAM_TYPE as Sl,
CALL_VIDEO_LIMIT_MEMBERS_GTE as Il,
CALL_VIDEO_LIMIT_INFO_DURATION as pl,
CALL_VIDEO_LIMIT_MEMBERS_GT as hl,
MOBILE_AUTO_END_MS_BEFORE_COUNTDOWN as bl,
AUTO_END_MS_BEFORE_COUNTDOWN as Cl,
AUTO_END_MS_COUNTDOWN as Al,
MOBILE_AUTO_END_MS_COUNTDOWN as vl,
AUTO_END_MS_STEP as Ll,
} from "./call.constants"
import { updateDevicesHandler as Ol } from "./call-device.saga"
import { getMyMemberId as Vl } from "../identity"
import { ENV_CONTEXT_KEY as wl } from "../constants"
import { checkScreenSharePermissionGranted as xl } from "../media/media-permissions.saga"
export function* callCloseShareScreenDialogSaga() {
yield i(K(!1))
}
export function* callOpenShareScreenDialogSaga() {
;(yield xl()) && (yield i(K(!0)))
}
export function* callSharedScreenSaga({ payload: l }) {
const e = (yield d(x)) ? "" : l.screenId,
a = yield d($)
if ((yield d(al)) === e || (!a && !e)) return
let c,
n = a
if (!a && e)
try {
n = m().local.openStream(Sl.SCREEN)
} catch (l) {
return void (yield I("callSharedScreen: Can't create stream", l))
}
if (n && e)
try {
const l = b({ sourceId: e }),
a = m().local.screenTrack?.id
yield m().local.applyStreamConstraints(n, l)
const c = m().local.screenTrack?.id
if (!c || (a && a === c)) throw new Error("Can't create screen video track")
} catch (l) {
;((c = l), yield I("callSharedScreen: constraints update fail", l))
}
if (!n || (e && !c)) yield i(cl({ screenId: e, streamId: n }))
else {
try {
m().local.closeStream(n)
} catch (l) {
yield I("callSharedScreen: stream close error", l)
}
a && (yield i(cl({ screenId: "", streamId: "" })))
}
}
const Dl = 2e3
export function* makeMeAllowed() {
;(yield y(Dl), (yield d(el)) || (yield i(ol())))
}
export function* callVideoLimitSaga() {
const { isMobile: e } = yield s(wl),
[a, { meAllowed: c, allowed: n, showInfo: o }, r] = yield l([d(v), d(ll), d(el)]),
y = { allowed: a < (e ? hl : Il), showInfo: o }
if ((!n || r || c || (yield t(makeMeAllowed)), n !== y.allowed)) {
if (o) {
const l = c ? p.CALL_LIMITS_INFO_LIMITED : p.CALL_LIMITS_INFO_DISABLED
;(yield i(h({ code: l, duration: pl })), (y.showInfo = !1))
}
;(yield i(il(y)), yield i(rl()))
}
}
export function* callAutoEndSaga(l) {
let e = null
const { isMobile: a } = yield s(wl)
function* o() {
yield y(a ? bl : Cl)
let l = a ? vl : Al
yield i(z(!0))
try {
for (; l > 0; ) (yield i(H(l)), yield y(Ll), (l -= Ll))
yield i(_())
} finally {
yield i(z(!1))
}
}
;(0 === (yield d(L, l)) && (e = yield c(o)),
yield n([Q, J, P, U, G, Y, Z], function* (a) {
const i = yield d(L, l),
n = yield d(M)
i > 0 || n > 0
? e && (e.cancel(), (e = null))
: (e && a && G.match(a) && (e.cancel(), (e = null)), e || (e = yield c(o)))
}))
}
function* El(l, e, a) {
const c = (yield u(l.getActiveCalls, e)).filter((l) => !l.endedAt),
i = c.find((l) => l.callId === a) || c[0]
if (i) {
const a = yield u(l.getRoomInfo, e)
return (sl(i, yl(a)) || (yield u(l.joinCall, e, i.callId, [])), i.callId)
}
if (yield d(V)) return (yield u(l.startCall, e, { version: 2, callId: a, streams: [] }), a)
yield u(l.startCall, e, { version: 1 })
const n = (yield u(l.getActiveCalls, e)).find((l) => !l.endedAt)
return n?.callId || a
}
function* Ml(l, e, a) {
const c = yield d(Vl)
yield g(
[l.subscribeActiveCalls, e],
function* (l) {
const e = l.find((l) => l.callId === a)
if (!e || e.endedAt) return (yield i(X({ calls: l, memberIds: [] })), void (yield i(_())))
const n = e.members.map((l) => l.memberId).filter((l) => l !== c),
o = yield d(D),
r = S(o, n),
t = yield d(E)
;(r || t?.length !== l.length) && (yield i(X({ calls: l, memberIds: n })))
},
{ onError: (l) => I("subscribeActiveCalls", l) },
)
}
export function* isLastInCall(l, e) {
if (1 !== l?.members.length) return !1
if (l?.members[0].devices.length > 1) return !1
const a = f(),
c = yield u(a.getRoomInfo, e)
return l.members[0].devices[0].deviceId === yl(c)
}
export function* callOngoingV1Saga({ roomId: l, callId: e }) {
let a = null,
d = null,
t = null,
y = null,
s = null,
f = null,
u = null,
g = null,
S = null,
p = !0
try {
for (;;) {
const I = yield r(k)
I.payload?.callId ||
((p = !0),
(S = m().subscribeActivateCall(e)),
yield callVideoLimitSaga(),
yield i(j({ roomId: l })),
(g = yield c(ml, { roomId: l, callId: e })),
(s = yield c(dl, { callId: e })),
(a = yield o(B, callOpenShareScreenDialogSaga)),
(d = yield o(q, callCloseShareScreenDialogSaga)),
(t = yield o(N, callSharedScreenSaga)),
(y = yield n([R, F, C, nl], callVideoLimitSaga)),
(f = yield n(A, Ol)),
(u = yield c(callAutoEndSaga, l)),
yield r(_),
(p = !1),
g?.cancel(),
a?.cancel(),
d?.cancel(),
t?.cancel(),
s?.cancel(),
y?.cancel(),
S?.destroy(),
f?.cancel(),
u?.cancel(),
(g = null),
yield tl())
}
} catch (l) {
yield I("callOngoingV1Saga", l)
} finally {
p &&
(g?.cancel(),
a?.cancel(),
d?.cancel(),
t?.cancel(),
y?.cancel(),
s?.cancel(),
S?.destroy(),
f?.cancel(),
u?.cancel(),
yield tl())
}
}
export function* callOngoingV2Saga({ roomId: l, discoveryKey: t }) {
const y = f()
let s = null,
u = null,
g = null,
S = null,
p = null,
h = null,
b = null,
v = null,
L = null,
O = null,
V = !0
try {
for (;;) {
const f = yield r(k),
x = f.payload?.callId,
D = x || (yield d(w))
if (!D) continue
if (((V = !0), !(yield d(Vl)))) {
yield I("callOngoingV2Saga", "unable to get member data")
continue
}
const { joined: E, cancelled: M } = yield a({ joined: e(El, y, l, D), cancelled: r([_, T]) })
if (M) continue
const K = E || D
;(yield i(W()),
yield i(X({ calls: [], memberIds: [] })),
(O = m().subscribeActivateCall(t)),
yield callVideoLimitSaga(),
yield i(j({ roomId: l })),
(L = yield c(ml, { roomId: l, callId: t })),
(s = yield c(Ml, y, l, K)),
(h = yield c(dl, { callId: t })),
(u = yield o(B, callOpenShareScreenDialogSaga)),
(g = yield o(q, callCloseShareScreenDialogSaga)),
(S = yield o(N, callSharedScreenSaga)),
(p = yield n([R, F, C, nl], callVideoLimitSaga)),
(b = yield n(A, Ol)),
(v = yield c(callAutoEndSaga, l)),
yield r(_),
(V = !1),
L?.cancel(),
s?.cancel(),
u?.cancel(),
g?.cancel(),
S?.cancel(),
h?.cancel(),
p?.cancel(),
O?.destroy(),
b?.cancel(),
v?.cancel(),
(L = null),
(s = null),
(b = null),
yield tl())
}
} catch (l) {
yield I("callOngoingV2Saga", l)
} finally {
V &&
(L?.cancel(),
s?.cancel(),
u?.cancel(),
g?.cancel(),
S?.cancel(),
p?.cancel(),
h?.cancel(),
O?.destroy(),
b?.cancel(),
v?.cancel(),
yield tl())
}
}
export function* callOngoingSaga({ roomId: l, callId: e }) {
for (; 0 === (yield d(fl(l))); ) yield r([ul, gl])
;(yield d(O(l)))
? yield callOngoingV2Saga({ roomId: l, discoveryKey: e })
: yield callOngoingV1Saga({ roomId: l, callId: e })
}