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