Skip to content

Commit 6d51766

Browse files
author
Eric Laurent
committed
system and UI sounds volume policy
Implement a more consistent policy for system and UI sounds (key clicks, lock/unlock, camera shutter, DTMF, low battery...): - All system sounds are played over STREAM_SYSTEM stream type. - The STREAM_SYSTEM volume that was previously fixed now tracks the volume of a "master" stream type. This "master" stream type is STREAM_RING for phones and STREAM_MUSIC for tablets which corresponds to the stream whose volume is modified by default by the volume keys. - The STREAM_SYSTEM volume ranges from -24dB to -6dB (-24dB to -12dB over headphones) when the "master" stream volume ranges from its min to its max. - DTMF tones are played over STREAM_DTMF that tracks the "master" stream volume in the same manner with the following exception: when in call, DTMF stream tracks STREAM_VOICE_CALL volume. - Camera shutter sound is played over STREAM_SYSTEM_ENFORCED stream that tracks the "master" stream volume except in countries where regulation enforces this sound. In this case its volume is fixed and cannot be muted. - Low battery sound is played over STREAM_SYSTEM and therefore has a tunable volume and is heard while in call. Issue 6344620. Issue 6069229. Issue 6213100. Change-Id: I53a237878ead596e706c5dbbb1420e62cde32bd7
1 parent f18222d commit 6d51766

File tree

5 files changed

+149
-61
lines changed

5 files changed

+149
-61
lines changed

media/java/android/media/AudioManager.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -700,6 +700,21 @@ public int getLastAudibleStreamVolume(int streamType) {
700700
}
701701
}
702702

703+
/**
704+
* Get the stream type whose volume is driving the UI sounds volume.
705+
* UI sounds are screen lock/unlock, camera shutter, key clicks...
706+
* @hide
707+
*/
708+
public int getMasterStreamType() {
709+
IAudioService service = getService();
710+
try {
711+
return service.getMasterStreamType();
712+
} catch (RemoteException e) {
713+
Log.e(TAG, "Dead object in getMasterStreamType", e);
714+
return STREAM_RING;
715+
}
716+
}
717+
703718
/**
704719
* Sets the ringer mode.
705720
* <p>

media/java/android/media/AudioService.java

Lines changed: 127 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -202,22 +202,39 @@ public class AudioService extends IAudioService.Stub {
202202
15, // STREAM_DTMF
203203
15 // STREAM_TTS
204204
};
205-
/* STREAM_VOLUME_ALIAS[] indicates for each stream if it uses the volume settings
205+
/* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
206206
* of another stream: This avoids multiplying the volume settings for hidden
207207
* stream types that follow other stream behavior for volume settings
208-
* NOTE: do not create loops in aliases! */
208+
* NOTE: do not create loops in aliases!
209+
* Some streams alias to different streams according to device category (phone or tablet) or
210+
* use case (in call s off call...).See updateStreamVolumeAlias() for more details
211+
* mStreamVolumeAlias contains the default aliases for a voice capable device (phone) and
212+
* STREAM_VOLUME_ALIAS_NON_VOICE for a non voice capable device (tablet).*/
209213
private final int[] STREAM_VOLUME_ALIAS = new int[] {
210-
AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
211-
AudioSystem.STREAM_SYSTEM, // STREAM_SYSTEM
212-
AudioSystem.STREAM_RING, // STREAM_RING
213-
AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
214-
AudioSystem.STREAM_ALARM, // STREAM_ALARM
215-
AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
216-
AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
217-
AudioSystem.STREAM_SYSTEM, // STREAM_SYSTEM_ENFORCED
218-
AudioSystem.STREAM_VOICE_CALL, // STREAM_DTMF
219-
AudioSystem.STREAM_MUSIC // STREAM_TTS
214+
AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
215+
AudioSystem.STREAM_RING, // STREAM_SYSTEM
216+
AudioSystem.STREAM_RING, // STREAM_RING
217+
AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
218+
AudioSystem.STREAM_ALARM, // STREAM_ALARM
219+
AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
220+
AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
221+
AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
222+
AudioSystem.STREAM_RING, // STREAM_DTMF
223+
AudioSystem.STREAM_MUSIC // STREAM_TTS
220224
};
225+
private final int[] STREAM_VOLUME_ALIAS_NON_VOICE = new int[] {
226+
AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
227+
AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM
228+
AudioSystem.STREAM_RING, // STREAM_RING
229+
AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
230+
AudioSystem.STREAM_ALARM, // STREAM_ALARM
231+
AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
232+
AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
233+
AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED
234+
AudioSystem.STREAM_MUSIC, // STREAM_DTMF
235+
AudioSystem.STREAM_MUSIC // STREAM_TTS
236+
};
237+
private int[] mStreamVolumeAlias;
221238

222239
private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
223240
public void onError(int error) {
@@ -333,7 +350,7 @@ public void onError(int error) {
333350
// message looper for SoundPool listener
334351
private Looper mSoundPoolLooper = null;
335352
// default volume applied to sound played with playSoundEffect()
336-
private static final int SOUND_EFFECT_DEFAULT_VOLUME_DB = -20;
353+
private static final int SOUND_EFFECT_DEFAULT_VOLUME_DB = 0;
337354
// volume applied to sound played with playSoundEffect() read from ro.config.sound_fx_volume
338355
private int SOUND_EFFECT_VOLUME_DB;
339356
// getActiveStreamType() will return STREAM_NOTIFICATION during this period after a notification
@@ -374,13 +391,14 @@ public AudioService(Context context) {
374391
SOUND_EFFECT_DEFAULT_VOLUME_DB);
375392

376393
mVolumePanel = new VolumePanel(context, this);
394+
mMode = AudioSystem.MODE_NORMAL;
377395
mForcedUseForComm = AudioSystem.FORCE_NONE;
378396
createAudioSystemThread();
379397
readPersistedSettings();
380398
mSettingsObserver = new SettingsObserver();
399+
updateStreamVolumeAlias(false /*updateVolumes*/);
381400
createStreamStates();
382401

383-
mMode = AudioSystem.MODE_NORMAL;
384402
mMediaServerOk = true;
385403

386404
// Call setRingerModeInt() to apply correct mute
@@ -459,26 +477,54 @@ private void createStreamStates() {
459477
VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
460478

461479
for (int i = 0; i < numStreamTypes; i++) {
462-
streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[STREAM_VOLUME_ALIAS[i]], i);
480+
streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
463481
}
464482

465483
// Correct stream index values for streams with aliases
466484
for (int i = 0; i < numStreamTypes; i++) {
467485
int device = getDeviceForStream(i);
468-
if (STREAM_VOLUME_ALIAS[i] != i) {
486+
if (mStreamVolumeAlias[i] != i) {
469487
int index = rescaleIndex(streams[i].getIndex(device, false /* lastAudible */),
470-
STREAM_VOLUME_ALIAS[i],
488+
mStreamVolumeAlias[i],
471489
i);
472490
streams[i].mIndex.put(device, streams[i].getValidIndex(index));
473491
streams[i].applyDeviceVolume(device);
474492
index = rescaleIndex(streams[i].getIndex(device, true /* lastAudible */),
475-
STREAM_VOLUME_ALIAS[i],
493+
mStreamVolumeAlias[i],
476494
i);
477495
streams[i].mLastAudibleIndex.put(device, streams[i].getValidIndex(index));
478496
}
479497
}
480498
}
481499

500+
501+
private void updateStreamVolumeAlias(boolean updateVolumes) {
502+
int dtmfStreamAlias;
503+
if (mVoiceCapable) {
504+
mStreamVolumeAlias = STREAM_VOLUME_ALIAS;
505+
dtmfStreamAlias = AudioSystem.STREAM_RING;
506+
} else {
507+
mStreamVolumeAlias = STREAM_VOLUME_ALIAS_NON_VOICE;
508+
dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
509+
}
510+
if (isInCommunication()) {
511+
dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
512+
}
513+
mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
514+
if (updateVolumes) {
515+
mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias],
516+
false /*lastAudible*/);
517+
mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias],
518+
true /*lastAudible*/);
519+
sendMsg(mAudioHandler,
520+
MSG_SET_ALL_VOLUMES,
521+
SENDMSG_QUEUE,
522+
0,
523+
0,
524+
mStreamStates[AudioSystem.STREAM_DTMF], 0);
525+
}
526+
}
527+
482528
private void readPersistedSettings() {
483529
final ContentResolver cr = mContentResolver;
484530

@@ -555,7 +601,7 @@ public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType,
555601

556602
// Play sounds on STREAM_RING only and if lock screen is not on.
557603
if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
558-
((STREAM_VOLUME_ALIAS[streamType] != AudioSystem.STREAM_RING)
604+
((mStreamVolumeAlias[streamType] != AudioSystem.STREAM_RING)
559605
|| (mKeyguardManager != null && mKeyguardManager.isKeyguardLocked()))) {
560606
flags &= ~AudioManager.FLAG_PLAY_SOUND;
561607
}
@@ -571,7 +617,7 @@ public void adjustStreamVolume(int streamType, int direction, int flags) {
571617
// use stream type alias here so that streams with same alias have the same behavior,
572618
// including with regard to silent mode control (e.g the use of STREAM_RING below and in
573619
// checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
574-
int streamTypeAlias = STREAM_VOLUME_ALIAS[streamType];
620+
int streamTypeAlias = mStreamVolumeAlias[streamType];
575621
VolumeStreamState streamState = mStreamStates[streamTypeAlias];
576622

577623
final int device = getDeviceForStream(streamTypeAlias);
@@ -603,7 +649,7 @@ public void adjustStreamVolume(int streamType, int direction, int flags) {
603649
// on last audible index for an alias would not give the correct value
604650
int numStreamTypes = AudioSystem.getNumStreamTypes();
605651
for (int i = numStreamTypes - 1; i >= 0; i--) {
606-
if (STREAM_VOLUME_ALIAS[i] == streamTypeAlias) {
652+
if (mStreamVolumeAlias[i] == streamTypeAlias) {
607653
VolumeStreamState s = mStreamStates[i];
608654

609655
s.adjustLastAudibleIndex(direction, device);
@@ -656,7 +702,7 @@ public void adjustMasterVolume(int steps, int flags) {
656702
/** @see AudioManager#setStreamVolume(int, int, int) */
657703
public void setStreamVolume(int streamType, int index, int flags) {
658704
ensureValidStreamType(streamType);
659-
VolumeStreamState streamState = mStreamStates[STREAM_VOLUME_ALIAS[streamType]];
705+
VolumeStreamState streamState = mStreamStates[mStreamVolumeAlias[streamType]];
660706

661707
final int device = getDeviceForStream(streamType);
662708
// get last audible index if stream is muted, current index otherwise
@@ -665,13 +711,13 @@ public void setStreamVolume(int streamType, int index, int flags) {
665711

666712
// setting ring or notifications volume to 0 on voice capable devices enters silent mode
667713
if (mVoiceCapable && (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
668-
(STREAM_VOLUME_ALIAS[streamType] == AudioSystem.STREAM_RING))) {
714+
(mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING))) {
669715
int newRingerMode;
670716
if (index == 0) {
671717
newRingerMode = System.getInt(mContentResolver, System.VIBRATE_IN_SILENT, 1) == 1
672718
? AudioManager.RINGER_MODE_VIBRATE
673719
: AudioManager.RINGER_MODE_SILENT;
674-
setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType],
720+
setStreamVolumeInt(mStreamVolumeAlias[streamType],
675721
index,
676722
device,
677723
false,
@@ -682,8 +728,8 @@ public void setStreamVolume(int streamType, int index, int flags) {
682728
setRingerMode(newRingerMode);
683729
}
684730

685-
index = rescaleIndex(index * 10, streamType, STREAM_VOLUME_ALIAS[streamType]);
686-
setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, device, false, true);
731+
index = rescaleIndex(index * 10, streamType, mStreamVolumeAlias[streamType]);
732+
setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false, true);
687733
// get last audible index if stream is muted, current index otherwise
688734
index = streamState.getIndex(device,
689735
(streamState.muteCount() != 0) /* lastAudible */);
@@ -964,6 +1010,15 @@ public int getLastAudibleMasterVolume() {
9641010
return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
9651011
}
9661012

1013+
/** @see AudioManager#getMasterStreamType(int) */
1014+
public int getMasterStreamType() {
1015+
if (mVoiceCapable) {
1016+
return AudioSystem.STREAM_RING;
1017+
} else {
1018+
return AudioSystem.STREAM_MUSIC;
1019+
}
1020+
}
1021+
9671022
/** @see AudioManager#getRingerMode() */
9681023
public int getRingerMode() {
9691024
synchronized(mSettingsLock) {
@@ -1004,7 +1059,7 @@ private void setRingerModeInt(int ringerMode, boolean persist) {
10041059
// ring and notifications volume should never be 0 when not silenced
10051060
// on voice capable devices
10061061
if (mVoiceCapable &&
1007-
STREAM_VOLUME_ALIAS[streamType] == AudioSystem.STREAM_RING) {
1062+
mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
10081063

10091064
Set set = mStreamStates[streamType].mLastAudibleIndex.entrySet();
10101065
Iterator i = set.iterator();
@@ -1244,8 +1299,10 @@ int setModeInt(int mode, IBinder cb, int pid) {
12441299
}
12451300
int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
12461301
int device = getDeviceForStream(streamType);
1247-
int index = mStreamStates[STREAM_VOLUME_ALIAS[streamType]].getIndex(device, false);
1248-
setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, device, true, false);
1302+
int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device, false);
1303+
setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true, false);
1304+
1305+
updateStreamVolumeAlias(true /*updateVolumes*/);
12491306
}
12501307
return newModeOwnerPid;
12511308
}
@@ -1978,18 +2035,23 @@ private void ensureValidStreamType(int streamType) {
19782035
}
19792036
}
19802037

1981-
private int getActiveStreamType(int suggestedStreamType) {
2038+
private boolean isInCommunication() {
2039+
boolean isOffhook = false;
19822040

19832041
if (mVoiceCapable) {
1984-
boolean isOffhook = false;
19852042
try {
19862043
ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
19872044
if (phone != null) isOffhook = phone.isOffhook();
19882045
} catch (RemoteException e) {
19892046
Log.w(TAG, "Couldn't connect to phone service", e);
19902047
}
2048+
}
2049+
return (isOffhook || getMode() == AudioManager.MODE_IN_COMMUNICATION);
2050+
}
19912051

1992-
if (isOffhook || getMode() == AudioManager.MODE_IN_COMMUNICATION) {
2052+
private int getActiveStreamType(int suggestedStreamType) {
2053+
if (mVoiceCapable) {
2054+
if (isInCommunication()) {
19932055
if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
19942056
== AudioSystem.FORCE_BT_SCO) {
19952057
// Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
@@ -2010,7 +2072,7 @@ private int getActiveStreamType(int suggestedStreamType) {
20102072
return suggestedStreamType;
20112073
}
20122074
} else {
2013-
if (getMode() == AudioManager.MODE_IN_COMMUNICATION) {
2075+
if (isInCommunication()) {
20142076
if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
20152077
== AudioSystem.FORCE_BT_SCO) {
20162078
// Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
@@ -2181,7 +2243,7 @@ public void readSettings() {
21812243
// 0 without the device being in silent mode
21822244
if ((lastAudibleIndex == 0) &&
21832245
(mVoiceCapable ||
2184-
(STREAM_VOLUME_ALIAS[mStreamType] != AudioSystem.STREAM_MUSIC))) {
2246+
(mStreamVolumeAlias[mStreamType] != AudioSystem.STREAM_MUSIC))) {
21852247
lastAudibleIndex = AudioManager.DEFAULT_STREAM_VOLUME[mStreamType];
21862248
// Correct the data base
21872249
sendMsg(mAudioHandler,
@@ -2198,7 +2260,7 @@ public void readSettings() {
21982260
// this is permitted on tablets for music stream type.
21992261
if (checkSilentVolume && (index == 0) &&
22002262
(mVoiceCapable ||
2201-
(STREAM_VOLUME_ALIAS[mStreamType] != AudioSystem.STREAM_MUSIC))) {
2263+
(mStreamVolumeAlias[mStreamType] != AudioSystem.STREAM_MUSIC))) {
22022264
index = lastAudibleIndex;
22032265
// Correct the data base
22042266
sendMsg(mAudioHandler,
@@ -2258,11 +2320,11 @@ public boolean setIndex(int index, int device, boolean lastAudible) {
22582320
// Apply change to all streams using this one as alias
22592321
int numStreamTypes = AudioSystem.getNumStreamTypes();
22602322
for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
2261-
if (streamType != mStreamType && STREAM_VOLUME_ALIAS[streamType] == mStreamType) {
2323+
if (streamType != mStreamType && mStreamVolumeAlias[streamType] == mStreamType) {
22622324
mStreamStates[streamType].setIndex(rescaleIndex(index,
22632325
mStreamType,
22642326
streamType),
2265-
device,
2327+
getDeviceForStream(streamType),
22662328
lastAudible);
22672329
}
22682330
}
@@ -2301,6 +2363,27 @@ public int getMaxIndex() {
23012363
return mIndexMax;
23022364
}
23032365

2366+
public HashMap <Integer, Integer> getAllIndexes(boolean lastAudible) {
2367+
if (lastAudible) {
2368+
return mLastAudibleIndex;
2369+
} else {
2370+
return mIndex;
2371+
}
2372+
}
2373+
2374+
public void setAllIndexes(VolumeStreamState srcStream, boolean lastAudible) {
2375+
HashMap <Integer, Integer> indexes = srcStream.getAllIndexes(lastAudible);
2376+
Set set = indexes.entrySet();
2377+
Iterator i = set.iterator();
2378+
while (i.hasNext()) {
2379+
Map.Entry entry = (Map.Entry)i.next();
2380+
int device = ((Integer)entry.getKey()).intValue();
2381+
int index = ((Integer)entry.getValue()).intValue();
2382+
index = rescaleIndex(index, srcStream.getStreamType(), mStreamType);
2383+
setIndex(index, device, lastAudible);
2384+
}
2385+
}
2386+
23042387
public void mute(IBinder cb, boolean state) {
23052388
VolumeDeathHandler handler = getDeathHandler(cb, state);
23062389
if (handler == null) {
@@ -2310,6 +2393,10 @@ public void mute(IBinder cb, boolean state) {
23102393
handler.mute(state);
23112394
}
23122395

2396+
public int getStreamType() {
2397+
return mStreamType;
2398+
}
2399+
23132400
private int getValidIndex(int index) {
23142401
if (index < 0) {
23152402
return 0;
@@ -2484,8 +2571,8 @@ private void setDeviceVolume(VolumeStreamState streamState, int device) {
24842571
int numStreamTypes = AudioSystem.getNumStreamTypes();
24852572
for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
24862573
if (streamType != streamState.mStreamType &&
2487-
STREAM_VOLUME_ALIAS[streamType] == streamState.mStreamType) {
2488-
mStreamStates[streamType].applyDeviceVolume(device);
2574+
mStreamVolumeAlias[streamType] == streamState.mStreamType) {
2575+
mStreamStates[streamType].applyDeviceVolume(getDeviceForStream(streamType));
24892576
}
24902577
}
24912578

@@ -2509,7 +2596,7 @@ private void setAllVolumes(VolumeStreamState streamState) {
25092596
int numStreamTypes = AudioSystem.getNumStreamTypes();
25102597
for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
25112598
if (streamType != streamState.mStreamType &&
2512-
STREAM_VOLUME_ALIAS[streamType] == streamState.mStreamType) {
2599+
mStreamVolumeAlias[streamType] == streamState.mStreamType) {
25132600
mStreamStates[streamType].applyAllVolumes();
25142601
}
25152602
}

media/java/android/media/IAudioService.aidl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,4 +117,6 @@ interface IAudioService {
117117
void stopBluetoothSco(IBinder cb);
118118

119119
void forceVolumeControlStream(int streamType, IBinder cb);
120+
121+
int getMasterStreamType();
120122
}

0 commit comments

Comments
 (0)