summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--media/java/android/media/MediaPlayer2.java117
-rw-r--r--media/java/android/media/MediaPlayer2Impl.java1046
-rw-r--r--media/jni/android_media_MediaPlayer2.cpp13
3 files changed, 7 insertions, 1169 deletions
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
index 0f83fd5803de..3d10c5630b9c 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -32,9 +32,6 @@ import android.view.SurfaceHolder;
import dalvik.system.CloseGuard;
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.InputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -456,8 +453,7 @@ import java.util.concurrent.Executor;
* thread by default has a Looper running).
*
*/
-public abstract class MediaPlayer2 implements SubtitleController.Listener
- , AutoCloseable
+public abstract class MediaPlayer2 implements AutoCloseable
, AudioRouting {
private final CloseGuard mGuard = CloseGuard.get();
@@ -1306,16 +1302,6 @@ public abstract class MediaPlayer2 implements SubtitleController.Listener
public abstract void reset();
/**
- * Set up a timer for {@link #TimeProvider}. {@link #TimeProvider} will be
- * notified when the presentation time reaches (becomes greater than or equal to)
- * the value specified.
- *
- * @param mediaTimeUs presentation time to get timed event callback at
- * @hide
- */
- public void notifyAt(long mediaTimeUs) { }
-
- /**
* Checks whether the MediaPlayer2 is looping or non-looping.
*
* @return true if the MediaPlayer2 is currently looping, false otherwise
@@ -1462,95 +1448,6 @@ public abstract class MediaPlayer2 implements SubtitleController.Listener
*/
public static final String MEDIA_MIMETYPE_TEXT_CEA_708 = "text/cea-708";
- /** @hide */
- public void setSubtitleAnchor(
- SubtitleController controller,
- SubtitleController.Anchor anchor) { }
-
- /** @hide */
- @Override
- public void onSubtitleTrackSelected(SubtitleTrack track) { }
-
- /** @hide */
- public void addSubtitleSource(InputStream is, MediaFormat format) { }
-
- /* TODO: Limit the total number of external timed text source to a reasonable number.
- */
- /**
- * Adds an external timed text source file.
- *
- * Currently supported format is SubRip with the file extension .srt, case insensitive.
- * Note that a single external timed text source may contain multiple tracks in it.
- * One can find the total number of available tracks using {@link #getTrackInfo()} to see what
- * additional tracks become available after this method call.
- *
- * @param path The file path of external timed text source file.
- * @param mimeType The mime type of the file. Must be one of the mime types listed above.
- * @throws IOException if the file cannot be accessed or is corrupted.
- * @throws IllegalArgumentException if the mimeType is not supported.
- * @throws IllegalStateException if called in an invalid state.
- * @hide
- */
- public void addTimedTextSource(String path, String mimeType) throws IOException { }
-
- /**
- * Adds an external timed text source file (Uri).
- *
- * Currently supported format is SubRip with the file extension .srt, case insensitive.
- * Note that a single external timed text source may contain multiple tracks in it.
- * One can find the total number of available tracks using {@link #getTrackInfo()} to see what
- * additional tracks become available after this method call.
- *
- * @param context the Context to use when resolving the Uri
- * @param uri the Content URI of the data you want to play
- * @param mimeType The mime type of the file. Must be one of the mime types listed above.
- * @throws IOException if the file cannot be accessed or is corrupted.
- * @throws IllegalArgumentException if the mimeType is not supported.
- * @throws IllegalStateException if called in an invalid state.
- * @hide
- */
- public void addTimedTextSource(Context context, Uri uri, String mimeType) throws IOException { }
-
- /**
- * Adds an external timed text source file (FileDescriptor).
- *
- * It is the caller's responsibility to close the file descriptor.
- * It is safe to do so as soon as this call returns.
- *
- * Currently supported format is SubRip. Note that a single external timed text source may
- * contain multiple tracks in it. One can find the total number of available tracks
- * using {@link #getTrackInfo()} to see what additional tracks become available
- * after this method call.
- *
- * @param fd the FileDescriptor for the file you want to play
- * @param mimeType The mime type of the file. Must be one of the mime types listed above.
- * @throws IllegalArgumentException if the mimeType is not supported.
- * @throws IllegalStateException if called in an invalid state.
- * @hide
- */
- public void addTimedTextSource(FileDescriptor fd, String mimeType) { }
-
- /**
- * Adds an external timed text file (FileDescriptor).
- *
- * It is the caller's responsibility to close the file descriptor.
- * It is safe to do so as soon as this call returns.
- *
- * Currently supported format is SubRip. Note that a single external timed text source may
- * contain multiple tracks in it. One can find the total number of available tracks
- * using {@link #getTrackInfo()} to see what additional tracks become available
- * after this method call.
- *
- * @param fd the FileDescriptor for the file you want to play
- * @param offset the offset into the file where the data to be played starts, in bytes
- * @param length the length in bytes of the data to be played
- * @param mime The mime type of the file. Must be one of the mime types listed above.
- * @throws IllegalArgumentException if the mimeType is not supported.
- * @throws IllegalStateException if called in an invalid state.
- * @hide
- */
- public abstract void addTimedTextSource(FileDescriptor fd, long offset, long length, String mime);
-
/**
* Returns the index of the audio, video, or subtitle track currently selected for playback,
* The return value is an index into the array returned by {@link #getTrackInfo()}, and can
@@ -1618,11 +1515,6 @@ public abstract class MediaPlayer2 implements SubtitleController.Listener
// This is an asynchronous call.
public abstract void deselectTrack(int index);
- /** @hide */
- public MediaTimeProvider getMediaTimeProvider() {
- return null;
- }
-
/**
* Interface definition for callbacks to be invoked when the player has the corresponding
* events.
@@ -1904,12 +1796,6 @@ public abstract class MediaPlayer2 implements SubtitleController.Listener
*/
public static final int MEDIA_INFO_METADATA_UPDATE = 802;
- /** A new set of external-only metadata is available. Used by
- * JAVA framework to avoid triggering track scanning.
- * @hide
- */
- public static final int MEDIA_INFO_EXTERNAL_METADATA_UPDATE = 803;
-
/** Informs that audio is not playing. Note that playback of the video
* is not interrupted.
* @see EventCallback#onInfo
@@ -1958,7 +1844,6 @@ public abstract class MediaPlayer2 implements SubtitleController.Listener
MEDIA_INFO_BAD_INTERLEAVING,
MEDIA_INFO_NOT_SEEKABLE,
MEDIA_INFO_METADATA_UPDATE,
- MEDIA_INFO_EXTERNAL_METADATA_UPDATE,
MEDIA_INFO_AUDIO_NOT_PLAYING,
MEDIA_INFO_VIDEO_NOT_PLAYING,
MEDIA_INFO_TIMED_TEXT_ERROR,
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index 53735e58a184..f46ee3408383 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -19,7 +19,6 @@ package android.media;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.ActivityThread;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
@@ -29,8 +28,6 @@ import android.graphics.Rect;
import android.media.MediaPlayer2Proto;
import android.media.MediaPlayer2Proto.PlayerMessage;
import android.media.MediaPlayer2Proto.Value;
-import android.media.SubtitleController.Anchor;
-import android.media.SubtitleTrack.RenderingWidget;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
@@ -38,24 +35,18 @@ import android.os.Looper;
import android.os.Message;
import android.os.PersistableBundle;
import android.os.PowerManager;
-import android.os.Process;
import android.os.SystemProperties;
import android.provider.Settings;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.OsConstants;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
import android.view.Surface;
import android.view.SurfaceHolder;
-import android.widget.VideoView;
import com.android.framework.protobuf.InvalidProtocolBufferException;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
-import libcore.io.IoBridge;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -70,15 +61,12 @@ import java.net.URL;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.BitSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.Scanner;
import java.util.UUID;
-import java.util.Vector;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicInteger;
@@ -156,9 +144,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
Looper looper = mHandlerThread.getLooper();
mTaskHandler = new TaskHandler(this, looper);
- mTimeProvider = new TimeProvider(this);
- mOpenSubtitleSources = new Vector<InputStream>();
-
/* Native setup requires a weak reference to our object.
* It's easier to create it here than in C++.
*/
@@ -1504,24 +1489,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
*/
@Override
public void reset() {
- mSelectedSubtitleTrackIndex = -1;
- synchronized(mOpenSubtitleSources) {
- for (final InputStream is: mOpenSubtitleSources) {
- try {
- is.close();
- } catch (IOException e) {
- }
- }
- mOpenSubtitleSources.clear();
- }
- if (mSubtitleController != null) {
- mSubtitleController.reset();
- }
- if (mTimeProvider != null) {
- mTimeProvider.close();
- mTimeProvider = null;
- }
-
synchronized (mEventCbLock) {
mEventCallbackRecords.clear();
}
@@ -1544,31 +1511,11 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
mTaskHandler.removeCallbacksAndMessages(null);
}
- synchronized (mIndexTrackPairs) {
- mIndexTrackPairs.clear();
- mInbandTrackIndices.clear();
- };
-
resetDrmState();
}
private native void _reset();
- /**
- * Set up a timer for {@link #TimeProvider}. {@link #TimeProvider} will be
- * notified when the presentation time reaches (becomes greater than or equal to)
- * the value specified.
- *
- * @param mediaTimeUs presentation time to get timed event callback at
- * @hide
- */
- @Override
- public void notifyAt(long mediaTimeUs) {
- _notifyAt(mediaTimeUs);
- }
-
- private native void _notifyAt(long mediaTimeUs);
-
// Keep KEY_PARAMETER_* in sync with include/media/mediaplayer2.h
private final static int KEY_PARAMETER_AUDIO_ATTRIBUTES = 1400;
/**
@@ -1782,16 +1729,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
}
};
- // We would like domain specific classes with more informative names than the `first` and `second`
- // in generic Pair, but we would also like to avoid creating new/trivial classes. As a compromise
- // we document the meanings of `first` and `second` here:
- //
- // Pair.first - inband track index; non-null iff representing an inband track.
- // Pair.second - a SubtitleTrack registered with mSubtitleController; non-null iff representing
- // an inband subtitle track or any out-of-band track (subtitle or timedtext).
- private Vector<Pair<Integer, SubtitleTrack>> mIndexTrackPairs = new Vector<>();
- private BitSet mInbandTrackIndices = new BitSet();
-
/**
* Returns a List of track information.
*
@@ -1803,21 +1740,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
@Override
public List<TrackInfo> getTrackInfo() {
TrackInfoImpl trackInfo[] = getInbandTrackInfoImpl();
- // add out-of-band tracks
- synchronized (mIndexTrackPairs) {
- TrackInfoImpl allTrackInfo[] = new TrackInfoImpl[mIndexTrackPairs.size()];
- for (int i = 0; i < allTrackInfo.length; i++) {
- Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i);
- if (p.first != null) {
- // inband track
- allTrackInfo[i] = trackInfo[p.first];
- } else {
- SubtitleTrack track = p.second;
- allTrackInfo[i] = new TrackInfoImpl(track.getTrackType(), track.getFormat());
- }
- }
- return Arrays.asList(allTrackInfo);
- }
+ return Arrays.asList(trackInfo);
}
private TrackInfoImpl[] getInbandTrackInfoImpl() throws IllegalStateException {
@@ -1850,419 +1773,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
return false;
}
- private SubtitleController mSubtitleController;
-
- /** @hide */
- @Override
- public void setSubtitleAnchor(
- SubtitleController controller,
- SubtitleController.Anchor anchor) {
- // TODO: create SubtitleController in MediaPlayer2
- mSubtitleController = controller;
- mSubtitleController.setAnchor(anchor);
- }
-
- /**
- * The private version of setSubtitleAnchor is used internally to set mSubtitleController if
- * necessary when clients don't provide their own SubtitleControllers using the public version
- * {@link #setSubtitleAnchor(SubtitleController, Anchor)} (e.g. {@link VideoView} provides one).
- */
- private synchronized void setSubtitleAnchor() {
- if ((mSubtitleController == null) && (ActivityThread.currentApplication() != null)) {
- final HandlerThread thread = new HandlerThread("SetSubtitleAnchorThread");
- thread.start();
- Handler handler = new Handler(thread.getLooper());
- handler.post(new Runnable() {
- @Override
- public void run() {
- Context context = ActivityThread.currentApplication();
- mSubtitleController = new SubtitleController(context, mTimeProvider, MediaPlayer2Impl.this);
- mSubtitleController.setAnchor(new Anchor() {
- @Override
- public void setSubtitleWidget(RenderingWidget subtitleWidget) {
- }
-
- @Override
- public Looper getSubtitleLooper() {
- return Looper.getMainLooper();
- }
- });
- thread.getLooper().quitSafely();
- }
- });
- try {
- thread.join();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- Log.w(TAG, "failed to join SetSubtitleAnchorThread");
- }
- }
- }
-
- private int mSelectedSubtitleTrackIndex = -1;
- private Vector<InputStream> mOpenSubtitleSources;
-
- private EventCallback mSubtitleDataCallback = new EventCallback() {
- @Override
- public void onSubtitleData(MediaPlayer2 mp, DataSourceDesc dsd, SubtitleData data) {
- int index = data.getTrackIndex();
- synchronized (mIndexTrackPairs) {
- for (Pair<Integer, SubtitleTrack> p : mIndexTrackPairs) {
- if (p.first != null && p.first == index && p.second != null) {
- // inband subtitle track that owns data
- SubtitleTrack track = p.second;
- track.onData(data);
- }
- }
- }
- }
- };
-
- /** @hide */
- @Override
- public void onSubtitleTrackSelected(SubtitleTrack track) {
- if (mSelectedSubtitleTrackIndex >= 0) {
- try {
- selectOrDeselectInbandTrack(mSelectedSubtitleTrackIndex, false);
- } catch (IllegalStateException e) {
- }
- mSelectedSubtitleTrackIndex = -1;
- }
- unregisterEventCallback(mSubtitleDataCallback);
- if (track == null) {
- return;
- }
-
- synchronized (mIndexTrackPairs) {
- for (Pair<Integer, SubtitleTrack> p : mIndexTrackPairs) {
- if (p.first != null && p.second == track) {
- // inband subtitle track that is selected
- mSelectedSubtitleTrackIndex = p.first;
- break;
- }
- }
- }
-
- if (mSelectedSubtitleTrackIndex >= 0) {
- try {
- selectOrDeselectInbandTrack(mSelectedSubtitleTrackIndex, true);
- } catch (IllegalStateException e) {
- }
- final Executor executor = (runnable) -> mTaskHandler.post(runnable);
- registerEventCallback(executor, mSubtitleDataCallback);
- }
- // no need to select out-of-band tracks
- }
-
- /** @hide */
- @Override
- public void addSubtitleSource(InputStream is, MediaFormat format)
- throws IllegalStateException
- {
- final InputStream fIs = is;
- final MediaFormat fFormat = format;
-
- if (is != null) {
- // Ensure all input streams are closed. It is also a handy
- // way to implement timeouts in the future.
- synchronized(mOpenSubtitleSources) {
- mOpenSubtitleSources.add(is);
- }
- } else {
- Log.w(TAG, "addSubtitleSource called with null InputStream");
- }
-
- getMediaTimeProvider();
-
- // process each subtitle in its own thread
- final HandlerThread thread = new HandlerThread("SubtitleReadThread",
- Process.THREAD_PRIORITY_BACKGROUND + Process.THREAD_PRIORITY_MORE_FAVORABLE);
- thread.start();
- Handler handler = new Handler(thread.getLooper());
- handler.post(new Runnable() {
- private int addTrack() {
- if (fIs == null || mSubtitleController == null) {
- return MEDIA_INFO_UNSUPPORTED_SUBTITLE;
- }
-
- SubtitleTrack track = mSubtitleController.addTrack(fFormat);
- if (track == null) {
- return MEDIA_INFO_UNSUPPORTED_SUBTITLE;
- }
-
- // TODO: do the conversion in the subtitle track
- Scanner scanner = new Scanner(fIs, "UTF-8");
- String contents = scanner.useDelimiter("\\A").next();
- synchronized(mOpenSubtitleSources) {
- mOpenSubtitleSources.remove(fIs);
- }
- scanner.close();
- synchronized (mIndexTrackPairs) {
- mIndexTrackPairs.add(Pair.<Integer, SubtitleTrack>create(null, track));
- }
- Handler h = mTimeProvider.mEventHandler;
- int what = TimeProvider.NOTIFY;
- int arg1 = TimeProvider.NOTIFY_TRACK_DATA;
- Pair<SubtitleTrack, byte[]> trackData = Pair.create(track, contents.getBytes());
- Message m = h.obtainMessage(what, arg1, 0, trackData);
- h.sendMessage(m);
- return MEDIA_INFO_EXTERNAL_METADATA_UPDATE;
- }
-
- public void run() {
- int res = addTrack();
- if (mTaskHandler != null) {
- Message m = mTaskHandler.obtainMessage(MEDIA_INFO, res, 0, null);
- mTaskHandler.sendMessage(m);
- }
- thread.getLooper().quitSafely();
- }
- });
- }
-
- private void scanInternalSubtitleTracks() {
- setSubtitleAnchor();
-
- populateInbandTracks();
-
- if (mSubtitleController != null) {
- mSubtitleController.selectDefaultTrack();
- }
- }
-
- private void populateInbandTracks() {
- TrackInfoImpl[] tracks = getInbandTrackInfoImpl();
- synchronized (mIndexTrackPairs) {
- for (int i = 0; i < tracks.length; i++) {
- if (mInbandTrackIndices.get(i)) {
- continue;
- } else {
- mInbandTrackIndices.set(i);
- }
-
- // newly appeared inband track
- if (tracks[i].getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
- SubtitleTrack track = mSubtitleController.addTrack(
- tracks[i].getFormat());
- mIndexTrackPairs.add(Pair.create(i, track));
- } else {
- mIndexTrackPairs.add(Pair.<Integer, SubtitleTrack>create(i, null));
- }
- }
- }
- }
-
- /* TODO: Limit the total number of external timed text source to a reasonable number.
- */
- /**
- * Adds an external timed text source file.
- *
- * Currently supported format is SubRip with the file extension .srt, case insensitive.
- * Note that a single external timed text source may contain multiple tracks in it.
- * One can find the total number of available tracks using {@link #getTrackInfo()} to see what
- * additional tracks become available after this method call.
- *
- * @param path The file path of external timed text source file.
- * @param mimeType The mime type of the file. Must be one of the mime types listed above.
- * @throws IOException if the file cannot be accessed or is corrupted.
- * @throws IllegalArgumentException if the mimeType is not supported.
- * @throws IllegalStateException if called in an invalid state.
- * @hide
- */
- @Override
- public void addTimedTextSource(String path, String mimeType)
- throws IOException {
- if (!availableMimeTypeForExternalSource(mimeType)) {
- final String msg = "Illegal mimeType for timed text source: " + mimeType;
- throw new IllegalArgumentException(msg);
- }
-
- File file = new File(path);
- if (file.exists()) {
- FileInputStream is = new FileInputStream(file);
- FileDescriptor fd = is.getFD();
- addTimedTextSource(fd, mimeType);
- is.close();
- } else {
- // We do not support the case where the path is not a file.
- throw new IOException(path);
- }
- }
-
-
- /**
- * Adds an external timed text source file (Uri).
- *
- * Currently supported format is SubRip with the file extension .srt, case insensitive.
- * Note that a single external timed text source may contain multiple tracks in it.
- * One can find the total number of available tracks using {@link #getTrackInfo()} to see what
- * additional tracks become available after this method call.
- *
- * @param context the Context to use when resolving the Uri
- * @param uri the Content URI of the data you want to play
- * @param mimeType The mime type of the file. Must be one of the mime types listed above.
- * @throws IOException if the file cannot be accessed or is corrupted.
- * @throws IllegalArgumentException if the mimeType is not supported.
- * @throws IllegalStateException if called in an invalid state.
- * @hide
- */
- @Override
- public void addTimedTextSource(Context context, Uri uri, String mimeType)
- throws IOException {
- String scheme = uri.getScheme();
- if(scheme == null || scheme.equals("file")) {
- addTimedTextSource(uri.getPath(), mimeType);
- return;
- }
-
- AssetFileDescriptor fd = null;
- try {
- ContentResolver resolver = context.getContentResolver();
- fd = resolver.openAssetFileDescriptor(uri, "r");
- if (fd == null) {
- return;
- }
- addTimedTextSource(fd.getFileDescriptor(), mimeType);
- return;
- } catch (SecurityException ex) {
- } catch (IOException ex) {
- } finally {
- if (fd != null) {
- fd.close();
- }
- }
- }
-
- /**
- * Adds an external timed text source file (FileDescriptor).
- *
- * It is the caller's responsibility to close the file descriptor.
- * It is safe to do so as soon as this call returns.
- *
- * Currently supported format is SubRip. Note that a single external timed text source may
- * contain multiple tracks in it. One can find the total number of available tracks
- * using {@link #getTrackInfo()} to see what additional tracks become available
- * after this method call.
- *
- * @param fd the FileDescriptor for the file you want to play
- * @param mimeType The mime type of the file. Must be one of the mime types listed above.
- * @throws IllegalArgumentException if the mimeType is not supported.
- * @throws IllegalStateException if called in an invalid state.
- * @hide
- */
- @Override
- public void addTimedTextSource(FileDescriptor fd, String mimeType) {
- // intentionally less than LONG_MAX
- addTimedTextSource(fd, 0, 0x7ffffffffffffffL, mimeType);
- }
-
- /**
- * Adds an external timed text file (FileDescriptor).
- *
- * It is the caller's responsibility to close the file descriptor.
- * It is safe to do so as soon as this call returns.
- *
- * Currently supported format is SubRip. Note that a single external timed text source may
- * contain multiple tracks in it. One can find the total number of available tracks
- * using {@link #getTrackInfo()} to see what additional tracks become available
- * after this method call.
- *
- * @param fd the FileDescriptor for the file you want to play
- * @param offset the offset into the file where the data to be played starts, in bytes
- * @param length the length in bytes of the data to be played
- * @param mime The mime type of the file. Must be one of the mime types listed above.
- * @throws IllegalArgumentException if the mimeType is not supported.
- * @throws IllegalStateException if called in an invalid state.
- * @hide
- */
- @Override
- public void addTimedTextSource(FileDescriptor fd, long offset, long length, String mime) {
- if (!availableMimeTypeForExternalSource(mime)) {
- throw new IllegalArgumentException("Illegal mimeType for timed text source: " + mime);
- }
-
- final FileDescriptor dupedFd;
- try {
- dupedFd = Os.dup(fd);
- } catch (ErrnoException ex) {
- Log.e(TAG, ex.getMessage(), ex);
- throw new RuntimeException(ex);
- }
-
- final MediaFormat fFormat = new MediaFormat();
- fFormat.setString(MediaFormat.KEY_MIME, mime);
- fFormat.setInteger(MediaFormat.KEY_IS_TIMED_TEXT, 1);
-
- // A MediaPlayer2 created by a VideoView should already have its mSubtitleController set.
- if (mSubtitleController == null) {
- setSubtitleAnchor();
- }
-
- if (!mSubtitleController.hasRendererFor(fFormat)) {
- // test and add not atomic
- Context context = ActivityThread.currentApplication();
- mSubtitleController.registerRenderer(new SRTRenderer(context, mTaskHandler));
- }
- final SubtitleTrack track = mSubtitleController.addTrack(fFormat);
- synchronized (mIndexTrackPairs) {
- mIndexTrackPairs.add(Pair.<Integer, SubtitleTrack>create(null, track));
- }
-
- getMediaTimeProvider();
-
- final long offset2 = offset;
- final long length2 = length;
- final HandlerThread thread = new HandlerThread(
- "TimedTextReadThread",
- Process.THREAD_PRIORITY_BACKGROUND + Process.THREAD_PRIORITY_MORE_FAVORABLE);
- thread.start();
- Handler handler = new Handler(thread.getLooper());
- handler.post(new Runnable() {
- private int addTrack() {
- final ByteArrayOutputStream bos = new ByteArrayOutputStream();
- try {
- Os.lseek(dupedFd, offset2, OsConstants.SEEK_SET);
- byte[] buffer = new byte[4096];
- for (long total = 0; total < length2;) {
- int bytesToRead = (int) Math.min(buffer.length, length2 - total);
- int bytes = IoBridge.read(dupedFd, buffer, 0, bytesToRead);
- if (bytes < 0) {
- break;
- } else {
- bos.write(buffer, 0, bytes);
- total += bytes;
- }
- }
- Handler h = mTimeProvider.mEventHandler;
- int what = TimeProvider.NOTIFY;
- int arg1 = TimeProvider.NOTIFY_TRACK_DATA;
- Pair<SubtitleTrack, byte[]> trackData = Pair.create(track, bos.toByteArray());
- Message m = h.obtainMessage(what, arg1, 0, trackData);
- h.sendMessage(m);
- return MEDIA_INFO_EXTERNAL_METADATA_UPDATE;
- } catch (Exception e) {
- Log.e(TAG, e.getMessage(), e);
- return MEDIA_INFO_TIMED_TEXT_ERROR;
- } finally {
- try {
- Os.close(dupedFd);
- } catch (ErrnoException e) {
- Log.e(TAG, e.getMessage(), e);
- }
- }
- }
-
- public void run() {
- int res = addTrack();
- if (mTaskHandler != null) {
- Message m = mTaskHandler.obtainMessage(MEDIA_INFO, res, 0, null);
- mTaskHandler.sendMessage(m);
- }
- thread.getLooper().quitSafely();
- }
- });
- }
-
/**
* Returns the index of the audio, video, or subtitle track currently selected for playback,
* The return value is an index into the array returned by {@link #getTrackInfo()}, and can
@@ -2282,22 +1792,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
*/
@Override
public int getSelectedTrack(int trackType) {
- if (mSubtitleController != null
- && (trackType == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE
- || trackType == TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT)) {
- SubtitleTrack subtitleTrack = mSubtitleController.getSelectedTrack();
- if (subtitleTrack != null) {
- synchronized (mIndexTrackPairs) {
- for (int i = 0; i < mIndexTrackPairs.size(); i++) {
- Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i);
- if (p.second == subtitleTrack && subtitleTrack.getTrackType() == trackType) {
- return i;
- }
- }
- }
- }
- }
-
PlayerMessage request = PlayerMessage.newBuilder()
.addValues(Value.newBuilder().setInt32Value(INVOKE_ID_GET_SELECTED_TRACK))
.addValues(Value.newBuilder().setInt32Value(trackType))
@@ -2306,16 +1800,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
if (response == null) {
return -1;
}
- int inbandTrackIndex = response.getValues(0).getInt32Value();
- synchronized (mIndexTrackPairs) {
- for (int i = 0; i < mIndexTrackPairs.size(); i++) {
- Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i);
- if (p.first != null && p.first == inbandTrackIndex) {
- return i;
- }
- }
- }
- return -1;
+ return response.getValues(0).getInt32Value();
}
/**
@@ -2382,56 +1867,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
private void selectOrDeselectTrack(int index, boolean select)
throws IllegalStateException {
- // handle subtitle track through subtitle controller
- populateInbandTracks();
-
- Pair<Integer,SubtitleTrack> p = null;
- try {
- p = mIndexTrackPairs.get(index);
- } catch (ArrayIndexOutOfBoundsException e) {
- // ignore bad index
- return;
- }
-
- SubtitleTrack track = p.second;
- if (track == null) {
- // inband (de)select
- selectOrDeselectInbandTrack(p.first, select);
- return;
- }
-
- if (mSubtitleController == null) {
- return;
- }
-
- if (!select) {
- // out-of-band deselect
- if (mSubtitleController.getSelectedTrack() == track) {
- mSubtitleController.selectTrack(null);
- } else {
- Log.w(TAG, "trying to deselect track that was not selected");
- }
- return;
- }
-
- // out-of-band select
- if (track.getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT) {
- int ttIndex = getSelectedTrack(TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT);
- synchronized (mIndexTrackPairs) {
- if (ttIndex >= 0 && ttIndex < mIndexTrackPairs.size()) {
- Pair<Integer,SubtitleTrack> p2 = mIndexTrackPairs.get(ttIndex);
- if (p2.first != null && p2.second == null) {
- // deselect inband counterpart
- selectOrDeselectInbandTrack(p2.first, false);
- }
- }
- }
- }
- mSubtitleController.selectTrack(track);
- }
-
- private void selectOrDeselectInbandTrack(int index, boolean select)
- throws IllegalStateException {
PlayerMessage request = PlayerMessage.newBuilder()
.addValues(Value.newBuilder().setInt32Value(
select? INVOKE_ID_SELECT_TRACK: INVOKE_ID_DESELECT_TRACK))
@@ -2461,10 +1896,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
mHandlerThread.quitSafely();
mHandlerThread = null;
}
- if (mTimeProvider != null) {
- mTimeProvider.close();
- mTimeProvider = null;
- }
// Modular DRM clean up
mOnDrmConfigHelper = null;
@@ -2501,17 +1932,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
private static final int MEDIA_DRM_INFO = 210;
private static final int MEDIA_AUDIO_ROUTING_CHANGED = 10000;
- private TimeProvider mTimeProvider;
-
- /** @hide */
- @Override
- public MediaTimeProvider getMediaTimeProvider() {
- if (mTimeProvider == null) {
- mTimeProvider = new TimeProvider(this);
- }
- return mTimeProvider;
- }
-
private class TaskHandler extends Handler {
private MediaPlayer2Impl mMediaPlayer;
@@ -2551,17 +1971,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
switch(msg.what) {
case MEDIA_PREPARED:
{
- try {
- scanInternalSubtitleTracks();
- } catch (RuntimeException e) {
- // send error message instead of crashing;
- // send error message instead of inlining a call to onError
- // to avoid code duplication.
- Message msg2 = obtainMessage(
- MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null);
- sendMessage(msg2);
- }
-
if (dsd != null) {
sendEvent(new EventNotifier() {
@Override
@@ -2657,21 +2066,13 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
}
case MEDIA_STOPPED:
- {
- TimeProvider timeProvider = mTimeProvider;
- if (timeProvider != null) {
- timeProvider.onStopped();
- }
- break;
- }
-
case MEDIA_STARTED:
case MEDIA_PAUSED:
+ case MEDIA_SKIPPED:
+ case MEDIA_NOTIFY_TIME:
{
- TimeProvider timeProvider = mTimeProvider;
- if (timeProvider != null) {
- timeProvider.onPaused(msg.what == MEDIA_PAUSED);
- }
+ // Do nothing. The client should have enough information with
+ // {@link EventCallback#onMediaTimeDiscontinuity}.
break;
}
@@ -2707,15 +2108,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
processPendingTask_l();
}
}
- }
- // fall through
-
- case MEDIA_SKIPPED:
- {
- TimeProvider timeProvider = mTimeProvider;
- if (timeProvider != null) {
- timeProvider.onSeekComplete(mMediaPlayer);
- }
return;
}
@@ -2760,33 +2152,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
case MEDIA_INFO_VIDEO_TRACK_LAGGING:
Log.i(TAG, "Info (" + msg.arg1 + "," + msg.arg2 + ")");
break;
-
- case MEDIA_INFO_METADATA_UPDATE:
- try {
- scanInternalSubtitleTracks();
- } catch (RuntimeException e) {
- Message msg2 = obtainMessage(
- MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED,
- null);
- sendMessage(msg2);
- }
- // fall through
-
- case MEDIA_INFO_EXTERNAL_METADATA_UPDATE:
- msg.arg1 = MEDIA_INFO_METADATA_UPDATE;
- // update default track selection
- if (mSubtitleController != null) {
- mSubtitleController.selectDefaultTrack();
- }
- break;
-
- case MEDIA_INFO_BUFFERING_START:
- case MEDIA_INFO_BUFFERING_END:
- TimeProvider timeProvider = mTimeProvider;
- if (timeProvider != null) {
- timeProvider.onBuffering(msg.arg1 == MEDIA_INFO_BUFFERING_START);
- }
- break;
}
sendEvent(new EventNotifier() {
@@ -2807,15 +2172,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
return;
}
- case MEDIA_NOTIFY_TIME:
- {
- TimeProvider timeProvider = mTimeProvider;
- if (timeProvider != null) {
- timeProvider.onNotifyTime();
- }
- return;
- }
-
case MEDIA_TIMED_TEXT:
{
final TimedText text;
@@ -4236,396 +3592,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
}
}
- /** @hide */
- static class TimeProvider implements MediaTimeProvider {
- private static final String TAG = "MTP";
- private static final long MAX_NS_WITHOUT_POSITION_CHECK = 5000000000L;
- private static final long MAX_EARLY_CALLBACK_US = 1000;
- private static final long TIME_ADJUSTMENT_RATE = 2; /* meaning 1/2 */
- private long mLastTimeUs = 0;
- private MediaPlayer2Impl mPlayer;
- private boolean mPaused = true;
- private boolean mStopped = true;
- private boolean mBuffering;
- private long mLastReportedTime;
- // since we are expecting only a handful listeners per stream, there is
- // no need for log(N) search performance
- private MediaTimeProvider.OnMediaTimeListener mListeners[];
- private long mTimes[];
- private EventHandler mEventHandler;
- private boolean mRefresh = false;
- private boolean mPausing = false;
- private boolean mSeeking = false;
- private static final int NOTIFY = 1;
- private static final int NOTIFY_TIME = 0;
- private static final int NOTIFY_STOP = 2;
- private static final int NOTIFY_SEEK = 3;
- private static final int NOTIFY_TRACK_DATA = 4;
- private HandlerThread mHandlerThread;
-
- /** @hide */
- public boolean DEBUG = false;
-
- public TimeProvider(MediaPlayer2Impl mp) {
- mPlayer = mp;
- try {
- getCurrentTimeUs(true, false);
- } catch (IllegalStateException e) {
- // we assume starting position
- mRefresh = true;
- }
-
- Looper looper;
- if ((looper = Looper.myLooper()) == null &&
- (looper = Looper.getMainLooper()) == null) {
- // Create our own looper here in case MP was created without one
- mHandlerThread = new HandlerThread("MediaPlayer2MTPEventThread",
- Process.THREAD_PRIORITY_FOREGROUND);
- mHandlerThread.start();
- looper = mHandlerThread.getLooper();
- }
- mEventHandler = new EventHandler(looper);
-
- mListeners = new MediaTimeProvider.OnMediaTimeListener[0];
- mTimes = new long[0];
- mLastTimeUs = 0;
- }
-
- private void scheduleNotification(int type, long delayUs) {
- // ignore time notifications until seek is handled
- if (mSeeking && type == NOTIFY_TIME) {
- return;
- }
-
- if (DEBUG) Log.v(TAG, "scheduleNotification " + type + " in " + delayUs);
- mEventHandler.removeMessages(NOTIFY);
- Message msg = mEventHandler.obtainMessage(NOTIFY, type, 0);
- mEventHandler.sendMessageDelayed(msg, (int) (delayUs / 1000));
- }
-
- /** @hide */
- public void close() {
- mEventHandler.removeMessages(NOTIFY);
- if (mHandlerThread != null) {
- mHandlerThread.quitSafely();
- mHandlerThread = null;
- }
- }
-
- /** @hide */
- protected void finalize() {
- if (mHandlerThread != null) {
- mHandlerThread.quitSafely();
- }
- }
-
- /** @hide */
- public void onNotifyTime() {
- synchronized (this) {
- if (DEBUG) Log.d(TAG, "onNotifyTime: ");
- scheduleNotification(NOTIFY_TIME, 0 /* delay */);
- }
- }
-
- /** @hide */
- public void onPaused(boolean paused) {
- synchronized(this) {
- if (DEBUG) Log.d(TAG, "onPaused: " + paused);
- if (mStopped) { // handle as seek if we were stopped
- mStopped = false;
- mSeeking = true;
- scheduleNotification(NOTIFY_SEEK, 0 /* delay */);
- } else {
- mPausing = paused; // special handling if player disappeared
- mSeeking = false;
- scheduleNotification(NOTIFY_TIME, 0 /* delay */);
- }
- }
- }
-
- /** @hide */
- public void onBuffering(boolean buffering) {
- synchronized (this) {
- if (DEBUG) Log.d(TAG, "onBuffering: " + buffering);
- mBuffering = buffering;
- scheduleNotification(NOTIFY_TIME, 0 /* delay */);
- }
- }
-
- /** @hide */
- public void onStopped() {
- synchronized(this) {
- if (DEBUG) Log.d(TAG, "onStopped");
- mPaused = true;
- mStopped = true;
- mSeeking = false;
- mBuffering = false;
- scheduleNotification(NOTIFY_STOP, 0 /* delay */);
- }
- }
-
- /** @hide */
- public void onSeekComplete(MediaPlayer2Impl mp) {
- synchronized(this) {
- mStopped = false;
- mSeeking = true;
- scheduleNotification(NOTIFY_SEEK, 0 /* delay */);
- }
- }
-
- /** @hide */
- public void onNewPlayer() {
- if (mRefresh) {
- synchronized(this) {
- mStopped = false;
- mSeeking = true;
- mBuffering = false;
- scheduleNotification(NOTIFY_SEEK, 0 /* delay */);
- }
- }
- }
-
- private synchronized void notifySeek() {
- mSeeking = false;
- try {
- long timeUs = getCurrentTimeUs(true, false);
- if (DEBUG) Log.d(TAG, "onSeekComplete at " + timeUs);
-
- for (MediaTimeProvider.OnMediaTimeListener listener: mListeners) {
- if (listener == null) {
- break;
- }
- listener.onSeek(timeUs);
- }
- } catch (IllegalStateException e) {
- // we should not be there, but at least signal pause
- if (DEBUG) Log.d(TAG, "onSeekComplete but no player");
- mPausing = true; // special handling if player disappeared
- notifyTimedEvent(false /* refreshTime */);
- }
- }
-
- private synchronized void notifyTrackData(Pair<SubtitleTrack, byte[]> trackData) {
- SubtitleTrack track = trackData.first;
- byte[] data = trackData.second;
- track.onData(data, true /* eos */, ~0 /* runID: keep forever */);
- }
-
- private synchronized void notifyStop() {
- for (MediaTimeProvider.OnMediaTimeListener listener: mListeners) {
- if (listener == null) {
- break;
- }
- listener.onStop();
- }
- }
-
- private int registerListener(MediaTimeProvider.OnMediaTimeListener listener) {
- int i = 0;
- for (; i < mListeners.length; i++) {
- if (mListeners[i] == listener || mListeners[i] == null) {
- break;
- }
- }
-
- // new listener
- if (i >= mListeners.length) {
- MediaTimeProvider.OnMediaTimeListener[] newListeners =
- new MediaTimeProvider.OnMediaTimeListener[i + 1];
- long[] newTimes = new long[i + 1];
- System.arraycopy(mListeners, 0, newListeners, 0, mListeners.length);
- System.arraycopy(mTimes, 0, newTimes, 0, mTimes.length);
- mListeners = newListeners;
- mTimes = newTimes;
- }
-
- if (mListeners[i] == null) {
- mListeners[i] = listener;
- mTimes[i] = MediaTimeProvider.NO_TIME;
- }
- return i;
- }
-
- public void notifyAt(
- long timeUs, MediaTimeProvider.OnMediaTimeListener listener) {
- synchronized(this) {
- if (DEBUG) Log.d(TAG, "notifyAt " + timeUs);
- mTimes[registerListener(listener)] = timeUs;
- scheduleNotification(NOTIFY_TIME, 0 /* delay */);
- }
- }
-
- public void scheduleUpdate(MediaTimeProvider.OnMediaTimeListener listener) {
- synchronized(this) {
- if (DEBUG) Log.d(TAG, "scheduleUpdate");
- int i = registerListener(listener);
-
- if (!mStopped) {
- mTimes[i] = 0;
- scheduleNotification(NOTIFY_TIME, 0 /* delay */);
- }
- }
- }
-
- public void cancelNotifications(
- MediaTimeProvider.OnMediaTimeListener listener) {
- synchronized(this) {
- int i = 0;
- for (; i < mListeners.length; i++) {
- if (mListeners[i] == listener) {
- System.arraycopy(mListeners, i + 1,
- mListeners, i, mListeners.length - i - 1);
- System.arraycopy(mTimes, i + 1,
- mTimes, i, mTimes.length - i - 1);
- mListeners[mListeners.length - 1] = null;
- mTimes[mTimes.length - 1] = NO_TIME;
- break;
- } else if (mListeners[i] == null) {
- break;
- }
- }
-
- scheduleNotification(NOTIFY_TIME, 0 /* delay */);
- }
- }
-
- private synchronized void notifyTimedEvent(boolean refreshTime) {
- // figure out next callback
- long nowUs;
- try {
- nowUs = getCurrentTimeUs(refreshTime, true);
- } catch (IllegalStateException e) {
- // assume we paused until new player arrives
- mRefresh = true;
- mPausing = true; // this ensures that call succeeds
- nowUs = getCurrentTimeUs(refreshTime, true);
- }
- long nextTimeUs = nowUs;
-
- if (mSeeking) {
- // skip timed-event notifications until seek is complete
- return;
- }
-
- if (DEBUG) {
- StringBuilder sb = new StringBuilder();
- sb.append("notifyTimedEvent(").append(mLastTimeUs).append(" -> ")
- .append(nowUs).append(") from {");
- boolean first = true;
- for (long time: mTimes) {
- if (time == NO_TIME) {
- continue;
- }
- if (!first) sb.append(", ");
- sb.append(time);
- first = false;
- }
- sb.append("}");
- Log.d(TAG, sb.toString());
- }
-
- Vector<MediaTimeProvider.OnMediaTimeListener> activatedListeners =
- new Vector<MediaTimeProvider.OnMediaTimeListener>();
- for (int ix = 0; ix < mTimes.length; ix++) {
- if (mListeners[ix] == null) {
- break;
- }
- if (mTimes[ix] <= NO_TIME) {
- // ignore, unless we were stopped
- } else if (mTimes[ix] <= nowUs + MAX_EARLY_CALLBACK_US) {
- activatedListeners.add(mListeners[ix]);
- if (DEBUG) Log.d(TAG, "removed");
- mTimes[ix] = NO_TIME;
- } else if (nextTimeUs == nowUs || mTimes[ix] < nextTimeUs) {
- nextTimeUs = mTimes[ix];
- }
- }
-
- if (nextTimeUs > nowUs && !mPaused) {
- // schedule callback at nextTimeUs
- if (DEBUG) Log.d(TAG, "scheduling for " + nextTimeUs + " and " + nowUs);
- mPlayer.notifyAt(nextTimeUs);
- } else {
- mEventHandler.removeMessages(NOTIFY);
- // no more callbacks
- }
-
- for (MediaTimeProvider.OnMediaTimeListener listener: activatedListeners) {
- listener.onTimedEvent(nowUs);
- }
- }
-
- public long getCurrentTimeUs(boolean refreshTime, boolean monotonic)
- throws IllegalStateException {
- synchronized (this) {
- // we always refresh the time when the paused-state changes, because
- // we expect to have received the pause-change event delayed.
- if (mPaused && !refreshTime) {
- return mLastReportedTime;
- }
-
- try {
- mLastTimeUs = mPlayer.getCurrentPosition() * 1000L;
- mPaused = !mPlayer.isPlaying() || mBuffering;
- if (DEBUG) Log.v(TAG, (mPaused ? "paused" : "playing") + " at " + mLastTimeUs);
- } catch (IllegalStateException e) {
- if (mPausing) {
- // if we were pausing, get last estimated timestamp
- mPausing = false;
- if (!monotonic || mLastReportedTime < mLastTimeUs) {
- mLastReportedTime = mLastTimeUs;
- }
- mPaused = true;
- if (DEBUG) Log.d(TAG, "illegal state, but pausing: estimating at " + mLastReportedTime);
- return mLastReportedTime;
- }
- // TODO get time when prepared
- throw e;
- }
- if (monotonic && mLastTimeUs < mLastReportedTime) {
- /* have to adjust time */
- if (mLastReportedTime - mLastTimeUs > 1000000) {
- // schedule seeked event if time jumped significantly
- // TODO: do this properly by introducing an exception
- mStopped = false;
- mSeeking = true;
- scheduleNotification(NOTIFY_SEEK, 0 /* delay */);
- }
- } else {
- mLastReportedTime = mLastTimeUs;
- }
-
- return mLastReportedTime;
- }
- }
-
- private class EventHandler extends Handler {
- public EventHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- if (msg.what == NOTIFY) {
- switch (msg.arg1) {
- case NOTIFY_TIME:
- notifyTimedEvent(true /* refreshTime */);
- break;
- case NOTIFY_STOP:
- notifyStop();
- break;
- case NOTIFY_SEEK:
- notifySeek();
- break;
- case NOTIFY_TRACK_DATA:
- notifyTrackData((Pair<SubtitleTrack, byte[]>)msg.obj);
- break;
- }
- }
- }
- }
- }
-
private abstract class Task implements Runnable {
private final int mMediaCallType;
private final boolean mNeedToWaitForEventToComplete;
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index 693a3d0b23df..b52da362beff 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -769,18 +769,6 @@ android_media_MediaPlayer2_seekTo(JNIEnv *env, jobject thiz, jlong msec, jint mo
NULL, NULL);
}
-static void
-android_media_MediaPlayer2_notifyAt(JNIEnv *env, jobject thiz, jlong mediaTimeUs)
-{
- sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
- if (mp == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
- return;
- }
- ALOGV("notifyAt: %lld", (long long)mediaTimeUs);
- process_media_player_call( env, thiz, mp->notifyAt((int64_t)mediaTimeUs), NULL, NULL );
-}
-
static jint
android_media_MediaPlayer2_getState(JNIEnv *env, jobject thiz)
{
@@ -1482,7 +1470,6 @@ static const JNINativeMethod gMethods[] = {
{"_setSyncParams", "(Landroid/media/SyncParams;)V", (void *)android_media_MediaPlayer2_setSyncParams},
{"getSyncParams", "()Landroid/media/SyncParams;", (void *)android_media_MediaPlayer2_getSyncParams},
{"_seekTo", "(JI)V", (void *)android_media_MediaPlayer2_seekTo},
- {"_notifyAt", "(J)V", (void *)android_media_MediaPlayer2_notifyAt},
{"_pause", "()V", (void *)android_media_MediaPlayer2_pause},
{"isPlaying", "()Z", (void *)android_media_MediaPlayer2_isPlaying},
{"getCurrentPosition", "()J", (void *)android_media_MediaPlayer2_getCurrentPosition},