Loading media/java/android/media/AudioRecord.java +39 −1 Original line number Original line Diff line number Diff line Loading @@ -18,10 +18,15 @@ package android.media; import java.lang.ref.WeakReference; import java.lang.ref.WeakReference; import java.nio.ByteBuffer; import java.nio.ByteBuffer; import java.util.Iterator; import android.os.Binder; import android.os.Handler; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Looper; import android.os.Message; import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; import android.util.Log; /** /** Loading Loading @@ -99,6 +104,8 @@ public class AudioRecord private final static String TAG = "android.media.AudioRecord"; private final static String TAG = "android.media.AudioRecord"; /** @hide */ public final static String SUBMIX_FIXED_VOLUME = "fixedVolume"; //--------------------------------------------------------- //--------------------------------------------------------- // Used exclusively by native code // Used exclusively by native code Loading Loading @@ -184,6 +191,7 @@ public class AudioRecord * AudioAttributes * AudioAttributes */ */ private AudioAttributes mAudioAttributes; private AudioAttributes mAudioAttributes; private boolean mIsSubmixFullVolume = false; //--------------------------------------------------------- //--------------------------------------------------------- // Constructor, Finalize // Constructor, Finalize Loading Loading @@ -267,6 +275,18 @@ public class AudioRecord mAudioAttributes = attributes; 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; int rate = 0; if ((format.getPropertySetMask() if ((format.getPropertySetMask() & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE) != 0) & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE) != 0) Loading Loading @@ -420,7 +440,8 @@ public class AudioRecord @Override @Override protected void finalize() { protected void finalize() { native_finalize(); // will cause stop() to be called, and if appropriate, will handle fixed volume recording release(); } } Loading Loading @@ -587,6 +608,7 @@ public class AudioRecord // start recording // start recording synchronized(mRecordingStateLock) { synchronized(mRecordingStateLock) { if (native_start(MediaSyncEvent.SYNC_EVENT_NONE, 0) == SUCCESS) { if (native_start(MediaSyncEvent.SYNC_EVENT_NONE, 0) == SUCCESS) { handleFullVolumeRec(true); mRecordingState = RECORDSTATE_RECORDING; mRecordingState = RECORDSTATE_RECORDING; } } } } Loading @@ -609,6 +631,7 @@ public class AudioRecord // start recording // start recording synchronized(mRecordingStateLock) { synchronized(mRecordingStateLock) { if (native_start(syncEvent.getType(), syncEvent.getAudioSessionId()) == SUCCESS) { if (native_start(syncEvent.getType(), syncEvent.getAudioSessionId()) == SUCCESS) { handleFullVolumeRec(true); mRecordingState = RECORDSTATE_RECORDING; mRecordingState = RECORDSTATE_RECORDING; } } } } Loading @@ -626,11 +649,25 @@ public class AudioRecord // stop recording // stop recording synchronized(mRecordingStateLock) { synchronized(mRecordingStateLock) { handleFullVolumeRec(false); native_stop(); native_stop(); mRecordingState = RECORDSTATE_STOPPED; 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 // Audio data supply Loading Loading @@ -881,6 +918,7 @@ public class AudioRecord int sampleRate, int channelMask, int audioFormat, int sampleRate, int channelMask, int audioFormat, int buffSizeInBytes, int[] sessionId); 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_finalize(); private native final void native_release(); private native final void native_release(); Loading media/java/android/media/AudioService.java +113 −5 Original line number Original line Diff line number Diff line Loading @@ -485,6 +485,7 @@ public class AudioService extends IAudioService.Stub { AudioSystem.DEVICE_OUT_HDMI_ARC | AudioSystem.DEVICE_OUT_HDMI_ARC | AudioSystem.DEVICE_OUT_SPDIF | AudioSystem.DEVICE_OUT_SPDIF | AudioSystem.DEVICE_OUT_AUX_LINE; AudioSystem.DEVICE_OUT_AUX_LINE; int mFullVolumeDevices = 0; // TODO merge orientation and rotation // TODO merge orientation and rotation private final boolean mMonitorOrientation; private final boolean mMonitorOrientation; Loading Loading @@ -727,6 +728,10 @@ public class AudioService extends IAudioService.Stub { } } } } private void checkAllFixedVolumeDevices(int streamType) { mStreamStates[streamType].checkFixedVolumeDevices(); } private void createStreamStates() { private void createStreamStates() { int numStreamTypes = AudioSystem.getNumStreamTypes(); int numStreamTypes = AudioSystem.getNumStreamTypes(); VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes]; VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes]; Loading Loading @@ -1466,6 +1471,106 @@ public class AudioService extends IAudioService.Stub { return mStreamStates[streamType].isMuted(); 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) */ /** @see AudioManager#setMasterMute(boolean, int) */ public void setMasterMute(boolean state, int flags, String callingPackage, IBinder cb) { public void setMasterMute(boolean state, int flags, String callingPackage, IBinder cb) { if (mUseFixedVolume) { if (mUseFixedVolume) { Loading Loading @@ -3243,8 +3348,8 @@ public class AudioService extends IAudioService.Stub { int index; int index; if (isMuted()) { if (isMuted()) { index = 0; index = 0; } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported) mAvrcpAbsVolSupported) { || ((device & mFullVolumeDevices) != 0)) { index = (mIndexMax + 5)/10; index = (mIndexMax + 5)/10; } else { } else { index = (getIndex(device) + 5)/10; index = (getIndex(device) + 5)/10; Loading Loading @@ -3272,8 +3377,10 @@ public class AudioService extends IAudioService.Stub { if (device != AudioSystem.DEVICE_OUT_DEFAULT) { if (device != AudioSystem.DEVICE_OUT_DEFAULT) { if (isMuted()) { if (isMuted()) { index = 0; index = 0; } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported) { mAvrcpAbsVolSupported) || ((device & mFullVolumeDevices) != 0)) { index = (mIndexMax + 5)/10; index = (mIndexMax + 5)/10; } else { } else { index = ((Integer)entry.getValue() + 5)/10; index = ((Integer)entry.getValue() + 5)/10; Loading Loading @@ -3403,7 +3510,8 @@ public class AudioService extends IAudioService.Stub { 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(); int index = ((Integer)entry.getValue()).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); entry.setValue(mIndexMax); } } applyDeviceVolume(device); applyDeviceVolume(device); Loading media/java/android/media/IAudioService.aidl +2 −0 Original line number Original line Diff line number Diff line Loading @@ -56,6 +56,8 @@ interface IAudioService { boolean isStreamMute(int streamType); boolean isStreamMute(int streamType); void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb); void setMasterMute(boolean state, int flags, String callingPackage, IBinder cb); void setMasterMute(boolean state, int flags, String callingPackage, IBinder cb); boolean isMasterMute(); boolean isMasterMute(); Loading Loading
media/java/android/media/AudioRecord.java +39 −1 Original line number Original line Diff line number Diff line Loading @@ -18,10 +18,15 @@ package android.media; import java.lang.ref.WeakReference; import java.lang.ref.WeakReference; import java.nio.ByteBuffer; import java.nio.ByteBuffer; import java.util.Iterator; import android.os.Binder; import android.os.Handler; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Looper; import android.os.Message; import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; import android.util.Log; /** /** Loading Loading @@ -99,6 +104,8 @@ public class AudioRecord private final static String TAG = "android.media.AudioRecord"; private final static String TAG = "android.media.AudioRecord"; /** @hide */ public final static String SUBMIX_FIXED_VOLUME = "fixedVolume"; //--------------------------------------------------------- //--------------------------------------------------------- // Used exclusively by native code // Used exclusively by native code Loading Loading @@ -184,6 +191,7 @@ public class AudioRecord * AudioAttributes * AudioAttributes */ */ private AudioAttributes mAudioAttributes; private AudioAttributes mAudioAttributes; private boolean mIsSubmixFullVolume = false; //--------------------------------------------------------- //--------------------------------------------------------- // Constructor, Finalize // Constructor, Finalize Loading Loading @@ -267,6 +275,18 @@ public class AudioRecord mAudioAttributes = attributes; 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; int rate = 0; if ((format.getPropertySetMask() if ((format.getPropertySetMask() & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE) != 0) & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE) != 0) Loading Loading @@ -420,7 +440,8 @@ public class AudioRecord @Override @Override protected void finalize() { protected void finalize() { native_finalize(); // will cause stop() to be called, and if appropriate, will handle fixed volume recording release(); } } Loading Loading @@ -587,6 +608,7 @@ public class AudioRecord // start recording // start recording synchronized(mRecordingStateLock) { synchronized(mRecordingStateLock) { if (native_start(MediaSyncEvent.SYNC_EVENT_NONE, 0) == SUCCESS) { if (native_start(MediaSyncEvent.SYNC_EVENT_NONE, 0) == SUCCESS) { handleFullVolumeRec(true); mRecordingState = RECORDSTATE_RECORDING; mRecordingState = RECORDSTATE_RECORDING; } } } } Loading @@ -609,6 +631,7 @@ public class AudioRecord // start recording // start recording synchronized(mRecordingStateLock) { synchronized(mRecordingStateLock) { if (native_start(syncEvent.getType(), syncEvent.getAudioSessionId()) == SUCCESS) { if (native_start(syncEvent.getType(), syncEvent.getAudioSessionId()) == SUCCESS) { handleFullVolumeRec(true); mRecordingState = RECORDSTATE_RECORDING; mRecordingState = RECORDSTATE_RECORDING; } } } } Loading @@ -626,11 +649,25 @@ public class AudioRecord // stop recording // stop recording synchronized(mRecordingStateLock) { synchronized(mRecordingStateLock) { handleFullVolumeRec(false); native_stop(); native_stop(); mRecordingState = RECORDSTATE_STOPPED; 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 // Audio data supply Loading Loading @@ -881,6 +918,7 @@ public class AudioRecord int sampleRate, int channelMask, int audioFormat, int sampleRate, int channelMask, int audioFormat, int buffSizeInBytes, int[] sessionId); 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_finalize(); private native final void native_release(); private native final void native_release(); Loading
media/java/android/media/AudioService.java +113 −5 Original line number Original line Diff line number Diff line Loading @@ -485,6 +485,7 @@ public class AudioService extends IAudioService.Stub { AudioSystem.DEVICE_OUT_HDMI_ARC | AudioSystem.DEVICE_OUT_HDMI_ARC | AudioSystem.DEVICE_OUT_SPDIF | AudioSystem.DEVICE_OUT_SPDIF | AudioSystem.DEVICE_OUT_AUX_LINE; AudioSystem.DEVICE_OUT_AUX_LINE; int mFullVolumeDevices = 0; // TODO merge orientation and rotation // TODO merge orientation and rotation private final boolean mMonitorOrientation; private final boolean mMonitorOrientation; Loading Loading @@ -727,6 +728,10 @@ public class AudioService extends IAudioService.Stub { } } } } private void checkAllFixedVolumeDevices(int streamType) { mStreamStates[streamType].checkFixedVolumeDevices(); } private void createStreamStates() { private void createStreamStates() { int numStreamTypes = AudioSystem.getNumStreamTypes(); int numStreamTypes = AudioSystem.getNumStreamTypes(); VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes]; VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes]; Loading Loading @@ -1466,6 +1471,106 @@ public class AudioService extends IAudioService.Stub { return mStreamStates[streamType].isMuted(); 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) */ /** @see AudioManager#setMasterMute(boolean, int) */ public void setMasterMute(boolean state, int flags, String callingPackage, IBinder cb) { public void setMasterMute(boolean state, int flags, String callingPackage, IBinder cb) { if (mUseFixedVolume) { if (mUseFixedVolume) { Loading Loading @@ -3243,8 +3348,8 @@ public class AudioService extends IAudioService.Stub { int index; int index; if (isMuted()) { if (isMuted()) { index = 0; index = 0; } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported) mAvrcpAbsVolSupported) { || ((device & mFullVolumeDevices) != 0)) { index = (mIndexMax + 5)/10; index = (mIndexMax + 5)/10; } else { } else { index = (getIndex(device) + 5)/10; index = (getIndex(device) + 5)/10; Loading Loading @@ -3272,8 +3377,10 @@ public class AudioService extends IAudioService.Stub { if (device != AudioSystem.DEVICE_OUT_DEFAULT) { if (device != AudioSystem.DEVICE_OUT_DEFAULT) { if (isMuted()) { if (isMuted()) { index = 0; index = 0; } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported) { mAvrcpAbsVolSupported) || ((device & mFullVolumeDevices) != 0)) { index = (mIndexMax + 5)/10; index = (mIndexMax + 5)/10; } else { } else { index = ((Integer)entry.getValue() + 5)/10; index = ((Integer)entry.getValue() + 5)/10; Loading Loading @@ -3403,7 +3510,8 @@ public class AudioService extends IAudioService.Stub { 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(); int index = ((Integer)entry.getValue()).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); entry.setValue(mIndexMax); } } applyDeviceVolume(device); applyDeviceVolume(device); Loading
media/java/android/media/IAudioService.aidl +2 −0 Original line number Original line Diff line number Diff line Loading @@ -56,6 +56,8 @@ interface IAudioService { boolean isStreamMute(int streamType); boolean isStreamMute(int streamType); void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb); void setMasterMute(boolean state, int flags, String callingPackage, IBinder cb); void setMasterMute(boolean state, int flags, String callingPackage, IBinder cb); boolean isMasterMute(); boolean isMasterMute(); Loading