mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-21 17:29:32 +01:00
Refactor call audio routing and bluetooth management.
This commit is contained in:
@@ -1,214 +0,0 @@
|
||||
package org.thoughtcrime.securesms.events;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.annimon.stream.OptionalLong;
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import org.thoughtcrime.securesms.components.webrtc.BroadcastVideoSink;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class WebRtcViewModel {
|
||||
|
||||
public enum State {
|
||||
IDLE,
|
||||
|
||||
// Normal states
|
||||
CALL_PRE_JOIN,
|
||||
CALL_INCOMING,
|
||||
CALL_OUTGOING,
|
||||
CALL_CONNECTED,
|
||||
CALL_RINGING,
|
||||
CALL_BUSY,
|
||||
CALL_DISCONNECTED,
|
||||
CALL_NEEDS_PERMISSION,
|
||||
|
||||
// Error states
|
||||
NETWORK_FAILURE,
|
||||
RECIPIENT_UNAVAILABLE,
|
||||
NO_SUCH_USER,
|
||||
UNTRUSTED_IDENTITY,
|
||||
|
||||
// Multiring Hangup States
|
||||
CALL_ACCEPTED_ELSEWHERE,
|
||||
CALL_DECLINED_ELSEWHERE,
|
||||
CALL_ONGOING_ELSEWHERE;
|
||||
|
||||
public boolean isErrorState() {
|
||||
return this == NETWORK_FAILURE ||
|
||||
this == RECIPIENT_UNAVAILABLE ||
|
||||
this == NO_SUCH_USER ||
|
||||
this == UNTRUSTED_IDENTITY;
|
||||
}
|
||||
|
||||
public boolean isPreJoinOrNetworkUnavailable() {
|
||||
return this == CALL_PRE_JOIN || this == NETWORK_FAILURE;
|
||||
}
|
||||
|
||||
public boolean isPassedPreJoin() {
|
||||
return this.ordinal() > CALL_PRE_JOIN.ordinal();
|
||||
}
|
||||
}
|
||||
|
||||
public enum GroupCallState {
|
||||
IDLE,
|
||||
RINGING,
|
||||
DISCONNECTED,
|
||||
CONNECTING,
|
||||
RECONNECTING,
|
||||
CONNECTED,
|
||||
CONNECTED_AND_JOINING,
|
||||
CONNECTED_AND_JOINED;
|
||||
|
||||
public boolean isIdle() {
|
||||
return this == IDLE;
|
||||
}
|
||||
|
||||
public boolean isNotIdle() {
|
||||
return this != IDLE;
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
switch (this) {
|
||||
case CONNECTED:
|
||||
case CONNECTED_AND_JOINING:
|
||||
case CONNECTED_AND_JOINED:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isNotIdleOrConnected() {
|
||||
switch (this) {
|
||||
case DISCONNECTED:
|
||||
case CONNECTING:
|
||||
case RECONNECTING:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isRinging() {
|
||||
return this == RINGING;
|
||||
}
|
||||
}
|
||||
|
||||
private final @NonNull State state;
|
||||
private final @NonNull GroupCallState groupState;
|
||||
private final @NonNull Recipient recipient;
|
||||
|
||||
private final boolean isBluetoothAvailable;
|
||||
private final boolean isRemoteVideoOffer;
|
||||
private final long callConnectedTime;
|
||||
|
||||
private final CallParticipant localParticipant;
|
||||
private final List<CallParticipant> remoteParticipants;
|
||||
private final Set<RecipientId> identityChangedRecipients;
|
||||
private final OptionalLong remoteDevicesCount;
|
||||
private final Long participantLimit;
|
||||
private final boolean ringGroup;
|
||||
private final Recipient ringerRecipient;
|
||||
|
||||
public WebRtcViewModel(@NonNull WebRtcServiceState state) {
|
||||
this.state = state.getCallInfoState().getCallState();
|
||||
this.groupState = state.getCallInfoState().getGroupCallState();
|
||||
this.recipient = state.getCallInfoState().getCallRecipient();
|
||||
this.isRemoteVideoOffer = state.getCallSetupState().isRemoteVideoOffer();
|
||||
this.isBluetoothAvailable = state.getLocalDeviceState().isBluetoothAvailable();
|
||||
this.remoteParticipants = state.getCallInfoState().getRemoteCallParticipants();
|
||||
this.identityChangedRecipients = state.getCallInfoState().getIdentityChangedRecipients();
|
||||
this.callConnectedTime = state.getCallInfoState().getCallConnectedTime();
|
||||
this.remoteDevicesCount = state.getCallInfoState().getRemoteDevicesCount();
|
||||
this.participantLimit = state.getCallInfoState().getParticipantLimit();
|
||||
this.ringGroup = state.getCallSetupState().shouldRingGroup();
|
||||
this.ringerRecipient = state.getCallSetupState().getRingerRecipient();
|
||||
this.localParticipant = CallParticipant.createLocal(state.getLocalDeviceState().getCameraState(),
|
||||
state.getVideoState().getLocalSink() != null ? state.getVideoState().getLocalSink()
|
||||
: new BroadcastVideoSink(),
|
||||
state.getLocalDeviceState().isMicrophoneEnabled());
|
||||
}
|
||||
|
||||
public @NonNull State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public @NonNull GroupCallState getGroupState() {
|
||||
return groupState;
|
||||
}
|
||||
|
||||
public @NonNull Recipient getRecipient() {
|
||||
return recipient;
|
||||
}
|
||||
|
||||
public boolean isRemoteVideoEnabled() {
|
||||
return Stream.of(remoteParticipants).anyMatch(CallParticipant::isVideoEnabled) || (groupState.isNotIdle() && remoteParticipants.size() > 1);
|
||||
}
|
||||
|
||||
public boolean isBluetoothAvailable() {
|
||||
return isBluetoothAvailable;
|
||||
}
|
||||
|
||||
public boolean isRemoteVideoOffer() {
|
||||
return isRemoteVideoOffer;
|
||||
}
|
||||
|
||||
public long getCallConnectedTime() {
|
||||
return callConnectedTime;
|
||||
}
|
||||
|
||||
public @NonNull CallParticipant getLocalParticipant() {
|
||||
return localParticipant;
|
||||
}
|
||||
|
||||
public @NonNull List<CallParticipant> getRemoteParticipants() {
|
||||
return remoteParticipants;
|
||||
}
|
||||
|
||||
public @NonNull Set<RecipientId> getIdentityChangedParticipants() {
|
||||
return identityChangedRecipients;
|
||||
}
|
||||
|
||||
public OptionalLong getRemoteDevicesCount() {
|
||||
return remoteDevicesCount;
|
||||
}
|
||||
|
||||
public boolean areRemoteDevicesInCall() {
|
||||
return remoteDevicesCount.isPresent() && remoteDevicesCount.getAsLong() > 0;
|
||||
}
|
||||
|
||||
public @Nullable Long getParticipantLimit() {
|
||||
return participantLimit;
|
||||
}
|
||||
|
||||
public boolean shouldRingGroup() {
|
||||
return ringGroup;
|
||||
}
|
||||
|
||||
public @NonNull Recipient getRingerRecipient() {
|
||||
return ringerRecipient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull String toString() {
|
||||
return "WebRtcViewModel{" +
|
||||
"state=" + state +
|
||||
", recipient=" + recipient.getId() +
|
||||
", isBluetoothAvailable=" + isBluetoothAvailable +
|
||||
", isRemoteVideoOffer=" + isRemoteVideoOffer +
|
||||
", callConnectedTime=" + callConnectedTime +
|
||||
", localParticipant=" + localParticipant +
|
||||
", remoteParticipants=" + remoteParticipants +
|
||||
", identityChangedRecipients=" + identityChangedRecipients +
|
||||
", remoteDevicesCount=" + remoteDevicesCount +
|
||||
", participantLimit=" + participantLimit +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
package org.thoughtcrime.securesms.events
|
||||
|
||||
import com.annimon.stream.OptionalLong
|
||||
import org.thoughtcrime.securesms.components.webrtc.BroadcastVideoSink
|
||||
import org.thoughtcrime.securesms.events.CallParticipant.Companion.createLocal
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState
|
||||
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager
|
||||
|
||||
class WebRtcViewModel(state: WebRtcServiceState) {
|
||||
|
||||
enum class State {
|
||||
IDLE,
|
||||
|
||||
// Normal states
|
||||
CALL_PRE_JOIN,
|
||||
CALL_INCOMING,
|
||||
CALL_OUTGOING,
|
||||
CALL_CONNECTED,
|
||||
CALL_RINGING,
|
||||
CALL_BUSY,
|
||||
CALL_DISCONNECTED,
|
||||
CALL_NEEDS_PERMISSION,
|
||||
|
||||
// Error states
|
||||
NETWORK_FAILURE,
|
||||
RECIPIENT_UNAVAILABLE,
|
||||
NO_SUCH_USER,
|
||||
UNTRUSTED_IDENTITY,
|
||||
|
||||
// Multiring Hangup States
|
||||
CALL_ACCEPTED_ELSEWHERE,
|
||||
CALL_DECLINED_ELSEWHERE,
|
||||
CALL_ONGOING_ELSEWHERE;
|
||||
|
||||
val isErrorState: Boolean
|
||||
get() = this == NETWORK_FAILURE || this == RECIPIENT_UNAVAILABLE || this == NO_SUCH_USER || this == UNTRUSTED_IDENTITY
|
||||
|
||||
val isPreJoinOrNetworkUnavailable: Boolean
|
||||
get() = this == CALL_PRE_JOIN || this == NETWORK_FAILURE
|
||||
|
||||
val isPassedPreJoin: Boolean
|
||||
get() = ordinal > ordinal
|
||||
}
|
||||
|
||||
enum class GroupCallState {
|
||||
IDLE,
|
||||
RINGING,
|
||||
DISCONNECTED,
|
||||
CONNECTING,
|
||||
RECONNECTING,
|
||||
CONNECTED,
|
||||
CONNECTED_AND_JOINING,
|
||||
CONNECTED_AND_JOINED;
|
||||
|
||||
val isIdle: Boolean
|
||||
get() = this == IDLE
|
||||
|
||||
val isNotIdle: Boolean
|
||||
get() = this != IDLE
|
||||
|
||||
val isConnected: Boolean
|
||||
get() {
|
||||
return when (this) {
|
||||
CONNECTED, CONNECTED_AND_JOINING, CONNECTED_AND_JOINED -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
val isNotIdleOrConnected: Boolean
|
||||
get() {
|
||||
return when (this) {
|
||||
DISCONNECTED, CONNECTING, RECONNECTING -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
val isRinging: Boolean
|
||||
get() = this == RINGING
|
||||
}
|
||||
|
||||
val state: State = state.callInfoState.callState
|
||||
val groupState: GroupCallState = state.callInfoState.groupCallState
|
||||
val recipient: Recipient = state.callInfoState.callRecipient
|
||||
val isRemoteVideoOffer: Boolean = state.callSetupState.isRemoteVideoOffer
|
||||
val callConnectedTime: Long = state.callInfoState.callConnectedTime
|
||||
val remoteParticipants: List<CallParticipant> = state.callInfoState.remoteCallParticipants
|
||||
val identityChangedParticipants: Set<RecipientId> = state.callInfoState.identityChangedRecipients
|
||||
val remoteDevicesCount: OptionalLong = state.callInfoState.remoteDevicesCount
|
||||
val participantLimit: Long? = state.callInfoState.participantLimit
|
||||
@get:JvmName("shouldRingGroup")
|
||||
val ringGroup: Boolean = state.callSetupState.ringGroup
|
||||
val ringerRecipient: Recipient = state.callSetupState.ringerRecipient
|
||||
val activeDevice: SignalAudioManager.AudioDevice = state.localDeviceState.activeDevice
|
||||
val availableDevices: Set<SignalAudioManager.AudioDevice> = state.localDeviceState.availableDevices
|
||||
|
||||
val localParticipant: CallParticipant = createLocal(
|
||||
state.localDeviceState.cameraState,
|
||||
(if (state.videoState.localSink != null) state.videoState.localSink else BroadcastVideoSink())!!,
|
||||
state.localDeviceState.isMicrophoneEnabled
|
||||
)
|
||||
|
||||
val isRemoteVideoEnabled: Boolean
|
||||
get() = remoteParticipants.any(CallParticipant::isVideoEnabled) || groupState.isNotIdle && remoteParticipants.size > 1
|
||||
|
||||
fun areRemoteDevicesInCall(): Boolean {
|
||||
return remoteDevicesCount.isPresent && remoteDevicesCount.asLong > 0
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return """
|
||||
WebRtcViewModel {
|
||||
state=$state,
|
||||
recipient=${recipient.id},
|
||||
isRemoteVideoOffer=$isRemoteVideoOffer,
|
||||
callConnectedTime=$callConnectedTime,
|
||||
localParticipant=$localParticipant,
|
||||
remoteParticipants=$remoteParticipants,
|
||||
identityChangedRecipients=$identityChangedParticipants,
|
||||
remoteDevicesCount=$remoteDevicesCount,
|
||||
participantLimit=$participantLimit,
|
||||
activeDevice=$activeDevice,
|
||||
availableDevices=$availableDevices,
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user