1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package android.telecom; 18 19 import android.net.Uri; 20 import android.os.Handler; 21 import android.os.IBinder; 22 import android.os.Looper; 23 import android.os.Message; 24 import android.os.RemoteException; 25 import android.telecom.InCallService.VideoCall; 26 import android.view.Surface; 27 28 import com.android.internal.os.SomeArgs; 29 import com.android.internal.telecom.IVideoCallback; 30 import com.android.internal.telecom.IVideoProvider; 31 32 /** 33 * Implementation of a Video Call, which allows InCallUi to communicate commands to the underlying 34 * {@link Connection.VideoProvider}, and direct callbacks from the 35 * {@link Connection.VideoProvider} to the appropriate {@link VideoCall.Listener}. 36 * 37 * {@hide} 38 */ 39 public class VideoCallImpl extends VideoCall { 40 41 private final IVideoProvider mVideoProvider; 42 private final VideoCallListenerBinder mBinder; 43 private VideoCall.Callback mCallback; 44 private int mVideoQuality = VideoProfile.QUALITY_UNKNOWN; 45 private Call mCall; 46 47 private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { 48 @Override 49 public void binderDied() { 50 mVideoProvider.asBinder().unlinkToDeath(this, 0); 51 } 52 }; 53 54 /** 55 * IVideoCallback stub implementation. 56 */ 57 private final class VideoCallListenerBinder extends IVideoCallback.Stub { 58 @Override receiveSessionModifyRequest(VideoProfile videoProfile)59 public void receiveSessionModifyRequest(VideoProfile videoProfile) { 60 mHandler.obtainMessage(MessageHandler.MSG_RECEIVE_SESSION_MODIFY_REQUEST, 61 videoProfile).sendToTarget(); 62 } 63 64 @Override receiveSessionModifyResponse(int status, VideoProfile requestProfile, VideoProfile responseProfile)65 public void receiveSessionModifyResponse(int status, VideoProfile requestProfile, 66 VideoProfile responseProfile) { 67 SomeArgs args = SomeArgs.obtain(); 68 args.arg1 = status; 69 args.arg2 = requestProfile; 70 args.arg3 = responseProfile; 71 mHandler.obtainMessage(MessageHandler.MSG_RECEIVE_SESSION_MODIFY_RESPONSE, args) 72 .sendToTarget(); 73 } 74 75 @Override handleCallSessionEvent(int event)76 public void handleCallSessionEvent(int event) { 77 mHandler.obtainMessage(MessageHandler.MSG_HANDLE_CALL_SESSION_EVENT, event) 78 .sendToTarget(); 79 } 80 81 @Override changePeerDimensions(int width, int height)82 public void changePeerDimensions(int width, int height) { 83 SomeArgs args = SomeArgs.obtain(); 84 args.arg1 = width; 85 args.arg2 = height; 86 mHandler.obtainMessage(MessageHandler.MSG_CHANGE_PEER_DIMENSIONS, args).sendToTarget(); 87 } 88 89 @Override changeVideoQuality(int videoQuality)90 public void changeVideoQuality(int videoQuality) { 91 mHandler.obtainMessage(MessageHandler.MSG_CHANGE_VIDEO_QUALITY, videoQuality, 0) 92 .sendToTarget(); 93 } 94 95 @Override changeCallDataUsage(long dataUsage)96 public void changeCallDataUsage(long dataUsage) { 97 mHandler.obtainMessage(MessageHandler.MSG_CHANGE_CALL_DATA_USAGE, dataUsage) 98 .sendToTarget(); 99 } 100 101 @Override changeCameraCapabilities(VideoProfile.CameraCapabilities cameraCapabilities)102 public void changeCameraCapabilities(VideoProfile.CameraCapabilities cameraCapabilities) { 103 mHandler.obtainMessage(MessageHandler.MSG_CHANGE_CAMERA_CAPABILITIES, 104 cameraCapabilities).sendToTarget(); 105 } 106 } 107 108 /** Default handler used to consolidate binder method calls onto a single thread. */ 109 private final class MessageHandler extends Handler { 110 private static final int MSG_RECEIVE_SESSION_MODIFY_REQUEST = 1; 111 private static final int MSG_RECEIVE_SESSION_MODIFY_RESPONSE = 2; 112 private static final int MSG_HANDLE_CALL_SESSION_EVENT = 3; 113 private static final int MSG_CHANGE_PEER_DIMENSIONS = 4; 114 private static final int MSG_CHANGE_CALL_DATA_USAGE = 5; 115 private static final int MSG_CHANGE_CAMERA_CAPABILITIES = 6; 116 private static final int MSG_CHANGE_VIDEO_QUALITY = 7; 117 MessageHandler(Looper looper)118 public MessageHandler(Looper looper) { 119 super(looper); 120 } 121 122 @Override handleMessage(Message msg)123 public void handleMessage(Message msg) { 124 if (mCallback == null) { 125 return; 126 } 127 128 SomeArgs args; 129 switch (msg.what) { 130 case MSG_RECEIVE_SESSION_MODIFY_REQUEST: 131 mCallback.onSessionModifyRequestReceived((VideoProfile) msg.obj); 132 break; 133 case MSG_RECEIVE_SESSION_MODIFY_RESPONSE: 134 args = (SomeArgs) msg.obj; 135 try { 136 int status = (int) args.arg1; 137 VideoProfile requestProfile = (VideoProfile) args.arg2; 138 VideoProfile responseProfile = (VideoProfile) args.arg3; 139 140 mCallback.onSessionModifyResponseReceived( 141 status, requestProfile, responseProfile); 142 } finally { 143 args.recycle(); 144 } 145 break; 146 case MSG_HANDLE_CALL_SESSION_EVENT: 147 mCallback.onCallSessionEvent((int) msg.obj); 148 break; 149 case MSG_CHANGE_PEER_DIMENSIONS: 150 args = (SomeArgs) msg.obj; 151 try { 152 int width = (int) args.arg1; 153 int height = (int) args.arg2; 154 mCallback.onPeerDimensionsChanged(width, height); 155 } finally { 156 args.recycle(); 157 } 158 break; 159 case MSG_CHANGE_CALL_DATA_USAGE: 160 mCallback.onCallDataUsageChanged((long) msg.obj); 161 break; 162 case MSG_CHANGE_CAMERA_CAPABILITIES: 163 mCallback.onCameraCapabilitiesChanged( 164 (VideoProfile.CameraCapabilities) msg.obj); 165 break; 166 case MSG_CHANGE_VIDEO_QUALITY: 167 mVideoQuality = msg.arg1; 168 mCallback.onVideoQualityChanged(msg.arg1); 169 break; 170 default: 171 break; 172 } 173 } 174 }; 175 176 private Handler mHandler; 177 VideoCallImpl(IVideoProvider videoProvider, Call call)178 VideoCallImpl(IVideoProvider videoProvider, Call call) throws RemoteException { 179 mVideoProvider = videoProvider; 180 mVideoProvider.asBinder().linkToDeath(mDeathRecipient, 0); 181 182 mBinder = new VideoCallListenerBinder(); 183 mVideoProvider.addVideoCallback(mBinder); 184 mCall = call; 185 } 186 destroy()187 public void destroy() { 188 unregisterCallback(mCallback); 189 } 190 191 /** {@inheritDoc} */ registerCallback(VideoCall.Callback callback)192 public void registerCallback(VideoCall.Callback callback) { 193 registerCallback(callback, null); 194 } 195 196 /** {@inheritDoc} */ registerCallback(VideoCall.Callback callback, Handler handler)197 public void registerCallback(VideoCall.Callback callback, Handler handler) { 198 mCallback = callback; 199 if (handler == null) { 200 mHandler = new MessageHandler(Looper.getMainLooper()); 201 } else { 202 mHandler = new MessageHandler(handler.getLooper()); 203 } 204 } 205 206 /** {@inheritDoc} */ unregisterCallback(VideoCall.Callback callback)207 public void unregisterCallback(VideoCall.Callback callback) { 208 if (callback != mCallback) { 209 return; 210 } 211 212 mCallback = null; 213 try { 214 mVideoProvider.removeVideoCallback(mBinder); 215 } catch (RemoteException e) { 216 } 217 } 218 219 /** {@inheritDoc} */ setCamera(String cameraId)220 public void setCamera(String cameraId) { 221 try { 222 mVideoProvider.setCamera(cameraId); 223 } catch (RemoteException e) { 224 } 225 } 226 227 /** {@inheritDoc} */ setPreviewSurface(Surface surface)228 public void setPreviewSurface(Surface surface) { 229 try { 230 mVideoProvider.setPreviewSurface(surface); 231 } catch (RemoteException e) { 232 } 233 } 234 235 /** {@inheritDoc} */ setDisplaySurface(Surface surface)236 public void setDisplaySurface(Surface surface) { 237 try { 238 mVideoProvider.setDisplaySurface(surface); 239 } catch (RemoteException e) { 240 } 241 } 242 243 /** {@inheritDoc} */ setDeviceOrientation(int rotation)244 public void setDeviceOrientation(int rotation) { 245 try { 246 mVideoProvider.setDeviceOrientation(rotation); 247 } catch (RemoteException e) { 248 } 249 } 250 251 /** {@inheritDoc} */ setZoom(float value)252 public void setZoom(float value) { 253 try { 254 mVideoProvider.setZoom(value); 255 } catch (RemoteException e) { 256 } 257 } 258 259 /** 260 * Sends a session modification request to the video provider. 261 * <p> 262 * The {@link InCallService} will create the {@code requestProfile} based on the current 263 * video state (i.e. {@link Call.Details#getVideoState()}). It is, however, possible that the 264 * video state maintained by the {@link InCallService} could get out of sync with what is known 265 * by the {@link android.telecom.Connection.VideoProvider}. To remove ambiguity, the 266 * {@link VideoCallImpl} passes along the pre-modify video profile to the {@code VideoProvider} 267 * to ensure it has full context of the requested change. 268 * 269 * @param requestProfile The requested video profile. 270 */ sendSessionModifyRequest(VideoProfile requestProfile)271 public void sendSessionModifyRequest(VideoProfile requestProfile) { 272 try { 273 VideoProfile originalProfile = new VideoProfile(mCall.getDetails().getVideoState(), 274 mVideoQuality); 275 276 mVideoProvider.sendSessionModifyRequest(originalProfile, requestProfile); 277 } catch (RemoteException e) { 278 } 279 } 280 281 /** {@inheritDoc} */ sendSessionModifyResponse(VideoProfile responseProfile)282 public void sendSessionModifyResponse(VideoProfile responseProfile) { 283 try { 284 mVideoProvider.sendSessionModifyResponse(responseProfile); 285 } catch (RemoteException e) { 286 } 287 } 288 289 /** {@inheritDoc} */ requestCameraCapabilities()290 public void requestCameraCapabilities() { 291 try { 292 mVideoProvider.requestCameraCapabilities(); 293 } catch (RemoteException e) { 294 } 295 } 296 297 /** {@inheritDoc} */ requestCallDataUsage()298 public void requestCallDataUsage() { 299 try { 300 mVideoProvider.requestCallDataUsage(); 301 } catch (RemoteException e) { 302 } 303 } 304 305 /** {@inheritDoc} */ setPauseImage(Uri uri)306 public void setPauseImage(Uri uri) { 307 try { 308 mVideoProvider.setPauseImage(uri); 309 } catch (RemoteException e) { 310 } 311 } 312 } 313