OverviewFilesCommitsIssuesDocsReleasesPeers

keet-deobfuscated / @holepunchto / keet-store / store / ui-mobile / ui-call.saga.js

207 lines · javascript ref:
import {
  select as e,
  put as i,
  take as l,
  getContext as t,
  call as a,
  takeLatest as n,
  takeEvery as o,
  delay as r,
  fork as d,
  race as c,
} from "redux-saga/effects"
import { getAppCurrentRoomId as y, hasAppCurrentRoomCallMatch as s } from "../app"
import { getRoomCanCall as m, getRoomItemById as g } from "../room"
import { taskErrorSaga as u } from "../error"
import {
  getCallStatus as p,
  getCallId as C,
  callJoinCmd as f,
  callLeave as S,
  CALL_STATUS as v,
  openCallSettings as R,
  isCallJoinedMode as A,
  updateCallRemoteMedia as E,
  removeCallRemoteMedia as b,
  STREAM_TYPE as h,
  callCancel as w,
} from "../call"
import {
  uiLeaveAndJoinNewCall as N,
  uiShowMicPermissionBottomSheet as O,
  uiShowCallOnGoingBottomSheet as _,
  uiStartCall as I,
  uiCallWebrtcCleared as L,
  uiExpoDeviceVibrateSuccess as x,
  uiNavigateToRoute as M,
  uiShowCallPreview as T,
  uiCallFetchAudioOutputs as F,
  uiUpdateWorklet as k,
} from "./ui.action"
import { APP_CONTEXT_KEY as H } from "../constants"
import { userErrorNotification as J, userInfoNotification as V } from "../notification"
import {
  setUIIsCallLoading as j,
  setUICallAudioOutputs as D,
  setUICallCurrentAudioOutput as K,
  getUIAppNavigatorCurrentRoute as P,
  setUICallScreenVideoTrackId as U,
} from "./ui.reducer"
import { requestMicPermissionSaga as W } from "../media/media-permissions.saga"
import { getCallApi as B, getCoreBackend as X } from "../../backend"
import { apiTakeMatch as q } from "../lib/external-src"
import { setupWebrtcCallInfra as z } from "./ui-call.utils"
export const MAX_ACTIVE_CALL_WAIT = 2e4
export function* waitForActiveCallSync(e) {
  try {
    const n = X(),
      o = yield c({
        hasActiveCall: q([n.subscribeActiveCalls, e], {
          matchFn: (e) => e.length > 0,
          onError: (e) => u("waitForActiveCallSync: subscribeActiveCalls", e),
        }),
        cancelled: l(w),
        timedout: r(2e4),
      })
    if (o.timedout) {
      const { navigationHelpers: e, webRTC: l, localeManager: n } = yield t(H),
        o = n.getStrings(),
        { timedoutJoinCall: r } = o.call
      ;(yield i(J({ message: r })),
        e.back(),
        yield a(l.setInCall, { enabled: !1 }),
        yield i(L()),
        yield i(k()))
    }
    return o
  } catch (e) {
    return (yield u("waitForActiveCallSync", e), { timedout: !0 })
  }
}
function* G(l) {
  try {
    const { payload: n } = l || {},
      o = yield e(y),
      r = n?.answeringCallRing
    if (o) {
      const { localeManager: l, navigationConstants: d } = yield t(H),
        c = l.getStrings(),
        y = yield e(g(o))
      if (!y.canCall) return void (yield i(V({ message: c.room.callDisabledNotification })))
      const m = yield e(p),
        u = yield e(s)
      if (m === v.JOINED && !u) return void (yield i(_()))
      if ((yield i(j(!0)), !(yield W()))) return void (yield i(O()))
      if (r) {
        const { timedout: e, cancelled: i } = yield a(waitForActiveCallSync, o)
        if (e || i) return
      }
      ;(yield i(f()),
        yield i(M({ routeName: d.SCREEN_ROOM_CALL, params: { roomId: o } })),
        yield a(z, {
          roomTitle: y.title,
          hasExistingCallKit: r,
          answeringInAppCallRing: n?.answeringInAppCallRing,
        }))
    }
  } catch (e) {
    yield u("startCallSaga", e)
  } finally {
    yield i(j(!1))
  }
}
function* Q() {
  try {
    const { navigationConstants: e, navigationHelpers: a } = yield t(H)
    ;(yield i(S()), yield l(L), yield r(500), yield i(R()), a.navigate(e.SCREEN_ROOM_CALL_PREVIEW))
  } catch (e) {
    yield u("leaveAndJoinNewCallSaga", e)
  }
}
function* Y() {
  try {
    const {
      navigationConstants: l,
      navigationHelpers: n,
      webRTC: o,
      callBackgroundHandler: r,
    } = yield t(H)
    ;((yield e(P)) === l.SCREEN_ROOM_CALL && n.back(),
      yield a(o.setInCall, { enabled: !1 }),
      yield a(r.stopService),
      yield a(o.setKeepScreenOn, !1),
      yield i(L()))
  } catch (e) {
    yield u("uiCallLeaveSaga", e)
  }
}
function* Z(l) {
  try {
    const { payload: a } = l || {},
      n = a?.joinCall,
      o = yield e(y),
      r = yield e(p),
      d = yield e(s),
      c = yield A(r),
      g = yield e(m(o)),
      { navigationConstants: u, navigationHelpers: C, localeManager: f } = yield t(H),
      S = f.getStrings()
    ;(yield i(x(o)),
      c && !d
        ? yield i(_())
        : g
          ? (yield i(R()), C.navigate(u.SCREEN_ROOM_CALL_PREVIEW, { joinCall: n }))
          : yield i(V({ message: S.room.callDisabledNotification })))
  } catch (e) {
    yield u("showCallPreviewSaga", e)
  }
}
function* $() {
  try {
    const { webRTC: e } = yield t(H),
      l = yield a(e.listAudioRoutes)
    yield i(D(l))
    const n = yield a(e.getAudioOutput)
    yield i(K(n.type))
  } catch (e) {
    yield u("uiCallFetchAudioOutputsSaga", e)
  }
}
function* ee(i) {
  try {
    if (!i.payload?.resume) return
    const l = yield e(y),
      t = yield e(g(l))
    yield d(z, { roomTitle: t.title, hasExistingCallKit: !1, answeringInAppCallRing: !1 })
  } catch (e) {
    yield u("resumeCallJoinSaga", e)
  }
}
export function* screenStreamUpdateSaga(l) {
  try {
    const { streamName: t, streamId: a, videoMuted: n } = l.payload
    if (t !== h.SCREEN) return
    if (n) return void (yield i(U(null)))
    const o = yield e(C)
    if (!o || !a) return
    const r = B().getRemoteSrcObject(o, a),
      d = r?.getVideoTracks?.()[0]
    yield i(U(d ? String(d) : null))
  } catch (e) {
    yield u("screenStreamUpdateSaga", e)
  }
}
export function* screenStreamRemoveSaga(e) {
  e.payload?.streamName === h.SCREEN && (yield i(U(null)))
}
export function* uiCallSaga() {
  ;(yield n(I, G),
    yield n(S, Y),
    yield n(N, Q),
    yield n(T, Z),
    yield n(F, $),
    yield n(f, ee),
    yield o(E, screenStreamUpdateSaga),
    yield o(b, screenStreamRemoveSaga))
}