summaryrefslogtreecommitdiff
path: root/android/media
diff options
context:
space:
mode:
authorJustin Klaassen <justinklaassen@google.com>2017-11-30 18:18:21 -0500
committerJustin Klaassen <justinklaassen@google.com>2017-11-30 18:18:21 -0500
commit4217cf85c20565a3446a662a7f07f26137b26b7f (patch)
treea0417b47a8cc802f6642f369fd2371165bec7b5c /android/media
parent6a65f2da209bff03cb0eb6da309710ac6ee5026d (diff)
downloadandroid-28-4217cf85c20565a3446a662a7f07f26137b26b7f.tar.gz
Import Android SDK Platform P [4477446]
/google/data/ro/projects/android/fetch_artifact \ --bid 4477446 \ --target sdk_phone_armv7-win_sdk \ sdk-repo-linux-sources-4477446.zip AndroidVersion.ApiLevel has been modified to appear as 28 Change-Id: If0559643d7c328e36aafca98f0c114641d33642c
Diffstat (limited to 'android/media')
-rw-r--r--android/media/ImageReader.java1
-rw-r--r--android/media/MediaDrm.java68
-rw-r--r--android/media/MediaFormat.java8
-rw-r--r--android/media/MediaMetadata.java66
-rw-r--r--android/media/MediaMuxer.java16
-rw-r--r--android/media/MediaRecorder.java165
-rw-r--r--android/media/tv/TvInputManager.java4
7 files changed, 285 insertions, 43 deletions
diff --git a/android/media/ImageReader.java b/android/media/ImageReader.java
index c78c99f7..10195805 100644
--- a/android/media/ImageReader.java
+++ b/android/media/ImageReader.java
@@ -640,7 +640,6 @@ public class ImageReader implements AutoCloseable {
* The ImageReader continues to be usable after this call, but may need to reallocate buffers
* when more buffers are needed for rendering.
* </p>
- * @hide
*/
public void discardFreeBuffers() {
synchronized (mCloseLock) {
diff --git a/android/media/MediaDrm.java b/android/media/MediaDrm.java
index 1feea890..12e5744d 100644
--- a/android/media/MediaDrm.java
+++ b/android/media/MediaDrm.java
@@ -91,10 +91,10 @@ import android.util.Log;
* are only decrypted when the samples are delivered to the decoder.
* <p>
* MediaDrm methods throw {@link android.media.MediaDrm.MediaDrmStateException}
- * when a method is called on a MediaDrm object that has had an unrecoverable failure
- * in the DRM plugin or security hardware.
- * {@link android.media.MediaDrm.MediaDrmStateException} extends
- * {@link java.lang.IllegalStateException} with the addition of a developer-readable
+ * when a method is called on a MediaDrm object that has had an unrecoverable failure
+ * in the DRM plugin or security hardware.
+ * {@link android.media.MediaDrm.MediaDrmStateException} extends
+ * {@link java.lang.IllegalStateException} with the addition of a developer-readable
* diagnostic information string associated with the exception.
* <p>
* In the event of a mediaserver process crash or restart while a MediaDrm object
@@ -102,9 +102,9 @@ import android.util.Log;
* To recover, the app must release the MediaDrm object, then create and initialize
* a new one.
* <p>
- * As {@link android.media.MediaDrmResetException} and
- * {@link android.media.MediaDrm.MediaDrmStateException} both extend
- * {@link java.lang.IllegalStateException}, they should be in an earlier catch()
+ * As {@link android.media.MediaDrmResetException} and
+ * {@link android.media.MediaDrm.MediaDrmStateException} both extend
+ * {@link java.lang.IllegalStateException}, they should be in an earlier catch()
* block than {@link java.lang.IllegalStateException} if handled separately.
* <p>
* <a name="Callbacks"></a>
@@ -165,7 +165,7 @@ public final class MediaDrm {
/**
* Query if the given scheme identified by its UUID is supported on
- * this device, and whether the drm plugin is able to handle the
+ * this device, and whether the DRM plugin is able to handle the
* media container format specified by mimeType.
* @param uuid The UUID of the crypto scheme.
* @param mimeType The MIME type of the media container, e.g. "video/mp4"
@@ -745,7 +745,7 @@ public final class MediaDrm {
* returned in KeyRequest.defaultUrl.
* <p>
* After the app has received the key request response from the server,
- * it should deliver to the response to the DRM engine plugin using the method
+ * it should deliver to the response to the MediaDrm instance using the method
* {@link #provideKeyResponse}.
*
* @param scope may be a sessionId or a keySetId, depending on the specified keyType.
@@ -781,7 +781,7 @@ public final class MediaDrm {
/**
* A key response is received from the license server by the app, then it is
- * provided to the DRM engine plugin using provideKeyResponse. When the
+ * provided to the MediaDrm instance using provideKeyResponse. When the
* response is for an offline key request, a keySetId is returned that can be
* used to later restore the keys to a new session with the method
* {@link #restoreKeys}.
@@ -829,7 +829,7 @@ public final class MediaDrm {
* in the form of {name, value} pairs. Since DRM license policies vary by vendor,
* the specific status field names are determined by each DRM vendor. Refer to your
* DRM provider documentation for definitions of the field names for a particular
- * DRM engine plugin.
+ * DRM plugin.
*
* @param sessionId the session ID for the DRM session
*/
@@ -897,11 +897,11 @@ public final class MediaDrm {
@NonNull String certAuthority);
/**
- * After a provision response is received by the app, it is provided to the DRM
- * engine plugin using this method.
+ * After a provision response is received by the app, it is provided to the
+ * MediaDrm instance using this method.
*
* @param response the opaque provisioning response byte array to provide to the
- * DRM engine plugin.
+ * MediaDrm instance.
*
* @throws DeniedByServerException if the response indicates that the
* server rejected the request
@@ -912,7 +912,6 @@ public final class MediaDrm {
}
@NonNull
- /* could there be a valid response with 0-sized certificate or key? */
private native Certificate provideProvisionResponseNative(@NonNull byte[] response)
throws DeniedByServerException;
@@ -953,26 +952,26 @@ public final class MediaDrm {
/**
* Remove all secure stops without requiring interaction with the server.
*/
- public native void releaseAllSecureStops();
+ public native void releaseAllSecureStops();
/**
- * String property name: identifies the maker of the DRM engine plugin
+ * String property name: identifies the maker of the DRM plugin
*/
public static final String PROPERTY_VENDOR = "vendor";
/**
- * String property name: identifies the version of the DRM engine plugin
+ * String property name: identifies the version of the DRM plugin
*/
public static final String PROPERTY_VERSION = "version";
/**
- * String property name: describes the DRM engine plugin
+ * String property name: describes the DRM plugin
*/
public static final String PROPERTY_DESCRIPTION = "description";
/**
* String property name: a comma-separated list of cipher and mac algorithms
- * supported by CryptoSession. The list may be empty if the DRM engine
+ * supported by CryptoSession. The list may be empty if the DRM
* plugin does not support CryptoSession operations.
*/
public static final String PROPERTY_ALGORITHMS = "algorithms";
@@ -988,7 +987,7 @@ public final class MediaDrm {
public @interface StringProperty {}
/**
- * Read a DRM engine plugin String property value, given the property name string.
+ * Read a MediaDrm String property value, given the property name string.
* <p>
* Standard fields names are:
* {@link #PROPERTY_VENDOR}, {@link #PROPERTY_VERSION},
@@ -998,6 +997,13 @@ public final class MediaDrm {
public native String getPropertyString(@NonNull @StringProperty String propertyName);
/**
+ * Set a MediaDrm String property value, given the property name string
+ * and new value for the property.
+ */
+ public native void setPropertyString(@NonNull @StringProperty String propertyName,
+ @NonNull String value);
+
+ /**
* Byte array property name: the device unique identifier is established during
* device provisioning and provides a means of uniquely identifying each device.
*/
@@ -1011,7 +1017,7 @@ public final class MediaDrm {
public @interface ArrayProperty {}
/**
- * Read a DRM engine plugin byte array property value, given the property name string.
+ * Read a MediaDrm byte array property value, given the property name string.
* <p>
* Standard fields names are {@link #PROPERTY_DEVICE_UNIQUE_ID}
*/
@@ -1019,17 +1025,13 @@ public final class MediaDrm {
public native byte[] getPropertyByteArray(@ArrayProperty String propertyName);
/**
- * Set a DRM engine plugin String property value.
- */
- public native void setPropertyString(
- String propertyName, @NonNull String value);
-
- /**
- * Set a DRM engine plugin byte array property value.
- */
- public native void setPropertyByteArray(
+ * Set a MediaDrm byte array property value, given the property name string
+ * and new value for the property.
+ */
+ public native void setPropertyByteArray(@NonNull @ArrayProperty
String propertyName, @NonNull byte[] value);
+
private static final native void setCipherAlgorithmNative(
@NonNull MediaDrm drm, @NonNull byte[] sessionId, @NonNull String algorithm);
@@ -1158,7 +1160,7 @@ public final class MediaDrm {
* The algorithm string conforms to JCA Standard Names for Mac
* Algorithms and is case insensitive. For example "HmacSHA256".
* <p>
- * The list of supported algorithms for a DRM engine plugin can be obtained
+ * The list of supported algorithms for a DRM plugin can be obtained
* using the method {@link #getPropertyString} with the property name
* "algorithms".
*/
@@ -1272,7 +1274,7 @@ public final class MediaDrm {
* storage, and used when invoking the signRSA method.
*
* @param response the opaque certificate response byte array to provide to the
- * DRM engine plugin.
+ * MediaDrm instance.
*
* @throws DeniedByServerException if the response indicates that the
* server rejected the request
diff --git a/android/media/MediaFormat.java b/android/media/MediaFormat.java
index c475e122..306ed83c 100644
--- a/android/media/MediaFormat.java
+++ b/android/media/MediaFormat.java
@@ -721,14 +721,16 @@ public final class MediaFormat {
/**
* A key for boolean DEFAULT behavior for the track. The track with DEFAULT=true is
* selected in the absence of a specific user choice.
- * This is currently only used for subtitle tracks, when the user selected
- * 'Default' for the captioning locale.
+ * This is currently used in two scenarios:
+ * 1) for subtitle tracks, when the user selected 'Default' for the captioning locale.
+ * 2) for a {@link #MIMETYPE_IMAGE_ANDROID_HEIC} track, indicating the image is the
+ * primary item in the file.
+
* The associated value is an integer, where non-0 means TRUE. This is an optional
* field; if not specified, DEFAULT is considered to be FALSE.
*/
public static final String KEY_IS_DEFAULT = "is-default";
-
/**
* A key for the FORCED field for subtitle tracks. True if it is a
* forced subtitle track. Forced subtitle tracks are essential for the
diff --git a/android/media/MediaMetadata.java b/android/media/MediaMetadata.java
index bdc0fda6..31eb948d 100644
--- a/android/media/MediaMetadata.java
+++ b/android/media/MediaMetadata.java
@@ -34,6 +34,7 @@ import android.util.SparseArray;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Set;
+import java.util.Objects;
/**
* Contains metadata about an item, such as the title, artist, etc.
@@ -616,6 +617,71 @@ public final class MediaMetadata implements Parcelable {
};
/**
+ * Compares the contents of this object to another MediaMetadata object. It
+ * does not compare Bitmaps and Ratings as the media player can choose to
+ * forgo these fields depending on how you retrieve the MediaMetadata.
+ *
+ * @param o The Metadata object to compare this object against
+ * @return Whether or not the two objects have matching fields (excluding
+ * Bitmaps and Ratings)
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+
+ if (!(o instanceof MediaMetadata)) {
+ return false;
+ }
+
+ final MediaMetadata m = (MediaMetadata) o;
+
+ for (int i = 0; i < METADATA_KEYS_TYPE.size(); i++) {
+ String key = METADATA_KEYS_TYPE.keyAt(i);
+ switch (METADATA_KEYS_TYPE.valueAt(i)) {
+ case METADATA_TYPE_TEXT:
+ if (!Objects.equals(getString(key), m.getString(key))) {
+ return false;
+ }
+ break;
+ case METADATA_TYPE_LONG:
+ if (getLong(key) != m.getLong(key)) {
+ return false;
+ }
+ break;
+ default:
+ // Ignore ratings and bitmaps when comparing
+ break;
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int hashCode = 17;
+
+ for (int i = 0; i < METADATA_KEYS_TYPE.size(); i++) {
+ String key = METADATA_KEYS_TYPE.keyAt(i);
+ switch (METADATA_KEYS_TYPE.valueAt(i)) {
+ case METADATA_TYPE_TEXT:
+ hashCode = 31 * hashCode + Objects.hash(getString(key));
+ break;
+ case METADATA_TYPE_LONG:
+ hashCode = 31 * hashCode + Long.hashCode(getLong(key));
+ break;
+ default:
+ // Ignore ratings and bitmaps when comparing
+ break;
+ }
+ }
+
+ return hashCode;
+ }
+
+ /**
* Use to build MediaMetadata objects. The system defined metadata keys must
* use the appropriate data type.
*/
diff --git a/android/media/MediaMuxer.java b/android/media/MediaMuxer.java
index 91e57ee0..02c71b28 100644
--- a/android/media/MediaMuxer.java
+++ b/android/media/MediaMuxer.java
@@ -258,12 +258,18 @@ final public class MediaMuxer {
* in include/media/stagefright/MediaMuxer.h!
*/
private OutputFormat() {}
+ /** @hide */
+ public static final int MUXER_OUTPUT_FIRST = 0;
/** MPEG4 media file format*/
- public static final int MUXER_OUTPUT_MPEG_4 = 0;
+ public static final int MUXER_OUTPUT_MPEG_4 = MUXER_OUTPUT_FIRST;
/** WEBM media file format*/
- public static final int MUXER_OUTPUT_WEBM = 1;
+ public static final int MUXER_OUTPUT_WEBM = MUXER_OUTPUT_FIRST + 1;
/** 3GPP media file format*/
- public static final int MUXER_OUTPUT_3GPP = 2;
+ public static final int MUXER_OUTPUT_3GPP = MUXER_OUTPUT_FIRST + 2;
+ /** HEIF media file format*/
+ public static final int MUXER_OUTPUT_HEIF = MUXER_OUTPUT_FIRST + 3;
+ /** @hide */
+ public static final int MUXER_OUTPUT_LAST = MUXER_OUTPUT_HEIF;
};
/** @hide */
@@ -271,6 +277,7 @@ final public class MediaMuxer {
OutputFormat.MUXER_OUTPUT_MPEG_4,
OutputFormat.MUXER_OUTPUT_WEBM,
OutputFormat.MUXER_OUTPUT_3GPP,
+ OutputFormat.MUXER_OUTPUT_HEIF,
})
@Retention(RetentionPolicy.SOURCE)
public @interface Format {}
@@ -347,8 +354,7 @@ final public class MediaMuxer {
}
private void setUpMediaMuxer(@NonNull FileDescriptor fd, @Format int format) throws IOException {
- if (format != OutputFormat.MUXER_OUTPUT_MPEG_4 && format != OutputFormat.MUXER_OUTPUT_WEBM
- && format != OutputFormat.MUXER_OUTPUT_3GPP) {
+ if (format < OutputFormat.MUXER_OUTPUT_FIRST || format > OutputFormat.MUXER_OUTPUT_LAST) {
throw new IllegalArgumentException("format: " + format + " is invalid");
}
mNativeObject = nativeSetup(fd, format);
diff --git a/android/media/MediaRecorder.java b/android/media/MediaRecorder.java
index 76784904..3c49b80b 100644
--- a/android/media/MediaRecorder.java
+++ b/android/media/MediaRecorder.java
@@ -25,6 +25,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.PersistableBundle;
+import android.util.ArrayMap;
import android.util.Log;
import android.view.Surface;
@@ -34,6 +35,8 @@ import java.io.IOException;
import java.io.RandomAccessFile;
import java.lang.ref.WeakReference;
+import com.android.internal.annotations.GuardedBy;
+
/**
* Used to record audio and video. The recording control is based on a
* simple state machine (see below).
@@ -76,7 +79,7 @@ import java.lang.ref.WeakReference;
* <a href="{@docRoot}guide/topics/media/audio-capture.html">Audio Capture</a> developer guide.</p>
* </div>
*/
-public class MediaRecorder
+public class MediaRecorder implements AudioRouting
{
static {
System.loadLibrary("media_jni");
@@ -1243,6 +1246,7 @@ public class MediaRecorder
private static final int MEDIA_RECORDER_TRACK_EVENT_INFO = 101;
private static final int MEDIA_RECORDER_TRACK_EVENT_LIST_END = 1000;
+ private static final int MEDIA_RECORDER_AUDIO_ROUTING_CHANGED = 10000;
@Override
public void handleMessage(Message msg) {
@@ -1265,6 +1269,16 @@ public class MediaRecorder
return;
+ case MEDIA_RECORDER_AUDIO_ROUTING_CHANGED:
+ AudioManager.resetAudioPortGeneration();
+ synchronized (mRoutingChangeListeners) {
+ for (NativeRoutingEventHandlerDelegate delegate
+ : mRoutingChangeListeners.values()) {
+ delegate.notifyClient();
+ }
+ }
+ return;
+
default:
Log.e(TAG, "Unknown message type " + msg.what);
return;
@@ -1272,6 +1286,155 @@ public class MediaRecorder
}
}
+ //--------------------------------------------------------------------------
+ // Explicit Routing
+ //--------------------
+ private AudioDeviceInfo mPreferredDevice = null;
+
+ /**
+ * Specifies an audio device (via an {@link AudioDeviceInfo} object) to route
+ * the input from this MediaRecorder.
+ * @param deviceInfo The {@link AudioDeviceInfo} specifying the audio source.
+ * If deviceInfo is null, default routing is restored.
+ * @return true if succesful, false if the specified {@link AudioDeviceInfo} is non-null and
+ * does not correspond to a valid audio input device.
+ */
+ @Override
+ public boolean setPreferredDevice(AudioDeviceInfo deviceInfo) {
+ if (deviceInfo != null && !deviceInfo.isSource()) {
+ return false;
+ }
+ int preferredDeviceId = deviceInfo != null ? deviceInfo.getId() : 0;
+ boolean status = native_setInputDevice(preferredDeviceId);
+ if (status == true) {
+ synchronized (this) {
+ mPreferredDevice = deviceInfo;
+ }
+ }
+ return status;
+ }
+
+ /**
+ * Returns the selected input device specified by {@link #setPreferredDevice}. Note that this
+ * is not guaranteed to correspond to the actual device being used for recording.
+ */
+ @Override
+ public AudioDeviceInfo getPreferredDevice() {
+ synchronized (this) {
+ return mPreferredDevice;
+ }
+ }
+
+ /**
+ * Returns an {@link AudioDeviceInfo} identifying the current routing of this MediaRecorder
+ * Note: The query is only valid if the MediaRecorder is currently recording.
+ * If the recorder is not recording, the returned device can be null or correspond to previously
+ * selected device when the recorder was last active.
+ */
+ @Override
+ public AudioDeviceInfo getRoutedDevice() {
+ int deviceId = native_getRoutedDeviceId();
+ if (deviceId == 0) {
+ return null;
+ }
+ AudioDeviceInfo[] devices =
+ AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_INPUTS);
+ for (int i = 0; i < devices.length; i++) {
+ if (devices[i].getId() == deviceId) {
+ return devices[i];
+ }
+ }
+ return null;
+ }
+
+ /*
+ * Call BEFORE adding a routing callback handler or AFTER removing a routing callback handler.
+ */
+ private void enableNativeRoutingCallbacksLocked(boolean enabled) {
+ if (mRoutingChangeListeners.size() == 0) {
+ native_enableDeviceCallback(enabled);
+ }
+ }
+
+ /**
+ * The list of AudioRouting.OnRoutingChangedListener interfaces added (with
+ * {@link #addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, Handler)}
+ * by an app to receive (re)routing notifications.
+ */
+ @GuardedBy("mRoutingChangeListeners")
+ private ArrayMap<AudioRouting.OnRoutingChangedListener,
+ NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = new ArrayMap<>();
+
+ /**
+ * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing
+ * changes on this MediaRecorder.
+ * @param listener The {@link AudioRouting.OnRoutingChangedListener} interface to receive
+ * notifications of rerouting events.
+ * @param handler Specifies the {@link Handler} object for the thread on which to execute
+ * the callback. If <code>null</code>, the handler on the main looper will be used.
+ */
+ @Override
+ public void addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener,
+ Handler handler) {
+ synchronized (mRoutingChangeListeners) {
+ if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
+ enableNativeRoutingCallbacksLocked(true);
+ mRoutingChangeListeners.put(
+ listener, new NativeRoutingEventHandlerDelegate(this, listener, handler));
+ }
+ }
+ }
+
+ /**
+ * Removes an {@link AudioRouting.OnRoutingChangedListener} which has been previously added
+ * to receive rerouting notifications.
+ * @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface
+ * to remove.
+ */
+ @Override
+ public void removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener) {
+ synchronized (mRoutingChangeListeners) {
+ if (mRoutingChangeListeners.containsKey(listener)) {
+ mRoutingChangeListeners.remove(listener);
+ enableNativeRoutingCallbacksLocked(false);
+ }
+ }
+ }
+
+ /**
+ * Helper class to handle the forwarding of native events to the appropriate listener
+ * (potentially) handled in a different thread
+ */
+ private class NativeRoutingEventHandlerDelegate {
+ private MediaRecorder mMediaRecorder;
+ private AudioRouting.OnRoutingChangedListener mOnRoutingChangedListener;
+ private Handler mHandler;
+
+ NativeRoutingEventHandlerDelegate(final MediaRecorder mediaRecorder,
+ final AudioRouting.OnRoutingChangedListener listener, Handler handler) {
+ mMediaRecorder = mediaRecorder;
+ mOnRoutingChangedListener = listener;
+ mHandler = handler != null ? handler : mEventHandler;
+ }
+
+ void notifyClient() {
+ if (mHandler != null) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mOnRoutingChangedListener != null) {
+ mOnRoutingChangedListener.onRoutingChanged(mMediaRecorder);
+ }
+ }
+ });
+ }
+ }
+ }
+
+ private native final boolean native_setInputDevice(int deviceId);
+ private native final int native_getRoutedDeviceId();
+ private native final void native_enableDeviceCallback(boolean enabled);
+
/**
* Called from native code when an interesting event happens. This method
* just uses the EventHandler system to post the event back to the main app thread.
diff --git a/android/media/tv/TvInputManager.java b/android/media/tv/TvInputManager.java
index fd1f2cf6..143182f8 100644
--- a/android/media/tv/TvInputManager.java
+++ b/android/media/tv/TvInputManager.java
@@ -1330,6 +1330,7 @@ public final class TvInputManager {
*
* @return the list of content ratings blocked by the user.
*/
+ @SystemApi
public List<TvContentRating> getBlockedRatings() {
try {
List<TvContentRating> ratings = new ArrayList<>();
@@ -1585,8 +1586,10 @@ public final class TvInputManager {
* @param info The TV input which will use the acquired Hardware.
* @return Hardware on success, {@code null} otherwise.
*
+ * @hide
* @removed
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
public Hardware acquireTvInputHardware(int deviceId, final HardwareCallback callback,
TvInputInfo info) {
@@ -2591,6 +2594,7 @@ public final class TvInputManager {
}
/** @removed */
+ @SystemApi
public boolean dispatchKeyEventToHdmi(KeyEvent event) {
return false;
}