diff options
author | Eric Laurent <elaurent@google.com> | 2020-12-23 09:44:49 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2020-12-23 09:44:49 +0000 |
commit | 54e6b9c79b86ab1c8407c13a3c3d9be231d6a028 (patch) | |
tree | 8dc0c717aa36080e706d1996d1d882152a0e6a15 /media/java | |
parent | a53b25ad26dd48151d6abf6eba6e90d5f2cac1ef (diff) | |
parent | db9517269607a758192ce5dd573996bac22b6471 (diff) |
Merge "Support set/clear/get preferred device for capture preset." am: 617d14954d am: db95172696
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1534430
MUST ONLY BE SUBMITTED BY AUTOMERGER
Change-Id: Ic7ff104b7e0aab924ff51950b41ce63ec3a742f3
Diffstat (limited to 'media/java')
-rw-r--r-- | media/java/android/media/AudioDeviceAttributes.java | 25 | ||||
-rw-r--r-- | media/java/android/media/AudioDeviceInfo.java | 45 | ||||
-rwxr-xr-x | media/java/android/media/AudioManager.java | 343 | ||||
-rw-r--r-- | media/java/android/media/AudioSystem.java | 129 | ||||
-rwxr-xr-x | media/java/android/media/IAudioService.aidl | 13 | ||||
-rw-r--r-- | media/java/android/media/ICapturePresetDevicesRoleDispatcher.aidl | 31 | ||||
-rw-r--r-- | media/java/android/media/MediaRecorder.java | 26 |
7 files changed, 610 insertions, 2 deletions
diff --git a/media/java/android/media/AudioDeviceAttributes.java b/media/java/android/media/AudioDeviceAttributes.java index 0ab62c14ab9f..6c8b50037d3d 100644 --- a/media/java/android/media/AudioDeviceAttributes.java +++ b/media/java/android/media/AudioDeviceAttributes.java @@ -72,6 +72,11 @@ public final class AudioDeviceAttributes implements Parcelable { private final @Role int mRole; /** + * The internal audio device type + */ + private final int mNativeType; + + /** * @hide * Constructor from a valid {@link AudioDeviceInfo} * @param deviceInfo the connected audio device from which to obtain the device-identifying @@ -83,6 +88,7 @@ public final class AudioDeviceAttributes implements Parcelable { mRole = deviceInfo.isSink() ? ROLE_OUTPUT : ROLE_INPUT; mType = deviceInfo.getType(); mAddress = deviceInfo.getAddress(); + mNativeType = deviceInfo.getInternalType(); } /** @@ -101,9 +107,12 @@ public final class AudioDeviceAttributes implements Parcelable { } if (role == ROLE_OUTPUT) { AudioDeviceInfo.enforceValidAudioDeviceTypeOut(type); - } - if (role == ROLE_INPUT) { + mNativeType = AudioDeviceInfo.convertDeviceTypeToInternalDevice(type); + } else if (role == ROLE_INPUT) { AudioDeviceInfo.enforceValidAudioDeviceTypeIn(type); + mNativeType = AudioDeviceInfo.convertDeviceTypeToInternalInputDevice(type); + } else { + mNativeType = AudioSystem.DEVICE_NONE; } mRole = role; @@ -115,6 +124,7 @@ public final class AudioDeviceAttributes implements Parcelable { mRole = (nativeType & AudioSystem.DEVICE_BIT_IN) != 0 ? ROLE_INPUT : ROLE_OUTPUT; mType = AudioDeviceInfo.convertInternalDeviceToDeviceType(nativeType); mAddress = address; + mNativeType = nativeType; } /** @@ -147,6 +157,15 @@ public final class AudioDeviceAttributes implements Parcelable { return mAddress; } + /** + * @hide + * Returns the internal device type of a device + * @return the internal device type + */ + public int getInternalType() { + return mNativeType; + } + @Override public int hashCode() { return Objects.hash(mRole, mType, mAddress); @@ -189,12 +208,14 @@ public final class AudioDeviceAttributes implements Parcelable { dest.writeInt(mRole); dest.writeInt(mType); dest.writeString(mAddress); + dest.writeInt(mNativeType); } private AudioDeviceAttributes(@NonNull Parcel in) { mRole = in.readInt(); mType = in.readInt(); mAddress = in.readString(); + mNativeType = in.readInt(); } public static final @NonNull Parcelable.Creator<AudioDeviceAttributes> CREATOR = diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java index ff4a25622bca..f79fc92477f7 100644 --- a/media/java/android/media/AudioDeviceInfo.java +++ b/media/java/android/media/AudioDeviceInfo.java @@ -350,6 +350,14 @@ public final class AudioDeviceInfo { } /** + * @hide + * @return the internal device tyoe + */ + public int getInternalType() { + return mPort.type(); + } + + /** * @return The internal device ID. */ public int getId() { @@ -512,10 +520,21 @@ public final class AudioDeviceInfo { return INT_TO_EXT_DEVICE_MAPPING.get(intDevice, TYPE_UNKNOWN); } + /** @hide */ + public static int convertDeviceTypeToInternalInputDevice(int deviceType) { + return EXT_TO_INT_INPUT_DEVICE_MAPPING.get(deviceType, AudioSystem.DEVICE_NONE); + } + private static final SparseIntArray INT_TO_EXT_DEVICE_MAPPING; private static final SparseIntArray EXT_TO_INT_DEVICE_MAPPING; + /** + * EXT_TO_INT_INPUT_DEVICE_MAPPING aims at mapping external device type to internal input device + * type. + */ + private static final SparseIntArray EXT_TO_INT_INPUT_DEVICE_MAPPING; + static { INT_TO_EXT_DEVICE_MAPPING = new SparseIntArray(); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_EARPIECE, TYPE_BUILTIN_EARPIECE); @@ -600,6 +619,32 @@ public final class AudioDeviceInfo { EXT_TO_INT_DEVICE_MAPPING.put(TYPE_REMOTE_SUBMIX, AudioSystem.DEVICE_OUT_REMOTE_SUBMIX); EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BLE_HEADSET, AudioSystem.DEVICE_OUT_BLE_HEADSET); EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BLE_SPEAKER, AudioSystem.DEVICE_OUT_BLE_SPEAKER); + + // privileges mapping to input device + EXT_TO_INT_INPUT_DEVICE_MAPPING = new SparseIntArray(); + EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_BUILTIN_MIC, AudioSystem.DEVICE_IN_BUILTIN_MIC); + EXT_TO_INT_INPUT_DEVICE_MAPPING.put( + TYPE_BLUETOOTH_SCO, AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET); + EXT_TO_INT_INPUT_DEVICE_MAPPING.put( + TYPE_WIRED_HEADSET, AudioSystem.DEVICE_IN_WIRED_HEADSET); + EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_HDMI, AudioSystem.DEVICE_IN_HDMI); + EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_TELEPHONY, AudioSystem.DEVICE_IN_TELEPHONY_RX); + EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_DOCK, AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET); + EXT_TO_INT_INPUT_DEVICE_MAPPING.put( + TYPE_USB_ACCESSORY, AudioSystem.DEVICE_IN_USB_ACCESSORY); + EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_USB_DEVICE, AudioSystem.DEVICE_IN_USB_DEVICE); + EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_USB_HEADSET, AudioSystem.DEVICE_IN_USB_HEADSET); + EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_FM_TUNER, AudioSystem.DEVICE_IN_FM_TUNER); + EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_TV_TUNER, AudioSystem.DEVICE_IN_TV_TUNER); + EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_LINE_ANALOG, AudioSystem.DEVICE_IN_LINE); + EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_LINE_DIGITAL, AudioSystem.DEVICE_IN_SPDIF); + EXT_TO_INT_INPUT_DEVICE_MAPPING.put( + TYPE_BLUETOOTH_A2DP, AudioSystem.DEVICE_IN_BLUETOOTH_A2DP); + EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_IP, AudioSystem.DEVICE_IN_IP); + EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_BUS, AudioSystem.DEVICE_IN_BUS); + EXT_TO_INT_INPUT_DEVICE_MAPPING.put( + TYPE_REMOTE_SUBMIX, AudioSystem.DEVICE_IN_REMOTE_SUBMIX); + EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_BLE_HEADSET, AudioSystem.DEVICE_IN_BLE_HEADSET); } } diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index b33003737ccd..ed9e5175fb78 100755 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -1948,6 +1948,349 @@ public class AudioManager { } //==================================================================== + // Audio Capture Preset routing + + /** + * @hide + * Set the preferred device for a given capture preset, i.e. the audio routing to be used by + * this capture preset. Note that the device may not be available at the time the preferred + * device is set, but it will be used once made available. + * <p>Use {@link #clearPreferredDevicesForCapturePreset(int)} to cancel setting this preference + * for this capture preset.</p> + * @param capturePreset the audio capture preset whose routing will be affected + * @param device the audio device to route to when available + * @return true if the operation was successful, false otherwise + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + public boolean setPreferredDeviceForCapturePreset(int capturePreset, + @NonNull AudioDeviceAttributes device) { + return setPreferredDevicesForCapturePreset(capturePreset, Arrays.asList(device)); + } + + /** + * @hide + * Remove all the preferred audio devices previously set + * @param capturePreset the audio capture preset whose routing will be affected + * @return true if the operation was successful, false otherwise (invalid capture preset, or no + * device set for example) + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + public boolean clearPreferredDevicesForCapturePreset(int capturePreset) { + if (!MediaRecorder.isValidAudioSource(capturePreset)) { + return false; + } + try { + final int status = getService().clearPreferredDevicesForCapturePreset(capturePreset); + return status == AudioSystem.SUCCESS; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + * Return the preferred devices for an audio capture preset, previously set with + * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)} + * @param capturePreset the capture preset to query + * @return a list that contains preferred devices for that capture preset. + */ + @NonNull + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + public List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset(int capturePreset) { + if (!MediaRecorder.isValidAudioSource(capturePreset)) { + return new ArrayList<AudioDeviceAttributes>(); + } + try { + return getService().getPreferredDevicesForCapturePreset(capturePreset); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + private boolean setPreferredDevicesForCapturePreset( + int capturePreset, @NonNull List<AudioDeviceAttributes> devices) { + Objects.requireNonNull(devices); + if (!MediaRecorder.isValidAudioSource(capturePreset)) { + return false; + } + if (devices.size() != 1) { + throw new IllegalArgumentException( + "Only support setting one preferred devices for capture preset"); + } + for (AudioDeviceAttributes device : devices) { + Objects.requireNonNull(device); + } + try { + final int status = + getService().setPreferredDevicesForCapturePreset(capturePreset, devices); + return status == AudioSystem.SUCCESS; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + * Interface to be notified of changes in the preferred audio devices set for a given capture + * preset. + * <p>Note that this listener will only be invoked whenever + * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)} or + * {@link #clearPreferredDevicesForCapturePreset(int)} causes a change in + * preferred device. It will not be invoked directly after registration with + * {@link #addOnPreferredDevicesForCapturePresetChangedListener( + * Executor, OnPreferredDevicesForCapturePresetChangedListener)} + * to indicate which strategies had preferred devices at the time of registration.</p> + * @see #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes) + * @see #clearPreferredDevicesForCapturePreset(int) + * @see #getPreferredDevicesForCapturePreset(int) + */ + @SystemApi + public interface OnPreferredDevicesForCapturePresetChangedListener { + /** + * Called on the listener to indicate that the preferred audio devices for the given + * capture preset has changed. + * @param capturePreset the capture preset whose preferred device changed + * @param devices a list of newly set preferred audio devices + */ + void onPreferredDevicesForCapturePresetChanged( + int capturePreset, @NonNull List<AudioDeviceAttributes> devices); + } + + /** + * @hide + * Adds a listener for being notified of changes to the capture-preset-preferred audio device. + * @param executor + * @param listener + * @throws SecurityException if the caller doesn't hold the required permission + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + public void addOnPreferredDevicesForCapturePresetChangedListener( + @NonNull @CallbackExecutor Executor executor, + @NonNull OnPreferredDevicesForCapturePresetChangedListener listener) + throws SecurityException { + Objects.requireNonNull(executor); + Objects.requireNonNull(listener); + int status = addOnDevRoleForCapturePresetChangedListener( + executor, listener, AudioSystem.DEVICE_ROLE_PREFERRED); + if (status == AudioSystem.ERROR) { + // This must not happen + throw new RuntimeException("Unknown error happened"); + } + if (status == AudioSystem.BAD_VALUE) { + throw new IllegalArgumentException( + "attempt to call addOnPreferredDevicesForCapturePresetChangedListener() " + + "on a previously registered listener"); + } + } + + /** + * @hide + * Removes a previously added listener of changes to the capture-preset-preferred audio device. + * @param listener + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + public void removeOnPreferredDevicesForCapturePresetChangedListener( + @NonNull OnPreferredDevicesForCapturePresetChangedListener listener) { + Objects.requireNonNull(listener); + int status = removeOnDevRoleForCapturePresetChangedListener( + listener, AudioSystem.DEVICE_ROLE_PREFERRED); + if (status == AudioSystem.ERROR) { + // This must not happen + throw new RuntimeException("Unknown error happened"); + } + if (status == AudioSystem.BAD_VALUE) { + throw new IllegalArgumentException( + "attempt to call removeOnPreferredDevicesForCapturePresetChangedListener() " + + "on an unregistered listener"); + } + } + + private <T> int addOnDevRoleForCapturePresetChangedListener( + @NonNull @CallbackExecutor Executor executor, + @NonNull T listener, int deviceRole) { + Objects.requireNonNull(executor); + Objects.requireNonNull(listener); + DevRoleListeners<T> devRoleListeners = + (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole); + if (devRoleListeners == null) { + return AudioSystem.ERROR; + } + synchronized (devRoleListeners.mDevRoleListenersLock) { + if (devRoleListeners.hasDevRoleListener(listener)) { + return AudioSystem.BAD_VALUE; + } + // lazy initialization of the list of device role listener + if (devRoleListeners.mListenerInfos == null) { + devRoleListeners.mListenerInfos = new ArrayList<>(); + } + final int oldCbCount = devRoleListeners.mListenerInfos.size(); + devRoleListeners.mListenerInfos.add(new DevRoleListenerInfo<T>(executor, listener)); + if (oldCbCount == 0 && devRoleListeners.mListenerInfos.size() > 0) { + // register binder for callbacks + synchronized (mDevRoleForCapturePresetListenersLock) { + int deviceRoleListenerStatus = mDeviceRoleListenersStatus; + mDeviceRoleListenersStatus |= (1 << deviceRole); + if (deviceRoleListenerStatus != 0) { + // There are already device role changed listeners active. + return AudioSystem.SUCCESS; + } + if (mDevicesRoleForCapturePresetDispatcherStub == null) { + mDevicesRoleForCapturePresetDispatcherStub = + new CapturePresetDevicesRoleDispatcherStub(); + } + try { + getService().registerCapturePresetDevicesRoleDispatcher( + mDevicesRoleForCapturePresetDispatcherStub); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + } + return AudioSystem.SUCCESS; + } + + private <T> int removeOnDevRoleForCapturePresetChangedListener( + @NonNull T listener, int deviceRole) { + Objects.requireNonNull(listener); + DevRoleListeners<T> devRoleListeners = + (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole); + if (devRoleListeners == null) { + return AudioSystem.ERROR; + } + synchronized (devRoleListeners.mDevRoleListenersLock) { + if (!devRoleListeners.removeDevRoleListener(listener)) { + return AudioSystem.BAD_VALUE; + } + if (devRoleListeners.mListenerInfos.size() == 0) { + // unregister binder for callbacks + synchronized (mDevRoleForCapturePresetListenersLock) { + mDeviceRoleListenersStatus ^= (1 << deviceRole); + if (mDeviceRoleListenersStatus != 0) { + // There are some other device role changed listeners active. + return AudioSystem.SUCCESS; + } + try { + getService().unregisterCapturePresetDevicesRoleDispatcher( + mDevicesRoleForCapturePresetDispatcherStub); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + } + return AudioSystem.SUCCESS; + } + + private final Map<Integer, Object> mDevRoleForCapturePresetListeners = new HashMap<>(){{ + put(AudioSystem.DEVICE_ROLE_PREFERRED, + new DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>()); + }}; + + private class DevRoleListenerInfo<T> { + final @NonNull Executor mExecutor; + final @NonNull T mListener; + DevRoleListenerInfo(Executor executor, T listener) { + mExecutor = executor; + mListener = listener; + } + } + + private class DevRoleListeners<T> { + private final Object mDevRoleListenersLock = new Object(); + @GuardedBy("mDevRoleListenersLock") + private @Nullable ArrayList<DevRoleListenerInfo<T>> mListenerInfos; + + @GuardedBy("mDevRoleListenersLock") + private @Nullable DevRoleListenerInfo<T> getDevRoleListenerInfo(T listener) { + if (mListenerInfos == null) { + return null; + } + for (DevRoleListenerInfo<T> listenerInfo : mListenerInfos) { + if (listenerInfo.mListener == listener) { + return listenerInfo; + } + } + return null; + } + + @GuardedBy("mDevRoleListenersLock") + private boolean hasDevRoleListener(T listener) { + return getDevRoleListenerInfo(listener) != null; + } + + @GuardedBy("mDevRoleListenersLock") + private boolean removeDevRoleListener(T listener) { + final DevRoleListenerInfo<T> infoToRemove = getDevRoleListenerInfo(listener); + if (infoToRemove != null) { + mListenerInfos.remove(infoToRemove); + return true; + } + return false; + } + } + + private final Object mDevRoleForCapturePresetListenersLock = new Object(); + /** + * Record if there is a listener added for device role change. If there is a listener added for + * a specified device role change, the bit at position `1 << device_role` is set. + */ + @GuardedBy("mDevRoleForCapturePresetListenersLock") + private int mDeviceRoleListenersStatus = 0; + @GuardedBy("mDevRoleForCapturePresetListenersLock") + private CapturePresetDevicesRoleDispatcherStub mDevicesRoleForCapturePresetDispatcherStub; + + private final class CapturePresetDevicesRoleDispatcherStub + extends ICapturePresetDevicesRoleDispatcher.Stub { + + @Override + public void dispatchDevicesRoleChanged( + int capturePreset, int role, List<AudioDeviceAttributes> devices) { + final Object listenersObj = mDevRoleForCapturePresetListeners.get(role); + if (listenersObj == null) { + return; + } + switch (role) { + case AudioSystem.DEVICE_ROLE_PREFERRED: { + final DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener> + listeners = + (DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>) + listenersObj; + final ArrayList<DevRoleListenerInfo< + OnPreferredDevicesForCapturePresetChangedListener>> prefDevListeners; + synchronized (listeners.mDevRoleListenersLock) { + if (listeners.mListenerInfos.isEmpty()) { + return; + } + prefDevListeners = (ArrayList<DevRoleListenerInfo< + OnPreferredDevicesForCapturePresetChangedListener>>) + listeners.mListenerInfos.clone(); + } + final long ident = Binder.clearCallingIdentity(); + try { + for (DevRoleListenerInfo< + OnPreferredDevicesForCapturePresetChangedListener> info : + prefDevListeners) { + info.mExecutor.execute(() -> + info.mListener.onPreferredDevicesForCapturePresetChanged( + capturePreset, devices)); + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } break; + default: + break; + } + } + } + + //==================================================================== // Offload query /** * Returns whether offloaded playback of an audio format is supported on the device. diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 159048548ce8..ef6ba065f414 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -28,6 +28,7 @@ import android.media.audiopolicy.AudioMix; import android.os.Build; import android.telephony.TelephonyManager; import android.util.Log; +import android.util.Pair; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -1750,6 +1751,134 @@ public class AudioSystem public static native int getDevicesForRoleAndStrategy( int strategy, int role, @NonNull List<AudioDeviceAttributes> devices); + // use case routing by capture preset + + private static Pair<int[], String[]> populateInputDevicesTypeAndAddress( + @NonNull List<AudioDeviceAttributes> devices) { + int[] types = new int[devices.size()]; + String[] addresses = new String[devices.size()]; + for (int i = 0; i < devices.size(); ++i) { + types[i] = devices.get(i).getInternalType(); + if (types[i] == AudioSystem.DEVICE_NONE) { + types[i] = AudioDeviceInfo.convertDeviceTypeToInternalInputDevice( + devices.get(i).getType()); + } + addresses[i] = devices.get(i).getAddress(); + } + return new Pair<int[], String[]>(types, addresses); + } + + /** + * @hide + * Set devices as role for capture preset. + * @param capturePreset the capture preset to configure + * @param role the role of the devices + * @param devices the list of devices to be set as role for the given capture preset + * @return {@link #SUCCESS} if successfully set + */ + public static int setDevicesRoleForCapturePreset( + int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devices) { + if (devices.isEmpty()) { + return BAD_VALUE; + } + Pair<int[], String[]> typeAddresses = populateInputDevicesTypeAndAddress(devices); + return setDevicesRoleForCapturePreset( + capturePreset, role, typeAddresses.first, typeAddresses.second); + } + + /** + * @hide + * Set devices as role for capture preset. + * @param capturePreset the capture preset to configure + * @param role the role of the devices + * @param types all device types + * @param addresses all device addresses + * @return {@link #SUCCESS} if successfully set + */ + private static native int setDevicesRoleForCapturePreset( + int capturePreset, int role, @NonNull int[] types, @NonNull String[] addresses); + + /** + * @hide + * Add devices as role for capture preset. + * @param capturePreset the capture preset to configure + * @param role the role of the devices + * @param devices the list of devices to be added as role for the given capture preset + * @return {@link #SUCCESS} if successfully add + */ + public static int addDevicesRoleForCapturePreset( + int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devices) { + if (devices.isEmpty()) { + return BAD_VALUE; + } + Pair<int[], String[]> typeAddresses = populateInputDevicesTypeAndAddress(devices); + return addDevicesRoleForCapturePreset( + capturePreset, role, typeAddresses.first, typeAddresses.second); + } + + /** + * @hide + * Add devices as role for capture preset. + * @param capturePreset the capture preset to configure + * @param role the role of the devices + * @param types all device types + * @param addresses all device addresses + * @return {@link #SUCCESS} if successfully set + */ + private static native int addDevicesRoleForCapturePreset( + int capturePreset, int role, @NonNull int[] types, @NonNull String[] addresses); + + /** + * @hide + * Remove devices as role for the capture preset + * @param capturePreset the capture preset to configure + * @param role the role of the devices + * @param devices the devices to be removed + * @return {@link #SUCCESS} if successfully removed + */ + public static int removeDevicesRoleForCapturePreset( + int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devices) { + if (devices.isEmpty()) { + return BAD_VALUE; + } + Pair<int[], String[]> typeAddresses = populateInputDevicesTypeAndAddress(devices); + return removeDevicesRoleForCapturePreset( + capturePreset, role, typeAddresses.first, typeAddresses.second); + } + + /** + * @hide + * Remove devices as role for capture preset. + * @param capturePreset the capture preset to configure + * @param role the role of the devices + * @param types all device types + * @param addresses all device addresses + * @return {@link #SUCCESS} if successfully set + */ + private static native int removeDevicesRoleForCapturePreset( + int capturePreset, int role, @NonNull int[] types, @NonNull String[] addresses); + + /** + * @hide + * Remove all devices as role for the capture preset + * @param capturePreset the capture preset to configure + * @param role the role of the devices + * @return {@link #SUCCESS} if successfully removed + */ + public static native int clearDevicesRoleForCapturePreset(int capturePreset, int role); + + /** + * @hide + * Query previously set devices as role for a capture preset + * @param capturePreset the capture preset to query for + * @param role the role of the devices + * @param devices a list that will contain the devices of role + * @return {@link #SUCCESS} if there is a preferred device and it was successfully retrieved + * and written to the array + */ + public static native int getDevicesForRoleAndCapturePreset( + int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devices); + // Items shared with audio service /** diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index bc2839ea214d..d9b44cdd20e7 100755 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -26,6 +26,7 @@ import android.media.AudioRoutesInfo; import android.media.IAudioFocusDispatcher; import android.media.IAudioRoutesObserver; import android.media.IAudioServerStateDispatcher; +import android.media.ICapturePresetDevicesRoleDispatcher; import android.media.IPlaybackConfigDispatcher; import android.media.IRecordingConfigDispatcher; import android.media.IRingtonePlayer; @@ -307,4 +308,16 @@ interface IAudioService { // code via IAudioManager.h need to be added to the top section. oneway void setMultiAudioFocusEnabled(in boolean enabled); + + int setPreferredDevicesForCapturePreset( + in int capturePreset, in List<AudioDeviceAttributes> devices); + + int clearPreferredDevicesForCapturePreset(in int capturePreset); + + List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset(in int capturePreset); + + void registerCapturePresetDevicesRoleDispatcher(ICapturePresetDevicesRoleDispatcher dispatcher); + + oneway void unregisterCapturePresetDevicesRoleDispatcher( + ICapturePresetDevicesRoleDispatcher dispatcher); } diff --git a/media/java/android/media/ICapturePresetDevicesRoleDispatcher.aidl b/media/java/android/media/ICapturePresetDevicesRoleDispatcher.aidl new file mode 100644 index 000000000000..5e03e632c4ff --- /dev/null +++ b/media/java/android/media/ICapturePresetDevicesRoleDispatcher.aidl @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2020 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.media.AudioDeviceAttributes; + +/** + * AIDL for AudioService to signal devices role for capture preset updates. + * + * {@hide} + */ +oneway interface ICapturePresetDevicesRoleDispatcher { + + void dispatchDevicesRoleChanged( + int capturePreset, int role, in List<AudioDeviceAttributes> devices); + +} diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java index 73ef31504b74..c61a2eb02921 100644 --- a/media/java/android/media/MediaRecorder.java +++ b/media/java/android/media/MediaRecorder.java @@ -404,6 +404,32 @@ public class MediaRecorder implements AudioRouting, } } + /** + * @hide + * @param source An audio source to test + * @return true if the source is a valid one + */ + public static boolean isValidAudioSource(int source) { + switch(source) { + case AudioSource.MIC: + case AudioSource.VOICE_UPLINK: + case AudioSource.VOICE_DOWNLINK: + case AudioSource.VOICE_CALL: + case AudioSource.CAMCORDER: + case AudioSource.VOICE_RECOGNITION: + case AudioSource.VOICE_COMMUNICATION: + case AudioSource.REMOTE_SUBMIX: + case AudioSource.UNPROCESSED: + case AudioSource.VOICE_PERFORMANCE: + case AudioSource.ECHO_REFERENCE: + case AudioSource.RADIO_TUNER: + case AudioSource.HOTWORD: + return true; + default: + return false; + } + } + /** @hide */ public static final String toLogFriendlyAudioSource(int source) { switch(source) { |