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