Use thunks for calling action creators
This commit is contained in:
parent
618c0fce1e
commit
7e23bb6246
1 changed files with 94 additions and 112 deletions
|
@ -1,9 +1,11 @@
|
||||||
// Copyright 2020 Signal Messenger, LLC
|
// Copyright 2020 Signal Messenger, LLC
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
import { ThunkAction } from 'redux-thunk';
|
||||||
import { CallEndedReason } from 'ringrtc';
|
import { CallEndedReason } from 'ringrtc';
|
||||||
import { notify } from '../../services/notify';
|
import { notify } from '../../services/notify';
|
||||||
import { calling } from '../../services/calling';
|
import { calling } from '../../services/calling';
|
||||||
|
import { StateType as RootStateType } from '../reducer';
|
||||||
import {
|
import {
|
||||||
CallingDeviceType,
|
CallingDeviceType,
|
||||||
CallState,
|
CallState,
|
||||||
|
@ -11,7 +13,6 @@ import {
|
||||||
MediaDeviceSettings,
|
MediaDeviceSettings,
|
||||||
} from '../../types/Calling';
|
} from '../../types/Calling';
|
||||||
import { ColorType } from '../../types/Colors';
|
import { ColorType } from '../../types/Colors';
|
||||||
import { NoopActionType } from './noop';
|
|
||||||
import { callingTones } from '../../util/callingTones';
|
import { callingTones } from '../../util/callingTones';
|
||||||
import { requestCameraPermissions } from '../../util/callingPermissions';
|
import { requestCameraPermissions } from '../../util/callingPermissions';
|
||||||
import {
|
import {
|
||||||
|
@ -116,12 +117,10 @@ export function isCallActive({
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
|
|
||||||
const ACCEPT_CALL = 'calling/ACCEPT_CALL';
|
const ACCEPT_CALL_PENDING = 'calling/ACCEPT_CALL_PENDING';
|
||||||
const CANCEL_CALL = 'calling/CANCEL_CALL';
|
const CANCEL_CALL = 'calling/CANCEL_CALL';
|
||||||
const SHOW_CALL_LOBBY = 'calling/SHOW_CALL_LOBBY';
|
const SHOW_CALL_LOBBY = 'calling/SHOW_CALL_LOBBY';
|
||||||
const CALL_STATE_CHANGE = 'calling/CALL_STATE_CHANGE';
|
|
||||||
const CALL_STATE_CHANGE_FULFILLED = 'calling/CALL_STATE_CHANGE_FULFILLED';
|
const CALL_STATE_CHANGE_FULFILLED = 'calling/CALL_STATE_CHANGE_FULFILLED';
|
||||||
const CHANGE_IO_DEVICE = 'calling/CHANGE_IO_DEVICE';
|
|
||||||
const CHANGE_IO_DEVICE_FULFILLED = 'calling/CHANGE_IO_DEVICE_FULFILLED';
|
const CHANGE_IO_DEVICE_FULFILLED = 'calling/CHANGE_IO_DEVICE_FULFILLED';
|
||||||
const CLOSE_NEED_PERMISSION_SCREEN = 'calling/CLOSE_NEED_PERMISSION_SCREEN';
|
const CLOSE_NEED_PERMISSION_SCREEN = 'calling/CLOSE_NEED_PERMISSION_SCREEN';
|
||||||
const DECLINE_CALL = 'calling/DECLINE_CALL';
|
const DECLINE_CALL = 'calling/DECLINE_CALL';
|
||||||
|
@ -131,15 +130,14 @@ const OUTGOING_CALL = 'calling/OUTGOING_CALL';
|
||||||
const REFRESH_IO_DEVICES = 'calling/REFRESH_IO_DEVICES';
|
const REFRESH_IO_DEVICES = 'calling/REFRESH_IO_DEVICES';
|
||||||
const REMOTE_VIDEO_CHANGE = 'calling/REMOTE_VIDEO_CHANGE';
|
const REMOTE_VIDEO_CHANGE = 'calling/REMOTE_VIDEO_CHANGE';
|
||||||
const SET_LOCAL_AUDIO = 'calling/SET_LOCAL_AUDIO';
|
const SET_LOCAL_AUDIO = 'calling/SET_LOCAL_AUDIO';
|
||||||
const SET_LOCAL_VIDEO = 'calling/SET_LOCAL_VIDEO';
|
|
||||||
const SET_LOCAL_VIDEO_FULFILLED = 'calling/SET_LOCAL_VIDEO_FULFILLED';
|
const SET_LOCAL_VIDEO_FULFILLED = 'calling/SET_LOCAL_VIDEO_FULFILLED';
|
||||||
const START_CALL = 'calling/START_CALL';
|
const START_CALL = 'calling/START_CALL';
|
||||||
const TOGGLE_PARTICIPANTS = 'calling/TOGGLE_PARTICIPANTS';
|
const TOGGLE_PARTICIPANTS = 'calling/TOGGLE_PARTICIPANTS';
|
||||||
const TOGGLE_PIP = 'calling/TOGGLE_PIP';
|
const TOGGLE_PIP = 'calling/TOGGLE_PIP';
|
||||||
const TOGGLE_SETTINGS = 'calling/TOGGLE_SETTINGS';
|
const TOGGLE_SETTINGS = 'calling/TOGGLE_SETTINGS';
|
||||||
|
|
||||||
type AcceptCallActionType = {
|
type AcceptCallPendingActionType = {
|
||||||
type: 'calling/ACCEPT_CALL';
|
type: 'calling/ACCEPT_CALL_PENDING';
|
||||||
payload: AcceptCallType;
|
payload: AcceptCallType;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -152,21 +150,11 @@ type CallLobbyActionType = {
|
||||||
payload: OutgoingCallType;
|
payload: OutgoingCallType;
|
||||||
};
|
};
|
||||||
|
|
||||||
type CallStateChangeActionType = {
|
|
||||||
type: 'calling/CALL_STATE_CHANGE';
|
|
||||||
payload: Promise<CallStateChangeType>;
|
|
||||||
};
|
|
||||||
|
|
||||||
type CallStateChangeFulfilledActionType = {
|
type CallStateChangeFulfilledActionType = {
|
||||||
type: 'calling/CALL_STATE_CHANGE_FULFILLED';
|
type: 'calling/CALL_STATE_CHANGE_FULFILLED';
|
||||||
payload: CallStateChangeType;
|
payload: CallStateChangeType;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ChangeIODeviceActionType = {
|
|
||||||
type: 'calling/CHANGE_IO_DEVICE';
|
|
||||||
payload: Promise<ChangeIODevicePayloadType>;
|
|
||||||
};
|
|
||||||
|
|
||||||
type ChangeIODeviceFulfilledActionType = {
|
type ChangeIODeviceFulfilledActionType = {
|
||||||
type: 'calling/CHANGE_IO_DEVICE_FULFILLED';
|
type: 'calling/CHANGE_IO_DEVICE_FULFILLED';
|
||||||
payload: ChangeIODevicePayloadType;
|
payload: ChangeIODevicePayloadType;
|
||||||
|
@ -212,11 +200,6 @@ type SetLocalAudioActionType = {
|
||||||
payload: SetLocalAudioType;
|
payload: SetLocalAudioType;
|
||||||
};
|
};
|
||||||
|
|
||||||
type SetLocalVideoActionType = {
|
|
||||||
type: 'calling/SET_LOCAL_VIDEO';
|
|
||||||
payload: Promise<SetLocalVideoType>;
|
|
||||||
};
|
|
||||||
|
|
||||||
type SetLocalVideoFulfilledActionType = {
|
type SetLocalVideoFulfilledActionType = {
|
||||||
type: 'calling/SET_LOCAL_VIDEO_FULFILLED';
|
type: 'calling/SET_LOCAL_VIDEO_FULFILLED';
|
||||||
payload: SetLocalVideoType;
|
payload: SetLocalVideoType;
|
||||||
|
@ -239,12 +222,10 @@ type ToggleSettingsActionType = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CallingActionType =
|
export type CallingActionType =
|
||||||
| AcceptCallActionType
|
| AcceptCallPendingActionType
|
||||||
| CancelCallActionType
|
| CancelCallActionType
|
||||||
| CallLobbyActionType
|
| CallLobbyActionType
|
||||||
| CallStateChangeActionType
|
|
||||||
| CallStateChangeFulfilledActionType
|
| CallStateChangeFulfilledActionType
|
||||||
| ChangeIODeviceActionType
|
|
||||||
| ChangeIODeviceFulfilledActionType
|
| ChangeIODeviceFulfilledActionType
|
||||||
| CloseNeedPermissionScreenActionType
|
| CloseNeedPermissionScreenActionType
|
||||||
| DeclineCallActionType
|
| DeclineCallActionType
|
||||||
|
@ -254,7 +235,6 @@ export type CallingActionType =
|
||||||
| RefreshIODevicesActionType
|
| RefreshIODevicesActionType
|
||||||
| RemoteVideoChangeActionType
|
| RemoteVideoChangeActionType
|
||||||
| SetLocalAudioActionType
|
| SetLocalAudioActionType
|
||||||
| SetLocalVideoActionType
|
|
||||||
| SetLocalVideoFulfilledActionType
|
| SetLocalVideoFulfilledActionType
|
||||||
| StartCallActionType
|
| StartCallActionType
|
||||||
| ToggleParticipantsActionType
|
| ToggleParticipantsActionType
|
||||||
|
@ -265,73 +245,76 @@ export type CallingActionType =
|
||||||
|
|
||||||
function acceptCall(
|
function acceptCall(
|
||||||
payload: AcceptCallType
|
payload: AcceptCallType
|
||||||
): AcceptCallActionType | NoopActionType {
|
): ThunkAction<void, RootStateType, unknown, AcceptCallPendingActionType> {
|
||||||
(async () => {
|
return async dispatch => {
|
||||||
|
dispatch({
|
||||||
|
type: ACCEPT_CALL_PENDING,
|
||||||
|
payload,
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await calling.accept(payload.callId, payload.asVideoCall);
|
await calling.accept(payload.callId, payload.asVideoCall);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
window.log.error(`Failed to acceptCall: ${err.stack}`);
|
window.log.error(`Failed to acceptCall: ${err.stack}`);
|
||||||
}
|
}
|
||||||
})();
|
|
||||||
|
|
||||||
return {
|
|
||||||
type: ACCEPT_CALL,
|
|
||||||
payload,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function callStateChange(
|
function callStateChange(
|
||||||
payload: CallStateChangeType
|
payload: CallStateChangeType
|
||||||
): CallStateChangeActionType {
|
): ThunkAction<
|
||||||
return {
|
void,
|
||||||
type: CALL_STATE_CHANGE,
|
RootStateType,
|
||||||
payload: doCallStateChange(payload),
|
unknown,
|
||||||
|
CallStateChangeFulfilledActionType
|
||||||
|
> {
|
||||||
|
return async dispatch => {
|
||||||
|
const { callDetails, callState } = payload;
|
||||||
|
const { isIncoming } = callDetails;
|
||||||
|
if (callState === CallState.Ringing && isIncoming) {
|
||||||
|
await callingTones.playRingtone();
|
||||||
|
await showCallNotification(callDetails);
|
||||||
|
bounceAppIconStart();
|
||||||
|
}
|
||||||
|
if (callState !== CallState.Ringing) {
|
||||||
|
await callingTones.stopRingtone();
|
||||||
|
bounceAppIconStop();
|
||||||
|
}
|
||||||
|
if (callState === CallState.Ended) {
|
||||||
|
await callingTones.playEndCall();
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: CALL_STATE_CHANGE_FULFILLED,
|
||||||
|
payload,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeIODevice(
|
function changeIODevice(
|
||||||
payload: ChangeIODevicePayloadType
|
payload: ChangeIODevicePayloadType
|
||||||
): ChangeIODeviceActionType {
|
): ThunkAction<
|
||||||
return {
|
void,
|
||||||
type: CHANGE_IO_DEVICE,
|
RootStateType,
|
||||||
payload: doChangeIODevice(payload),
|
unknown,
|
||||||
|
ChangeIODeviceFulfilledActionType
|
||||||
|
> {
|
||||||
|
return async dispatch => {
|
||||||
|
// Only `setPreferredCamera` returns a Promise.
|
||||||
|
if (payload.type === CallingDeviceType.CAMERA) {
|
||||||
|
await calling.setPreferredCamera(payload.selectedDevice);
|
||||||
|
} else if (payload.type === CallingDeviceType.MICROPHONE) {
|
||||||
|
calling.setPreferredMicrophone(payload.selectedDevice);
|
||||||
|
} else if (payload.type === CallingDeviceType.SPEAKER) {
|
||||||
|
calling.setPreferredSpeaker(payload.selectedDevice);
|
||||||
|
}
|
||||||
|
dispatch({
|
||||||
|
type: CHANGE_IO_DEVICE_FULFILLED,
|
||||||
|
payload,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function doChangeIODevice(
|
|
||||||
payload: ChangeIODevicePayloadType
|
|
||||||
): Promise<ChangeIODevicePayloadType> {
|
|
||||||
if (payload.type === CallingDeviceType.CAMERA) {
|
|
||||||
await calling.setPreferredCamera(payload.selectedDevice);
|
|
||||||
} else if (payload.type === CallingDeviceType.MICROPHONE) {
|
|
||||||
calling.setPreferredMicrophone(payload.selectedDevice);
|
|
||||||
} else if (payload.type === CallingDeviceType.SPEAKER) {
|
|
||||||
calling.setPreferredSpeaker(payload.selectedDevice);
|
|
||||||
}
|
|
||||||
|
|
||||||
return payload;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function doCallStateChange(
|
|
||||||
payload: CallStateChangeType
|
|
||||||
): Promise<CallStateChangeType> {
|
|
||||||
const { callDetails, callState } = payload;
|
|
||||||
const { isIncoming } = callDetails;
|
|
||||||
if (callState === CallState.Ringing && isIncoming) {
|
|
||||||
await callingTones.playRingtone();
|
|
||||||
await showCallNotification(callDetails);
|
|
||||||
bounceAppIconStart();
|
|
||||||
}
|
|
||||||
if (callState !== CallState.Ringing) {
|
|
||||||
await callingTones.stopRingtone();
|
|
||||||
bounceAppIconStop();
|
|
||||||
}
|
|
||||||
if (callState === CallState.Ended) {
|
|
||||||
await callingTones.playEndCall();
|
|
||||||
}
|
|
||||||
return payload;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function showCallNotification(callDetails: CallDetailsType) {
|
async function showCallNotification(callDetails: CallDetailsType) {
|
||||||
const canNotify = await window.getCallSystemNotification();
|
const canNotify = await window.getCallSystemNotification();
|
||||||
if (!canNotify) {
|
if (!canNotify) {
|
||||||
|
@ -420,21 +403,19 @@ function remoteVideoChange(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function setLocalPreview(payload: SetLocalPreviewType): NoopActionType {
|
function setLocalPreview(
|
||||||
calling.videoCapturer.setLocalPreview(payload.element);
|
payload: SetLocalPreviewType
|
||||||
|
): ThunkAction<void, RootStateType, unknown, never> {
|
||||||
return {
|
return () => {
|
||||||
type: 'NOOP',
|
calling.videoCapturer.setLocalPreview(payload.element);
|
||||||
payload: null,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function setRendererCanvas(payload: SetRendererCanvasType): NoopActionType {
|
function setRendererCanvas(
|
||||||
calling.videoRenderer.setCanvas(payload.element);
|
payload: SetRendererCanvasType
|
||||||
|
): ThunkAction<void, RootStateType, unknown, never> {
|
||||||
return {
|
return () => {
|
||||||
type: 'NOOP',
|
calling.videoRenderer.setCanvas(payload.element);
|
||||||
payload: null,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -449,10 +430,31 @@ function setLocalAudio(payload: SetLocalAudioType): SetLocalAudioActionType {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function setLocalVideo(payload: SetLocalVideoType): SetLocalVideoActionType {
|
function setLocalVideo(
|
||||||
return {
|
payload: SetLocalVideoType
|
||||||
type: SET_LOCAL_VIDEO,
|
): ThunkAction<void, RootStateType, unknown, SetLocalVideoFulfilledActionType> {
|
||||||
payload: doSetLocalVideo(payload),
|
return async dispatch => {
|
||||||
|
let enabled: boolean;
|
||||||
|
if (await requestCameraPermissions()) {
|
||||||
|
if (payload.callId) {
|
||||||
|
calling.setOutgoingVideo(payload.callId, payload.enabled);
|
||||||
|
} else if (payload.enabled) {
|
||||||
|
calling.enableLocalCamera();
|
||||||
|
} else {
|
||||||
|
calling.disableLocalCamera();
|
||||||
|
}
|
||||||
|
({ enabled } = payload);
|
||||||
|
} else {
|
||||||
|
enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: SET_LOCAL_VIDEO_FULFILLED,
|
||||||
|
payload: {
|
||||||
|
...payload,
|
||||||
|
enabled,
|
||||||
|
},
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -493,26 +495,6 @@ function toggleSettings(): ToggleSettingsActionType {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function doSetLocalVideo(
|
|
||||||
payload: SetLocalVideoType
|
|
||||||
): Promise<SetLocalVideoType> {
|
|
||||||
if (await requestCameraPermissions()) {
|
|
||||||
if (payload.callId) {
|
|
||||||
calling.setOutgoingVideo(payload.callId, payload.enabled);
|
|
||||||
} else if (payload.enabled) {
|
|
||||||
calling.enableLocalCamera();
|
|
||||||
} else {
|
|
||||||
calling.disableLocalCamera();
|
|
||||||
}
|
|
||||||
return payload;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...payload,
|
|
||||||
enabled: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const actions = {
|
export const actions = {
|
||||||
acceptCall,
|
acceptCall,
|
||||||
cancelCall,
|
cancelCall,
|
||||||
|
@ -581,7 +563,7 @@ export function reducer(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.type === ACCEPT_CALL) {
|
if (action.type === ACCEPT_CALL_PENDING) {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
hasLocalAudio: true,
|
hasLocalAudio: true,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue