summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorJean-Michel Trivi <jmtrivi@google.com>2014-10-07 17:33:05 +0000
committerAndroid Git Automerger <android-git-automerger@android.com>2014-10-07 17:33:05 +0000
commit986468a8ab77ce1e89247078d4e93a3aaa5d294b (patch)
tree0be5ecef30a9f8f88c973709444d1ac6620e72f8 /media
parentf7b7b7585acb0bec5c8ccfd646981a1b9f906f60 (diff)
parentdce7a427593c6e11277d9e3075ab027512923276 (diff)
downloadframeworks_base-986468a8ab77ce1e89247078d4e93a3aaa5d294b.zip
frameworks_base-986468a8ab77ce1e89247078d4e93a3aaa5d294b.tar.gz
frameworks_base-986468a8ab77ce1e89247078d4e93a3aaa5d294b.tar.bz2
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
Diffstat (limited to 'media')
-rw-r--r--media/java/android/media/AudioRecord.java40
-rw-r--r--media/java/android/media/AudioService.java118
-rw-r--r--media/java/android/media/IAudioService.aidl2
3 files changed, 154 insertions, 6 deletions
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index ef1c0b0..ce78bb6 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -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();
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 5c2abc5..96ce2c1 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -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);
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 75fc03c..1c41432 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -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();