diff options
Diffstat (limited to 'media')
-rw-r--r-- | media/java/android/media/AudioAttributes.java | 17 | ||||
-rw-r--r-- | media/java/android/media/AudioDevicesManager.java | 271 | ||||
-rw-r--r-- | media/java/android/media/AudioManager.java | 17 | ||||
-rw-r--r-- | media/java/android/media/AudioTrack.java | 3 | ||||
-rw-r--r-- | media/java/android/media/IAudioService.aidl | 2 | ||||
-rw-r--r-- | media/java/android/media/MediaPlayer.java | 6 | ||||
-rw-r--r-- | media/java/android/media/MediaRouter.java | 5 | ||||
-rw-r--r-- | media/java/android/media/OnAudioDeviceConnectionListener.java | 28 | ||||
-rw-r--r-- | media/java/android/media/SoundPool.java | 3 |
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(), |