Skip to content
This repository has been archived by the owner on Nov 8, 2023. It is now read-only.

Commit

Permalink
Player superclass for handling AppOps features
Browse files Browse the repository at this point in the history
Add a new class to group media/audio player features under one
 interface. Currently only used for audio-related AppsOps
 restrictions. In the future can group routing, audio focus
 handling by the framework...
MediaPlayer inherits from PlayerBase, and overrides the methods
 that are needed to delegate the handling of the restrictions
 in a separate class.
When AppOps restrictions change (as triggered through the
 callback in PlayerBase), reset the volume to its value intended
 by the application (when unmuting) or the framework (0 when
 enforcing the restriction).

Bug 28069414

Change-Id: I2f38e4b9b3c029778836868cf78f4d15d7603247
  • Loading branch information
jmtrivi authored and Eric Laurent committed Apr 14, 2016
1 parent 4ecc096 commit 3c86a34
Show file tree
Hide file tree
Showing 3 changed files with 236 additions and 78 deletions.
64 changes: 20 additions & 44 deletions media/java/android/media/AudioTrack.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
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;
Expand All @@ -41,7 +40,6 @@
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.
Expand Down Expand Up @@ -78,7 +76,8 @@
*
* 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
Expand Down Expand Up @@ -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.
*/
Expand All @@ -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
*/
Expand Down Expand Up @@ -448,11 +442,9 @@ public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int aud
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");
}
Expand Down Expand Up @@ -491,10 +483,6 @@ public AudioTrack(AudioAttributes attributes, AudioFormat format, int bufferSize
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);
Expand Down Expand Up @@ -534,9 +522,8 @@ public AudioTrack(AudioAttributes attributes, AudioFormat format, int bufferSize
* OpenSLES interface is realized.
*/
/*package*/ AudioTrack(long nativeTrackInJavaObj) {
super(new AudioAttributes.Builder().build());
// "final"s
mAttributes = null;
mAppOps = null;
mNativeTrackInJavaObj = 0;
mJniData = 0;

Expand Down Expand Up @@ -961,12 +948,14 @@ public void release() {
} 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();
}

Expand Down Expand Up @@ -1492,19 +1481,20 @@ private static float clampGainOrLevel(float gainOrLevel) {
*/
@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);
}


Expand Down Expand Up @@ -1728,29 +1718,13 @@ public void play()
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
Expand Down Expand Up @@ -2375,12 +2349,14 @@ public int attachAuxEffect(int effectId) {
* {@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;
Expand Down
57 changes: 23 additions & 34 deletions media/java/android/media/MediaPlayer.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
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;
Expand All @@ -34,8 +33,6 @@
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;
Expand All @@ -56,7 +53,6 @@
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;
Expand All @@ -66,15 +62,13 @@
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;
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;
Expand Down Expand Up @@ -561,7 +555,8 @@
* 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
Expand Down Expand Up @@ -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;
Expand All @@ -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) {
Expand All @@ -640,8 +635,6 @@ public MediaPlayer() {

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++.
Expand Down Expand Up @@ -1211,29 +1204,13 @@ public void prepare() throws IOException, IllegalStateException {
* @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) {
Expand Down Expand Up @@ -1687,6 +1664,7 @@ public int setMetadataFilter(Set<Integer> allow, Set<Integer> block) {
* at the same time.
*/
public void release() {
baseRelease();
stayAwake(false);
updateSurfaceScreenOn();
mOnPreparedListener = null;
Expand Down Expand Up @@ -1756,6 +1734,8 @@ public void reset() {
* @see android.media.AudioManager
*/
public void setAudioStreamType(int streamtype) {
baseUpdateAudioAttributes(
new AudioAttributes.Builder().setInternalLegacyStreamType(streamtype).build());
_setAudioStreamType(streamtype);
mStreamType = streamtype;
}
Expand Down Expand Up @@ -1785,6 +1765,7 @@ public void setAudioAttributes(AudioAttributes attributes) throws IllegalArgumen
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;
Expand Down Expand Up @@ -1826,9 +1807,11 @@ public void setAudioAttributes(AudioAttributes attributes) throws IllegalArgumen
* 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);
}

Expand Down Expand Up @@ -1898,10 +1881,13 @@ public void setVolume(float volume) {
* @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);
Expand Down Expand Up @@ -2795,7 +2781,10 @@ public void setRetransmitEndpoint(InetSocketAddress endpoint)
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!
Expand Down
Loading

0 comments on commit 3c86a34

Please sign in to comment.