AudioService.java revision 2930bb2d47be279dd228ba8c749c1e39e5da8be1
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.BroadcastReceiver; 21import android.content.ComponentName; 22import android.content.ContentResolver; 23import android.content.Context; 24import android.content.Intent; 25import android.content.IntentFilter; 26import android.bluetooth.BluetoothA2dp; 27import android.bluetooth.BluetoothClass; 28import android.bluetooth.BluetoothDevice; 29import android.bluetooth.BluetoothHeadset; 30import android.content.pm.PackageManager; 31import android.database.ContentObserver; 32import android.media.MediaPlayer.OnCompletionListener; 33import android.media.MediaPlayer.OnErrorListener; 34import android.os.Binder; 35import android.os.Environment; 36import android.os.Handler; 37import android.os.IBinder; 38import android.os.Looper; 39import android.os.Message; 40import android.os.RemoteException; 41import android.os.ServiceManager; 42import android.provider.Settings; 43import android.provider.Settings.System; 44import android.util.Log; 45import android.view.KeyEvent; 46import android.view.VolumePanel; 47import android.os.SystemProperties; 48 49import com.android.internal.telephony.ITelephony; 50 51import java.io.FileDescriptor; 52import java.io.IOException; 53import java.io.PrintWriter; 54import java.util.ArrayList; 55import java.util.HashMap; 56import java.util.Iterator; 57import java.util.Map; 58import java.util.Set; 59import java.util.Stack; 60 61/** 62 * The implementation of the volume manager service. 63 * <p> 64 * This implementation focuses on delivering a responsive UI. Most methods are 65 * asynchronous to external calls. For example, the task of setting a volume 66 * will update our internal state, but in a separate thread will set the system 67 * volume and later persist to the database. Similarly, setting the ringer mode 68 * will update the state and broadcast a change and in a separate thread later 69 * persist the ringer mode. 70 * 71 * @hide 72 */ 73public class AudioService extends IAudioService.Stub { 74 75 private static final String TAG = "AudioService"; 76 77 /** How long to delay before persisting a change in volume/ringer mode. */ 78 private static final int PERSIST_DELAY = 3000; 79 80 private Context mContext; 81 private ContentResolver mContentResolver; 82 83 84 /** The UI */ 85 private VolumePanel mVolumePanel; 86 87 // sendMsg() flags 88 /** Used when a message should be shared across all stream types. */ 89 private static final int SHARED_MSG = -1; 90 /** If the msg is already queued, replace it with this one. */ 91 private static final int SENDMSG_REPLACE = 0; 92 /** If the msg is already queued, ignore this one and leave the old. */ 93 private static final int SENDMSG_NOOP = 1; 94 /** If the msg is already queued, queue this one and leave the old. */ 95 private static final int SENDMSG_QUEUE = 2; 96 97 // AudioHandler message.whats 98 private static final int MSG_SET_SYSTEM_VOLUME = 0; 99 private static final int MSG_PERSIST_VOLUME = 1; 100 private static final int MSG_PERSIST_RINGER_MODE = 3; 101 private static final int MSG_PERSIST_VIBRATE_SETTING = 4; 102 private static final int MSG_MEDIA_SERVER_DIED = 5; 103 private static final int MSG_MEDIA_SERVER_STARTED = 6; 104 private static final int MSG_PLAY_SOUND_EFFECT = 7; 105 106 /** @see AudioSystemThread */ 107 private AudioSystemThread mAudioSystemThread; 108 /** @see AudioHandler */ 109 private AudioHandler mAudioHandler; 110 /** @see VolumeStreamState */ 111 private VolumeStreamState[] mStreamStates; 112 private SettingsObserver mSettingsObserver; 113 114 private int mMode; 115 private Object mSettingsLock = new Object(); 116 private boolean mMediaServerOk; 117 118 private SoundPool mSoundPool; 119 private Object mSoundEffectsLock = new Object(); 120 private static final int NUM_SOUNDPOOL_CHANNELS = 4; 121 private static final int SOUND_EFFECT_VOLUME = 1000; 122 123 /* Sound effect file names */ 124 private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/"; 125 private static final String[] SOUND_EFFECT_FILES = new String[] { 126 "Effect_Tick.ogg", 127 "KeypressStandard.ogg", 128 "KeypressSpacebar.ogg", 129 "KeypressDelete.ogg", 130 "KeypressReturn.ogg" 131 }; 132 133 /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to 134 * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect 135 * uses soundpool (second column) */ 136 private int[][] SOUND_EFFECT_FILES_MAP = new int[][] { 137 {0, -1}, // FX_KEY_CLICK 138 {0, -1}, // FX_FOCUS_NAVIGATION_UP 139 {0, -1}, // FX_FOCUS_NAVIGATION_DOWN 140 {0, -1}, // FX_FOCUS_NAVIGATION_LEFT 141 {0, -1}, // FX_FOCUS_NAVIGATION_RIGHT 142 {1, -1}, // FX_KEYPRESS_STANDARD 143 {2, -1}, // FX_KEYPRESS_SPACEBAR 144 {3, -1}, // FX_FOCUS_DELETE 145 {4, -1} // FX_FOCUS_RETURN 146 }; 147 148 /** @hide Maximum volume index values for audio streams */ 149 private int[] MAX_STREAM_VOLUME = new int[] { 150 5, // STREAM_VOICE_CALL 151 7, // STREAM_SYSTEM 152 7, // STREAM_RING 153 15, // STREAM_MUSIC 154 7, // STREAM_ALARM 155 7, // STREAM_NOTIFICATION 156 15, // STREAM_BLUETOOTH_SCO 157 7, // STREAM_SYSTEM_ENFORCED 158 15, // STREAM_DTMF 159 15 // STREAM_TTS 160 }; 161 /* STREAM_VOLUME_ALIAS[] indicates for each stream if it uses the volume settings 162 * of another stream: This avoids multiplying the volume settings for hidden 163 * stream types that follow other stream behavior for volume settings 164 * NOTE: do not create loops in aliases! */ 165 private int[] STREAM_VOLUME_ALIAS = new int[] { 166 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL 167 AudioSystem.STREAM_SYSTEM, // STREAM_SYSTEM 168 AudioSystem.STREAM_RING, // STREAM_RING 169 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC 170 AudioSystem.STREAM_ALARM, // STREAM_ALARM 171 AudioSystem.STREAM_NOTIFICATION, // STREAM_NOTIFICATION 172 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO 173 AudioSystem.STREAM_SYSTEM, // STREAM_SYSTEM_ENFORCED 174 AudioSystem.STREAM_VOICE_CALL, // STREAM_DTMF 175 AudioSystem.STREAM_MUSIC // STREAM_TTS 176 }; 177 178 private AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() { 179 public void onError(int error) { 180 switch (error) { 181 case AudioSystem.AUDIO_STATUS_SERVER_DIED: 182 if (mMediaServerOk) { 183 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SHARED_MSG, SENDMSG_NOOP, 0, 0, 184 null, 1500); 185 mMediaServerOk = false; 186 } 187 break; 188 case AudioSystem.AUDIO_STATUS_OK: 189 if (!mMediaServerOk) { 190 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_STARTED, SHARED_MSG, SENDMSG_NOOP, 0, 0, 191 null, 0); 192 mMediaServerOk = true; 193 } 194 break; 195 default: 196 break; 197 } 198 } 199 }; 200 201 /** 202 * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL}, 203 * {@link AudioManager#RINGER_MODE_SILENT}, or 204 * {@link AudioManager#RINGER_MODE_VIBRATE}. 205 */ 206 private int mRingerMode; 207 208 /** @see System#MODE_RINGER_STREAMS_AFFECTED */ 209 private int mRingerModeAffectedStreams; 210 211 // Streams currently muted by ringer mode 212 private int mRingerModeMutedStreams; 213 214 /** @see System#MUTE_STREAMS_AFFECTED */ 215 private int mMuteAffectedStreams; 216 217 /** 218 * Has multiple bits per vibrate type to indicate the type's vibrate 219 * setting. See {@link #setVibrateSetting(int, int)}. 220 * <p> 221 * NOTE: This is not the final decision of whether vibrate is on/off for the 222 * type since it depends on the ringer mode. See {@link #shouldVibrate(int)}. 223 */ 224 private int mVibrateSetting; 225 226 /** @see System#NOTIFICATIONS_USE_RING_VOLUME */ 227 private int mNotificationsUseRingVolume; 228 229 // Broadcast receiver for device connections intent broadcasts 230 private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver(); 231 232 // Broadcast receiver for media button broadcasts (separate from mReceiver to 233 // independently change its priority) 234 private final BroadcastReceiver mMediaButtonReceiver = new MediaButtonBroadcastReceiver(); 235 236 // Devices currently connected 237 private HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>(); 238 239 // Forced device usage for communications 240 private int mForcedUseForComm; 241 242 // List of binder death handlers for setMode() client processes. 243 // The last process to have called setMode() is at the top of the list. 244 private ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>(); 245 246 // List of clients having issued a SCO start request 247 private ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>(); 248 249 // BluetoothHeadset API to control SCO connection 250 private BluetoothHeadset mBluetoothHeadset; 251 252 // Bluetooth headset connection state 253 private boolean mBluetoothHeadsetConnected; 254 255 /////////////////////////////////////////////////////////////////////////// 256 // Construction 257 /////////////////////////////////////////////////////////////////////////// 258 259 /** @hide */ 260 public AudioService(Context context) { 261 mContext = context; 262 mContentResolver = context.getContentResolver(); 263 264 // Intialized volume 265 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = SystemProperties.getInt( 266 "ro.config.vc_call_vol_steps", 267 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]); 268 269 mVolumePanel = new VolumePanel(context, this); 270 mSettingsObserver = new SettingsObserver(); 271 mForcedUseForComm = AudioSystem.FORCE_NONE; 272 createAudioSystemThread(); 273 readPersistedSettings(); 274 createStreamStates(); 275 // Call setMode() to initialize mSetModeDeathHandlers 276 mMode = AudioSystem.MODE_INVALID; 277 setMode(AudioSystem.MODE_NORMAL, null); 278 mMediaServerOk = true; 279 AudioSystem.setErrorCallback(mAudioSystemCallback); 280 loadSoundEffects(); 281 282 mBluetoothHeadsetConnected = false; 283 mBluetoothHeadset = new BluetoothHeadset(context, 284 mBluetoothHeadsetServiceListener); 285 286 // Register for device connection intent broadcasts. 287 IntentFilter intentFilter = 288 new IntentFilter(Intent.ACTION_HEADSET_PLUG); 289 intentFilter.addAction(BluetoothA2dp.ACTION_SINK_STATE_CHANGED); 290 intentFilter.addAction(BluetoothHeadset.ACTION_STATE_CHANGED); 291 intentFilter.addAction(Intent.ACTION_DOCK_EVENT); 292 intentFilter.addAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED); 293 context.registerReceiver(mReceiver, intentFilter); 294 295 // Register for media button intent broadcasts. 296 intentFilter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON); 297 intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); 298 context.registerReceiver(mMediaButtonReceiver, intentFilter); 299 } 300 301 private void createAudioSystemThread() { 302 mAudioSystemThread = new AudioSystemThread(); 303 mAudioSystemThread.start(); 304 waitForAudioHandlerCreation(); 305 } 306 307 /** Waits for the volume handler to be created by the other thread. */ 308 private void waitForAudioHandlerCreation() { 309 synchronized(this) { 310 while (mAudioHandler == null) { 311 try { 312 // Wait for mAudioHandler to be set by the other thread 313 wait(); 314 } catch (InterruptedException e) { 315 Log.e(TAG, "Interrupted while waiting on volume handler."); 316 } 317 } 318 } 319 } 320 321 private void createStreamStates() { 322 int numStreamTypes = AudioSystem.getNumStreamTypes(); 323 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes]; 324 325 for (int i = 0; i < numStreamTypes; i++) { 326 streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[STREAM_VOLUME_ALIAS[i]], i); 327 } 328 329 // Correct stream index values for streams with aliases 330 for (int i = 0; i < numStreamTypes; i++) { 331 if (STREAM_VOLUME_ALIAS[i] != i) { 332 int index = rescaleIndex(streams[i].mIndex, STREAM_VOLUME_ALIAS[i], i); 333 streams[i].mIndex = streams[i].getValidIndex(index); 334 setStreamVolumeIndex(i, index); 335 index = rescaleIndex(streams[i].mLastAudibleIndex, STREAM_VOLUME_ALIAS[i], i); 336 streams[i].mLastAudibleIndex = streams[i].getValidIndex(index); 337 } 338 } 339 } 340 341 private void readPersistedSettings() { 342 final ContentResolver cr = mContentResolver; 343 344 mRingerMode = System.getInt(cr, System.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL); 345 346 mVibrateSetting = System.getInt(cr, System.VIBRATE_ON, 0); 347 348 mRingerModeAffectedStreams = Settings.System.getInt(cr, 349 Settings.System.MODE_RINGER_STREAMS_AFFECTED, 350 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)| 351 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED))); 352 353 mMuteAffectedStreams = System.getInt(cr, 354 System.MUTE_STREAMS_AFFECTED, 355 ((1 << AudioSystem.STREAM_MUSIC)|(1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_SYSTEM))); 356 357 mNotificationsUseRingVolume = System.getInt(cr, 358 Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1); 359 360 if (mNotificationsUseRingVolume == 1) { 361 STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_RING; 362 } 363 // Each stream will read its own persisted settings 364 365 // Broadcast the sticky intent 366 broadcastRingerMode(); 367 368 // Broadcast vibrate settings 369 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER); 370 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION); 371 } 372 373 private void setStreamVolumeIndex(int stream, int index) { 374 AudioSystem.setStreamVolumeIndex(stream, (index + 5)/10); 375 } 376 377 private int rescaleIndex(int index, int srcStream, int dstStream) { 378 return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex(); 379 } 380 381 /////////////////////////////////////////////////////////////////////////// 382 // IPC methods 383 /////////////////////////////////////////////////////////////////////////// 384 385 /** @see AudioManager#adjustVolume(int, int) */ 386 public void adjustVolume(int direction, int flags) { 387 adjustSuggestedStreamVolume(direction, AudioManager.USE_DEFAULT_STREAM_TYPE, flags); 388 } 389 390 /** @see AudioManager#adjustVolume(int, int, int) */ 391 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) { 392 393 int streamType = getActiveStreamType(suggestedStreamType); 394 395 // Don't play sound on other streams 396 if (streamType != AudioSystem.STREAM_RING && (flags & AudioManager.FLAG_PLAY_SOUND) != 0) { 397 flags &= ~AudioManager.FLAG_PLAY_SOUND; 398 } 399 400 adjustStreamVolume(streamType, direction, flags); 401 } 402 403 /** @see AudioManager#adjustStreamVolume(int, int, int) */ 404 public void adjustStreamVolume(int streamType, int direction, int flags) { 405 ensureValidDirection(direction); 406 ensureValidStreamType(streamType); 407 408 409 VolumeStreamState streamState = mStreamStates[STREAM_VOLUME_ALIAS[streamType]]; 410 final int oldIndex = (streamState.muteCount() != 0) ? streamState.mLastAudibleIndex : streamState.mIndex; 411 boolean adjustVolume = true; 412 413 // If either the client forces allowing ringer modes for this adjustment, 414 // or the stream type is one that is affected by ringer modes 415 if ((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0 416 || streamType == AudioSystem.STREAM_RING) { 417 // Check if the ringer mode changes with this volume adjustment. If 418 // it does, it will handle adjusting the volume, so we won't below 419 adjustVolume = checkForRingerModeChange(oldIndex, direction); 420 } 421 422 // If stream is muted, adjust last audible index only 423 int index; 424 if (streamState.muteCount() != 0) { 425 if (adjustVolume) { 426 streamState.adjustLastAudibleIndex(direction); 427 // Post a persist volume msg 428 sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamType, 429 SENDMSG_REPLACE, 0, 1, streamState, PERSIST_DELAY); 430 } 431 index = streamState.mLastAudibleIndex; 432 } else { 433 if (adjustVolume && streamState.adjustIndex(direction)) { 434 // Post message to set system volume (it in turn will post a message 435 // to persist). Do not change volume if stream is muted. 436 sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, STREAM_VOLUME_ALIAS[streamType], SENDMSG_NOOP, 0, 0, 437 streamState, 0); 438 } 439 index = streamState.mIndex; 440 } 441 // UI 442 mVolumePanel.postVolumeChanged(streamType, flags); 443 // Broadcast Intent 444 sendVolumeUpdate(streamType, oldIndex, index); 445 } 446 447 /** @see AudioManager#setStreamVolume(int, int, int) */ 448 public void setStreamVolume(int streamType, int index, int flags) { 449 ensureValidStreamType(streamType); 450 VolumeStreamState streamState = mStreamStates[STREAM_VOLUME_ALIAS[streamType]]; 451 452 final int oldIndex = (streamState.muteCount() != 0) ? streamState.mLastAudibleIndex : streamState.mIndex; 453 454 index = rescaleIndex(index * 10, streamType, STREAM_VOLUME_ALIAS[streamType]); 455 setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, false, true); 456 457 index = (streamState.muteCount() != 0) ? streamState.mLastAudibleIndex : streamState.mIndex; 458 459 // UI, etc. 460 mVolumePanel.postVolumeChanged(streamType, flags); 461 // Broadcast Intent 462 sendVolumeUpdate(streamType, oldIndex, index); 463 } 464 465 private void sendVolumeUpdate(int streamType, int oldIndex, int index) { 466 oldIndex = (oldIndex + 5) / 10; 467 index = (index + 5) / 10; 468 469 Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION); 470 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType); 471 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index); 472 intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex); 473 474 mContext.sendBroadcast(intent); 475 } 476 477 /** 478 * Sets the stream state's index, and posts a message to set system volume. 479 * This will not call out to the UI. Assumes a valid stream type. 480 * 481 * @param streamType Type of the stream 482 * @param index Desired volume index of the stream 483 * @param force If true, set the volume even if the desired volume is same 484 * as the current volume. 485 * @param lastAudible If true, stores new index as last audible one 486 */ 487 private void setStreamVolumeInt(int streamType, int index, boolean force, boolean lastAudible) { 488 VolumeStreamState streamState = mStreamStates[streamType]; 489 490 // If stream is muted, set last audible index only 491 if (streamState.muteCount() != 0) { 492 streamState.setLastAudibleIndex(index); 493 // Post a persist volume msg 494 sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamType, 495 SENDMSG_REPLACE, 0, 1, streamState, PERSIST_DELAY); 496 } else { 497 if (streamState.setIndex(index, lastAudible) || force) { 498 // Post message to set system volume (it in turn will post a message 499 // to persist). 500 // If we are in silent mode and stream is affected by ringer mode 501 // and the new volume is not 0, just persist the new volume but do not change 502 // current value 503 if (mRingerMode == AudioManager.RINGER_MODE_NORMAL || 504 !isStreamAffectedByRingerMode(streamType) || 505 index == 0) { 506 sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, streamType, SENDMSG_NOOP, 0, 0, 507 streamState, 0); 508 } else { 509 // Post a persist volume msg 510 sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamType, 511 SENDMSG_REPLACE, 0, 1, streamState, PERSIST_DELAY); 512 } 513 } 514 } 515 } 516 517 /** @see AudioManager#setStreamSolo(int, boolean) */ 518 public void setStreamSolo(int streamType, boolean state, IBinder cb) { 519 for (int stream = 0; stream < mStreamStates.length; stream++) { 520 if (!isStreamAffectedByMute(stream) || stream == streamType) continue; 521 // Bring back last audible volume 522 mStreamStates[stream].mute(cb, state); 523 } 524 } 525 526 /** @see AudioManager#setStreamMute(int, boolean) */ 527 public void setStreamMute(int streamType, boolean state, IBinder cb) { 528 if (isStreamAffectedByMute(streamType)) { 529 mStreamStates[streamType].mute(cb, state); 530 } 531 } 532 533 /** @see AudioManager#getStreamVolume(int) */ 534 public int getStreamVolume(int streamType) { 535 ensureValidStreamType(streamType); 536 return (mStreamStates[streamType].mIndex + 5) / 10; 537 } 538 539 /** @see AudioManager#getStreamMaxVolume(int) */ 540 public int getStreamMaxVolume(int streamType) { 541 ensureValidStreamType(streamType); 542 return (mStreamStates[streamType].getMaxIndex() + 5) / 10; 543 } 544 545 /** @see AudioManager#getRingerMode() */ 546 public int getRingerMode() { 547 return mRingerMode; 548 } 549 550 /** @see AudioManager#setRingerMode(int) */ 551 public void setRingerMode(int ringerMode) { 552 synchronized (mSettingsLock) { 553 if (ringerMode != mRingerMode) { 554 setRingerModeInt(ringerMode, true); 555 // Send sticky broadcast 556 broadcastRingerMode(); 557 } 558 } 559 } 560 561 private void setRingerModeInt(int ringerMode, boolean persist) { 562 mRingerMode = ringerMode; 563 564 // Mute stream if not previously muted by ringer mode and ringer mode 565 // is not RINGER_MODE_NORMAL and stream is affected by ringer mode. 566 // Unmute stream if previously muted by ringer mode and ringer mode 567 // is RINGER_MODE_NORMAL or stream is not affected by ringer mode. 568 int numStreamTypes = AudioSystem.getNumStreamTypes(); 569 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 570 if (isStreamMutedByRingerMode(streamType)) { 571 if (!isStreamAffectedByRingerMode(streamType) || 572 mRingerMode == AudioManager.RINGER_MODE_NORMAL) { 573 mStreamStates[streamType].mute(null, false); 574 mRingerModeMutedStreams &= ~(1 << streamType); 575 } 576 } else { 577 if (isStreamAffectedByRingerMode(streamType) && 578 mRingerMode != AudioManager.RINGER_MODE_NORMAL) { 579 mStreamStates[streamType].mute(null, true); 580 mRingerModeMutedStreams |= (1 << streamType); 581 } 582 } 583 } 584 585 // Post a persist ringer mode msg 586 if (persist) { 587 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE, SHARED_MSG, 588 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY); 589 } 590 } 591 592 /** @see AudioManager#shouldVibrate(int) */ 593 public boolean shouldVibrate(int vibrateType) { 594 595 switch (getVibrateSetting(vibrateType)) { 596 597 case AudioManager.VIBRATE_SETTING_ON: 598 return mRingerMode != AudioManager.RINGER_MODE_SILENT; 599 600 case AudioManager.VIBRATE_SETTING_ONLY_SILENT: 601 return mRingerMode == AudioManager.RINGER_MODE_VIBRATE; 602 603 case AudioManager.VIBRATE_SETTING_OFF: 604 // Phone ringer should always vibrate in vibrate mode 605 if (vibrateType == AudioManager.VIBRATE_TYPE_RINGER) { 606 return mRingerMode == AudioManager.RINGER_MODE_VIBRATE; 607 } 608 609 default: 610 return false; 611 } 612 } 613 614 /** @see AudioManager#getVibrateSetting(int) */ 615 public int getVibrateSetting(int vibrateType) { 616 return (mVibrateSetting >> (vibrateType * 2)) & 3; 617 } 618 619 /** @see AudioManager#setVibrateSetting(int, int) */ 620 public void setVibrateSetting(int vibrateType, int vibrateSetting) { 621 622 mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting); 623 624 // Broadcast change 625 broadcastVibrateSetting(vibrateType); 626 627 // Post message to set ringer mode (it in turn will post a message 628 // to persist) 629 sendMsg(mAudioHandler, MSG_PERSIST_VIBRATE_SETTING, SHARED_MSG, SENDMSG_NOOP, 0, 0, 630 null, 0); 631 } 632 633 /** 634 * @see #setVibrateSetting(int, int) 635 */ 636 public static int getValueForVibrateSetting(int existingValue, int vibrateType, 637 int vibrateSetting) { 638 639 // First clear the existing setting. Each vibrate type has two bits in 640 // the value. Note '3' is '11' in binary. 641 existingValue &= ~(3 << (vibrateType * 2)); 642 643 // Set into the old value 644 existingValue |= (vibrateSetting & 3) << (vibrateType * 2); 645 646 return existingValue; 647 } 648 649 private class SetModeDeathHandler implements IBinder.DeathRecipient { 650 private IBinder mCb; // To be notified of client's death 651 private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client 652 653 SetModeDeathHandler(IBinder cb) { 654 mCb = cb; 655 } 656 657 public void binderDied() { 658 synchronized(mSetModeDeathHandlers) { 659 Log.w(TAG, "setMode() client died"); 660 int index = mSetModeDeathHandlers.indexOf(this); 661 if (index < 0) { 662 Log.w(TAG, "unregistered setMode() client died"); 663 } else { 664 mSetModeDeathHandlers.remove(this); 665 // If dead client was a the top of client list, 666 // apply next mode in the stack 667 if (index == 0) { 668 // mSetModeDeathHandlers is never empty as the initial entry 669 // created when AudioService starts is never removed 670 SetModeDeathHandler hdlr = mSetModeDeathHandlers.get(0); 671 int mode = hdlr.getMode(); 672 if (AudioService.this.mMode != mode) { 673 if (AudioSystem.setPhoneState(mode) == AudioSystem.AUDIO_STATUS_OK) { 674 AudioService.this.mMode = mode; 675 } 676 } 677 } 678 } 679 } 680 } 681 682 public void setMode(int mode) { 683 mMode = mode; 684 } 685 686 public int getMode() { 687 return mMode; 688 } 689 690 public IBinder getBinder() { 691 return mCb; 692 } 693 } 694 695 /** @see AudioManager#setMode(int) */ 696 public void setMode(int mode, IBinder cb) { 697 if (!checkAudioSettingsPermission("setMode()")) { 698 return; 699 } 700 701 if (mode < AudioSystem.MODE_CURRENT || mode > AudioSystem.MODE_IN_CALL) { 702 return; 703 } 704 705 synchronized (mSettingsLock) { 706 if (mode == AudioSystem.MODE_CURRENT) { 707 mode = mMode; 708 } 709 if (mode != mMode) { 710 if (AudioSystem.setPhoneState(mode) == AudioSystem.AUDIO_STATUS_OK) { 711 checkForUndispatchedAudioFocusChange(mMode, mode); 712 mMode = mode; 713 714 synchronized(mSetModeDeathHandlers) { 715 SetModeDeathHandler hdlr = null; 716 Iterator iter = mSetModeDeathHandlers.iterator(); 717 while (iter.hasNext()) { 718 SetModeDeathHandler h = (SetModeDeathHandler)iter.next(); 719 if (h.getBinder() == cb) { 720 hdlr = h; 721 // Remove from client list so that it is re-inserted at top of list 722 iter.remove(); 723 break; 724 } 725 } 726 if (hdlr == null) { 727 hdlr = new SetModeDeathHandler(cb); 728 // cb is null when setMode() is called by AudioService constructor 729 if (cb != null) { 730 // Register for client death notification 731 try { 732 cb.linkToDeath(hdlr, 0); 733 } catch (RemoteException e) { 734 // Client has died! 735 Log.w(TAG, "setMode() could not link to "+cb+" binder death"); 736 } 737 } 738 } 739 // Last client to call setMode() is always at top of client list 740 // as required by SetModeDeathHandler.binderDied() 741 mSetModeDeathHandlers.add(0, hdlr); 742 hdlr.setMode(mode); 743 } 744 745 if (mode != AudioSystem.MODE_NORMAL) { 746 clearAllScoClients(); 747 } 748 } 749 } 750 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE); 751 int index = mStreamStates[STREAM_VOLUME_ALIAS[streamType]].mIndex; 752 setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, true, false); 753 } 754 } 755 756 /** @see AudioManager#getMode() */ 757 public int getMode() { 758 return mMode; 759 } 760 761 /** @see AudioManager#playSoundEffect(int) */ 762 public void playSoundEffect(int effectType) { 763 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SHARED_MSG, SENDMSG_NOOP, 764 effectType, -1, null, 0); 765 } 766 767 /** @see AudioManager#playSoundEffect(int, float) */ 768 public void playSoundEffectVolume(int effectType, float volume) { 769 loadSoundEffects(); 770 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SHARED_MSG, SENDMSG_NOOP, 771 effectType, (int) (volume * 1000), null, 0); 772 } 773 774 /** 775 * Loads samples into the soundpool. 776 * This method must be called at when sound effects are enabled 777 */ 778 public boolean loadSoundEffects() { 779 synchronized (mSoundEffectsLock) { 780 if (mSoundPool != null) { 781 return true; 782 } 783 mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0); 784 if (mSoundPool == null) { 785 return false; 786 } 787 /* 788 * poolId table: The value -1 in this table indicates that corresponding 789 * file (same index in SOUND_EFFECT_FILES[] has not been loaded. 790 * Once loaded, the value in poolId is the sample ID and the same 791 * sample can be reused for another effect using the same file. 792 */ 793 int[] poolId = new int[SOUND_EFFECT_FILES.length]; 794 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) { 795 poolId[fileIdx] = -1; 796 } 797 /* 798 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded. 799 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0: 800 * this indicates we have a valid sample loaded for this effect. 801 */ 802 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) { 803 // Do not load sample if this effect uses the MediaPlayer 804 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) { 805 continue; 806 } 807 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) { 808 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effect][0]]; 809 int sampleId = mSoundPool.load(filePath, 0); 810 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId; 811 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId; 812 if (sampleId <= 0) { 813 Log.w(TAG, "Soundpool could not load file: "+filePath); 814 } 815 } else { 816 SOUND_EFFECT_FILES_MAP[effect][1] = poolId[SOUND_EFFECT_FILES_MAP[effect][0]]; 817 } 818 } 819 } 820 821 return true; 822 } 823 824 /** 825 * Unloads samples from the sound pool. 826 * This method can be called to free some memory when 827 * sound effects are disabled. 828 */ 829 public void unloadSoundEffects() { 830 synchronized (mSoundEffectsLock) { 831 if (mSoundPool == null) { 832 return; 833 } 834 int[] poolId = new int[SOUND_EFFECT_FILES.length]; 835 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) { 836 poolId[fileIdx] = 0; 837 } 838 839 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) { 840 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) { 841 continue; 842 } 843 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) { 844 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]); 845 SOUND_EFFECT_FILES_MAP[effect][1] = -1; 846 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1; 847 } 848 } 849 mSoundPool = null; 850 } 851 } 852 853 /** @see AudioManager#reloadAudioSettings() */ 854 public void reloadAudioSettings() { 855 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings 856 readPersistedSettings(); 857 858 // restore volume settings 859 int numStreamTypes = AudioSystem.getNumStreamTypes(); 860 for (int streamType = 0; streamType < numStreamTypes; streamType++) { 861 VolumeStreamState streamState = mStreamStates[streamType]; 862 863 String settingName = System.VOLUME_SETTINGS[STREAM_VOLUME_ALIAS[streamType]]; 864 String lastAudibleSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE; 865 int index = Settings.System.getInt(mContentResolver, 866 settingName, 867 AudioManager.DEFAULT_STREAM_VOLUME[streamType]); 868 if (STREAM_VOLUME_ALIAS[streamType] != streamType) { 869 index = rescaleIndex(index * 10, STREAM_VOLUME_ALIAS[streamType], streamType); 870 } else { 871 index *= 10; 872 } 873 streamState.mIndex = streamState.getValidIndex(index); 874 875 index = (index + 5) / 10; 876 index = Settings.System.getInt(mContentResolver, 877 lastAudibleSettingName, 878 (index > 0) ? index : AudioManager.DEFAULT_STREAM_VOLUME[streamType]); 879 if (STREAM_VOLUME_ALIAS[streamType] != streamType) { 880 index = rescaleIndex(index * 10, STREAM_VOLUME_ALIAS[streamType], streamType); 881 } else { 882 index *= 10; 883 } 884 streamState.mLastAudibleIndex = streamState.getValidIndex(index); 885 886 // unmute stream that was muted but is not affect by mute anymore 887 if (streamState.muteCount() != 0 && !isStreamAffectedByMute(streamType)) { 888 int size = streamState.mDeathHandlers.size(); 889 for (int i = 0; i < size; i++) { 890 streamState.mDeathHandlers.get(i).mMuteCount = 1; 891 streamState.mDeathHandlers.get(i).mute(false); 892 } 893 } 894 // apply stream volume 895 if (streamState.muteCount() == 0) { 896 setStreamVolumeIndex(streamType, streamState.mIndex); 897 } 898 } 899 900 // apply new ringer mode 901 setRingerModeInt(getRingerMode(), false); 902 } 903 904 /** @see AudioManager#setSpeakerphoneOn() */ 905 public void setSpeakerphoneOn(boolean on){ 906 if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) { 907 return; 908 } 909 if (on) { 910 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_SPEAKER); 911 mForcedUseForComm = AudioSystem.FORCE_SPEAKER; 912 } else { 913 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE); 914 mForcedUseForComm = AudioSystem.FORCE_NONE; 915 } 916 } 917 918 /** @see AudioManager#isSpeakerphoneOn() */ 919 public boolean isSpeakerphoneOn() { 920 if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER) { 921 return true; 922 } else { 923 return false; 924 } 925 } 926 927 /** @see AudioManager#setBluetoothScoOn() */ 928 public void setBluetoothScoOn(boolean on){ 929 if (!checkAudioSettingsPermission("setBluetoothScoOn()")) { 930 return; 931 } 932 if (on) { 933 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_BT_SCO); 934 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, AudioSystem.FORCE_BT_SCO); 935 mForcedUseForComm = AudioSystem.FORCE_BT_SCO; 936 } else { 937 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE); 938 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE); 939 mForcedUseForComm = AudioSystem.FORCE_NONE; 940 } 941 } 942 943 /** @see AudioManager#isBluetoothScoOn() */ 944 public boolean isBluetoothScoOn() { 945 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) { 946 return true; 947 } else { 948 return false; 949 } 950 } 951 952 /** @see AudioManager#startBluetoothSco() */ 953 public void startBluetoothSco(IBinder cb){ 954 if (!checkAudioSettingsPermission("startBluetoothSco()")) { 955 return; 956 } 957 ScoClient client = getScoClient(cb); 958 client.incCount(); 959 } 960 961 /** @see AudioManager#stopBluetoothSco() */ 962 public void stopBluetoothSco(IBinder cb){ 963 if (!checkAudioSettingsPermission("stopBluetoothSco()")) { 964 return; 965 } 966 ScoClient client = getScoClient(cb); 967 client.decCount(); 968 } 969 970 private class ScoClient implements IBinder.DeathRecipient { 971 private IBinder mCb; // To be notified of client's death 972 private int mStartcount; // number of SCO connections started by this client 973 974 ScoClient(IBinder cb) { 975 mCb = cb; 976 mStartcount = 0; 977 } 978 979 public void binderDied() { 980 synchronized(mScoClients) { 981 Log.w(TAG, "SCO client died"); 982 int index = mScoClients.indexOf(this); 983 if (index < 0) { 984 Log.w(TAG, "unregistered SCO client died"); 985 } else { 986 clearCount(true); 987 mScoClients.remove(this); 988 } 989 } 990 } 991 992 public void incCount() { 993 synchronized(mScoClients) { 994 requestScoState(BluetoothHeadset.AUDIO_STATE_CONNECTED); 995 if (mStartcount == 0) { 996 try { 997 mCb.linkToDeath(this, 0); 998 } catch (RemoteException e) { 999 // client has already died! 1000 Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death"); 1001 } 1002 } 1003 mStartcount++; 1004 } 1005 } 1006 1007 public void decCount() { 1008 synchronized(mScoClients) { 1009 if (mStartcount == 0) { 1010 Log.w(TAG, "ScoClient.decCount() already 0"); 1011 } else { 1012 mStartcount--; 1013 if (mStartcount == 0) { 1014 mCb.unlinkToDeath(this, 0); 1015 } 1016 requestScoState(BluetoothHeadset.AUDIO_STATE_DISCONNECTED); 1017 } 1018 } 1019 } 1020 1021 public void clearCount(boolean stopSco) { 1022 synchronized(mScoClients) { 1023 mStartcount = 0; 1024 mCb.unlinkToDeath(this, 0); 1025 if (stopSco) { 1026 requestScoState(BluetoothHeadset.AUDIO_STATE_DISCONNECTED); 1027 } 1028 } 1029 } 1030 1031 public int getCount() { 1032 return mStartcount; 1033 } 1034 1035 public IBinder getBinder() { 1036 return mCb; 1037 } 1038 1039 public int totalCount() { 1040 synchronized(mScoClients) { 1041 int count = 0; 1042 int size = mScoClients.size(); 1043 for (int i = 0; i < size; i++) { 1044 count += mScoClients.get(i).getCount(); 1045 } 1046 return count; 1047 } 1048 } 1049 1050 private void requestScoState(int state) { 1051 if (totalCount() == 0 && 1052 mBluetoothHeadsetConnected && 1053 AudioService.this.mMode == AudioSystem.MODE_NORMAL) { 1054 if (state == BluetoothHeadset.AUDIO_STATE_CONNECTED) { 1055 mBluetoothHeadset.startVoiceRecognition(); 1056 } else { 1057 mBluetoothHeadset.stopVoiceRecognition(); 1058 } 1059 } 1060 } 1061 } 1062 1063 public ScoClient getScoClient(IBinder cb) { 1064 synchronized(mScoClients) { 1065 ScoClient client; 1066 int size = mScoClients.size(); 1067 for (int i = 0; i < size; i++) { 1068 client = mScoClients.get(i); 1069 if (client.getBinder() == cb) 1070 return client; 1071 } 1072 client = new ScoClient(cb); 1073 mScoClients.add(client); 1074 return client; 1075 } 1076 } 1077 1078 public void clearAllScoClients() { 1079 synchronized(mScoClients) { 1080 int size = mScoClients.size(); 1081 for (int i = 0; i < size; i++) { 1082 mScoClients.get(i).clearCount(false); 1083 } 1084 } 1085 } 1086 1087 private BluetoothHeadset.ServiceListener mBluetoothHeadsetServiceListener = 1088 new BluetoothHeadset.ServiceListener() { 1089 public void onServiceConnected() { 1090 if (mBluetoothHeadset != null && 1091 mBluetoothHeadset.getState() == BluetoothHeadset.STATE_CONNECTED) { 1092 mBluetoothHeadsetConnected = true; 1093 } 1094 } 1095 public void onServiceDisconnected() { 1096 if (mBluetoothHeadset != null && 1097 mBluetoothHeadset.getState() == BluetoothHeadset.STATE_DISCONNECTED) { 1098 mBluetoothHeadsetConnected = false; 1099 clearAllScoClients(); 1100 } 1101 } 1102 }; 1103 1104 /////////////////////////////////////////////////////////////////////////// 1105 // Internal methods 1106 /////////////////////////////////////////////////////////////////////////// 1107 1108 /** 1109 * Checks if the adjustment should change ringer mode instead of just 1110 * adjusting volume. If so, this will set the proper ringer mode and volume 1111 * indices on the stream states. 1112 */ 1113 private boolean checkForRingerModeChange(int oldIndex, int direction) { 1114 boolean adjustVolumeIndex = true; 1115 int newRingerMode = mRingerMode; 1116 1117 if (mRingerMode == AudioManager.RINGER_MODE_NORMAL) { 1118 // audible mode, at the bottom of the scale 1119 if (direction == AudioManager.ADJUST_LOWER 1120 && (oldIndex + 5) / 10 == 1) { 1121 // "silent mode", but which one? 1122 newRingerMode = System.getInt(mContentResolver, System.VIBRATE_IN_SILENT, 1) == 1 1123 ? AudioManager.RINGER_MODE_VIBRATE 1124 : AudioManager.RINGER_MODE_SILENT; 1125 } 1126 } else { 1127 if (direction == AudioManager.ADJUST_RAISE) { 1128 // exiting silent mode 1129 newRingerMode = AudioManager.RINGER_MODE_NORMAL; 1130 } 1131 } 1132 1133 if (newRingerMode != mRingerMode) { 1134 setRingerMode(newRingerMode); 1135 1136 /* 1137 * If we are changing ringer modes, do not increment/decrement the 1138 * volume index. Instead, the handler for the message above will 1139 * take care of changing the index. 1140 */ 1141 adjustVolumeIndex = false; 1142 } 1143 1144 return adjustVolumeIndex; 1145 } 1146 1147 public boolean isStreamAffectedByRingerMode(int streamType) { 1148 return (mRingerModeAffectedStreams & (1 << streamType)) != 0; 1149 } 1150 1151 private boolean isStreamMutedByRingerMode(int streamType) { 1152 return (mRingerModeMutedStreams & (1 << streamType)) != 0; 1153 } 1154 1155 public boolean isStreamAffectedByMute(int streamType) { 1156 return (mMuteAffectedStreams & (1 << streamType)) != 0; 1157 } 1158 1159 private void ensureValidDirection(int direction) { 1160 if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) { 1161 throw new IllegalArgumentException("Bad direction " + direction); 1162 } 1163 } 1164 1165 private void ensureValidStreamType(int streamType) { 1166 if (streamType < 0 || streamType >= mStreamStates.length) { 1167 throw new IllegalArgumentException("Bad stream type " + streamType); 1168 } 1169 } 1170 1171 private int getActiveStreamType(int suggestedStreamType) { 1172 boolean isOffhook = false; 1173 try { 1174 ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); 1175 if (phone != null) isOffhook = phone.isOffhook(); 1176 } catch (RemoteException e) { 1177 Log.w(TAG, "Couldn't connect to phone service", e); 1178 } 1179 1180 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) == AudioSystem.FORCE_BT_SCO) { 1181 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO..."); 1182 return AudioSystem.STREAM_BLUETOOTH_SCO; 1183 } else if (isOffhook || AudioSystem.isStreamActive(AudioSystem.STREAM_VOICE_CALL)) { 1184 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL..."); 1185 return AudioSystem.STREAM_VOICE_CALL; 1186 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC)) { 1187 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC..."); 1188 return AudioSystem.STREAM_MUSIC; 1189 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { 1190 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING..."); 1191 return AudioSystem.STREAM_RING; 1192 } else { 1193 // Log.v(TAG, "getActiveStreamType: Returning suggested type " + suggestedStreamType); 1194 return suggestedStreamType; 1195 } 1196 } 1197 1198 private void broadcastRingerMode() { 1199 // Send sticky broadcast 1200 Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION); 1201 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, mRingerMode); 1202 broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 1203 | Intent.FLAG_RECEIVER_REPLACE_PENDING); 1204 long origCallerIdentityToken = Binder.clearCallingIdentity(); 1205 mContext.sendStickyBroadcast(broadcast); 1206 Binder.restoreCallingIdentity(origCallerIdentityToken); 1207 } 1208 1209 private void broadcastVibrateSetting(int vibrateType) { 1210 // Send broadcast 1211 if (ActivityManagerNative.isSystemReady()) { 1212 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION); 1213 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType); 1214 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType)); 1215 mContext.sendBroadcast(broadcast); 1216 } 1217 } 1218 1219 // Message helper methods 1220 private static int getMsg(int baseMsg, int streamType) { 1221 return (baseMsg & 0xffff) | streamType << 16; 1222 } 1223 1224 private static int getMsgBase(int msg) { 1225 return msg & 0xffff; 1226 } 1227 1228 private static void sendMsg(Handler handler, int baseMsg, int streamType, 1229 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) { 1230 int msg = (streamType == SHARED_MSG) ? baseMsg : getMsg(baseMsg, streamType); 1231 1232 if (existingMsgPolicy == SENDMSG_REPLACE) { 1233 handler.removeMessages(msg); 1234 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) { 1235 return; 1236 } 1237 1238 handler 1239 .sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay); 1240 } 1241 1242 boolean checkAudioSettingsPermission(String method) { 1243 if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS") 1244 == PackageManager.PERMISSION_GRANTED) { 1245 return true; 1246 } 1247 String msg = "Audio Settings Permission Denial: " + method + " from pid=" 1248 + Binder.getCallingPid() 1249 + ", uid=" + Binder.getCallingUid(); 1250 Log.w(TAG, msg); 1251 return false; 1252 } 1253 1254 1255 /////////////////////////////////////////////////////////////////////////// 1256 // Inner classes 1257 /////////////////////////////////////////////////////////////////////////// 1258 1259 public class VolumeStreamState { 1260 private final int mStreamType; 1261 1262 private String mVolumeIndexSettingName; 1263 private String mLastAudibleVolumeIndexSettingName; 1264 private int mIndexMax; 1265 private int mIndex; 1266 private int mLastAudibleIndex; 1267 private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo requests client death 1268 1269 private VolumeStreamState(String settingName, int streamType) { 1270 1271 setVolumeIndexSettingName(settingName); 1272 1273 mStreamType = streamType; 1274 1275 final ContentResolver cr = mContentResolver; 1276 mIndexMax = MAX_STREAM_VOLUME[streamType]; 1277 mIndex = Settings.System.getInt(cr, 1278 mVolumeIndexSettingName, 1279 AudioManager.DEFAULT_STREAM_VOLUME[streamType]); 1280 mLastAudibleIndex = Settings.System.getInt(cr, 1281 mLastAudibleVolumeIndexSettingName, 1282 (mIndex > 0) ? mIndex : AudioManager.DEFAULT_STREAM_VOLUME[streamType]); 1283 AudioSystem.initStreamVolume(streamType, 0, mIndexMax); 1284 mIndexMax *= 10; 1285 mIndex = getValidIndex(10 * mIndex); 1286 mLastAudibleIndex = getValidIndex(10 * mLastAudibleIndex); 1287 setStreamVolumeIndex(streamType, mIndex); 1288 mDeathHandlers = new ArrayList<VolumeDeathHandler>(); 1289 } 1290 1291 public void setVolumeIndexSettingName(String settingName) { 1292 mVolumeIndexSettingName = settingName; 1293 mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE; 1294 } 1295 1296 public boolean adjustIndex(int deltaIndex) { 1297 return setIndex(mIndex + deltaIndex * 10, true); 1298 } 1299 1300 public boolean setIndex(int index, boolean lastAudible) { 1301 int oldIndex = mIndex; 1302 mIndex = getValidIndex(index); 1303 1304 if (oldIndex != mIndex) { 1305 if (lastAudible) { 1306 mLastAudibleIndex = mIndex; 1307 } 1308 // Apply change to all streams using this one as alias 1309 int numStreamTypes = AudioSystem.getNumStreamTypes(); 1310 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 1311 if (streamType != mStreamType && STREAM_VOLUME_ALIAS[streamType] == mStreamType) { 1312 mStreamStates[streamType].setIndex(rescaleIndex(mIndex, mStreamType, streamType), lastAudible); 1313 } 1314 } 1315 return true; 1316 } else { 1317 return false; 1318 } 1319 } 1320 1321 public void setLastAudibleIndex(int index) { 1322 mLastAudibleIndex = getValidIndex(index); 1323 } 1324 1325 public void adjustLastAudibleIndex(int deltaIndex) { 1326 setLastAudibleIndex(mLastAudibleIndex + deltaIndex * 10); 1327 } 1328 1329 public int getMaxIndex() { 1330 return mIndexMax; 1331 } 1332 1333 public void mute(IBinder cb, boolean state) { 1334 VolumeDeathHandler handler = getDeathHandler(cb, state); 1335 if (handler == null) { 1336 Log.e(TAG, "Could not get client death handler for stream: "+mStreamType); 1337 return; 1338 } 1339 handler.mute(state); 1340 } 1341 1342 private int getValidIndex(int index) { 1343 if (index < 0) { 1344 return 0; 1345 } else if (index > mIndexMax) { 1346 return mIndexMax; 1347 } 1348 1349 return index; 1350 } 1351 1352 private class VolumeDeathHandler implements IBinder.DeathRecipient { 1353 private IBinder mICallback; // To be notified of client's death 1354 private int mMuteCount; // Number of active mutes for this client 1355 1356 VolumeDeathHandler(IBinder cb) { 1357 mICallback = cb; 1358 } 1359 1360 public void mute(boolean state) { 1361 synchronized(mDeathHandlers) { 1362 if (state) { 1363 if (mMuteCount == 0) { 1364 // Register for client death notification 1365 try { 1366 // mICallback can be 0 if muted by AudioService 1367 if (mICallback != null) { 1368 mICallback.linkToDeath(this, 0); 1369 } 1370 mDeathHandlers.add(this); 1371 // If the stream is not yet muted by any client, set lvel to 0 1372 if (muteCount() == 0) { 1373 setIndex(0, false); 1374 sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, mStreamType, SENDMSG_NOOP, 0, 0, 1375 VolumeStreamState.this, 0); 1376 } 1377 } catch (RemoteException e) { 1378 // Client has died! 1379 binderDied(); 1380 mDeathHandlers.notify(); 1381 return; 1382 } 1383 } else { 1384 Log.w(TAG, "stream: "+mStreamType+" was already muted by this client"); 1385 } 1386 mMuteCount++; 1387 } else { 1388 if (mMuteCount == 0) { 1389 Log.e(TAG, "unexpected unmute for stream: "+mStreamType); 1390 } else { 1391 mMuteCount--; 1392 if (mMuteCount == 0) { 1393 // Unregistr from client death notification 1394 mDeathHandlers.remove(this); 1395 // mICallback can be 0 if muted by AudioService 1396 if (mICallback != null) { 1397 mICallback.unlinkToDeath(this, 0); 1398 } 1399 if (muteCount() == 0) { 1400 // If the stream is not muted any more, restore it's volume if 1401 // ringer mode allows it 1402 if (!isStreamAffectedByRingerMode(mStreamType) || mRingerMode == AudioManager.RINGER_MODE_NORMAL) { 1403 setIndex(mLastAudibleIndex, false); 1404 sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, mStreamType, SENDMSG_NOOP, 0, 0, 1405 VolumeStreamState.this, 0); 1406 } 1407 } 1408 } 1409 } 1410 } 1411 mDeathHandlers.notify(); 1412 } 1413 } 1414 1415 public void binderDied() { 1416 Log.w(TAG, "Volume service client died for stream: "+mStreamType); 1417 if (mMuteCount != 0) { 1418 // Reset all active mute requests from this client. 1419 mMuteCount = 1; 1420 mute(false); 1421 } 1422 } 1423 } 1424 1425 private int muteCount() { 1426 int count = 0; 1427 int size = mDeathHandlers.size(); 1428 for (int i = 0; i < size; i++) { 1429 count += mDeathHandlers.get(i).mMuteCount; 1430 } 1431 return count; 1432 } 1433 1434 private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) { 1435 synchronized(mDeathHandlers) { 1436 VolumeDeathHandler handler; 1437 int size = mDeathHandlers.size(); 1438 for (int i = 0; i < size; i++) { 1439 handler = mDeathHandlers.get(i); 1440 if (cb == handler.mICallback) { 1441 return handler; 1442 } 1443 } 1444 // If this is the first mute request for this client, create a new 1445 // client death handler. Otherwise, it is an out of sequence unmute request. 1446 if (state) { 1447 handler = new VolumeDeathHandler(cb); 1448 } else { 1449 Log.w(TAG, "stream was not muted by this client"); 1450 handler = null; 1451 } 1452 return handler; 1453 } 1454 } 1455 } 1456 1457 /** Thread that handles native AudioSystem control. */ 1458 private class AudioSystemThread extends Thread { 1459 AudioSystemThread() { 1460 super("AudioService"); 1461 } 1462 1463 @Override 1464 public void run() { 1465 // Set this thread up so the handler will work on it 1466 Looper.prepare(); 1467 1468 synchronized(AudioService.this) { 1469 mAudioHandler = new AudioHandler(); 1470 1471 // Notify that the handler has been created 1472 AudioService.this.notify(); 1473 } 1474 1475 // Listen for volume change requests that are set by VolumePanel 1476 Looper.loop(); 1477 } 1478 } 1479 1480 /** Handles internal volume messages in separate volume thread. */ 1481 private class AudioHandler extends Handler { 1482 1483 private void setSystemVolume(VolumeStreamState streamState) { 1484 1485 // Adjust volume 1486 setStreamVolumeIndex(streamState.mStreamType, streamState.mIndex); 1487 1488 // Apply change to all streams using this one as alias 1489 int numStreamTypes = AudioSystem.getNumStreamTypes(); 1490 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 1491 if (streamType != streamState.mStreamType && 1492 STREAM_VOLUME_ALIAS[streamType] == streamState.mStreamType) { 1493 setStreamVolumeIndex(streamType, mStreamStates[streamType].mIndex); 1494 } 1495 } 1496 1497 // Post a persist volume msg 1498 sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamState.mStreamType, 1499 SENDMSG_REPLACE, 1, 1, streamState, PERSIST_DELAY); 1500 } 1501 1502 private void persistVolume(VolumeStreamState streamState, boolean current, boolean lastAudible) { 1503 if (current) { 1504 System.putInt(mContentResolver, streamState.mVolumeIndexSettingName, 1505 (streamState.mIndex + 5)/ 10); 1506 } 1507 if (lastAudible) { 1508 System.putInt(mContentResolver, streamState.mLastAudibleVolumeIndexSettingName, 1509 (streamState.mLastAudibleIndex + 5) / 10); 1510 } 1511 } 1512 1513 private void persistRingerMode() { 1514 System.putInt(mContentResolver, System.MODE_RINGER, mRingerMode); 1515 } 1516 1517 private void persistVibrateSetting() { 1518 System.putInt(mContentResolver, System.VIBRATE_ON, mVibrateSetting); 1519 } 1520 1521 private void playSoundEffect(int effectType, int volume) { 1522 synchronized (mSoundEffectsLock) { 1523 if (mSoundPool == null) { 1524 return; 1525 } 1526 float volFloat; 1527 // use STREAM_MUSIC volume attenuated by 3 dB if volume is not specified by caller 1528 if (volume < 0) { 1529 // Same linear to log conversion as in native AudioSystem::linearToLog() (AudioSystem.cpp) 1530 float dBPerStep = (float)((0.5 * 100) / MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]); 1531 int musicVolIndex = (mStreamStates[AudioSystem.STREAM_MUSIC].mIndex + 5) / 10; 1532 float musicVoldB = dBPerStep * (musicVolIndex - MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]); 1533 volFloat = (float)Math.pow(10, (musicVoldB - 3)/20); 1534 } else { 1535 volFloat = (float) volume / 1000.0f; 1536 } 1537 1538 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) { 1539 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1], volFloat, volFloat, 0, 0, 1.0f); 1540 } else { 1541 MediaPlayer mediaPlayer = new MediaPlayer(); 1542 if (mediaPlayer != null) { 1543 try { 1544 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effectType][0]]; 1545 mediaPlayer.setDataSource(filePath); 1546 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM); 1547 mediaPlayer.prepare(); 1548 mediaPlayer.setVolume(volFloat, volFloat); 1549 mediaPlayer.setOnCompletionListener(new OnCompletionListener() { 1550 public void onCompletion(MediaPlayer mp) { 1551 cleanupPlayer(mp); 1552 } 1553 }); 1554 mediaPlayer.setOnErrorListener(new OnErrorListener() { 1555 public boolean onError(MediaPlayer mp, int what, int extra) { 1556 cleanupPlayer(mp); 1557 return true; 1558 } 1559 }); 1560 mediaPlayer.start(); 1561 } catch (IOException ex) { 1562 Log.w(TAG, "MediaPlayer IOException: "+ex); 1563 } catch (IllegalArgumentException ex) { 1564 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex); 1565 } catch (IllegalStateException ex) { 1566 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex); 1567 } 1568 } 1569 } 1570 } 1571 } 1572 1573 private void cleanupPlayer(MediaPlayer mp) { 1574 if (mp != null) { 1575 try { 1576 mp.stop(); 1577 mp.release(); 1578 } catch (IllegalStateException ex) { 1579 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex); 1580 } 1581 } 1582 } 1583 1584 @Override 1585 public void handleMessage(Message msg) { 1586 int baseMsgWhat = getMsgBase(msg.what); 1587 1588 switch (baseMsgWhat) { 1589 1590 case MSG_SET_SYSTEM_VOLUME: 1591 setSystemVolume((VolumeStreamState) msg.obj); 1592 break; 1593 1594 case MSG_PERSIST_VOLUME: 1595 persistVolume((VolumeStreamState) msg.obj, (msg.arg1 != 0), (msg.arg2 != 0)); 1596 break; 1597 1598 case MSG_PERSIST_RINGER_MODE: 1599 persistRingerMode(); 1600 break; 1601 1602 case MSG_PERSIST_VIBRATE_SETTING: 1603 persistVibrateSetting(); 1604 break; 1605 1606 case MSG_MEDIA_SERVER_DIED: 1607 // Force creation of new IAudioflinger interface 1608 if (!mMediaServerOk) { 1609 Log.e(TAG, "Media server died."); 1610 AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC); 1611 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SHARED_MSG, SENDMSG_NOOP, 0, 0, 1612 null, 500); 1613 } 1614 break; 1615 1616 case MSG_MEDIA_SERVER_STARTED: 1617 Log.e(TAG, "Media server started."); 1618 // Restore device connection states 1619 Set set = mConnectedDevices.entrySet(); 1620 Iterator i = set.iterator(); 1621 while(i.hasNext()){ 1622 Map.Entry device = (Map.Entry)i.next(); 1623 AudioSystem.setDeviceConnectionState(((Integer)device.getKey()).intValue(), 1624 AudioSystem.DEVICE_STATE_AVAILABLE, 1625 (String)device.getValue()); 1626 } 1627 1628 // Restore call state 1629 AudioSystem.setPhoneState(mMode); 1630 1631 // Restore forced usage for communcations and record 1632 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm); 1633 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm); 1634 1635 // Restore stream volumes 1636 int numStreamTypes = AudioSystem.getNumStreamTypes(); 1637 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 1638 int index; 1639 VolumeStreamState streamState = mStreamStates[streamType]; 1640 AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10); 1641 if (streamState.muteCount() == 0) { 1642 index = streamState.mIndex; 1643 } else { 1644 index = 0; 1645 } 1646 setStreamVolumeIndex(streamType, index); 1647 } 1648 1649 // Restore ringer mode 1650 setRingerModeInt(getRingerMode(), false); 1651 break; 1652 1653 case MSG_PLAY_SOUND_EFFECT: 1654 playSoundEffect(msg.arg1, msg.arg2); 1655 break; 1656 } 1657 } 1658 } 1659 1660 private class SettingsObserver extends ContentObserver { 1661 1662 SettingsObserver() { 1663 super(new Handler()); 1664 mContentResolver.registerContentObserver(Settings.System.getUriFor( 1665 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this); 1666 mContentResolver.registerContentObserver(Settings.System.getUriFor( 1667 Settings.System.NOTIFICATIONS_USE_RING_VOLUME), false, this); 1668 } 1669 1670 @Override 1671 public void onChange(boolean selfChange) { 1672 super.onChange(selfChange); 1673 synchronized (mSettingsLock) { 1674 int ringerModeAffectedStreams = Settings.System.getInt(mContentResolver, 1675 Settings.System.MODE_RINGER_STREAMS_AFFECTED, 1676 0); 1677 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) { 1678 /* 1679 * Ensure all stream types that should be affected by ringer mode 1680 * are in the proper state. 1681 */ 1682 mRingerModeAffectedStreams = ringerModeAffectedStreams; 1683 setRingerModeInt(getRingerMode(), false); 1684 } 1685 1686 int notificationsUseRingVolume = Settings.System.getInt(mContentResolver, 1687 Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1688 1); 1689 if (notificationsUseRingVolume != mNotificationsUseRingVolume) { 1690 mNotificationsUseRingVolume = notificationsUseRingVolume; 1691 if (mNotificationsUseRingVolume == 1) { 1692 STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_RING; 1693 mStreamStates[AudioSystem.STREAM_NOTIFICATION].setVolumeIndexSettingName( 1694 System.VOLUME_SETTINGS[AudioSystem.STREAM_RING]); 1695 } else { 1696 STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_NOTIFICATION; 1697 mStreamStates[AudioSystem.STREAM_NOTIFICATION].setVolumeIndexSettingName( 1698 System.VOLUME_SETTINGS[AudioSystem.STREAM_NOTIFICATION]); 1699 // Persist notification volume volume as it was not persisted while aliased to ring volume 1700 // and persist with no delay as there might be registered observers of the persisted 1701 // notification volume. 1702 sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, AudioSystem.STREAM_NOTIFICATION, 1703 SENDMSG_REPLACE, 1, 1, mStreamStates[AudioSystem.STREAM_NOTIFICATION], 0); 1704 } 1705 } 1706 } 1707 } 1708 } 1709 1710 /** 1711 * Receiver for misc intent broadcasts the Phone app cares about. 1712 */ 1713 private class AudioServiceBroadcastReceiver extends BroadcastReceiver { 1714 @Override 1715 public void onReceive(Context context, Intent intent) { 1716 String action = intent.getAction(); 1717 1718 if (action.equals(Intent.ACTION_DOCK_EVENT)) { 1719 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, 1720 Intent.EXTRA_DOCK_STATE_UNDOCKED); 1721 int config; 1722 switch (dockState) { 1723 case Intent.EXTRA_DOCK_STATE_DESK: 1724 config = AudioSystem.FORCE_BT_DESK_DOCK; 1725 break; 1726 case Intent.EXTRA_DOCK_STATE_CAR: 1727 config = AudioSystem.FORCE_BT_CAR_DOCK; 1728 break; 1729 case Intent.EXTRA_DOCK_STATE_UNDOCKED: 1730 default: 1731 config = AudioSystem.FORCE_NONE; 1732 } 1733 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config); 1734 } else if (action.equals(BluetoothA2dp.ACTION_SINK_STATE_CHANGED)) { 1735 int state = intent.getIntExtra(BluetoothA2dp.EXTRA_SINK_STATE, 1736 BluetoothA2dp.STATE_DISCONNECTED); 1737 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 1738 String address = btDevice.getAddress(); 1739 boolean isConnected = (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) && 1740 ((String)mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)).equals(address)); 1741 1742 if (isConnected && 1743 state != BluetoothA2dp.STATE_CONNECTED && state != BluetoothA2dp.STATE_PLAYING) { 1744 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 1745 AudioSystem.DEVICE_STATE_UNAVAILABLE, 1746 address); 1747 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP); 1748 } else if (!isConnected && 1749 (state == BluetoothA2dp.STATE_CONNECTED || 1750 state == BluetoothA2dp.STATE_PLAYING)) { 1751 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 1752 AudioSystem.DEVICE_STATE_AVAILABLE, 1753 address); 1754 // Reset A2DP suspend state each time a new sink is connected 1755 AudioSystem.setParameters("A2dpSuspended=false"); 1756 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP), 1757 address); 1758 } 1759 } else if (action.equals(BluetoothHeadset.ACTION_STATE_CHANGED)) { 1760 int state = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, 1761 BluetoothHeadset.STATE_ERROR); 1762 int device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO; 1763 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 1764 String address = null; 1765 if (btDevice != null) { 1766 address = btDevice.getAddress(); 1767 BluetoothClass btClass = btDevice.getBluetoothClass(); 1768 if (btClass != null) { 1769 switch (btClass.getDeviceClass()) { 1770 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET: 1771 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE: 1772 device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET; 1773 break; 1774 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO: 1775 device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT; 1776 break; 1777 } 1778 } 1779 } 1780 1781 boolean isConnected = (mConnectedDevices.containsKey(device) && 1782 ((String)mConnectedDevices.get(device)).equals(address)); 1783 1784 if (isConnected && state != BluetoothHeadset.STATE_CONNECTED) { 1785 AudioSystem.setDeviceConnectionState(device, 1786 AudioSystem.DEVICE_STATE_UNAVAILABLE, 1787 address); 1788 mConnectedDevices.remove(device); 1789 mBluetoothHeadsetConnected = false; 1790 clearAllScoClients(); 1791 } else if (!isConnected && state == BluetoothHeadset.STATE_CONNECTED) { 1792 AudioSystem.setDeviceConnectionState(device, 1793 AudioSystem.DEVICE_STATE_AVAILABLE, 1794 address); 1795 mConnectedDevices.put(new Integer(device), address); 1796 mBluetoothHeadsetConnected = true; 1797 } 1798 } else if (action.equals(Intent.ACTION_HEADSET_PLUG)) { 1799 int state = intent.getIntExtra("state", 0); 1800 int microphone = intent.getIntExtra("microphone", 0); 1801 1802 if (microphone != 0) { 1803 boolean isConnected = mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_WIRED_HEADSET); 1804 if (state == 0 && isConnected) { 1805 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET, 1806 AudioSystem.DEVICE_STATE_UNAVAILABLE, 1807 ""); 1808 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_WIRED_HEADSET); 1809 } else if (state == 1 && !isConnected) { 1810 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET, 1811 AudioSystem.DEVICE_STATE_AVAILABLE, 1812 ""); 1813 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_WIRED_HEADSET), ""); 1814 } 1815 } else { 1816 boolean isConnected = mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE); 1817 if (state == 0 && isConnected) { 1818 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE, 1819 AudioSystem.DEVICE_STATE_UNAVAILABLE, 1820 ""); 1821 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE); 1822 } else if (state == 1 && !isConnected) { 1823 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE, 1824 AudioSystem.DEVICE_STATE_AVAILABLE, 1825 ""); 1826 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE), ""); 1827 } 1828 } 1829 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) { 1830 int state = intent.getIntExtra(BluetoothHeadset.EXTRA_AUDIO_STATE, 1831 BluetoothHeadset.STATE_ERROR); 1832 synchronized (mScoClients) { 1833 if (!mScoClients.isEmpty()) { 1834 switch (state) { 1835 case BluetoothHeadset.AUDIO_STATE_CONNECTED: 1836 state = AudioManager.SCO_AUDIO_STATE_CONNECTED; 1837 break; 1838 case BluetoothHeadset.AUDIO_STATE_DISCONNECTED: 1839 state = AudioManager.SCO_AUDIO_STATE_DISCONNECTED; 1840 break; 1841 default: 1842 state = AudioManager.SCO_AUDIO_STATE_ERROR; 1843 break; 1844 } 1845 if (state != AudioManager.SCO_AUDIO_STATE_ERROR) { 1846 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED); 1847 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state); 1848 mContext.sendStickyBroadcast(newIntent); 1849 } 1850 } 1851 } 1852 } 1853 } 1854 } 1855 1856 //========================================================================================== 1857 // AudioFocus 1858 //========================================================================================== 1859 /** 1860 * Flag to indicate that the top of the audio focus stack needs to recover focus 1861 * but hasn't been signaled yet. 1862 */ 1863 private boolean mHasUndispatchedAudioFocus = false; 1864 1865 private void checkForUndispatchedAudioFocusChange(int prevMode, int newMode) { 1866 // when exiting a call 1867 if ((prevMode == AudioSystem.MODE_IN_CALL) && (newMode != AudioSystem.MODE_IN_CALL)) { 1868 // check for undispatched remote control focus gain 1869 if (mHasUndispatchedAudioFocus) { 1870 notifyTopOfAudioFocusStack(); 1871 } 1872 } 1873 } 1874 1875 private void notifyTopOfAudioFocusStack() { 1876 // notify the top of the stack it gained focus 1877 if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) { 1878 if (canReassignAudioFocus()) { 1879 try { 1880 mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange( 1881 AudioManager.AUDIOFOCUS_GAIN, mFocusStack.peek().mClientId); 1882 mHasUndispatchedAudioFocus = false; 1883 } catch (RemoteException e) { 1884 Log.e(TAG, "Failure to signal gain of audio control focus due to "+ e); 1885 e.printStackTrace(); 1886 } 1887 } else { 1888 mHasUndispatchedAudioFocus = true; 1889 } 1890 } 1891 } 1892 1893 private static class FocusStackEntry { 1894 public int mStreamType = -1;// no stream type 1895 public boolean mIsTransportControlReceiver = false; 1896 public IAudioFocusDispatcher mFocusDispatcher = null; 1897 public IBinder mSourceRef = null; 1898 public String mClientId; 1899 public int mFocusChangeType; 1900 1901 public FocusStackEntry() { 1902 } 1903 1904 public FocusStackEntry(int streamType, int duration, boolean isTransportControlReceiver, 1905 IAudioFocusDispatcher afl, IBinder source, String id) { 1906 mStreamType = streamType; 1907 mIsTransportControlReceiver = isTransportControlReceiver; 1908 mFocusDispatcher = afl; 1909 mSourceRef = source; 1910 mClientId = id; 1911 mFocusChangeType = duration; 1912 } 1913 } 1914 1915 private Stack<FocusStackEntry> mFocusStack = new Stack<FocusStackEntry>(); 1916 1917 /** 1918 * Helper function: 1919 * Display in the log the current entries in the audio focus stack 1920 */ 1921 private void dumpFocusStack(PrintWriter pw) { 1922 pw.println("Audio Focus stack entries:"); 1923 synchronized(mFocusStack) { 1924 Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); 1925 while(stackIterator.hasNext()) { 1926 FocusStackEntry fse = stackIterator.next(); 1927 pw.println(" source:" + fse.mSourceRef + " -- client: " + fse.mClientId 1928 + " -- duration: " +fse.mFocusChangeType); 1929 } 1930 } 1931 } 1932 1933 /** 1934 * Helper function: 1935 * Remove a focus listener from the focus stack. 1936 * @param focusListenerToRemove the focus listener 1937 * @param signal if true and the listener was at the top of the focus stack, i.e. it was holding 1938 * focus, notify the next item in the stack it gained focus. 1939 */ 1940 private void removeFocusStackEntry(String clientToRemove, boolean signal) { 1941 // is the current top of the focus stack abandoning focus? (because of death or request) 1942 if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientToRemove)) 1943 { 1944 //Log.i(TAG, " removeFocusStackEntry() removing top of stack"); 1945 mFocusStack.pop(); 1946 if (signal) { 1947 // notify the new top of the stack it gained focus 1948 notifyTopOfAudioFocusStack(); 1949 } 1950 } else { 1951 // focus is abandoned by a client that's not at the top of the stack, 1952 // no need to update focus. 1953 Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); 1954 while(stackIterator.hasNext()) { 1955 FocusStackEntry fse = (FocusStackEntry)stackIterator.next(); 1956 if(fse.mClientId.equals(clientToRemove)) { 1957 Log.i(TAG, " AudioFocus abandonAudioFocus(): removing entry for " 1958 + fse.mClientId); 1959 mFocusStack.remove(fse); 1960 } 1961 } 1962 } 1963 } 1964 1965 /** 1966 * Helper function: 1967 * Remove focus listeners from the focus stack for a particular client. 1968 */ 1969 private void removeFocusStackEntryForClient(IBinder cb) { 1970 // is the owner of the audio focus part of the client to remove? 1971 boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() && 1972 mFocusStack.peek().mSourceRef.equals(cb); 1973 Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); 1974 while(stackIterator.hasNext()) { 1975 FocusStackEntry fse = (FocusStackEntry)stackIterator.next(); 1976 if(fse.mSourceRef.equals(cb)) { 1977 Log.i(TAG, " AudioFocus abandonAudioFocus(): removing entry for " 1978 + fse.mClientId); 1979 mFocusStack.remove(fse); 1980 } 1981 } 1982 if (isTopOfStackForClientToRemove) { 1983 // we removed an entry at the top of the stack: 1984 // notify the new top of the stack it gained focus. 1985 notifyTopOfAudioFocusStack(); 1986 } 1987 } 1988 1989 /** 1990 * Helper function: 1991 * Returns true if the system is in a state where the focus can be reevaluated, false otherwise. 1992 */ 1993 private boolean canReassignAudioFocus() { 1994 // focus requests are rejected during a phone call 1995 if (getMode() == AudioSystem.MODE_IN_CALL) { 1996 Log.i(TAG, " AudioFocus can't be reassigned during a call, exiting"); 1997 return false; 1998 } 1999 return true; 2000 } 2001 2002 /** 2003 * Inner class to monitor audio focus client deaths, and remove them from the audio focus 2004 * stack if necessary. 2005 */ 2006 private class AudioFocusDeathHandler implements IBinder.DeathRecipient { 2007 private IBinder mCb; // To be notified of client's death 2008 2009 AudioFocusDeathHandler(IBinder cb) { 2010 mCb = cb; 2011 } 2012 2013 public void binderDied() { 2014 synchronized(mFocusStack) { 2015 Log.w(TAG, " AudioFocus audio focus client died"); 2016 removeFocusStackEntryForClient(mCb); 2017 } 2018 } 2019 2020 public IBinder getBinder() { 2021 return mCb; 2022 } 2023 } 2024 2025 2026 /** @see AudioManager#requestAudioFocus(IAudioFocusDispatcher, int, int) */ 2027 public int requestAudioFocus(int mainStreamType, int focusChangeHint, IBinder cb, 2028 IAudioFocusDispatcher fd, String clientId) { 2029 Log.i(TAG, " AudioFocus requestAudioFocus() from " + clientId); 2030 // the main stream type for the audio focus request is currently not used. It may 2031 // potentially be used to handle multiple stream type-dependent audio focuses. 2032 2033 if ((cb == null) || !cb.pingBinder()) { 2034 Log.i(TAG, " AudioFocus DOA client for requestAudioFocus(), exiting"); 2035 return AudioManager.AUDIOFOCUS_REQUEST_FAILED; 2036 } 2037 2038 if (!canReassignAudioFocus()) { 2039 return AudioManager.AUDIOFOCUS_REQUEST_FAILED; 2040 } 2041 2042 synchronized(mFocusStack) { 2043 if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientId)) { 2044 // if focus is already owned by this client and the reason for acquiring the focus 2045 // hasn't changed, don't do anything 2046 if (mFocusStack.peek().mFocusChangeType == focusChangeHint) { 2047 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 2048 } 2049 // the reason for the audio focus request has changed: remove the current top of 2050 // stack and respond as if we had a new focus owner 2051 mFocusStack.pop(); 2052 } 2053 2054 // notify current top of stack it is losing focus 2055 if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) { 2056 try { 2057 mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange( 2058 -1 * focusChangeHint, // loss and gain codes are inverse of each other 2059 mFocusStack.peek().mClientId); 2060 } catch (RemoteException e) { 2061 Log.e(TAG, " Failure to signal loss of focus due to "+ e); 2062 e.printStackTrace(); 2063 } 2064 } 2065 2066 // focus requester might already be somewhere below in the stack, remove it 2067 removeFocusStackEntry(clientId, false); 2068 2069 // push focus requester at the top of the audio focus stack 2070 mFocusStack.push(new FocusStackEntry(mainStreamType, focusChangeHint, false, fd, cb, 2071 clientId)); 2072 }//synchronized(mFocusStack) 2073 2074 // handle the potential premature death of the new holder of the focus 2075 // (premature death == death before abandoning focus) 2076 // Register for client death notification 2077 AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb); 2078 try { 2079 cb.linkToDeath(afdh, 0); 2080 } catch (RemoteException e) { 2081 // client has already died! 2082 Log.w(TAG, " AudioFocus requestAudioFocus() could not link to "+cb+" binder death"); 2083 } 2084 2085 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 2086 } 2087 2088 /** @see AudioManager#abandonAudioFocus(IAudioFocusDispatcher) */ 2089 public int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId) { 2090 Log.i(TAG, " AudioFocus abandonAudioFocus() from " + clientId); 2091 2092 // this will take care of notifying the new focus owner if needed 2093 synchronized(mFocusStack) { 2094 removeFocusStackEntry(clientId, true); 2095 } 2096 2097 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 2098 } 2099 2100 2101 public void unregisterAudioFocusClient(String clientId) { 2102 synchronized(mFocusStack) { 2103 removeFocusStackEntry(clientId, false); 2104 } 2105 } 2106 2107 2108 //========================================================================================== 2109 // RemoteControl 2110 //========================================================================================== 2111 /** 2112 * Receiver for media button intents. Handles the dispatching of the media button event 2113 * to one of the registered listeners, or if there was none, resumes the intent broadcast 2114 * to the rest of the system. 2115 */ 2116 private class MediaButtonBroadcastReceiver extends BroadcastReceiver { 2117 @Override 2118 public void onReceive(Context context, Intent intent) { 2119 String action = intent.getAction(); 2120 if (!Intent.ACTION_MEDIA_BUTTON.equals(action)) { 2121 return; 2122 } 2123 KeyEvent event = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); 2124 if (event != null) { 2125 // if in a call or ringing, do not break the current phone app behavior 2126 // TODO modify this to let the phone app specifically get the RC focus 2127 // add modify the phone app to take advantage of the new API 2128 if ((getMode() == AudioSystem.MODE_IN_CALL) || 2129 (getMode() == AudioSystem.MODE_RINGTONE)) { 2130 return; 2131 } 2132 synchronized(mRCStack) { 2133 if (!mRCStack.empty()) { 2134 // create a new intent specifically aimed at the current registered listener 2135 Intent targetedIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); 2136 targetedIntent.putExtras(intent.getExtras()); 2137 targetedIntent.setComponent(mRCStack.peek().mReceiverComponent); 2138 // trap the current broadcast 2139 abortBroadcast(); 2140 //Log.v(TAG, " Sending intent" + targetedIntent); 2141 context.sendBroadcast(targetedIntent, null); 2142 } 2143 } 2144 } 2145 } 2146 } 2147 2148 private static class RemoteControlStackEntry { 2149 public ComponentName mReceiverComponent;// always non null 2150 // TODO implement registration expiration? 2151 //public int mRegistrationTime; 2152 2153 public RemoteControlStackEntry() { 2154 } 2155 2156 public RemoteControlStackEntry(ComponentName r) { 2157 mReceiverComponent = r; 2158 } 2159 } 2160 2161 private Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>(); 2162 2163 /** 2164 * Helper function: 2165 * Display in the log the current entries in the remote control focus stack 2166 */ 2167 private void dumpRCStack(PrintWriter pw) { 2168 pw.println("Remote Control stack entries:"); 2169 synchronized(mRCStack) { 2170 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 2171 while(stackIterator.hasNext()) { 2172 RemoteControlStackEntry fse = stackIterator.next(); 2173 pw.println(" receiver:" + fse.mReceiverComponent); 2174 } 2175 } 2176 } 2177 2178 /** 2179 * Helper function: 2180 * Set the new remote control receiver at the top of the RC focus stack 2181 */ 2182 private void pushMediaButtonReceiver(ComponentName newReceiver) { 2183 // already at top of stack? 2184 if (!mRCStack.empty() && mRCStack.peek().mReceiverComponent.equals(newReceiver)) { 2185 return; 2186 } 2187 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 2188 while(stackIterator.hasNext()) { 2189 RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next(); 2190 if(rcse.mReceiverComponent.equals(newReceiver)) { 2191 mRCStack.remove(rcse); 2192 break; 2193 } 2194 } 2195 mRCStack.push(new RemoteControlStackEntry(newReceiver)); 2196 } 2197 2198 /** 2199 * Helper function: 2200 * Remove the remote control receiver from the RC focus stack 2201 */ 2202 private void removeMediaButtonReceiver(ComponentName newReceiver) { 2203 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 2204 while(stackIterator.hasNext()) { 2205 RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next(); 2206 if(rcse.mReceiverComponent.equals(newReceiver)) { 2207 mRCStack.remove(rcse); 2208 break; 2209 } 2210 } 2211 } 2212 2213 2214 /** see AudioManager.registerMediaButtonEventReceiver(ComponentName eventReceiver) */ 2215 public void registerMediaButtonEventReceiver(ComponentName eventReceiver) { 2216 Log.i(TAG, " Remote Control registerMediaButtonEventReceiver() for " + eventReceiver); 2217 2218 synchronized(mRCStack) { 2219 pushMediaButtonReceiver(eventReceiver); 2220 } 2221 } 2222 2223 /** see AudioManager.unregisterMediaButtonEventReceiver(ComponentName eventReceiver) */ 2224 public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) { 2225 Log.i(TAG, " Remote Control unregisterMediaButtonEventReceiver() for " + eventReceiver); 2226 2227 synchronized(mRCStack) { 2228 removeMediaButtonReceiver(eventReceiver); 2229 } 2230 } 2231 2232 2233 @Override 2234 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2235 // TODO probably a lot more to do here than just the audio focus and remote control stacks 2236 dumpFocusStack(pw); 2237 dumpRCStack(pw); 2238 } 2239 2240 2241} 2242