AudioService.java revision d5603c126acdd94d9f7400bb1d04188020a425b4
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.IntentFilter; 24import android.bluetooth.BluetoothIntent; 25import android.content.BroadcastReceiver; 26import android.bluetooth.BluetoothHeadset; 27import android.bluetooth.BluetoothA2dp; 28import android.bluetooth.BluetoothDevice; 29import android.bluetooth.BluetoothClass; 30 31import android.content.pm.PackageManager; 32import android.database.ContentObserver; 33import android.media.MediaPlayer.OnCompletionListener; 34import android.media.MediaPlayer.OnErrorListener; 35import android.os.Binder; 36import android.os.Environment; 37import android.os.Handler; 38import android.os.IBinder; 39import android.os.Looper; 40import android.os.Message; 41import android.os.RemoteException; 42import android.os.ServiceManager; 43import android.provider.Settings; 44import android.provider.Settings.System; 45import android.util.Log; 46import android.view.VolumePanel; 47 48import com.android.internal.telephony.ITelephony; 49 50import java.io.IOException; 51import java.util.ArrayList; 52import java.util.HashMap; 53import java.util.Iterator; 54import java.util.Map; 55import java.util.Set; 56 57/** 58 * The implementation of the volume manager service. 59 * <p> 60 * This implementation focuses on delivering a responsive UI. Most methods are 61 * asynchronous to external calls. For example, the task of setting a volume 62 * will update our internal state, but in a separate thread will set the system 63 * volume and later persist to the database. Similarly, setting the ringer mode 64 * will update the state and broadcast a change and in a separate thread later 65 * persist the ringer mode. 66 * 67 * @hide 68 */ 69public class AudioService extends IAudioService.Stub { 70 71 private static final String TAG = "AudioService"; 72 73 /** How long to delay before persisting a change in volume/ringer mode. */ 74 private static final int PERSIST_DELAY = 3000; 75 76 private Context mContext; 77 private ContentResolver mContentResolver; 78 79 /** The UI */ 80 private VolumePanel mVolumePanel; 81 82 // sendMsg() flags 83 /** Used when a message should be shared across all stream types. */ 84 private static final int SHARED_MSG = -1; 85 /** If the msg is already queued, replace it with this one. */ 86 private static final int SENDMSG_REPLACE = 0; 87 /** If the msg is already queued, ignore this one and leave the old. */ 88 private static final int SENDMSG_NOOP = 1; 89 /** If the msg is already queued, queue this one and leave the old. */ 90 private static final int SENDMSG_QUEUE = 2; 91 92 // AudioHandler message.whats 93 private static final int MSG_SET_SYSTEM_VOLUME = 0; 94 private static final int MSG_PERSIST_VOLUME = 1; 95 private static final int MSG_PERSIST_RINGER_MODE = 3; 96 private static final int MSG_PERSIST_VIBRATE_SETTING = 4; 97 private static final int MSG_MEDIA_SERVER_DIED = 5; 98 private static final int MSG_MEDIA_SERVER_STARTED = 6; 99 private static final int MSG_PLAY_SOUND_EFFECT = 7; 100 101 /** @see AudioSystemThread */ 102 private AudioSystemThread mAudioSystemThread; 103 /** @see AudioHandler */ 104 private AudioHandler mAudioHandler; 105 /** @see VolumeStreamState */ 106 private VolumeStreamState[] mStreamStates; 107 private SettingsObserver mSettingsObserver; 108 109 private int mMode; 110 private Object mSettingsLock = new Object(); 111 private boolean mMediaServerOk; 112 113 private SoundPool mSoundPool; 114 private Object mSoundEffectsLock = new Object(); 115 private static final int NUM_SOUNDPOOL_CHANNELS = 4; 116 private static final int SOUND_EFFECT_VOLUME = 1000; 117 118 /* Sound effect file names */ 119 private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/"; 120 private static final String[] SOUND_EFFECT_FILES = new String[] { 121 "Effect_Tick.ogg", 122 "KeypressStandard.ogg", 123 "KeypressSpacebar.ogg", 124 "KeypressDelete.ogg", 125 "KeypressReturn.ogg" 126 }; 127 128 /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to 129 * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect 130 * uses soundpool (second column) */ 131 private int[][] SOUND_EFFECT_FILES_MAP = new int[][] { 132 {0, -1}, // FX_KEY_CLICK 133 {0, -1}, // FX_FOCUS_NAVIGATION_UP 134 {0, -1}, // FX_FOCUS_NAVIGATION_DOWN 135 {0, -1}, // FX_FOCUS_NAVIGATION_LEFT 136 {0, -1}, // FX_FOCUS_NAVIGATION_RIGHT 137 {1, -1}, // FX_KEYPRESS_STANDARD 138 {2, -1}, // FX_KEYPRESS_SPACEBAR 139 {3, -1}, // FX_FOCUS_DELETE 140 {4, -1} // FX_FOCUS_RETURN 141 }; 142 143 /* STREAM_VOLUME_ALIAS[] indicates for each stream if it uses the volume settings 144 * of another stream: This avoids multiplying the volume settings for hidden 145 * stream types that follow other stream behavior for volume settings 146 * NOTE: do not create loops in aliases! */ 147 private int[] STREAM_VOLUME_ALIAS = new int[] { 148 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL 149 AudioSystem.STREAM_SYSTEM, // STREAM_SYSTEM 150 AudioSystem.STREAM_RING, // STREAM_RING 151 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC 152 AudioSystem.STREAM_ALARM, // STREAM_ALARM 153 AudioSystem.STREAM_NOTIFICATION, // STREAM_NOTIFICATION 154 AudioSystem.STREAM_VOICE_CALL, // STREAM_BLUETOOTH_SCO 155 AudioSystem.STREAM_SYSTEM, // STREAM_SYSTEM_ENFORCED 156 AudioSystem.STREAM_VOICE_CALL, // STREAM_DTMF 157 AudioSystem.STREAM_MUSIC // STREAM_TTS 158 }; 159 160 private AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() { 161 public void onError(int error) { 162 switch (error) { 163 case AudioSystem.AUDIO_STATUS_SERVER_DIED: 164 if (mMediaServerOk) { 165 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SHARED_MSG, SENDMSG_NOOP, 0, 0, 166 null, 1500); 167 } 168 break; 169 case AudioSystem.AUDIO_STATUS_OK: 170 if (!mMediaServerOk) { 171 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_STARTED, SHARED_MSG, SENDMSG_NOOP, 0, 0, 172 null, 0); 173 } 174 break; 175 default: 176 break; 177 } 178 } 179 }; 180 181 /** 182 * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL}, 183 * {@link AudioManager#RINGER_MODE_SILENT}, or 184 * {@link AudioManager#RINGER_MODE_VIBRATE}. 185 */ 186 private int mRingerMode; 187 188 /** @see System#MODE_RINGER_STREAMS_AFFECTED */ 189 private int mRingerModeAffectedStreams; 190 191 /** @see System#MUTE_STREAMS_AFFECTED */ 192 private int mMuteAffectedStreams; 193 194 /** 195 * Has multiple bits per vibrate type to indicate the type's vibrate 196 * setting. See {@link #setVibrateSetting(int, int)}. 197 * <p> 198 * NOTE: This is not the final decision of whether vibrate is on/off for the 199 * type since it depends on the ringer mode. See {@link #shouldVibrate(int)}. 200 */ 201 private int mVibrateSetting; 202 203 /** @see System#NOTIFICATIONS_USE_RING_VOLUME */ 204 private int mNotificationsUseRingVolume; 205 206 // Broadcast receiver for device connections intent broadcasts 207 private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver(); 208 209 //TODO: use common definitions with HeadsetObserver 210 private static final int BIT_HEADSET = (1 << 0); 211 private static final int BIT_HEADSET_NO_MIC = (1 << 1); 212 private static final int BIT_TTY = (1 << 2); 213 private static final int BIT_FM_HEADSET = (1 << 3); 214 private static final int BIT_FM_SPEAKER = (1 << 4); 215 216 private int mHeadsetState; 217 218 // Devices currently connected 219 private HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>(); 220 221 // Forced device usage for communications 222 private int mForcedUseForComm; 223 224 private BluetoothDevice mBluetoothDevice = null; 225 226 /////////////////////////////////////////////////////////////////////////// 227 // Construction 228 /////////////////////////////////////////////////////////////////////////// 229 230 /** @hide */ 231 public AudioService(Context context) { 232 mContext = context; 233 mContentResolver = context.getContentResolver(); 234 mVolumePanel = new VolumePanel(context, this); 235 mSettingsObserver = new SettingsObserver(); 236 mMode = AudioSystem.MODE_NORMAL; 237 mHeadsetState = 0; 238 mForcedUseForComm = AudioSystem.FORCE_NONE; 239 createAudioSystemThread(); 240 readPersistedSettings(); 241 createStreamStates(); 242 mMediaServerOk = true; 243 AudioSystem.setErrorCallback(mAudioSystemCallback); 244 loadSoundEffects(); 245 246 // Register for device connection intent broadcasts. 247 IntentFilter intentFilter = 248 new IntentFilter(Intent.ACTION_HEADSET_PLUG); 249 intentFilter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION); 250 intentFilter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION); 251 context.registerReceiver(mReceiver, intentFilter); 252 } 253 254 private void createAudioSystemThread() { 255 mAudioSystemThread = new AudioSystemThread(); 256 mAudioSystemThread.start(); 257 waitForAudioHandlerCreation(); 258 } 259 260 /** Waits for the volume handler to be created by the other thread. */ 261 private void waitForAudioHandlerCreation() { 262 synchronized(this) { 263 while (mAudioHandler == null) { 264 try { 265 // Wait for mAudioHandler to be set by the other thread 266 wait(); 267 } catch (InterruptedException e) { 268 Log.e(TAG, "Interrupted while waiting on volume handler."); 269 } 270 } 271 } 272 } 273 274 private void createStreamStates() { 275 int numStreamTypes = AudioSystem.getNumStreamTypes(); 276 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes]; 277 278 for (int i = 0; i < numStreamTypes; i++) { 279 streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[STREAM_VOLUME_ALIAS[i]], i); 280 } 281 282 // Correct stream index values for streams with aliases 283 for (int i = 0; i < numStreamTypes; i++) { 284 if (STREAM_VOLUME_ALIAS[i] != i) { 285 int index = rescaleIndex(streams[i].mIndex, STREAM_VOLUME_ALIAS[i], i); 286 streams[i].mIndex = streams[i].getValidIndex(index); 287 setStreamVolumeIndex(i, index); 288 index = rescaleIndex(streams[i].mLastAudibleIndex, STREAM_VOLUME_ALIAS[i], i); 289 streams[i].mLastAudibleIndex = streams[i].getValidIndex(index); 290 } 291 } 292 } 293 294 private void readPersistedSettings() { 295 final ContentResolver cr = mContentResolver; 296 297 mRingerMode = System.getInt(cr, System.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL); 298 299 mVibrateSetting = System.getInt(cr, System.VIBRATE_ON, 0); 300 301 mRingerModeAffectedStreams = Settings.System.getInt(cr, 302 Settings.System.MODE_RINGER_STREAMS_AFFECTED, 303 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)| 304 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED))); 305 306 mMuteAffectedStreams = System.getInt(cr, 307 System.MUTE_STREAMS_AFFECTED, 308 ((1 << AudioSystem.STREAM_MUSIC)|(1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_SYSTEM))); 309 310 mNotificationsUseRingVolume = System.getInt(cr, 311 Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1); 312 313 if (mNotificationsUseRingVolume == 1) { 314 STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_RING; 315 } 316 // Each stream will read its own persisted settings 317 318 // Broadcast the sticky intent 319 broadcastRingerMode(); 320 321 // Broadcast vibrate settings 322 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER); 323 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION); 324 } 325 326 private void setStreamVolumeIndex(int stream, int index) { 327 AudioSystem.setStreamVolumeIndex(stream, (index + 5)/10); 328 } 329 330 private int rescaleIndex(int index, int srcStream, int dstStream) { 331 return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex(); 332 } 333 334 /////////////////////////////////////////////////////////////////////////// 335 // IPC methods 336 /////////////////////////////////////////////////////////////////////////// 337 338 /** @see AudioManager#adjustVolume(int, int) */ 339 public void adjustVolume(int direction, int flags) { 340 adjustSuggestedStreamVolume(direction, AudioManager.USE_DEFAULT_STREAM_TYPE, flags); 341 } 342 343 /** @see AudioManager#adjustVolume(int, int, int) */ 344 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) { 345 346 int streamType = getActiveStreamType(suggestedStreamType); 347 348 // Don't play sound on other streams 349 if (streamType != AudioSystem.STREAM_RING && (flags & AudioManager.FLAG_PLAY_SOUND) != 0) { 350 flags &= ~AudioManager.FLAG_PLAY_SOUND; 351 } 352 353 adjustStreamVolume(streamType, direction, flags); 354 } 355 356 /** @see AudioManager#adjustStreamVolume(int, int, int) */ 357 public void adjustStreamVolume(int streamType, int direction, int flags) { 358 ensureValidDirection(direction); 359 ensureValidStreamType(streamType); 360 361 362 VolumeStreamState streamState = mStreamStates[STREAM_VOLUME_ALIAS[streamType]]; 363 final int oldIndex = streamState.mIndex; 364 boolean adjustVolume = true; 365 366 // If either the client forces allowing ringer modes for this adjustment, 367 // or the stream type is one that is affected by ringer modes 368 if ((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0 369 || streamType == AudioSystem.STREAM_RING) { 370 // Check if the ringer mode changes with this volume adjustment. If 371 // it does, it will handle adjusting the volume, so we won't below 372 adjustVolume = checkForRingerModeChange(oldIndex, direction); 373 } 374 375 if (adjustVolume && streamState.adjustIndex(direction)) { 376 // Post message to set system volume (it in turn will post a message 377 // to persist). Do not change volume if stream is muted. 378 if (streamState.muteCount() == 0) { 379 sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, STREAM_VOLUME_ALIAS[streamType], SENDMSG_NOOP, 0, 0, 380 streamState, 0); 381 } 382 } 383 384 // UI 385 mVolumePanel.postVolumeChanged(streamType, flags); 386 // Broadcast Intent 387 sendVolumeUpdate(streamType); 388 } 389 390 /** @see AudioManager#setStreamVolume(int, int, int) */ 391 public void setStreamVolume(int streamType, int index, int flags) { 392 ensureValidStreamType(streamType); 393 index = rescaleIndex(index * 10, streamType, STREAM_VOLUME_ALIAS[streamType]); 394 setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, false, true); 395 396 // UI, etc. 397 mVolumePanel.postVolumeChanged(streamType, flags); 398 // Broadcast Intent 399 sendVolumeUpdate(streamType); 400 } 401 402 private void sendVolumeUpdate(int streamType) { 403 Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION); 404 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType); 405 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, getStreamVolume(streamType)); 406 407 // Currently, sending the intent only when the stream is BLUETOOTH_SCO 408 if (streamType == AudioSystem.STREAM_BLUETOOTH_SCO) { 409 mContext.sendBroadcast(intent); 410 } 411 } 412 413 /** 414 * Sets the stream state's index, and posts a message to set system volume. 415 * This will not call out to the UI. Assumes a valid stream type. 416 * 417 * @param streamType Type of the stream 418 * @param index Desired volume index of the stream 419 * @param force If true, set the volume even if the desired volume is same 420 * as the current volume. 421 * @param lastAudible If true, stores new index as last audible one 422 */ 423 private void setStreamVolumeInt(int streamType, int index, boolean force, boolean lastAudible) { 424 VolumeStreamState streamState = mStreamStates[streamType]; 425 if (streamState.setIndex(index, lastAudible) || force) { 426 // Post message to set system volume (it in turn will post a message 427 // to persist). Do not change volume if stream is muted. 428 if (streamState.muteCount() == 0) { 429 sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, streamType, SENDMSG_NOOP, 0, 0, 430 streamState, 0); 431 } 432 } 433 } 434 435 /** @see AudioManager#setStreamSolo(int, boolean) */ 436 public void setStreamSolo(int streamType, boolean state, IBinder cb) { 437 for (int stream = 0; stream < mStreamStates.length; stream++) { 438 if (!isStreamAffectedByMute(stream) || stream == streamType) continue; 439 // Bring back last audible volume 440 mStreamStates[stream].mute(cb, state); 441 } 442 } 443 444 /** @see AudioManager#setStreamMute(int, boolean) */ 445 public void setStreamMute(int streamType, boolean state, IBinder cb) { 446 if (isStreamAffectedByMute(streamType)) { 447 mStreamStates[streamType].mute(cb, state); 448 } 449 } 450 451 /** @see AudioManager#getStreamVolume(int) */ 452 public int getStreamVolume(int streamType) { 453 ensureValidStreamType(streamType); 454 return (mStreamStates[streamType].mIndex + 5) / 10; 455 } 456 457 /** @see AudioManager#getStreamMaxVolume(int) */ 458 public int getStreamMaxVolume(int streamType) { 459 ensureValidStreamType(streamType); 460 return (mStreamStates[streamType].getMaxIndex() + 5) / 10; 461 } 462 463 /** @see AudioManager#getRingerMode() */ 464 public int getRingerMode() { 465 return mRingerMode; 466 } 467 468 /** @see AudioManager#setRingerMode(int) */ 469 public void setRingerMode(int ringerMode) { 470 synchronized (mSettingsLock) { 471 if (ringerMode != mRingerMode) { 472 setRingerModeInt(ringerMode, true); 473 // Send sticky broadcast 474 broadcastRingerMode(); 475 } 476 } 477 } 478 479 private void setRingerModeInt(int ringerMode, boolean persist) { 480 mRingerMode = ringerMode; 481 482 // Adjust volumes via posting message 483 int numStreamTypes = AudioSystem.getNumStreamTypes(); 484 if (mRingerMode == AudioManager.RINGER_MODE_NORMAL) { 485 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 486 if (!isStreamAffectedByRingerMode(streamType)) continue; 487 // Bring back last audible volume 488 setStreamVolumeInt(streamType, mStreamStates[streamType].mLastAudibleIndex, 489 false, false); 490 } 491 } else { 492 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 493 if (isStreamAffectedByRingerMode(streamType)) { 494 // Either silent or vibrate, either way volume is 0 495 setStreamVolumeInt(streamType, 0, false, false); 496 } else { 497 // restore stream volume in the case the stream changed from affected 498 // to non affected by ringer mode. Does not arm to do it for streams that 499 // are not affected as well. 500 setStreamVolumeInt(streamType, mStreamStates[streamType].mLastAudibleIndex, 501 false, false); 502 } 503 } 504 } 505 506 // Post a persist ringer mode msg 507 if (persist) { 508 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE, SHARED_MSG, 509 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY); 510 } 511 } 512 513 /** @see AudioManager#shouldVibrate(int) */ 514 public boolean shouldVibrate(int vibrateType) { 515 516 switch (getVibrateSetting(vibrateType)) { 517 518 case AudioManager.VIBRATE_SETTING_ON: 519 return mRingerMode != AudioManager.RINGER_MODE_SILENT; 520 521 case AudioManager.VIBRATE_SETTING_ONLY_SILENT: 522 return mRingerMode == AudioManager.RINGER_MODE_VIBRATE; 523 524 case AudioManager.VIBRATE_SETTING_OFF: 525 // Phone ringer should always vibrate in vibrate mode 526 if (vibrateType == AudioManager.VIBRATE_TYPE_RINGER) { 527 return mRingerMode == AudioManager.RINGER_MODE_VIBRATE; 528 } 529 530 default: 531 return false; 532 } 533 } 534 535 /** @see AudioManager#getVibrateSetting(int) */ 536 public int getVibrateSetting(int vibrateType) { 537 return (mVibrateSetting >> (vibrateType * 2)) & 3; 538 } 539 540 /** @see AudioManager#setVibrateSetting(int, int) */ 541 public void setVibrateSetting(int vibrateType, int vibrateSetting) { 542 543 mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting); 544 545 // Broadcast change 546 broadcastVibrateSetting(vibrateType); 547 548 // Post message to set ringer mode (it in turn will post a message 549 // to persist) 550 sendMsg(mAudioHandler, MSG_PERSIST_VIBRATE_SETTING, SHARED_MSG, SENDMSG_NOOP, 0, 0, 551 null, 0); 552 } 553 554 /** 555 * @see #setVibrateSetting(int, int) 556 */ 557 public static int getValueForVibrateSetting(int existingValue, int vibrateType, 558 int vibrateSetting) { 559 560 // First clear the existing setting. Each vibrate type has two bits in 561 // the value. Note '3' is '11' in binary. 562 existingValue &= ~(3 << (vibrateType * 2)); 563 564 // Set into the old value 565 existingValue |= (vibrateSetting & 3) << (vibrateType * 2); 566 567 return existingValue; 568 } 569 570 /** @see AudioManager#setMode(int) */ 571 public void setMode(int mode) { 572 if (!checkAudioSettingsPermission("setMode()")) { 573 return; 574 } 575 576 if (mode < AudioSystem.MODE_CURRENT || mode > AudioSystem.MODE_IN_CALL) { 577 return; 578 } 579 580 synchronized (mSettingsLock) { 581 if (mode == AudioSystem.MODE_CURRENT) { 582 mode = mMode; 583 } 584 if (mode != mMode) { 585 if (AudioSystem.setPhoneState(mode) == AudioSystem.AUDIO_STATUS_OK) { 586 mMode = mode; 587 } 588 } 589 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE); 590 int index = mStreamStates[STREAM_VOLUME_ALIAS[streamType]].mIndex; 591 setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, true, true); 592 } 593 } 594 595 /** @see AudioManager#getMode() */ 596 public int getMode() { 597 return mMode; 598 } 599 600 /** @see AudioManager#playSoundEffect(int) */ 601 public void playSoundEffect(int effectType) { 602 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SHARED_MSG, SENDMSG_NOOP, 603 effectType, SOUND_EFFECT_VOLUME, null, 0); 604 } 605 606 /** @see AudioManager#playSoundEffect(int, float) */ 607 public void playSoundEffectVolume(int effectType, float volume) { 608 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SHARED_MSG, SENDMSG_NOOP, 609 effectType, (int) (volume * 1000), null, 0); 610 } 611 612 /** 613 * Loads samples into the soundpool. 614 * This method must be called at when sound effects are enabled 615 */ 616 public boolean loadSoundEffects() { 617 synchronized (mSoundEffectsLock) { 618 mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0); 619 if (mSoundPool == null) { 620 return false; 621 } 622 /* 623 * poolId table: The value -1 in this table indicates that corresponding 624 * file (same index in SOUND_EFFECT_FILES[] has not been loaded. 625 * Once loaded, the value in poolId is the sample ID and the same 626 * sample can be reused for another effect using the same file. 627 */ 628 int[] poolId = new int[SOUND_EFFECT_FILES.length]; 629 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) { 630 poolId[fileIdx] = -1; 631 } 632 /* 633 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded. 634 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0: 635 * this indicates we have a valid sample loaded for this effect. 636 */ 637 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) { 638 // Do not load sample if this effect uses the MediaPlayer 639 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) { 640 continue; 641 } 642 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) { 643 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effect][0]]; 644 int sampleId = mSoundPool.load(filePath, 0); 645 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId; 646 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId; 647 if (sampleId <= 0) { 648 Log.w(TAG, "Soundpool could not load file: "+filePath); 649 } 650 } else { 651 SOUND_EFFECT_FILES_MAP[effect][1] = poolId[SOUND_EFFECT_FILES_MAP[effect][0]]; 652 } 653 } 654 } 655 656 return true; 657 } 658 659 /** 660 * Unloads samples from the sound pool. 661 * This method can be called to free some memory when 662 * sound effects are disabled. 663 */ 664 public void unloadSoundEffects() { 665 synchronized (mSoundEffectsLock) { 666 if (mSoundPool == null) { 667 return; 668 } 669 int[] poolId = new int[SOUND_EFFECT_FILES.length]; 670 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) { 671 poolId[fileIdx] = 0; 672 } 673 674 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) { 675 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) { 676 continue; 677 } 678 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) { 679 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]); 680 SOUND_EFFECT_FILES_MAP[effect][1] = -1; 681 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1; 682 } 683 } 684 mSoundPool = null; 685 } 686 } 687 688 /** @see AudioManager#reloadAudioSettings() */ 689 public void reloadAudioSettings() { 690 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings 691 readPersistedSettings(); 692 693 // restore volume settings 694 int numStreamTypes = AudioSystem.getNumStreamTypes(); 695 for (int streamType = 0; streamType < numStreamTypes; streamType++) { 696 VolumeStreamState streamState = mStreamStates[streamType]; 697 698 String settingName = System.VOLUME_SETTINGS[STREAM_VOLUME_ALIAS[streamType]]; 699 String lastAudibleSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE; 700 int index = Settings.System.getInt(mContentResolver, 701 settingName, 702 AudioManager.DEFAULT_STREAM_VOLUME[streamType]); 703 if (STREAM_VOLUME_ALIAS[streamType] != streamType) { 704 index = rescaleIndex(index * 10, STREAM_VOLUME_ALIAS[streamType], streamType); 705 } else { 706 index *= 10; 707 } 708 streamState.mIndex = streamState.getValidIndex(index); 709 710 index = (index + 5) / 10; 711 index = Settings.System.getInt(mContentResolver, 712 lastAudibleSettingName, 713 (index > 0) ? index : AudioManager.DEFAULT_STREAM_VOLUME[streamType]); 714 if (STREAM_VOLUME_ALIAS[streamType] != streamType) { 715 index = rescaleIndex(index * 10, STREAM_VOLUME_ALIAS[streamType], streamType); 716 } else { 717 index *= 10; 718 } 719 streamState.mLastAudibleIndex = streamState.getValidIndex(index); 720 721 // unmute stream that whas muted but is not affect by mute anymore 722 if (streamState.muteCount() != 0 && !isStreamAffectedByMute(streamType)) { 723 int size = streamState.mDeathHandlers.size(); 724 for (int i = 0; i < size; i++) { 725 streamState.mDeathHandlers.get(i).mMuteCount = 1; 726 streamState.mDeathHandlers.get(i).mute(false); 727 } 728 } 729 // apply stream volume 730 if (streamState.muteCount() == 0) { 731 setStreamVolumeIndex(streamType, streamState.mIndex); 732 } 733 } 734 735 // apply new ringer mode 736 setRingerModeInt(getRingerMode(), false); 737 } 738 739 /** @see AudioManager#setSpeakerphoneOn() */ 740 public void setSpeakerphoneOn(boolean on){ 741 if (on) { 742 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_SPEAKER); 743 mForcedUseForComm = AudioSystem.FORCE_SPEAKER; 744 } else { 745 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE); 746 mForcedUseForComm = AudioSystem.FORCE_NONE; 747 } 748 } 749 750 /** @see AudioManager#isSpeakerphoneOn() */ 751 public boolean isSpeakerphoneOn() { 752 if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER) { 753 return true; 754 } else { 755 return false; 756 } 757 } 758 759 /** @see AudioManager#setBluetoothScoOn() */ 760 public void setBluetoothScoOn(boolean on){ 761 if (on) { 762 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_BT_SCO); 763 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, AudioSystem.FORCE_BT_SCO); 764 mForcedUseForComm = AudioSystem.FORCE_BT_SCO; 765 } else { 766 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE); 767 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE); 768 mForcedUseForComm = AudioSystem.FORCE_NONE; 769 } 770 } 771 772 /** @see AudioManager#isBluetoothScoOn() */ 773 public boolean isBluetoothScoOn() { 774 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) { 775 return true; 776 } else { 777 return false; 778 } 779 } 780 781 /////////////////////////////////////////////////////////////////////////// 782 // Internal methods 783 /////////////////////////////////////////////////////////////////////////// 784 785 /** 786 * Checks if the adjustment should change ringer mode instead of just 787 * adjusting volume. If so, this will set the proper ringer mode and volume 788 * indices on the stream states. 789 */ 790 private boolean checkForRingerModeChange(int oldIndex, int direction) { 791 boolean adjustVolumeIndex = true; 792 int newRingerMode = mRingerMode; 793 794 if (mRingerMode == AudioManager.RINGER_MODE_NORMAL && (oldIndex + 5) / 10 == 1 795 && direction == AudioManager.ADJUST_LOWER) { 796 newRingerMode = AudioManager.RINGER_MODE_VIBRATE; 797 } else if (mRingerMode == AudioManager.RINGER_MODE_VIBRATE) { 798 if (direction == AudioManager.ADJUST_RAISE) { 799 newRingerMode = AudioManager.RINGER_MODE_NORMAL; 800 } else if (direction == AudioManager.ADJUST_LOWER) { 801 newRingerMode = AudioManager.RINGER_MODE_SILENT; 802 } 803 } else if (direction == AudioManager.ADJUST_RAISE 804 && mRingerMode == AudioManager.RINGER_MODE_SILENT) { 805 newRingerMode = AudioManager.RINGER_MODE_VIBRATE; 806 } 807 808 if (newRingerMode != mRingerMode) { 809 setRingerMode(newRingerMode); 810 811 /* 812 * If we are changing ringer modes, do not increment/decrement the 813 * volume index. Instead, the handler for the message above will 814 * take care of changing the index. 815 */ 816 adjustVolumeIndex = false; 817 } 818 819 return adjustVolumeIndex; 820 } 821 822 public boolean isStreamAffectedByRingerMode(int streamType) { 823 return (mRingerModeAffectedStreams & (1 << streamType)) != 0; 824 } 825 826 public boolean isStreamAffectedByMute(int streamType) { 827 return (mMuteAffectedStreams & (1 << streamType)) != 0; 828 } 829 830 private void ensureValidDirection(int direction) { 831 if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) { 832 throw new IllegalArgumentException("Bad direction " + direction); 833 } 834 } 835 836 private void ensureValidStreamType(int streamType) { 837 if (streamType < 0 || streamType >= mStreamStates.length) { 838 throw new IllegalArgumentException("Bad stream type " + streamType); 839 } 840 } 841 842 private int getActiveStreamType(int suggestedStreamType) { 843 boolean isOffhook = false; 844 try { 845 ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); 846 if (phone != null) isOffhook = phone.isOffhook(); 847 } catch (RemoteException e) { 848 Log.w(TAG, "Couldn't connect to phone service", e); 849 } 850 851 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) == AudioSystem.FORCE_BT_SCO) { 852 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO..."); 853 return AudioSystem.STREAM_BLUETOOTH_SCO; 854 } else if (isOffhook) { 855 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL..."); 856 return AudioSystem.STREAM_VOICE_CALL; 857 } else if (AudioSystem.isMusicActive()) { 858 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC..."); 859 return AudioSystem.STREAM_MUSIC; 860 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { 861 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING..."); 862 return AudioSystem.STREAM_RING; 863 } else { 864 // Log.v(TAG, "getActiveStreamType: Returning suggested type " + suggestedStreamType); 865 return suggestedStreamType; 866 } 867 } 868 869 private void broadcastRingerMode() { 870 // Send sticky broadcast 871 if (ActivityManagerNative.isSystemReady()) { 872 Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION); 873 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, mRingerMode); 874 long origCallerIdentityToken = Binder.clearCallingIdentity(); 875 mContext.sendStickyBroadcast(broadcast); 876 Binder.restoreCallingIdentity(origCallerIdentityToken); 877 } 878 } 879 880 private void broadcastVibrateSetting(int vibrateType) { 881 // Send broadcast 882 if (ActivityManagerNative.isSystemReady()) { 883 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION); 884 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType); 885 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType)); 886 mContext.sendBroadcast(broadcast); 887 } 888 } 889 890 // Message helper methods 891 private static int getMsg(int baseMsg, int streamType) { 892 return (baseMsg & 0xffff) | streamType << 16; 893 } 894 895 private static int getMsgBase(int msg) { 896 return msg & 0xffff; 897 } 898 899 private static void sendMsg(Handler handler, int baseMsg, int streamType, 900 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) { 901 int msg = (streamType == SHARED_MSG) ? baseMsg : getMsg(baseMsg, streamType); 902 903 if (existingMsgPolicy == SENDMSG_REPLACE) { 904 handler.removeMessages(msg); 905 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) { 906 return; 907 } 908 909 handler 910 .sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay); 911 } 912 913 boolean checkAudioSettingsPermission(String method) { 914 if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS") 915 == PackageManager.PERMISSION_GRANTED) { 916 return true; 917 } 918 String msg = "Audio Settings Permission Denial: " + method + " from pid=" 919 + Binder.getCallingPid() 920 + ", uid=" + Binder.getCallingUid(); 921 Log.w(TAG, msg); 922 return false; 923 } 924 925 926 /////////////////////////////////////////////////////////////////////////// 927 // Inner classes 928 /////////////////////////////////////////////////////////////////////////// 929 930 public class VolumeStreamState { 931 private final String mVolumeIndexSettingName; 932 private final String mLastAudibleVolumeIndexSettingName; 933 private final int mStreamType; 934 935 private int mIndexMax; 936 private int mIndex; 937 private int mLastAudibleIndex; 938 private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo requests client death 939 940 private VolumeStreamState(String settingName, int streamType) { 941 942 mVolumeIndexSettingName = settingName; 943 mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE; 944 945 mStreamType = streamType; 946 947 final ContentResolver cr = mContentResolver; 948 mIndexMax = AudioManager.MAX_STREAM_VOLUME[streamType]; 949 mIndex = Settings.System.getInt(cr, 950 mVolumeIndexSettingName, 951 AudioManager.DEFAULT_STREAM_VOLUME[streamType]); 952 mLastAudibleIndex = Settings.System.getInt(cr, 953 mLastAudibleVolumeIndexSettingName, 954 (mIndex > 0) ? mIndex : AudioManager.DEFAULT_STREAM_VOLUME[streamType]); 955 AudioSystem.initStreamVolume(streamType, 0, mIndexMax); 956 mIndexMax *= 10; 957 mIndex = getValidIndex(10 * mIndex); 958 mLastAudibleIndex = getValidIndex(10 * mLastAudibleIndex); 959 setStreamVolumeIndex(streamType, mIndex); 960 mDeathHandlers = new ArrayList<VolumeDeathHandler>(); 961 } 962 963 public boolean adjustIndex(int deltaIndex) { 964 return setIndex(mIndex + deltaIndex * 10, true); 965 } 966 967 public boolean setIndex(int index, boolean lastAudible) { 968 int oldIndex = mIndex; 969 mIndex = getValidIndex(index); 970 971 if (oldIndex != mIndex) { 972 if (lastAudible) { 973 mLastAudibleIndex = mIndex; 974 } 975 // Apply change to all streams using this one as alias 976 int numStreamTypes = AudioSystem.getNumStreamTypes(); 977 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 978 if (streamType != mStreamType && STREAM_VOLUME_ALIAS[streamType] == mStreamType) { 979 mStreamStates[streamType].setIndex(rescaleIndex(mIndex, mStreamType, streamType), lastAudible); 980 } 981 } 982 return true; 983 } else { 984 return false; 985 } 986 } 987 988 public int getMaxIndex() { 989 return mIndexMax; 990 } 991 992 public void mute(IBinder cb, boolean state) { 993 VolumeDeathHandler handler = getDeathHandler(cb, state); 994 if (handler == null) { 995 Log.e(TAG, "Could not get client death handler for stream: "+mStreamType); 996 return; 997 } 998 handler.mute(state); 999 } 1000 1001 private int getValidIndex(int index) { 1002 if (index < 0) { 1003 return 0; 1004 } else if (index > mIndexMax) { 1005 return mIndexMax; 1006 } 1007 1008 return index; 1009 } 1010 1011 private class VolumeDeathHandler implements IBinder.DeathRecipient { 1012 private IBinder mICallback; // To be notified of client's death 1013 private int mMuteCount; // Number of active mutes for this client 1014 1015 VolumeDeathHandler(IBinder cb) { 1016 mICallback = cb; 1017 } 1018 1019 public void mute(boolean state) { 1020 synchronized(mDeathHandlers) { 1021 if (state) { 1022 if (mMuteCount == 0) { 1023 // Register for client death notification 1024 try { 1025 mICallback.linkToDeath(this, 0); 1026 mDeathHandlers.add(this); 1027 // If the stream is not yet muted by any client, set lvel to 0 1028 if (muteCount() == 0) { 1029 setIndex(0, false); 1030 sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, mStreamType, SENDMSG_NOOP, 0, 0, 1031 VolumeStreamState.this, 0); 1032 } 1033 } catch (RemoteException e) { 1034 // Client has died! 1035 binderDied(); 1036 mDeathHandlers.notify(); 1037 return; 1038 } 1039 } else { 1040 Log.w(TAG, "stream: "+mStreamType+" was already muted by this client"); 1041 } 1042 mMuteCount++; 1043 } else { 1044 if (mMuteCount == 0) { 1045 Log.e(TAG, "unexpected unmute for stream: "+mStreamType); 1046 } else { 1047 mMuteCount--; 1048 if (mMuteCount == 0) { 1049 // Unregistr from client death notification 1050 mDeathHandlers.remove(this); 1051 mICallback.unlinkToDeath(this, 0); 1052 if (muteCount() == 0) { 1053 // If the stream is not mut any more, restore it's volume if 1054 // ringer mode allows it 1055 if (!isStreamAffectedByRingerMode(mStreamType) || mRingerMode == AudioManager.RINGER_MODE_NORMAL) { 1056 setIndex(mLastAudibleIndex, false); 1057 sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, mStreamType, SENDMSG_NOOP, 0, 0, 1058 VolumeStreamState.this, 0); 1059 } 1060 } 1061 } 1062 } 1063 } 1064 mDeathHandlers.notify(); 1065 } 1066 } 1067 1068 public void binderDied() { 1069 Log.w(TAG, "Volume service client died for stream: "+mStreamType); 1070 if (mMuteCount != 0) { 1071 // Reset all active mute requests from this client. 1072 mMuteCount = 1; 1073 mute(false); 1074 } 1075 } 1076 } 1077 1078 private int muteCount() { 1079 int count = 0; 1080 int size = mDeathHandlers.size(); 1081 for (int i = 0; i < size; i++) { 1082 count += mDeathHandlers.get(i).mMuteCount; 1083 } 1084 return count; 1085 } 1086 1087 private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) { 1088 synchronized(mDeathHandlers) { 1089 VolumeDeathHandler handler; 1090 int size = mDeathHandlers.size(); 1091 for (int i = 0; i < size; i++) { 1092 handler = mDeathHandlers.get(i); 1093 if (cb.equals(handler.mICallback)) { 1094 return handler; 1095 } 1096 } 1097 // If this is the first mute request for this client, create a new 1098 // client death handler. Otherwise, it is an out of sequence unmute request. 1099 if (state) { 1100 handler = new VolumeDeathHandler(cb); 1101 } else { 1102 Log.w(TAG, "stream was not muted by this client"); 1103 handler = null; 1104 } 1105 return handler; 1106 } 1107 } 1108 } 1109 1110 /** Thread that handles native AudioSystem control. */ 1111 private class AudioSystemThread extends Thread { 1112 AudioSystemThread() { 1113 super("AudioService"); 1114 } 1115 1116 @Override 1117 public void run() { 1118 // Set this thread up so the handler will work on it 1119 Looper.prepare(); 1120 1121 synchronized(AudioService.this) { 1122 mAudioHandler = new AudioHandler(); 1123 1124 // Notify that the handler has been created 1125 AudioService.this.notify(); 1126 } 1127 1128 // Listen for volume change requests that are set by VolumePanel 1129 Looper.loop(); 1130 } 1131 } 1132 1133 /** Handles internal volume messages in separate volume thread. */ 1134 private class AudioHandler extends Handler { 1135 1136 private void setSystemVolume(VolumeStreamState streamState) { 1137 1138 // Adjust volume 1139 setStreamVolumeIndex(streamState.mStreamType, streamState.mIndex); 1140 1141 // Apply change to all streams using this one as alias 1142 int numStreamTypes = AudioSystem.getNumStreamTypes(); 1143 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 1144 if (streamType != streamState.mStreamType && 1145 STREAM_VOLUME_ALIAS[streamType] == streamState.mStreamType) { 1146 setStreamVolumeIndex(streamType, mStreamStates[streamType].mIndex); 1147 } 1148 } 1149 1150 // Post a persist volume msg 1151 sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamState.mStreamType, 1152 SENDMSG_REPLACE, 0, 0, streamState, PERSIST_DELAY); 1153 } 1154 1155 private void persistVolume(VolumeStreamState streamState) { 1156 System.putInt(mContentResolver, streamState.mVolumeIndexSettingName, 1157 (streamState.mIndex + 5)/ 10); 1158 System.putInt(mContentResolver, streamState.mLastAudibleVolumeIndexSettingName, 1159 (streamState.mLastAudibleIndex + 5) / 10); 1160 } 1161 1162 private void persistRingerMode() { 1163 System.putInt(mContentResolver, System.MODE_RINGER, mRingerMode); 1164 } 1165 1166 private void persistVibrateSetting() { 1167 System.putInt(mContentResolver, System.VIBRATE_ON, mVibrateSetting); 1168 } 1169 1170 private void playSoundEffect(int effectType, int volume) { 1171 synchronized (mSoundEffectsLock) { 1172 if (mSoundPool == null) { 1173 return; 1174 } 1175 1176 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) { 1177 float v = (float) volume / 1000.0f; 1178 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1], v, v, 0, 0, 1.0f); 1179 } else { 1180 MediaPlayer mediaPlayer = new MediaPlayer(); 1181 if (mediaPlayer != null) { 1182 try { 1183 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effectType][0]]; 1184 mediaPlayer.setDataSource(filePath); 1185 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM); 1186 mediaPlayer.prepare(); 1187 mediaPlayer.setOnCompletionListener(new OnCompletionListener() { 1188 public void onCompletion(MediaPlayer mp) { 1189 cleanupPlayer(mp); 1190 } 1191 }); 1192 mediaPlayer.setOnErrorListener(new OnErrorListener() { 1193 public boolean onError(MediaPlayer mp, int what, int extra) { 1194 cleanupPlayer(mp); 1195 return true; 1196 } 1197 }); 1198 mediaPlayer.start(); 1199 } catch (IOException ex) { 1200 Log.w(TAG, "MediaPlayer IOException: "+ex); 1201 } catch (IllegalArgumentException ex) { 1202 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex); 1203 } catch (IllegalStateException ex) { 1204 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex); 1205 } 1206 } 1207 } 1208 } 1209 } 1210 1211 private void cleanupPlayer(MediaPlayer mp) { 1212 if (mp != null) { 1213 try { 1214 mp.stop(); 1215 mp.release(); 1216 } catch (IllegalStateException ex) { 1217 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex); 1218 } 1219 } 1220 } 1221 1222 @Override 1223 public void handleMessage(Message msg) { 1224 int baseMsgWhat = getMsgBase(msg.what); 1225 1226 switch (baseMsgWhat) { 1227 1228 case MSG_SET_SYSTEM_VOLUME: 1229 setSystemVolume((VolumeStreamState) msg.obj); 1230 break; 1231 1232 case MSG_PERSIST_VOLUME: 1233 persistVolume((VolumeStreamState) msg.obj); 1234 break; 1235 1236 case MSG_PERSIST_RINGER_MODE: 1237 persistRingerMode(); 1238 break; 1239 1240 case MSG_PERSIST_VIBRATE_SETTING: 1241 persistVibrateSetting(); 1242 break; 1243 1244 case MSG_MEDIA_SERVER_DIED: 1245 Log.e(TAG, "Media server died."); 1246 // Force creation of new IAudioflinger interface 1247 mMediaServerOk = false; 1248 AudioSystem.isMusicActive(); 1249 break; 1250 1251 case MSG_MEDIA_SERVER_STARTED: 1252 Log.e(TAG, "Media server started."); 1253 // Restore device connection states 1254 Set set = mConnectedDevices.entrySet(); 1255 Iterator i = set.iterator(); 1256 while(i.hasNext()){ 1257 Map.Entry device = (Map.Entry)i.next(); 1258 AudioSystem.setDeviceConnectionState(((Integer)device.getKey()).intValue(), 1259 AudioSystem.DEVICE_STATE_AVAILABLE, 1260 (String)device.getValue()); 1261 } 1262 1263 // Restore call state 1264 AudioSystem.setPhoneState(mMode); 1265 1266 // Restore forced usage for communcations and record 1267 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm); 1268 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm); 1269 1270 // Restore stream volumes 1271 int numStreamTypes = AudioSystem.getNumStreamTypes(); 1272 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 1273 int index; 1274 VolumeStreamState streamState = mStreamStates[streamType]; 1275 AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10); 1276 if (streamState.muteCount() == 0) { 1277 index = streamState.mIndex; 1278 } else { 1279 index = 0; 1280 } 1281 setStreamVolumeIndex(streamType, index); 1282 } 1283 1284 // Restore ringer mode 1285 setRingerModeInt(getRingerMode(), false); 1286 1287 mMediaServerOk = true; 1288 break; 1289 1290 case MSG_PLAY_SOUND_EFFECT: 1291 playSoundEffect(msg.arg1, msg.arg2); 1292 break; 1293 } 1294 } 1295 } 1296 1297 private class SettingsObserver extends ContentObserver { 1298 1299 SettingsObserver() { 1300 super(new Handler()); 1301 mContentResolver.registerContentObserver(Settings.System.getUriFor( 1302 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this); 1303 mContentResolver.registerContentObserver(Settings.System.getUriFor( 1304 Settings.System.NOTIFICATIONS_USE_RING_VOLUME), false, this); 1305 } 1306 1307 @Override 1308 public void onChange(boolean selfChange) { 1309 super.onChange(selfChange); 1310 synchronized (mSettingsLock) { 1311 int ringerModeAffectedStreams = Settings.System.getInt(mContentResolver, 1312 Settings.System.MODE_RINGER_STREAMS_AFFECTED, 1313 0); 1314 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) { 1315 /* 1316 * Ensure all stream types that should be affected by ringer mode 1317 * are in the proper state. 1318 */ 1319 mRingerModeAffectedStreams = ringerModeAffectedStreams; 1320 setRingerModeInt(getRingerMode(), false); 1321 } 1322 1323 int notificationsUseRingVolume = Settings.System.getInt(mContentResolver, 1324 Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1325 1); 1326 if (notificationsUseRingVolume != mNotificationsUseRingVolume) { 1327 mNotificationsUseRingVolume = notificationsUseRingVolume; 1328 if (mNotificationsUseRingVolume == 1) { 1329 STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_RING; 1330 } else { 1331 STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_NOTIFICATION; 1332 // Persist notification volume volume as it was not persisted while aliased to ring volume 1333 sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, AudioSystem.STREAM_NOTIFICATION, 1334 SENDMSG_REPLACE, 0, 0, mStreamStates[AudioSystem.STREAM_NOTIFICATION], PERSIST_DELAY); 1335 } 1336 } 1337 } 1338 } 1339 } 1340 1341 /** 1342 * Receiver for misc intent broadcasts the Phone app cares about. 1343 */ 1344 private class AudioServiceBroadcastReceiver extends BroadcastReceiver { 1345 @Override 1346 public void onReceive(Context context, Intent intent) { 1347 String action = intent.getAction(); 1348 1349 if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) { 1350 int state = intent.getIntExtra(BluetoothA2dp.SINK_STATE, 1351 BluetoothA2dp.STATE_DISCONNECTED); 1352 String address = intent.getStringExtra(BluetoothIntent.ADDRESS); 1353 1354 boolean isConnected = (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) && 1355 ((String)mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)).equals(address)); 1356 1357 if (isConnected && 1358 state != BluetoothA2dp.STATE_CONNECTED && state != BluetoothA2dp.STATE_PLAYING) { 1359 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 1360 AudioSystem.DEVICE_STATE_UNAVAILABLE, 1361 address); 1362 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP); 1363 } else if (!isConnected && 1364 (state == BluetoothA2dp.STATE_CONNECTED || state != BluetoothA2dp.STATE_PLAYING)){ 1365 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 1366 AudioSystem.DEVICE_STATE_AVAILABLE, 1367 address); 1368 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP), address); 1369 } 1370 } else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) { 1371 int state = intent.getIntExtra(BluetoothIntent.HEADSET_STATE, 1372 BluetoothHeadset.STATE_ERROR); 1373 String address = intent.getStringExtra(BluetoothIntent.ADDRESS); 1374 int device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO; 1375 if (mBluetoothDevice == null) { 1376 mBluetoothDevice = (BluetoothDevice)mContext.getSystemService(Context.BLUETOOTH_SERVICE); 1377 } 1378 if (mBluetoothDevice != null) { 1379 int btClass = mBluetoothDevice.getRemoteClass(address); 1380 if (BluetoothClass.Device.Major.getDeviceMajor(btClass) == BluetoothClass.Device.Major.AUDIO_VIDEO) { 1381 switch (BluetoothClass.Device.getDevice(btClass)) { 1382 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET: 1383 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE: 1384 device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET; 1385 break; 1386 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO: 1387 device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT; 1388 break; 1389 default: 1390 break; 1391 } 1392 } 1393 } 1394 1395 boolean isConnected = (mConnectedDevices.containsKey(device) && 1396 ((String)mConnectedDevices.get(device)).equals(address)); 1397 1398 if (isConnected && state != BluetoothHeadset.STATE_CONNECTED) { 1399 AudioSystem.setDeviceConnectionState(device, 1400 AudioSystem.DEVICE_STATE_UNAVAILABLE, 1401 address); 1402 mConnectedDevices.remove(device); 1403 } else if (!isConnected && state == BluetoothHeadset.STATE_CONNECTED) { 1404 AudioSystem.setDeviceConnectionState(device, 1405 AudioSystem.DEVICE_STATE_AVAILABLE, 1406 address); 1407 mConnectedDevices.put( new Integer(device), address); 1408 } 1409 } else if (action.equals(Intent.ACTION_HEADSET_PLUG)) { 1410 int state = intent.getIntExtra("state", 0); 1411 if ((state & BIT_HEADSET) == 0 && 1412 (mHeadsetState & BIT_HEADSET) != 0) { 1413 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET, 1414 AudioSystem.DEVICE_STATE_UNAVAILABLE, 1415 ""); 1416 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_WIRED_HEADSET); 1417 } else if ((state & BIT_HEADSET) != 0 && 1418 (mHeadsetState & BIT_HEADSET) == 0) { 1419 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET, 1420 AudioSystem.DEVICE_STATE_AVAILABLE, 1421 ""); 1422 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_WIRED_HEADSET), ""); 1423 } 1424 if ((state & BIT_HEADSET_NO_MIC) == 0 && 1425 (mHeadsetState & BIT_HEADSET_NO_MIC) != 0) { 1426 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE, 1427 AudioSystem.DEVICE_STATE_UNAVAILABLE, 1428 ""); 1429 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE); 1430 } else if ((state & BIT_HEADSET_NO_MIC) != 0 && 1431 (mHeadsetState & BIT_HEADSET_NO_MIC) == 0) { 1432 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE, 1433 AudioSystem.DEVICE_STATE_AVAILABLE, 1434 ""); 1435 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE), ""); 1436 } 1437 if ((state & BIT_TTY) == 0 && 1438 (mHeadsetState & BIT_TTY) != 0) { 1439 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_TTY, 1440 AudioSystem.DEVICE_STATE_UNAVAILABLE, 1441 ""); 1442 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_TTY); 1443 } else if ((state & BIT_TTY) != 0 && 1444 (mHeadsetState & BIT_TTY) == 0) { 1445 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_TTY, 1446 AudioSystem.DEVICE_STATE_AVAILABLE, 1447 ""); 1448 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_TTY), ""); 1449 } 1450 if ((state & BIT_FM_HEADSET) == 0 && 1451 (mHeadsetState & BIT_FM_HEADSET) != 0) { 1452 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_HEADPHONE, 1453 AudioSystem.DEVICE_STATE_UNAVAILABLE, 1454 ""); 1455 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_FM_HEADPHONE); 1456 } else if ((state & BIT_FM_HEADSET) != 0 && 1457 (mHeadsetState & BIT_FM_HEADSET) == 0) { 1458 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_HEADPHONE, 1459 AudioSystem.DEVICE_STATE_AVAILABLE, 1460 ""); 1461 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_FM_HEADPHONE), ""); 1462 } 1463 if ((state & BIT_FM_SPEAKER) == 0 && 1464 (mHeadsetState & BIT_FM_SPEAKER) != 0) { 1465 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_SPEAKER, 1466 AudioSystem.DEVICE_STATE_UNAVAILABLE, 1467 ""); 1468 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_FM_SPEAKER); 1469 } else if ((state & BIT_FM_SPEAKER) != 0 && 1470 (mHeadsetState & BIT_FM_SPEAKER) == 0) { 1471 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_SPEAKER, 1472 AudioSystem.DEVICE_STATE_AVAILABLE, 1473 ""); 1474 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_FM_SPEAKER), ""); 1475 } 1476 mHeadsetState = state; 1477 } 1478 } 1479 } 1480} 1481