AudioService.java revision da996f390e17e16f2dfa60e972e7ebc4f868f37e
1/*
2 * Copyright (C) 2006 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.media;
18
19import android.app.ActivityManagerNative;
20import android.content.ContentResolver;
21import android.content.Context;
22import android.content.Intent;
23import android.content.pm.PackageManager;
24import android.media.MediaPlayer.OnCompletionListener;
25import android.media.MediaPlayer.OnErrorListener;
26import android.os.Binder;
27import android.os.Environment;
28import android.os.Handler;
29import android.os.IBinder;
30import android.os.Looper;
31import android.os.Message;
32import android.os.RemoteException;
33import android.os.ServiceManager;
34import android.provider.Settings;
35import android.provider.Settings.System;
36import android.util.Log;
37import android.view.VolumePanel;
38
39import com.android.internal.telephony.ITelephony;
40
41import java.io.IOException;
42import java.util.ArrayList;
43
44
45/**
46 * The implementation of the volume manager service.
47 * <p>
48 * This implementation focuses on delivering a responsive UI. Most methods are
49 * asynchronous to external calls. For example, the task of setting a volume
50 * will update our internal state, but in a separate thread will set the system
51 * volume and later persist to the database. Similarly, setting the ringer mode
52 * will update the state and broadcast a change and in a separate thread later
53 * persist the ringer mode.
54 *
55 * @hide
56 */
57public class AudioService extends IAudioService.Stub {
58
59    private static final String TAG = "AudioService";
60
61    /** How long to delay before persisting a change in volume/ringer mode. */
62    private static final int PERSIST_DELAY = 3000;
63
64    private Context mContext;
65    private ContentResolver mContentResolver;
66
67    /** The UI */
68    private VolumePanel mVolumePanel;
69
70    // sendMsg() flags
71    /** Used when a message should be shared across all stream types. */
72    private static final int SHARED_MSG = -1;
73    /** If the msg is already queued, replace it with this one. */
74    private static final int SENDMSG_REPLACE = 0;
75    /** If the msg is already queued, ignore this one and leave the old. */
76    private static final int SENDMSG_NOOP = 1;
77    /** If the msg is already queued, queue this one and leave the old. */
78    private static final int SENDMSG_QUEUE = 2;
79
80    // AudioHandler message.whats
81    private static final int MSG_SET_SYSTEM_VOLUME = 0;
82    private static final int MSG_PERSIST_VOLUME = 1;
83    private static final int MSG_PERSIST_RINGER_MODE = 3;
84    private static final int MSG_PERSIST_VIBRATE_SETTING = 4;
85    private static final int MSG_MEDIA_SERVER_DIED = 5;
86    private static final int MSG_MEDIA_SERVER_STARTED = 6;
87    private static final int MSG_PLAY_SOUND_EFFECT = 7;
88
89    /** @see AudioSystemThread */
90    private AudioSystemThread mAudioSystemThread;
91    /** @see AudioHandler */
92    private AudioHandler mAudioHandler;
93    /** @see VolumeStreamState */
94    private VolumeStreamState[] mStreamStates;
95
96    private boolean mMicMute;
97    private int mMode;
98    private int[] mRoutes = new int[AudioSystem.NUM_MODES];
99    private Object mSettingsLock = new Object();
100    private boolean mMediaServerOk;
101
102    private SoundPool mSoundPool;
103    private Object mSoundEffectsLock = new Object();
104    private static final int NUM_SOUNDPOOL_CHANNELS = 4;
105    private static final float SOUND_EFFECT_VOLUME = 1.0f;
106
107    /* Sound effect file names  */
108    private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
109    private static final String[] SOUND_EFFECT_FILES = new String[] {
110        "Effect_Tick.ogg"
111    };
112
113    /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
114     * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
115     * uses soundpool (second column) */
116    private int[][] SOUND_EFFECT_FILES_MAP = new int[][] {
117        {0, -1},  // FX_KEY_CLICK
118        {0, -1},  // FX_FOCUS_NAVIGATION_UP
119        {0, -1},  // FX_FOCUS_NAVIGATION_DOWN
120        {0, -1},  // FX_FOCUS_NAVIGATION_LEFT
121        {0, -1}   // FX_FOCUS_NAVIGATION_RIGHT
122    };
123
124    private AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
125        public void onError(int error) {
126            switch (error) {
127            case AudioSystem.AUDIO_STATUS_SERVER_DIED:
128                if (mMediaServerOk) {
129                    sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SHARED_MSG, SENDMSG_NOOP, 0, 0,
130                            null, 1500);
131                }
132                break;
133            case AudioSystem.AUDIO_STATUS_OK:
134                if (!mMediaServerOk) {
135                    sendMsg(mAudioHandler, MSG_MEDIA_SERVER_STARTED, SHARED_MSG, SENDMSG_NOOP, 0, 0,
136                            null, 0);
137                }
138                break;
139            default:
140                break;
141            }
142       }
143    };
144
145    /**
146     * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
147     * {@link AudioManager#RINGER_MODE_SILENT}, or
148     * {@link AudioManager#RINGER_MODE_VIBRATE}.
149     */
150    private int mRingerMode;
151
152    /** @see System#MODE_RINGER_STREAMS_AFFECTED */
153    private int mRingerModeAffectedStreams;
154
155    /** @see System#MUTE_STREAMS_AFFECTED */
156    private int mMuteAffectedStreams;
157
158    /**
159     * Has multiple bits per vibrate type to indicate the type's vibrate
160     * setting. See {@link #setVibrateSetting(int, int)}.
161     * <p>
162     * NOTE: This is not the final decision of whether vibrate is on/off for the
163     * type since it depends on the ringer mode. See {@link #shouldVibrate(int)}.
164     */
165    private int mVibrateSetting;
166
167    ///////////////////////////////////////////////////////////////////////////
168    // Construction
169    ///////////////////////////////////////////////////////////////////////////
170
171    /** @hide */
172    public AudioService(Context context) {
173        mContext = context;
174        mContentResolver = context.getContentResolver();
175        mVolumePanel = new VolumePanel(context, this);
176
177        createAudioSystemThread();
178        createStreamStates();
179        readPersistedSettings();
180        readAudioSettings();
181        mMediaServerOk = true;
182        AudioSystem.setErrorCallback(mAudioSystemCallback);
183        if (Settings.System.getInt(mContentResolver, Settings.System.SOUND_EFFECTS_ENABLED, 0) == 1) {
184            loadSoundEffects();
185        }
186    }
187
188    private void createAudioSystemThread() {
189        mAudioSystemThread = new AudioSystemThread();
190        mAudioSystemThread.start();
191        waitForAudioHandlerCreation();
192    }
193
194    /** Waits for the volume handler to be created by the other thread. */
195    private void waitForAudioHandlerCreation() {
196        synchronized(this) {
197            while (mAudioHandler == null) {
198                try {
199                    // Wait for mAudioHandler to be set by the other thread
200                    wait();
201                } catch (InterruptedException e) {
202                    Log.e(TAG, "Interrupted while waiting on volume handler.");
203                }
204            }
205        }
206    }
207
208    private void createStreamStates() {
209        final int[] volumeLevelsPhone =
210            createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_VOICE_CALL]);
211        final int[] volumeLevelsCoarse =
212            createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_SYSTEM]);
213        final int[] volumeLevelsFine =
214            createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC]);
215        final int[] volumeLevelsBtPhone =
216            createVolumeLevels(0,
217                    AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_BLUETOOTH_SCO]);
218
219        int numStreamTypes = AudioSystem.getNumStreamTypes();
220        VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
221
222        for (int i = 0; i < numStreamTypes; i++) {
223            final int[] levels;
224
225            switch (i) {
226
227                case AudioSystem.STREAM_MUSIC:
228                    levels = volumeLevelsFine;
229                    break;
230
231                case AudioSystem.STREAM_VOICE_CALL:
232                    levels = volumeLevelsPhone;
233                    break;
234
235                case AudioSystem.STREAM_BLUETOOTH_SCO:
236                    levels = volumeLevelsBtPhone;
237                    break;
238
239                default:
240                    levels = volumeLevelsCoarse;
241                    break;
242            }
243
244            if (i == AudioSystem.STREAM_BLUETOOTH_SCO) {
245                streams[i] = new VolumeStreamState(AudioManager.DEFAULT_STREAM_VOLUME[i], i,levels);
246            } else {
247                streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[i], i, levels);
248            }
249        }
250    }
251
252    private static int[] createVolumeLevels(int offset, int numlevels) {
253        double curve = 1.0f; // 1.4f
254        int [] volumes = new int[numlevels + offset];
255        for (int i = 0; i < offset; i++) {
256            volumes[i] = 0;
257        }
258
259        double val = 0;
260        double max = Math.pow(numlevels - 1, curve);
261        for (int i = 0; i < numlevels; i++) {
262            val = Math.pow(i, curve) / max;
263            volumes[offset + i] = (int) (val * 100.0f);
264        }
265        return volumes;
266    }
267
268    private void readPersistedSettings() {
269        final ContentResolver cr = mContentResolver;
270
271        mRingerMode = System.getInt(cr, System.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
272        mRingerModeAffectedStreams = System.getInt(mContentResolver,
273                System.MODE_RINGER_STREAMS_AFFECTED, 1 << AudioSystem.STREAM_RING);
274
275        mVibrateSetting = System.getInt(cr, System.VIBRATE_ON, 0);
276
277        mMuteAffectedStreams = System.getInt(cr,
278                System.MUTE_STREAMS_AFFECTED,
279                ((1 << AudioSystem.STREAM_MUSIC)|(1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_SYSTEM)));
280
281        // Each stream will read its own persisted settings
282
283        // Broadcast the sticky intent
284        broadcastRingerMode();
285
286        // Broadcast vibrate settings
287        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
288        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
289    }
290
291    private void readAudioSettings() {
292        synchronized (mSettingsLock) {
293            mMicMute = AudioSystem.isMicrophoneMuted();
294            mMode = AudioSystem.getMode();
295            for (int mode = 0; mode < AudioSystem.NUM_MODES; mode++) {
296                mRoutes[mode] = AudioSystem.getRouting(mode);
297            }
298        }
299    }
300
301    private void applyAudioSettings() {
302        synchronized (mSettingsLock) {
303            AudioSystem.muteMicrophone(mMicMute);
304            AudioSystem.setMode(mMode);
305            for (int mode = 0; mode < AudioSystem.NUM_MODES; mode++) {
306                AudioSystem.setRouting(mode, mRoutes[mode], AudioSystem.ROUTE_ALL);
307            }
308        }
309   }
310
311    ///////////////////////////////////////////////////////////////////////////
312    // IPC methods
313    ///////////////////////////////////////////////////////////////////////////
314
315    /** @see AudioManager#adjustVolume(int, int) */
316    public void adjustVolume(int direction, int flags) {
317        adjustSuggestedStreamVolume(direction, AudioManager.USE_DEFAULT_STREAM_TYPE, flags);
318    }
319
320    /** @see AudioManager#adjustVolume(int, int, int) */
321    public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
322
323        int streamType = getActiveStreamType(suggestedStreamType);
324
325        // Don't play sound on other streams
326        if (streamType != AudioSystem.STREAM_RING && (flags & AudioManager.FLAG_PLAY_SOUND) != 0) {
327            flags &= ~AudioManager.FLAG_PLAY_SOUND;
328        }
329
330        adjustStreamVolume(streamType, direction, flags);
331    }
332
333    /** @see AudioManager#adjustStreamVolume(int, int, int) */
334    public void adjustStreamVolume(int streamType, int direction, int flags) {
335        ensureValidDirection(direction);
336        ensureValidStreamType(streamType);
337
338        boolean notificationsUseRingVolume = Settings.System.getInt(mContentResolver,
339                Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1) == 1;
340        if (notificationsUseRingVolume && streamType == AudioManager.STREAM_NOTIFICATION) {
341            // Redirect the volume change to the ring stream
342            streamType = AudioManager.STREAM_RING;
343        }
344
345        VolumeStreamState streamState = mStreamStates[streamType];
346        final int oldIndex = streamState.mIndex;
347        boolean adjustVolume = true;
348
349        // If either the client forces allowing ringer modes for this adjustment,
350        // or the stream type is one that is affected by ringer modes
351        if ((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0
352                || streamType == AudioManager.STREAM_RING) {
353            // Check if the ringer mode changes with this volume adjustment. If
354            // it does, it will handle adjusting the volume, so we won't below
355            adjustVolume = checkForRingerModeChange(oldIndex, direction);
356        }
357
358        if (adjustVolume && streamState.adjustIndex(direction)) {
359
360            boolean alsoUpdateNotificationVolume =  notificationsUseRingVolume &&
361                    streamType == AudioManager.STREAM_RING;
362            if (alsoUpdateNotificationVolume) {
363                mStreamStates[AudioManager.STREAM_NOTIFICATION].adjustIndex(direction);
364            }
365
366            // Post message to set system volume (it in turn will post a message
367            // to persist). Do not change volume if stream is muted.
368            if (streamState.muteCount() == 0) {
369                sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, streamType, SENDMSG_NOOP, 0, 0,
370                        streamState, 0);
371
372                if (alsoUpdateNotificationVolume) {
373                    sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, AudioManager.STREAM_NOTIFICATION,
374                            SENDMSG_NOOP, 0, 0, mStreamStates[AudioManager.STREAM_NOTIFICATION], 0);
375                }
376            }
377        }
378
379        // UI
380        mVolumePanel.postVolumeChanged(streamType, flags);
381        // Broadcast Intent
382        sendVolumeUpdate(streamType);
383    }
384
385    /** @see AudioManager#setStreamVolume(int, int, int) */
386    public void setStreamVolume(int streamType, int index, int flags) {
387        ensureValidStreamType(streamType);
388        syncRingerAndNotificationStreamVolume(streamType, index, false);
389
390        setStreamVolumeInt(streamType, index, false);
391
392        // UI, etc.
393        mVolumePanel.postVolumeChanged(streamType, flags);
394        // Broadcast Intent
395        sendVolumeUpdate(streamType);
396    }
397
398    private void sendVolumeUpdate(int streamType) {
399        Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
400        intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
401        intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, getStreamVolume(streamType));
402
403        // Currently, sending the intent only when the stream is BLUETOOTH_SCO
404        if (streamType == AudioManager.STREAM_BLUETOOTH_SCO) {
405            mContext.sendBroadcast(intent);
406        }
407    }
408
409    /**
410     * Sync the STREAM_RING and STREAM_NOTIFICATION volumes if mandated by the
411     * value in Settings.
412     *
413     * @param streamType Type of the stream
414     * @param index Volume index for the stream
415     * @param force If true, set the volume even if the current and desired
416     * volume as same
417     */
418    private void syncRingerAndNotificationStreamVolume(int streamType, int index, boolean force) {
419        boolean notificationsUseRingVolume = Settings.System.getInt(mContentResolver,
420                Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1) == 1;
421        if (notificationsUseRingVolume) {
422            if (streamType == AudioManager.STREAM_NOTIFICATION) {
423                // Redirect the volume change to the ring stream
424                streamType = AudioManager.STREAM_RING;
425            }
426            if (streamType == AudioManager.STREAM_RING) {
427                // One-off to sync notification volume to ringer volume
428                setStreamVolumeInt(AudioManager.STREAM_NOTIFICATION, index, force);
429            }
430        }
431    }
432
433
434    /**
435     * Sets the stream state's index, and posts a message to set system volume.
436     * This will not call out to the UI. Assumes a valid stream type.
437     *
438     * @param streamType Type of the stream
439     * @param index Desired volume index of the stream
440     * @param force If true, set the volume even if the desired volume is same
441     * as the current volume.
442     */
443    private void setStreamVolumeInt(int streamType, int index, boolean force) {
444        VolumeStreamState streamState = mStreamStates[streamType];
445        if (streamState.setIndex(index) || force) {
446            // Post message to set system volume (it in turn will post a message
447            // to persist). Do not change volume if stream is muted.
448            if (streamState.muteCount() == 0) {
449                sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, streamType, SENDMSG_NOOP, 0, 0,
450                        streamState, 0);
451            }
452        }
453    }
454
455    /** @see AudioManager#setStreamSolo(int, boolean) */
456    public void setStreamSolo(int streamType, boolean state, IBinder cb) {
457        for (int stream = 0; stream < mStreamStates.length; stream++) {
458            if (!isStreamAffectedByMute(stream) || stream == streamType) continue;
459            // Bring back last audible volume
460            mStreamStates[stream].mute(cb, state);
461         }
462    }
463
464    /** @see AudioManager#setStreamMute(int, boolean) */
465    public void setStreamMute(int streamType, boolean state, IBinder cb) {
466        if (isStreamAffectedByMute(streamType)) {
467            mStreamStates[streamType].mute(cb, state);
468        }
469    }
470
471    /** @see AudioManager#getStreamVolume(int) */
472    public int getStreamVolume(int streamType) {
473        ensureValidStreamType(streamType);
474        return mStreamStates[streamType].mIndex;
475    }
476
477    /** @see AudioManager#getStreamMaxVolume(int) */
478    public int getStreamMaxVolume(int streamType) {
479        ensureValidStreamType(streamType);
480        return mStreamStates[streamType].getMaxIndex();
481    }
482
483    /** @see AudioManager#getRingerMode() */
484    public int getRingerMode() {
485        return mRingerMode;
486    }
487
488    /** @see AudioManager#setRingerMode(int) */
489    public void setRingerMode(int ringerMode) {
490        if (ringerMode != mRingerMode) {
491            mRingerMode = ringerMode;
492
493            // Adjust volumes via posting message
494            int numStreamTypes = AudioSystem.getNumStreamTypes();
495            if (mRingerMode == AudioManager.RINGER_MODE_NORMAL) {
496                for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
497                    if (!isStreamAffectedByRingerMode(streamType)) continue;
498                    // Bring back last audible volume
499                    setStreamVolumeInt(streamType, mStreamStates[streamType].mLastAudibleIndex,
500                                       false);
501                }
502            } else {
503                for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
504                    if (!isStreamAffectedByRingerMode(streamType)) continue;
505                    // Either silent or vibrate, either way volume is 0
506                    setStreamVolumeInt(streamType, 0, false);
507                }
508            }
509
510            // Send sticky broadcast
511            broadcastRingerMode();
512
513            // Post a persist ringer mode msg
514            sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE, SHARED_MSG,
515                    SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
516        }
517    }
518
519    /** @see AudioManager#shouldVibrate(int) */
520    public boolean shouldVibrate(int vibrateType) {
521
522        switch (getVibrateSetting(vibrateType)) {
523
524            case AudioManager.VIBRATE_SETTING_ON:
525                return mRingerMode != AudioManager.RINGER_MODE_SILENT;
526
527            case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
528                return mRingerMode == AudioManager.RINGER_MODE_VIBRATE;
529
530            case AudioManager.VIBRATE_SETTING_OFF:
531                // Phone ringer should always vibrate in vibrate mode
532                if (vibrateType == AudioManager.VIBRATE_TYPE_RINGER) {
533                    return mRingerMode == AudioManager.RINGER_MODE_VIBRATE;
534                }
535
536            default:
537                return false;
538        }
539    }
540
541    /** @see AudioManager#getVibrateSetting(int) */
542    public int getVibrateSetting(int vibrateType) {
543        return (mVibrateSetting >> (vibrateType * 2)) & 3;
544    }
545
546    /** @see AudioManager#setVibrateSetting(int, int) */
547    public void setVibrateSetting(int vibrateType, int vibrateSetting) {
548
549        mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting);
550
551        // Broadcast change
552        broadcastVibrateSetting(vibrateType);
553
554        // Post message to set ringer mode (it in turn will post a message
555        // to persist)
556        sendMsg(mAudioHandler, MSG_PERSIST_VIBRATE_SETTING, SHARED_MSG, SENDMSG_NOOP, 0, 0,
557                null, 0);
558    }
559
560    /**
561     * @see #setVibrateSetting(int, int)
562     * @hide
563     */
564    public static int getValueForVibrateSetting(int existingValue, int vibrateType,
565            int vibrateSetting) {
566
567        // First clear the existing setting. Each vibrate type has two bits in
568        // the value. Note '3' is '11' in binary.
569        existingValue &= ~(3 << (vibrateType * 2));
570
571        // Set into the old value
572        existingValue |= (vibrateSetting & 3) << (vibrateType * 2);
573
574        return existingValue;
575    }
576
577    /** @see AudioManager#setMicrophoneMute(boolean) */
578    public void setMicrophoneMute(boolean on) {
579        if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
580            return;
581        }
582        synchronized (mSettingsLock) {
583            if (on != mMicMute) {
584                AudioSystem.muteMicrophone(on);
585                mMicMute = on;
586            }
587        }
588    }
589
590    /** @see AudioManager#isMicrophoneMute() */
591    public boolean isMicrophoneMute() {
592        return mMicMute;
593    }
594
595    /** @see AudioManager#setMode(int) */
596    public void setMode(int mode) {
597        if (!checkAudioSettingsPermission("setMode()")) {
598            return;
599        }
600        synchronized (mSettingsLock) {
601            if (mode != mMode) {
602                AudioSystem.setMode(mode);
603                mMode = mode;
604            }
605            int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
606            int index = mStreamStates[streamType].mIndex;
607            syncRingerAndNotificationStreamVolume(streamType, index, true);
608            setStreamVolumeInt(streamType, index, true);
609        }
610    }
611
612    /** @see AudioManager#getMode() */
613    public int getMode() {
614        return mMode;
615    }
616
617    /** @see AudioManager#setRouting(int, int, int) */
618    public void setRouting(int mode, int routes, int mask) {
619        if (!checkAudioSettingsPermission("setRouting()")) {
620            return;
621        }
622        synchronized (mSettingsLock) {
623            if ((mRoutes[mode] & mask) != (routes & mask)) {
624                AudioSystem.setRouting(mode, routes, mask);
625                mRoutes[mode] = (mRoutes[mode] & ~mask) | (routes & mask);
626            }
627            int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
628            int index = mStreamStates[streamType].mIndex;
629            syncRingerAndNotificationStreamVolume(streamType, index, true);
630            setStreamVolumeInt(streamType, index, true);
631        }
632    }
633
634    /** @see AudioManager#getRouting(int) */
635    public int getRouting(int mode) {
636        return mRoutes[mode];
637    }
638
639    /** @see AudioManager#isMusicActive() */
640    public boolean isMusicActive() {
641        return AudioSystem.isMusicActive();
642    }
643
644    /** @see AudioManager#setParameter(String, String) */
645    public void setParameter(String key, String value) {
646        AudioSystem.setParameter(key, value);
647    }
648
649    /** @see AudioManager#playSoundEffect(int) */
650    public void playSoundEffect(int effectType) {
651        sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SHARED_MSG, SENDMSG_NOOP, effectType, 0,
652                null, 0);
653    }
654
655    /**
656     * Loads samples into the soundpool.
657     * This method must be called at when sound effects are enabled
658     */
659    public boolean loadSoundEffects() {
660        synchronized (mSoundEffectsLock) {
661            mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0);
662            if (mSoundPool == null) {
663                return false;
664            }
665            /*
666             * poolId table: The value -1 in this table indicates that corresponding
667             * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
668             * Once loaded, the value in poolId is the sample ID and the same
669             * sample can be reused for another effect using the same file.
670             */
671            int[] poolId = new int[SOUND_EFFECT_FILES.length];
672            for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) {
673                poolId[fileIdx] = -1;
674            }
675            /*
676             * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
677             * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
678             * this indicates we have a valid sample loaded for this effect.
679             */
680            for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
681                // Do not load sample if this effect uses the MediaPlayer
682                if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
683                    continue;
684                }
685                if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
686                    String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effect][0]];
687                    int sampleId = mSoundPool.load(filePath, 0);
688                    SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
689                    poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
690                    if (sampleId <= 0) {
691                        Log.w(TAG, "Soundpool could not load file: "+filePath);
692                    }
693                } else {
694                    SOUND_EFFECT_FILES_MAP[effect][1] = poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
695                }
696            }
697        }
698
699        return true;
700    }
701
702    /**
703     *  Unloads samples from the sound pool.
704     *  This method can be called to free some memory when
705     *  sound effects are disabled.
706     */
707    public void unloadSoundEffects() {
708        synchronized (mSoundEffectsLock) {
709            if (mSoundPool == null) {
710                return;
711            }
712            int[] poolId = new int[SOUND_EFFECT_FILES.length];
713            for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) {
714                poolId[fileIdx] = 0;
715            }
716
717            for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
718                if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
719                    continue;
720                }
721                if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
722                    mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
723                    SOUND_EFFECT_FILES_MAP[effect][1] = -1;
724                    poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
725                }
726            }
727            mSoundPool = null;
728        }
729    }
730
731    ///////////////////////////////////////////////////////////////////////////
732    // Internal methods
733    ///////////////////////////////////////////////////////////////////////////
734
735    /**
736     * Checks if the adjustment should change ringer mode instead of just
737     * adjusting volume. If so, this will set the proper ringer mode and volume
738     * indices on the stream states.
739     */
740    private boolean checkForRingerModeChange(int oldIndex, int direction) {
741        boolean adjustVolumeIndex = true;
742        int newRingerMode = mRingerMode;
743
744        if (mRingerMode == AudioManager.RINGER_MODE_NORMAL && oldIndex == 1
745                && direction == AudioManager.ADJUST_LOWER) {
746            newRingerMode = AudioManager.RINGER_MODE_VIBRATE;
747        } else if (mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
748            if (direction == AudioManager.ADJUST_RAISE) {
749                newRingerMode = AudioManager.RINGER_MODE_NORMAL;
750            } else if (direction == AudioManager.ADJUST_LOWER) {
751                newRingerMode = AudioManager.RINGER_MODE_SILENT;
752            }
753        } else if (direction == AudioManager.ADJUST_RAISE
754                && mRingerMode == AudioManager.RINGER_MODE_SILENT) {
755            newRingerMode = AudioManager.RINGER_MODE_VIBRATE;
756        }
757
758        if (newRingerMode != mRingerMode) {
759            setRingerMode(newRingerMode);
760
761            /*
762             * If we are changing ringer modes, do not increment/decrement the
763             * volume index. Instead, the handler for the message above will
764             * take care of changing the index.
765             */
766            adjustVolumeIndex = false;
767        }
768
769        return adjustVolumeIndex;
770    }
771
772    public boolean isStreamAffectedByRingerMode(int streamType) {
773        return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
774    }
775
776    public boolean isStreamAffectedByMute(int streamType) {
777        return (mMuteAffectedStreams & (1 << streamType)) != 0;
778    }
779
780    private void ensureValidDirection(int direction) {
781        if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) {
782            throw new IllegalArgumentException("Bad direction " + direction);
783        }
784    }
785
786    private void ensureValidStreamType(int streamType) {
787        if (streamType < 0 || streamType >= mStreamStates.length) {
788            throw new IllegalArgumentException("Bad stream type " + streamType);
789        }
790    }
791
792    private int getActiveStreamType(int suggestedStreamType) {
793        boolean isOffhook = false;
794        try {
795            ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
796            if (phone != null) isOffhook = phone.isOffhook();
797        } catch (RemoteException e) {
798            Log.w(TAG, "Couldn't connect to phone service", e);
799        }
800
801        if ((getRouting(AudioSystem.MODE_IN_CALL) & AudioSystem.ROUTE_BLUETOOTH_SCO) != 0) {
802            // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
803            return AudioSystem.STREAM_BLUETOOTH_SCO;
804        } else if (isOffhook) {
805            // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
806            return AudioSystem.STREAM_VOICE_CALL;
807        } else if (AudioSystem.isMusicActive()) {
808            // Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC...");
809            return AudioSystem.STREAM_MUSIC;
810        } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
811            // Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING...");
812            return AudioSystem.STREAM_RING;
813        } else {
814            // Log.v(TAG, "getActiveStreamType: Returning suggested type " + suggestedStreamType);
815            return suggestedStreamType;
816        }
817    }
818
819    private void broadcastRingerMode() {
820        // Send sticky broadcast
821        if (ActivityManagerNative.isSystemReady()) {
822            Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION);
823            broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, mRingerMode);
824            long origCallerIdentityToken = Binder.clearCallingIdentity();
825            mContext.sendStickyBroadcast(broadcast);
826            Binder.restoreCallingIdentity(origCallerIdentityToken);
827        }
828    }
829
830    private void broadcastVibrateSetting(int vibrateType) {
831        // Send broadcast
832        if (ActivityManagerNative.isSystemReady()) {
833            Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
834            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
835            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
836            mContext.sendBroadcast(broadcast);
837        }
838    }
839
840    // Message helper methods
841    private static int getMsg(int baseMsg, int streamType) {
842        return (baseMsg & 0xffff) | streamType << 16;
843    }
844
845    private static int getMsgBase(int msg) {
846        return msg & 0xffff;
847    }
848
849    private static void sendMsg(Handler handler, int baseMsg, int streamType,
850            int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
851        int msg = (streamType == SHARED_MSG) ? baseMsg : getMsg(baseMsg, streamType);
852
853        if (existingMsgPolicy == SENDMSG_REPLACE) {
854            handler.removeMessages(msg);
855        } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
856            return;
857        }
858
859        handler
860                .sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay);
861    }
862
863    boolean checkAudioSettingsPermission(String method) {
864        if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS")
865                == PackageManager.PERMISSION_GRANTED) {
866            return true;
867        }
868        String msg = "Audio Settings Permission Denial: " + method + " from pid="
869                + Binder.getCallingPid()
870                + ", uid=" + Binder.getCallingUid();
871        Log.w(TAG, msg);
872        return false;
873    }
874
875
876    ///////////////////////////////////////////////////////////////////////////
877    // Inner classes
878    ///////////////////////////////////////////////////////////////////////////
879
880    public class VolumeStreamState {
881        private final String mVolumeIndexSettingName;
882        private final String mLastAudibleVolumeIndexSettingName;
883        private final int mStreamType;
884
885        private final int[] mVolumes;
886        private int mIndex;
887        private int mLastAudibleIndex;
888        private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo requests client death
889
890        private VolumeStreamState(String settingName, int streamType, int[] volumes) {
891
892            mVolumeIndexSettingName = settingName;
893            mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE;
894
895            mStreamType = streamType;
896            mVolumes = volumes;
897
898            final ContentResolver cr = mContentResolver;
899            mIndex = getValidIndex(Settings.System.getInt(cr, mVolumeIndexSettingName, AudioManager.DEFAULT_STREAM_VOLUME[streamType]));
900            mLastAudibleIndex = getValidIndex(Settings.System.getInt(cr,
901                    mLastAudibleVolumeIndexSettingName, mIndex > 0 ? mIndex : AudioManager.DEFAULT_STREAM_VOLUME[streamType]));
902
903            AudioSystem.setVolume(streamType, volumes[mIndex]);
904            mDeathHandlers = new ArrayList<VolumeDeathHandler>();
905        }
906
907        /**
908         * Constructor to be used when there is no setting associated with the VolumeStreamState.
909         *
910         * @param defaultVolume Default volume of the stream to use.
911         * @param streamType Type of the stream.
912         * @param volumes Volumes levels associated with this stream.
913         */
914        private VolumeStreamState(int defaultVolume, int streamType, int[] volumes) {
915            mVolumeIndexSettingName = null;
916            mLastAudibleVolumeIndexSettingName = null;
917            mIndex = mLastAudibleIndex = defaultVolume;
918            mStreamType = streamType;
919            mVolumes = volumes;
920            AudioSystem.setVolume(mStreamType, defaultVolume);
921            mDeathHandlers = new ArrayList<VolumeDeathHandler>();
922        }
923
924        public boolean adjustIndex(int deltaIndex) {
925            return setIndex(mIndex + deltaIndex);
926        }
927
928        public boolean setIndex(int index) {
929            int oldIndex = mIndex;
930            mIndex = getValidIndex(index);
931
932            if (oldIndex != mIndex) {
933                if (mIndex > 0) {
934                    mLastAudibleIndex = mIndex;
935                }
936                return true;
937            } else {
938                return false;
939            }
940        }
941
942        public int getMaxIndex() {
943            return mVolumes.length - 1;
944        }
945
946        public void mute(IBinder cb, boolean state) {
947            VolumeDeathHandler handler = getDeathHandler(cb, state);
948            if (handler == null) {
949                Log.e(TAG, "Could not get client death handler for stream: "+mStreamType);
950                return;
951            }
952            handler.mute(state);
953        }
954
955        private int getValidIndex(int index) {
956            if (index < 0) {
957                return 0;
958            } else if (index >= mVolumes.length) {
959                return mVolumes.length - 1;
960            }
961
962            return index;
963        }
964
965        private class VolumeDeathHandler implements IBinder.DeathRecipient {
966            private IBinder mICallback; // To be notified of client's death
967            private int mMuteCount; // Number of active mutes for this client
968
969            VolumeDeathHandler(IBinder cb) {
970                mICallback = cb;
971            }
972
973            public void mute(boolean state) {
974                synchronized(mDeathHandlers) {
975                    if (state) {
976                        if (mMuteCount == 0) {
977                            // Register for client death notification
978                            try {
979                                mICallback.linkToDeath(this, 0);
980                                mDeathHandlers.add(this);
981                                // If the stream is not yet muted by any client, set lvel to 0
982                                if (muteCount() == 0) {
983                                    setIndex(0);
984                                    sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, mStreamType, SENDMSG_NOOP, 0, 0,
985                                            VolumeStreamState.this, 0);
986                                }
987                            } catch (RemoteException e) {
988                                // Client has died!
989                                binderDied();
990                                mDeathHandlers.notify();
991                                return;
992                            }
993                        } else {
994                            Log.w(TAG, "stream: "+mStreamType+" was already muted by this client");
995                        }
996                        mMuteCount++;
997                    } else {
998                        if (mMuteCount == 0) {
999                            Log.e(TAG, "unexpected unmute for stream: "+mStreamType);
1000                        } else {
1001                            mMuteCount--;
1002                            if (mMuteCount == 0) {
1003                                // Unregistr from client death notification
1004                                mDeathHandlers.remove(this);
1005                                mICallback.unlinkToDeath(this, 0);
1006                                if (muteCount() == 0) {
1007                                    // If the stream is not mut any more, restore it's volume if
1008                                    // ringer mode allows it
1009                                    if (!isStreamAffectedByRingerMode(mStreamType) || mRingerMode == AudioManager.RINGER_MODE_NORMAL) {
1010                                        setIndex(mLastAudibleIndex);
1011                                        sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, mStreamType, SENDMSG_NOOP, 0, 0,
1012                                                VolumeStreamState.this, 0);
1013                                    }
1014                                }
1015                            }
1016                        }
1017                    }
1018                    mDeathHandlers.notify();
1019                }
1020            }
1021
1022            public void binderDied() {
1023                Log.w(TAG, "Volume service client died for stream: "+mStreamType);
1024                if (mMuteCount != 0) {
1025                    // Reset all active mute requests from this client.
1026                    mMuteCount = 1;
1027                    mute(false);
1028                }
1029            }
1030        }
1031
1032        private int muteCount() {
1033            int count = 0;
1034            int size = mDeathHandlers.size();
1035            for (int i = 0; i < size; i++) {
1036                count += mDeathHandlers.get(i).mMuteCount;
1037            }
1038            return count;
1039        }
1040
1041        private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) {
1042            synchronized(mDeathHandlers) {
1043                VolumeDeathHandler handler;
1044                int size = mDeathHandlers.size();
1045                for (int i = 0; i < size; i++) {
1046                    handler = mDeathHandlers.get(i);
1047                    if (cb.equals(handler.mICallback)) {
1048                        return handler;
1049                    }
1050                }
1051                // If this is the first mute request for this client, create a new
1052                // client death handler. Otherwise, it is an out of sequence unmute request.
1053                if (state) {
1054                    handler = new VolumeDeathHandler(cb);
1055                } else {
1056                    Log.w(TAG, "stream was not muted by this client");
1057                    handler = null;
1058                }
1059                return handler;
1060            }
1061        }
1062    }
1063
1064    /** Thread that handles native AudioSystem control. */
1065    private class AudioSystemThread extends Thread {
1066        AudioSystemThread() {
1067            super("AudioService");
1068        }
1069
1070        @Override
1071        public void run() {
1072            // Set this thread up so the handler will work on it
1073            Looper.prepare();
1074
1075            synchronized(AudioService.this) {
1076                mAudioHandler = new AudioHandler();
1077
1078                // Notify that the handler has been created
1079                AudioService.this.notify();
1080            }
1081
1082            // Listen for volume change requests that are set by VolumePanel
1083            Looper.loop();
1084        }
1085    }
1086
1087    /** Handles internal volume messages in separate volume thread. */
1088    private class AudioHandler extends Handler {
1089
1090        private void setSystemVolume(VolumeStreamState streamState) {
1091
1092            // Adjust volume
1093            AudioSystem
1094                    .setVolume(streamState.mStreamType, streamState.mVolumes[streamState.mIndex]);
1095
1096            // Post a persist volume msg
1097            sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamState.mStreamType,
1098                    SENDMSG_REPLACE, 0, 0, streamState, PERSIST_DELAY);
1099        }
1100
1101        private void persistVolume(VolumeStreamState streamState) {
1102            System.putInt(mContentResolver, streamState.mVolumeIndexSettingName,
1103                    streamState.mIndex);
1104            System.putInt(mContentResolver, streamState.mLastAudibleVolumeIndexSettingName,
1105                    streamState.mLastAudibleIndex);
1106        }
1107
1108        private void persistRingerMode() {
1109            System.putInt(mContentResolver, System.MODE_RINGER, mRingerMode);
1110        }
1111
1112        private void persistVibrateSetting() {
1113            System.putInt(mContentResolver, System.VIBRATE_ON, mVibrateSetting);
1114        }
1115
1116        private void playSoundEffect(int effectType) {
1117            synchronized (mSoundEffectsLock) {
1118                if (mSoundPool == null) {
1119                    return;
1120                }
1121
1122                if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
1123                    mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1], SOUND_EFFECT_VOLUME, SOUND_EFFECT_VOLUME,
1124                            0, 0, 1.0f);
1125                } else {
1126                    MediaPlayer mediaPlayer = new MediaPlayer();
1127                    if (mediaPlayer != null) {
1128                        try {
1129                            String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effectType][0]];
1130                            mediaPlayer.setDataSource(filePath);
1131                            mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
1132                            mediaPlayer.prepare();
1133                            mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
1134                                public void onCompletion(MediaPlayer mp) {
1135                                    cleanupPlayer(mp);
1136                                }
1137                            });
1138                            mediaPlayer.setOnErrorListener(new OnErrorListener() {
1139                                public boolean onError(MediaPlayer mp, int what, int extra) {
1140                                    cleanupPlayer(mp);
1141                                    return true;
1142                                }
1143                            });
1144                            mediaPlayer.start();
1145                        } catch (IOException ex) {
1146                            Log.w(TAG, "MediaPlayer IOException: "+ex);
1147                        } catch (IllegalArgumentException ex) {
1148                            Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
1149                        } catch (IllegalStateException ex) {
1150                            Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
1151                        }
1152                    }
1153                }
1154            }
1155        }
1156
1157        private void cleanupPlayer(MediaPlayer mp) {
1158            if (mp != null) {
1159                try {
1160                    mp.stop();
1161                    mp.release();
1162                } catch (IllegalStateException ex) {
1163                    Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
1164                }
1165            }
1166        }
1167
1168        @Override
1169        public void handleMessage(Message msg) {
1170            int baseMsgWhat = getMsgBase(msg.what);
1171
1172            switch (baseMsgWhat) {
1173
1174                case MSG_SET_SYSTEM_VOLUME:
1175                    setSystemVolume((VolumeStreamState) msg.obj);
1176                    break;
1177
1178                case MSG_PERSIST_VOLUME:
1179                    persistVolume((VolumeStreamState) msg.obj);
1180                    break;
1181
1182                case MSG_PERSIST_RINGER_MODE:
1183                    persistRingerMode();
1184                    break;
1185
1186                case MSG_PERSIST_VIBRATE_SETTING:
1187                    persistVibrateSetting();
1188                    break;
1189
1190                case MSG_MEDIA_SERVER_DIED:
1191                    Log.e(TAG, "Media server died.");
1192                    // Force creation of new IAudioflinger interface
1193                    mMediaServerOk = false;
1194                    AudioSystem.getMode();
1195                    break;
1196
1197                case MSG_MEDIA_SERVER_STARTED:
1198                    Log.e(TAG, "Media server started.");
1199                    // Restore audio routing and stream volumes
1200                    applyAudioSettings();
1201                    int numStreamTypes = AudioSystem.getNumStreamTypes();
1202                    for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
1203                        int volume;
1204                        VolumeStreamState streamState = mStreamStates[streamType];
1205                        if (streamState.muteCount() == 0) {
1206                            volume = streamState.mVolumes[streamState.mIndex];
1207                        } else {
1208                            volume = streamState.mVolumes[0];
1209                        }
1210                        AudioSystem.setVolume(streamType, volume);
1211                    }
1212                    setRingerMode(mRingerMode);
1213                    mMediaServerOk = true;
1214                    break;
1215
1216                case MSG_PLAY_SOUND_EFFECT:
1217                    playSoundEffect(msg.arg1);
1218                    break;
1219            }
1220        }
1221    }
1222
1223}
1224