Reworked UI & Voice-only calls

Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
Mario Danic 2018-05-10 14:42:11 +02:00
parent 1922673974
commit f2aee50a74
6 changed files with 142 additions and 92 deletions

View File

@ -198,10 +198,12 @@ public class CallActivity extends AppCompatActivity {
private String credentials; private String credentials;
private List<MagicPeerConnectionWrapper> magicPeerConnectionWrapperList = new ArrayList<>(); private List<MagicPeerConnectionWrapper> magicPeerConnectionWrapperList = new ArrayList<>();
private List<String> basicUISetupList = new ArrayList<>();
private boolean videoOn = false; private boolean videoOn = false;
private boolean audioOn = false; private boolean audioOn = false;
private boolean isMultiSession = false; private boolean isMultiSession = false;
private boolean isVoiceOnlyCall = false;
private Handler handler = new Handler(); private Handler handler = new Handler();
@ -211,8 +213,6 @@ public class CallActivity extends AppCompatActivity {
private String baseUrl; private String baseUrl;
private boolean initialPermissionsCheck = true;
private SpotlightView spotlightView; private SpotlightView spotlightView;
private static int getSystemUiVisibility() { private static int getSystemUiVisibility() {
@ -249,6 +249,7 @@ public class CallActivity extends AppCompatActivity {
userEntity = Parcels.unwrap(getIntent().getExtras().getParcelable(BundleKeys.KEY_USER_ENTITY)); userEntity = Parcels.unwrap(getIntent().getExtras().getParcelable(BundleKeys.KEY_USER_ENTITY));
callSession = getIntent().getExtras().getString(BundleKeys.KEY_CALL_SESSION, "0"); callSession = getIntent().getExtras().getString(BundleKeys.KEY_CALL_SESSION, "0");
credentials = ApiUtils.getCredentials(userEntity.getUsername(), userEntity.getToken()); credentials = ApiUtils.getCredentials(userEntity.getUsername(), userEntity.getToken());
isVoiceOnlyCall = getIntent().getExtras().getBoolean(BundleKeys.KEY_CALL_VOICE_ONLY, false);
if (getIntent().getExtras().containsKey(BundleKeys.KEY_MODIFIED_BASE_URL)) { if (getIntent().getExtras().containsKey(BundleKeys.KEY_MODIFIED_BASE_URL)) {
credentials = null; credentials = null;
@ -442,6 +443,10 @@ public class CallActivity extends AppCompatActivity {
toggleMedia(true, false); toggleMedia(true, false);
} }
if (isVoiceOnlyCall && !inCall) {
startCall();
}
} else if (EffortlessPermissions.somePermissionPermanentlyDenied(this, PERMISSIONS_MICROPHONE)) { } else if (EffortlessPermissions.somePermissionPermanentlyDenied(this, PERMISSIONS_MICROPHONE)) {
// Microphone permission is permanently denied so we cannot request it normally. // Microphone permission is permanently denied so we cannot request it normally.
OpenAppDetailsDialogFragment.show( OpenAppDetailsDialogFragment.show(
@ -547,6 +552,11 @@ public class CallActivity extends AppCompatActivity {
} }
public void initViews() { public void initViews() {
if (isVoiceOnlyCall) {
cameraSwitchButton.setVisibility(View.GONE);
cameraControlButton.setVisibility(View.GONE);
pipVideoView.setVisibility(View.GONE);
} else {
if (cameraEnumerator.getDeviceNames().length < 2) { if (cameraEnumerator.getDeviceNames().length < 2) {
cameraSwitchButton.setVisibility(View.GONE); cameraSwitchButton.setVisibility(View.GONE);
} }
@ -559,17 +569,22 @@ public class CallActivity extends AppCompatActivity {
pipVideoView.setEnableHardwareScaler(false); pipVideoView.setEnableHardwareScaler(false);
pipVideoView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT); pipVideoView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT);
} }
}
private void checkPermissions() { private void checkPermissions() {
if (isVoiceOnlyCall) {
onMicrophoneClick();
} else {
EffortlessPermissions.requestPermissions(this, R.string.nc_permissions, EffortlessPermissions.requestPermissions(this, R.string.nc_permissions,
R.string.nc_proceed, R.string.nc_empty, 100, PERMISSIONS_CALL); R.string.nc_proceed, R.string.nc_empty, 100, PERMISSIONS_CALL);
}
} }
@AfterPermissionGranted(100) @AfterPermissionGranted(100)
private void onPermissionsGranted() { private void onPermissionsGranted() {
if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_CALL)) { if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_CALL)) {
if (!videoOn && !initialPermissionsCheck) { if (!videoOn && !isVoiceOnlyCall) {
onCameraClick(); onCameraClick();
} }
@ -577,15 +592,13 @@ public class CallActivity extends AppCompatActivity {
onMicrophoneClick(); onMicrophoneClick();
} }
if (!isVoiceOnlyCall) {
if (cameraEnumerator.getDeviceNames().length == 0) { if (cameraEnumerator.getDeviceNames().length == 0) {
cameraControlButton.setVisibility(View.GONE); cameraControlButton.setVisibility(View.GONE);
} }
if (cameraEnumerator.getDeviceNames().length > 1) { if (cameraEnumerator.getDeviceNames().length > 1) {
if (!initialPermissionsCheck) {
cameraSwitchButton.setVisibility(View.VISIBLE); cameraSwitchButton.setVisibility(View.VISIBLE);
} else {
cameraSwitchButton.setVisibility(View.GONE);
} }
} }
@ -597,10 +610,10 @@ public class CallActivity extends AppCompatActivity {
checkIfSomeAreApproved(); checkIfSomeAreApproved();
} }
initialPermissionsCheck = false;
} }
private void checkIfSomeAreApproved() { private void checkIfSomeAreApproved() {
if (!isVoiceOnlyCall) {
if (cameraEnumerator.getDeviceNames().length == 0) { if (cameraEnumerator.getDeviceNames().length == 0) {
cameraControlButton.setVisibility(View.GONE); cameraControlButton.setVisibility(View.GONE);
} }
@ -609,7 +622,7 @@ public class CallActivity extends AppCompatActivity {
cameraSwitchButton.setVisibility(View.VISIBLE); cameraSwitchButton.setVisibility(View.VISIBLE);
} }
if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_CAMERA) && !initialPermissionsCheck) { if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_CAMERA)) {
if (!videoOn) { if (!videoOn) {
onCameraClick(); onCameraClick();
} }
@ -618,6 +631,7 @@ public class CallActivity extends AppCompatActivity {
cameraControlButton.setAlpha(0.7f); cameraControlButton.setAlpha(0.7f);
cameraSwitchButton.setVisibility(View.GONE); cameraSwitchButton.setVisibility(View.GONE);
} }
}
if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_MICROPHONE)) { if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_MICROPHONE)) {
if (!audioOn) { if (!audioOn) {
@ -634,12 +648,13 @@ public class CallActivity extends AppCompatActivity {
@AfterPermissionDenied(100) @AfterPermissionDenied(100)
private void onPermissionsDenied() { private void onPermissionsDenied() {
initialPermissionsCheck = false; if (!isVoiceOnlyCall) {
if (cameraEnumerator.getDeviceNames().length == 0) { if (cameraEnumerator.getDeviceNames().length == 0) {
cameraControlButton.setVisibility(View.GONE); cameraControlButton.setVisibility(View.GONE);
} else if (cameraEnumerator.getDeviceNames().length == 1) { } else if (cameraEnumerator.getDeviceNames().length == 1) {
cameraSwitchButton.setVisibility(View.GONE); cameraSwitchButton.setVisibility(View.GONE);
} }
}
if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_CAMERA) || if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_CAMERA) ||
EffortlessPermissions.hasPermissions(this, PERMISSIONS_MICROPHONE)) { EffortlessPermissions.hasPermissions(this, PERMISSIONS_MICROPHONE)) {
@ -685,11 +700,20 @@ public class CallActivity extends AppCompatActivity {
//create sdpConstraints //create sdpConstraints
sdpConstraints = new MediaConstraints(); sdpConstraints = new MediaConstraints();
sdpConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true")); sdpConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true"));
sdpConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveVideo", "true")); String offerToReceiveVideoString = "true";
if (isVoiceOnlyCall) {
offerToReceiveVideoString = "false";
}
sdpConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveVideo",
offerToReceiveVideoString));
sdpConstraints.optional.add(new MediaConstraints.KeyValuePair("internalSctpDataChannels", "true")); sdpConstraints.optional.add(new MediaConstraints.KeyValuePair("internalSctpDataChannels", "true"));
sdpConstraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true")); sdpConstraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"));
if (!isVoiceOnlyCall) {
cameraInitialization(); cameraInitialization();
}
microphoneInitialization(); microphoneInitialization();
} }
@ -1153,17 +1177,6 @@ public class CallActivity extends AppCompatActivity {
private void hangupNetworkCalls() { private void hangupNetworkCalls() {
ncApi.leaveCall(credentials, ApiUtils.getUrlForCall(baseUrl, roomToken)) ncApi.leaveCall(credentials, ApiUtils.getUrlForCall(baseUrl, roomToken))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<GenericOverall>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(GenericOverall genericOverall) {
ncApi.leaveRoom(credentials, ApiUtils.getUrlForRoomParticipants(baseUrl, roomToken))
.subscribeOn(Schedulers.newThread()) .subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<GenericOverall>() { .subscribe(new Observer<GenericOverall>() {
@ -1185,19 +1198,6 @@ public class CallActivity extends AppCompatActivity {
@Override @Override
public void onComplete() { public void onComplete() {
}
});
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
} }
}); });
} }
@ -1214,8 +1214,19 @@ public class CallActivity extends AppCompatActivity {
RelativeLayout relativeLayout = remoteRenderersLayout.findViewWithTag(sessionId); RelativeLayout relativeLayout = remoteRenderersLayout.findViewWithTag(sessionId);
if (relativeLayout != null) { if (relativeLayout != null) {
ImageView imageView; ImageView imageView;
ImageView avatarImageView = relativeLayout.findViewById(R.id.avatarImageView);
SurfaceViewRenderer surfaceViewRenderer = relativeLayout.findViewById(R.id.surface_view);
if (video) { if (video) {
imageView = relativeLayout.findViewById(R.id.remote_video_off); imageView = relativeLayout.findViewById(R.id.remote_video_off);
if (change) {
avatarImageView.setVisibility(View.INVISIBLE);
surfaceViewRenderer.setVisibility(View.VISIBLE);
} else {
avatarImageView.setVisibility(View.VISIBLE);
surfaceViewRenderer.setVisibility(View.INVISIBLE);
}
} else { } else {
imageView = relativeLayout.findViewById(R.id.remote_audio_off); imageView = relativeLayout.findViewById(R.id.remote_audio_off);
} }
@ -1228,14 +1239,12 @@ public class CallActivity extends AppCompatActivity {
} }
} }
private void gotRemoteStream(MediaStream stream, String session) { private void setupNewPeerLayout(String session) {
removeMediaStream(session); if (remoteRenderersLayout.findViewWithTag(session) == null) {
basicUISetupList.add(session);
if (stream.videoTracks.size() == 1) { runOnUiThread(() -> {
VideoTrack videoTrack = stream.videoTracks.get(0);
try {
RelativeLayout relativeLayout = (RelativeLayout) RelativeLayout relativeLayout = (RelativeLayout)
getLayoutInflater().inflate(R.layout.surface_renderer, remoteRenderersLayout, getLayoutInflater().inflate(R.layout.call_item, remoteRenderersLayout,
false); false);
relativeLayout.setTag(session); relativeLayout.setTag(session);
SurfaceViewRenderer surfaceViewRenderer = relativeLayout.findViewById(R.id SurfaceViewRenderer surfaceViewRenderer = relativeLayout.findViewById(R.id
@ -1247,12 +1256,40 @@ public class CallActivity extends AppCompatActivity {
surfaceViewRenderer.setEnableHardwareScaler(false); surfaceViewRenderer.setEnableHardwareScaler(false);
surfaceViewRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT); surfaceViewRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT);
surfaceViewRenderer.setOnClickListener(videoOnClickListener); surfaceViewRenderer.setOnClickListener(videoOnClickListener);
VideoRenderer remoteRenderer = new VideoRenderer(surfaceViewRenderer);
videoTrack.addRenderer(remoteRenderer);
remoteRenderersLayout.addView(relativeLayout); remoteRenderersLayout.addView(relativeLayout);
gotNick(session, getPeerConnectionWrapperForSessionId(session).getNick()); gotNick(session, getPeerConnectionWrapperForSessionId(session).getNick());
} catch (Exception e) {
Log.d(TAG, "Failed to create a new video view"); basicUISetupList.remove(session);
callControls.setZ(100.0f);
});
}
}
private void setupVideoStreamForLayout(@Nullable MediaStream mediaStream, String session, boolean enable) {
boolean isInitialLayoutSetupForPeer = false;
if (remoteRenderersLayout.findViewWithTag(session) == null) {
setupNewPeerLayout(session);
isInitialLayoutSetupForPeer = true;
}
RelativeLayout relativeLayout = remoteRenderersLayout.findViewWithTag(session);
SurfaceViewRenderer surfaceViewRenderer = relativeLayout.findViewById(R.id.surface_view);
ImageView imageView = relativeLayout.findViewById(R.id.avatarImageView);
if (mediaStream != null && mediaStream.videoTracks != null && mediaStream.videoTracks.size() > 0 && enable) {
VideoTrack videoTrack = mediaStream.videoTracks.get(0);
VideoRenderer remoteRenderer = new VideoRenderer(surfaceViewRenderer);
videoTrack.addRenderer(remoteRenderer);
imageView.setVisibility(View.INVISIBLE);
surfaceViewRenderer.setVisibility(View.VISIBLE);
} else {
imageView.setVisibility(View.VISIBLE);
surfaceViewRenderer.setVisibility(View.INVISIBLE);
if (isInitialLayoutSetupForPeer && isVoiceOnlyCall) {
gotAudioOrVideoChange(true, session, false);
} }
} }
@ -1311,7 +1348,7 @@ public class CallActivity extends AppCompatActivity {
@Subscribe(threadMode = ThreadMode.BACKGROUND) @Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMessageEvent(PeerConnectionEvent peerConnectionEvent) { public void onMessageEvent(PeerConnectionEvent peerConnectionEvent) {
if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent.PeerConnectionEventType if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent.PeerConnectionEventType
.CLOSE_PEER)) { .PEER_CLOSED)) {
endPeerConnection(peerConnectionEvent.getSessionId()); endPeerConnection(peerConnectionEvent.getSessionId());
} else if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent } else if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent
.PeerConnectionEventType.SENSOR_FAR) || .PeerConnectionEventType.SENSOR_FAR) ||
@ -1327,7 +1364,7 @@ public class CallActivity extends AppCompatActivity {
.PeerConnectionEventType.NICK_CHANGE)) { .PeerConnectionEventType.NICK_CHANGE)) {
runOnUiThread(() -> gotNick(peerConnectionEvent.getSessionId(), peerConnectionEvent.getNick())); runOnUiThread(() -> gotNick(peerConnectionEvent.getSessionId(), peerConnectionEvent.getNick()));
} else if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent } else if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent
.PeerConnectionEventType.VIDEO_CHANGE)) { .PeerConnectionEventType.VIDEO_CHANGE) && !isVoiceOnlyCall) {
runOnUiThread(() -> gotAudioOrVideoChange(true, peerConnectionEvent.getSessionId(), runOnUiThread(() -> gotAudioOrVideoChange(true, peerConnectionEvent.getSessionId(),
peerConnectionEvent.getChangeValue())); peerConnectionEvent.getChangeValue()));
} else if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent } else if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent
@ -1362,9 +1399,11 @@ public class CallActivity extends AppCompatActivity {
@Subscribe(threadMode = ThreadMode.MAIN) @Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MediaStreamEvent mediaStreamEvent) { public void onMessageEvent(MediaStreamEvent mediaStreamEvent) {
if (mediaStreamEvent.getMediaStream() != null) { if (mediaStreamEvent.getMediaStream() != null) {
gotRemoteStream(mediaStreamEvent.getMediaStream(), mediaStreamEvent.getSession()); setupVideoStreamForLayout(mediaStreamEvent.getMediaStream(), mediaStreamEvent.getSession(),
mediaStreamEvent.getMediaStream().videoTracks != null
&& mediaStreamEvent.getMediaStream().videoTracks.size() > 0);
} else { } else {
removeMediaStream(mediaStreamEvent.getSession()); setupVideoStreamForLayout(null, mediaStreamEvent.getSession(), false);
} }
} }

View File

@ -40,6 +40,6 @@ public class PeerConnectionEvent {
} }
public enum PeerConnectionEventType { public enum PeerConnectionEventType {
CLOSE_PEER, SENSOR_FAR, SENSOR_NEAR, NICK_CHANGE, AUDIO_CHANGE, VIDEO_CHANGE PEER_CONNECTED, PEER_CLOSED, SENSOR_FAR, SENSOR_NEAR, NICK_CHANGE, AUDIO_CHANGE, VIDEO_CHANGE
} }
} }

View File

@ -55,6 +55,7 @@ public class MagicPeerConnectionWrapper {
private PeerConnection peerConnection; private PeerConnection peerConnection;
private String sessionId; private String sessionId;
private String nick; private String nick;
private String userId;
private MediaConstraints mediaConstraints; private MediaConstraints mediaConstraints;
private DataChannel magicDataChannel; private DataChannel magicDataChannel;
private MagicSdpObserver magicSdpObserver; private MagicSdpObserver magicSdpObserver;
@ -248,11 +249,15 @@ public class MagicPeerConnectionWrapper {
@Override @Override
public void onIceConnectionChange(PeerConnection.IceConnectionState iceConnectionState) { public void onIceConnectionChange(PeerConnection.IceConnectionState iceConnectionState) {
if (iceConnectionState.equals(PeerConnection.IceConnectionState.CONNECTED) && hasInitiated) { if (iceConnectionState.equals(PeerConnection.IceConnectionState.CONNECTED)) {
EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType
.PEER_CONNECTED, sessionId, null, null));
if (hasInitiated) {
sendInitialMediaStatus(); sendInitialMediaStatus();
}
} else if (iceConnectionState.equals(PeerConnection.IceConnectionState.CLOSED)) { } else if (iceConnectionState.equals(PeerConnection.IceConnectionState.CLOSED)) {
EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType
.CLOSE_PEER, sessionId, null, null)); .PEER_CLOSED, sessionId, null, null));
} }
} }

View File

@ -74,7 +74,6 @@
android:layout_width="60dp" android:layout_width="60dp"
android:layout_height="60dp" android:layout_height="60dp"
android:layout_marginEnd="20dp" android:layout_marginEnd="20dp"
android:alpha="0.7"
android:visibility="gone" android:visibility="gone"
app:checked="false" app:checked="false"
app:enableInitialAnimation="false" app:enableInitialAnimation="false"

View File

@ -29,7 +29,15 @@
<org.webrtc.SurfaceViewRenderer <org.webrtc.SurfaceViewRenderer
android:id="@+id/surface_view" android:id="@+id/surface_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"/> android:layout_height="match_parent"
android:visibility="invisible"/>
<ImageView
android:layout_width="80dp"
android:layout_height="80dp"
android:id="@+id/avatarImageView"
android:layout_centerInParent="true"
android:src="@drawable/ic_baseline_arrow_downward_24px"/>
<ImageView <ImageView
android:id="@+id/remote_video_off" android:id="@+id/remote_video_off"

View File

@ -26,7 +26,6 @@
android:id="@+id/conversation_voice_call" android:id="@+id/conversation_voice_call"
android:icon="@drawable/ic_call_white_24dp" android:icon="@drawable/ic_call_white_24dp"
android:title="@string/nc_conversation_menu_voice_call" android:title="@string/nc_conversation_menu_voice_call"
android:visible="false"
app:showAsAction="always"/> app:showAsAction="always"/>
<item <item