IMS-VT: FR36165 - UI renders after receiving video frame
- Show far end video after receiving the first video frame
- IMS notifies us when it receives the first video frame
through the PLAYER_START event. Show incoming video
once we receive this event
- When frames stop transmitting, IMS notifies us through
the PLAYER_STOP event. Hide the incoming video once
we receive this event
Change-Id: Ibdd001679d08cd5dbefd2f944ac97597897bcc51
CRs-Fixed: 1051225
diff --git a/InCallUI/src/com/android/incallui/InCallVideoCallCallbackNotifier.java b/InCallUI/src/com/android/incallui/InCallVideoCallCallbackNotifier.java
index d65640b..1a24b16 100644
--- a/InCallUI/src/com/android/incallui/InCallVideoCallCallbackNotifier.java
+++ b/InCallUI/src/com/android/incallui/InCallVideoCallCallbackNotifier.java
@@ -46,6 +46,14 @@
private final Set<SurfaceChangeListener> mSurfaceChangeListeners = Collections.newSetFromMap(
new ConcurrentHashMap<SurfaceChangeListener, Boolean>(8, 0.9f, 1));
+ /* Invalid call session event */
+ public static final int CALL_SESSION_INVALID_EVENT = -1;
+
+ /** Cache the call session event for cases where the call is in background and listeners
+ * are unregistered.
+ */
+ private int mCallSessionEvent = CALL_SESSION_INVALID_EVENT;
+
/**
* Static singleton accessor method.
*/
@@ -91,6 +99,22 @@
}
/**
+ * Adds a new {@link VideoEventListener} and notifies the entity that registered
+ * if flag notify is true.
+ *
+ * @param listener The listener.
+ * @param notify true or false
+ */
+ public void addVideoEventListener(VideoEventListener listener, boolean notify) {
+ addVideoEventListener(listener);
+
+ // Notify registered listeners of cached call session event if it's a valid value
+ if (notify && mCallSessionEvent != CALL_SESSION_INVALID_EVENT) {
+ callSessionEvent(mCallSessionEvent);
+ }
+ }
+
+ /**
* Remove a {@link VideoEventListener}.
*
* @param listener The listener.
@@ -151,8 +175,9 @@
* @param event The call session event.
*/
public void callSessionEvent(int event) {
+ mCallSessionEvent = event;
for (VideoEventListener listener : mVideoEventListeners) {
- listener.onCallSessionEvent(event);
+ listener.onCallSessionEvent(mCallSessionEvent);
}
}
diff --git a/InCallUI/src/com/android/incallui/VideoCallPresenter.java b/InCallUI/src/com/android/incallui/VideoCallPresenter.java
index cb5f43b..fabdc99 100644
--- a/InCallUI/src/com/android/incallui/VideoCallPresenter.java
+++ b/InCallUI/src/com/android/incallui/VideoCallPresenter.java
@@ -205,6 +205,14 @@
private int mActivityOrientationMode = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
/**
+ * Determines if the incoming video is available. If the call session resume event has been
+ * received (i.e PLAYER_START has been received from lower layers), incoming video is
+ * available. If the call session pause event has been received (i.e PLAYER_STOP has been
+ * received from lower layers), incoming video is not available.
+ */
+ private static boolean mIsIncomingVideoAvailable = false;
+
+ /**
* Initializes the presenter.
*
* @param context The current context.
@@ -247,7 +255,6 @@
// Register for surface and video events from {@link InCallVideoCallListener}s.
InCallVideoCallCallbackNotifier.getInstance().addSurfaceChangeListener(this);
- InCallVideoCallCallbackNotifier.getInstance().addVideoEventListener(this);
InCallUiStateNotifier.getInstance().addListener(this);
mCurrentVideoState = VideoProfile.STATE_AUDIO_ONLY;
mCurrentCallState = Call.State.INVALID;
@@ -255,6 +262,8 @@
final InCallPresenter.InCallState inCallState =
InCallPresenter.getInstance().getInCallState();
onStateChange(inCallState, inCallState, CallList.getInstance());
+ InCallVideoCallCallbackNotifier.getInstance().addVideoEventListener(this,
+ VideoUtils.isVideoCall(mCurrentVideoState));
}
/**
@@ -310,6 +319,12 @@
}
} else if (surface == VideoCallFragment.SURFACE_DISPLAY) {
mVideoCall.setDisplaySurface(ui.getDisplayVideoSurface());
+
+ // Show/hide the incoming video once surface is created based on
+ // whether PLAYER_START event has been received or not. Since we
+ // start with showing incoming video by default for surface creation,
+ // we need to make sure we hide it once surface is available.
+ showVideoUi(mCurrentVideoState, mCurrentCallState);
}
}
@@ -768,7 +783,10 @@
/**
* Based on the current video state and call state, show or hide the incoming and
* outgoing video surfaces. The outgoing video surface is shown any time video is transmitting.
- * The incoming video surface is shown whenever the video is un-paused and active.
+ * The incoming video surface is shown whenever the video is un-paused and active and incoming
+ * video is available. If display surface has not been created and video reception is enabled,
+ * we override the value returned by showIncomingVideo and show the incoming video so surface
+ * creation is enabled
*
* @param videoState The video state.
* @param callState The call state.
@@ -779,14 +797,19 @@
Log.e(this, "showVideoUi, VideoCallUi is null returning");
return;
}
- boolean showIncomingVideo = showIncomingVideo(videoState, callState);
+
+ final boolean isDisplaySurfaceCreated = ui.isDisplayVideoSurfaceCreated();
+ final boolean isVideoReceptionEnabled = VideoProfile.isReceptionEnabled(videoState);
+ boolean showIncomingVideo = showIncomingVideo(videoState, callState) ||
+ (!isDisplaySurfaceCreated && isVideoReceptionEnabled);
boolean showOutgoingVideo = showOutgoingVideo(videoState);
+
Log.v(this, "showVideoUi : showIncoming = " + showIncomingVideo + " showOutgoing = "
+ showOutgoingVideo);
if (showIncomingVideo || showOutgoingVideo) {
ui.showVideoViews(showOutgoingVideo, showIncomingVideo);
- if (VideoProfile.isReceptionEnabled(videoState)) {
+ if (isVideoReceptionEnabled) {
loadProfilePhotoAsync();
}
} else {
@@ -799,8 +822,9 @@
/**
* Determines if the incoming video surface should be shown based on the current videoState and
- * callState. The video surface is shown when incoming video is not paused, the call is active
- * or dialing and video reception is enabled.
+ * callState. The video surface is shown when video reception is enabled AND either incoming
+ * video is not paused, the call is active or dialing, incoming video is available
+ * (i.e PLAYER_START event has been raised by lower layers)
*
* @param videoState The current video state.
* @param callState The current call state.
@@ -818,7 +842,7 @@
callState == Call.State.CONNECTING;
return !isPaused && (isCallActive || isCallOutgoing) &&
- VideoProfile.isReceptionEnabled(videoState);
+ VideoProfile.isReceptionEnabled(videoState) && mIsIncomingVideoAvailable;
}
/**
@@ -996,10 +1020,11 @@
switch (event) {
case Connection.VideoProvider.SESSION_EVENT_RX_PAUSE:
- sb.append("rx_pause");
- break;
case Connection.VideoProvider.SESSION_EVENT_RX_RESUME:
- sb.append("rx_resume");
+ mIsIncomingVideoAvailable =
+ event == Connection.VideoProvider.SESSION_EVENT_RX_RESUME;
+ showVideoUi(mCurrentVideoState, mCurrentCallState);
+ sb.append(mIsIncomingVideoAvailable ? "rx_resume" : "rx_pause");
break;
case Connection.VideoProvider.SESSION_EVENT_CAMERA_FAILURE:
sb.append("camera_failure");