diff options
Diffstat (limited to 'media')
-rw-r--r-- | media/java/android/media/AudioDeviceInfo.java | 39 | ||||
-rw-r--r-- | media/java/android/media/Image.java | 39 | ||||
-rw-r--r-- | media/java/android/media/ImageReader.java | 123 | ||||
-rw-r--r-- | media/java/android/media/ImageUtils.java | 16 | ||||
-rw-r--r-- | media/java/android/media/ImageWriter.java | 93 | ||||
-rw-r--r-- | media/java/android/media/MediaDataSource.java | 21 | ||||
-rw-r--r-- | media/java/android/media/MediaPlayer.java | 34 | ||||
-rw-r--r-- | media/java/android/media/MediaSync.java | 118 | ||||
-rw-r--r-- | media/java/android/media/MediaTimestamp.java | 24 | ||||
-rw-r--r-- | media/java/android/media/tv/DvbDeviceInfo.aidl | 20 | ||||
-rw-r--r-- | media/java/android/media/tv/DvbDeviceInfo.java | 97 | ||||
-rw-r--r-- | media/java/android/media/tv/ITvInputManager.aidl | 6 | ||||
-rw-r--r-- | media/java/android/media/tv/TvInputManager.java | 59 | ||||
-rw-r--r-- | media/jni/android_media_ImageReader.cpp | 18 | ||||
-rw-r--r-- | media/jni/android_media_MediaDataSource.cpp | 15 | ||||
-rw-r--r-- | media/jni/android_media_MediaExtractor.cpp | 5 | ||||
-rw-r--r-- | media/jni/soundpool/SoundPool.cpp | 8 |
17 files changed, 418 insertions, 317 deletions
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java index 566f8dc..0384d40 100644 --- a/media/java/android/media/AudioDeviceInfo.java +++ b/media/java/android/media/AudioDeviceInfo.java @@ -16,6 +16,7 @@ package android.media; +import android.annotation.NonNull; import android.util.SparseIntArray; /** @@ -121,8 +122,9 @@ public final class AudioDeviceInfo { /** * @return The human-readable name of the audio device. */ - public CharSequence getName() { - return mPort.name(); + public CharSequence getProductName() { + String portName = mPort.name(); + return portName.length() != 0 ? portName : android.os.Build.MODEL; } /** @@ -151,27 +153,38 @@ public final class AudioDeviceInfo { /** * @return An array of sample rates supported by the audio device. */ - public int[] getSampleRates() { + public @NonNull int[] getSampleRates() { return mPort.samplingRates(); } /** - * @return An array of channel masks ({@link AudioFormat#CHANNEL_IN_STEREO}, - * {@link AudioFormat#CHANNEL_OUT_7POINT1) for which this audio device can be configured. + * @return An array of channel position masks (e.g. {@link AudioFormat#CHANNEL_IN_STEREO}, + * {@link AudioFormat#CHANNEL_OUT_7POINT1}) for which this audio device can be configured. * * @see AudioFormat */ - public int[] getChannelMasks() { + public @NonNull int[] getChannelMasks() { return mPort.channelMasks(); } /** - * @return An array of channel counts (1, 2, 4....) for which this audio device + * @return An array of channel index masks for which this audio device can be configured. + * + * @see AudioFormat + */ + public @NonNull int[] getChannelIndexMasks() { + // TODO: implement + return new int[0]; + } + + /** + * @return An array of channel counts (1, 2, 4, ...) for which this audio device * can be configured. */ - public int[] getChannelCounts() { + public @NonNull int[] getChannelCounts() { int[] masks = getChannelMasks(); int[] counts = new int[masks.length]; + // TODO: consider channel index masks for (int mask_index = 0; mask_index < masks.length; mask_index++) { counts[mask_index] = isSink() ? AudioFormat.channelCountFromOutChannelMask(masks[mask_index]) @@ -181,12 +194,16 @@ public final class AudioDeviceInfo { } /** - * @return An array of audio format IDs (@link AudioFormat#ENCODING_PCM_16BIT, - * {@link AudioFormat#ENCODING_PCM_FLOAT}...) supported by the audio device. + * @return An array of audio encodings (e.g. {@link AudioFormat#ENCODING_PCM_16BIT}, + * {@link AudioFormat#ENCODING_PCM_FLOAT}) supported by the audio device. + * <code>ENCODING_PCM_FLOAT</code> indicates the device supports more + * than 16 bits of integer precision. Specifying <code>ENCODING_PCM_FLOAT</code> + * with {@link AudioTrack} or {@link AudioRecord} can preserve at least 24 bits of + * integer precision to that device. * * @see AudioFormat */ - public int[] getFormats() { + public @NonNull int[] getFormats() { return mPort.formats(); } diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java index 195c987..e18e9a3 100644 --- a/media/java/android/media/Image.java +++ b/media/java/android/media/Image.java @@ -163,10 +163,12 @@ public abstract class Image implements AutoCloseable { * Get the timestamp associated with this frame. * <p> * The timestamp is measured in nanoseconds, and is normally monotonically - * increasing. However, the behavior of the timestamp depends on the source - * of this image. See {@link android.hardware.Camera Camera}, - * {@link android.hardware.camera2.CameraDevice CameraDevice}, {@link MediaPlayer} and - * {@link MediaCodec} for more details. + * increasing. The timestamps for the images from different sources may have + * different timebases therefore may not be comparable. The specific meaning and + * timebase of the timestamp depend on the source providing images. See + * {@link android.hardware.Camera Camera}, + * {@link android.hardware.camera2.CameraDevice CameraDevice}, + * {@link MediaPlayer} and {@link MediaCodec} for more details. * </p> */ public abstract long getTimestamp(); @@ -175,9 +177,11 @@ public abstract class Image implements AutoCloseable { * Set the timestamp associated with this frame. * <p> * The timestamp is measured in nanoseconds, and is normally monotonically - * increasing. However, the behavior of the timestamp depends on - * the destination of this image. See {@link android.hardware.Camera Camera} - * , {@link android.hardware.camera2.CameraDevice CameraDevice}, + * increasing. The timestamps for the images from different sources may have + * different timebases therefore may not be comparable. The specific meaning and + * timebase of the timestamp depend on the source providing images. See + * {@link android.hardware.Camera Camera}, + * {@link android.hardware.camera2.CameraDevice CameraDevice}, * {@link MediaPlayer} and {@link MediaCodec} for more details. * </p> * <p> @@ -195,18 +199,6 @@ public abstract class Image implements AutoCloseable { return; } - /** - * <p>Check if the image is opaque.</p> - * - * <p>The pixel data of opaque images are not accessible to the application, - * and therefore {@link #getPlanes} will return an empty array for an opaque image. - * </p> - */ - public boolean isOpaque() { - throwISEIfImageIsInvalid(); - return false; - } - private Rect mCropRect; /** @@ -243,10 +235,11 @@ public abstract class Image implements AutoCloseable { /** * Get the array of pixel planes for this Image. The number of planes is - * determined by the format of the Image. The application will get an - * empty array if the image is opaque because the opaque image pixel data - * is not directly accessible. The application can check if an image is - * opaque by calling {@link Image#isOpaque}. + * determined by the format of the Image. The application will get an empty + * array if the image format is {@link android.graphics.ImageFormat#PRIVATE + * PRIVATE}, because the image pixel data is not directly accessible. The + * application can check the image format by calling + * {@link Image#getFormat()}. */ public abstract Plane[] getPlanes(); diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java index 6d30208..9bd721a 100644 --- a/media/java/android/media/ImageReader.java +++ b/media/java/android/media/ImageReader.java @@ -68,76 +68,45 @@ public class ImageReader implements AutoCloseable { private static final int ACQUIRE_MAX_IMAGES = 2; /** - * <p>Create a new reader for images of the desired size and format.</p> - * - * <p>The {@code maxImages} parameter determines the maximum number of {@link Image} - * objects that can be be acquired from the {@code ImageReader} - * simultaneously. Requesting more buffers will use up more memory, so it is - * important to use only the minimum number necessary for the use case.</p> - * - * <p>The valid sizes and formats depend on the source of the image - * data.</p> - * - * @param width - * The default width in pixels of the Images that this reader will produce. - * @param height - * The default height in pixels of the Images that this reader will produce. - * @param format - * The format of the Image that this reader will produce. This - * must be one of the {@link android.graphics.ImageFormat} or - * {@link android.graphics.PixelFormat} constants. Note that - * not all formats is supported, like ImageFormat.NV21. - * @param maxImages - * The maximum number of images the user will want to - * access simultaneously. This should be as small as possible to limit - * memory use. Once maxImages Images are obtained by the user, one of them - * has to be released before a new Image will become available for access - * through {@link #acquireLatestImage()} or {@link #acquireNextImage()}. - * Must be greater than 0. - * - * @see Image - */ - public static ImageReader newInstance(int width, int height, int format, int maxImages) { - if (format == ImageFormat.PRIVATE) { - throw new IllegalArgumentException("To obtain an opaque ImageReader, please use" - + " newOpaqueInstance rather than newInstance"); - } - return new ImageReader(width, height, format, maxImages); - } - - /** - * <p> - * Create a new opaque reader for images of the desired size. - * </p> * <p> - * An opaque {@link ImageReader} produces images that are not directly - * accessible by the application. The application can still acquire images - * from an opaque image reader, and send them to the - * {@link android.hardware.camera2.CameraDevice camera} for reprocessing via - * {@link ImageWriter} interface. However, the {@link Image#getPlanes() - * getPlanes()} will return an empty array for opaque images. The - * application can check if an existing reader is an opaque reader by - * calling {@link #isOpaque()}. + * Create a new reader for images of the desired size and format. * </p> * <p> * The {@code maxImages} parameter determines the maximum number of * {@link Image} objects that can be be acquired from the * {@code ImageReader} simultaneously. Requesting more buffers will use up - * more memory, so it is important to use only the minimum number necessary. + * more memory, so it is important to use only the minimum number necessary + * for the use case. * </p> * <p> * The valid sizes and formats depend on the source of the image data. * </p> * <p> - * Opaque ImageReaders are more efficient to use when application access to - * image data is not necessary, compared to ImageReaders using a non-opaque - * format such as {@link ImageFormat#YUV_420_888 YUV_420_888}. + * If the {@code format} is {@link ImageFormat#PRIVATE PRIVATE}, the created + * {@link ImageReader} will produce images that are not directly accessible + * by the application. The application can still acquire images from this + * {@link ImageReader}, and send them to the + * {@link android.hardware.camera2.CameraDevice camera} for reprocessing via + * {@link ImageWriter} interface. However, the {@link Image#getPlanes() + * getPlanes()} will return an empty array for {@link ImageFormat#PRIVATE + * PRIVATE} format images. The application can check if an existing reader's + * format by calling {@link #getImageFormat()}. + * </p> + * <p> + * {@link ImageFormat#PRIVATE PRIVATE} format {@link ImageReader + * ImageReaders} are more efficient to use when application access to image + * data is not necessary, compared to ImageReaders using other format such + * as {@link ImageFormat#YUV_420_888 YUV_420_888}. * </p> * * @param width The default width in pixels of the Images that this reader * will produce. * @param height The default height in pixels of the Images that this reader * will produce. + * @param format The format of the Image that this reader will produce. This + * must be one of the {@link android.graphics.ImageFormat} or + * {@link android.graphics.PixelFormat} constants. Note that not + * all formats are supported, like ImageFormat.NV21. * @param maxImages The maximum number of images the user will want to * access simultaneously. This should be as small as possible to * limit memory use. Once maxImages Images are obtained by the @@ -147,8 +116,8 @@ public class ImageReader implements AutoCloseable { * Must be greater than 0. * @see Image */ - public static ImageReader newOpaqueInstance(int width, int height, int maxImages) { - return new ImageReader(width, height, ImageFormat.PRIVATE, maxImages); + public static ImageReader newInstance(int width, int height, int format, int maxImages) { + return new ImageReader(width, height, format, maxImages); } /** @@ -248,23 +217,6 @@ public class ImageReader implements AutoCloseable { } /** - * <p> - * Check if the {@link ImageReader} is an opaque reader. - * </p> - * <p> - * An opaque image reader produces opaque images, see {@link Image#isOpaque} - * for more details. - * </p> - * - * @return true if the ImageReader is opaque. - * @see Image#isOpaque - * @see ImageReader#newOpaqueInstance - */ - public boolean isOpaque() { - return mFormat == ImageFormat.PRIVATE; - } - - /** * <p>Get a {@link Surface} that can be used to produce {@link Image Images} for this * {@code ImageReader}.</p> * @@ -540,11 +492,11 @@ public class ImageReader implements AutoCloseable { * </p> * <p> * This method can be used to achieve zero buffer copy for use cases like - * {@link android.hardware.camera2.CameraDevice Camera2 API} OPAQUE and YUV + * {@link android.hardware.camera2.CameraDevice Camera2 API} PRIVATE and YUV * reprocessing, where the application can select an output image from * {@link ImageReader} and transfer this image directly to * {@link ImageWriter}, where this image can be consumed by camera directly. - * For OPAQUE reprocessing, this is the only way to send input buffers to + * For PRIVATE reprocessing, this is the only way to send input buffers to * the {@link android.hardware.camera2.CameraDevice camera} for * reprocessing. * </p> @@ -703,26 +655,26 @@ public class ImageReader implements AutoCloseable { @Override public int getFormat() { throwISEIfImageIsInvalid(); + int readerFormat = ImageReader.this.getImageFormat(); + // Assume opaque reader always produce opaque images. + mFormat = (readerFormat == ImageFormat.PRIVATE) ? readerFormat : + nativeGetFormat(readerFormat); return mFormat; } @Override public int getWidth() { throwISEIfImageIsInvalid(); - if (mWidth == -1) { - mWidth = (getFormat() == ImageFormat.JPEG) ? ImageReader.this.getWidth() : - nativeGetWidth(mFormat); - } + mWidth = (getFormat() == ImageFormat.JPEG) ? ImageReader.this.getWidth() : + nativeGetWidth(mFormat); return mWidth; } @Override public int getHeight() { throwISEIfImageIsInvalid(); - if (mHeight == -1) { - mHeight = (getFormat() == ImageFormat.JPEG) ? ImageReader.this.getHeight() : - nativeGetHeight(mFormat); - } + mHeight = (getFormat() == ImageFormat.JPEG) ? ImageReader.this.getHeight() : + nativeGetHeight(mFormat); return mHeight; } @@ -746,12 +698,6 @@ public class ImageReader implements AutoCloseable { } @Override - public boolean isOpaque() { - throwISEIfImageIsInvalid(); - return mFormat == ImageFormat.PRIVATE; - } - - @Override protected final void finalize() throws Throwable { try { close(); @@ -876,6 +822,7 @@ public class ImageReader implements AutoCloseable { private synchronized native SurfacePlane nativeCreatePlane(int idx, int readerFormat); private synchronized native int nativeGetWidth(int format); private synchronized native int nativeGetHeight(int format); + private synchronized native int nativeGetFormat(int readerFormat); } private synchronized native void nativeInit(Object weakSelf, int w, int h, diff --git a/media/java/android/media/ImageUtils.java b/media/java/android/media/ImageUtils.java index 89313bf..c312525 100644 --- a/media/java/android/media/ImageUtils.java +++ b/media/java/android/media/ImageUtils.java @@ -57,7 +57,7 @@ class ImageUtils { case ImageFormat.RAW_SENSOR: case ImageFormat.RAW10: return 1; - case PixelFormat.OPAQUE: + case ImageFormat.PRIVATE: return 0; default: throw new UnsupportedOperationException( @@ -70,10 +70,11 @@ class ImageUtils { * Copy source image data to destination Image. * </p> * <p> - * Only support the copy between two non-opaque images with same properties - * (format, size, etc.). The data from the source image will be copied to - * the byteBuffers from the destination Image starting from position zero, - * and the destination image will be rewound to zero after copy is done. + * Only support the copy between two non-{@link ImageFormat#PRIVATE PRIVATE} format + * images with same properties (format, size, etc.). The data from the + * source image will be copied to the byteBuffers from the destination Image + * starting from position zero, and the destination image will be rewound to + * zero after copy is done. * </p> * * @param src The source image to be copied from. @@ -88,8 +89,9 @@ class ImageUtils { if (src.getFormat() != dst.getFormat()) { throw new IllegalArgumentException("Src and dst images should have the same format"); } - if (src.isOpaque() || dst.isOpaque()) { - throw new IllegalArgumentException("Opaque image is not copyable"); + if (src.getFormat() == ImageFormat.PRIVATE || + dst.getFormat() == ImageFormat.PRIVATE) { + throw new IllegalArgumentException("PRIVATE format images are not copyable"); } if (!(dst.getOwner() instanceof ImageWriter)) { throw new IllegalArgumentException("Destination image is not from ImageWriter. Only" diff --git a/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java index f805339..2ef2519 100644 --- a/media/java/android/media/ImageWriter.java +++ b/media/java/android/media/ImageWriter.java @@ -33,8 +33,8 @@ import java.util.List; /** * <p> * The ImageWriter class allows an application to produce Image data into a - * {@link android.view.Surface}, and have it be consumed by another component like - * {@link android.hardware.camera2.CameraDevice CameraDevice}. + * {@link android.view.Surface}, and have it be consumed by another component + * like {@link android.hardware.camera2.CameraDevice CameraDevice}. * </p> * <p> * Several Android API classes can provide input {@link android.view.Surface @@ -54,21 +54,21 @@ import java.util.List; * <p> * If the application already has an Image from {@link ImageReader}, the * application can directly queue this Image into ImageWriter (via - * {@link #queueInputImage}), potentially with zero buffer copies. For the opaque - * Images produced by an opaque ImageReader (created by - * {@link ImageReader#newOpaqueInstance}), this is the only way to send Image - * data to ImageWriter, as the Image data aren't accessible by the application. + * {@link #queueInputImage}), potentially with zero buffer copies. For the + * {@link ImageFormat#PRIVATE PRIVATE} format Images produced by + * {@link ImageReader}, this is the only way to send Image data to ImageWriter, + * as the Image data aren't accessible by the application. * </p> - * Once new input Images are queued into an ImageWriter, it's up to the downstream - * components (e.g. {@link ImageReader} or + * Once new input Images are queued into an ImageWriter, it's up to the + * downstream components (e.g. {@link ImageReader} or * {@link android.hardware.camera2.CameraDevice}) to consume the Images. If the * downstream components cannot consume the Images at least as fast as the - * ImageWriter production rate, the {@link #dequeueInputImage} call will eventually - * block and the application will have to drop input frames. </p> + * ImageWriter production rate, the {@link #dequeueInputImage} call will + * eventually block and the application will have to drop input frames. </p> */ public class ImageWriter implements AutoCloseable { private final Object mListenerLock = new Object(); - private ImageListener mListener; + private OnImageReleasedListener mListener; private ListenerHandler mListenerHandler; private long mNativeContext; @@ -168,32 +168,34 @@ public class ImageWriter implements AutoCloseable { * This call will block if all available input images have been queued by * the application and the downstream consumer has not yet consumed any. * When an Image is consumed by the downstream consumer and released, an - * {@link ImageListener#onInputImageReleased} callback will be fired, which - * indicates that there is one input Image available. For non-opaque formats - * (({@link ImageWriter#getFormat()} != {@link ImageFormat#PRIVATE})), it is + * {@link OnImageReleasedListener#onImageReleased} callback will be fired, + * which indicates that there is one input Image available. For non- + * {@link ImageFormat#PRIVATE PRIVATE} formats ( + * {@link ImageWriter#getFormat()} != {@link ImageFormat#PRIVATE}), it is * recommended to dequeue the next Image only after this callback is fired, * in the steady state. * </p> * <p> - * If the ImageWriter is opaque ({@link ImageWriter#getFormat()} == - * {@link ImageFormat#PRIVATE}), the image buffer is inaccessible to - * the application, and calling this method will result in an - * {@link IllegalStateException}. Instead, the application should acquire - * opaque images from some other component (e.g. an opaque + * If the format of ImageWriter is {@link ImageFormat#PRIVATE PRIVATE} ( + * {@link ImageWriter#getFormat()} == {@link ImageFormat#PRIVATE}), the + * image buffer is inaccessible to the application, and calling this method + * will result in an {@link IllegalStateException}. Instead, the application + * should acquire images from some other component (e.g. an * {@link ImageReader}), and queue them directly to this ImageWriter via the * {@link ImageWriter#queueInputImage queueInputImage()} method. * </p> * * @return The next available input Image from this ImageWriter. * @throws IllegalStateException if {@code maxImages} Images are currently - * dequeued, or the ImageWriter is opaque. + * dequeued, or the ImageWriter format is + * {@link ImageFormat#PRIVATE PRIVATE}. * @see #queueInputImage * @see Image#close */ public Image dequeueInputImage() { if (mWriterFormat == ImageFormat.PRIVATE) { throw new IllegalStateException( - "Opaque ImageWriter doesn't support this operation since opaque images are" + "PRIVATE format ImageWriter doesn't support this operation since the images are" + " inaccessible to the application!"); } @@ -229,10 +231,10 @@ public class ImageWriter implements AutoCloseable { * </p> * <p> * After this method is called and the downstream consumer consumes and - * releases the Image, an {@link ImageListener#onInputImageReleased - * onInputImageReleased()} callback will fire. The application can use this - * callback to avoid sending Images faster than the downstream consumer - * processing rate in steady state. + * releases the Image, an {@link OnImageReleasedListener#onImageReleased} + * callback will fire. The application can use this callback to avoid + * sending Images faster than the downstream consumer processing rate in + * steady state. * </p> * <p> * Passing in an Image from some other component (e.g. an @@ -271,12 +273,12 @@ public class ImageWriter implements AutoCloseable { } ImageReader prevOwner = (ImageReader) image.getOwner(); - // Only do the image attach for opaque images for now. Do the image + // Only do the image attach for PRIVATE format images for now. Do the image // copy for other formats. TODO: use attach for other formats to // improve the performance, and fall back to copy when attach/detach // fails. Right now, detach is guaranteed to fail as the buffer is // locked when ImageReader#acquireNextImage is called. See bug 19962027. - if (image.isOpaque()) { + if (image.getFormat() == ImageFormat.PRIVATE) { prevOwner.detachImage(image); attachAndQueueInputImage(image); // This clears the native reference held by the original owner. @@ -319,8 +321,9 @@ public class ImageWriter implements AutoCloseable { * Get the ImageWriter format. * <p> * This format may be different than the Image format returned by - * {@link Image#getFormat()}. However, if the ImageWriter is opaque (format - * == {@link ImageFormat#PRIVATE}) , the images from it will also be opaque. + * {@link Image#getFormat()}. However, if the ImageWriter format is + * {@link ImageFormat#PRIVATE PRIVATE}, calling {@link #dequeueInputImage()} + * will result in an {@link IllegalStateException}. * </p> * * @return The ImageWriter format. @@ -333,7 +336,7 @@ public class ImageWriter implements AutoCloseable { * ImageWriter callback interface, used to to asynchronously notify the * application of various ImageWriter events. */ - public interface ImageListener { + public interface OnImageReleasedListener { /** * <p> * Callback that is called when an input Image is released back to @@ -361,7 +364,7 @@ public class ImageWriter implements AutoCloseable { * @see ImageWriter * @see Image */ - void onInputImageReleased(ImageWriter writer); + void onImageReleased(ImageWriter writer); } /** @@ -375,7 +378,7 @@ public class ImageWriter implements AutoCloseable { * @throws IllegalArgumentException If no handler specified and the calling * thread has no looper. */ - public void setImageListener(ImageListener listener, Handler handler) { + public void setOnImageReleasedListener(OnImageReleasedListener listener, Handler handler) { synchronized (mListenerLock) { if (listener != null) { Looper looper = handler != null ? handler.getLooper() : Looper.myLooper(); @@ -408,7 +411,7 @@ public class ImageWriter implements AutoCloseable { */ @Override public void close() { - setImageListener(null, null); + setOnImageReleasedListener(null, null); for (Image image : mDequeuedImages) { image.close(); } @@ -431,19 +434,18 @@ public class ImageWriter implements AutoCloseable { * Attach and queue input Image to this ImageWriter. * </p> * <p> - * When an Image is from an opaque source (e.g. an opaque ImageReader - * created by {@link ImageReader#newOpaqueInstance}), or the source Image is - * so large that copying its data is too expensive, this method can be used - * to migrate the source Image into ImageWriter without a data copy, and - * then queue it to this ImageWriter. The source Image must be detached from - * its previous owner already, or this call will throw an + * When the format of an Image is {@link ImageFormat#PRIVATE PRIVATE}, or + * the source Image is so large that copying its data is too expensive, this + * method can be used to migrate the source Image into ImageWriter without a + * data copy, and then queue it to this ImageWriter. The source Image must + * be detached from its previous owner already, or this call will throw an * {@link IllegalStateException}. * </p> * <p> * After this call, the ImageWriter takes ownership of this Image. This * ownership will automatically be removed from this writer after the * consumer releases this Image, that is, after - * {@link ImageListener#onInputImageReleased}. The caller is responsible for + * {@link OnImageReleasedListener#onImageReleased}. The caller is responsible for * closing this Image through {@link Image#close()} to free up the resources * held by this Image. * </p> @@ -492,12 +494,12 @@ public class ImageWriter implements AutoCloseable { @Override public void handleMessage(Message msg) { - ImageListener listener; + OnImageReleasedListener listener; synchronized (mListenerLock) { listener = mListener; } if (listener != null) { - listener.onInputImageReleased(ImageWriter.this); + listener.onImageReleased(ImageWriter.this); } } } @@ -647,13 +649,6 @@ public class ImageWriter implements AutoCloseable { } @Override - public boolean isOpaque() { - throwISEIfImageIsInvalid(); - - return getFormat() == ImageFormat.PRIVATE; - } - - @Override public Plane[] getPlanes() { throwISEIfImageIsInvalid(); diff --git a/media/java/android/media/MediaDataSource.java b/media/java/android/media/MediaDataSource.java index 246c0ef..948da0b 100644 --- a/media/java/android/media/MediaDataSource.java +++ b/media/java/android/media/MediaDataSource.java @@ -18,6 +18,7 @@ package android.media; import java.io.Closeable; +import java.io.IOException; /** * For supplying media data to the framework. Implement this if your app has @@ -29,34 +30,32 @@ import java.io.Closeable; * you don't need to do your own synchronization unless you're modifying the * MediaDataSource from another thread while it's being used by the framework.</p> */ -public interface MediaDataSource extends Closeable { +public abstract class MediaDataSource implements Closeable { /** * Called to request data from the given position. * * Implementations should should write up to {@code size} bytes into * {@code buffer}, and return the number of bytes written. * - * Return {@code 0} to indicate that {@code position} is at, or beyond, the - * end of the source. + * Return {@code 0} if size is zero (thus no bytes are read). * - * Return {@code -1} to indicate that a fatal error occurred. The failed - * read will not be retried, so transient errors should be handled - * internally. - * - * Throwing an exception from this method will have the same effect as - * returning {@code -1}. + * Return {@code -1} to indicate that end of stream is reached. * * @param position the position in the data source to read from. * @param buffer the buffer to read the data into. + * @param offset the offset within buffer to read the data into. * @param size the number of bytes to read. + * @throws IOException on fatal errors. * @return the number of bytes read, or -1 if there was an error. */ - public int readAt(long position, byte[] buffer, int size); + public abstract int readAt(long position, byte[] buffer, int offset, int size) + throws IOException; /** * Called to get the size of the data source. * + * @throws IOException on fatal errors * @return the size of data source in bytes, or -1 if the size is unknown. */ - public long getSize(); + public abstract long getSize() throws IOException; } diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 256ab29..e3a6a83 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -1360,6 +1360,8 @@ public class MediaPlayer implements SubtitleController.Listener * frequency. * When rate is larger than 1.0, pitch becomes higher. * When rate is smaller than 1.0, pitch becomes lower. + * + * @hide */ public static final int PLAYBACK_RATE_AUDIO_MODE_RESAMPLE = 2; @@ -1372,6 +1374,8 @@ public class MediaPlayer implements SubtitleController.Listener * <p> * This mode is only supported for a limited range of playback speed factors, * e.g. between 1/2x and 2x. + * + * @hide */ public static final int PLAYBACK_RATE_AUDIO_MODE_STRETCH = 1; @@ -1383,6 +1387,8 @@ public class MediaPlayer implements SubtitleController.Listener * Try to keep audio pitch when changing the playback rate, but allow the * system to determine how to change audio playback if the rate is out * of range. + * + * @hide */ public static final int PLAYBACK_RATE_AUDIO_MODE_DEFAULT = 0; @@ -1406,8 +1412,11 @@ public class MediaPlayer implements SubtitleController.Listener * @throws IllegalStateException if the internal player engine has not been * initialized. * @throws IllegalArgumentException if audioMode is not supported. + * + * @hide */ - public void setPlaybackRate(float rate, @PlaybackRateAudioMode int audioMode) { + @NonNull + public PlaybackParams easyPlaybackParams(float rate, @PlaybackRateAudioMode int audioMode) { PlaybackParams params = new PlaybackParams(); params.allowDefaults(); switch (audioMode) { @@ -1425,7 +1434,7 @@ public class MediaPlayer implements SubtitleController.Listener final String msg = "Audio playback mode " + audioMode + " is not supported"; throw new IllegalArgumentException(msg); } - setPlaybackParams(params); + return params; } /** @@ -1481,23 +1490,22 @@ public class MediaPlayer implements SubtitleController.Listener public native void seekTo(int msec) throws IllegalStateException; /** - * Get current playback position. + * Get current playback position as a {@link MediaTimestamp}. * <p> * The MediaTimestamp represents how the media time correlates to the system time in - * a linear fashion. It contains the media time and system timestamp of an anchor frame - * ({@link MediaTimestamp#mediaTimeUs} and {@link MediaTimestamp#nanoTime}) - * and the speed of the media clock ({@link MediaTimestamp#clockRate}). + * a linear fashion using an anchor and a clock rate. During regular playback, the media + * time moves fairly constantly (though the anchor frame may be rebased to a current + * system time, the linear correlation stays steady). Therefore, this method does not + * need to be called often. * <p> - * During regular playback, the media time moves fairly constantly (though the - * anchor frame may be rebased to a current system time, the linear correlation stays - * steady). Therefore, this method does not need to be called often. - * <p> - * To help users to get current playback position, this method always returns the timestamp of - * just-rendered frame, i.e., {@link System#nanoTime} and its corresponding media time. They - * can be used as current playback position. + * To help users get current playback position, this method always anchors the timestamp + * to the current {@link System#nanoTime system time}, so + * {@link MediaTimestamp#getAnchorMediaTimeUs} can be used as current playback position. * * @return a MediaTimestamp object if a timestamp is available, or {@code null} if no timestamp * is available, e.g. because the media player has not been initialized. + * + * @see MediaTimestamp */ @Nullable public MediaTimestamp getTimestamp() diff --git a/media/java/android/media/MediaSync.java b/media/java/android/media/MediaSync.java index d9e554c..b07931d 100644 --- a/media/java/android/media/MediaSync.java +++ b/media/java/android/media/MediaSync.java @@ -352,89 +352,6 @@ public final class MediaSync { public native final Surface createInputSurface(); /** - * Resample audio data when changing playback speed. - * <p> - * Resample the waveform based on the requested playback rate to get - * a new waveform, and play back the new waveform at the original sampling - * frequency. - * <p><ul> - * <li>When rate is larger than 1.0, pitch becomes higher. - * <li>When rate is smaller than 1.0, pitch becomes lower. - * </ul> - */ - public static final int PLAYBACK_RATE_AUDIO_MODE_RESAMPLE = 2; - - /** - * Time stretch audio when changing playback speed. - * <p> - * Time stretching changes the duration of the audio samples without - * affecting their pitch. This is only supported for a limited range - * of playback speeds, e.g. from 1/2x to 2x. If the rate is adjusted - * beyond this limit, the rate change will fail. - */ - public static final int PLAYBACK_RATE_AUDIO_MODE_STRETCH = 1; - - /** - * Time stretch audio when changing playback speed, and may mute if - * stretching is no longer supported. - * <p> - * Time stretching changes the duration of the audio samples without - * affecting their pitch. This is only supported for a limited range - * of playback speeds, e.g. from 1/2x to 2x. When it is no longer - * supported, the audio may be muted. Using this mode will not fail - * for non-negative playback rates. - */ - public static final int PLAYBACK_RATE_AUDIO_MODE_DEFAULT = 0; - - /** @hide */ - @IntDef( - value = { - PLAYBACK_RATE_AUDIO_MODE_DEFAULT, - PLAYBACK_RATE_AUDIO_MODE_STRETCH, - PLAYBACK_RATE_AUDIO_MODE_RESAMPLE, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface PlaybackRateAudioMode {} - - /** - * Sets playback rate and audio mode. - * - * @param rate the ratio between desired playback rate and normal one. 1.0 means normal - * playback speed. 0.0 means pause. Value larger than 1.0 means faster playback, - * while value between 0.0 and 1.0 for slower playback. <b>Note:</b> the normal rate - * does not change as a result of this call. To restore the original rate at any time, - * use 1.0. - * @param audioMode audio playback mode. Must be one of the supported - * audio modes. - * - * @throws IllegalStateException if the internal sync engine or the audio track has not - * been initialized. - * @throws IllegalArgumentException if audioMode is not supported. - */ - public void setPlaybackRate(float rate, @PlaybackRateAudioMode int audioMode) { - PlaybackParams rateParams = new PlaybackParams(); - rateParams.allowDefaults(); - switch (audioMode) { - case PLAYBACK_RATE_AUDIO_MODE_DEFAULT: - rateParams.setSpeed(rate).setPitch(1.0f); - break; - case PLAYBACK_RATE_AUDIO_MODE_STRETCH: - rateParams.setSpeed(rate).setPitch(1.0f) - .setAudioFallbackMode(rateParams.AUDIO_FALLBACK_MODE_FAIL); - break; - case PLAYBACK_RATE_AUDIO_MODE_RESAMPLE: - rateParams.setSpeed(rate).setPitch(rate); - break; - default: - { - final String msg = "Audio playback mode " + audioMode + " is not supported"; - throw new IllegalArgumentException(msg); - } - } - setPlaybackParams(rateParams); - } - - /** * Sets playback rate using {@link PlaybackParams}. * <p> * When using MediaSync with {@link AudioTrack}, set playback params using this @@ -524,24 +441,23 @@ public final class MediaSync { } /** - * Get current playback position. - * <p> - * The MediaTimestamp represents how the media time correlates to the system time in - * a linear fashion. It contains the media time and system timestamp of an anchor frame - * ({@link MediaTimestamp#mediaTimeUs} and {@link MediaTimestamp#nanoTime}) - * and the speed of the media clock ({@link MediaTimestamp#clockRate}). - * <p> - * During regular playback, the media time moves fairly constantly (though the - * anchor frame may be rebased to a current system time, the linear correlation stays - * steady). Therefore, this method does not need to be called often. - * <p> - * To help users to get current playback position, this method always returns the timestamp of - * just-rendered frame, i.e., {@link System#nanoTime} and its corresponding media time. They - * can be used as current playback position. - * - * @return a MediaTimestamp object if a timestamp is available, or {@code null} if no timestamp - * is available, e.g. because the media sync has not been initialized. - */ + * Get current playback position. + * <p> + * The MediaTimestamp represents how the media time correlates to the system time in + * a linear fashion using an anchor and a clock rate. During regular playback, the media + * time moves fairly constantly (though the anchor frame may be rebased to a current + * system time, the linear correlation stays steady). Therefore, this method does not + * need to be called often. + * <p> + * To help users get current playback position, this method always anchors the timestamp + * to the current {@link System#nanoTime system time}, so + * {@link MediaTimestamp#getAnchorMediaTimeUs} can be used as current playback position. + * + * @return a MediaTimestamp object if a timestamp is available, or {@code null} if no timestamp + * is available, e.g. because the media player has not been initialized. + * + * @see MediaTimestamp + */ @Nullable public MediaTimestamp getTimestamp() { diff --git a/media/java/android/media/MediaTimestamp.java b/media/java/android/media/MediaTimestamp.java index d3d5618..5ea6bbe 100644 --- a/media/java/android/media/MediaTimestamp.java +++ b/media/java/android/media/MediaTimestamp.java @@ -37,22 +37,36 @@ package android.media; public final class MediaTimestamp { /** - * Media time in microseconds. + * Get the media time of the anchor in microseconds. */ - public final long mediaTimeUs; + public long getAnchorMediaTimeUs() { + return mediaTimeUs; + } /** - * The {@link java.lang.System#nanoTime system time} corresponding to the media time + * Get the {@link java.lang.System#nanoTime system time} corresponding to the media time * in nanoseconds. */ - public final long nanoTime; + public long getAnchorSytemNanoTime() { + return nanoTime; + } /** - * The rate of the media clock in relation to the system time. + * Get the rate of the media clock in relation to the system time. + * <p> * It is 1.0 if media clock advances in sync with the system clock; * greater than 1.0 if media clock is faster than the system clock; * less than 1.0 if media clock is slower than the system clock. */ + public float getMediaClockRate() { + return clockRate; + } + + /** @hide - accessor shorthand */ + public final long mediaTimeUs; + /** @hide - accessor shorthand */ + public final long nanoTime; + /** @hide - accessor shorthand */ public final float clockRate; /** @hide */ diff --git a/media/java/android/media/tv/DvbDeviceInfo.aidl b/media/java/android/media/tv/DvbDeviceInfo.aidl new file mode 100644 index 0000000..4851050 --- /dev/null +++ b/media/java/android/media/tv/DvbDeviceInfo.aidl @@ -0,0 +1,20 @@ +/* + * + * Copyright 2015, 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.tv; + +parcelable DvbDeviceInfo;
\ No newline at end of file diff --git a/media/java/android/media/tv/DvbDeviceInfo.java b/media/java/android/media/tv/DvbDeviceInfo.java new file mode 100644 index 0000000..1885a34 --- /dev/null +++ b/media/java/android/media/tv/DvbDeviceInfo.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2015 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.tv; + +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; +import android.media.tv.TvInputManager; +import android.util.Log; + +import java.lang.IllegalArgumentException; + +/** + * Simple container for information about DVB device. + * Not for third-party developers. + * + * @hide + */ +public final class DvbDeviceInfo implements Parcelable { + static final String TAG = "DvbDeviceInfo"; + + public static final Parcelable.Creator<DvbDeviceInfo> CREATOR = + new Parcelable.Creator<DvbDeviceInfo>() { + @Override + public DvbDeviceInfo createFromParcel(Parcel source) { + try { + return new DvbDeviceInfo(source); + } catch (Exception e) { + Log.e(TAG, "Exception creating DvbDeviceInfo from parcel", e); + return null; + } + } + + @Override + public DvbDeviceInfo[] newArray(int size) { + return new DvbDeviceInfo[size]; + } + }; + + private final int mAdapterId; + private final int mDeviceId; + + private DvbDeviceInfo(Parcel source) { + mAdapterId = source.readInt(); + mDeviceId = source.readInt(); + } + + /** + * Constructs a new {@link DvbDeviceInfo} with the given adapter ID and device ID. + */ + public DvbDeviceInfo(int adapterId, int deviceId) { + mAdapterId = adapterId; + mDeviceId = deviceId; + } + + /** + * Returns the adapter ID of DVB device, in terms of enumerating the DVB device adapters + * installed in the system. The adapter ID counts from zero. + */ + public int getAdapterId() { + return mAdapterId; + } + + /** + * Returns the device ID of DVB device, in terms of enumerating the DVB devices attached to + * the same device adapter. The device ID counts from zero. + */ + public int getDeviceId() { + return mDeviceId; + } + + // Parcelable + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mAdapterId); + dest.writeInt(mDeviceId); + } +} diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl index 078fb2f..6fe5dbb 100644 --- a/media/java/android/media/tv/ITvInputManager.aidl +++ b/media/java/android/media/tv/ITvInputManager.aidl @@ -18,6 +18,7 @@ package android.media.tv; import android.content.ComponentName; import android.graphics.Rect; +import android.media.tv.DvbDeviceInfo; import android.media.tv.ITvInputClient; import android.media.tv.ITvInputHardware; import android.media.tv.ITvInputHardwareCallback; @@ -29,6 +30,7 @@ import android.media.tv.TvStreamConfig; import android.media.tv.TvTrackInfo; import android.net.Uri; import android.os.Bundle; +import android.os.ParcelFileDescriptor; import android.view.Surface; /** @@ -91,4 +93,8 @@ interface ITvInputManager { boolean captureFrame(in String inputId, in Surface surface, in TvStreamConfig config, int userId); boolean isSingleSessionActive(int userId); + + // For DVB device binding + List<DvbDeviceInfo> getDvbDeviceList(); + ParcelFileDescriptor openDvbDevice(in DvbDeviceInfo info, int device); } diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java index 705aa3d6..e74860e 100644 --- a/media/java/android/media/tv/TvInputManager.java +++ b/media/java/android/media/tv/TvInputManager.java @@ -21,12 +21,14 @@ import android.annotation.Nullable; import android.annotation.SystemApi; import android.graphics.Rect; import android.media.MediaPlayer; +import android.media.tv.DvbDeviceInfo; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.util.ArrayMap; import android.util.Log; @@ -42,6 +44,7 @@ import android.view.View; import com.android.internal.util.Preconditions; +import java.lang.IllegalArgumentException; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; @@ -55,6 +58,25 @@ import java.util.Map; public final class TvInputManager { private static final String TAG = "TvInputManager"; + static final int DVB_DEVICE_START = 0; + static final int DVB_DEVICE_END = 2; + + /** + * A demux device of DVB API for controlling the filters of DVB hardware/software. + * @hide + */ + public static final int DVB_DEVICE_DEMUX = DVB_DEVICE_START; + /** + * A DVR device of DVB API for reading transport streams. + * @hide + */ + public static final int DVB_DEVICE_DVR = 1; + /** + * A frontend device of DVB API for controlling the tuner and DVB demodulator hardware. + * @hide + */ + public static final int DVB_DEVICE_FRONTEND = DVB_DEVICE_END; + static final int VIDEO_UNAVAILABLE_REASON_START = 0; static final int VIDEO_UNAVAILABLE_REASON_END = 4; @@ -1258,6 +1280,43 @@ public final class TvInputManager { } /** + * Returns the list of currently available DVB devices on the system. + * + * @return the list of {@link DvbDeviceInfo} objects representing available DVB devices. + * @hide + */ + public List<DvbDeviceInfo> getDvbDeviceList() { + try { + return mService.getDvbDeviceList(); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Returns a {@link ParcelFileDescriptor} of a specified DVB device for a given + * {@link DvbDeviceInfo} + * + * @param info A {@link DvbDeviceInfo} to open a DVB device. + * @param device A DVB device. The DVB device can be {@link DVB_DEVICE_DEMUX}, + * {@link DVB_DEVICE_DVR} or {@link DVB_DEVICE_FRONTEND}. + * @return a {@link ParcelFileDescriptor} of a specified DVB device for a given + * {@link DvbDeviceInfo}, or {@code null} if the given {@link DvbDeviceInfo} was + * invalid or the specified DVB device was busy with a previous request. + * @hide + */ + public ParcelFileDescriptor openDvbDevice(DvbDeviceInfo info, int device) { + try { + if (DVB_DEVICE_START > device || DVB_DEVICE_END < device) { + throw new IllegalArgumentException("Invalid DVB device: " + device); + } + return mService.openDvbDevice(info, device); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** * The Session provides the per-session functionality of TV inputs. * @hide */ diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index 043e20b..49614bd 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -1222,6 +1222,19 @@ static jint Image_getHeight(JNIEnv* env, jobject thiz, jint format) } } +static jint Image_getFormat(JNIEnv* env, jobject thiz, jint readerFormat) +{ + if (isFormatOpaque(readerFormat)) { + // Assuming opaque reader produce opaque images. + return static_cast<jint>(PublicFormat::PRIVATE); + } else { + CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz); + PublicFormat publicFmt = android_view_Surface_mapHalFormatDataspaceToPublicFormat( + buffer->flexFormat, buffer->dataSpace); + return static_cast<jint>(publicFmt); + } +} + } // extern "C" // ---------------------------------------------------------------------------- @@ -1240,8 +1253,9 @@ static JNINativeMethod gImageMethods[] = { {"nativeImageGetBuffer", "(II)Ljava/nio/ByteBuffer;", (void*)Image_getByteBuffer }, {"nativeCreatePlane", "(II)Landroid/media/ImageReader$SurfaceImage$SurfacePlane;", (void*)Image_createSurfacePlane }, - {"nativeGetWidth", "(I)I", (void*)Image_getWidth }, - {"nativeGetHeight", "(I)I", (void*)Image_getHeight }, + {"nativeGetWidth", "(I)I", (void*)Image_getWidth }, + {"nativeGetHeight", "(I)I", (void*)Image_getHeight }, + {"nativeGetFormat", "(I)I", (void*)Image_getFormat }, }; int register_android_media_ImageReader(JNIEnv *env) { diff --git a/media/jni/android_media_MediaDataSource.cpp b/media/jni/android_media_MediaDataSource.cpp index 1e6d2af..025133f 100644 --- a/media/jni/android_media_MediaDataSource.cpp +++ b/media/jni/android_media_MediaDataSource.cpp @@ -39,7 +39,7 @@ JMediaDataSource::JMediaDataSource(JNIEnv* env, jobject source) ScopedLocalRef<jclass> mediaDataSourceClass(env, env->GetObjectClass(mMediaDataSourceObj)); CHECK(mediaDataSourceClass.get() != NULL); - mReadMethod = env->GetMethodID(mediaDataSourceClass.get(), "readAt", "(J[BI)I"); + mReadMethod = env->GetMethodID(mediaDataSourceClass.get(), "readAt", "(J[BII)I"); CHECK(mReadMethod != NULL); mGetSizeMethod = env->GetMethodID(mediaDataSourceClass.get(), "getSize", "()J"); CHECK(mGetSizeMethod != NULL); @@ -80,7 +80,7 @@ ssize_t JMediaDataSource::readAt(off64_t offset, size_t size) { JNIEnv* env = AndroidRuntime::getJNIEnv(); jint numread = env->CallIntMethod(mMediaDataSourceObj, mReadMethod, - (jlong)offset, mByteArrayObj, (jint)size); + (jlong)offset, mByteArrayObj, (jint)0, (jint)size); if (env->ExceptionCheck()) { ALOGW("An exception occurred in readAt()"); LOGW_EX(env); @@ -89,9 +89,14 @@ ssize_t JMediaDataSource::readAt(off64_t offset, size_t size) { return -1; } if (numread < 0) { - ALOGW("An error occurred in readAt()"); - mJavaObjStatus = UNKNOWN_ERROR; - return -1; + if (numread != -1) { + ALOGW("An error occurred in readAt()"); + mJavaObjStatus = UNKNOWN_ERROR; + return -1; + } else { + // numread == -1 indicates EOF + return 0; + } } if ((size_t)numread > size) { ALOGE("readAt read too many bytes."); diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp index b6b7a80..4e9b726 100644 --- a/media/jni/android_media_MediaExtractor.cpp +++ b/media/jni/android_media_MediaExtractor.cpp @@ -715,6 +715,11 @@ static void android_media_MediaExtractor_setDataSourceCallback( status_t err = extractor->setDataSource(bridge); if (err != OK) { + // Clear bridge so that JMediaDataSource::close() is called _before_ + // we throw the IOException. + // Otherwise close() gets called when we go out of scope, it calls + // Java with a pending exception and crashes the process. + bridge.clear(); jniThrowException( env, "java/io/IOException", diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp index 84ae3b4..6c1bd97 100644 --- a/media/jni/soundpool/SoundPool.cpp +++ b/media/jni/soundpool/SoundPool.cpp @@ -738,12 +738,16 @@ void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftV // do not create a new audio track if current track is compatible with sample parameters #ifdef USE_SHARED_MEM_BUFFER newTrack = new AudioTrack(streamType, sampleRate, sample->format(), - channelMask, sample->getIMemory(), AUDIO_OUTPUT_FLAG_FAST, callback, userData); + channelMask, sample->getIMemory(), AUDIO_OUTPUT_FLAG_FAST, callback, userData, + 0 /*default notification frames*/, AUDIO_SESSION_ALLOCATE, + AudioTrack::TRANSFER_DEFAULT, + NULL /*offloadInfo*/, -1 /*uid*/, -1 /*pid*/, mSoundPool->attributes()); #else uint32_t bufferFrames = (totalFrames + (kDefaultBufferCount - 1)) / kDefaultBufferCount; newTrack = new AudioTrack(streamType, sampleRate, sample->format(), channelMask, frameCount, AUDIO_OUTPUT_FLAG_FAST, callback, userData, - bufferFrames); + bufferFrames, AUDIO_SESSION_ALLOCATE, AudioTrack::TRANSFER_DEFAULT, + NULL /*offloadInfo*/, -1 /*uid*/, -1 /*pid*/, mSoundPool->attributes()); #endif oldTrack = mAudioTrack; status = newTrack->initCheck(); |