am dce7a427: Merge "Full volume on remote submix for apps that need it" into lmp-dev
* commit 'dce7a427593c6e11277d9e3075ab027512923276': Full volume on remote submix for apps that need it
This commit is contained in:
@@ -18,10 +18,15 @@ package android.media;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Iterator;
|
||||
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
@@ -99,6 +104,8 @@ public class AudioRecord
|
||||
|
||||
private final static String TAG = "android.media.AudioRecord";
|
||||
|
||||
/** @hide */
|
||||
public final static String SUBMIX_FIXED_VOLUME = "fixedVolume";
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Used exclusively by native code
|
||||
@@ -184,6 +191,7 @@ public class AudioRecord
|
||||
* AudioAttributes
|
||||
*/
|
||||
private AudioAttributes mAudioAttributes;
|
||||
private boolean mIsSubmixFullVolume = false;
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Constructor, Finalize
|
||||
@@ -267,6 +275,18 @@ public class AudioRecord
|
||||
|
||||
mAudioAttributes = attributes;
|
||||
|
||||
// is this AudioRecord using REMOTE_SUBMIX at full volume?
|
||||
if (mAudioAttributes.getCapturePreset() == MediaRecorder.AudioSource.REMOTE_SUBMIX) {
|
||||
final Iterator<String> tagsIter = mAudioAttributes.getTags().iterator();
|
||||
while (tagsIter.hasNext()) {
|
||||
if (tagsIter.next().equalsIgnoreCase(SUBMIX_FIXED_VOLUME)) {
|
||||
mIsSubmixFullVolume = true;
|
||||
Log.v(TAG, "Will record from REMOTE_SUBMIX at full fixed volume");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int rate = 0;
|
||||
if ((format.getPropertySetMask()
|
||||
& AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE) != 0)
|
||||
@@ -420,7 +440,8 @@ public class AudioRecord
|
||||
|
||||
@Override
|
||||
protected void finalize() {
|
||||
native_finalize();
|
||||
// will cause stop() to be called, and if appropriate, will handle fixed volume recording
|
||||
release();
|
||||
}
|
||||
|
||||
|
||||
@@ -587,6 +608,7 @@ public class AudioRecord
|
||||
// start recording
|
||||
synchronized(mRecordingStateLock) {
|
||||
if (native_start(MediaSyncEvent.SYNC_EVENT_NONE, 0) == SUCCESS) {
|
||||
handleFullVolumeRec(true);
|
||||
mRecordingState = RECORDSTATE_RECORDING;
|
||||
}
|
||||
}
|
||||
@@ -609,6 +631,7 @@ public class AudioRecord
|
||||
// start recording
|
||||
synchronized(mRecordingStateLock) {
|
||||
if (native_start(syncEvent.getType(), syncEvent.getAudioSessionId()) == SUCCESS) {
|
||||
handleFullVolumeRec(true);
|
||||
mRecordingState = RECORDSTATE_RECORDING;
|
||||
}
|
||||
}
|
||||
@@ -626,11 +649,25 @@ public class AudioRecord
|
||||
|
||||
// stop recording
|
||||
synchronized(mRecordingStateLock) {
|
||||
handleFullVolumeRec(false);
|
||||
native_stop();
|
||||
mRecordingState = RECORDSTATE_STOPPED;
|
||||
}
|
||||
}
|
||||
|
||||
private final IBinder mICallBack = new Binder();
|
||||
private void handleFullVolumeRec(boolean starting) {
|
||||
if (!mIsSubmixFullVolume) {
|
||||
return;
|
||||
}
|
||||
final IBinder b = ServiceManager.getService(android.content.Context.AUDIO_SERVICE);
|
||||
final IAudioService ias = IAudioService.Stub.asInterface(b);
|
||||
try {
|
||||
ias.forceRemoteSubmixFullVolume(starting, mICallBack);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error talking to AudioService when handling full submix volume", e);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Audio data supply
|
||||
@@ -881,6 +918,7 @@ public class AudioRecord
|
||||
int sampleRate, int channelMask, int audioFormat,
|
||||
int buffSizeInBytes, int[] sessionId);
|
||||
|
||||
// TODO remove: implementation calls directly into implementation of native_release()
|
||||
private native final void native_finalize();
|
||||
|
||||
private native final void native_release();
|
||||
|
||||
@@ -485,6 +485,7 @@ public class AudioService extends IAudioService.Stub {
|
||||
AudioSystem.DEVICE_OUT_HDMI_ARC |
|
||||
AudioSystem.DEVICE_OUT_SPDIF |
|
||||
AudioSystem.DEVICE_OUT_AUX_LINE;
|
||||
int mFullVolumeDevices = 0;
|
||||
|
||||
// TODO merge orientation and rotation
|
||||
private final boolean mMonitorOrientation;
|
||||
@@ -727,6 +728,10 @@ public class AudioService extends IAudioService.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkAllFixedVolumeDevices(int streamType) {
|
||||
mStreamStates[streamType].checkFixedVolumeDevices();
|
||||
}
|
||||
|
||||
private void createStreamStates() {
|
||||
int numStreamTypes = AudioSystem.getNumStreamTypes();
|
||||
VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
|
||||
@@ -1466,6 +1471,106 @@ public class AudioService extends IAudioService.Stub {
|
||||
return mStreamStates[streamType].isMuted();
|
||||
}
|
||||
|
||||
private class RmtSbmxFullVolDeathHandler implements IBinder.DeathRecipient {
|
||||
private IBinder mICallback; // To be notified of client's death
|
||||
|
||||
RmtSbmxFullVolDeathHandler(IBinder cb) {
|
||||
mICallback = cb;
|
||||
try {
|
||||
cb.linkToDeath(this, 0/*flags*/);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "can't link to death", e);
|
||||
}
|
||||
}
|
||||
|
||||
boolean isHandlerFor(IBinder cb) {
|
||||
return mICallback.equals(cb);
|
||||
}
|
||||
|
||||
void forget() {
|
||||
try {
|
||||
mICallback.unlinkToDeath(this, 0/*flags*/);
|
||||
} catch (NoSuchElementException e) {
|
||||
Log.e(TAG, "error unlinking to death", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void binderDied() {
|
||||
Log.w(TAG, "Recorder with remote submix at full volume died " + mICallback);
|
||||
forceRemoteSubmixFullVolume(false, mICallback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* call must be synchronized on mRmtSbmxFullVolDeathHandlers
|
||||
* @return true if there is a registered death handler, false otherwise */
|
||||
private boolean discardRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
|
||||
Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
|
||||
while (it.hasNext()) {
|
||||
final RmtSbmxFullVolDeathHandler handler = it.next();
|
||||
if (handler.isHandlerFor(cb)) {
|
||||
handler.forget();
|
||||
mRmtSbmxFullVolDeathHandlers.remove(handler);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** call synchronized on mRmtSbmxFullVolDeathHandlers */
|
||||
private boolean hasRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
|
||||
Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
|
||||
while (it.hasNext()) {
|
||||
if (it.next().isHandlerFor(cb)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private int mRmtSbmxFullVolRefCount = 0;
|
||||
private ArrayList<RmtSbmxFullVolDeathHandler> mRmtSbmxFullVolDeathHandlers =
|
||||
new ArrayList<RmtSbmxFullVolDeathHandler>();
|
||||
|
||||
public void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb) {
|
||||
if (cb == null) {
|
||||
return;
|
||||
}
|
||||
if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
|
||||
android.Manifest.permission.CAPTURE_AUDIO_OUTPUT))) {
|
||||
Log.w(TAG, "Trying to call forceRemoteSubmixFullVolume() without CAPTURE_AUDIO_OUTPUT");
|
||||
return;
|
||||
}
|
||||
synchronized(mRmtSbmxFullVolDeathHandlers) {
|
||||
boolean applyRequired = false;
|
||||
if (startForcing) {
|
||||
if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) {
|
||||
mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb));
|
||||
if (mRmtSbmxFullVolRefCount == 0) {
|
||||
mFullVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
|
||||
mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
|
||||
applyRequired = true;
|
||||
}
|
||||
mRmtSbmxFullVolRefCount++;
|
||||
}
|
||||
} else {
|
||||
if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) {
|
||||
mRmtSbmxFullVolRefCount--;
|
||||
if (mRmtSbmxFullVolRefCount == 0) {
|
||||
mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
|
||||
mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
|
||||
applyRequired = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (applyRequired) {
|
||||
// Assumes only STREAM_MUSIC going through DEVICE_OUT_REMOTE_SUBMIX
|
||||
checkAllFixedVolumeDevices(AudioSystem.STREAM_MUSIC);
|
||||
mStreamStates[AudioSystem.STREAM_MUSIC].applyAllVolumes();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @see AudioManager#setMasterMute(boolean, int) */
|
||||
public void setMasterMute(boolean state, int flags, String callingPackage, IBinder cb) {
|
||||
if (mUseFixedVolume) {
|
||||
@@ -3243,8 +3348,8 @@ public class AudioService extends IAudioService.Stub {
|
||||
int index;
|
||||
if (isMuted()) {
|
||||
index = 0;
|
||||
} else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
|
||||
mAvrcpAbsVolSupported) {
|
||||
} else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported)
|
||||
|| ((device & mFullVolumeDevices) != 0)) {
|
||||
index = (mIndexMax + 5)/10;
|
||||
} else {
|
||||
index = (getIndex(device) + 5)/10;
|
||||
@@ -3272,8 +3377,10 @@ public class AudioService extends IAudioService.Stub {
|
||||
if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
|
||||
if (isMuted()) {
|
||||
index = 0;
|
||||
} else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
|
||||
mAvrcpAbsVolSupported) {
|
||||
} else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
|
||||
mAvrcpAbsVolSupported)
|
||||
|| ((device & mFullVolumeDevices) != 0))
|
||||
{
|
||||
index = (mIndexMax + 5)/10;
|
||||
} else {
|
||||
index = ((Integer)entry.getValue() + 5)/10;
|
||||
@@ -3403,7 +3510,8 @@ public class AudioService extends IAudioService.Stub {
|
||||
Map.Entry entry = (Map.Entry)i.next();
|
||||
int device = ((Integer)entry.getKey()).intValue();
|
||||
int index = ((Integer)entry.getValue()).intValue();
|
||||
if (((device & mFixedVolumeDevices) != 0) && index != 0) {
|
||||
if (((device & mFullVolumeDevices) != 0)
|
||||
|| (((device & mFixedVolumeDevices) != 0) && index != 0)) {
|
||||
entry.setValue(mIndexMax);
|
||||
}
|
||||
applyDeviceVolume(device);
|
||||
|
||||
@@ -56,6 +56,8 @@ interface IAudioService {
|
||||
|
||||
boolean isStreamMute(int streamType);
|
||||
|
||||
void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb);
|
||||
|
||||
void setMasterMute(boolean state, int flags, String callingPackage, IBinder cb);
|
||||
|
||||
boolean isMasterMute();
|
||||
|
||||
Reference in New Issue
Block a user