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