blob: 9b2cc7a9127a049f21279f9c32a079139115f8f0 [file] [log] [blame]
Tyler Gunn86014fc2015-06-12 14:31:25 -07001/*
2 * Copyright (C) 2015 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 com.android.server.telecom;
18
19import android.net.Uri;
20import android.os.IBinder;
21import android.os.Looper;
22import android.os.RemoteException;
23import android.telecom.Connection;
24import android.telecom.InCallService;
25import android.telecom.VideoProfile;
26import android.view.Surface;
27
28import com.android.internal.telecom.IVideoCallback;
29import com.android.internal.telecom.IVideoProvider;
30
31import java.util.Collections;
Tyler Gunn86014fc2015-06-12 14:31:25 -070032import java.util.Set;
33import java.util.concurrent.ConcurrentHashMap;
34
35/**
36 * Proxies video provider messages from {@link InCallService.VideoCall}
37 * implementations to the underlying {@link Connection.VideoProvider} implementation. Also proxies
38 * callbacks from the {@link Connection.VideoProvider} to {@link InCallService.VideoCall}
39 * implementations.
40 *
41 * Also provides a means for Telecom to send and receive these messages.
42 */
43public class VideoProviderProxy extends Connection.VideoProvider {
44
45 /**
46 * Listener for Telecom components interested in callbacks from the video provider.
47 */
48 interface Listener {
49 void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile);
50 }
51
52 /**
53 * Set of listeners on this VideoProviderProxy.
54 *
55 * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
56 * load factor before resizing, 1 means we only expect a single thread to
57 * access the map so make only a single shard
58 */
59 private final Set<Listener> mListeners = Collections.newSetFromMap(
60 new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1));
61
62 /** The TelecomSystem SyncRoot used for synchronized operations. */
63 private final TelecomSystem.SyncRoot mLock;
64
65 /**
66 * The {@link android.telecom.Connection.VideoProvider} implementation residing with the
67 * {@link android.telecom.ConnectionService} which is being wrapped by this
68 * {@link VideoProviderProxy}.
69 */
70 private final IVideoProvider mConectionServiceVideoProvider;
71
72 /**
73 * Binder used to bind to the {@link android.telecom.ConnectionService}'s
74 * {@link com.android.internal.telecom.IVideoCallback}.
75 */
76 private final VideoCallListenerBinder mVideoCallListenerBinder;
77
78 /**
79 * The Telecom {@link Call} this {@link VideoProviderProxy} is associated with.
80 */
81 private Call mCall;
82
83 private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
84 @Override
85 public void binderDied() {
86 mConectionServiceVideoProvider.asBinder().unlinkToDeath(this, 0);
87 }
88 };
89
90 /**
91 * Creates a new instance of the {@link VideoProviderProxy}, binding it to the passed in
92 * {@code videoProvider} residing with the {@link android.telecom.ConnectionService}.
93 *
94 *
95 * @param lock
96 * @param videoProvider The {@link android.telecom.ConnectionService}'s video provider.
97 * @param call The current call.
98 * @throws RemoteException Remote exception.
99 */
100 VideoProviderProxy(TelecomSystem.SyncRoot lock,
101 IVideoProvider videoProvider, Call call) throws RemoteException {
102
103 super(Looper.getMainLooper());
104
105 mLock = lock;
106
107 mConectionServiceVideoProvider = videoProvider;
108 mConectionServiceVideoProvider.asBinder().linkToDeath(mDeathRecipient, 0);
109
110 mVideoCallListenerBinder = new VideoCallListenerBinder();
111 mConectionServiceVideoProvider.addVideoCallback(mVideoCallListenerBinder);
112 mCall = call;
113 }
114
115 /**
116 * IVideoCallback stub implementation. An instance of this class receives callbacks from the
117 * {@code ConnectionService}'s video provider.
118 */
119 private final class VideoCallListenerBinder extends IVideoCallback.Stub {
120 /**
121 * Proxies a request from the {@link #mConectionServiceVideoProvider} to the
122 * {@link InCallService} when a session modification request is received.
123 *
124 * @param videoProfile The requested video profile.
125 */
126 @Override
127 public void receiveSessionModifyRequest(VideoProfile videoProfile) {
Brad Ebinger3165d502015-12-15 17:22:29 -0800128 try {
129 Log.startSession("VPP.rSMR");
130 synchronized (mLock) {
131 logFromVideoProvider("receiveSessionModifyRequest: " + videoProfile);
Tyler Gunn70d6f852016-06-21 10:22:06 -0700132 Log.event(mCall, Log.Events.RECEIVE_VIDEO_REQUEST,
133 VideoProfile.videoStateToString(videoProfile.getVideoState()));
Tyler Gunn86014fc2015-06-12 14:31:25 -0700134
Hall Liu4640c4f2016-06-22 17:13:20 -0700135 mCall.getAnalytics().addVideoEvent(
136 Analytics.RECEIVE_REMOTE_SESSION_MODIFY_REQUEST,
137 videoProfile.getVideoState());
Brad Ebinger3165d502015-12-15 17:22:29 -0800138 // Inform other Telecom components of the session modification request.
139 for (Listener listener : mListeners) {
140 listener.onSessionModifyRequestReceived(mCall, videoProfile);
141 }
142
143 VideoProviderProxy.this.receiveSessionModifyRequest(videoProfile);
Tyler Gunn86014fc2015-06-12 14:31:25 -0700144 }
Brad Ebinger3165d502015-12-15 17:22:29 -0800145 } finally {
146 Log.endSession();
Tyler Gunn86014fc2015-06-12 14:31:25 -0700147 }
148 }
149
150 /**
151 * Proxies a request from the {@link #mConectionServiceVideoProvider} to the
152 * {@link InCallService} when a session modification response is received.
153 *
154 * @param status The status of the response.
155 * @param requestProfile The requested video profile.
156 * @param responseProfile The response video profile.
157 */
158 @Override
159 public void receiveSessionModifyResponse(int status, VideoProfile requestProfile,
160 VideoProfile responseProfile) {
Brad Ebinger10f8cd22016-07-13 16:06:56 -0700161 logFromVideoProvider("receiveSessionModifyResponse: status=" + status +
162 " requestProfile=" + requestProfile + " responseProfile=" + responseProfile);
163 String eventMessage = "Status Code : " + status + " Video State: " +
164 (responseProfile != null ? responseProfile.getVideoState() : "null");
165 Log.event(mCall, Log.Events.RECEIVE_VIDEO_RESPONSE, eventMessage);
Tyler Gunn86014fc2015-06-12 14:31:25 -0700166 synchronized (mLock) {
Brad Ebinger10f8cd22016-07-13 16:06:56 -0700167 if (status == Connection.VideoProvider.SESSION_MODIFY_REQUEST_SUCCESS) {
168 mCall.getAnalytics().addVideoEvent(
169 Analytics.RECEIVE_REMOTE_SESSION_MODIFY_RESPONSE,
170 requestProfile.getVideoState());
171 }
Tyler Gunn86014fc2015-06-12 14:31:25 -0700172 VideoProviderProxy.this.receiveSessionModifyResponse(status, requestProfile,
173 responseProfile);
174 }
175 }
176
177 /**
178 * Proxies a request from the {@link #mConectionServiceVideoProvider} to the
179 * {@link InCallService} when a call session event occurs.
180 *
181 * @param event The call session event.
182 */
183 @Override
184 public void handleCallSessionEvent(int event) {
185 synchronized (mLock) {
186 logFromVideoProvider("handleCallSessionEvent: " + event);
187 VideoProviderProxy.this.handleCallSessionEvent(event);
188 }
189 }
190
191 /**
192 * Proxies a request from the {@link #mConectionServiceVideoProvider} to the
193 * {@link InCallService} when the peer dimensions change.
194 *
195 * @param width The width of the peer's video.
196 * @param height The height of the peer's video.
197 */
198 @Override
199 public void changePeerDimensions(int width, int height) {
200 synchronized (mLock) {
201 logFromVideoProvider("changePeerDimensions: width=" + width + " height=" +
202 height);
203 VideoProviderProxy.this.changePeerDimensions(width, height);
204 }
205 }
206
207 /**
208 * Proxies a request from the {@link #mConectionServiceVideoProvider} to the
209 * {@link InCallService} when the video quality changes.
210 *
211 * @param videoQuality The video quality.
212 */
213 @Override
214 public void changeVideoQuality(int videoQuality) {
215 synchronized (mLock) {
216 logFromVideoProvider("changeVideoQuality: " + videoQuality);
217 VideoProviderProxy.this.changeVideoQuality(videoQuality);
218 }
219 }
220
221 /**
222 * Proxies a request from the {@link #mConectionServiceVideoProvider} to the
223 * {@link InCallService} when the call data usage changes.
224 *
Tyler Gunn7a1f8232015-12-03 19:52:59 -0800225 * Also tracks the current call data usage on the {@link Call} for use when writing to the
226 * call log.
227 *
Tyler Gunn86014fc2015-06-12 14:31:25 -0700228 * @param dataUsage The data usage.
229 */
230 @Override
231 public void changeCallDataUsage(long dataUsage) {
232 synchronized (mLock) {
233 logFromVideoProvider("changeCallDataUsage: " + dataUsage);
234 VideoProviderProxy.this.setCallDataUsage(dataUsage);
Tyler Gunn7a1f8232015-12-03 19:52:59 -0800235 mCall.setCallDataUsage(dataUsage);
Tyler Gunn86014fc2015-06-12 14:31:25 -0700236 }
237 }
238
239 /**
240 * Proxies a request from the {@link #mConectionServiceVideoProvider} to the
241 * {@link InCallService} when the camera capabilities change.
242 *
243 * @param cameraCapabilities The camera capabilities.
244 */
245 @Override
246 public void changeCameraCapabilities(VideoProfile.CameraCapabilities cameraCapabilities) {
247 synchronized (mLock) {
248 logFromVideoProvider("changeCameraCapabilities: " + cameraCapabilities);
249 VideoProviderProxy.this.changeCameraCapabilities(cameraCapabilities);
250 }
251 }
252 }
253
254 /**
255 * Proxies a request from the {@link InCallService} to the
256 * {@link #mConectionServiceVideoProvider} to change the camera.
257 *
258 * @param cameraId The id of the camera.
259 */
260 @Override
261 public void onSetCamera(String cameraId) {
262 synchronized (mLock) {
263 logFromInCall("setCamera: " + cameraId);
264 try {
265 mConectionServiceVideoProvider.setCamera(cameraId);
266 } catch (RemoteException e) {
267 }
268 }
269 }
270
271 /**
272 * Proxies a request from the {@link InCallService} to the
273 * {@link #mConectionServiceVideoProvider} to set the preview surface.
274 *
275 * @param surface The surface.
276 */
277 @Override
278 public void onSetPreviewSurface(Surface surface) {
279 synchronized (mLock) {
280 logFromInCall("setPreviewSurface");
281 try {
282 mConectionServiceVideoProvider.setPreviewSurface(surface);
283 } catch (RemoteException e) {
284 }
285 }
286 }
287
288 /**
289 * Proxies a request from the {@link InCallService} to the
290 * {@link #mConectionServiceVideoProvider} to change the display surface.
291 *
292 * @param surface The surface.
293 */
294 @Override
295 public void onSetDisplaySurface(Surface surface) {
296 synchronized (mLock) {
297 logFromInCall("setDisplaySurface");
298 try {
299 mConectionServiceVideoProvider.setDisplaySurface(surface);
300 } catch (RemoteException e) {
301 }
302 }
303 }
304
305 /**
306 * Proxies a request from the {@link InCallService} to the
307 * {@link #mConectionServiceVideoProvider} to change the device orientation.
308 *
309 * @param rotation The device orientation, in degrees.
310 */
311 @Override
312 public void onSetDeviceOrientation(int rotation) {
313 synchronized (mLock) {
314 logFromInCall("setDeviceOrientation: " + rotation);
315 try {
316 mConectionServiceVideoProvider.setDeviceOrientation(rotation);
317 } catch (RemoteException e) {
318 }
319 }
320 }
321
322 /**
323 * Proxies a request from the {@link InCallService} to the
324 * {@link #mConectionServiceVideoProvider} to change the camera zoom ratio.
325 *
326 * @param value The camera zoom ratio.
327 */
328 @Override
329 public void onSetZoom(float value) {
330 synchronized (mLock) {
331 logFromInCall("setZoom: " + value);
332 try {
333 mConectionServiceVideoProvider.setZoom(value);
334 } catch (RemoteException e) {
335 }
336 }
337 }
338
339 /**
340 * Proxies a request from the {@link InCallService} to the
341 * {@link #mConectionServiceVideoProvider} to provide a response to a session modification
342 * request.
343 *
344 * @param fromProfile The video properties prior to the request.
345 * @param toProfile The video properties with the requested changes made.
346 */
347 @Override
348 public void onSendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile) {
349 synchronized (mLock) {
350 logFromInCall("sendSessionModifyRequest: from=" + fromProfile + " to=" + toProfile);
Tyler Gunn70d6f852016-06-21 10:22:06 -0700351 Log.event(mCall, Log.Events.SEND_VIDEO_REQUEST,
352 VideoProfile.videoStateToString(toProfile.getVideoState()));
Hall Liu4640c4f2016-06-22 17:13:20 -0700353 mCall.getAnalytics().addVideoEvent(
354 Analytics.SEND_LOCAL_SESSION_MODIFY_REQUEST,
355 toProfile.getVideoState());
Tyler Gunn86014fc2015-06-12 14:31:25 -0700356 try {
357 mConectionServiceVideoProvider.sendSessionModifyRequest(fromProfile, toProfile);
358 } catch (RemoteException e) {
359 }
360 }
361 }
362
363 /**
364 * Proxies a request from the {@link InCallService} to the
365 * {@link #mConectionServiceVideoProvider} to send a session modification request.
366 *
367 * @param responseProfile The response connection video properties.
368 */
369 @Override
370 public void onSendSessionModifyResponse(VideoProfile responseProfile) {
371 synchronized (mLock) {
372 logFromInCall("sendSessionModifyResponse: " + responseProfile);
Tyler Gunn70d6f852016-06-21 10:22:06 -0700373 Log.event(mCall, Log.Events.SEND_VIDEO_RESPONSE,
374 VideoProfile.videoStateToString(responseProfile.getVideoState()));
Hall Liu4640c4f2016-06-22 17:13:20 -0700375 mCall.getAnalytics().addVideoEvent(
376 Analytics.SEND_LOCAL_SESSION_MODIFY_RESPONSE,
377 responseProfile.getVideoState());
Tyler Gunn86014fc2015-06-12 14:31:25 -0700378 try {
379 mConectionServiceVideoProvider.sendSessionModifyResponse(responseProfile);
380 } catch (RemoteException e) {
381 }
382 }
383 }
384
385 /**
386 * Proxies a request from the {@link InCallService} to the
387 * {@link #mConectionServiceVideoProvider} to request the camera capabilities.
388 */
389 @Override
390 public void onRequestCameraCapabilities() {
391 synchronized (mLock) {
392 logFromInCall("requestCameraCapabilities");
393 try {
394 mConectionServiceVideoProvider.requestCameraCapabilities();
395 } catch (RemoteException e) {
396 }
397 }
398 }
399
400 /**
401 * Proxies a request from the {@link InCallService} to the
402 * {@link #mConectionServiceVideoProvider} to request the connection data usage.
403 */
404 @Override
405 public void onRequestConnectionDataUsage() {
406 synchronized (mLock) {
407 logFromInCall("requestCallDataUsage");
408 try {
409 mConectionServiceVideoProvider.requestCallDataUsage();
410 } catch (RemoteException e) {
411 }
412 }
413 }
414
415 /**
416 * Proxies a request from the {@link InCallService} to the
417 * {@link #mConectionServiceVideoProvider} to set the pause image.
418 *
419 * @param uri URI of image to display.
420 */
421 @Override
422 public void onSetPauseImage(Uri uri) {
423 synchronized (mLock) {
424 logFromInCall("setPauseImage: " + uri);
425 try {
426 mConectionServiceVideoProvider.setPauseImage(uri);
427 } catch (RemoteException e) {
428 }
429 }
430 }
431
432 /**
433 * Add a listener to this {@link VideoProviderProxy}.
434 *
435 * @param listener The listener.
436 */
437 public void addListener(Listener listener) {
438 mListeners.add(listener);
439 }
440
441 /**
442 * Remove a listener from this {@link VideoProviderProxy}.
443 *
444 * @param listener The listener.
445 */
446 public void removeListener(Listener listener) {
447 if (listener != null) {
448 mListeners.remove(listener);
449 }
450 }
451
452 /**
453 * Logs a message originating from the {@link InCallService}.
454 *
455 * @param toLog The message to log.
456 */
457 private void logFromInCall(String toLog) {
458 Log.v(this, "IC->VP: " + toLog);
459 }
460
461 /**
462 * Logs a message originating from the {@link android.telecom.ConnectionService}'s
463 * {@link Connection.VideoProvider}.
464 *
465 * @param toLog The message to log.
466 */
467 private void logFromVideoProvider(String toLog) {
468 Log.v(this, "VP->IC: " + toLog);
469 }
470}