OverviewFilesCommitsIssuesDocsReleasesPeers

keet-deobfuscated / @holepunchto / keet-store / store / call / call-settings.saga.js

275 lines · javascript ref:
import {
  race as e,
  fork as i,
  take as a,
  put as l,
  all as d,
  call as o,
  takeLeading as t,
  select as c,
  takeLatest as n,
  flush as y,
  actionChannel as r,
  getContext as s,
  delay as u,
} from "redux-saga/effects"
import { getCallApi as m } from "../../backend"
import {
  getPreferencesData as p,
  PREFERENCES as f,
  preferenceUpdateTask as S,
} from "../preferences"
import {
  getDeviceState as g,
  getCameraAudioConstraints as v,
  getCameraVideoConstraints as I,
  getVideoDevice as D,
  getAudioDevice as A,
  setVideoDevice as V,
  setAudioDevice as h,
  setAudioOutputDevice as x,
  getVideoDevices as M,
  getFaceCamDeviceStaticId as O,
  setAllDevices as w,
  checkDevicePermissionCompleted as C,
} from "../media"
import { taskError as T, taskErrorSaga as E } from "../error"
import {
  getCallPeerVideoCount as U,
  getCallStatus as _,
  isCallSettingsMode as P,
} from "./call.reducer"
import {
  callAudioDeviceUpdate as k,
  callAudioStreamToggle as L,
  callAudioOutputDeviceUpdate as Q,
  callVideoDeviceUpdate as b,
  callVideoStreamToggle as F,
  callVideoQualityUpdate as H,
  callJoinedEvt as B,
  callCancel as R,
  callToggleVideo as j,
  callSwapVideoCamera as Y,
  callLeave as G,
  callReset as N,
  callCloseVideo as $,
} from "./call.action"
import {
  getMyAudioMuted as q,
  getMyVideoMuted as z,
  getMyVideoQuality as J,
  getMyCameraStreamId as K,
  getMyVideoAllowed as W,
  getMyVideoLimits as X,
  getCallSettingsState as Z,
} from "./call-settings.reducer"
import {
  setMyVideoMuted as ee,
  setMyVideoQuality as ie,
  setMyAudioMuted as ae,
  setMyCameraStreamId as le,
  setCallSettingsReady as de,
  updateMyCameraStreamCmd as oe,
  setMyVideoTrackId as te,
} from "./call-settings.action"
import {
  CALL_VIDEO_LIMIT_MEMBERS_GT as ce,
  DEVICE_INIT_TIMEOUT as ne,
  PERMISSION_NOT_GRANTED_ERROR_NAME as ye,
  STREAM_TYPE as re,
} from "./call.constants"
import {
  cacheAllMediaPermissions as se,
  checkCameraPermissionGranted as ue,
  checkMicPermissionGranted as me,
  isMediaPermissionsSupported as pe,
} from "../media/media-permissions.saga"
import { ENV_CONTEXT_KEY as fe } from "../constants"
import { first as Se } from "../lib/array"
import { DEVICE_PERMISSION as ge } from "../media/device.constants"
export function* checkAudioSaga(e) {
  if (yield c(q)) return
  if (!(yield pe())) return
  const i = yield me(e)
  i || (yield l(ae(!0)), i && (yield l(ae(!1)), yield l(oe())))
}
export function* checkVideoSaga(e) {
  if (yield c(z)) return
  if (!(yield pe())) return
  const i = yield ue(e)
  i || (yield l(ee(!0)), i && (yield l(ee(!1)), yield l(oe())))
}
export function* windowsPermissionsHandleSaga(e) {
  ;(yield l(ae(!0)), yield l(ee(!0)))
  const i = e?.showModalForCamera ? ge.CAMERA : e?.showModalForMicrophone && ge.MICROPHONE
  i && (yield l(C({ permission: i, isGranted: !1, showPermissionDeniedModal: !0 })))
}
export function* updateCameraStream(e) {
  const [i, a, o, t, n, y, r, s] = yield d([c(_), c(K), c(D), c(z), c(J), c(X), c(A), c(q)])
  P(i) && (yield l(de(!1)))
  const u = y.meAllowed ? t : !y.allowed || t,
    p = Math.min(y.maxQuality, n),
    f = I({ videoDevice: o, videoMuted: u, videoQuality: p }),
    S = v({ audioDevice: r, audioMuted: s })
  try {
    yield m().local.applyStreamConstraints(a, { audio: S, video: f })
    const e = m().local.videoTrack?.id
    yield l(te(e))
  } catch (i) {
    i.name === ye ? yield windowsPermissionsHandleSaga(e) : yield E("updateCameraStream", i)
  }
  P(i) && (yield l(de(!0)))
}
const ve = { showPermissionDeniedModal: !0 }
export function* updateCameraStreamSaga() {
  const e = yield r(oe)
  try {
    for (;;) {
      const { payload: i } = yield a(e)
      ;(yield checkAudioSaga(ve), yield checkVideoSaga(ve), yield updateCameraStream(i))
    }
  } finally {
    yield y(e)
  }
}
export function* callVideoDeviceSaga({ payload: e }) {
  const { devicesMap: i } = yield c(g)
  ;(yield l(V(i[e])), yield l(oe()))
}
export function* callVideoStreamToggleSaga() {
  const e = yield c(z)
  ;(yield c(W)) && (yield l(ee(!e)), yield l(oe({ showModalForCamera: !0 })))
}
export function* callVideoQualitySaga({ payload: e }) {
  ;(yield c(W)) && (yield l(ie(e)), yield l(oe()))
}
export function* callAudioDeviceSaga({ payload: e }) {
  const { devicesMap: i } = yield c(g)
  ;(yield l(h(i[e])), yield l(oe()))
}
export function* callAudioStreamToggleSaga() {
  const e = yield c(q)
  ;(yield l(ae(!e)), yield l(oe({ showModalForMicrophone: !0 })))
}
export function* callAudioOutputDeviceSaga({ payload: e }) {
  const { devicesMap: i } = yield c(g)
  yield l(x(i[e]))
}
export function* updateDevicePreferences() {
  const i = yield c(p),
    d = i[f.IS_VIDEO_DISABLED],
    o = i[f.IS_AUDIO_DISABLED]
  ;("boolean" == typeof o && (yield l(ae(o))), "boolean" == typeof d && (yield l(ee(d))))
  const { isReady: t } = yield c(g)
  if (!t) {
    const [i] = yield e([u(ne, { message: "timed out" }), a(w)])
    if (i)
      return void (yield l(T("updateDevicePreferences", { message: `init fail: ${i.message}` })))
  }
  const n = yield c(g),
    { audio: y, video: r, audioOutput: s, devicesMap: m } = n,
    S = m[i[f.AUDIO]] || y.devices.find((e) => e.default) || Se(y.devices) || null
  yield l(h(S))
  const v = m[i[f.AUDIO_OUTPUT]] || s.devices.find((e) => e.default) || Se(s.devices) || null
  yield l(x(v))
  const I = m[i[f.VIDEO]] || r.devices.find((e) => e.default) || Se(r.devices) || null
  yield l(V(I))
  const D = i[f.VIDEO_QUALITY]
  ;("number" == typeof D && (yield l(ie(D))), d || (yield l(oe())))
}
export function* callPreferencesSaga() {
  ;(yield n(V, function* ({ payload: e }) {
    const i = e?.deviceStaticId || ""
    yield o(S, f.VIDEO, i)
  }),
    yield n(ee, function* ({ payload: e }) {
      yield o(S, f.IS_VIDEO_DISABLED, e)
    }),
    yield n(ie, function* ({ payload: e }) {
      yield o(S, f.VIDEO_QUALITY, e)
    }),
    yield n(h, function* ({ payload: e }) {
      const i = e?.deviceStaticId || ""
      yield o(S, f.AUDIO, i)
    }),
    yield n(ae, function* ({ payload: e }) {
      yield o(S, f.IS_AUDIO_DISABLED, e)
    }),
    yield n(x, function* ({ payload: e }) {
      const i = e?.deviceStaticId || ""
      yield o(S, f.AUDIO_OUTPUT, i)
    }))
}
export function* callVideoToggleSaga() {
  try {
    const { isIOS: e } = yield s(fe),
      { isVideoMuted: i } = yield c(Z)
    if (i) {
      if ((yield c(U)) < ce) {
        const i = yield c(M),
          a = yield c(D)
        ;((a && i.some((e) => e.deviceStaticId === a.deviceStaticId)) ||
          (i.find((i) => i.deviceStaticId === O(e)) && (yield l(b(O(e))))),
          yield l(H(e ? 2 : 1)),
          yield l(F()))
      }
    } else yield l(F())
  } catch (e) {
    yield E("callVideoToggleSaga", e)
  }
}
export function* callVideoCloseSaga() {
  ;(yield c(z)) || (yield l(ee(!0)), yield l(oe({ showModalForCamera: !0 })))
}
export function* callSwapViewCameraSaga() {
  try {
    const e = yield c(M),
      i = yield c(D),
      a = e.find((e) => e.deviceStaticId !== i.deviceStaticId)
    a && (yield l(b(a.deviceStaticId)))
  } catch (e) {
    yield E("callSwapViewCameraSaga", e)
  }
}
export function* callSettingsHandler() {
  ;(yield t(k, callAudioDeviceSaga),
    yield t(L, callAudioStreamToggleSaga),
    yield t(Q, callAudioOutputDeviceSaga),
    yield t(b, callVideoDeviceSaga),
    yield t(F, callVideoStreamToggleSaga),
    yield t(H, callVideoQualitySaga),
    yield t(j, callVideoToggleSaga),
    yield t(Y, callSwapViewCameraSaga),
    yield t($, callVideoCloseSaga))
}
export function* callSettingsSaga() {
  let d = null,
    t = null
  try {
    yield e({
      main: o(function* () {
        ;(yield updateDevicePreferences(), yield se())
        const o = m().local.openStream(re.CAMERA)
        ;(yield l(le({ streamId: o })),
          (d = yield i(updateCameraStreamSaga)),
          (t = yield i(callSettingsHandler)),
          yield checkAudioSaga(),
          yield checkVideoSaga(),
          yield updateCameraStream())
        const { cancelAction: c, joinedAction: n } = yield e({
          cancelAction: a(R),
          joinedAction: a(B),
        })
        ;(c &&
          (o && (yield l(le({ streamId: "" })), m().local.closeStream(o)), d.cancel(), t.cancel()),
          n && (yield a(G), d.cancel(), t.cancel()))
      }),
      cancel: a(N),
    })
  } catch (e) {
    yield E("call-settings", e)
  } finally {
    ;(d && d.cancel(), t && t.cancel())
  }
}