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.media;
18 
19 import android.os.Handler;
20 import android.os.Looper;
21 import android.os.Message;
22 import java.util.ArrayList;
23 import java.lang.ref.WeakReference;
24 
25 /**
26  * The AudioPortEventHandler handles AudioManager.OnAudioPortUpdateListener callbacks
27  * posted from JNI
28  * @hide
29  */
30 
31 class AudioPortEventHandler {
32     private Handler mHandler;
33     private final ArrayList<AudioManager.OnAudioPortUpdateListener> mListeners =
34             new ArrayList<AudioManager.OnAudioPortUpdateListener>();
35 
36     private static final String TAG = "AudioPortEventHandler";
37 
38     private static final int AUDIOPORT_EVENT_PORT_LIST_UPDATED = 1;
39     private static final int AUDIOPORT_EVENT_PATCH_LIST_UPDATED = 2;
40     private static final int AUDIOPORT_EVENT_SERVICE_DIED = 3;
41     private static final int AUDIOPORT_EVENT_NEW_LISTENER = 4;
42 
43     /**
44      * Accessed by native methods: JNI Callback context.
45      */
46     @SuppressWarnings("unused")
47     private long mJniCallback;
48 
init()49     void init() {
50         synchronized (this) {
51             if (mHandler != null) {
52                 return;
53             }
54             // find the looper for our new event handler
55             Looper looper = Looper.getMainLooper();
56 
57             if (looper != null) {
58                 mHandler = new Handler(looper) {
59                     @Override
60                     public void handleMessage(Message msg) {
61                         ArrayList<AudioManager.OnAudioPortUpdateListener> listeners;
62                         synchronized (this) {
63                             if (msg.what == AUDIOPORT_EVENT_NEW_LISTENER) {
64                                 listeners = new ArrayList<AudioManager.OnAudioPortUpdateListener>();
65                                 if (mListeners.contains(msg.obj)) {
66                                     listeners.add((AudioManager.OnAudioPortUpdateListener)msg.obj);
67                                 }
68                             } else {
69                                 listeners = mListeners;
70                             }
71                         }
72                         // reset audio port cache if the event corresponds to a change coming
73                         // from audio policy service or if mediaserver process died.
74                         if (msg.what == AUDIOPORT_EVENT_PORT_LIST_UPDATED ||
75                                 msg.what == AUDIOPORT_EVENT_PATCH_LIST_UPDATED ||
76                                 msg.what == AUDIOPORT_EVENT_SERVICE_DIED) {
77                             AudioManager.resetAudioPortGeneration();
78                         }
79 
80                         if (listeners.isEmpty()) {
81                             return;
82                         }
83 
84                         ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
85                         ArrayList<AudioPatch> patches = new ArrayList<AudioPatch>();
86                         if (msg.what != AUDIOPORT_EVENT_SERVICE_DIED) {
87                             int status = AudioManager.updateAudioPortCache(ports, patches, null);
88                             if (status != AudioManager.SUCCESS) {
89                                 return;
90                             }
91                         }
92 
93                         switch (msg.what) {
94                         case AUDIOPORT_EVENT_NEW_LISTENER:
95                         case AUDIOPORT_EVENT_PORT_LIST_UPDATED:
96                             AudioPort[] portList = ports.toArray(new AudioPort[0]);
97                             for (int i = 0; i < listeners.size(); i++) {
98                                 listeners.get(i).onAudioPortListUpdate(portList);
99                             }
100                             if (msg.what == AUDIOPORT_EVENT_PORT_LIST_UPDATED) {
101                                 break;
102                             }
103                             // FALL THROUGH
104 
105                         case AUDIOPORT_EVENT_PATCH_LIST_UPDATED:
106                             AudioPatch[] patchList = patches.toArray(new AudioPatch[0]);
107                             for (int i = 0; i < listeners.size(); i++) {
108                                 listeners.get(i).onAudioPatchListUpdate(patchList);
109                             }
110                             break;
111 
112                         case AUDIOPORT_EVENT_SERVICE_DIED:
113                             for (int i = 0; i < listeners.size(); i++) {
114                                 listeners.get(i).onServiceDied();
115                             }
116                             break;
117 
118                         default:
119                             break;
120                         }
121                     }
122                 };
123                 native_setup(new WeakReference<AudioPortEventHandler>(this));
124             } else {
125                 mHandler = null;
126             }
127         }
128     }
129 
native_setup(Object module_this)130     private native void native_setup(Object module_this);
131 
132     @Override
finalize()133     protected void finalize() {
134         native_finalize();
135     }
native_finalize()136     private native void native_finalize();
137 
registerListener(AudioManager.OnAudioPortUpdateListener l)138     void registerListener(AudioManager.OnAudioPortUpdateListener l) {
139         synchronized (this) {
140             mListeners.add(l);
141         }
142         if (mHandler != null) {
143             Message m = mHandler.obtainMessage(AUDIOPORT_EVENT_NEW_LISTENER, 0, 0, l);
144             mHandler.sendMessage(m);
145         }
146     }
147 
unregisterListener(AudioManager.OnAudioPortUpdateListener l)148     void unregisterListener(AudioManager.OnAudioPortUpdateListener l) {
149         synchronized (this) {
150             mListeners.remove(l);
151         }
152     }
153 
handler()154     Handler handler() {
155         return mHandler;
156     }
157 
158     @SuppressWarnings("unused")
postEventFromNative(Object module_ref, int what, int arg1, int arg2, Object obj)159     private static void postEventFromNative(Object module_ref,
160                                             int what, int arg1, int arg2, Object obj) {
161         AudioPortEventHandler eventHandler =
162                 (AudioPortEventHandler)((WeakReference)module_ref).get();
163         if (eventHandler == null) {
164             return;
165         }
166 
167         if (eventHandler != null) {
168             Handler handler = eventHandler.handler();
169             if (handler != null) {
170                 Message m = handler.obtainMessage(what, arg1, arg2, obj);
171                 handler.sendMessage(m);
172             }
173         }
174     }
175 
176 }
177