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 com.android.incallui;
18 
19 import com.google.common.base.Preconditions;
20 
21 import java.util.Collections;
22 import java.util.Set;
23 import java.util.concurrent.ConcurrentHashMap;
24 
25 /**
26  * Class used by {@link InCallService.VideoCallCallback} to notify interested parties of incoming
27  * events.
28  */
29 public class InCallVideoCallCallbackNotifier {
30     /**
31      * Singleton instance of this class.
32      */
33     private static InCallVideoCallCallbackNotifier sInstance =
34             new InCallVideoCallCallbackNotifier();
35 
36     /**
37      * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
38      * load factor before resizing, 1 means we only expect a single thread to
39      * access the map so make only a single shard
40      */
41     private final Set<SessionModificationListener> mSessionModificationListeners =
42             Collections.newSetFromMap(new ConcurrentHashMap<SessionModificationListener, Boolean>
43                     (8, 0.9f, 1));
44     private final Set<VideoEventListener> mVideoEventListeners = Collections.newSetFromMap(
45             new ConcurrentHashMap<VideoEventListener, Boolean>(8, 0.9f, 1));
46     private final Set<SurfaceChangeListener> mSurfaceChangeListeners = Collections.newSetFromMap(
47             new ConcurrentHashMap<SurfaceChangeListener, Boolean>(8, 0.9f, 1));
48 
49     /**
50      * Static singleton accessor method.
51      */
getInstance()52     public static InCallVideoCallCallbackNotifier getInstance() {
53         return sInstance;
54     }
55 
56     /**
57      * Private constructor.  Instance should only be acquired through getInstance().
58      */
InCallVideoCallCallbackNotifier()59     private InCallVideoCallCallbackNotifier() {
60     }
61 
62     /**
63      * Adds a new {@link SessionModificationListener}.
64      *
65      * @param listener The listener.
66      */
addSessionModificationListener(SessionModificationListener listener)67     public void addSessionModificationListener(SessionModificationListener listener) {
68         Preconditions.checkNotNull(listener);
69         mSessionModificationListeners.add(listener);
70     }
71 
72     /**
73      * Remove a {@link SessionModificationListener}.
74      *
75      * @param listener The listener.
76      */
removeSessionModificationListener(SessionModificationListener listener)77     public void removeSessionModificationListener(SessionModificationListener listener) {
78         if (listener != null) {
79             mSessionModificationListeners.remove(listener);
80         }
81     }
82 
83     /**
84      * Adds a new {@link VideoEventListener}.
85      *
86      * @param listener The listener.
87      */
addVideoEventListener(VideoEventListener listener)88     public void addVideoEventListener(VideoEventListener listener) {
89         Preconditions.checkNotNull(listener);
90         mVideoEventListeners.add(listener);
91     }
92 
93     /**
94      * Remove a {@link VideoEventListener}.
95      *
96      * @param listener The listener.
97      */
removeVideoEventListener(VideoEventListener listener)98     public void removeVideoEventListener(VideoEventListener listener) {
99         if (listener != null) {
100             mVideoEventListeners.remove(listener);
101         }
102     }
103 
104     /**
105      * Adds a new {@link SurfaceChangeListener}.
106      *
107      * @param listener The listener.
108      */
addSurfaceChangeListener(SurfaceChangeListener listener)109     public void addSurfaceChangeListener(SurfaceChangeListener listener) {
110         Preconditions.checkNotNull(listener);
111         mSurfaceChangeListeners.add(listener);
112     }
113 
114     /**
115      * Remove a {@link SurfaceChangeListener}.
116      *
117      * @param listener The listener.
118      */
removeSurfaceChangeListener(SurfaceChangeListener listener)119     public void removeSurfaceChangeListener(SurfaceChangeListener listener) {
120         if (listener != null) {
121             mSurfaceChangeListeners.remove(listener);
122         }
123     }
124 
125     /**
126      * Inform listeners of an upgrade to video request for a call.
127      * @param call The call.
128      * @param videoState The video state we want to upgrade to.
129      */
upgradeToVideoRequest(Call call, int videoState)130     public void upgradeToVideoRequest(Call call, int videoState) {
131         Log.d(this, "upgradeToVideoRequest call = " + call + " new video state = " + videoState);
132         for (SessionModificationListener listener : mSessionModificationListeners) {
133             listener.onUpgradeToVideoRequest(call, videoState);
134         }
135     }
136 
137     /**
138      * Inform listeners of a call session event.
139      *
140      * @param event The call session event.
141      */
callSessionEvent(int event)142     public void callSessionEvent(int event) {
143         for (VideoEventListener listener : mVideoEventListeners) {
144             listener.onCallSessionEvent(event);
145         }
146     }
147 
148     /**
149      * Inform listeners of a downgrade to audio.
150      *
151      * @param call The call.
152      * @param paused The paused state.
153      */
peerPausedStateChanged(Call call, boolean paused)154     public void peerPausedStateChanged(Call call, boolean paused) {
155         for (VideoEventListener listener : mVideoEventListeners) {
156             listener.onPeerPauseStateChanged(call, paused);
157         }
158     }
159 
160     /**
161      * Inform listeners of any change in the video quality of the call
162      *
163      * @param call The call.
164      * @param videoQuality The updated video quality of the call.
165      */
videoQualityChanged(Call call, int videoQuality)166     public void videoQualityChanged(Call call, int videoQuality) {
167         for (VideoEventListener listener : mVideoEventListeners) {
168             listener.onVideoQualityChanged(call, videoQuality);
169         }
170     }
171 
172     /**
173      * Inform listeners of a change to peer dimensions.
174      *
175      * @param call The call.
176      * @param width New peer width.
177      * @param height New peer height.
178      */
peerDimensionsChanged(Call call, int width, int height)179     public void peerDimensionsChanged(Call call, int width, int height) {
180         for (SurfaceChangeListener listener : mSurfaceChangeListeners) {
181             listener.onUpdatePeerDimensions(call, width, height);
182         }
183     }
184 
185     /**
186      * Inform listeners of a change to camera dimensions.
187      *
188      * @param call The call.
189      * @param width The new camera video width.
190      * @param height The new camera video height.
191      */
cameraDimensionsChanged(Call call, int width, int height)192     public void cameraDimensionsChanged(Call call, int width, int height) {
193         for (SurfaceChangeListener listener : mSurfaceChangeListeners) {
194             listener.onCameraDimensionsChange(call, width, height);
195         }
196     }
197 
198     /**
199      * Inform listeners of a change to call data usage.
200      *
201      * @param dataUsage data usage value
202      */
callDataUsageChanged(long dataUsage)203     public void callDataUsageChanged(long dataUsage) {
204         for (VideoEventListener listener : mVideoEventListeners) {
205             listener.onCallDataUsageChange(dataUsage);
206         }
207     }
208 
209     /**
210      * Listener interface for any class that wants to be notified of upgrade to video request.
211      */
212     public interface SessionModificationListener {
213         /**
214          * Called when a peer request is received to upgrade an audio-only call to a video call.
215          *
216          * @param call The call the request was received for.
217          * @param videoState The requested video state.
218          */
onUpgradeToVideoRequest(Call call, int videoState)219         public void onUpgradeToVideoRequest(Call call, int videoState);
220     }
221 
222     /**
223      * Listener interface for any class that wants to be notified of video events, including pause
224      * and un-pause of peer video, video quality changes.
225      */
226     public interface VideoEventListener {
227         /**
228          * Called when the peer pauses or un-pauses video transmission.
229          *
230          * @param call   The call which paused or un-paused video transmission.
231          * @param paused {@code True} when the video transmission is paused, {@code false}
232          *               otherwise.
233          */
onPeerPauseStateChanged(Call call, boolean paused)234         public void onPeerPauseStateChanged(Call call, boolean paused);
235 
236         /**
237          * Called when the video quality changes.
238          *
239          * @param call   The call whose video quality changes.
240          * @param videoCallQuality - values are QUALITY_HIGH, MEDIUM, LOW and UNKNOWN.
241          */
onVideoQualityChanged(Call call, int videoCallQuality)242         public void onVideoQualityChanged(Call call, int videoCallQuality);
243 
244         /*
245          * Called when call data usage value is requested or when call data usage value is updated
246          * because of a call state change
247          *
248          * @param dataUsage call data usage value
249          */
onCallDataUsageChange(long dataUsage)250         public void onCallDataUsageChange(long dataUsage);
251 
252         /**
253          * Called when call session event is raised.
254          *
255          * @param event The call session event.
256          */
onCallSessionEvent(int event)257         public void onCallSessionEvent(int event);
258     }
259 
260     /**
261      * Listener interface for any class that wants to be notified of changes to the video surfaces.
262      */
263     public interface SurfaceChangeListener {
264         /**
265          * Called when the peer video feed changes dimensions. This can occur when the peer rotates
266          * their device, changing the aspect ratio of the video signal.
267          *
268          * @param call The call which experienced a peer video
269          * @param width
270          * @param height
271          */
onUpdatePeerDimensions(Call call, int width, int height)272         public void onUpdatePeerDimensions(Call call, int width, int height);
273 
274         /**
275          * Called when the local camera changes dimensions.  This occurs when a change in camera
276          * occurs.
277          *
278          * @param call The call which experienced the camera dimension change.
279          * @param width The new camera video width.
280          * @param height The new camera video height.
281          */
onCameraDimensionsChange(Call call, int width, int height)282         public void onCameraDimensionsChange(Call call, int width, int height);
283     }
284 }
285