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