Loading media/java/android/media/AudioTrack.java +20 −44 Original line number Diff line number Diff line Loading @@ -28,7 +28,6 @@ import java.util.Collection; import android.annotation.IntDef; import android.annotation.NonNull; import android.app.ActivityThread; import android.app.AppOpsManager; import android.content.Context; import android.os.Handler; import android.os.IBinder; Loading @@ -41,7 +40,6 @@ import android.util.ArrayMap; import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IAppOpsService; /** * The AudioTrack class manages and plays a single audio resource for Java applications. Loading Loading @@ -78,7 +76,8 @@ import com.android.internal.app.IAppOpsService; * * AudioTrack is not final and thus permits subclasses, but such use is not recommended. */ public class AudioTrack implements AudioRouting public class AudioTrack extends PlayerBase implements AudioRouting { //--------------------------------------------------------- // Constants Loading Loading @@ -271,7 +270,6 @@ public class AudioTrack implements AudioRouting */ private int mStreamType = AudioManager.STREAM_MUSIC; private final AudioAttributes mAttributes; /** * The way audio is consumed by the audio sink, one of MODE_STATIC or MODE_STREAM. */ Loading @@ -297,10 +295,6 @@ public class AudioTrack implements AudioRouting * Audio session ID */ private int mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE; /** * Reference to the app-ops service. */ private final IAppOpsService mAppOps; /** * HW_AV_SYNC track AV Sync Header */ Loading Loading @@ -448,11 +442,9 @@ public class AudioTrack implements AudioRouting public AudioTrack(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes, int mode, int sessionId) throws IllegalArgumentException { super(attributes); // mState already == STATE_UNINITIALIZED if (attributes == null) { throw new IllegalArgumentException("Illegal null AudioAttributes"); } if (format == null) { throw new IllegalArgumentException("Illegal null AudioFormat"); } Loading Loading @@ -491,10 +483,6 @@ public class AudioTrack implements AudioRouting audioBuffSizeCheck(bufferSizeInBytes); mInitializationLooper = looper; IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE); mAppOps = IAppOpsService.Stub.asInterface(b); mAttributes = new AudioAttributes.Builder(attributes).build(); if (sessionId < 0) { throw new IllegalArgumentException("Invalid audio session ID: "+sessionId); Loading Loading @@ -534,9 +522,8 @@ public class AudioTrack implements AudioRouting * OpenSLES interface is realized. */ /*package*/ AudioTrack(long nativeTrackInJavaObj) { super(new AudioAttributes.Builder().build()); // "final"s mAttributes = null; mAppOps = null; mNativeTrackInJavaObj = 0; mJniData = 0; Loading Loading @@ -961,12 +948,14 @@ public class AudioTrack implements AudioRouting } catch(IllegalStateException ise) { // don't raise an exception, we're releasing the resources. } baseRelease(); native_release(); mState = STATE_UNINITIALIZED; } @Override protected void finalize() { baseRelease(); native_finalize(); } Loading Loading @@ -1492,19 +1481,20 @@ public class AudioTrack implements AudioRouting */ @Deprecated public int setStereoVolume(float leftGain, float rightGain) { if (isRestricted()) { return SUCCESS; } if (mState == STATE_UNINITIALIZED) { return ERROR_INVALID_OPERATION; } leftGain = clampGainOrLevel(leftGain); rightGain = clampGainOrLevel(rightGain); baseSetVolume(leftGain, rightGain); return SUCCESS; } native_setVolume(leftGain, rightGain); @Override void playerSetVolume(float leftVolume, float rightVolume) { leftVolume = clampGainOrLevel(leftVolume); rightVolume = clampGainOrLevel(rightVolume); return SUCCESS; native_setVolume(leftVolume, rightVolume); } Loading Loading @@ -1728,29 +1718,13 @@ public class AudioTrack implements AudioRouting if (mState != STATE_INITIALIZED) { throw new IllegalStateException("play() called on uninitialized AudioTrack."); } if (isRestricted()) { setVolume(0); } baseStart(); synchronized(mPlayStateLock) { native_start(); mPlayState = PLAYSTATE_PLAYING; } } private boolean isRestricted() { if ((mAttributes.getAllFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) { return false; } try { final int usage = AudioAttributes.usageForLegacyStreamType(mStreamType); final int mode = mAppOps.checkAudioOperation(AppOpsManager.OP_PLAY_AUDIO, usage, Process.myUid(), ActivityThread.currentPackageName()); return mode != AppOpsManager.MODE_ALLOWED; } catch (RemoteException e) { return false; } } /** * Stops playing the audio data. * When used on an instance created in {@link #MODE_STREAM} mode, audio will stop playing Loading Loading @@ -2375,12 +2349,14 @@ public class AudioTrack implements AudioRouting * {@link #ERROR_INVALID_OPERATION}, {@link #ERROR} */ public int setAuxEffectSendLevel(float level) { if (isRestricted()) { return SUCCESS; } if (mState == STATE_UNINITIALIZED) { return ERROR_INVALID_OPERATION; } return baseSetAuxEffectSendLevel(level); } @Override int playerSetAuxEffectSendLevel(float level) { level = clampGainOrLevel(level); int err = native_setAuxEffectSendLevel(level); return err == 0 ? SUCCESS : ERROR; Loading media/java/android/media/MediaPlayer.java +23 −34 Original line number Diff line number Diff line Loading @@ -20,7 +20,6 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityThread; import android.app.AppOpsManager; import android.content.ContentResolver; import android.content.Context; import android.content.res.AssetFileDescriptor; Loading @@ -34,8 +33,6 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.Process; import android.os.PowerManager; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; import android.provider.Settings; import android.system.ErrnoException; Loading @@ -56,7 +53,6 @@ import android.media.SubtitleData; import android.media.SubtitleTrack.RenderingWidget; import android.media.SyncParams; import com.android.internal.app.IAppOpsService; import com.android.internal.util.Preconditions; import libcore.io.IoBridge; Loading @@ -66,7 +62,6 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.lang.Runnable; Loading @@ -74,7 +69,6 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.net.InetSocketAddress; import java.util.BitSet; import java.util.HashSet; import java.util.Map; import java.util.Scanner; import java.util.Set; Loading Loading @@ -561,7 +555,8 @@ import java.lang.ref.WeakReference; * thread by default has a Looper running). * */ public class MediaPlayer implements SubtitleController.Listener public class MediaPlayer extends PlayerBase implements SubtitleController.Listener { /** Constant to retrieve only the new metadata since the last Loading Loading @@ -615,7 +610,6 @@ public class MediaPlayer implements SubtitleController.Listener private PowerManager.WakeLock mWakeLock = null; private boolean mScreenOnWhilePlaying; private boolean mStayAwake; private final IAppOpsService mAppOps; private int mStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE; private int mUsage = -1; private boolean mBypassInterruptionPolicy; Loading @@ -628,6 +622,7 @@ public class MediaPlayer implements SubtitleController.Listener * result in an exception.</p> */ public MediaPlayer() { super(new AudioAttributes.Builder().build()); Looper looper; if ((looper = Looper.myLooper()) != null) { Loading @@ -640,8 +635,6 @@ public class MediaPlayer implements SubtitleController.Listener mTimeProvider = new TimeProvider(this); mOpenSubtitleSources = new Vector<InputStream>(); IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE); mAppOps = IAppOpsService.Stub.asInterface(b); /* Native setup requires a weak reference to our object. * It's easier to create it here than in C++. Loading Loading @@ -1211,29 +1204,13 @@ public class MediaPlayer implements SubtitleController.Listener * @throws IllegalStateException if it is called in an invalid state */ public void start() throws IllegalStateException { if (isRestricted()) { _setVolume(0, 0); } baseStart(); stayAwake(true); _start(); } private native void _start() throws IllegalStateException; private boolean isRestricted() { if (mBypassInterruptionPolicy) { return false; } try { final int usage = mUsage != -1 ? mUsage : AudioAttributes.usageForLegacyStreamType(getAudioStreamType()); final int mode = mAppOps.checkAudioOperation(AppOpsManager.OP_PLAY_AUDIO, usage, Process.myUid(), ActivityThread.currentPackageName()); return mode != AppOpsManager.MODE_ALLOWED; } catch (RemoteException e) { return false; } } private int getAudioStreamType() { if (mStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { Loading Loading @@ -1687,6 +1664,7 @@ public class MediaPlayer implements SubtitleController.Listener * at the same time. */ public void release() { baseRelease(); stayAwake(false); updateSurfaceScreenOn(); mOnPreparedListener = null; Loading Loading @@ -1756,6 +1734,8 @@ public class MediaPlayer implements SubtitleController.Listener * @see android.media.AudioManager */ public void setAudioStreamType(int streamtype) { baseUpdateAudioAttributes( new AudioAttributes.Builder().setInternalLegacyStreamType(streamtype).build()); _setAudioStreamType(streamtype); mStreamType = streamtype; } Loading Loading @@ -1785,6 +1765,7 @@ public class MediaPlayer implements SubtitleController.Listener final String msg = "Cannot set AudioAttributes to null"; throw new IllegalArgumentException(msg); } baseUpdateAudioAttributes(attributes); mUsage = attributes.getUsage(); mBypassInterruptionPolicy = (attributes.getAllFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0; Loading Loading @@ -1826,9 +1807,11 @@ public class MediaPlayer implements SubtitleController.Listener * to be set independently. */ public void setVolume(float leftVolume, float rightVolume) { if (isRestricted()) { return; baseSetVolume(leftVolume, rightVolume); } @Override void playerSetVolume(float leftVolume, float rightVolume) { _setVolume(leftVolume, rightVolume); } Loading Loading @@ -1898,10 +1881,13 @@ public class MediaPlayer implements SubtitleController.Listener * @param level send level scalar */ public void setAuxEffectSendLevel(float level) { if (isRestricted()) { return; baseSetAuxEffectSendLevel(level); } @Override int playerSetAuxEffectSendLevel(float level) { _setAuxEffectSendLevel(level); return AudioSystem.SUCCESS; } private native void _setAuxEffectSendLevel(float level); Loading Loading @@ -2795,7 +2781,10 @@ public class MediaPlayer implements SubtitleController.Listener private native final int native_setRetransmitEndpoint(String addrString, int port); @Override protected void finalize() { native_finalize(); } protected void finalize() { baseRelease(); native_finalize(); } /* Do not change these values without updating their counterparts * in include/media/mediaplayer.h! Loading media/java/android/media/PlayerBase.java 0 → 100644 +193 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.media; import java.lang.IllegalArgumentException; import android.annotation.NonNull; import android.app.ActivityThread; import android.app.AppOpsManager; import android.content.Context; import android.os.IBinder; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; import com.android.internal.app.IAppOpsCallback; import com.android.internal.app.IAppOpsService; /** * Class to encapsulate a number of common player operations: * - AppOps for OP_PLAY_AUDIO * - more to come (routing, transport control) * @hide */ public abstract class PlayerBase { // parameters of the player that affect AppOps protected AudioAttributes mAttributes; protected float mLeftVolume = 1.0f; protected float mRightVolume = 1.0f; protected float mAuxEffectSendLevel = 0.0f; // for AppOps private final IAppOpsService mAppOps; private final IAppOpsCallback mAppOpsCallback; private boolean mHasAppOpsPlayAudio = true; private final Object mAppOpsLock = new Object(); /** * Constructor. Must be given audio attributes, as they are required for AppOps. * @param attr non-null audio attributes */ PlayerBase(@NonNull AudioAttributes attr) { if (attr == null) { throw new IllegalArgumentException("Illegal null AudioAttributes"); } mAttributes = attr; IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE); mAppOps = IAppOpsService.Stub.asInterface(b); // initialize mHasAppOpsPlayAudio updateAppOpsPlayAudio_sync(); // register a callback to monitor whether the OP_PLAY_AUDIO is still allowed mAppOpsCallback = new IAppOpsCallback.Stub() { public void opChanged(int op, int uid, String packageName) { synchronized (mAppOpsLock) { if (op == AppOpsManager.OP_PLAY_AUDIO) { updateAppOpsPlayAudio_sync(); } } } }; try { mAppOps.startWatchingMode(AppOpsManager.OP_PLAY_AUDIO, ActivityThread.currentPackageName(), mAppOpsCallback); } catch (RemoteException e) { mHasAppOpsPlayAudio = false; } } /** * To be called whenever the audio attributes of the player change * @param attr non-null audio attributes */ void baseUpdateAudioAttributes(@NonNull AudioAttributes attr) { if (attr == null) { throw new IllegalArgumentException("Illegal null AudioAttributes"); } synchronized (mAppOpsLock) { mAttributes = attr; updateAppOpsPlayAudio_sync(); } } void baseStart() { synchronized (mAppOpsLock) { if (isRestricted_sync()) { playerSetVolume(0, 0); } } } void baseSetVolume(float leftVolume, float rightVolume) { synchronized (mAppOpsLock) { mLeftVolume = leftVolume; mRightVolume = rightVolume; if (isRestricted_sync()) { return; } } playerSetVolume(leftVolume, rightVolume); } int baseSetAuxEffectSendLevel(float level) { synchronized (mAppOpsLock) { mAuxEffectSendLevel = level; if (isRestricted_sync()) { return AudioSystem.SUCCESS; } } return playerSetAuxEffectSendLevel(level); } /** * To be called from a subclass release or finalize method. * Releases AppOps related resources. */ void baseRelease() { try { mAppOps.stopWatchingMode(mAppOpsCallback); } catch (RemoteException e) { // nothing to do here, the object is supposed to be released anyway } } /** * To be called whenever a condition that might affect audibility of this player is updated. * Must be called synchronized on mAppOpsLock. */ void updateAppOpsPlayAudio_sync() { boolean oldHasAppOpsPlayAudio = mHasAppOpsPlayAudio; try { final int mode = mAppOps.checkAudioOperation(AppOpsManager.OP_PLAY_AUDIO, mAttributes.getUsage(), Process.myUid(), ActivityThread.currentPackageName()); mHasAppOpsPlayAudio = (mode == AppOpsManager.MODE_ALLOWED); } catch (RemoteException e) { mHasAppOpsPlayAudio = false; } // AppsOps alters a player's volume; when the restriction changes, reflect it on the actual // volume used by the player try { if (oldHasAppOpsPlayAudio != mHasAppOpsPlayAudio) { if (mHasAppOpsPlayAudio) { playerSetVolume(mLeftVolume, mRightVolume); playerSetAuxEffectSendLevel(mAuxEffectSendLevel); } else { playerSetVolume(0.0f, 0.0f); playerSetAuxEffectSendLevel(0.0f); } } } catch (Exception e) { // failing silently, player might not be in right state } } /** * To be called by the subclass whenever an operation is potentially restricted. * As the media player-common behavior are incorporated into this class, the subclass's need * to call this method should be removed, and this method could become private. * FIXME can this method be private so subclasses don't have to worry about when to check * the restrictions. * @return */ boolean isRestricted_sync() { if ((mAttributes.getAllFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) { return false; } return !mHasAppOpsPlayAudio; } // Abstract methods a subclass needs to implement abstract void playerSetVolume(float leftVolume, float rightVolume); abstract int playerSetAuxEffectSendLevel(float level); } Loading
media/java/android/media/AudioTrack.java +20 −44 Original line number Diff line number Diff line Loading @@ -28,7 +28,6 @@ import java.util.Collection; import android.annotation.IntDef; import android.annotation.NonNull; import android.app.ActivityThread; import android.app.AppOpsManager; import android.content.Context; import android.os.Handler; import android.os.IBinder; Loading @@ -41,7 +40,6 @@ import android.util.ArrayMap; import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IAppOpsService; /** * The AudioTrack class manages and plays a single audio resource for Java applications. Loading Loading @@ -78,7 +76,8 @@ import com.android.internal.app.IAppOpsService; * * AudioTrack is not final and thus permits subclasses, but such use is not recommended. */ public class AudioTrack implements AudioRouting public class AudioTrack extends PlayerBase implements AudioRouting { //--------------------------------------------------------- // Constants Loading Loading @@ -271,7 +270,6 @@ public class AudioTrack implements AudioRouting */ private int mStreamType = AudioManager.STREAM_MUSIC; private final AudioAttributes mAttributes; /** * The way audio is consumed by the audio sink, one of MODE_STATIC or MODE_STREAM. */ Loading @@ -297,10 +295,6 @@ public class AudioTrack implements AudioRouting * Audio session ID */ private int mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE; /** * Reference to the app-ops service. */ private final IAppOpsService mAppOps; /** * HW_AV_SYNC track AV Sync Header */ Loading Loading @@ -448,11 +442,9 @@ public class AudioTrack implements AudioRouting public AudioTrack(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes, int mode, int sessionId) throws IllegalArgumentException { super(attributes); // mState already == STATE_UNINITIALIZED if (attributes == null) { throw new IllegalArgumentException("Illegal null AudioAttributes"); } if (format == null) { throw new IllegalArgumentException("Illegal null AudioFormat"); } Loading Loading @@ -491,10 +483,6 @@ public class AudioTrack implements AudioRouting audioBuffSizeCheck(bufferSizeInBytes); mInitializationLooper = looper; IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE); mAppOps = IAppOpsService.Stub.asInterface(b); mAttributes = new AudioAttributes.Builder(attributes).build(); if (sessionId < 0) { throw new IllegalArgumentException("Invalid audio session ID: "+sessionId); Loading Loading @@ -534,9 +522,8 @@ public class AudioTrack implements AudioRouting * OpenSLES interface is realized. */ /*package*/ AudioTrack(long nativeTrackInJavaObj) { super(new AudioAttributes.Builder().build()); // "final"s mAttributes = null; mAppOps = null; mNativeTrackInJavaObj = 0; mJniData = 0; Loading Loading @@ -961,12 +948,14 @@ public class AudioTrack implements AudioRouting } catch(IllegalStateException ise) { // don't raise an exception, we're releasing the resources. } baseRelease(); native_release(); mState = STATE_UNINITIALIZED; } @Override protected void finalize() { baseRelease(); native_finalize(); } Loading Loading @@ -1492,19 +1481,20 @@ public class AudioTrack implements AudioRouting */ @Deprecated public int setStereoVolume(float leftGain, float rightGain) { if (isRestricted()) { return SUCCESS; } if (mState == STATE_UNINITIALIZED) { return ERROR_INVALID_OPERATION; } leftGain = clampGainOrLevel(leftGain); rightGain = clampGainOrLevel(rightGain); baseSetVolume(leftGain, rightGain); return SUCCESS; } native_setVolume(leftGain, rightGain); @Override void playerSetVolume(float leftVolume, float rightVolume) { leftVolume = clampGainOrLevel(leftVolume); rightVolume = clampGainOrLevel(rightVolume); return SUCCESS; native_setVolume(leftVolume, rightVolume); } Loading Loading @@ -1728,29 +1718,13 @@ public class AudioTrack implements AudioRouting if (mState != STATE_INITIALIZED) { throw new IllegalStateException("play() called on uninitialized AudioTrack."); } if (isRestricted()) { setVolume(0); } baseStart(); synchronized(mPlayStateLock) { native_start(); mPlayState = PLAYSTATE_PLAYING; } } private boolean isRestricted() { if ((mAttributes.getAllFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) { return false; } try { final int usage = AudioAttributes.usageForLegacyStreamType(mStreamType); final int mode = mAppOps.checkAudioOperation(AppOpsManager.OP_PLAY_AUDIO, usage, Process.myUid(), ActivityThread.currentPackageName()); return mode != AppOpsManager.MODE_ALLOWED; } catch (RemoteException e) { return false; } } /** * Stops playing the audio data. * When used on an instance created in {@link #MODE_STREAM} mode, audio will stop playing Loading Loading @@ -2375,12 +2349,14 @@ public class AudioTrack implements AudioRouting * {@link #ERROR_INVALID_OPERATION}, {@link #ERROR} */ public int setAuxEffectSendLevel(float level) { if (isRestricted()) { return SUCCESS; } if (mState == STATE_UNINITIALIZED) { return ERROR_INVALID_OPERATION; } return baseSetAuxEffectSendLevel(level); } @Override int playerSetAuxEffectSendLevel(float level) { level = clampGainOrLevel(level); int err = native_setAuxEffectSendLevel(level); return err == 0 ? SUCCESS : ERROR; Loading
media/java/android/media/MediaPlayer.java +23 −34 Original line number Diff line number Diff line Loading @@ -20,7 +20,6 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityThread; import android.app.AppOpsManager; import android.content.ContentResolver; import android.content.Context; import android.content.res.AssetFileDescriptor; Loading @@ -34,8 +33,6 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.Process; import android.os.PowerManager; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; import android.provider.Settings; import android.system.ErrnoException; Loading @@ -56,7 +53,6 @@ import android.media.SubtitleData; import android.media.SubtitleTrack.RenderingWidget; import android.media.SyncParams; import com.android.internal.app.IAppOpsService; import com.android.internal.util.Preconditions; import libcore.io.IoBridge; Loading @@ -66,7 +62,6 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.lang.Runnable; Loading @@ -74,7 +69,6 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.net.InetSocketAddress; import java.util.BitSet; import java.util.HashSet; import java.util.Map; import java.util.Scanner; import java.util.Set; Loading Loading @@ -561,7 +555,8 @@ import java.lang.ref.WeakReference; * thread by default has a Looper running). * */ public class MediaPlayer implements SubtitleController.Listener public class MediaPlayer extends PlayerBase implements SubtitleController.Listener { /** Constant to retrieve only the new metadata since the last Loading Loading @@ -615,7 +610,6 @@ public class MediaPlayer implements SubtitleController.Listener private PowerManager.WakeLock mWakeLock = null; private boolean mScreenOnWhilePlaying; private boolean mStayAwake; private final IAppOpsService mAppOps; private int mStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE; private int mUsage = -1; private boolean mBypassInterruptionPolicy; Loading @@ -628,6 +622,7 @@ public class MediaPlayer implements SubtitleController.Listener * result in an exception.</p> */ public MediaPlayer() { super(new AudioAttributes.Builder().build()); Looper looper; if ((looper = Looper.myLooper()) != null) { Loading @@ -640,8 +635,6 @@ public class MediaPlayer implements SubtitleController.Listener mTimeProvider = new TimeProvider(this); mOpenSubtitleSources = new Vector<InputStream>(); IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE); mAppOps = IAppOpsService.Stub.asInterface(b); /* Native setup requires a weak reference to our object. * It's easier to create it here than in C++. Loading Loading @@ -1211,29 +1204,13 @@ public class MediaPlayer implements SubtitleController.Listener * @throws IllegalStateException if it is called in an invalid state */ public void start() throws IllegalStateException { if (isRestricted()) { _setVolume(0, 0); } baseStart(); stayAwake(true); _start(); } private native void _start() throws IllegalStateException; private boolean isRestricted() { if (mBypassInterruptionPolicy) { return false; } try { final int usage = mUsage != -1 ? mUsage : AudioAttributes.usageForLegacyStreamType(getAudioStreamType()); final int mode = mAppOps.checkAudioOperation(AppOpsManager.OP_PLAY_AUDIO, usage, Process.myUid(), ActivityThread.currentPackageName()); return mode != AppOpsManager.MODE_ALLOWED; } catch (RemoteException e) { return false; } } private int getAudioStreamType() { if (mStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { Loading Loading @@ -1687,6 +1664,7 @@ public class MediaPlayer implements SubtitleController.Listener * at the same time. */ public void release() { baseRelease(); stayAwake(false); updateSurfaceScreenOn(); mOnPreparedListener = null; Loading Loading @@ -1756,6 +1734,8 @@ public class MediaPlayer implements SubtitleController.Listener * @see android.media.AudioManager */ public void setAudioStreamType(int streamtype) { baseUpdateAudioAttributes( new AudioAttributes.Builder().setInternalLegacyStreamType(streamtype).build()); _setAudioStreamType(streamtype); mStreamType = streamtype; } Loading Loading @@ -1785,6 +1765,7 @@ public class MediaPlayer implements SubtitleController.Listener final String msg = "Cannot set AudioAttributes to null"; throw new IllegalArgumentException(msg); } baseUpdateAudioAttributes(attributes); mUsage = attributes.getUsage(); mBypassInterruptionPolicy = (attributes.getAllFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0; Loading Loading @@ -1826,9 +1807,11 @@ public class MediaPlayer implements SubtitleController.Listener * to be set independently. */ public void setVolume(float leftVolume, float rightVolume) { if (isRestricted()) { return; baseSetVolume(leftVolume, rightVolume); } @Override void playerSetVolume(float leftVolume, float rightVolume) { _setVolume(leftVolume, rightVolume); } Loading Loading @@ -1898,10 +1881,13 @@ public class MediaPlayer implements SubtitleController.Listener * @param level send level scalar */ public void setAuxEffectSendLevel(float level) { if (isRestricted()) { return; baseSetAuxEffectSendLevel(level); } @Override int playerSetAuxEffectSendLevel(float level) { _setAuxEffectSendLevel(level); return AudioSystem.SUCCESS; } private native void _setAuxEffectSendLevel(float level); Loading Loading @@ -2795,7 +2781,10 @@ public class MediaPlayer implements SubtitleController.Listener private native final int native_setRetransmitEndpoint(String addrString, int port); @Override protected void finalize() { native_finalize(); } protected void finalize() { baseRelease(); native_finalize(); } /* Do not change these values without updating their counterparts * in include/media/mediaplayer.h! Loading
media/java/android/media/PlayerBase.java 0 → 100644 +193 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.media; import java.lang.IllegalArgumentException; import android.annotation.NonNull; import android.app.ActivityThread; import android.app.AppOpsManager; import android.content.Context; import android.os.IBinder; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; import com.android.internal.app.IAppOpsCallback; import com.android.internal.app.IAppOpsService; /** * Class to encapsulate a number of common player operations: * - AppOps for OP_PLAY_AUDIO * - more to come (routing, transport control) * @hide */ public abstract class PlayerBase { // parameters of the player that affect AppOps protected AudioAttributes mAttributes; protected float mLeftVolume = 1.0f; protected float mRightVolume = 1.0f; protected float mAuxEffectSendLevel = 0.0f; // for AppOps private final IAppOpsService mAppOps; private final IAppOpsCallback mAppOpsCallback; private boolean mHasAppOpsPlayAudio = true; private final Object mAppOpsLock = new Object(); /** * Constructor. Must be given audio attributes, as they are required for AppOps. * @param attr non-null audio attributes */ PlayerBase(@NonNull AudioAttributes attr) { if (attr == null) { throw new IllegalArgumentException("Illegal null AudioAttributes"); } mAttributes = attr; IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE); mAppOps = IAppOpsService.Stub.asInterface(b); // initialize mHasAppOpsPlayAudio updateAppOpsPlayAudio_sync(); // register a callback to monitor whether the OP_PLAY_AUDIO is still allowed mAppOpsCallback = new IAppOpsCallback.Stub() { public void opChanged(int op, int uid, String packageName) { synchronized (mAppOpsLock) { if (op == AppOpsManager.OP_PLAY_AUDIO) { updateAppOpsPlayAudio_sync(); } } } }; try { mAppOps.startWatchingMode(AppOpsManager.OP_PLAY_AUDIO, ActivityThread.currentPackageName(), mAppOpsCallback); } catch (RemoteException e) { mHasAppOpsPlayAudio = false; } } /** * To be called whenever the audio attributes of the player change * @param attr non-null audio attributes */ void baseUpdateAudioAttributes(@NonNull AudioAttributes attr) { if (attr == null) { throw new IllegalArgumentException("Illegal null AudioAttributes"); } synchronized (mAppOpsLock) { mAttributes = attr; updateAppOpsPlayAudio_sync(); } } void baseStart() { synchronized (mAppOpsLock) { if (isRestricted_sync()) { playerSetVolume(0, 0); } } } void baseSetVolume(float leftVolume, float rightVolume) { synchronized (mAppOpsLock) { mLeftVolume = leftVolume; mRightVolume = rightVolume; if (isRestricted_sync()) { return; } } playerSetVolume(leftVolume, rightVolume); } int baseSetAuxEffectSendLevel(float level) { synchronized (mAppOpsLock) { mAuxEffectSendLevel = level; if (isRestricted_sync()) { return AudioSystem.SUCCESS; } } return playerSetAuxEffectSendLevel(level); } /** * To be called from a subclass release or finalize method. * Releases AppOps related resources. */ void baseRelease() { try { mAppOps.stopWatchingMode(mAppOpsCallback); } catch (RemoteException e) { // nothing to do here, the object is supposed to be released anyway } } /** * To be called whenever a condition that might affect audibility of this player is updated. * Must be called synchronized on mAppOpsLock. */ void updateAppOpsPlayAudio_sync() { boolean oldHasAppOpsPlayAudio = mHasAppOpsPlayAudio; try { final int mode = mAppOps.checkAudioOperation(AppOpsManager.OP_PLAY_AUDIO, mAttributes.getUsage(), Process.myUid(), ActivityThread.currentPackageName()); mHasAppOpsPlayAudio = (mode == AppOpsManager.MODE_ALLOWED); } catch (RemoteException e) { mHasAppOpsPlayAudio = false; } // AppsOps alters a player's volume; when the restriction changes, reflect it on the actual // volume used by the player try { if (oldHasAppOpsPlayAudio != mHasAppOpsPlayAudio) { if (mHasAppOpsPlayAudio) { playerSetVolume(mLeftVolume, mRightVolume); playerSetAuxEffectSendLevel(mAuxEffectSendLevel); } else { playerSetVolume(0.0f, 0.0f); playerSetAuxEffectSendLevel(0.0f); } } } catch (Exception e) { // failing silently, player might not be in right state } } /** * To be called by the subclass whenever an operation is potentially restricted. * As the media player-common behavior are incorporated into this class, the subclass's need * to call this method should be removed, and this method could become private. * FIXME can this method be private so subclasses don't have to worry about when to check * the restrictions. * @return */ boolean isRestricted_sync() { if ((mAttributes.getAllFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) { return false; } return !mHasAppOpsPlayAudio; } // Abstract methods a subclass needs to implement abstract void playerSetVolume(float leftVolume, float rightVolume); abstract int playerSetAuxEffectSendLevel(float level); }