Loading core/api/current.txt +4 −3 Original line number Diff line number Diff line Loading @@ -20177,14 +20177,15 @@ package android.media { method public void adjustStreamVolume(int, int, int); method public void adjustSuggestedStreamVolume(int, int, int); method public void adjustVolume(int, int); method public void clearDeviceForCommunication(); method public void clearCommunicationDevice(); method public void dispatchMediaKeyEvent(android.view.KeyEvent); method public int generateAudioSessionId(); method @NonNull public java.util.List<android.media.AudioPlaybackConfiguration> getActivePlaybackConfigurations(); method @NonNull public java.util.List<android.media.AudioRecordingConfiguration> getActiveRecordingConfigurations(); method public int getAllowedCapturePolicy(); method public int getAudioHwSyncForSession(int); method @Nullable public android.media.AudioDeviceInfo getDeviceForCommunication(); method @NonNull public java.util.List<android.media.AudioDeviceInfo> getAvailableCommunicationDevices(); method @Nullable public android.media.AudioDeviceInfo getCommunicationDevice(); method public android.media.AudioDeviceInfo[] getDevices(int); method public java.util.List<android.media.MicrophoneInfo> getMicrophones() throws java.io.IOException; method public int getMode(); Loading Loading @@ -20226,7 +20227,7 @@ package android.media { method public void setAllowedCapturePolicy(int); method @Deprecated public void setBluetoothA2dpOn(boolean); method public void setBluetoothScoOn(boolean); method public boolean setDeviceForCommunication(@NonNull android.media.AudioDeviceInfo); method public boolean setCommunicationDevice(@NonNull android.media.AudioDeviceInfo); method public void setMicrophoneMute(boolean); method public void setMode(int); method public void setParameters(String); media/java/android/media/AudioManager.java +77 −32 Original line number Diff line number Diff line Loading @@ -7062,20 +7062,12 @@ public class AudioManager { * Selects the audio device that should be used for communication use cases, for instance voice * or video calls. This method can be used by voice or video chat applications to select a * different audio device than the one selected by default by the platform. * <p>The device selection is expressed as an {@link AudioDeviceInfo}, of role sink * ({@link AudioDeviceInfo#isSink()} is <code>true</code>) and of one of the following types: * <ul> * <li> {@link AudioDeviceInfo#TYPE_BUILTIN_EARPIECE} * <li> {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER} * <li> {@link AudioDeviceInfo#TYPE_WIRED_HEADSET} * <li> {@link AudioDeviceInfo#TYPE_BLUETOOTH_SCO} * <li> {@link AudioDeviceInfo#TYPE_USB_HEADSET} * <li> {@link AudioDeviceInfo#TYPE_BLE_HEADSET} * </ul> * The selection is active as long as the requesting application lives, until * {@link #clearDeviceForCommunication} is called or until the device is disconnected. * <p>The device selection is expressed as an {@link AudioDeviceInfo} among devices returned by * {@link #getAvailableCommunicationDevices()}. * The selection is active as long as the requesting application process lives, until * {@link #clearCommunicationDevice} is called or until the device is disconnected. * It is therefore important for applications to clear the request when a call ends or the * application is paused. * the requesting activity or service is stopped or destroyed. * <p>In case of simultaneous requests by multiple applications the priority is given to the * application currently controlling the audio mode (see {@link #setMode(int)}). This is the * latest application having selected mode {@link #MODE_IN_COMMUNICATION} or mode Loading @@ -7097,7 +7089,7 @@ public class AudioManager { * AudioManager audioManager = Context.getSystemService(AudioManager.class); * try { * AudioDeviceInfo speakerDevice = null; * AudioDeviceInfo[] devices = audioManager.getDevices(GET_DEVICES_OUTPUTS); * List<AudioDeviceInfo> devices = audioManager.getAvailableCommunicationDevices(); * for (AudioDeviceInfo device : devices) { * if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) { * speakerDevice = device; Loading @@ -7106,12 +7098,12 @@ public class AudioManager { * } * if (speakerDevice != null) { * // Turn speakerphone ON. * boolean result = audioManager.setDeviceForCommunication(speakerDevice); * boolean result = audioManager.setCommunicationDevice(speakerDevice); * if (!result) { * // Handle error. * } * // Turn speakerphone OFF. * audioManager.clearDeviceForCommunication(); * audioManager.clearCommunicationDevice(); * } * } catch (IllegalArgumentException e) { * // Handle exception. Loading @@ -7121,13 +7113,13 @@ public class AudioManager { * @return <code>true</code> if the request was accepted, <code>false</code> otherwise. * @throws IllegalArgumentException If an invalid device is specified. */ public boolean setDeviceForCommunication(@NonNull AudioDeviceInfo device) { public boolean setCommunicationDevice(@NonNull AudioDeviceInfo device) { Objects.requireNonNull(device); try { if (device.getId() == 0) { throw new IllegalArgumentException("In valid device: " + device); } return getService().setDeviceForCommunication(mICallBack, device.getId()); return getService().setCommunicationDevice(mICallBack, device.getId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading @@ -7135,11 +7127,11 @@ public class AudioManager { /** * Cancels previous communication device selection made with * {@link #setDeviceForCommunication(AudioDeviceInfo)}. * {@link #setCommunicationDevice(AudioDeviceInfo)}. */ public void clearDeviceForCommunication() { public void clearCommunicationDevice() { try { getService().setDeviceForCommunication(mICallBack, 0); getService().setCommunicationDevice(mICallBack, 0); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading @@ -7153,14 +7145,38 @@ public class AudioManager { * <li> {@link #isSpeakerphoneOn()} * </ul> * @return an {@link AudioDeviceInfo} indicating which audio device is * currently selected or communication use cases or null if default selection * currently selected for communication use cases. Can be null on platforms * not supporting {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}. * is used. */ @Nullable public AudioDeviceInfo getDeviceForCommunication() { public AudioDeviceInfo getCommunicationDevice() { try { return getDeviceForPortId( getService().getDeviceForCommunication(), GET_DEVICES_OUTPUTS); getService().getCommunicationDevice(), GET_DEVICES_OUTPUTS); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Returns a list of audio devices that can be selected for communication use cases via * {@link #setCommunicationDevice(AudioDeviceInfo)}. * @return a list of {@link AudioDeviceInfo} suitable for use with setCommunicationDevice(). */ @NonNull public List<AudioDeviceInfo> getAvailableCommunicationDevices() { try { ArrayList<AudioDeviceInfo> devices = new ArrayList<>(); int[] portIds = getService().getAvailableCommunicationDeviceIds(); for (int portId : portIds) { AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS); if (device == null) { continue; } devices.add(device); } return devices; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading @@ -7183,30 +7199,59 @@ public class AudioManager { @Nullable public static AudioDeviceInfo getDeviceInfoFromType( @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) { return getDeviceInfoFromTypeAndAddress(deviceType, null); } /** * @hide * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type and * address provided. * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class, * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}. * If a null address is provided, the matching will happen on the type only. * The method will return null if no device of the provided type and address is connected. * If more than one device of the provided type is connected, an object corresponding to the * first device encountered in the enumeration list will be returned. * @param type The device device for which an <code>AudioDeviceInfo</code> * object is queried. * @param address The device address for which an <code>AudioDeviceInfo</code> * object is queried or null if requesting match on type only. * @return An AudioDeviceInfo object or null if no matching device is connected. * @throws IllegalArgumentException If an invalid device type is specified. */ @Nullable public static AudioDeviceInfo getDeviceInfoFromTypeAndAddress( @AudioDeviceInfo.AudioDeviceTypeOut int type, @Nullable String address) { AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_OUTPUTS); AudioDeviceInfo deviceForType = null; for (AudioDeviceInfo device : devices) { if (device.getType() == deviceType) { if (device.getType() == type) { deviceForType = device; if (address == null || address.equals(device.getAddress())) { return device; } } return null; } return deviceForType; } /** * Listener registered by client to be notified upon communication audio device change. * See {@link #setDeviceForCommunication(AudioDeviceInfo)}. * See {@link #setCommunicationDevice(AudioDeviceInfo)}. */ public interface OnCommunicationDeviceChangedListener { /** * Callback method called upon communication audio device change. * @param device the audio device selected for communication use cases * @param device the audio device requested for communication use cases. * Can be null on platforms not supporting * {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}. */ void onCommunicationDeviceChanged(@Nullable AudioDeviceInfo device); } /** * Adds a listener for being notified of changes to the communication audio device. * See {@link #setDeviceForCommunication(AudioDeviceInfo)}. * See {@link #setCommunicationDevice(AudioDeviceInfo)}. * @param executor * @param listener */ Loading Loading @@ -7243,7 +7288,7 @@ public class AudioManager { /** * Removes a previously added listener of changes to the communication audio device. * See {@link #setDeviceForCommunication(AudioDeviceInfo)}. * See {@link #setCommunicationDevice(AudioDeviceInfo)}. * @param listener */ public void removeOnCommunicationDeviceChangedListener( Loading media/java/android/media/IAudioService.aidl +4 −2 Original line number Diff line number Diff line Loading @@ -342,9 +342,11 @@ interface IAudioService { int getDevicesForStream(in int streamType); boolean setDeviceForCommunication(IBinder cb, int portId); int[] getAvailableCommunicationDeviceIds(); int getDeviceForCommunication(); boolean setCommunicationDevice(IBinder cb, int portId); int getCommunicationDevice(); void registerCommunicationDeviceDispatcher(ICommunicationDeviceDispatcher dispatcher); Loading services/core/java/com/android/server/audio/AudioDeviceBroker.java +30 −18 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.bluetooth.BluetoothProfile; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.media.AudioAttributes; import android.media.AudioDeviceAttributes; import android.media.AudioDeviceInfo; import android.media.AudioManager; Loading Loading @@ -80,7 +81,7 @@ import java.util.concurrent.atomic.AtomicBoolean; private final @NonNull Context mContext; /** Forced device usage for communications sent to AudioSystem */ private AudioDeviceAttributes mPreferredDeviceforComm; private AudioDeviceAttributes mPreferredCommunicationDevice; private int mCommunicationStrategyId = -1; // Manages all connected devices, only ever accessed on the message loop Loading Loading @@ -152,7 +153,7 @@ import java.util.concurrent.atomic.AtomicBoolean; private void init() { setupMessaging(mContext); mPreferredDeviceforComm = null; mPreferredCommunicationDevice = null; initCommunicationStrategyId(); mSystemServer.registerUserStartedReceiver(mContext); Loading Loading @@ -260,11 +261,11 @@ import java.util.concurrent.atomic.AtomicBoolean; * @param device Device selected or null to unselect. * @param eventSource for logging purposes */ /*package*/ boolean setDeviceForCommunication( /*package*/ boolean setCommunicationDevice( IBinder cb, int pid, AudioDeviceInfo device, String eventSource) { if (AudioService.DEBUG_COMM_RTE) { Log.v(TAG, "setDeviceForCommunication, device: " + device + ", pid: " + pid); Log.v(TAG, "setCommunicationDevice, device: " + device + ", pid: " + pid); } synchronized (mSetModeLock) { Loading Loading @@ -385,13 +386,21 @@ import java.util.concurrent.atomic.AtomicBoolean; * Returns the device currently requested for communication use case. * @return AudioDeviceInfo the requested device for communication. */ AudioDeviceInfo getDeviceForCommunication() { AudioDeviceInfo getCommunicationDevice() { synchronized (mDeviceStateLock) { AudioDeviceAttributes device = requestedCommunicationDevice(); if (device == null) { AudioAttributes attr = AudioProductStrategy.getAudioAttributesForStrategyWithLegacyStreamType( AudioSystem.STREAM_VOICE_CALL); List<AudioDeviceAttributes> devices = AudioSystem.getDevicesForAttributes(attr); if (devices.isEmpty()) { return null; } return AudioManager.getDeviceInfoFromType(device.getType()); device = devices.get(0); } return AudioManager.getDeviceInfoFromTypeAndAddress( device.getType(), device.getAddress()); } } Loading Loading @@ -736,8 +745,8 @@ import java.util.concurrent.atomic.AtomicBoolean; @GuardedBy("mDeviceStateLock") private void dispatchCommunicationDevice() { AudioDeviceInfo device = getDeviceForCommunication(); int portId = (getDeviceForCommunication() == null) ? 0 : device.getId(); AudioDeviceInfo device = getCommunicationDevice(); int portId = (getCommunicationDevice() == null) ? 0 : device.getId(); if (portId == mCurCommunicationPortId) { return; } Loading Loading @@ -1010,8 +1019,11 @@ import java.util.concurrent.atomic.AtomicBoolean; pw.println(" " + prefix + "pid: " + cl.getPid() + " device: " + cl.getDevice() + " cb: " + cl.getBinder()); }); pw.println("\n" + prefix + "mPreferredDeviceforComm: " + mPreferredDeviceforComm); pw.println("\n" + prefix + "mPreferredCommunicationDevice: " + mPreferredCommunicationDevice); pw.println(prefix + "Selected Communication Device: " + ((getCommunicationDevice() == null) ? "None" : new AudioDeviceAttributes(getCommunicationDevice()))); pw.println(prefix + "mCommunicationStrategyId: " + mCommunicationStrategyId); Loading Loading @@ -1692,24 +1704,24 @@ import java.util.concurrent.atomic.AtomicBoolean; // @GuardedBy("mSetModeLock") @GuardedBy("mDeviceStateLock") private void onUpdateCommunicationRoute(String eventSource) { mPreferredDeviceforComm = getPreferredDeviceForComm(); mPreferredCommunicationDevice = getPreferredDeviceForComm(); if (AudioService.DEBUG_COMM_RTE) { Log.v(TAG, "onUpdateCommunicationRoute, mPreferredDeviceforComm: " + mPreferredDeviceforComm + " eventSource: " + eventSource); Log.v(TAG, "onUpdateCommunicationRoute, mPreferredCommunicationDevice: " + mPreferredCommunicationDevice + " eventSource: " + eventSource); } if (mPreferredDeviceforComm == null if (mPreferredCommunicationDevice == null || !AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains( mPreferredDeviceforComm.getInternalType())) { mPreferredCommunicationDevice.getInternalType())) { AudioSystem.setParameters("BT_SCO=off"); } else { AudioSystem.setParameters("BT_SCO=on"); } if (mPreferredDeviceforComm == null) { if (mPreferredCommunicationDevice == null) { postRemovePreferredDevicesForStrategy(mCommunicationStrategyId); } else { postSetPreferredDevicesForStrategy( mCommunicationStrategyId, Arrays.asList(mPreferredDeviceforComm)); mCommunicationStrategyId, Arrays.asList(mPreferredCommunicationDevice)); } mAudioService.postUpdateRingerModeServiceInt(); dispatchCommunicationDevice(); Loading services/core/java/com/android/server/audio/AudioService.java +20 −9 Original line number Diff line number Diff line Loading @@ -4761,8 +4761,19 @@ public class AudioService extends IAudioService.Stub return false; } /** @see AudioManager#setDeviceForCommunication(int) */ public boolean setDeviceForCommunication(IBinder cb, int portId) { /** @see AudioManager#getAvailableCommunicationDevices(int) */ public int[] getAvailableCommunicationDeviceIds() { ArrayList<Integer> deviceIds = new ArrayList<>(); AudioDeviceInfo[] devices = AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_OUTPUTS); for (AudioDeviceInfo device : devices) { if (isValidCommunicationDevice(device)) { deviceIds.add(device.getId()); } } return deviceIds.stream().mapToInt(Integer::intValue).toArray(); } /** @see AudioManager#setCommunicationDevice(int) */ public boolean setCommunicationDevice(IBinder cb, int portId) { final int uid = Binder.getCallingUid(); final int pid = Binder.getCallingPid(); Loading @@ -4776,7 +4787,7 @@ public class AudioService extends IAudioService.Stub throw new IllegalArgumentException("invalid device type " + device.getType()); } } final String eventSource = new StringBuilder("setDeviceForCommunication(") final String eventSource = new StringBuilder("setCommunicationDevice(") .append(") from u/pid:").append(uid).append("/") .append(pid).toString(); Loading @@ -4786,7 +4797,7 @@ public class AudioService extends IAudioService.Stub deviceType = device.getPort().type(); deviceAddress = device.getAddress(); } else { AudioDeviceInfo curDevice = mDeviceBroker.getDeviceForCommunication(); AudioDeviceInfo curDevice = mDeviceBroker.getCommunicationDevice(); if (curDevice != null) { deviceType = curDevice.getPort().type(); deviceAddress = curDevice.getAddress(); Loading @@ -4796,7 +4807,7 @@ public class AudioService extends IAudioService.Stub // was selected if (deviceType != AudioSystem.DEVICE_OUT_DEFAULT) { new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE + MediaMetrics.SEPARATOR + "setDeviceForCommunication") + MediaMetrics.SEPARATOR + "setCommunicationDevice") .set(MediaMetrics.Property.DEVICE, AudioSystem.getDeviceName(deviceType)) .set(MediaMetrics.Property.ADDRESS, deviceAddress) Loading @@ -4807,15 +4818,15 @@ public class AudioService extends IAudioService.Stub final long ident = Binder.clearCallingIdentity(); boolean status = mDeviceBroker.setDeviceForCommunication(cb, pid, device, eventSource); mDeviceBroker.setCommunicationDevice(cb, pid, device, eventSource); Binder.restoreCallingIdentity(ident); return status; } /** @see AudioManager#getDeviceForCommunication() */ public int getDeviceForCommunication() { /** @see AudioManager#getCommunicationDevice() */ public int getCommunicationDevice() { final long ident = Binder.clearCallingIdentity(); AudioDeviceInfo device = mDeviceBroker.getDeviceForCommunication(); AudioDeviceInfo device = mDeviceBroker.getCommunicationDevice(); Binder.restoreCallingIdentity(ident); if (device == null) { return 0; Loading Loading
core/api/current.txt +4 −3 Original line number Diff line number Diff line Loading @@ -20177,14 +20177,15 @@ package android.media { method public void adjustStreamVolume(int, int, int); method public void adjustSuggestedStreamVolume(int, int, int); method public void adjustVolume(int, int); method public void clearDeviceForCommunication(); method public void clearCommunicationDevice(); method public void dispatchMediaKeyEvent(android.view.KeyEvent); method public int generateAudioSessionId(); method @NonNull public java.util.List<android.media.AudioPlaybackConfiguration> getActivePlaybackConfigurations(); method @NonNull public java.util.List<android.media.AudioRecordingConfiguration> getActiveRecordingConfigurations(); method public int getAllowedCapturePolicy(); method public int getAudioHwSyncForSession(int); method @Nullable public android.media.AudioDeviceInfo getDeviceForCommunication(); method @NonNull public java.util.List<android.media.AudioDeviceInfo> getAvailableCommunicationDevices(); method @Nullable public android.media.AudioDeviceInfo getCommunicationDevice(); method public android.media.AudioDeviceInfo[] getDevices(int); method public java.util.List<android.media.MicrophoneInfo> getMicrophones() throws java.io.IOException; method public int getMode(); Loading Loading @@ -20226,7 +20227,7 @@ package android.media { method public void setAllowedCapturePolicy(int); method @Deprecated public void setBluetoothA2dpOn(boolean); method public void setBluetoothScoOn(boolean); method public boolean setDeviceForCommunication(@NonNull android.media.AudioDeviceInfo); method public boolean setCommunicationDevice(@NonNull android.media.AudioDeviceInfo); method public void setMicrophoneMute(boolean); method public void setMode(int); method public void setParameters(String);
media/java/android/media/AudioManager.java +77 −32 Original line number Diff line number Diff line Loading @@ -7062,20 +7062,12 @@ public class AudioManager { * Selects the audio device that should be used for communication use cases, for instance voice * or video calls. This method can be used by voice or video chat applications to select a * different audio device than the one selected by default by the platform. * <p>The device selection is expressed as an {@link AudioDeviceInfo}, of role sink * ({@link AudioDeviceInfo#isSink()} is <code>true</code>) and of one of the following types: * <ul> * <li> {@link AudioDeviceInfo#TYPE_BUILTIN_EARPIECE} * <li> {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER} * <li> {@link AudioDeviceInfo#TYPE_WIRED_HEADSET} * <li> {@link AudioDeviceInfo#TYPE_BLUETOOTH_SCO} * <li> {@link AudioDeviceInfo#TYPE_USB_HEADSET} * <li> {@link AudioDeviceInfo#TYPE_BLE_HEADSET} * </ul> * The selection is active as long as the requesting application lives, until * {@link #clearDeviceForCommunication} is called or until the device is disconnected. * <p>The device selection is expressed as an {@link AudioDeviceInfo} among devices returned by * {@link #getAvailableCommunicationDevices()}. * The selection is active as long as the requesting application process lives, until * {@link #clearCommunicationDevice} is called or until the device is disconnected. * It is therefore important for applications to clear the request when a call ends or the * application is paused. * the requesting activity or service is stopped or destroyed. * <p>In case of simultaneous requests by multiple applications the priority is given to the * application currently controlling the audio mode (see {@link #setMode(int)}). This is the * latest application having selected mode {@link #MODE_IN_COMMUNICATION} or mode Loading @@ -7097,7 +7089,7 @@ public class AudioManager { * AudioManager audioManager = Context.getSystemService(AudioManager.class); * try { * AudioDeviceInfo speakerDevice = null; * AudioDeviceInfo[] devices = audioManager.getDevices(GET_DEVICES_OUTPUTS); * List<AudioDeviceInfo> devices = audioManager.getAvailableCommunicationDevices(); * for (AudioDeviceInfo device : devices) { * if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) { * speakerDevice = device; Loading @@ -7106,12 +7098,12 @@ public class AudioManager { * } * if (speakerDevice != null) { * // Turn speakerphone ON. * boolean result = audioManager.setDeviceForCommunication(speakerDevice); * boolean result = audioManager.setCommunicationDevice(speakerDevice); * if (!result) { * // Handle error. * } * // Turn speakerphone OFF. * audioManager.clearDeviceForCommunication(); * audioManager.clearCommunicationDevice(); * } * } catch (IllegalArgumentException e) { * // Handle exception. Loading @@ -7121,13 +7113,13 @@ public class AudioManager { * @return <code>true</code> if the request was accepted, <code>false</code> otherwise. * @throws IllegalArgumentException If an invalid device is specified. */ public boolean setDeviceForCommunication(@NonNull AudioDeviceInfo device) { public boolean setCommunicationDevice(@NonNull AudioDeviceInfo device) { Objects.requireNonNull(device); try { if (device.getId() == 0) { throw new IllegalArgumentException("In valid device: " + device); } return getService().setDeviceForCommunication(mICallBack, device.getId()); return getService().setCommunicationDevice(mICallBack, device.getId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading @@ -7135,11 +7127,11 @@ public class AudioManager { /** * Cancels previous communication device selection made with * {@link #setDeviceForCommunication(AudioDeviceInfo)}. * {@link #setCommunicationDevice(AudioDeviceInfo)}. */ public void clearDeviceForCommunication() { public void clearCommunicationDevice() { try { getService().setDeviceForCommunication(mICallBack, 0); getService().setCommunicationDevice(mICallBack, 0); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading @@ -7153,14 +7145,38 @@ public class AudioManager { * <li> {@link #isSpeakerphoneOn()} * </ul> * @return an {@link AudioDeviceInfo} indicating which audio device is * currently selected or communication use cases or null if default selection * currently selected for communication use cases. Can be null on platforms * not supporting {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}. * is used. */ @Nullable public AudioDeviceInfo getDeviceForCommunication() { public AudioDeviceInfo getCommunicationDevice() { try { return getDeviceForPortId( getService().getDeviceForCommunication(), GET_DEVICES_OUTPUTS); getService().getCommunicationDevice(), GET_DEVICES_OUTPUTS); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Returns a list of audio devices that can be selected for communication use cases via * {@link #setCommunicationDevice(AudioDeviceInfo)}. * @return a list of {@link AudioDeviceInfo} suitable for use with setCommunicationDevice(). */ @NonNull public List<AudioDeviceInfo> getAvailableCommunicationDevices() { try { ArrayList<AudioDeviceInfo> devices = new ArrayList<>(); int[] portIds = getService().getAvailableCommunicationDeviceIds(); for (int portId : portIds) { AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS); if (device == null) { continue; } devices.add(device); } return devices; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading @@ -7183,30 +7199,59 @@ public class AudioManager { @Nullable public static AudioDeviceInfo getDeviceInfoFromType( @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) { return getDeviceInfoFromTypeAndAddress(deviceType, null); } /** * @hide * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type and * address provided. * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class, * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}. * If a null address is provided, the matching will happen on the type only. * The method will return null if no device of the provided type and address is connected. * If more than one device of the provided type is connected, an object corresponding to the * first device encountered in the enumeration list will be returned. * @param type The device device for which an <code>AudioDeviceInfo</code> * object is queried. * @param address The device address for which an <code>AudioDeviceInfo</code> * object is queried or null if requesting match on type only. * @return An AudioDeviceInfo object or null if no matching device is connected. * @throws IllegalArgumentException If an invalid device type is specified. */ @Nullable public static AudioDeviceInfo getDeviceInfoFromTypeAndAddress( @AudioDeviceInfo.AudioDeviceTypeOut int type, @Nullable String address) { AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_OUTPUTS); AudioDeviceInfo deviceForType = null; for (AudioDeviceInfo device : devices) { if (device.getType() == deviceType) { if (device.getType() == type) { deviceForType = device; if (address == null || address.equals(device.getAddress())) { return device; } } return null; } return deviceForType; } /** * Listener registered by client to be notified upon communication audio device change. * See {@link #setDeviceForCommunication(AudioDeviceInfo)}. * See {@link #setCommunicationDevice(AudioDeviceInfo)}. */ public interface OnCommunicationDeviceChangedListener { /** * Callback method called upon communication audio device change. * @param device the audio device selected for communication use cases * @param device the audio device requested for communication use cases. * Can be null on platforms not supporting * {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}. */ void onCommunicationDeviceChanged(@Nullable AudioDeviceInfo device); } /** * Adds a listener for being notified of changes to the communication audio device. * See {@link #setDeviceForCommunication(AudioDeviceInfo)}. * See {@link #setCommunicationDevice(AudioDeviceInfo)}. * @param executor * @param listener */ Loading Loading @@ -7243,7 +7288,7 @@ public class AudioManager { /** * Removes a previously added listener of changes to the communication audio device. * See {@link #setDeviceForCommunication(AudioDeviceInfo)}. * See {@link #setCommunicationDevice(AudioDeviceInfo)}. * @param listener */ public void removeOnCommunicationDeviceChangedListener( Loading
media/java/android/media/IAudioService.aidl +4 −2 Original line number Diff line number Diff line Loading @@ -342,9 +342,11 @@ interface IAudioService { int getDevicesForStream(in int streamType); boolean setDeviceForCommunication(IBinder cb, int portId); int[] getAvailableCommunicationDeviceIds(); int getDeviceForCommunication(); boolean setCommunicationDevice(IBinder cb, int portId); int getCommunicationDevice(); void registerCommunicationDeviceDispatcher(ICommunicationDeviceDispatcher dispatcher); Loading
services/core/java/com/android/server/audio/AudioDeviceBroker.java +30 −18 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.bluetooth.BluetoothProfile; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.media.AudioAttributes; import android.media.AudioDeviceAttributes; import android.media.AudioDeviceInfo; import android.media.AudioManager; Loading Loading @@ -80,7 +81,7 @@ import java.util.concurrent.atomic.AtomicBoolean; private final @NonNull Context mContext; /** Forced device usage for communications sent to AudioSystem */ private AudioDeviceAttributes mPreferredDeviceforComm; private AudioDeviceAttributes mPreferredCommunicationDevice; private int mCommunicationStrategyId = -1; // Manages all connected devices, only ever accessed on the message loop Loading Loading @@ -152,7 +153,7 @@ import java.util.concurrent.atomic.AtomicBoolean; private void init() { setupMessaging(mContext); mPreferredDeviceforComm = null; mPreferredCommunicationDevice = null; initCommunicationStrategyId(); mSystemServer.registerUserStartedReceiver(mContext); Loading Loading @@ -260,11 +261,11 @@ import java.util.concurrent.atomic.AtomicBoolean; * @param device Device selected or null to unselect. * @param eventSource for logging purposes */ /*package*/ boolean setDeviceForCommunication( /*package*/ boolean setCommunicationDevice( IBinder cb, int pid, AudioDeviceInfo device, String eventSource) { if (AudioService.DEBUG_COMM_RTE) { Log.v(TAG, "setDeviceForCommunication, device: " + device + ", pid: " + pid); Log.v(TAG, "setCommunicationDevice, device: " + device + ", pid: " + pid); } synchronized (mSetModeLock) { Loading Loading @@ -385,13 +386,21 @@ import java.util.concurrent.atomic.AtomicBoolean; * Returns the device currently requested for communication use case. * @return AudioDeviceInfo the requested device for communication. */ AudioDeviceInfo getDeviceForCommunication() { AudioDeviceInfo getCommunicationDevice() { synchronized (mDeviceStateLock) { AudioDeviceAttributes device = requestedCommunicationDevice(); if (device == null) { AudioAttributes attr = AudioProductStrategy.getAudioAttributesForStrategyWithLegacyStreamType( AudioSystem.STREAM_VOICE_CALL); List<AudioDeviceAttributes> devices = AudioSystem.getDevicesForAttributes(attr); if (devices.isEmpty()) { return null; } return AudioManager.getDeviceInfoFromType(device.getType()); device = devices.get(0); } return AudioManager.getDeviceInfoFromTypeAndAddress( device.getType(), device.getAddress()); } } Loading Loading @@ -736,8 +745,8 @@ import java.util.concurrent.atomic.AtomicBoolean; @GuardedBy("mDeviceStateLock") private void dispatchCommunicationDevice() { AudioDeviceInfo device = getDeviceForCommunication(); int portId = (getDeviceForCommunication() == null) ? 0 : device.getId(); AudioDeviceInfo device = getCommunicationDevice(); int portId = (getCommunicationDevice() == null) ? 0 : device.getId(); if (portId == mCurCommunicationPortId) { return; } Loading Loading @@ -1010,8 +1019,11 @@ import java.util.concurrent.atomic.AtomicBoolean; pw.println(" " + prefix + "pid: " + cl.getPid() + " device: " + cl.getDevice() + " cb: " + cl.getBinder()); }); pw.println("\n" + prefix + "mPreferredDeviceforComm: " + mPreferredDeviceforComm); pw.println("\n" + prefix + "mPreferredCommunicationDevice: " + mPreferredCommunicationDevice); pw.println(prefix + "Selected Communication Device: " + ((getCommunicationDevice() == null) ? "None" : new AudioDeviceAttributes(getCommunicationDevice()))); pw.println(prefix + "mCommunicationStrategyId: " + mCommunicationStrategyId); Loading Loading @@ -1692,24 +1704,24 @@ import java.util.concurrent.atomic.AtomicBoolean; // @GuardedBy("mSetModeLock") @GuardedBy("mDeviceStateLock") private void onUpdateCommunicationRoute(String eventSource) { mPreferredDeviceforComm = getPreferredDeviceForComm(); mPreferredCommunicationDevice = getPreferredDeviceForComm(); if (AudioService.DEBUG_COMM_RTE) { Log.v(TAG, "onUpdateCommunicationRoute, mPreferredDeviceforComm: " + mPreferredDeviceforComm + " eventSource: " + eventSource); Log.v(TAG, "onUpdateCommunicationRoute, mPreferredCommunicationDevice: " + mPreferredCommunicationDevice + " eventSource: " + eventSource); } if (mPreferredDeviceforComm == null if (mPreferredCommunicationDevice == null || !AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains( mPreferredDeviceforComm.getInternalType())) { mPreferredCommunicationDevice.getInternalType())) { AudioSystem.setParameters("BT_SCO=off"); } else { AudioSystem.setParameters("BT_SCO=on"); } if (mPreferredDeviceforComm == null) { if (mPreferredCommunicationDevice == null) { postRemovePreferredDevicesForStrategy(mCommunicationStrategyId); } else { postSetPreferredDevicesForStrategy( mCommunicationStrategyId, Arrays.asList(mPreferredDeviceforComm)); mCommunicationStrategyId, Arrays.asList(mPreferredCommunicationDevice)); } mAudioService.postUpdateRingerModeServiceInt(); dispatchCommunicationDevice(); Loading
services/core/java/com/android/server/audio/AudioService.java +20 −9 Original line number Diff line number Diff line Loading @@ -4761,8 +4761,19 @@ public class AudioService extends IAudioService.Stub return false; } /** @see AudioManager#setDeviceForCommunication(int) */ public boolean setDeviceForCommunication(IBinder cb, int portId) { /** @see AudioManager#getAvailableCommunicationDevices(int) */ public int[] getAvailableCommunicationDeviceIds() { ArrayList<Integer> deviceIds = new ArrayList<>(); AudioDeviceInfo[] devices = AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_OUTPUTS); for (AudioDeviceInfo device : devices) { if (isValidCommunicationDevice(device)) { deviceIds.add(device.getId()); } } return deviceIds.stream().mapToInt(Integer::intValue).toArray(); } /** @see AudioManager#setCommunicationDevice(int) */ public boolean setCommunicationDevice(IBinder cb, int portId) { final int uid = Binder.getCallingUid(); final int pid = Binder.getCallingPid(); Loading @@ -4776,7 +4787,7 @@ public class AudioService extends IAudioService.Stub throw new IllegalArgumentException("invalid device type " + device.getType()); } } final String eventSource = new StringBuilder("setDeviceForCommunication(") final String eventSource = new StringBuilder("setCommunicationDevice(") .append(") from u/pid:").append(uid).append("/") .append(pid).toString(); Loading @@ -4786,7 +4797,7 @@ public class AudioService extends IAudioService.Stub deviceType = device.getPort().type(); deviceAddress = device.getAddress(); } else { AudioDeviceInfo curDevice = mDeviceBroker.getDeviceForCommunication(); AudioDeviceInfo curDevice = mDeviceBroker.getCommunicationDevice(); if (curDevice != null) { deviceType = curDevice.getPort().type(); deviceAddress = curDevice.getAddress(); Loading @@ -4796,7 +4807,7 @@ public class AudioService extends IAudioService.Stub // was selected if (deviceType != AudioSystem.DEVICE_OUT_DEFAULT) { new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE + MediaMetrics.SEPARATOR + "setDeviceForCommunication") + MediaMetrics.SEPARATOR + "setCommunicationDevice") .set(MediaMetrics.Property.DEVICE, AudioSystem.getDeviceName(deviceType)) .set(MediaMetrics.Property.ADDRESS, deviceAddress) Loading @@ -4807,15 +4818,15 @@ public class AudioService extends IAudioService.Stub final long ident = Binder.clearCallingIdentity(); boolean status = mDeviceBroker.setDeviceForCommunication(cb, pid, device, eventSource); mDeviceBroker.setCommunicationDevice(cb, pid, device, eventSource); Binder.restoreCallingIdentity(ident); return status; } /** @see AudioManager#getDeviceForCommunication() */ public int getDeviceForCommunication() { /** @see AudioManager#getCommunicationDevice() */ public int getCommunicationDevice() { final long ident = Binder.clearCallingIdentity(); AudioDeviceInfo device = mDeviceBroker.getDeviceForCommunication(); AudioDeviceInfo device = mDeviceBroker.getCommunicationDevice(); Binder.restoreCallingIdentity(ident); if (device == null) { return 0; Loading