diff options
Diffstat (limited to 'media')
| -rw-r--r-- | media/java/android/media/AudioFormat.java | 19 | ||||
| -rw-r--r-- | media/java/android/media/AudioRecord.java | 2 | ||||
| -rw-r--r-- | media/java/android/media/AudioTrack.java | 113 | ||||
| -rw-r--r-- | media/java/android/media/JetPlayer.java | 6 | ||||
| -rw-r--r-- | media/java/android/media/session/ISession.aidl | 4 | ||||
| -rw-r--r-- | media/java/android/media/session/ISessionManager.aidl | 2 | ||||
| -rw-r--r-- | media/java/android/media/session/MediaSessionLegacyHelper.java | 16 | ||||
| -rw-r--r-- | media/java/android/media/session/Session.java | 107 | ||||
| -rw-r--r-- | media/java/android/media/session/SessionManager.java | 27 | ||||
| -rw-r--r-- | media/jni/Android.mk | 2 | ||||
| -rw-r--r-- | media/jni/android_media_MediaPlayer.cpp | 4 |
11 files changed, 231 insertions, 71 deletions
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java index ad0d459..6b2a247 100644 --- a/media/java/android/media/AudioFormat.java +++ b/media/java/android/media/AudioFormat.java @@ -32,11 +32,13 @@ public class AudioFormat { /** Default audio data format */ public static final int ENCODING_DEFAULT = 1; - // These two values must be kept in sync with core/jni/android_media_AudioFormat.h + // These values must be kept in sync with core/jni/android_media_AudioFormat.h /** Audio data format: PCM 16 bit per sample. Guaranteed to be supported by devices. */ public static final int ENCODING_PCM_16BIT = 2; /** Audio data format: PCM 8 bit per sample. Not guaranteed to be supported by devices. */ public static final int ENCODING_PCM_8BIT = 3; + /** @hide Candidate for public API */ + public static final int ENCODING_PCM_FLOAT = 4; /** Invalid audio channel configuration */ /** @deprecated use CHANNEL_INVALID instead */ @@ -139,4 +141,19 @@ public class AudioFormat { public static final int CHANNEL_IN_FRONT_BACK = CHANNEL_IN_FRONT | CHANNEL_IN_BACK; // CHANNEL_IN_ALL is not yet defined; if added then it should match AUDIO_CHANNEL_IN_ALL + /** @hide */ + public static int getBytesPerSample(int audioFormat) + { + switch (audioFormat) { + case ENCODING_PCM_8BIT: + return 1; + case ENCODING_PCM_16BIT: + case ENCODING_DEFAULT: + return 2; + case ENCODING_INVALID: + default: + throw new IllegalArgumentException("Bad audio format " + audioFormat); + } + } + } diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java index a4891f8..384e120 100644 --- a/media/java/android/media/AudioRecord.java +++ b/media/java/android/media/AudioRecord.java @@ -319,7 +319,7 @@ public class AudioRecord // NB: this section is only valid with PCM data. // To update when supporting compressed formats int frameSizeInBytes = mChannelCount - * (mAudioFormat == AudioFormat.ENCODING_PCM_8BIT ? 1 : 2); + * (AudioFormat.getBytesPerSample(mAudioFormat)); if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) { throw new IllegalArgumentException("Invalid audio buffer size."); } diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index 17840f2..dab6eed 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -72,6 +72,7 @@ import com.android.internal.app.IAppOpsService; * * AudioTrack is not final and thus permits subclasses, but such use is not recommended. */ +// add {@link #write(float[], int, int)} when @hide removed public class AudioTrack { //--------------------------------------------------------- @@ -172,16 +173,14 @@ public class AudioTrack public @interface WriteMode {} /** - * @hide CANDIDATE FOR PUBLIC API * The write mode indicating the write operation will block until all data has been written, - * to be used in {@link #write(ByteBuffer, int, int, int)}. + * to be used in {@link #write(ByteBuffer, int, int)} */ public final static int WRITE_BLOCKING = 0; /** - * @hide CANDIDATE FOR PUBLIC API * The write mode indicating the write operation will return immediately after * queuing as much audio data for playback as possible without blocking, to be used in - * {@link #write(ByteBuffer, int, int, int)}. + * {@link #write(ByteBuffer, int, int)}. */ public final static int WRITE_NON_BLOCKING = 1; @@ -247,6 +246,7 @@ public class AudioTrack * @see AudioFormat#ENCODING_PCM_8BIT * @see AudioFormat#ENCODING_PCM_16BIT */ + // add @see AudioFormat#ENCODING_PCM_FLOAT when @hide removed private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT; /** * Audio session ID @@ -302,6 +302,7 @@ public class AudioTrack * @param mode streaming or static buffer. See {@link #MODE_STATIC} and {@link #MODE_STREAM} * @throws java.lang.IllegalArgumentException */ + // add {@link AudioFormat#ENCODING_PCM_FLOAT} to audioFormat section above, when @hide removed public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode) throws IllegalArgumentException { @@ -343,6 +344,7 @@ public class AudioTrack * @param sessionId Id of audio session the AudioTrack must be attached to * @throws java.lang.IllegalArgumentException */ + // add {@link AudioFormat#ENCODING_PCM_FLOAT} to audioFormat section above, when @hide removed public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode, int sessionId) throws IllegalArgumentException { @@ -461,11 +463,14 @@ public class AudioTrack break; case AudioFormat.ENCODING_PCM_16BIT: case AudioFormat.ENCODING_PCM_8BIT: + case AudioFormat.ENCODING_PCM_FLOAT: mAudioFormat = audioFormat; break; default: throw new IllegalArgumentException("Unsupported sample encoding." - + " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT."); + + " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT" + // + " or ENCODING_PCM_FLOAT" when @hide removed + + "."); } //-------------- @@ -518,7 +523,7 @@ public class AudioTrack // NB: this section is only valid with PCM data. // To update when supporting compressed formats int frameSizeInBytes = mChannelCount - * (mAudioFormat == AudioFormat.ENCODING_PCM_8BIT ? 1 : 2); + * (AudioFormat.getBytesPerSample(mAudioFormat)); if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) { throw new IllegalArgumentException("Invalid audio buffer size."); } @@ -730,6 +735,7 @@ public class AudioTrack * or {@link #ERROR} if unable to query for output properties, * or the minimum buffer size expressed in bytes. */ + // add {@link AudioFormat#ENCODING_PCM_FLOAT} to audioFormat section above, when @hide removed static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) { int channelCount = 0; switch(channelConfig) { @@ -752,7 +758,8 @@ public class AudioTrack } if ((audioFormat != AudioFormat.ENCODING_PCM_16BIT) - && (audioFormat != AudioFormat.ENCODING_PCM_8BIT)) { + && (audioFormat != AudioFormat.ENCODING_PCM_8BIT) + && (audioFormat != AudioFormat.ENCODING_PCM_FLOAT)) { loge("getMinBufferSize(): Invalid audio format."); return ERROR_BAD_VALUE; } @@ -1152,7 +1159,7 @@ public class AudioTrack public int write(byte[] audioData, int offsetInBytes, int sizeInBytes) { - if (mState == STATE_UNINITIALIZED) { + if (mState == STATE_UNINITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) { return ERROR_INVALID_OPERATION; } @@ -1190,13 +1197,13 @@ public class AudioTrack * starts. * @param sizeInShorts the number of shorts to read in audioData after the offset. * @return the number of shorts that were written or {@link #ERROR_INVALID_OPERATION} - * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if - * the parameters don't resolve to valid data and indexes. + * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if + * the parameters don't resolve to valid data and indexes. */ public int write(short[] audioData, int offsetInShorts, int sizeInShorts) { - if (mState == STATE_UNINITIALIZED) { + if (mState == STATE_UNINITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) { return ERROR_INVALID_OPERATION; } @@ -1220,7 +1227,80 @@ public class AudioTrack /** - * @hide CANDIDATE FOR PUBLIC API + * Writes the audio data to the audio sink for playback (streaming mode), + * or copies audio data for later playback (static buffer mode). + * In static buffer mode, copies the data to the buffer starting at offset 0, + * and the write mode is ignored. + * In streaming mode, the blocking behavior will depend on the write mode. + * <p> + * Note that the actual playback of this data might occur after this function + * returns. This function is thread safe with respect to {@link #stop} calls, + * in which case all of the specified data might not be written to the audio sink. + * <p> + * @param audioData the array that holds the data to play. + * The implementation does not clip for sample values within the nominal range + * [-1.0f, 1.0f], provided that all gains in the audio pipeline are + * less than or equal to unity (1.0f), and in the absence of post-processing effects + * that could add energy, such as reverb. For the convenience of applications + * that compute samples using filters with non-unity gain, + * sample values +3 dB beyond the nominal range are permitted. + * However such values may eventually be limited or clipped, depending on various gains + * and later processing in the audio path. Therefore applications are encouraged + * to provide samples values within the nominal range. + * @param offsetInFloats the offset, expressed as a number of floats, + * in audioData where the data to play starts. + * @param sizeInFloats the number of floats to read in audioData after the offset. + * @param writeMode one of {@link #WRITE_BLOCKING}, {@link #WRITE_NON_BLOCKING}. It has no + * effect in static mode. + * <BR>With {@link #WRITE_BLOCKING}, the write will block until all data has been written + * to the audio sink. + * <BR>With {@link #WRITE_NON_BLOCKING}, the write will return immediately after + * queuing as much audio data for playback as possible without blocking. + * @return the number of floats that were written, or {@link #ERROR_INVALID_OPERATION} + * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if + * the parameters don't resolve to valid data and indexes. + * @hide candidate for public API + */ + public int write(float[] audioData, int offsetInFloats, int sizeInFloats, + @WriteMode int writeMode) { + + if (mState == STATE_UNINITIALIZED) { + Log.e(TAG, "AudioTrack.write() called in invalid state STATE_UNINITIALIZED"); + return ERROR_INVALID_OPERATION; + } + + if (mAudioFormat != AudioFormat.ENCODING_PCM_FLOAT) { + Log.e(TAG, "AudioTrack.write(float[] ...) requires format ENCODING_PCM_FLOAT"); + return ERROR_INVALID_OPERATION; + } + + if ((writeMode != WRITE_BLOCKING) && (writeMode != WRITE_NON_BLOCKING)) { + Log.e(TAG, "AudioTrack.write() called with invalid blocking mode"); + return ERROR_BAD_VALUE; + } + + if ( (audioData == null) || (offsetInFloats < 0 ) || (sizeInFloats < 0) + || (offsetInFloats + sizeInFloats < 0) // detect integer overflow + || (offsetInFloats + sizeInFloats > audioData.length)) { + Log.e(TAG, "AudioTrack.write() called with invalid array, offset, or size"); + return ERROR_BAD_VALUE; + } + + int ret = native_write_float(audioData, offsetInFloats, sizeInFloats, mAudioFormat, + writeMode == WRITE_BLOCKING); + + if ((mDataLoadMode == MODE_STATIC) + && (mState == STATE_NO_STATIC_DATA) + && (ret > 0)) { + // benign race with respect to other APIs that read mState + mState = STATE_INITIALIZED; + } + + return ret; + } + + + /** * Writes the audio data to the audio sink for playback (streaming mode), * or copies audio data for later playback (static buffer mode). * In static buffer mode, copies the data to the buffer starting at its 0 offset, and the write @@ -1250,6 +1330,11 @@ public class AudioTrack return ERROR_INVALID_OPERATION; } + if (mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) { + Log.e(TAG, "AudioTrack.write(ByteBuffer ...) not yet supported for ENCODING_PCM_FLOAT"); + return ERROR_INVALID_OPERATION; + } + if ((writeMode != WRITE_BLOCKING) && (writeMode != WRITE_NON_BLOCKING)) { Log.e(TAG, "AudioTrack.write() called with invalid blocking mode"); return ERROR_BAD_VALUE; @@ -1490,6 +1575,10 @@ public class AudioTrack private native final int native_write_short(short[] audioData, int offsetInShorts, int sizeInShorts, int format); + private native final int native_write_float(float[] audioData, + int offsetInFloats, int sizeInFloats, int format, + boolean isBlocking); + private native final int native_write_native_bytes(Object audioData, int positionInBytes, int sizeInBytes, int format, boolean blocking); diff --git a/media/java/android/media/JetPlayer.java b/media/java/android/media/JetPlayer.java index bd91fc5..7735e78 100644 --- a/media/java/android/media/JetPlayer.java +++ b/media/java/android/media/JetPlayer.java @@ -169,9 +169,11 @@ public class JetPlayer native_setup(new WeakReference<JetPlayer>(this), JetPlayer.getMaxTracks(), - // bytes to frame conversion: sample format is ENCODING_PCM_16BIT, 2 channels + // bytes to frame conversion: // 1200 == minimum buffer size in frames on generation 1 hardware - Math.max(1200, buffSizeInBytes / 4)); + Math.max(1200, buffSizeInBytes / + (AudioFormat.getBytesPerSample(AudioFormat.ENCODING_PCM_16BIT) * + 2 /*channels*/))); } } diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl index ca77f04..3ff07d9 100644 --- a/media/java/android/media/session/ISession.aidl +++ b/media/java/android/media/session/ISession.aidl @@ -31,8 +31,8 @@ import android.os.ResultReceiver; interface ISession { void sendEvent(String event, in Bundle data); ISessionController getController(); - void setTransportPerformerEnabled(); - void publish(); + void setFlags(int flags); + void setActive(boolean active); void destroy(); // These commands are for setting up and communicating with routes diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl index 84b9a0f..7a8c22e 100644 --- a/media/java/android/media/session/ISessionManager.aidl +++ b/media/java/android/media/session/ISessionManager.aidl @@ -15,6 +15,7 @@ package android.media.session; +import android.content.ComponentName; import android.media.session.ISession; import android.media.session.ISessionCallback; import android.os.Bundle; @@ -25,4 +26,5 @@ import android.os.Bundle; */ interface ISessionManager { ISession createSession(String packageName, in ISessionCallback cb, String tag); + List<IBinder> getSessions(in ComponentName compName); }
\ No newline at end of file diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java index 4ee67d1..c07229d 100644 --- a/media/java/android/media/session/MediaSessionLegacyHelper.java +++ b/media/java/android/media/session/MediaSessionLegacyHelper.java @@ -43,7 +43,8 @@ public class MediaSessionLegacyHelper { private Handler mHandler = new Handler(Looper.getMainLooper()); // The legacy APIs use PendingIntents to register/unregister media button // receivers and these are associated with RCC. - private ArrayMap<PendingIntent, SessionHolder> mSessions = new ArrayMap<PendingIntent, SessionHolder>(); + private ArrayMap<PendingIntent, SessionHolder> mSessions + = new ArrayMap<PendingIntent, SessionHolder>(); private MediaSessionLegacyHelper(Context context) { mSessionManager = (SessionManager) context @@ -78,6 +79,8 @@ public class MediaSessionLegacyHelper { } performer.addListener(listener, mHandler); holder.mRccListener = listener; + holder.mFlags |= Session.FLAG_HANDLES_TRANSPORT_CONTROLS; + holder.mSession.setFlags(holder.mFlags); holder.update(); } @@ -86,6 +89,8 @@ public class MediaSessionLegacyHelper { if (holder != null && holder.mRccListener != null) { holder.mSession.getTransportPerformer().removeListener(holder.mRccListener); holder.mRccListener = null; + holder.mFlags &= ~Session.FLAG_HANDLES_TRANSPORT_CONTROLS; + holder.mSession.setFlags(holder.mFlags); holder.update(); } } @@ -98,6 +103,8 @@ public class MediaSessionLegacyHelper { return; } holder.mMediaButtonListener = new MediaButtonListener(pi, context); + holder.mFlags |= Session.FLAG_HANDLES_MEDIA_BUTTONS; + holder.mSession.setFlags(holder.mFlags); holder.mSession.getTransportPerformer().addListener(holder.mMediaButtonListener, mHandler); } @@ -105,6 +112,9 @@ public class MediaSessionLegacyHelper { SessionHolder holder = getHolder(pi, false); if (holder != null && holder.mMediaButtonListener != null) { holder.mSession.getTransportPerformer().removeListener(holder.mMediaButtonListener); + holder.mFlags &= ~Session.FLAG_HANDLES_MEDIA_BUTTONS; + holder.mSession.setFlags(holder.mFlags); + holder.mMediaButtonListener = null; holder.update(); } } @@ -113,8 +123,7 @@ public class MediaSessionLegacyHelper { SessionHolder holder = mSessions.get(pi); if (holder == null && createIfMissing) { Session session = mSessionManager.createSession(TAG); - session.setTransportPerformerEnabled(); - session.publish(); + session.setActive(true); holder = new SessionHolder(session, pi); mSessions.put(pi, holder); } @@ -193,6 +202,7 @@ public class MediaSessionLegacyHelper { public final PendingIntent mPi; public MediaButtonListener mMediaButtonListener; public TransportPerformer.Listener mRccListener; + public int mFlags; public SessionHolder(Session session, PendingIntent pi) { mSession = session; diff --git a/media/java/android/media/session/Session.java b/media/java/android/media/session/Session.java index 8ccd788..194679e7 100644 --- a/media/java/android/media/session/Session.java +++ b/media/java/android/media/session/Session.java @@ -45,12 +45,13 @@ import java.util.List; * media to multiple routes or to provide finer grain controls of media. * <p> * A MediaSession is created by calling - * {@link SessionManager#createSession(String)}. Once a session is created - * apps that have the MEDIA_CONTENT_CONTROL permission can interact with the - * session through {@link SessionManager#getActiveSessions()}. The owner of - * the session may also use {@link #getSessionToken()} to allow apps without - * this permission to create a {@link SessionController} to interact with this - * session. + * {@link SessionManager#createSession(String)}. Once a session is created apps + * that have the MEDIA_CONTENT_CONTROL permission can interact with the session + * through + * {@link SessionManager#getActiveSessions(android.content.ComponentName)}. The + * owner of the session may also use {@link #getSessionToken()} to allow apps + * without this permission to create a {@link SessionController} to interact + * with this session. * <p> * To receive commands, media keys, and other events a Callback must be set with * {@link #addCallback(Callback)}. @@ -63,6 +64,28 @@ import java.util.List; public final class Session { private static final String TAG = "Session"; + /** + * Set this flag on the session to indicate that it can handle media button + * events. + */ + public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1 << 0; + + /** + * Set this flag on the session to indicate that it handles commands through + * the {@link TransportPerformer}. The performer can be retrieved by calling + * {@link #getTransportPerformer()}. + */ + public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 1 << 1; + + /** + * System only flag for a session that needs to have priority over all other + * sessions. This flag ensures this session will receive media button events + * regardless of the current ordering in the system. + * + * @hide + */ + public static final int FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 1 << 16; + private static final int MSG_MEDIA_BUTTON = 1; private static final int MSG_COMMAND = 2; private static final int MSG_ROUTE_CHANGE = 3; @@ -86,7 +109,7 @@ public final class Session { private TransportPerformer mPerformer; private Route mRoute; - private boolean mPublished = false;; + private boolean mActive = false;; /** * @hide @@ -101,6 +124,7 @@ public final class Session { throw new RuntimeException("Dead object in MediaSessionController constructor: ", e); } mSessionToken = new SessionToken(controllerBinder); + mPerformer = new TransportPerformer(mBinder); } /** @@ -148,56 +172,57 @@ public final class Session { } /** - * Start using a TransportPerformer with this media session. This must be - * called before calling publish and cannot be called more than once. - * Calling this will allow MediaControllers to retrieve a - * TransportController. + * Retrieves the {@link TransportPerformer} for this session. To receive + * commands through the performer you must also set the + * {@link #FLAG_HANDLES_TRANSPORT_CONTROLS} flag using + * {@link #setFlags(int)}. * - * @see TransportController - * @return The TransportPerformer created for this session + * @return The performer associated with this session. */ - public TransportPerformer setTransportPerformerEnabled() { - if (mPerformer != null) { - throw new IllegalStateException("setTransportPerformer can only be called once."); - } - if (mPublished) { - throw new IllegalStateException("setTransportPerformer cannot be called after publish"); - } - - mPerformer = new TransportPerformer(mBinder); - try { - mBinder.setTransportPerformerEnabled(); - } catch (RemoteException e) { - Log.wtf(TAG, "Failure in setTransportPerformerEnabled.", e); - } + public TransportPerformer getTransportPerformer() { return mPerformer; } /** - * Retrieves the TransportPerformer used by this session. If called before - * {@link #setTransportPerformerEnabled} null will be returned. + * Set any flags for the session. * - * @return The TransportPerformer associated with this session or null + * @param flags The flags to set for this session. */ - public TransportPerformer getTransportPerformer() { - return mPerformer; + public void setFlags(int flags) { + try { + mBinder.setFlags(flags); + } catch (RemoteException e) { + Log.wtf(TAG, "Failure in setFlags.", e); + } } /** - * Call after you have finished setting up the session. This will make it - * available to listeners and begin pushing updates to MediaControllers. - * This can only be called once. + * Set if this session is currently active and ready to receive commands. If + * set to false your session's controller may not be discoverable. You must + * set the session to active before it can start receiving media button + * events or transport commands. + * + * @param active Whether this session is active or not. */ - public void publish() { - if (mPublished) { - throw new RuntimeException("publish() may only be called once."); + public void setActive(boolean active) { + if (mActive == active) { + return; } try { - mBinder.publish(); + mBinder.setActive(active); + mActive = active; } catch (RemoteException e) { - Log.wtf(TAG, "Failure in publish.", e); + Log.wtf(TAG, "Failure in setActive.", e); } - mPublished = true; + } + + /** + * Get the current active state of this session. + * + * @return True if the session is active, false otherwise. + */ + public boolean isActive() { + return mActive; } /** diff --git a/media/java/android/media/session/SessionManager.java b/media/java/android/media/session/SessionManager.java index 15bf0e3..fd022fc 100644 --- a/media/java/android/media/session/SessionManager.java +++ b/media/java/android/media/session/SessionManager.java @@ -16,11 +16,13 @@ package android.media.session; +import android.content.ComponentName; import android.content.Context; import android.media.session.ISessionManager; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; +import android.service.notification.NotificationListenerService; import android.util.Log; import java.util.ArrayList; @@ -79,12 +81,27 @@ public final class SessionManager { /** * Get a list of controllers for all ongoing sessions. This requires the * android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by - * the calling app. + * the calling app. You may also retrieve this list if your app is an + * enabled notification listener using the + * {@link NotificationListenerService} APIs, in which case you must pass the + * {@link ComponentName} of your enabled listener. * - * @return a list of controllers for ongoing sessions + * @param notificationListener The enabled notification listener component. + * May be null. + * @return A list of controllers for ongoing sessions */ - public List<SessionController> getActiveSessions() { - // TODO - return new ArrayList<SessionController>(); + public List<SessionController> getActiveSessions(ComponentName notificationListener) { + ArrayList<SessionController> controllers = new ArrayList<SessionController>(); + try { + List<IBinder> binders = mService.getSessions(notificationListener); + for (int i = binders.size() - 1; i >= 0; i--) { + SessionController controller = SessionController.fromBinder(ISessionController.Stub + .asInterface(binders.get(i))); + controllers.add(controller); + } + } catch (RemoteException e) { + Log.e(TAG, "Failed to get active sessions: ", e); + } + return controllers; } } diff --git a/media/jni/Android.mk b/media/jni/Android.mk index ed98b96..90fe695 100644 --- a/media/jni/Android.mk +++ b/media/jni/Android.mk @@ -66,8 +66,6 @@ LOCAL_C_INCLUDES += \ LOCAL_CFLAGS += -LOCAL_LDLIBS := -lpthread - LOCAL_MODULE:= libmedia_jni include $(BUILD_SHARED_LIBRARY) diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index abebd48..6f42057 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -648,7 +648,7 @@ android_media_MediaPlayer_native_init(JNIEnv *env) return; } - clazz = env->FindClass("android/net/ProxyProperties"); + clazz = env->FindClass("android/net/ProxyInfo"); if (clazz == NULL) { return; } @@ -660,7 +660,7 @@ android_media_MediaPlayer_native_init(JNIEnv *env) env->GetMethodID(clazz, "getPort", "()I"); fields.proxyConfigGetExclusionList = - env->GetMethodID(clazz, "getExclusionList", "()Ljava/lang/String;"); + env->GetMethodID(clazz, "getExclusionListAsString", "()Ljava/lang/String;"); } static void |
