summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
Diffstat (limited to 'media')
-rw-r--r--media/java/android/media/AudioAttributes.java17
-rw-r--r--media/java/android/media/AudioDevicesManager.java271
-rw-r--r--media/java/android/media/AudioManager.java17
-rw-r--r--media/java/android/media/AudioTrack.java3
-rw-r--r--media/java/android/media/IAudioService.aidl2
-rw-r--r--media/java/android/media/MediaPlayer.java6
-rw-r--r--media/java/android/media/MediaRouter.java5
-rw-r--r--media/java/android/media/OnAudioDeviceConnectionListener.java28
-rw-r--r--media/java/android/media/SoundPool.java3
9 files changed, 347 insertions, 5 deletions
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index ca242e4..97919a9 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -209,8 +209,23 @@ public final class AudioAttributes implements Parcelable {
@SystemApi
public final static int FLAG_HW_HOTWORD = 0x1 << 5;
+ /**
+ * @hide
+ * Flag requesting audible playback even under limited interruptions.
+ */
+ @SystemApi
+ public final static int FLAG_BYPASS_INTERRUPTION_POLICY = 0x1 << 6;
+
+ /**
+ * @hide
+ * Flag requesting audible playback even when the underlying stream is muted.
+ */
+ @SystemApi
+ public final static int FLAG_BYPASS_MUTE = 0x1 << 7;
+
private final static int FLAG_ALL = FLAG_AUDIBILITY_ENFORCED | FLAG_SECURE | FLAG_SCO |
- FLAG_BEACON | FLAG_HW_AV_SYNC | FLAG_HW_HOTWORD;
+ FLAG_BEACON | FLAG_HW_AV_SYNC | FLAG_HW_HOTWORD | FLAG_BYPASS_INTERRUPTION_POLICY |
+ FLAG_BYPASS_MUTE;
private final static int FLAG_ALL_PUBLIC = FLAG_AUDIBILITY_ENFORCED | FLAG_HW_AV_SYNC;
private int mUsage = USAGE_UNKNOWN;
diff --git a/media/java/android/media/AudioDevicesManager.java b/media/java/android/media/AudioDevicesManager.java
new file mode 100644
index 0000000..bce2100
--- /dev/null
+++ b/media/java/android/media/AudioDevicesManager.java
@@ -0,0 +1,271 @@
+/*
+ * 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;
+
+import android.content.Context;
+import android.util.Slog;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import android.content.Context;
+
+/** @hide
+ * API candidate
+ */
+public class AudioDevicesManager {
+ private static String TAG = "AudioDevicesManager";
+ private static boolean DEBUG = true;
+
+ private AudioManager mAudioManager = null;
+ private OnAmPortUpdateListener mPortListener = null;
+
+ /*
+ * Enum/Selection API
+ */
+ public AudioDevicesManager(Context context) {
+ mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
+ mPortListener = new OnAmPortUpdateListener();
+ mAudioManager.registerAudioPortUpdateListener(mPortListener);
+ }
+
+ /** @hide
+ * API candidate
+ */
+ //TODO Merge this class into android.media.AudioDevice
+ public class AudioDeviceInfo {
+ private AudioDevicePort mPort = null;
+
+ /** @hide */
+ /* package */ AudioDeviceInfo(AudioDevicePort port) {
+ mPort = port;
+ }
+
+ public int getId() { return mPort.handle().id(); }
+
+ public String getName() { return mPort.name(); }
+
+ public int getType() {
+ return mPort.type();
+ }
+
+ public String getAddress() {
+ return mPort.address();
+ }
+
+ public int getRole() { return mPort.role(); }
+
+ public int[] getSampleRates() { return mPort.samplingRates(); }
+
+ public int[] getChannelMasks() { return mPort.channelMasks(); }
+
+ public int[] getChannelCounts() {
+ int[] masks = getChannelMasks();
+ int[] counts = new int[masks.length];
+ for (int mask_index = 0; mask_index < masks.length; mask_index++) {
+ counts[mask_index] = getRole() == AudioPort.ROLE_SINK
+ ? AudioFormat.channelCountFromOutChannelMask(masks[mask_index])
+ : AudioFormat.channelCountFromInChannelMask(masks[mask_index]);
+ }
+ return counts;
+ }
+
+ /* The format IDs are in AudioFormat.java */
+ public int[] getFormats() { return mPort.formats(); }
+
+ public String toString() { return "" + getId() + " - " + getName(); }
+ }
+
+ /** @hide */
+ public static final int LIST_DEVICES_OUTPUTS = 0x0001;
+ /** @hide */
+ public static final int LIST_DEVICES_INPUTS = 0x0002;
+ /** @hide */
+ public static final int LIST_DEVICES_BUILTIN = 0x0004;
+ /** @hide */
+ public static final int LIST_DEVICES_USB = 0x0008;
+ // TODO implement the semantics for these.
+ /** @hide */
+ public static final int LIST_DEVICES_WIRED = 0x0010;
+ /** @hide */
+ public static final int LIST_DEVICES_UNWIRED = 0x0020;
+
+ /** @hide */
+ public static final int LIST_DEVICES_ALL = LIST_DEVICES_OUTPUTS | LIST_DEVICES_INPUTS;
+
+ private boolean checkFlags(AudioDevicePort port, int flags) {
+ // Inputs / Outputs
+ boolean passed =
+ port.role() == AudioPort.ROLE_SINK && (flags & LIST_DEVICES_OUTPUTS) != 0 ||
+ port.role() == AudioPort.ROLE_SOURCE && (flags & LIST_DEVICES_INPUTS) != 0;
+
+ // USB
+ if (passed && (flags & LIST_DEVICES_USB) != 0) {
+ int role = port.role();
+ int type = port.type();
+ Slog.i(TAG, " role:" + role + " type:0x" + Integer.toHexString(type));
+ passed =
+ (role == AudioPort.ROLE_SINK && (type & AudioSystem.DEVICE_OUT_ALL_USB) != 0) ||
+ (role == AudioPort.ROLE_SOURCE && (type & AudioSystem.DEVICE_IN_ALL_USB) != 0);
+ }
+
+ return passed;
+ }
+
+ /** @hide */
+ public ArrayList<AudioDeviceInfo> listDevices(int flags) {
+ Slog.i(TAG, "AudioManager.listDevices(" + Integer.toHexString(flags) + ")");
+
+ ArrayList<AudioDevicePort> ports = new ArrayList<AudioDevicePort>();
+ int status = mAudioManager.listAudioDevicePorts(ports);
+
+ Slog.i(TAG, " status:" + status + " numPorts:" + ports.size());
+
+ ArrayList<AudioDeviceInfo> deviceList = new ArrayList<AudioDeviceInfo>();
+
+ if (status == AudioManager.SUCCESS) {
+ deviceList = new ArrayList<AudioDeviceInfo>();
+ for (AudioDevicePort port : ports) {
+ if (checkFlags(port, flags)) {
+ deviceList.add(new AudioDeviceInfo(port));
+ }
+ }
+ }
+ return deviceList;
+ }
+
+ private ArrayList<OnAudioDeviceConnectionListener> mDeviceConnectionListeners =
+ new ArrayList<OnAudioDeviceConnectionListener>();
+
+ private HashMap<Integer, AudioPort> mCurrentPortlist =
+ new HashMap<Integer, AudioPort>();
+
+ private ArrayList<AudioDeviceInfo> calcAddedDevices(AudioPort[] portList) {
+ ArrayList<AudioDeviceInfo> addedDevices = new ArrayList<AudioDeviceInfo>();
+ synchronized(mCurrentPortlist) {
+ for(int portIndex = 0; portIndex < portList.length; portIndex++) {
+ if (portList[portIndex] instanceof AudioDevicePort) {
+ if (!mCurrentPortlist.containsKey(portList[portIndex].handle().id())) {
+ addedDevices.add(new AudioDeviceInfo((AudioDevicePort)portList[portIndex]));
+ }
+ }
+ }
+ }
+ return addedDevices;
+ }
+
+ private boolean hasPortId(AudioPort[] portList, int id) {
+ for(int portIndex = 0; portIndex < portList.length; portIndex++) {
+ if (portList[portIndex].handle().id() == id) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private ArrayList<AudioDeviceInfo> calcRemovedDevices(AudioPort[] portList) {
+ ArrayList<AudioDeviceInfo> removedDevices = new ArrayList<AudioDeviceInfo>();
+
+ synchronized (mCurrentPortlist) {
+ Iterator it = mCurrentPortlist.entrySet().iterator();
+ while (it.hasNext()) {
+ HashMap.Entry pairs = (HashMap.Entry)it.next();
+ if (pairs.getValue() instanceof AudioDevicePort) {
+ if (!hasPortId(portList, ((Integer)pairs.getKey()).intValue())) {
+ removedDevices.add(new AudioDeviceInfo((AudioDevicePort)pairs.getValue()));
+ }
+ }
+ }
+ }
+ return removedDevices;
+ }
+
+ private void buildCurrentDevicesList(AudioPort[] portList) {
+ synchronized (mCurrentPortlist) {
+ mCurrentPortlist.clear();
+ for (int portIndex = 0; portIndex < portList.length; portIndex++) {
+ if (portList[portIndex] instanceof AudioDevicePort) {
+ mCurrentPortlist.put(portList[portIndex].handle().id(),
+ (AudioDevicePort)portList[portIndex]);
+ }
+ }
+ }
+ }
+
+ /** @hide */
+ public void addDeviceConnectionListener(OnAudioDeviceConnectionListener listener) {
+ synchronized (mDeviceConnectionListeners) {
+ mDeviceConnectionListeners.add(listener);
+ }
+ }
+
+ /** @hide */
+ public void removeDeviceConnectionListener(OnAudioDeviceConnectionListener listener) {
+ synchronized (mDeviceConnectionListeners) {
+ mDeviceConnectionListeners.remove(listener);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ private class OnAmPortUpdateListener implements AudioManager.OnAudioPortUpdateListener {
+ static final String TAG = "OnAmPortUpdateListener";
+ public void onAudioPortListUpdate(AudioPort[] portList) {
+ Slog.i(TAG, "onAudioPortListUpdate() " + portList.length + " ports.");
+ ArrayList<AudioDeviceInfo> addedDevices = calcAddedDevices(portList);
+ ArrayList<AudioDeviceInfo> removedDevices = calcRemovedDevices(portList);
+
+ ArrayList<OnAudioDeviceConnectionListener> listeners = null;
+ synchronized (mDeviceConnectionListeners) {
+ listeners =
+ new ArrayList<OnAudioDeviceConnectionListener>(mDeviceConnectionListeners);
+ }
+
+ // Connect
+ if (addedDevices.size() != 0) {
+ for (OnAudioDeviceConnectionListener listener : listeners) {
+ listener.onConnect(addedDevices);
+ }
+ }
+
+ // Disconnect?
+ if (removedDevices.size() != 0) {
+ for (OnAudioDeviceConnectionListener listener : listeners) {
+ listener.onDisconnect(removedDevices);
+ }
+ }
+
+ buildCurrentDevicesList(portList);
+ }
+
+ /**
+ * Callback method called upon audio patch list update.
+ * @param patchList the updated list of audio patches
+ */
+ public void onAudioPatchListUpdate(AudioPatch[] patchList) {
+ Slog.i(TAG, "onAudioPatchListUpdate() " + patchList.length + " patches.");
+ }
+
+ /**
+ * Callback method called when the mediaserver dies
+ */
+ public void onServiceDied() {
+ Slog.i(TAG, "onServiceDied()");
+ }
+ }
+}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 7084eba..9876995 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -3334,6 +3334,19 @@ public class AudioManager {
* Only useful for volume controllers.
* @hide
*/
+ public boolean isStreamAffectedByMute(int streamType) {
+ try {
+ return getService().isStreamAffectedByMute(streamType);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Error calling isStreamAffectedByMute", e);
+ return false;
+ }
+ }
+
+ /**
+ * Only useful for volume controllers.
+ * @hide
+ */
public void disableSafeMediaVolume() {
try {
getService().disableSafeMediaVolume();
@@ -3446,14 +3459,14 @@ public class AudioManager {
* @see listAudioPorts(ArrayList<AudioPort>)
* @hide
*/
- public int listAudioDevicePorts(ArrayList<AudioPort> devices) {
+ public int listAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
int status = updateAudioPortCache(ports, null);
if (status == SUCCESS) {
devices.clear();
for (int i = 0; i < ports.size(); i++) {
if (ports.get(i) instanceof AudioDevicePort) {
- devices.add(ports.get(i));
+ devices.add((AudioDevicePort)ports.get(i));
}
}
}
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index caccb6e..cd78234 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1178,6 +1178,9 @@ public class AudioTrack
}
private boolean isRestricted() {
+ if ((mAttributes.getFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) {
+ return false;
+ }
try {
final int usage = AudioAttributes.usageForLegacyStreamType(mStreamType);
final int mode = mAppOps.checkAudioOperation(AppOpsManager.OP_PLAY_AUDIO, usage,
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index dabd9c2..17f5b59 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -202,6 +202,8 @@ interface IAudioService {
boolean isStreamAffectedByRingerMode(int streamType);
+ boolean isStreamAffectedByMute(int streamType);
+
void disableSafeMediaVolume();
int setHdmiSystemAudioSupported(boolean on);
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 615dac2..fc372eb 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -604,6 +604,7 @@ public class MediaPlayer implements SubtitleController.Listener
private final IAppOpsService mAppOps;
private int mStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
private int mUsage = -1;
+ private boolean mBypassInterruptionPolicy;
/**
* Default constructor. Consider using one of the create() methods for
@@ -1169,6 +1170,9 @@ public class MediaPlayer implements SubtitleController.Listener
private native void _start() throws IllegalStateException;
private boolean isRestricted() {
+ if (mBypassInterruptionPolicy) {
+ return false;
+ }
try {
final int usage = mUsage != -1 ? mUsage
: AudioAttributes.usageForLegacyStreamType(getAudioStreamType());
@@ -1560,6 +1564,8 @@ public class MediaPlayer implements SubtitleController.Listener
throw new IllegalArgumentException(msg);
}
mUsage = attributes.getUsage();
+ mBypassInterruptionPolicy = (attributes.getFlags()
+ & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0;
Parcel pattributes = Parcel.obtain();
attributes.writeToParcel(pattributes, AudioAttributes.FLATTEN_TAGS);
setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, pattributes);
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 5285074..b4c612a 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -17,6 +17,7 @@
package android.media;
import android.Manifest;
+import android.annotation.DrawableRes;
import android.app.ActivityThread;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -2083,7 +2084,7 @@ public class MediaRouter {
*
* @param resId Resource ID of an icon drawable to use to represent this route
*/
- public void setIconResource(int resId) {
+ public void setIconResource(@DrawableRes int resId) {
setIconDrawable(sStatic.mResources.getDrawable(resId));
}
@@ -2393,7 +2394,7 @@ public class MediaRouter {
*
* @param resId Resource ID of an icon drawable to use to represent this group
*/
- public void setIconResource(int resId) {
+ public void setIconResource(@DrawableRes int resId) {
setIconDrawable(sStatic.mResources.getDrawable(resId));
}
diff --git a/media/java/android/media/OnAudioDeviceConnectionListener.java b/media/java/android/media/OnAudioDeviceConnectionListener.java
new file mode 100644
index 0000000..4bdd4d0
--- /dev/null
+++ b/media/java/android/media/OnAudioDeviceConnectionListener.java
@@ -0,0 +1,28 @@
+/*
+ * 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;
+
+import java.util.ArrayList;
+
+/**
+ * @hide
+ * API candidate
+ */
+public abstract class OnAudioDeviceConnectionListener {
+ public void onConnect(ArrayList<AudioDevicesManager.AudioDeviceInfo> devices) {}
+ public void onDisconnect(ArrayList<AudioDevicesManager.AudioDeviceInfo> devices) {}
+}
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index 32d5b82..db6b38b 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -608,6 +608,9 @@ public class SoundPool {
int priority, int loop, float rate);
private boolean isRestricted() {
+ if ((mAttributes.getFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) {
+ return false;
+ }
try {
final int mode = mAppOps.checkAudioOperation(AppOpsManager.OP_PLAY_AUDIO,
mAttributes.getUsage(),