7070import java .io .IOException ;
7171import java .io .PrintWriter ;
7272import java .util .ArrayList ;
73+ import java .util .concurrent .ConcurrentHashMap ;
7374import java .util .HashMap ;
7475import java .util .Iterator ;
7576import java .util .List ;
@@ -515,12 +516,14 @@ private void createStreamStates() {
515516 int index = rescaleIndex (streams [i ].getIndex (device , false /* lastAudible */ ),
516517 mStreamVolumeAlias [i ],
517518 i );
518- streams [i ].mIndex .put (device , streams [i ].getValidIndex (index ));
519- streams [i ].applyDeviceVolume (device );
520- index = rescaleIndex (streams [i ].getIndex (device , true /* lastAudible */ ),
521- mStreamVolumeAlias [i ],
522- i );
523- streams [i ].mLastAudibleIndex .put (device , streams [i ].getValidIndex (index ));
519+ synchronized (streams [i ]) {
520+ streams [i ].mIndex .put (device , streams [i ].getValidIndex (index ));
521+ streams [i ].applyDeviceVolume (device );
522+ index = rescaleIndex (streams [i ].getIndex (device , true /* lastAudible */ ),
523+ mStreamVolumeAlias [i ],
524+ i );
525+ streams [i ].mLastAudibleIndex .put (device , streams [i ].getValidIndex (index ));
526+ }
524527 }
525528 }
526529 }
@@ -1112,12 +1115,14 @@ private void setRingerModeInt(int ringerMode, boolean persist) {
11121115 // on voice capable devices
11131116 if (mVoiceCapable &&
11141117 mStreamVolumeAlias [streamType ] == AudioSystem .STREAM_RING ) {
1115- Set set = mStreamStates [streamType ].mLastAudibleIndex .entrySet ();
1116- Iterator i = set .iterator ();
1117- while (i .hasNext ()) {
1118- Map .Entry entry = (Map .Entry )i .next ();
1119- if ((Integer )entry .getValue () == 0 ) {
1120- entry .setValue (10 );
1118+ synchronized (mStreamStates [streamType ]) {
1119+ Set set = mStreamStates [streamType ].mLastAudibleIndex .entrySet ();
1120+ Iterator i = set .iterator ();
1121+ while (i .hasNext ()) {
1122+ Map .Entry entry = (Map .Entry )i .next ();
1123+ if ((Integer )entry .getValue () == 0 ) {
1124+ entry .setValue (10 );
1125+ }
11211126 }
11221127 }
11231128 }
@@ -1583,19 +1588,21 @@ public void reloadAudioSettings() {
15831588 for (int streamType = 0 ; streamType < numStreamTypes ; streamType ++) {
15841589 VolumeStreamState streamState = mStreamStates [streamType ];
15851590
1586- streamState .readSettings ();
1591+ synchronized (streamState ) {
1592+ streamState .readSettings ();
15871593
1588- // unmute stream that was muted but is not affect by mute anymore
1589- if (streamState .muteCount () != 0 && !isStreamAffectedByMute (streamType )) {
1590- int size = streamState .mDeathHandlers .size ();
1591- for (int i = 0 ; i < size ; i ++) {
1592- streamState .mDeathHandlers .get (i ).mMuteCount = 1 ;
1593- streamState .mDeathHandlers .get (i ).mute (false );
1594+ // unmute stream that was muted but is not affect by mute anymore
1595+ if (streamState .muteCount () != 0 && !isStreamAffectedByMute (streamType )) {
1596+ int size = streamState .mDeathHandlers .size ();
1597+ for (int i = 0 ; i < size ; i ++) {
1598+ streamState .mDeathHandlers .get (i ).mMuteCount = 1 ;
1599+ streamState .mDeathHandlers .get (i ).mute (false );
1600+ }
1601+ }
1602+ // apply stream volume
1603+ if (streamState .muteCount () == 0 ) {
1604+ streamState .applyAllVolumes ();
15941605 }
1595- }
1596- // apply stream volume
1597- if (streamState .muteCount () == 0 ) {
1598- streamState .applyAllVolumes ();
15991606 }
16001607 }
16011608
@@ -2232,9 +2239,10 @@ public class VolumeStreamState {
22322239 private String mVolumeIndexSettingName ;
22332240 private String mLastAudibleVolumeIndexSettingName ;
22342241 private int mIndexMax ;
2235- private final HashMap <Integer , Integer > mIndex = new HashMap <Integer , Integer >();
2236- private final HashMap <Integer , Integer > mLastAudibleIndex =
2237- new HashMap <Integer , Integer >();
2242+ private final ConcurrentHashMap <Integer , Integer > mIndex =
2243+ new ConcurrentHashMap <Integer , Integer >(8 , 0.75f , 4 );
2244+ private final ConcurrentHashMap <Integer , Integer > mLastAudibleIndex =
2245+ new ConcurrentHashMap <Integer , Integer >(8 , 0.75f , 4 );
22382246 private ArrayList <VolumeDeathHandler > mDeathHandlers ; //handles mute/solo clients death
22392247
22402248 private VolumeStreamState (String settingName , int streamType ) {
@@ -2265,7 +2273,7 @@ public String getSettingNameForDevice(boolean lastAudible, int device) {
22652273 return name + "_" + suffix ;
22662274 }
22672275
2268- public void readSettings () {
2276+ public synchronized void readSettings () {
22692277 int remainingDevices = AudioSystem .DEVICE_OUT_ALL ;
22702278
22712279 for (int i = 0 ; remainingDevices != 0 ; i ++) {
@@ -2339,7 +2347,7 @@ public void applyDeviceVolume(int device) {
23392347 device );
23402348 }
23412349
2342- public void applyAllVolumes () {
2350+ public synchronized void applyAllVolumes () {
23432351 // apply default volume first: by convention this will reset all
23442352 // devices volumes in audio policy manager to the supplied value
23452353 AudioSystem .setStreamVolumeIndex (mStreamType ,
@@ -2366,7 +2374,7 @@ public boolean adjustIndex(int deltaIndex, int device) {
23662374 true /* lastAudible */ );
23672375 }
23682376
2369- public boolean setIndex (int index , int device , boolean lastAudible ) {
2377+ public synchronized boolean setIndex (int index , int device , boolean lastAudible ) {
23702378 int oldIndex = getIndex (device , false /* lastAudible */ );
23712379 index = getValidIndex (index );
23722380 mIndex .put (device , getValidIndex (index ));
@@ -2400,8 +2408,8 @@ public boolean setIndex(int index, int device, boolean lastAudible) {
24002408 }
24012409 }
24022410
2403- public int getIndex (int device , boolean lastAudible ) {
2404- HashMap <Integer , Integer > indexes ;
2411+ public synchronized int getIndex (int device , boolean lastAudible ) {
2412+ ConcurrentHashMap <Integer , Integer > indexes ;
24052413 if (lastAudible ) {
24062414 indexes = mLastAudibleIndex ;
24072415 } else {
@@ -2415,11 +2423,11 @@ public int getIndex(int device, boolean lastAudible) {
24152423 return index .intValue ();
24162424 }
24172425
2418- public void setLastAudibleIndex (int index , int device ) {
2426+ public synchronized void setLastAudibleIndex (int index , int device ) {
24192427 mLastAudibleIndex .put (device , getValidIndex (index ));
24202428 }
24212429
2422- public void adjustLastAudibleIndex (int deltaIndex , int device ) {
2430+ public synchronized void adjustLastAudibleIndex (int deltaIndex , int device ) {
24232431 setLastAudibleIndex (getIndex (device ,
24242432 true /* lastAudible */ ) + deltaIndex * 10 ,
24252433 device );
@@ -2429,16 +2437,17 @@ public int getMaxIndex() {
24292437 return mIndexMax ;
24302438 }
24312439
2432- public HashMap <Integer , Integer > getAllIndexes (boolean lastAudible ) {
2440+ // only called by setAllIndexes() which is already synchronized
2441+ public ConcurrentHashMap <Integer , Integer > getAllIndexes (boolean lastAudible ) {
24332442 if (lastAudible ) {
24342443 return mLastAudibleIndex ;
24352444 } else {
24362445 return mIndex ;
24372446 }
24382447 }
24392448
2440- public void setAllIndexes (VolumeStreamState srcStream , boolean lastAudible ) {
2441- HashMap <Integer , Integer > indexes = srcStream .getAllIndexes (lastAudible );
2449+ public synchronized void setAllIndexes (VolumeStreamState srcStream , boolean lastAudible ) {
2450+ ConcurrentHashMap <Integer , Integer > indexes = srcStream .getAllIndexes (lastAudible );
24422451 Set set = indexes .entrySet ();
24432452 Iterator i = set .iterator ();
24442453 while (i .hasNext ()) {
@@ -2450,7 +2459,7 @@ public void setAllIndexes(VolumeStreamState srcStream, boolean lastAudible) {
24502459 }
24512460 }
24522461
2453- public void mute (IBinder cb , boolean state ) {
2462+ public synchronized void mute (IBinder cb , boolean state ) {
24542463 VolumeDeathHandler handler = getDeathHandler (cb , state );
24552464 if (handler == null ) {
24562465 Log .e (TAG , "Could not get client death handler for stream: " +mStreamType );
@@ -2481,25 +2490,68 @@ private class VolumeDeathHandler implements IBinder.DeathRecipient {
24812490 mICallback = cb ;
24822491 }
24832492
2493+ // must be called while synchronized on parent VolumeStreamState
24842494 public void mute (boolean state ) {
2485- synchronized (mDeathHandlers ) {
2486- if (state ) {
2487- if (mMuteCount == 0 ) {
2488- // Register for client death notification
2489- try {
2490- // mICallback can be 0 if muted by AudioService
2491- if (mICallback != null ) {
2492- mICallback .linkToDeath (this , 0 );
2495+ if (state ) {
2496+ if (mMuteCount == 0 ) {
2497+ // Register for client death notification
2498+ try {
2499+ // mICallback can be 0 if muted by AudioService
2500+ if (mICallback != null ) {
2501+ mICallback .linkToDeath (this , 0 );
2502+ }
2503+ mDeathHandlers .add (this );
2504+ // If the stream is not yet muted by any client, set level to 0
2505+ if (muteCount () == 0 ) {
2506+ Set set = mIndex .entrySet ();
2507+ Iterator i = set .iterator ();
2508+ while (i .hasNext ()) {
2509+ Map .Entry entry = (Map .Entry )i .next ();
2510+ int device = ((Integer )entry .getKey ()).intValue ();
2511+ setIndex (0 , device , false /* lastAudible */ );
24932512 }
2494- mDeathHandlers .add (this );
2495- // If the stream is not yet muted by any client, set level to 0
2496- if (muteCount () == 0 ) {
2513+ sendMsg (mAudioHandler ,
2514+ MSG_SET_ALL_VOLUMES ,
2515+ SENDMSG_QUEUE ,
2516+ 0 ,
2517+ 0 ,
2518+ VolumeStreamState .this , 0 );
2519+ }
2520+ } catch (RemoteException e ) {
2521+ // Client has died!
2522+ binderDied ();
2523+ return ;
2524+ }
2525+ } else {
2526+ Log .w (TAG , "stream: " +mStreamType +" was already muted by this client" );
2527+ }
2528+ mMuteCount ++;
2529+ } else {
2530+ if (mMuteCount == 0 ) {
2531+ Log .e (TAG , "unexpected unmute for stream: " +mStreamType );
2532+ } else {
2533+ mMuteCount --;
2534+ if (mMuteCount == 0 ) {
2535+ // Unregister from client death notification
2536+ mDeathHandlers .remove (this );
2537+ // mICallback can be 0 if muted by AudioService
2538+ if (mICallback != null ) {
2539+ mICallback .unlinkToDeath (this , 0 );
2540+ }
2541+ if (muteCount () == 0 ) {
2542+ // If the stream is not muted any more, restore its volume if
2543+ // ringer mode allows it
2544+ if (!isStreamAffectedByRingerMode (mStreamType ) ||
2545+ mRingerMode == AudioManager .RINGER_MODE_NORMAL ) {
24972546 Set set = mIndex .entrySet ();
24982547 Iterator i = set .iterator ();
24992548 while (i .hasNext ()) {
25002549 Map .Entry entry = (Map .Entry )i .next ();
25012550 int device = ((Integer )entry .getKey ()).intValue ();
2502- setIndex (0 , device , false /* lastAudible */ );
2551+ setIndex (getIndex (device ,
2552+ true /* lastAudible */ ),
2553+ device ,
2554+ false /* lastAudible */ );
25032555 }
25042556 sendMsg (mAudioHandler ,
25052557 MSG_SET_ALL_VOLUMES ,
@@ -2508,55 +2560,9 @@ public void mute(boolean state) {
25082560 0 ,
25092561 VolumeStreamState .this , 0 );
25102562 }
2511- } catch (RemoteException e ) {
2512- // Client has died!
2513- binderDied ();
2514- mDeathHandlers .notify ();
2515- return ;
2516- }
2517- } else {
2518- Log .w (TAG , "stream: " +mStreamType +" was already muted by this client" );
2519- }
2520- mMuteCount ++;
2521- } else {
2522- if (mMuteCount == 0 ) {
2523- Log .e (TAG , "unexpected unmute for stream: " +mStreamType );
2524- } else {
2525- mMuteCount --;
2526- if (mMuteCount == 0 ) {
2527- // Unregistr from client death notification
2528- mDeathHandlers .remove (this );
2529- // mICallback can be 0 if muted by AudioService
2530- if (mICallback != null ) {
2531- mICallback .unlinkToDeath (this , 0 );
2532- }
2533- if (muteCount () == 0 ) {
2534- // If the stream is not muted any more, restore it's volume if
2535- // ringer mode allows it
2536- if (!isStreamAffectedByRingerMode (mStreamType ) ||
2537- mRingerMode == AudioManager .RINGER_MODE_NORMAL ) {
2538- Set set = mIndex .entrySet ();
2539- Iterator i = set .iterator ();
2540- while (i .hasNext ()) {
2541- Map .Entry entry = (Map .Entry )i .next ();
2542- int device = ((Integer )entry .getKey ()).intValue ();
2543- setIndex (getIndex (device ,
2544- true /* lastAudible */ ),
2545- device ,
2546- false /* lastAudible */ );
2547- }
2548- sendMsg (mAudioHandler ,
2549- MSG_SET_ALL_VOLUMES ,
2550- SENDMSG_QUEUE ,
2551- 0 ,
2552- 0 ,
2553- VolumeStreamState .this , 0 );
2554- }
2555- }
25562563 }
25572564 }
25582565 }
2559- mDeathHandlers .notify ();
25602566 }
25612567 }
25622568
@@ -2570,7 +2576,7 @@ public void binderDied() {
25702576 }
25712577 }
25722578
2573- private int muteCount () {
2579+ private synchronized int muteCount () {
25742580 int count = 0 ;
25752581 int size = mDeathHandlers .size ();
25762582 for (int i = 0 ; i < size ; i ++) {
@@ -2579,26 +2585,25 @@ private int muteCount() {
25792585 return count ;
25802586 }
25812587
2588+ // only called by mute() which is already synchronized
25822589 private VolumeDeathHandler getDeathHandler (IBinder cb , boolean state ) {
2583- synchronized (mDeathHandlers ) {
2584- VolumeDeathHandler handler ;
2585- int size = mDeathHandlers .size ();
2586- for (int i = 0 ; i < size ; i ++) {
2587- handler = mDeathHandlers .get (i );
2588- if (cb == handler .mICallback ) {
2589- return handler ;
2590- }
2591- }
2592- // If this is the first mute request for this client, create a new
2593- // client death handler. Otherwise, it is an out of sequence unmute request.
2594- if (state ) {
2595- handler = new VolumeDeathHandler (cb );
2596- } else {
2597- Log .w (TAG , "stream was not muted by this client" );
2598- handler = null ;
2590+ VolumeDeathHandler handler ;
2591+ int size = mDeathHandlers .size ();
2592+ for (int i = 0 ; i < size ; i ++) {
2593+ handler = mDeathHandlers .get (i );
2594+ if (cb == handler .mICallback ) {
2595+ return handler ;
25992596 }
2600- return handler ;
26012597 }
2598+ // If this is the first mute request for this client, create a new
2599+ // client death handler. Otherwise, it is an out of sequence unmute request.
2600+ if (state ) {
2601+ handler = new VolumeDeathHandler (cb );
2602+ } else {
2603+ Log .w (TAG , "stream was not muted by this client" );
2604+ handler = null ;
2605+ }
2606+ return handler ;
26022607 }
26032608
26042609 private void dump (PrintWriter pw ) {
0 commit comments