summaryrefslogtreecommitdiff
path: root/media
diff options
context:
space:
mode:
authorHaamed Gheibi <haamed@google.com>2021-07-12 20:47:45 +0000
committerHaamed Gheibi <haamed@google.com>2021-07-14 18:21:17 +0000
commit02a7ee5d65cb8d40fd1dde9aaf6b5ead9222a5a6 (patch)
tree6fb30a5bc0d0e7fadd37d62cdba537c4d5d9237b /media
parentbab7c6ab6b363574baaace4df576c1abb67f4507 (diff)
parentfa0439912edd9559d7c0f46bef2b2898de68f50f (diff)
Merge SP1A.210709.002
Change-Id: I4610885d5d770d858895057cdd9fea387a5e33dd
Diffstat (limited to 'media')
-rw-r--r--media/java/android/media/AudioFormat.java4
-rw-r--r--media/java/android/media/AudioManager.java52
-rw-r--r--media/java/android/media/MediaRecorder.java6
-rw-r--r--media/java/android/media/MediaRouter2Manager.java58
-rw-r--r--media/java/android/media/MediaServiceManager.java16
-rw-r--r--media/java/android/media/Ringtone.java2
-rw-r--r--media/java/android/media/RingtoneManager.java9
7 files changed, 131 insertions, 16 deletions
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index e35b0d516e56..b07dc9b581b2 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -310,6 +310,10 @@ public final class AudioFormat implements Parcelable {
public static final int ENCODING_LEGACY_SHORT_ARRAY_THRESHOLD = ENCODING_OPUS;
/** Audio data format: PCM 24 bit per sample packed as 3 bytes.
+ *
+ * The bytes are in little-endian order, so the least significant byte
+ * comes first in the byte array.
+ *
* Not guaranteed to be supported by devices, may be emulated if not supported. */
public static final int ENCODING_PCM_24BIT_PACKED = 21;
/** Audio data format: PCM 32 bit per sample.
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index ef478ee6aa6b..5b48bea776a8 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -103,6 +103,8 @@ public class AudioManager {
private static final AudioVolumeGroupChangeHandler sAudioAudioVolumeGroupChangedHandler =
new AudioVolumeGroupChangeHandler();
+ private static Context sContext;
+
/**
* Broadcast intent, a hint for applications that audio is about to become
* 'noisy' due to a change in audio outputs. For example, this intent may
@@ -798,6 +800,7 @@ public class AudioManager {
} else {
mOriginalContext = context;
}
+ sContext = context;
}
@UnsupportedAppUsage
@@ -7276,15 +7279,56 @@ public class AudioManager {
/**
* Return if an asset contains haptic channels or not.
+ *
+ * @param context the {@link Context} to resolve the uri.
* @param uri the {@link Uri} of the asset.
* @return true if the assert contains haptic channels.
* @hide
*/
- public static boolean hasHapticChannels(Uri uri) {
+ public static boolean hasHapticChannelsImpl(@NonNull Context context, @NonNull Uri uri) {
+ MediaExtractor extractor = new MediaExtractor();
try {
- return getService().hasHapticChannels(uri);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ extractor.setDataSource(context, uri, null);
+ for (int i = 0; i < extractor.getTrackCount(); i++) {
+ MediaFormat format = extractor.getTrackFormat(i);
+ if (format.containsKey(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT)
+ && format.getInteger(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT) > 0) {
+ return true;
+ }
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "hasHapticChannels failure:" + e);
+ }
+ return false;
+ }
+
+ /**
+ * Return if an asset contains haptic channels or not.
+ *
+ * @param context the {@link Context} to resolve the uri.
+ * @param uri the {@link Uri} of the asset.
+ * @return true if the assert contains haptic channels.
+ * @hide
+ */
+ public static boolean hasHapticChannels(@Nullable Context context, @NonNull Uri uri) {
+ Objects.requireNonNull(uri);
+ if (context != null) {
+ return hasHapticChannelsImpl(context, uri);
+ } else if (sContext != null) {
+ if (DEBUG) {
+ Log.d(TAG, "Try to use static context to query if having haptic channels");
+ }
+ return hasHapticChannelsImpl(sContext, uri);
+ } else {
+ // Try with audio service context, this may fail to get correct result.
+ if (DEBUG) {
+ Log.d(TAG, "Try to use audio service context to query if having haptic channels");
+ }
+ try {
+ return getService().hasHapticChannels(uri);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
}
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 805340be688c..5936700ed742 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -854,7 +854,7 @@ public class MediaRecorder implements AudioRouting,
setVideoSize(profile.getWidth(), profile.getHeight());
setVideoEncodingBitRate(profile.getBitrate());
setVideoEncoder(profile.getCodec());
- if (profile.getProfile() > 0) {
+ if (profile.getProfile() >= 0) {
setVideoEncodingProfileLevel(profile.getProfile(), 0 /* level */);
}
}
@@ -1135,10 +1135,10 @@ public class MediaRecorder implements AudioRouting,
* @throws IllegalArgumentException when an invalid profile or level value is used.
*/
public void setVideoEncodingProfileLevel(int profile, int level) {
- if (profile <= 0) {
+ if (profile < 0) {
throw new IllegalArgumentException("Video encoding profile is not positive");
}
- if (level <= 0) {
+ if (level < 0) {
throw new IllegalArgumentException("Video encoding level is not positive");
}
setParameter("video-param-encoder-profile=" + profile);
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 915cb1272040..628f7eef84f9 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -221,10 +221,24 @@ public final class MediaRouter2Manager {
Objects.requireNonNull(packageName, "packageName must not be null");
List<RoutingSessionInfo> sessions = getRoutingSessions(packageName);
- return getAvailableRoutesForRoutingSession(sessions.get(sessions.size() - 1));
+ return getAvailableRoutes(sessions.get(sessions.size() - 1));
}
/**
+ * Gets routes that can be transferable seamlessly for an application.
+ *
+ * @param packageName the package name of the application
+ */
+ @NonNull
+ public List<MediaRoute2Info> getTransferableRoutes(@NonNull String packageName) {
+ Objects.requireNonNull(packageName, "packageName must not be null");
+
+ List<RoutingSessionInfo> sessions = getRoutingSessions(packageName);
+ return getTransferableRoutes(sessions.get(sessions.size() - 1));
+ }
+
+
+ /**
* Gets available routes for the given routing session.
* The returned routes can be passed to
* {@link #transfer(RoutingSessionInfo, MediaRoute2Info)} for transferring the routing session.
@@ -232,8 +246,7 @@ public final class MediaRouter2Manager {
* @param sessionInfo the routing session that would be transferred
*/
@NonNull
- public List<MediaRoute2Info> getAvailableRoutesForRoutingSession(
- @NonNull RoutingSessionInfo sessionInfo) {
+ public List<MediaRoute2Info> getAvailableRoutes(@NonNull RoutingSessionInfo sessionInfo) {
Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
List<MediaRoute2Info> routes = new ArrayList<>();
@@ -256,6 +269,45 @@ public final class MediaRouter2Manager {
}
/**
+ * Gets routes that can be transferable seamlessly for the given routing session.
+ * The returned routes can be passed to
+ * {@link #transfer(RoutingSessionInfo, MediaRoute2Info)} for transferring the routing session.
+ * <p>
+ * This includes routes that are {@link RoutingSessionInfo#getTransferableRoutes() transferable}
+ * by provider itself and routes that are different playback type (e.g. local/remote)
+ * from the given routing session.
+ *
+ * @param sessionInfo the routing session that would be transferred
+ */
+ @NonNull
+ public List<MediaRoute2Info> getTransferableRoutes(@NonNull RoutingSessionInfo sessionInfo) {
+ Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
+
+ List<MediaRoute2Info> routes = new ArrayList<>();
+
+ String packageName = sessionInfo.getClientPackageName();
+ List<String> preferredFeatures = mPreferredFeaturesMap.get(packageName);
+ if (preferredFeatures == null) {
+ preferredFeatures = Collections.emptyList();
+ }
+ synchronized (mRoutesLock) {
+ for (MediaRoute2Info route : mRoutes.values()) {
+ if (sessionInfo.getSelectedRoutes().contains(route.getId())
+ || sessionInfo.getTransferableRoutes().contains(route.getId())) {
+ routes.add(route);
+ continue;
+ }
+ // Add Phone -> Cast and Cast -> Phone
+ if (route.hasAnyFeatures(preferredFeatures)
+ && (sessionInfo.isSystemSession() ^ route.isSystemRoute())) {
+ routes.add(route);
+ }
+ }
+ }
+ return routes;
+ }
+
+ /**
* Returns the preferred features of the specified package name.
*/
@NonNull
diff --git a/media/java/android/media/MediaServiceManager.java b/media/java/android/media/MediaServiceManager.java
index b899559d2e50..fd89c0c67e71 100644
--- a/media/java/android/media/MediaServiceManager.java
+++ b/media/java/android/media/MediaServiceManager.java
@@ -45,12 +45,21 @@ public class MediaServiceManager {
*/
public static final class ServiceRegisterer {
private final String mServiceName;
+ private final boolean mLazyStart;
/**
* @hide
*/
- public ServiceRegisterer(String serviceName) {
+ public ServiceRegisterer(String serviceName, boolean lazyStart) {
mServiceName = serviceName;
+ mLazyStart = lazyStart;
+ }
+
+ /**
+ * @hide
+ */
+ public ServiceRegisterer(String serviceName) {
+ this(serviceName, false /*lazyStart*/);
}
/**
@@ -61,6 +70,9 @@ public class MediaServiceManager {
*/
@Nullable
public IBinder get() {
+ if (mLazyStart) {
+ return ServiceManager.waitForService(mServiceName);
+ }
return ServiceManager.getService(mServiceName);
}
}
@@ -78,7 +90,7 @@ public class MediaServiceManager {
*/
@NonNull
public ServiceRegisterer getMediaTranscodingServiceRegisterer() {
- return new ServiceRegisterer(MEDIA_TRANSCODING_SERVICE);
+ return new ServiceRegisterer(MEDIA_TRANSCODING_SERVICE, true /*lazyStart*/);
}
/**
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index f8297bc93b72..3cf03417334b 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -407,7 +407,7 @@ public class Ringtone {
if (mLocalPlayer != null) {
// Play ringtones if stream volume is over 0 or if it is a haptic-only ringtone
// (typically because ringer mode is vibrate).
- boolean isHapticOnly = AudioManager.hasHapticChannels(mUri)
+ boolean isHapticOnly = AudioManager.hasHapticChannels(mContext, mUri)
&& !mAudioAttributes.areHapticChannelsMuted() && mVolume == 0;
if (isHapticOnly || mAudioManager.getStreamVolume(
AudioAttributes.toLegacyStreamType(mAudioAttributes)) != 0) {
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index be6ff1baadd6..4ec79b7e085a 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -1082,18 +1082,21 @@ public class RingtoneManager {
* @return true if the ringtone contains haptic channels.
*/
public boolean hasHapticChannels(int position) {
- return hasHapticChannels(getRingtoneUri(position));
+ return AudioManager.hasHapticChannels(mContext, getRingtoneUri(position));
}
/**
* Returns if the {@link Ringtone} from a given sound URI contains
- * haptic channels or not.
+ * haptic channels or not. As this function doesn't has a context
+ * to resolve the uri, the result may be wrong if the uri cannot be
+ * resolved correctly.
+ * Use {@link #hasHapticChannels(int)} instead when possible.
*
* @param ringtoneUri The {@link Uri} of a sound or ringtone.
* @return true if the ringtone contains haptic channels.
*/
public static boolean hasHapticChannels(@NonNull Uri ringtoneUri) {
- return AudioManager.hasHapticChannels(ringtoneUri);
+ return AudioManager.hasHapticChannels(null, ringtoneUri);
}
/**