mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-29 11:17:47 +00:00
Add button to flip camera (front vs rear). Fixes #6279
This commit is contained in:
parent
6c1a1fb9ad
commit
f1c79eaebf
9
res/drawable/webrtc_camera_flip_button.xml
Normal file
9
res/drawable/webrtc_camera_flip_button.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/webrtc_control_background"/>
|
||||
<item android:top="5dp"
|
||||
android:left="5dp"
|
||||
android:right="5dp"
|
||||
android:bottom="5dp"
|
||||
android:drawable="@drawable/quick_camera_rear"/>
|
||||
</layer-list>
|
@ -34,6 +34,13 @@
|
||||
<org.thoughtcrime.securesms.components.AccessibleToggleButton
|
||||
android:id="@+id/video_mute_button"
|
||||
style="@style/WebRtcCallCompoundButton"
|
||||
android:layout_marginRight="15dp"
|
||||
android:background="@drawable/webrtc_video_mute_button"/>
|
||||
|
||||
<org.thoughtcrime.securesms.components.AccessibleToggleButton
|
||||
android:id="@+id/camera_flip_button"
|
||||
style="@style/WebRtcCallCompoundButton"
|
||||
android:contentDescription="@string/redphone_call_controls__flip_camera_rear"
|
||||
android:background="@drawable/webrtc_camera_flip_button"/>
|
||||
|
||||
</merge>
|
||||
|
@ -995,6 +995,7 @@
|
||||
<!--- redphone_call_controls -->
|
||||
<string name="redphone_call_card__signal_call">Signal Call</string>
|
||||
<string name="redphone_call_controls__mute">Mute</string>
|
||||
<string name="redphone_call_controls__flip_camera_rear">Use rear camera</string>
|
||||
<string name="redphone_call_controls__signal_call">Signal Call</string>
|
||||
|
||||
<!-- registration_activity -->
|
||||
|
@ -139,6 +139,7 @@ public class WebRtcCallActivity extends Activity {
|
||||
callScreen.setIncomingCallActionListener(new IncomingCallActionListener());
|
||||
callScreen.setAudioMuteButtonListener(new AudioMuteButtonListener());
|
||||
callScreen.setVideoMuteButtonListener(new VideoMuteButtonListener());
|
||||
callScreen.setCameraFlipButtonListener(new CameraFlipButtonListener());
|
||||
callScreen.setSpeakerButtonListener(new SpeakerButtonListener());
|
||||
callScreen.setBluetoothButtonListener(new BluetoothButtonListener());
|
||||
|
||||
@ -159,6 +160,13 @@ public class WebRtcCallActivity extends Activity {
|
||||
startService(intent);
|
||||
}
|
||||
|
||||
private void handleSetCameraFlip(boolean isRear) {
|
||||
Intent intent = new Intent(this, WebRtcCallService.class);
|
||||
intent.setAction(WebRtcCallService.ACTION_SET_CAMERA_FLIP);
|
||||
intent.putExtra(WebRtcCallService.EXTRA_CAMERA_FLIP_REAR, isRear);
|
||||
startService(intent);
|
||||
}
|
||||
|
||||
private void handleAnswerCall() {
|
||||
WebRtcViewModel event = EventBus.getDefault().getStickyEvent(WebRtcViewModel.class);
|
||||
|
||||
@ -348,6 +356,11 @@ public class WebRtcCallActivity extends Activity {
|
||||
}
|
||||
}
|
||||
|
||||
private class CameraFlipButtonListener implements WebRtcCallControls.CameraFlipButtonListener {
|
||||
@Override
|
||||
public void onToggle(boolean isRear) { WebRtcCallActivity.this.handleSetCameraFlip(isRear); }
|
||||
}
|
||||
|
||||
private class SpeakerButtonListener implements WebRtcCallControls.SpeakerButtonListener {
|
||||
@Override
|
||||
public void onSpeakerChange(boolean isSpeaker) {
|
||||
|
@ -27,6 +27,7 @@ public class WebRtcCallControls extends LinearLayout {
|
||||
|
||||
private AccessibleToggleButton audioMuteButton;
|
||||
private AccessibleToggleButton videoMuteButton;
|
||||
private AccessibleToggleButton cameraFlipButton;
|
||||
private AccessibleToggleButton speakerButton;
|
||||
private AccessibleToggleButton bluetoothButton;
|
||||
|
||||
@ -60,6 +61,8 @@ public class WebRtcCallControls extends LinearLayout {
|
||||
this.bluetoothButton = ViewUtil.findById(this, R.id.bluetoothButton);
|
||||
this.audioMuteButton = ViewUtil.findById(this, R.id.muteButton);
|
||||
this.videoMuteButton = ViewUtil.findById(this, R.id.video_mute_button);
|
||||
this.cameraFlipButton = ViewUtil.findById(this, R.id.camera_flip_button);
|
||||
this.cameraFlipButton.setVisibility(View.INVISIBLE); // shown once video is enabled
|
||||
}
|
||||
|
||||
public void setAudioMuteButtonListener(final MuteButtonListener listener) {
|
||||
@ -75,7 +78,18 @@ public class WebRtcCallControls extends LinearLayout {
|
||||
videoMuteButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
listener.onToggle(!isChecked);
|
||||
boolean videoMuted = !isChecked;
|
||||
listener.onToggle(videoMuted);
|
||||
cameraFlipButton.setVisibility(videoMuted ? View.INVISIBLE : View.VISIBLE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setCameraFlipButtonListener(final CameraFlipButtonListener listener) {
|
||||
cameraFlipButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
listener.onToggle(isChecked);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -138,21 +152,25 @@ public class WebRtcCallControls extends LinearLayout {
|
||||
speakerButton.setAlpha(1.0f);
|
||||
bluetoothButton.setAlpha(1.0f);
|
||||
videoMuteButton.setAlpha(1.0f);
|
||||
cameraFlipButton.setAlpha(1.0f);
|
||||
audioMuteButton.setAlpha(1.0f);
|
||||
|
||||
speakerButton.setEnabled(true);
|
||||
bluetoothButton.setEnabled(true);
|
||||
videoMuteButton.setEnabled(true);
|
||||
cameraFlipButton.setEnabled(true);
|
||||
audioMuteButton.setEnabled(true);
|
||||
} else if (!enabled && Build.VERSION.SDK_INT >= 11) {
|
||||
speakerButton.setAlpha(0.3f);
|
||||
bluetoothButton.setAlpha(0.3f);
|
||||
videoMuteButton.setAlpha(0.3f);
|
||||
cameraFlipButton.setAlpha(0.3f);
|
||||
audioMuteButton.setAlpha(0.3f);
|
||||
|
||||
speakerButton.setEnabled(false);
|
||||
bluetoothButton.setEnabled(false);
|
||||
videoMuteButton.setEnabled(false);
|
||||
cameraFlipButton.setEnabled(false);
|
||||
audioMuteButton.setEnabled(false);
|
||||
}
|
||||
}
|
||||
@ -179,6 +197,10 @@ public class WebRtcCallControls extends LinearLayout {
|
||||
public void onToggle(boolean isMuted);
|
||||
}
|
||||
|
||||
public static interface CameraFlipButtonListener {
|
||||
public void onToggle(boolean isRear);
|
||||
}
|
||||
|
||||
public static interface SpeakerButtonListener {
|
||||
public void onSpeakerChange(boolean isSpeaker);
|
||||
}
|
||||
|
@ -154,6 +154,10 @@ public class WebRtcCallScreen extends FrameLayout implements RecipientModifiedLi
|
||||
this.controls.setVideoMuteButtonListener(listener);
|
||||
}
|
||||
|
||||
public void setCameraFlipButtonListener(WebRtcCallControls.CameraFlipButtonListener listener) {
|
||||
this.controls.setCameraFlipButtonListener(listener);
|
||||
}
|
||||
|
||||
public void setSpeakerButtonListener(WebRtcCallControls.SpeakerButtonListener listener) {
|
||||
this.controls.setSpeakerButtonListener(listener);
|
||||
}
|
||||
|
@ -116,6 +116,7 @@ public class WebRtcCallService extends Service implements InjectableType, PeerCo
|
||||
|
||||
public static final String EXTRA_REMOTE_ADDRESS = "remote_address";
|
||||
public static final String EXTRA_MUTE = "mute_value";
|
||||
public static final String EXTRA_CAMERA_FLIP_REAR = "camera_flip_rear_value";
|
||||
public static final String EXTRA_AVAILABLE = "enabled_value";
|
||||
public static final String EXTRA_REMOTE_DESCRIPTION = "remote_description";
|
||||
public static final String EXTRA_TIMESTAMP = "timestamp";
|
||||
@ -132,6 +133,7 @@ public class WebRtcCallService extends Service implements InjectableType, PeerCo
|
||||
public static final String ACTION_LOCAL_HANGUP = "LOCAL_HANGUP";
|
||||
public static final String ACTION_SET_MUTE_AUDIO = "SET_MUTE_AUDIO";
|
||||
public static final String ACTION_SET_MUTE_VIDEO = "SET_MUTE_VIDEO";
|
||||
public static final String ACTION_SET_CAMERA_FLIP = "SET_CAMERA_FLIP";
|
||||
public static final String ACTION_BLUETOOTH_CHANGE = "BLUETOOTH_CHANGE";
|
||||
public static final String ACTION_WIRED_HEADSET_CHANGE = "WIRED_HEADSET_CHANGE";
|
||||
public static final String ACTION_SCREEN_OFF = "SCREEN_OFF";
|
||||
@ -208,6 +210,7 @@ public class WebRtcCallService extends Service implements InjectableType, PeerCo
|
||||
else if (intent.getAction().equals(ACTION_REMOTE_HANGUP)) handleRemoteHangup(intent);
|
||||
else if (intent.getAction().equals(ACTION_SET_MUTE_AUDIO)) handleSetMuteAudio(intent);
|
||||
else if (intent.getAction().equals(ACTION_SET_MUTE_VIDEO)) handleSetMuteVideo(intent);
|
||||
else if (intent.getAction().equals(ACTION_SET_CAMERA_FLIP)) handleSetCameraFlip(intent);
|
||||
else if (intent.getAction().equals(ACTION_BLUETOOTH_CHANGE)) handleBluetoothChange(intent);
|
||||
else if (intent.getAction().equals(ACTION_WIRED_HEADSET_CHANGE)) handleWiredHeadsetChange(intent);
|
||||
else if (intent.getAction().equals((ACTION_SCREEN_OFF))) handleScreenOffChange(intent);
|
||||
@ -804,6 +807,17 @@ public class WebRtcCallService extends Service implements InjectableType, PeerCo
|
||||
sendMessage(viewModelStateFor(callState), this.recipient, localVideoEnabled, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled);
|
||||
}
|
||||
|
||||
private void handleSetCameraFlip(Intent intent) {
|
||||
boolean isRear = intent.getBooleanExtra(EXTRA_CAMERA_FLIP_REAR, false);
|
||||
Log.w(TAG, "handleSetCameraFlip(isRear=" + isRear + ")...");
|
||||
|
||||
if (this.localVideoEnabled) {
|
||||
if (this.peerConnection != null) {
|
||||
this.peerConnection.flipCameras(isRear);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleBluetoothChange(Intent intent) {
|
||||
this.bluetoothAvailable = intent.getBooleanExtra(EXTRA_AVAILABLE, false);
|
||||
|
||||
|
@ -40,8 +40,16 @@ public class PeerConnectionWrapper {
|
||||
@NonNull private final AudioSource audioSource;
|
||||
|
||||
@Nullable private final VideoCapturer videoCapturer;
|
||||
@Nullable private final VideoCapturer videoCapturerRear;
|
||||
@Nullable private final VideoSource videoSource;
|
||||
@Nullable private final VideoSource videoSourceRear;
|
||||
@Nullable private final VideoTrack videoTrack;
|
||||
@Nullable private final VideoTrack videoTrackRear;
|
||||
|
||||
@Nullable private VideoCapturer videoCapturerActive;
|
||||
@Nullable private VideoTrack videoTrackActive;
|
||||
|
||||
@Nullable private final MediaStream mediaStream;
|
||||
|
||||
public PeerConnectionWrapper(@NonNull Context context,
|
||||
@NonNull PeerConnectionFactory factory,
|
||||
@ -72,44 +80,71 @@ public class PeerConnectionWrapper {
|
||||
this.peerConnection.setAudioPlayout(false);
|
||||
this.peerConnection.setAudioRecording(false);
|
||||
|
||||
this.videoCapturer = createVideoCapturer(context);
|
||||
this.videoCapturer = createVideoCapturer(context, false);
|
||||
this.videoCapturerRear = createVideoCapturer(context, true);
|
||||
|
||||
MediaStream mediaStream = factory.createLocalMediaStream("ARDAMS");
|
||||
this.videoCapturerActive = videoCapturer;
|
||||
|
||||
this.mediaStream = factory.createLocalMediaStream("ARDAMS");
|
||||
this.audioSource = factory.createAudioSource(audioConstraints);
|
||||
this.audioTrack = factory.createAudioTrack("ARDAMSa0", audioSource);
|
||||
this.audioTrack.setEnabled(false);
|
||||
mediaStream.addTrack(audioTrack);
|
||||
this.mediaStream.addTrack(audioTrack);
|
||||
|
||||
if (videoCapturer != null) {
|
||||
this.videoSource = factory.createVideoSource(videoCapturer);
|
||||
this.videoTrack = factory.createVideoTrack("ARDAMSv0", videoSource);
|
||||
|
||||
this.videoTrackActive = videoTrack;
|
||||
|
||||
this.videoTrack.addRenderer(new VideoRenderer(localRenderer));
|
||||
this.videoTrack.setEnabled(false);
|
||||
mediaStream.addTrack(videoTrack);
|
||||
this.mediaStream.addTrack(videoTrack);
|
||||
} else {
|
||||
this.videoSource = null;
|
||||
this.videoTrack = null;
|
||||
this.videoTrackActive = null;
|
||||
}
|
||||
|
||||
if (videoCapturerRear != null) {
|
||||
this.videoSourceRear = factory.createVideoSource(videoCapturerRear);
|
||||
this.videoTrackRear = factory.createVideoTrack("ARDAMSv0", videoSourceRear);
|
||||
this.videoTrackRear.addRenderer(new VideoRenderer(localRenderer));
|
||||
this.videoTrackRear.setEnabled(false);
|
||||
} else {
|
||||
this.videoSourceRear = null;
|
||||
this.videoTrackRear = null;
|
||||
}
|
||||
|
||||
this.peerConnection.addStream(mediaStream);
|
||||
}
|
||||
|
||||
public void setVideoEnabled(boolean enabled) {
|
||||
if (this.videoTrack != null) {
|
||||
this.videoTrack.setEnabled(enabled);
|
||||
if (this.videoTrackActive != null) {
|
||||
this.videoTrackActive.setEnabled(enabled);
|
||||
}
|
||||
|
||||
if (this.videoCapturer != null) {
|
||||
if (this.videoCapturerActive != null) {
|
||||
try {
|
||||
if (enabled) this.videoCapturer.startCapture(1280, 720, 30);
|
||||
else this.videoCapturer.stopCapture();
|
||||
if (enabled) this.videoCapturerActive.startCapture(1280, 720, 30);
|
||||
else this.videoCapturerActive.stopCapture();
|
||||
} catch (InterruptedException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void flipCameras(boolean isRear) {
|
||||
if (videoCapturerRear != null) {
|
||||
setVideoEnabled(false);
|
||||
mediaStream.removeTrack(videoTrackActive);
|
||||
this.videoTrackActive = isRear ? videoTrackRear : videoTrack;
|
||||
this.videoCapturerActive = isRear ? videoCapturerRear : videoCapturer;
|
||||
mediaStream.addTrack(videoTrackActive);
|
||||
setVideoEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void setCommunicationMode() {
|
||||
this.peerConnection.setAudioPlayout(true);
|
||||
this.peerConnection.setAudioRecording(true);
|
||||
@ -268,10 +303,23 @@ public class PeerConnectionWrapper {
|
||||
this.videoCapturer.dispose();
|
||||
}
|
||||
|
||||
if (this.videoCapturerRear != null) {
|
||||
try {
|
||||
this.videoCapturerRear.stopCapture();
|
||||
} catch (InterruptedException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
this.videoCapturerRear.dispose();
|
||||
}
|
||||
|
||||
if (this.videoSource != null) {
|
||||
this.videoSource.dispose();
|
||||
}
|
||||
|
||||
if (this.videoSourceRear != null) {
|
||||
this.videoSourceRear.dispose();
|
||||
}
|
||||
|
||||
this.audioSource.dispose();
|
||||
this.peerConnection.close();
|
||||
this.peerConnection.dispose();
|
||||
@ -281,7 +329,7 @@ public class PeerConnectionWrapper {
|
||||
return this.peerConnection.addIceCandidate(candidate);
|
||||
}
|
||||
|
||||
private @Nullable CameraVideoCapturer createVideoCapturer(@NonNull Context context) {
|
||||
private @Nullable CameraVideoCapturer createVideoCapturer(@NonNull Context context, boolean rear) {
|
||||
boolean camera2EnumeratorIsSupported = false;
|
||||
try {
|
||||
camera2EnumeratorIsSupported = Camera2Enumerator.isSupported(context);
|
||||
@ -298,12 +346,16 @@ public class PeerConnectionWrapper {
|
||||
String[] deviceNames = enumerator.getDeviceNames();
|
||||
|
||||
for (String deviceName : deviceNames) {
|
||||
if (enumerator.isFrontFacing(deviceName)) {
|
||||
Log.w(TAG, "Creating front facing camera capturer.");
|
||||
boolean isDesiredDirection =
|
||||
rear ? enumerator.isBackFacing(deviceName)
|
||||
: enumerator.isFrontFacing(deviceName);
|
||||
if (isDesiredDirection) {
|
||||
String direction = rear ? "rear" : "front";
|
||||
Log.w(TAG, "Creating " + direction + " facing camera capturer.");
|
||||
final CameraVideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null);
|
||||
|
||||
if (videoCapturer != null) {
|
||||
Log.w(TAG, "Found front facing capturer: " + deviceName);
|
||||
Log.w(TAG, "Found " + direction + " facing capturer: " + deviceName);
|
||||
|
||||
return videoCapturer;
|
||||
}
|
||||
@ -311,7 +363,10 @@ public class PeerConnectionWrapper {
|
||||
}
|
||||
|
||||
for (String deviceName : deviceNames) {
|
||||
if (!enumerator.isFrontFacing(deviceName)) {
|
||||
boolean isDesiredDirection =
|
||||
rear ? enumerator.isBackFacing(deviceName)
|
||||
: enumerator.isFrontFacing(deviceName);
|
||||
if (!isDesiredDirection) {
|
||||
Log.w(TAG, "Creating other camera capturer.");
|
||||
final CameraVideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user