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