Refactor call audio routing and bluetooth management.

This commit is contained in:
Cody Henthorne
2021-09-27 11:23:10 -04:00
parent 6c55916cda
commit e637f15a43
36 changed files with 1345 additions and 981 deletions

View File

@@ -1,7 +1,5 @@
package org.thoughtcrime.securesms.service.webrtc;
import android.media.AudioManager;
import androidx.annotation.NonNull;
import org.signal.core.util.logging.Log;
@@ -13,7 +11,6 @@ import org.thoughtcrime.securesms.events.CallParticipantId;
import org.thoughtcrime.securesms.events.WebRtcViewModel;
import org.thoughtcrime.securesms.ringrtc.RemotePeer;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
import static org.thoughtcrime.securesms.webrtc.CallNotificationBuilder.TYPE_INCOMING_CONNECTING;
@@ -76,9 +73,6 @@ public class BeginCallActionProcessorDelegate extends WebRtcActionProcessor {
Log.i(tag, "assign activePeer callId: " + remotePeer.getCallId() + " key: " + remotePeer.hashCode());
AudioManager androidAudioManager = ServiceUtil.getAudioManager(context);
androidAudioManager.setSpeakerphoneOn(false);
webRtcInteractor.setCallInProgressNotification(TYPE_INCOMING_CONNECTING, remotePeer);
webRtcInteractor.retrieveTurnServers(remotePeer);

View File

@@ -7,11 +7,11 @@ import org.signal.ringrtc.CallException;
import org.signal.ringrtc.CallManager;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.events.WebRtcViewModel;
import org.thoughtcrime.securesms.ringrtc.CallState;
import org.thoughtcrime.securesms.ringrtc.Camera;
import org.thoughtcrime.securesms.ringrtc.RemotePeer;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
import org.thoughtcrime.securesms.util.NetworkUtil;
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager;
import org.thoughtcrime.securesms.webrtc.locks.LockManager;
import static org.thoughtcrime.securesms.webrtc.CallNotificationBuilder.TYPE_ESTABLISHED;
@@ -39,7 +39,7 @@ public class CallSetupActionProcessorDelegate extends WebRtcActionProcessor {
RemotePeer activePeer = currentState.getCallInfoState().requireActivePeer();
ApplicationDependencies.getAppForegroundObserver().removeListener(webRtcInteractor.getForegroundListener());
webRtcInteractor.startAudioCommunication(activePeer.getState() == CallState.REMOTE_RINGING);
webRtcInteractor.startAudioCommunication();
activePeer.connected();
@@ -56,12 +56,10 @@ public class CallSetupActionProcessorDelegate extends WebRtcActionProcessor {
.callConnectedTime(System.currentTimeMillis())
.commit()
.changeLocalDeviceState()
.wantsBluetooth(true)
.build();
webRtcInteractor.setCallInProgressNotification(TYPE_ESTABLISHED, activePeer);
webRtcInteractor.unregisterPowerButtonReceiver();
webRtcInteractor.setWantsBluetoothConnection(true);
try {
CallManager callManager = webRtcInteractor.getCallManager();
@@ -77,6 +75,12 @@ public class CallSetupActionProcessorDelegate extends WebRtcActionProcessor {
currentState = currentState.getActionProcessor().handleSetEnableVideo(currentState, true);
}
if (currentState.getCallSetupState().isAcceptWithVideo() || currentState.getLocalDeviceState().getCameraState().isEnabled()) {
webRtcInteractor.setDefaultAudioDevice(SignalAudioManager.AudioDevice.SPEAKER_PHONE, false);
} else {
webRtcInteractor.setDefaultAudioDevice(SignalAudioManager.AudioDevice.EARPIECE, false);
}
return currentState;
}
@@ -98,7 +102,7 @@ public class CallSetupActionProcessorDelegate extends WebRtcActionProcessor {
.cameraState(camera.getCameraState())
.build();
WebRtcUtil.enableSpeakerPhoneIfNeeded(context, currentState.getCallSetupState().isEnableVideoOnCreate());
WebRtcUtil.enableSpeakerPhoneIfNeeded(webRtcInteractor, currentState);
return currentState;
}

View File

@@ -55,7 +55,7 @@ public class ConnectedCallActionProcessor extends DeviceAwareActionProcessor {
webRtcInteractor.updatePhoneState(WebRtcUtil.getInCallPhoneState(context));
}
WebRtcUtil.enableSpeakerPhoneIfNeeded(context, currentState.getLocalDeviceState().getCameraState().isEnabled());
WebRtcUtil.enableSpeakerPhoneIfNeeded(webRtcInteractor, currentState);
return currentState;
}

View File

@@ -1,15 +1,14 @@
package org.thoughtcrime.securesms.service.webrtc;
import android.media.AudioManager;
import androidx.annotation.NonNull;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.components.webrtc.BroadcastVideoSink;
import org.thoughtcrime.securesms.ringrtc.Camera;
import org.thoughtcrime.securesms.ringrtc.CameraState;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager;
import java.util.Set;
/**
* Encapsulates the shared logic to deal with local device actions. Other action processors inherit
@@ -23,76 +22,29 @@ public abstract class DeviceAwareActionProcessor extends WebRtcActionProcessor {
}
@Override
protected @NonNull WebRtcServiceState handleWiredHeadsetChange(@NonNull WebRtcServiceState currentState, boolean present) {
Log.i(tag, "handleWiredHeadsetChange():");
protected @NonNull WebRtcServiceState handleAudioDeviceChanged(@NonNull WebRtcServiceState currentState, @NonNull SignalAudioManager.AudioDevice activeDevice, @NonNull Set<SignalAudioManager.AudioDevice> availableDevices) {
Log.i(tag, "handleAudioDeviceChanged(): active: " + activeDevice + " available: " + availableDevices);
AudioManager androidAudioManager = ServiceUtil.getAudioManager(context);
if (present && androidAudioManager.isSpeakerphoneOn()) {
androidAudioManager.setSpeakerphoneOn(false);
androidAudioManager.setBluetoothScoOn(false);
} else if (!present && !androidAudioManager.isSpeakerphoneOn() && !androidAudioManager.isBluetoothScoOn() && currentState.getLocalDeviceState().getCameraState().isEnabled()) {
androidAudioManager.setSpeakerphoneOn(true);
if (!currentState.getLocalDeviceState().getCameraState().isEnabled()) {
webRtcInteractor.updatePhoneState(WebRtcUtil.getInCallPhoneState(context));
}
webRtcInteractor.postStateUpdate(currentState);
return currentState.builder()
.changeLocalDeviceState()
.setActiveDevice(activeDevice)
.setAvailableDevices(availableDevices)
.build();
}
@Override
protected @NonNull WebRtcServiceState handleSetUserAudioDevice(@NonNull WebRtcServiceState currentState, @NonNull SignalAudioManager.AudioDevice userDevice) {
Log.i(tag, "handleSetUserAudioDevice(): userDevice: " + userDevice);
webRtcInteractor.setUserAudioDevice(userDevice);
return currentState;
}
@Override
protected @NonNull WebRtcServiceState handleBluetoothChange(@NonNull WebRtcServiceState currentState, boolean available) {
Log.i(tag, "handleBluetoothChange(): " + available);
if (available && currentState.getLocalDeviceState().wantsBluetooth()) {
webRtcInteractor.setWantsBluetoothConnection(true);
}
return currentState.builder()
.changeLocalDeviceState()
.isBluetoothAvailable(available)
.build();
}
@Override
protected @NonNull WebRtcServiceState handleSetSpeakerAudio(@NonNull WebRtcServiceState currentState, boolean isSpeaker) {
Log.i(tag, "handleSetSpeakerAudio(): " + isSpeaker);
AudioManager androidAudioManager = ServiceUtil.getAudioManager(context);
webRtcInteractor.setWantsBluetoothConnection(false);
androidAudioManager.setSpeakerphoneOn(isSpeaker);
if (!currentState.getLocalDeviceState().getCameraState().isEnabled()) {
webRtcInteractor.updatePhoneState(WebRtcUtil.getInCallPhoneState(context));
}
webRtcInteractor.postStateUpdate(currentState);
return currentState.builder()
.changeLocalDeviceState()
.wantsBluetooth(false)
.build();
}
@Override
protected @NonNull WebRtcServiceState handleSetBluetoothAudio(@NonNull WebRtcServiceState currentState, boolean isBluetooth) {
Log.i(tag, "handleSetBluetoothAudio(): " + isBluetooth);
webRtcInteractor.setWantsBluetoothConnection(isBluetooth);
if (!currentState.getLocalDeviceState().getCameraState().isEnabled()) {
webRtcInteractor.updatePhoneState(WebRtcUtil.getInCallPhoneState(context));
}
webRtcInteractor.postStateUpdate(currentState);
return currentState.builder()
.changeLocalDeviceState()
.wantsBluetooth(isBluetooth)
.build();
}
@Override
protected @NonNull WebRtcServiceState handleSetCameraFlip(@NonNull WebRtcServiceState currentState) {
Log.i(tag, "handleSetCameraFlip():");

View File

@@ -84,7 +84,7 @@ public class GroupConnectedActionProcessor extends GroupActionProcessor {
.cameraState(camera.getCameraState())
.build();
WebRtcUtil.enableSpeakerPhoneIfNeeded(context, currentState.getCallSetupState().isEnableVideoOnCreate());
WebRtcUtil.enableSpeakerPhoneIfNeeded(webRtcInteractor, currentState);
return currentState;
}

View File

@@ -1,7 +1,5 @@
package org.thoughtcrime.securesms.service.webrtc;
import static org.thoughtcrime.securesms.webrtc.CallNotificationBuilder.TYPE_ESTABLISHED;
import android.os.ResultReceiver;
import androidx.annotation.NonNull;
@@ -18,6 +16,8 @@ import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.NetworkUtil;
import org.thoughtcrime.securesms.webrtc.locks.LockManager;
import static org.thoughtcrime.securesms.webrtc.CallNotificationBuilder.TYPE_ESTABLISHED;
/**
* Process actions to go from lobby to a joined call.
*/
@@ -62,7 +62,8 @@ public class GroupJoiningActionProcessor extends GroupActionProcessor {
case CONNECTED:
if (device.getJoinState() == GroupCall.JoinState.JOINED) {
webRtcInteractor.startAudioCommunication(true);
webRtcInteractor.setCallInProgressNotification(TYPE_ESTABLISHED, currentState.getCallInfoState().getCallRecipient());
webRtcInteractor.startAudioCommunication();
if (currentState.getLocalDeviceState().getCameraState().isEnabled()) {
webRtcInteractor.updatePhoneState(LockManager.PhoneState.IN_VIDEO);
@@ -70,9 +71,6 @@ public class GroupJoiningActionProcessor extends GroupActionProcessor {
webRtcInteractor.updatePhoneState(WebRtcUtil.getInCallPhoneState(context));
}
webRtcInteractor.setCallInProgressNotification(TYPE_ESTABLISHED, currentState.getCallInfoState().getCallRecipient());
webRtcInteractor.setWantsBluetoothConnection(true);
try {
groupCall.setOutgoingVideoMuted(!currentState.getLocalDeviceState().getCameraState().isEnabled());
groupCall.setOutgoingAudioMuted(!currentState.getLocalDeviceState().isMicrophoneEnabled());
@@ -96,7 +94,6 @@ public class GroupJoiningActionProcessor extends GroupActionProcessor {
.callConnectedTime(System.currentTimeMillis())
.commit()
.changeLocalDeviceState()
.wantsBluetooth(true)
.commit()
.actionProcessor(new GroupConnectedActionProcessor(webRtcInteractor));
} else if (device.getJoinState() == GroupCall.JoinState.JOINING) {
@@ -152,7 +149,7 @@ public class GroupJoiningActionProcessor extends GroupActionProcessor {
.cameraState(camera.getCameraState())
.build();
WebRtcUtil.enableSpeakerPhoneIfNeeded(context, currentState.getCallSetupState().isEnableVideoOnCreate());
WebRtcUtil.enableSpeakerPhoneIfNeeded(webRtcInteractor, currentState);
return currentState;
}

View File

@@ -1,7 +1,5 @@
package org.thoughtcrime.securesms.service.webrtc;
import android.media.AudioManager;
import androidx.annotation.NonNull;
import com.annimon.stream.Stream;
@@ -20,7 +18,6 @@ import org.thoughtcrime.securesms.ringrtc.RemotePeer;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceStateBuilder;
import org.thoughtcrime.securesms.util.NetworkUtil;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
import java.util.List;
@@ -148,13 +145,9 @@ public class GroupPreJoinActionProcessor extends GroupActionProcessor {
currentState = WebRtcVideoUtil.reinitializeCamera(context, webRtcInteractor.getCameraEventListener(), currentState);
AudioManager androidAudioManager = ServiceUtil.getAudioManager(context);
androidAudioManager.setSpeakerphoneOn(false);
webRtcInteractor.setCallInProgressNotification(TYPE_OUTGOING_RINGING, currentState.getCallInfoState().getCallRecipient());
webRtcInteractor.updatePhoneState(WebRtcUtil.getInCallPhoneState(context));
webRtcInteractor.initializeAudioForCall();
webRtcInteractor.setCallInProgressNotification(TYPE_OUTGOING_RINGING, currentState.getCallInfoState().getCallRecipient());
webRtcInteractor.setWantsBluetoothConnection(true);
try {
groupCall.setOutgoingVideoSource(currentState.getVideoState().requireLocalSink(), currentState.getVideoState().requireCamera());
@@ -174,7 +167,6 @@ public class GroupPreJoinActionProcessor extends GroupActionProcessor {
.groupCallState(WebRtcViewModel.GroupCallState.CONNECTED_AND_JOINING)
.commit()
.changeLocalDeviceState()
.wantsBluetooth(true)
.build();
}

View File

@@ -1,6 +1,5 @@
package org.thoughtcrime.securesms.service.webrtc;
import android.media.AudioManager;
import android.net.Uri;
import androidx.annotation.NonNull;
@@ -23,7 +22,6 @@ import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.ringrtc.RemotePeer;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
import org.thoughtcrime.securesms.util.NetworkUtil;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.webrtc.locks.LockManager;
import org.whispersystems.libsignal.util.guava.Optional;
@@ -108,11 +106,9 @@ public final class IncomingGroupCallActionProcessor extends DeviceAwareActionPro
currentState = WebRtcVideoUtil.initializeVideo(context, webRtcInteractor.getCameraEventListener(), currentState);
AudioManager androidAudioManager = ServiceUtil.getAudioManager(context);
androidAudioManager.setSpeakerphoneOn(false);
webRtcInteractor.setCallInProgressNotification(TYPE_INCOMING_RINGING, remotePeerGroup);
webRtcInteractor.updatePhoneState(LockManager.PhoneState.INTERACTIVE);
webRtcInteractor.initializeAudioForCall();
boolean shouldDisturbUserWithCall = DoNotDisturbUtil.shouldDisturbUserWithCall(context.getApplicationContext());
if (shouldDisturbUserWithCall) {
@@ -123,7 +119,6 @@ public final class IncomingGroupCallActionProcessor extends DeviceAwareActionPro
}
}
webRtcInteractor.initializeAudioForCall();
if (shouldDisturbUserWithCall && SignalStore.settings().isCallNotificationsEnabled()) {
Uri ringtone = recipient.resolve().getCallRingtone();
RecipientDatabase.VibrateState vibrateState = recipient.resolve().getCallVibrate();
@@ -135,7 +130,6 @@ public final class IncomingGroupCallActionProcessor extends DeviceAwareActionPro
webRtcInteractor.startIncomingRinger(ringtone, vibrateState == RecipientDatabase.VibrateState.ENABLED || (vibrateState == RecipientDatabase.VibrateState.DEFAULT && SignalStore.settings().isCallVibrateEnabled()));
}
webRtcInteractor.setCallInProgressNotification(TYPE_INCOMING_RINGING, remotePeerGroup);
webRtcInteractor.registerPowerButtonReceiver();
return currentState.builder()
@@ -196,13 +190,9 @@ public final class IncomingGroupCallActionProcessor extends DeviceAwareActionPro
.enableVideoOnCreate(answerWithVideo)
.build();
AudioManager androidAudioManager = ServiceUtil.getAudioManager(context);
androidAudioManager.setSpeakerphoneOn(false);
webRtcInteractor.setCallInProgressNotification(TYPE_INCOMING_CONNECTING, currentState.getCallInfoState().getCallRecipient());
webRtcInteractor.updatePhoneState(WebRtcUtil.getInCallPhoneState(context));
webRtcInteractor.initializeAudioForCall();
webRtcInteractor.setCallInProgressNotification(TYPE_INCOMING_CONNECTING, currentState.getCallInfoState().getCallRecipient());
webRtcInteractor.setWantsBluetoothConnection(true);
try {
groupCall.setOutgoingVideoSource(currentState.getVideoState().requireLocalSink(), currentState.getVideoState().requireCamera());
@@ -222,7 +212,6 @@ public final class IncomingGroupCallActionProcessor extends DeviceAwareActionPro
.groupCallState(WebRtcViewModel.GroupCallState.CONNECTED_AND_JOINING)
.commit()
.changeLocalDeviceState()
.wantsBluetooth(true)
.build();
}
@@ -246,7 +235,6 @@ public final class IncomingGroupCallActionProcessor extends DeviceAwareActionPro
webRtcInteractor.updatePhoneState(LockManager.PhoneState.PROCESSING);
webRtcInteractor.stopAudio(false);
webRtcInteractor.setWantsBluetoothConnection(false);
webRtcInteractor.updatePhoneState(LockManager.PhoneState.IDLE);
webRtcInteractor.stopForegroundService();

View File

@@ -1,6 +1,5 @@
package org.thoughtcrime.securesms.service.webrtc;
import android.media.AudioManager;
import android.os.ResultReceiver;
import androidx.annotation.NonNull;
@@ -23,7 +22,7 @@ import org.thoughtcrime.securesms.service.webrtc.state.VideoState;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceStateBuilder;
import org.thoughtcrime.securesms.util.NetworkUtil;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager;
import org.webrtc.PeerConnection;
import org.whispersystems.libsignal.InvalidKeyException;
import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
@@ -66,17 +65,14 @@ public class OutgoingCallActionProcessor extends DeviceAwareActionProcessor {
Log.i(TAG, "assign activePeer callId: " + remotePeer.getCallId() + " key: " + remotePeer.hashCode());
AudioManager androidAudioManager = ServiceUtil.getAudioManager(context);
androidAudioManager.setSpeakerphoneOn(false);
WebRtcUtil.enableSpeakerPhoneIfNeeded(context, currentState.getCallSetupState().isEnableVideoOnCreate());
webRtcInteractor.setCallInProgressNotification(TYPE_OUTGOING_RINGING, remotePeer);
webRtcInteractor.setDefaultAudioDevice(currentState.getCallSetupState().isEnableVideoOnCreate() ? SignalAudioManager.AudioDevice.SPEAKER_PHONE
: SignalAudioManager.AudioDevice.EARPIECE,
false);
webRtcInteractor.updatePhoneState(WebRtcUtil.getInCallPhoneState(context));
webRtcInteractor.initializeAudioForCall();
webRtcInteractor.startOutgoingRinger();
webRtcInteractor.setCallInProgressNotification(TYPE_OUTGOING_RINGING, remotePeer);
webRtcInteractor.setWantsBluetoothConnection(true);
RecipientUtil.setAndSendUniversalExpireTimerIfNecessary(context, Recipient.resolved(remotePeer.getId()), DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(remotePeer.getId()));
DatabaseFactory.getSmsDatabase(context).insertOutgoingCall(remotePeer.getId(), currentState.getCallSetupState().isEnableVideoOnCreate());
@@ -87,7 +83,6 @@ public class OutgoingCallActionProcessor extends DeviceAwareActionProcessor {
.callState(WebRtcViewModel.State.CALL_OUTGOING)
.commit()
.changeLocalDeviceState()
.wantsBluetooth(true)
.build();
}

View File

@@ -1,12 +1,5 @@
package org.thoughtcrime.securesms.service.webrtc;
import static org.thoughtcrime.securesms.events.WebRtcViewModel.GroupCallState.IDLE;
import static org.thoughtcrime.securesms.events.WebRtcViewModel.State.CALL_INCOMING;
import static org.thoughtcrime.securesms.events.WebRtcViewModel.State.NETWORK_FAILURE;
import static org.thoughtcrime.securesms.events.WebRtcViewModel.State.NO_SUCH_USER;
import static org.thoughtcrime.securesms.events.WebRtcViewModel.State.UNTRUSTED_IDENTITY;
import static org.thoughtcrime.securesms.service.webrtc.WebRtcUtil.getUrgencyFromCallUrgency;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
@@ -85,6 +78,13 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import static org.thoughtcrime.securesms.events.WebRtcViewModel.GroupCallState.IDLE;
import static org.thoughtcrime.securesms.events.WebRtcViewModel.State.CALL_INCOMING;
import static org.thoughtcrime.securesms.events.WebRtcViewModel.State.NETWORK_FAILURE;
import static org.thoughtcrime.securesms.events.WebRtcViewModel.State.NO_SUCH_USER;
import static org.thoughtcrime.securesms.events.WebRtcViewModel.State.UNTRUSTED_IDENTITY;
import static org.thoughtcrime.securesms.service.webrtc.WebRtcUtil.getUrgencyFromCallUrgency;
/**
* Entry point for all things calling. Lives for the life of the app instance and will spin up a foreground service when needed to
* handle "active" calls.
@@ -126,7 +126,6 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall.
this.serviceState = new WebRtcServiceState(new IdleActionProcessor(new WebRtcInteractor(this.context,
this,
lockManager,
new SignalAudioManager(context),
this,
this,
this)));
@@ -193,14 +192,6 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall.
process((s, p) -> p.handleOrientationChanged(s, isLandscapeEnabled, degrees));
}
public void setAudioSpeaker(boolean isSpeaker) {
process((s, p) -> p.handleSetSpeakerAudio(s, isSpeaker));
}
public void setAudioBluetooth(boolean isBluetooth) {
process((s, p) -> p.handleSetBluetoothAudio(s, isBluetooth));
}
public void setMuteAudio(boolean enabled) {
process((s, p) -> p.handleSetMuteAudio(s, enabled));
}
@@ -237,10 +228,6 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall.
process((s, p) -> p.handleIsInCallQuery(s, resultReceiver));
}
public void wiredHeadsetChange(boolean available) {
process((s, p) -> p.handleWiredHeadsetChange(s, available));
}
public void networkChange(boolean available) {
process((s, p) -> p.handleNetworkChanged(s, available));
}
@@ -253,10 +240,6 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall.
process((s, p) -> p.handleScreenOffChange(s));
}
public void bluetoothChange(boolean available) {
process((s, p) -> p.handleBluetoothChange(s, available));
}
public void postStateUpdate(@NonNull WebRtcServiceState state) {
EventBus.getDefault().postSticky(new WebRtcViewModel(state));
}
@@ -299,6 +282,14 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall.
process((s, p) -> p.handleReceivedGroupCallPeekForRingingCheck(s, groupCallRingCheckInfo, deviceCount));
}
public void onAudioDeviceChanged(@NonNull SignalAudioManager.AudioDevice activeDevice, @NonNull Set<SignalAudioManager.AudioDevice> availableDevices) {
process((s, p) -> p.handleAudioDeviceChanged(s, activeDevice, availableDevices));
}
public void selectAudioDevice(@NonNull SignalAudioManager.AudioDevice desiredDevice) {
process((s, p) -> p.handleSetUserAudioDevice(s, desiredDevice));
}
public void peekGroupCall(@NonNull RecipientId id) {
if (callManager == null) {
Log.i(TAG, "Unable to peekGroupCall, call manager is null");

View File

@@ -1,9 +1,5 @@
package org.thoughtcrime.securesms.service.webrtc;
import static org.thoughtcrime.securesms.service.webrtc.WebRtcData.AnswerMetadata;
import static org.thoughtcrime.securesms.service.webrtc.WebRtcData.HangupMetadata;
import static org.thoughtcrime.securesms.service.webrtc.WebRtcData.ReceivedAnswerMetadata;
import android.content.Context;
import android.os.ResultReceiver;
@@ -39,6 +35,7 @@ import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceStateBuilder;
import org.thoughtcrime.securesms.util.NetworkUtil;
import org.thoughtcrime.securesms.util.TelephonyUtil;
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager;
import org.thoughtcrime.securesms.webrtc.locks.LockManager;
import org.webrtc.PeerConnection;
import org.whispersystems.libsignal.IdentityKey;
@@ -52,8 +49,13 @@ import org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMess
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import static org.thoughtcrime.securesms.service.webrtc.WebRtcData.AnswerMetadata;
import static org.thoughtcrime.securesms.service.webrtc.WebRtcData.HangupMetadata;
import static org.thoughtcrime.securesms.service.webrtc.WebRtcData.ReceivedAnswerMetadata;
/**
* Base WebRTC action processor and core of the calling state machine. As actions (as intents)
* are sent to the service, they are passed to an instance of the current state's action processor.
@@ -370,6 +372,16 @@ public abstract class WebRtcActionProcessor {
return builder.build();
}
protected @NonNull WebRtcServiceState handleAudioDeviceChanged(@NonNull WebRtcServiceState currentState, @NonNull SignalAudioManager.AudioDevice activeDevice, @NonNull Set<SignalAudioManager.AudioDevice> availableDevices) {
Log.i(tag, "handleAudioDeviceChanged not processed");
return currentState;
}
protected @NonNull WebRtcServiceState handleSetUserAudioDevice(@NonNull WebRtcServiceState currentState, @NonNull SignalAudioManager.AudioDevice userDevice) {
Log.i(tag, "handleSetUserAudioDevice not processed");
return currentState;
}
//endregion Active call
//region Call setup
@@ -410,16 +422,6 @@ public abstract class WebRtcActionProcessor {
return currentState;
}
protected @NonNull WebRtcServiceState handleSetSpeakerAudio(@NonNull WebRtcServiceState currentState, boolean isSpeaker) {
Log.i(tag, "handleSetSpeakerAudio not processed");
return currentState;
}
protected @NonNull WebRtcServiceState handleSetBluetoothAudio(@NonNull WebRtcServiceState currentState, boolean isBluetooth) {
Log.i(tag, "handleSetBluetoothAudio not processed");
return currentState;
}
protected @NonNull WebRtcServiceState handleSetCameraFlip(@NonNull WebRtcServiceState currentState) {
Log.i(tag, "handleSetCameraFlip not processed");
return currentState;
@@ -430,16 +432,6 @@ public abstract class WebRtcActionProcessor {
return currentState;
}
protected @NonNull WebRtcServiceState handleBluetoothChange(@NonNull WebRtcServiceState currentState, boolean available) {
Log.i(tag, "handleBluetoothChange not processed");
return currentState;
}
protected @NonNull WebRtcServiceState handleWiredHeadsetChange(@NonNull WebRtcServiceState currentState, boolean present) {
Log.i(tag, "handleWiredHeadsetChange not processed");
return currentState;
}
public @NonNull WebRtcServiceState handleCameraSwitchCompleted(@NonNull WebRtcServiceState currentState, @NonNull CameraState newCameraState) {
Log.i(tag, "handleCameraSwitchCompleted not processed");
return currentState;
@@ -564,7 +556,6 @@ public abstract class WebRtcActionProcessor {
(activePeer.getState() == CallState.CONNECTED);
webRtcInteractor.stopAudio(playDisconnectSound);
webRtcInteractor.setWantsBluetoothConnection(false);
webRtcInteractor.updatePhoneState(LockManager.PhoneState.IDLE);
webRtcInteractor.stopForegroundService();
@@ -574,7 +565,6 @@ public abstract class WebRtcActionProcessor {
.activePeer(null)
.commit()
.changeLocalDeviceState()
.wantsBluetooth(false)
.commit()
.actionProcessor(currentState.getCallInfoState().getCallState() == WebRtcViewModel.State.CALL_DISCONNECTED ? new DisconnectingCallActionProcessor(webRtcInteractor) : new IdleActionProcessor(webRtcInteractor))
.terminate()
@@ -723,7 +713,6 @@ public abstract class WebRtcActionProcessor {
webRtcInteractor.updatePhoneState(LockManager.PhoneState.PROCESSING);
boolean playDisconnectSound = currentState.getCallInfoState().getCallState() == WebRtcViewModel.State.CALL_DISCONNECTED;
webRtcInteractor.stopAudio(playDisconnectSound);
webRtcInteractor.setWantsBluetoothConnection(false);
webRtcInteractor.updatePhoneState(LockManager.PhoneState.IDLE);
webRtcInteractor.stopForegroundService();

View File

@@ -6,10 +6,8 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.IBinder;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
@@ -25,16 +23,18 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.TelephonyUtil;
import org.thoughtcrime.securesms.webrtc.CallNotificationBuilder;
import org.thoughtcrime.securesms.webrtc.UncaughtExceptionHandlerManager;
import org.thoughtcrime.securesms.webrtc.audio.BluetoothStateManager;
import org.thoughtcrime.securesms.webrtc.audio.AudioManagerCommand;
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager;
import org.thoughtcrime.securesms.webrtc.locks.LockManager;
import java.util.Objects;
import java.util.Set;
/**
* Provide a foreground service for {@link SignalCallManager} to leverage to run in the background when necessary. Also
* provides devices listeners needed for during a call (i.e., bluetooth, power button).
*/
public final class WebRtcCallService extends Service implements BluetoothStateManager.BluetoothStateListener {
public final class WebRtcCallService extends Service implements SignalAudioManager.EventListener {
private static final String TAG = Log.tag(WebRtcCallService.class);
@@ -42,23 +42,23 @@ public final class WebRtcCallService extends Service implements BluetoothStateMa
private static final String ACTION_STOP = "STOP";
private static final String ACTION_DENY_CALL = "DENY_CALL";
private static final String ACTION_LOCAL_HANGUP = "LOCAL_HANGUP";
private static final String ACTION_WANTS_BLUETOOTH = "WANTS_BLUETOOTH";
private static final String ACTION_CHANGE_POWER_BUTTON = "CHANGE_POWER_BUTTON";
private static final String ACTION_SEND_AUDIO_COMMAND = "SEND_AUDIO_COMMAND";
private static final String EXTRA_UPDATE_TYPE = "UPDATE_TYPE";
private static final String EXTRA_RECIPIENT_ID = "RECIPIENT_ID";
private static final String EXTRA_ENABLED = "ENABLED";
private static final String EXTRA_UPDATE_TYPE = "UPDATE_TYPE";
private static final String EXTRA_RECIPIENT_ID = "RECIPIENT_ID";
private static final String EXTRA_ENABLED = "ENABLED";
private static final String EXTRA_AUDIO_COMMAND = "AUDIO_COMMAND";
private static final int INVALID_NOTIFICATION_ID = -1;
private SignalCallManager callManager;
private WiredHeadsetStateReceiver wiredHeadsetStateReceiver;
private NetworkReceiver networkReceiver;
private PowerButtonReceiver powerButtonReceiver;
private UncaughtExceptionHandlerManager uncaughtExceptionHandlerManager;
private PhoneStateListener hangUpRtcOnDeviceCallAnswered;
private BluetoothStateManager bluetoothStateManager;
private SignalAudioManager signalAudioManager;
private int lastNotificationId;
private Notification lastNotification;
@@ -86,11 +86,10 @@ public final class WebRtcCallService extends Service implements BluetoothStateMa
return new Intent(context, WebRtcCallService.class).setAction(ACTION_LOCAL_HANGUP);
}
public static void setWantsBluetoothConnection(@NonNull Context context, boolean enabled) {
public static void sendAudioManagerCommand(@NonNull Context context, @NonNull AudioManagerCommand command) {
Intent intent = new Intent(context, WebRtcCallService.class);
intent.setAction(ACTION_WANTS_BLUETOOTH)
.putExtra(EXTRA_ENABLED, enabled);
intent.setAction(ACTION_SEND_AUDIO_COMMAND)
.putExtra(EXTRA_AUDIO_COMMAND, command);
ContextCompat.startForegroundService(context, intent);
}
@@ -107,12 +106,11 @@ public final class WebRtcCallService extends Service implements BluetoothStateMa
Log.v(TAG, "onCreate");
super.onCreate();
this.callManager = ApplicationDependencies.getSignalCallManager();
this.bluetoothStateManager = new BluetoothStateManager(this, this);
this.signalAudioManager = new SignalAudioManager(this, this);
this.hangUpRtcOnDeviceCallAnswered = new HangUpRtcOnPstnCallAnsweredListener();
this.lastNotificationId = INVALID_NOTIFICATION_ID;
registerUncaughtExceptionHandler();
registerWiredHeadsetStateReceiver();
registerNetworkReceiver();
TelephonyUtil.getManager(this)
@@ -128,13 +126,8 @@ public final class WebRtcCallService extends Service implements BluetoothStateMa
uncaughtExceptionHandlerManager.unregister();
}
if (bluetoothStateManager != null) {
bluetoothStateManager.onDestroy();
}
if (wiredHeadsetStateReceiver != null) {
unregisterReceiver(wiredHeadsetStateReceiver);
wiredHeadsetStateReceiver = null;
if (signalAudioManager != null) {
signalAudioManager.shutdown();
}
unregisterNetworkReceiver();
@@ -157,11 +150,9 @@ public final class WebRtcCallService extends Service implements BluetoothStateMa
setCallInProgressNotification(intent.getIntExtra(EXTRA_UPDATE_TYPE, 0),
Objects.requireNonNull(intent.getParcelableExtra(EXTRA_RECIPIENT_ID)));
return START_STICKY;
case ACTION_WANTS_BLUETOOTH:
case ACTION_SEND_AUDIO_COMMAND:
setCallNotification();
if (bluetoothStateManager != null) {
bluetoothStateManager.setWantsConnection(intent.getBooleanExtra(EXTRA_ENABLED, false));
}
signalAudioManager.handleCommand(Objects.requireNonNull(intent.getParcelableExtra(EXTRA_AUDIO_COMMAND)));
return START_STICKY;
case ACTION_CHANGE_POWER_BUTTON:
setCallNotification();
@@ -215,20 +206,6 @@ public final class WebRtcCallService extends Service implements BluetoothStateMa
uncaughtExceptionHandlerManager.registerHandler(new ProximityLockRelease(callManager.getLockManager()));
}
private void registerWiredHeadsetStateReceiver() {
wiredHeadsetStateReceiver = new WiredHeadsetStateReceiver();
String action;
if (Build.VERSION.SDK_INT >= 21) {
action = AudioManager.ACTION_HEADSET_PLUG;
} else {
action = Intent.ACTION_HEADSET_PLUG;
}
registerReceiver(wiredHeadsetStateReceiver, new IntentFilter(action));
}
private void registerNetworkReceiver() {
if (networkReceiver == null) {
networkReceiver = new NetworkReceiver();
@@ -267,8 +244,8 @@ public final class WebRtcCallService extends Service implements BluetoothStateMa
}
@Override
public void onBluetoothStateChanged(boolean isAvailable) {
callManager.bluetoothChange(isAvailable);
public void onAudioDeviceChanged(@NonNull SignalAudioManager.AudioDevice activeDevice, @NonNull Set<SignalAudioManager.AudioDevice> availableDevices) {
callManager.onAudioDeviceChanged(activeDevice, availableDevices);
}
private class HangUpRtcOnPstnCallAnsweredListener extends PhoneStateListener {
@@ -286,15 +263,6 @@ public final class WebRtcCallService extends Service implements BluetoothStateMa
}
}
private static class WiredHeadsetStateReceiver extends BroadcastReceiver {
@Override
public void onReceive(@NonNull Context context, @NonNull Intent intent) {
int state = intent.getIntExtra("state", -1);
ApplicationDependencies.getSignalCallManager().wiredHeadsetChange(state != 0);
}
}
private static class NetworkReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {

View File

@@ -14,7 +14,7 @@ import org.thoughtcrime.securesms.ringrtc.CameraEventListener;
import org.thoughtcrime.securesms.ringrtc.RemotePeer;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
import org.thoughtcrime.securesms.util.AppForegroundObserver;
import org.thoughtcrime.securesms.webrtc.audio.OutgoingRinger;
import org.thoughtcrime.securesms.webrtc.audio.AudioManagerCommand;
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager;
import org.thoughtcrime.securesms.webrtc.locks.LockManager;
import org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage;
@@ -32,7 +32,6 @@ public class WebRtcInteractor {
@NonNull private final Context context;
@NonNull private final SignalCallManager signalCallManager;
@NonNull private final LockManager lockManager;
@NonNull private final SignalAudioManager audioManager;
@NonNull private final CameraEventListener cameraEventListener;
@NonNull private final GroupCall.Observer groupCallObserver;
@NonNull private final AppForegroundObserver.Listener foregroundListener;
@@ -40,7 +39,6 @@ public class WebRtcInteractor {
public WebRtcInteractor(@NonNull Context context,
@NonNull SignalCallManager signalCallManager,
@NonNull LockManager lockManager,
@NonNull SignalAudioManager audioManager,
@NonNull CameraEventListener cameraEventListener,
@NonNull GroupCall.Observer groupCallObserver,
@NonNull AppForegroundObserver.Listener foregroundListener)
@@ -48,7 +46,6 @@ public class WebRtcInteractor {
this.context = context;
this.signalCallManager = signalCallManager;
this.lockManager = lockManager;
this.audioManager = audioManager;
this.cameraEventListener = cameraEventListener;
this.groupCallObserver = groupCallObserver;
this.foregroundListener = foregroundListener;
@@ -74,10 +71,6 @@ public class WebRtcInteractor {
return foregroundListener;
}
void setWantsBluetoothConnection(boolean enabled) {
WebRtcCallService.setWantsBluetoothConnection(context, enabled);
}
void updatePhoneState(@NonNull LockManager.PhoneState phoneState) {
lockManager.updatePhoneState(phoneState);
}
@@ -131,27 +124,35 @@ public class WebRtcInteractor {
}
void silenceIncomingRinger() {
audioManager.silenceIncomingRinger();
WebRtcCallService.sendAudioManagerCommand(context, new AudioManagerCommand.SilenceIncomingRinger());
}
void initializeAudioForCall() {
audioManager.initializeAudioForCall();
WebRtcCallService.sendAudioManagerCommand(context, new AudioManagerCommand.Initialize());
}
void startIncomingRinger(@Nullable Uri ringtoneUri, boolean vibrate) {
audioManager.startIncomingRinger(ringtoneUri, vibrate);
WebRtcCallService.sendAudioManagerCommand(context, new AudioManagerCommand.StartIncomingRinger(ringtoneUri, vibrate));
}
void startOutgoingRinger() {
audioManager.startOutgoingRinger(OutgoingRinger.Type.RINGING);
WebRtcCallService.sendAudioManagerCommand(context, new AudioManagerCommand.StartOutgoingRinger());
}
void stopAudio(boolean playDisconnect) {
audioManager.stop(playDisconnect);
WebRtcCallService.sendAudioManagerCommand(context, new AudioManagerCommand.Stop(playDisconnect));
}
void startAudioCommunication(boolean preserveSpeakerphone) {
audioManager.startCommunication(preserveSpeakerphone);
void startAudioCommunication() {
WebRtcCallService.sendAudioManagerCommand(context, new AudioManagerCommand.Start());
}
public void setUserAudioDevice(@NonNull SignalAudioManager.AudioDevice userDevice) {
WebRtcCallService.sendAudioManagerCommand(context, new AudioManagerCommand.SetUserDevice(userDevice));
}
public void setDefaultAudioDevice(@NonNull SignalAudioManager.AudioDevice userDevice, boolean clearUserEarpieceSelection) {
WebRtcCallService.sendAudioManagerCommand(context, new AudioManagerCommand.SetDefaultDevice(userDevice, clearUserEarpieceSelection));
}
void peekGroupCallForRingingCheck(@NonNull GroupCallRingCheckInfo groupCallRingCheckInfo) {

View File

@@ -1,7 +1,6 @@
package org.thoughtcrime.securesms.service.webrtc;
import android.content.Context;
import android.media.AudioManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -9,8 +8,11 @@ import androidx.annotation.Nullable;
import org.signal.ringrtc.CallManager;
import org.signal.ringrtc.GroupCall;
import org.signal.ringrtc.PeekInfo;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.events.WebRtcViewModel;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
import org.thoughtcrime.securesms.webrtc.audio.AudioManagerCompat;
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager;
import org.thoughtcrime.securesms.webrtc.locks.LockManager;
import org.whispersystems.libsignal.InvalidKeyException;
import org.whispersystems.libsignal.ecc.Curve;
@@ -32,7 +34,7 @@ public final class WebRtcUtil {
}
public static @NonNull LockManager.PhoneState getInCallPhoneState(@NonNull Context context) {
AudioManager audioManager = ServiceUtil.getAudioManager(context);
AudioManagerCompat audioManager = ApplicationDependencies.getAndroidCallAudioManager();
if (audioManager.isSpeakerphoneOn() || audioManager.isBluetoothScoOn() || audioManager.isWiredHeadsetOn()) {
return LockManager.PhoneState.IN_HANDS_FREE_CALL;
} else {
@@ -72,17 +74,15 @@ public final class WebRtcUtil {
return OpaqueMessage.Urgency.DROPPABLE;
}
public static void enableSpeakerPhoneIfNeeded(@NonNull Context context, boolean enable) {
if (!enable) {
public static void enableSpeakerPhoneIfNeeded(@NonNull WebRtcInteractor webRtcInteractor, WebRtcServiceState currentState) {
if (!currentState.getLocalDeviceState().getCameraState().isEnabled()) {
return;
}
AudioManager androidAudioManager = ServiceUtil.getAudioManager(context);
//noinspection deprecation
boolean shouldEnable = !(androidAudioManager.isSpeakerphoneOn() || androidAudioManager.isBluetoothScoOn() || androidAudioManager.isWiredHeadsetOn());
if (shouldEnable) {
androidAudioManager.setSpeakerphoneOn(true);
if (currentState.getLocalDeviceState().getActiveDevice() == SignalAudioManager.AudioDevice.EARPIECE ||
currentState.getLocalDeviceState().getActiveDevice() == SignalAudioManager.AudioDevice.NONE)
{
webRtcInteractor.setDefaultAudioDevice(SignalAudioManager.AudioDevice.SPEAKER_PHONE, true);
}
}

View File

@@ -1,72 +0,0 @@
package org.thoughtcrime.securesms.service.webrtc.state;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.components.sensors.Orientation;
import org.thoughtcrime.securesms.ringrtc.CameraState;
/**
* Local device specific state.
*/
public final class LocalDeviceState {
CameraState cameraState;
boolean microphoneEnabled;
boolean bluetoothAvailable;
boolean wantsBluetooth;
Orientation orientation;
boolean isLandscapeEnabled;
Orientation deviceOrientation;
LocalDeviceState() {
this(CameraState.UNKNOWN, true, false, false, Orientation.PORTRAIT_BOTTOM_EDGE, false, Orientation.PORTRAIT_BOTTOM_EDGE);
}
LocalDeviceState(@NonNull LocalDeviceState toCopy) {
this(toCopy.cameraState, toCopy.microphoneEnabled, toCopy.bluetoothAvailable, toCopy.wantsBluetooth, toCopy.orientation, toCopy.isLandscapeEnabled, toCopy.deviceOrientation);
}
LocalDeviceState(@NonNull CameraState cameraState,
boolean microphoneEnabled,
boolean bluetoothAvailable,
boolean wantsBluetooth,
@NonNull Orientation orientation,
boolean isLandscapeEnabled,
@NonNull Orientation deviceOrientation)
{
this.cameraState = cameraState;
this.microphoneEnabled = microphoneEnabled;
this.bluetoothAvailable = bluetoothAvailable;
this.wantsBluetooth = wantsBluetooth;
this.orientation = orientation;
this.isLandscapeEnabled = isLandscapeEnabled;
this.deviceOrientation = deviceOrientation;
}
public @NonNull CameraState getCameraState() {
return cameraState;
}
public boolean isMicrophoneEnabled() {
return microphoneEnabled;
}
public boolean isBluetoothAvailable() {
return bluetoothAvailable;
}
public boolean wantsBluetooth() {
return wantsBluetooth;
}
public @NonNull Orientation getOrientation() {
return orientation;
}
public boolean isLandscapeEnabled() {
return isLandscapeEnabled;
}
public @NonNull Orientation getDeviceOrientation() {
return deviceOrientation;
}
}

View File

@@ -0,0 +1,23 @@
package org.thoughtcrime.securesms.service.webrtc.state
import org.thoughtcrime.securesms.components.sensors.Orientation
import org.thoughtcrime.securesms.ringrtc.CameraState
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager
/**
* Local device specific state.
*/
data class LocalDeviceState constructor(
var cameraState: CameraState = CameraState.UNKNOWN,
var isMicrophoneEnabled: Boolean = true,
var orientation: Orientation = Orientation.PORTRAIT_BOTTOM_EDGE,
var isLandscapeEnabled: Boolean = false,
var deviceOrientation: Orientation = Orientation.PORTRAIT_BOTTOM_EDGE,
var activeDevice: SignalAudioManager.AudioDevice = SignalAudioManager.AudioDevice.NONE,
var availableDevices: Set<SignalAudioManager.AudioDevice> = emptySet()
) {
fun duplicate(): LocalDeviceState {
return copy()
}
}

View File

@@ -27,7 +27,7 @@ public final class WebRtcServiceState {
this.actionProcessor = toCopy.actionProcessor;
this.callSetupState = toCopy.callSetupState.duplicate();
this.callInfoState = new CallInfoState(toCopy.callInfoState);
this.localDeviceState = new LocalDeviceState(toCopy.localDeviceState);
this.localDeviceState = toCopy.localDeviceState.duplicate();
this.videoState = new VideoState(toCopy.videoState);
}

View File

@@ -18,8 +18,10 @@ import org.thoughtcrime.securesms.ringrtc.Camera;
import org.thoughtcrime.securesms.ringrtc.CameraState;
import org.thoughtcrime.securesms.ringrtc.RemotePeer;
import org.thoughtcrime.securesms.service.webrtc.WebRtcActionProcessor;
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager;
import java.util.Collection;
import java.util.Set;
/**
* Builder that creates a new {@link WebRtcServiceState} from an existing one and allows
@@ -73,7 +75,7 @@ public class WebRtcServiceStateBuilder {
private LocalDeviceState toBuild;
public LocalDeviceStateBuilder() {
toBuild = new LocalDeviceState(WebRtcServiceStateBuilder.this.toBuild.localDeviceState);
toBuild = WebRtcServiceStateBuilder.this.toBuild.localDeviceState.duplicate();
}
public @NonNull WebRtcServiceStateBuilder commit() {
@@ -87,37 +89,37 @@ public class WebRtcServiceStateBuilder {
}
public @NonNull LocalDeviceStateBuilder cameraState(@NonNull CameraState cameraState) {
toBuild.cameraState = cameraState;
toBuild.setCameraState(cameraState);
return this;
}
public @NonNull LocalDeviceStateBuilder isMicrophoneEnabled(boolean enabled) {
toBuild.microphoneEnabled = enabled;
return this;
}
public @NonNull LocalDeviceStateBuilder isBluetoothAvailable(boolean available) {
toBuild.bluetoothAvailable = available;
return this;
}
public @NonNull LocalDeviceStateBuilder wantsBluetooth(boolean wantsBluetooth) {
toBuild.wantsBluetooth = wantsBluetooth;
toBuild.setMicrophoneEnabled(enabled);
return this;
}
public @NonNull LocalDeviceStateBuilder setOrientation(@NonNull Orientation orientation) {
toBuild.orientation = orientation;
toBuild.setOrientation(orientation);
return this;
}
public @NonNull LocalDeviceStateBuilder setLandscapeEnabled(boolean isLandscapeEnabled) {
toBuild.isLandscapeEnabled = isLandscapeEnabled;
toBuild.setLandscapeEnabled(isLandscapeEnabled);
return this;
}
public @NonNull LocalDeviceStateBuilder setDeviceOrientation(@NonNull Orientation deviceOrientation) {
toBuild.deviceOrientation = deviceOrientation;
toBuild.setDeviceOrientation(deviceOrientation);
return this;
}
public @NonNull LocalDeviceStateBuilder setActiveDevice(@NonNull SignalAudioManager.AudioDevice audioDevice) {
toBuild.setActiveDevice(audioDevice);
return this;
}
public @NonNull LocalDeviceStateBuilder setAvailableDevices(@NonNull Set<SignalAudioManager.AudioDevice> availableDevices) {
toBuild.setAvailableDevices(availableDevices);
return this;
}
}