am 24938df9: Merge "AudioService: synchronized access to volume index" into jb-dev

* commit '24938df9e44dbed2ea9c72370907fe403674ee00':
  AudioService: synchronized access to volume index
This commit is contained in:
Eric Laurent
2012-05-10 15:23:17 -07:00
committed by Android Git Automerger

View File

@@ -70,6 +70,7 @@ import java.io.FileDescriptor;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@@ -515,12 +516,14 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
int index = rescaleIndex(streams[i].getIndex(device, false /* lastAudible */), int index = rescaleIndex(streams[i].getIndex(device, false /* lastAudible */),
mStreamVolumeAlias[i], mStreamVolumeAlias[i],
i); i);
streams[i].mIndex.put(device, streams[i].getValidIndex(index)); synchronized (streams[i]) {
streams[i].applyDeviceVolume(device); streams[i].mIndex.put(device, streams[i].getValidIndex(index));
index = rescaleIndex(streams[i].getIndex(device, true /* lastAudible */), streams[i].applyDeviceVolume(device);
mStreamVolumeAlias[i], index = rescaleIndex(streams[i].getIndex(device, true /* lastAudible */),
i); mStreamVolumeAlias[i],
streams[i].mLastAudibleIndex.put(device, streams[i].getValidIndex(index)); i);
streams[i].mLastAudibleIndex.put(device, streams[i].getValidIndex(index));
}
} }
} }
} }
@@ -1112,12 +1115,14 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
// on voice capable devices // on voice capable devices
if (mVoiceCapable && if (mVoiceCapable &&
mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) { mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
Set set = mStreamStates[streamType].mLastAudibleIndex.entrySet(); synchronized (mStreamStates[streamType]) {
Iterator i = set.iterator(); Set set = mStreamStates[streamType].mLastAudibleIndex.entrySet();
while (i.hasNext()) { Iterator i = set.iterator();
Map.Entry entry = (Map.Entry)i.next(); while (i.hasNext()) {
if ((Integer)entry.getValue() == 0) { Map.Entry entry = (Map.Entry)i.next();
entry.setValue(10); if ((Integer)entry.getValue() == 0) {
entry.setValue(10);
}
} }
} }
} }
@@ -1583,19 +1588,21 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
for (int streamType = 0; streamType < numStreamTypes; streamType++) { for (int streamType = 0; streamType < numStreamTypes; streamType++) {
VolumeStreamState streamState = mStreamStates[streamType]; VolumeStreamState streamState = mStreamStates[streamType];
streamState.readSettings(); synchronized (streamState) {
streamState.readSettings();
// unmute stream that was muted but is not affect by mute anymore // unmute stream that was muted but is not affect by mute anymore
if (streamState.muteCount() != 0 && !isStreamAffectedByMute(streamType)) { if (streamState.muteCount() != 0 && !isStreamAffectedByMute(streamType)) {
int size = streamState.mDeathHandlers.size(); int size = streamState.mDeathHandlers.size();
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
streamState.mDeathHandlers.get(i).mMuteCount = 1; streamState.mDeathHandlers.get(i).mMuteCount = 1;
streamState.mDeathHandlers.get(i).mute(false); streamState.mDeathHandlers.get(i).mute(false);
}
}
// apply stream volume
if (streamState.muteCount() == 0) {
streamState.applyAllVolumes();
} }
}
// apply stream volume
if (streamState.muteCount() == 0) {
streamState.applyAllVolumes();
} }
} }
@@ -2232,9 +2239,10 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
private String mVolumeIndexSettingName; private String mVolumeIndexSettingName;
private String mLastAudibleVolumeIndexSettingName; private String mLastAudibleVolumeIndexSettingName;
private int mIndexMax; private int mIndexMax;
private final HashMap <Integer, Integer> mIndex = new HashMap <Integer, Integer>(); private final ConcurrentHashMap<Integer, Integer> mIndex =
private final HashMap <Integer, Integer> mLastAudibleIndex = new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
new HashMap <Integer, Integer>(); private final ConcurrentHashMap<Integer, Integer> mLastAudibleIndex =
new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death
private VolumeStreamState(String settingName, int streamType) { private VolumeStreamState(String settingName, int streamType) {
@@ -2265,7 +2273,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
return name + "_" + suffix; return name + "_" + suffix;
} }
public void readSettings() { public synchronized void readSettings() {
int remainingDevices = AudioSystem.DEVICE_OUT_ALL; int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
for (int i = 0; remainingDevices != 0; i++) { for (int i = 0; remainingDevices != 0; i++) {
@@ -2339,7 +2347,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
device); device);
} }
public void applyAllVolumes() { public synchronized void applyAllVolumes() {
// apply default volume first: by convention this will reset all // apply default volume first: by convention this will reset all
// devices volumes in audio policy manager to the supplied value // devices volumes in audio policy manager to the supplied value
AudioSystem.setStreamVolumeIndex(mStreamType, AudioSystem.setStreamVolumeIndex(mStreamType,
@@ -2366,7 +2374,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
true /* lastAudible */); true /* lastAudible */);
} }
public boolean setIndex(int index, int device, boolean lastAudible) { public synchronized boolean setIndex(int index, int device, boolean lastAudible) {
int oldIndex = getIndex(device, false /* lastAudible */); int oldIndex = getIndex(device, false /* lastAudible */);
index = getValidIndex(index); index = getValidIndex(index);
mIndex.put(device, getValidIndex(index)); mIndex.put(device, getValidIndex(index));
@@ -2400,8 +2408,8 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
} }
} }
public int getIndex(int device, boolean lastAudible) { public synchronized int getIndex(int device, boolean lastAudible) {
HashMap <Integer, Integer> indexes; ConcurrentHashMap <Integer, Integer> indexes;
if (lastAudible) { if (lastAudible) {
indexes = mLastAudibleIndex; indexes = mLastAudibleIndex;
} else { } else {
@@ -2415,11 +2423,11 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
return index.intValue(); return index.intValue();
} }
public void setLastAudibleIndex(int index, int device) { public synchronized void setLastAudibleIndex(int index, int device) {
mLastAudibleIndex.put(device, getValidIndex(index)); mLastAudibleIndex.put(device, getValidIndex(index));
} }
public void adjustLastAudibleIndex(int deltaIndex, int device) { public synchronized void adjustLastAudibleIndex(int deltaIndex, int device) {
setLastAudibleIndex(getIndex(device, setLastAudibleIndex(getIndex(device,
true /* lastAudible */) + deltaIndex * 10, true /* lastAudible */) + deltaIndex * 10,
device); device);
@@ -2429,7 +2437,8 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
return mIndexMax; return mIndexMax;
} }
public HashMap <Integer, Integer> getAllIndexes(boolean lastAudible) { // only called by setAllIndexes() which is already synchronized
public ConcurrentHashMap <Integer, Integer> getAllIndexes(boolean lastAudible) {
if (lastAudible) { if (lastAudible) {
return mLastAudibleIndex; return mLastAudibleIndex;
} else { } else {
@@ -2437,8 +2446,8 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
} }
} }
public void setAllIndexes(VolumeStreamState srcStream, boolean lastAudible) { public synchronized void setAllIndexes(VolumeStreamState srcStream, boolean lastAudible) {
HashMap <Integer, Integer> indexes = srcStream.getAllIndexes(lastAudible); ConcurrentHashMap <Integer, Integer> indexes = srcStream.getAllIndexes(lastAudible);
Set set = indexes.entrySet(); Set set = indexes.entrySet();
Iterator i = set.iterator(); Iterator i = set.iterator();
while (i.hasNext()) { while (i.hasNext()) {
@@ -2450,7 +2459,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
} }
} }
public void mute(IBinder cb, boolean state) { public synchronized void mute(IBinder cb, boolean state) {
VolumeDeathHandler handler = getDeathHandler(cb, state); VolumeDeathHandler handler = getDeathHandler(cb, state);
if (handler == null) { if (handler == null) {
Log.e(TAG, "Could not get client death handler for stream: "+mStreamType); Log.e(TAG, "Could not get client death handler for stream: "+mStreamType);
@@ -2481,25 +2490,68 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
mICallback = cb; mICallback = cb;
} }
// must be called while synchronized on parent VolumeStreamState
public void mute(boolean state) { public void mute(boolean state) {
synchronized(mDeathHandlers) { if (state) {
if (state) { if (mMuteCount == 0) {
if (mMuteCount == 0) { // Register for client death notification
// Register for client death notification try {
try { // mICallback can be 0 if muted by AudioService
// mICallback can be 0 if muted by AudioService if (mICallback != null) {
if (mICallback != null) { mICallback.linkToDeath(this, 0);
mICallback.linkToDeath(this, 0); }
mDeathHandlers.add(this);
// If the stream is not yet muted by any client, set level to 0
if (muteCount() == 0) {
Set set = mIndex.entrySet();
Iterator i = set.iterator();
while (i.hasNext()) {
Map.Entry entry = (Map.Entry)i.next();
int device = ((Integer)entry.getKey()).intValue();
setIndex(0, device, false /* lastAudible */);
} }
mDeathHandlers.add(this); sendMsg(mAudioHandler,
// If the stream is not yet muted by any client, set level to 0 MSG_SET_ALL_VOLUMES,
if (muteCount() == 0) { SENDMSG_QUEUE,
0,
0,
VolumeStreamState.this, 0);
}
} catch (RemoteException e) {
// Client has died!
binderDied();
return;
}
} else {
Log.w(TAG, "stream: "+mStreamType+" was already muted by this client");
}
mMuteCount++;
} else {
if (mMuteCount == 0) {
Log.e(TAG, "unexpected unmute for stream: "+mStreamType);
} else {
mMuteCount--;
if (mMuteCount == 0) {
// Unregister from client death notification
mDeathHandlers.remove(this);
// mICallback can be 0 if muted by AudioService
if (mICallback != null) {
mICallback.unlinkToDeath(this, 0);
}
if (muteCount() == 0) {
// If the stream is not muted any more, restore its volume if
// ringer mode allows it
if (!isStreamAffectedByRingerMode(mStreamType) ||
mRingerMode == AudioManager.RINGER_MODE_NORMAL) {
Set set = mIndex.entrySet(); Set set = mIndex.entrySet();
Iterator i = set.iterator(); Iterator i = set.iterator();
while (i.hasNext()) { while (i.hasNext()) {
Map.Entry entry = (Map.Entry)i.next(); Map.Entry entry = (Map.Entry)i.next();
int device = ((Integer)entry.getKey()).intValue(); int device = ((Integer)entry.getKey()).intValue();
setIndex(0, device, false /* lastAudible */); setIndex(getIndex(device,
true /* lastAudible */),
device,
false /* lastAudible */);
} }
sendMsg(mAudioHandler, sendMsg(mAudioHandler,
MSG_SET_ALL_VOLUMES, MSG_SET_ALL_VOLUMES,
@@ -2508,55 +2560,9 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
0, 0,
VolumeStreamState.this, 0); VolumeStreamState.this, 0);
} }
} catch (RemoteException e) {
// Client has died!
binderDied();
mDeathHandlers.notify();
return;
}
} else {
Log.w(TAG, "stream: "+mStreamType+" was already muted by this client");
}
mMuteCount++;
} else {
if (mMuteCount == 0) {
Log.e(TAG, "unexpected unmute for stream: "+mStreamType);
} else {
mMuteCount--;
if (mMuteCount == 0) {
// Unregistr from client death notification
mDeathHandlers.remove(this);
// mICallback can be 0 if muted by AudioService
if (mICallback != null) {
mICallback.unlinkToDeath(this, 0);
}
if (muteCount() == 0) {
// If the stream is not muted any more, restore it's volume if
// ringer mode allows it
if (!isStreamAffectedByRingerMode(mStreamType) ||
mRingerMode == AudioManager.RINGER_MODE_NORMAL) {
Set set = mIndex.entrySet();
Iterator i = set.iterator();
while (i.hasNext()) {
Map.Entry entry = (Map.Entry)i.next();
int device = ((Integer)entry.getKey()).intValue();
setIndex(getIndex(device,
true /* lastAudible */),
device,
false /* lastAudible */);
}
sendMsg(mAudioHandler,
MSG_SET_ALL_VOLUMES,
SENDMSG_QUEUE,
0,
0,
VolumeStreamState.this, 0);
}
}
} }
} }
} }
mDeathHandlers.notify();
} }
} }
@@ -2570,7 +2576,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
} }
} }
private int muteCount() { private synchronized int muteCount() {
int count = 0; int count = 0;
int size = mDeathHandlers.size(); int size = mDeathHandlers.size();
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
@@ -2579,26 +2585,25 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
return count; return count;
} }
// only called by mute() which is already synchronized
private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) { private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) {
synchronized(mDeathHandlers) { VolumeDeathHandler handler;
VolumeDeathHandler handler; int size = mDeathHandlers.size();
int size = mDeathHandlers.size(); for (int i = 0; i < size; i++) {
for (int i = 0; i < size; i++) { handler = mDeathHandlers.get(i);
handler = mDeathHandlers.get(i); if (cb == handler.mICallback) {
if (cb == handler.mICallback) { return handler;
return handler;
}
} }
// If this is the first mute request for this client, create a new
// client death handler. Otherwise, it is an out of sequence unmute request.
if (state) {
handler = new VolumeDeathHandler(cb);
} else {
Log.w(TAG, "stream was not muted by this client");
handler = null;
}
return handler;
} }
// If this is the first mute request for this client, create a new
// client death handler. Otherwise, it is an out of sequence unmute request.
if (state) {
handler = new VolumeDeathHandler(cb);
} else {
Log.w(TAG, "stream was not muted by this client");
handler = null;
}
return handler;
} }
private void dump(PrintWriter pw) { private void dump(PrintWriter pw) {