Merge "AudioManager: API to query independent/alias stream types"

This commit is contained in:
Jean-Michel Trivi
2023-02-15 03:25:11 +00:00
committed by Android (Google) Code Review
6 changed files with 274 additions and 1 deletions

View File

@@ -6860,6 +6860,7 @@ package android.media {
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDeviceForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener) throws java.lang.SecurityException;
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDevicesForCapturePresetChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDevicesForCapturePresetChangedListener) throws java.lang.SecurityException;
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDevicesForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDevicesForStrategyChangedListener) throws java.lang.SecurityException;
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS) public void addOnStreamAliasingChangedListener(@NonNull java.util.concurrent.Executor, @NonNull Runnable);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void cancelMuteAwaitConnection(@NonNull android.media.AudioDeviceAttributes) throws java.lang.IllegalStateException;
method public void clearAudioServerStateCallback();
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean clearPreferredDevicesForCapturePreset(int);
@@ -6873,6 +6874,7 @@ package android.media {
method @NonNull @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION) public android.media.AudioTrack getCallUplinkInjectionAudioTrack(@NonNull android.media.AudioFormat);
method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, "android.permission.QUERY_AUDIO_STATE", android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS}) public int getDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes);
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, "android.permission.QUERY_AUDIO_STATE"}) public java.util.List<android.media.AudioDeviceAttributes> getDevicesForAttributes(@NonNull android.media.AudioAttributes);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS) public java.util.List<java.lang.Integer> getIndependentStreamTypes();
method @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public int getLastAudibleStreamVolume(int);
method @IntRange(from=0) @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public int getLastAudibleVolumeGroupVolume(int);
method @IntRange(from=0) public long getMaxAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo);
@@ -6883,6 +6885,7 @@ package android.media {
method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.AudioDeviceAttributes getPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getPreferredDevicesForCapturePreset(int);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getPreferredDevicesForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS) public int getStreamTypeAlias(int);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int[] getSupportedSystemUsages();
method @IntRange(from=0) @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS, android.Manifest.permission.MODIFY_AUDIO_ROUTING}) public int getVolumeGroupMaxVolumeIndex(int);
method @IntRange(from=0) @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS, android.Manifest.permission.MODIFY_AUDIO_ROUTING}) public int getVolumeGroupMinVolumeIndex(int);
@@ -6905,6 +6908,7 @@ package android.media {
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDeviceForStrategyChangedListener(@NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDevicesForCapturePresetChangedListener(@NonNull android.media.AudioManager.OnPreferredDevicesForCapturePresetChangedListener);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDevicesForStrategyChangedListener(@NonNull android.media.AudioManager.OnPreferredDevicesForStrategyChangedListener);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS) public void removeOnStreamAliasingChangedListener(@NonNull Runnable);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean removePreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int) throws java.lang.IllegalArgumentException;
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.MODIFY_AUDIO_ROUTING}) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int, android.media.audiopolicy.AudioPolicy) throws java.lang.IllegalArgumentException;

View File

@@ -1756,8 +1756,10 @@ package android.media {
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS) public boolean isCsdEnabled();
method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, android.Manifest.permission.QUERY_AUDIO_STATE, android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS}) public boolean isFullVolumeDevice();
method @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION) public boolean isPstnCallAudioInterceptable();
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS) public boolean isVolumeControlUsingVolumeGroups();
method @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public int requestAudioFocusForTest(@NonNull android.media.AudioFocusRequest, @NonNull String, int, int);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS) public void setCsd(float);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS) public void setNotifAliasRingForTest(boolean);
method public void setRampingRingerEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS) public void setRs2Value(float);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setTestDeviceConnectionState(@NonNull android.media.AudioDeviceAttributes, boolean);

View File

@@ -9465,6 +9465,140 @@ public class AudioManager {
}
}
//====================================================================
// Stream aliasing changed listener, getter for stream alias or independent streams
/**
* manages the stream aliasing listeners and StreamAliasingDispatcherStub
*/
private final CallbackUtil.LazyListenerManager<Runnable> mStreamAliasingListenerMgr =
new CallbackUtil.LazyListenerManager();
final class StreamAliasingDispatcherStub extends IStreamAliasingDispatcher.Stub
implements CallbackUtil.DispatcherStub {
@Override
public void register(boolean register) {
try {
getService().registerStreamAliasingDispatcher(this, register);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
}
@Override
public void dispatchStreamAliasingChanged() {
mStreamAliasingListenerMgr.callListeners((listener) -> listener.run());
}
}
/**
* @hide
* Adds a listener to be notified of changes to volume stream type aliasing.
* See {@link #getIndependentStreamTypes()} and {@link #getStreamTypeAlias(int)}
* @param executor the Executor running the listener
* @param onStreamAliasingChangedListener the listener to add for the aliasing changes
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS)
public void addOnStreamAliasingChangedListener(
@NonNull @CallbackExecutor Executor executor,
@NonNull Runnable onStreamAliasingChangedListener) {
mStreamAliasingListenerMgr.addListener(executor, onStreamAliasingChangedListener,
"addOnStreamAliasingChangedListener",
() -> new StreamAliasingDispatcherStub());
}
/**
* @hide
* Removes a previously added listener for changes to stream aliasing.
* See {@link #getIndependentStreamTypes()} and {@link #getStreamTypeAlias(int)}
* @see #addOnStreamAliasingChangedListener(Executor, Runnable)
* @param onStreamAliasingChangedListener the previously added listener of aliasing changes
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS)
public void removeOnStreamAliasingChangedListener(
@NonNull Runnable onStreamAliasingChangedListener) {
mStreamAliasingListenerMgr.removeListener(onStreamAliasingChangedListener,
"removeOnStreamAliasingChangedListener");
}
/**
* @hide
* Test method to temporarily override whether STREAM_NOTIFICATION is aliased to STREAM_RING,
* volumes will be updated in case of a change.
* @param isAliased if true, STREAM_NOTIFICATION is aliased to STREAM_RING
*/
@TestApi
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS)
public void setNotifAliasRingForTest(boolean isAliased) {
final IAudioService service = getService();
try {
service.setNotifAliasRingForTest(isAliased);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* @hide
* Return the list of independent stream types for volume control.
* A stream type is considered independent when the volume changes of that type do not
* affect any other independent volume control stream type.
* An independent stream type is its own alias when using {@link #getStreamTypeAlias(int)}.
* @return list of independent stream types.
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS)
public @NonNull List<Integer> getIndependentStreamTypes() {
final IAudioService service = getService();
try {
return service.getIndependentStreamTypes();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* @hide
* Return the stream type that a given stream is aliased to.
* A stream alias means that any change to the source stream will also be applied to the alias,
* and vice-versa.
* If a stream is independent (i.e. part of the stream types returned by
* {@link #getIndependentStreamTypes()}), its alias is itself.
* @param sourceStreamType the stream type to query for the alias.
* @return the stream type the source type is aliased to.
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS)
public @PublicStreamTypes int getStreamTypeAlias(@PublicStreamTypes int sourceStreamType) {
final IAudioService service = getService();
try {
return service.getStreamTypeAlias(sourceStreamType);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* @hide
* Returns whether the system uses {@link AudioVolumeGroup} for volume control
* @return true when volume control is performed through volume groups, false if it uses
* stream types.
*/
@TestApi
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS)
public boolean isVolumeControlUsingVolumeGroups() {
final IAudioService service = getService();
try {
return service.isVolumeControlUsingVolumeGroups();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
//====================================================================
// Mute await connection

View File

@@ -49,6 +49,7 @@ import android.media.ISpatializerHeadTrackerAvailableCallback;
import android.media.ISpatializerHeadTrackingModeCallback;
import android.media.ISpatializerHeadToSoundStagePoseCallback;
import android.media.ISpatializerOutputCallback;
import android.media.IStreamAliasingDispatcher;
import android.media.IVolumeController;
import android.media.PlayerBase;
import android.media.VolumeInfo;
@@ -257,6 +258,21 @@ interface IAudioService {
IRingtonePlayer getRingtonePlayer();
int getUiSoundsStreamType();
@EnforcePermission("MODIFY_AUDIO_SYSTEM_SETTINGS")
List getIndependentStreamTypes();
@EnforcePermission("MODIFY_AUDIO_SYSTEM_SETTINGS")
int getStreamTypeAlias(int streamType);
@EnforcePermission("MODIFY_AUDIO_SYSTEM_SETTINGS")
boolean isVolumeControlUsingVolumeGroups();
@EnforcePermission("MODIFY_AUDIO_SYSTEM_SETTINGS")
oneway void registerStreamAliasingDispatcher(IStreamAliasingDispatcher isad, boolean register);
@EnforcePermission("MODIFY_AUDIO_SYSTEM_SETTINGS")
void setNotifAliasRingForTest(boolean alias);
@EnforcePermission("MODIFY_AUDIO_ROUTING")
void setWiredDeviceConnectionState(in AudioDeviceAttributes aa, int state, String caller);

View File

@@ -0,0 +1,27 @@
/*
* Copyright (C) 2023 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;
/**
* AIDL for AudioService to signal stream aliasing update.
*
* {@hide}
*/
oneway interface IStreamAliasingDispatcher {
void dispatchStreamAliasingChanged();
}

View File

@@ -119,6 +119,7 @@ import android.media.ISpatializerHeadTrackingModeCallback;
import android.media.ISpatializerOutputCallback;
import android.media.IStrategyNonDefaultDevicesDispatcher;
import android.media.IStrategyPreferredDevicesDispatcher;
import android.media.IStreamAliasingDispatcher;
import android.media.IVolumeController;
import android.media.MediaMetrics;
import android.media.MediaRecorder.AudioSource;
@@ -310,7 +311,9 @@ public class AudioService extends IAudioService.Stub
* volumes will be updated in case of a change.
* @param alias if true, STREAM_NOTIFICATION is aliased to STREAM_RING
*/
/*package*/ void setNotifAliasRingForTest(boolean alias) {
@android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS)
public void setNotifAliasRingForTest(boolean alias) {
super.setNotifAliasRingForTest_enforcePermission();
boolean update = (mNotifAliasRing != alias);
mNotifAliasRing = alias;
if (update) {
@@ -2282,6 +2285,7 @@ public class AudioService extends IAudioService.Stub
0,
mStreamStates[AudioSystem.STREAM_ACCESSIBILITY], 0);
}
dispatchStreamAliasingUpdate();
}
private void readDockAudioSettings(ContentResolver cr)
@@ -5018,6 +5022,91 @@ public class AudioService extends IAudioService.Stub
return sDefaultVolumeInfo;
}
/**
* list of callback dispatchers for stream aliasing updates
*/
final RemoteCallbackList<IStreamAliasingDispatcher> mStreamAliasingDispatchers =
new RemoteCallbackList<IStreamAliasingDispatcher>();
/**
* Register/unregister a callback for stream aliasing updates
* @param isad the callback dispatcher
* @param register whether this for a registration or unregistration
* @see AudioManager#addOnStreamAliasingChangedListener(Executor, Runnable)
* @see AudioManager#removeOnStreamAliasingChangedListener(Runnable)
*/
@android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS)
public void registerStreamAliasingDispatcher(IStreamAliasingDispatcher isad, boolean register) {
super.registerStreamAliasingDispatcher_enforcePermission();
Objects.requireNonNull(isad);
if (register) {
mStreamAliasingDispatchers.register(isad);
} else {
mStreamAliasingDispatchers.unregister(isad);
}
}
protected void dispatchStreamAliasingUpdate() {
final int nbDispatchers = mStreamAliasingDispatchers.beginBroadcast();
for (int i = 0; i < nbDispatchers; i++) {
try {
mStreamAliasingDispatchers.getBroadcastItem(i).dispatchStreamAliasingChanged();
} catch (RemoteException e) {
Log.e(TAG, "Error on stream alias update dispatch", e);
}
}
mStreamAliasingDispatchers.finishBroadcast();
}
/**
* @see AudioManager#getIndependentStreamTypes()
* @return the list of non-aliased stream types
*/
@android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS)
public ArrayList<Integer> getIndependentStreamTypes() {
super.getIndependentStreamTypes_enforcePermission();
if (mUseVolumeGroupAliases) {
return new ArrayList<>(Arrays.stream(AudioManager.getPublicStreamTypes())
.boxed().toList());
}
ArrayList<Integer> res = new ArrayList(1);
for (int stream : mStreamVolumeAlias) {
if (!res.contains(stream)) {
res.add(stream);
}
}
return res;
}
/**
* @see AudioManager#getStreamTypeAlias(int)
* @param sourceStreamType the stream type for which the alias is queried
* @return the stream alias
*/
@android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS)
public @AudioManager.PublicStreamTypes
int getStreamTypeAlias(@AudioManager.PublicStreamTypes int sourceStreamType) {
super.getStreamTypeAlias_enforcePermission();
// verify parameters
ensureValidStreamType(sourceStreamType);
return mStreamVolumeAlias[sourceStreamType];
}
/**
* @see AudioManager#isVolumeControlUsingVolumeGroups()
* @return true when volume control is performed through volume groups, false if it uses
* stream types.
*/
@android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS)
public boolean isVolumeControlUsingVolumeGroups() {
super.isVolumeControlUsingVolumeGroups_enforcePermission();
return mUseVolumeGroupAliases;
}
/** @see AudioManager#getUiSoundsStreamType()
* TODO(b/181140246): when using VolumeGroup alias, we are lacking configurability for
* UI Sounds identification.
@@ -10723,6 +10812,7 @@ public class AudioService extends IAudioService.Stub
pw.print(" mBluetoothName="); pw.println(mDeviceBroker.getCurAudioRoutes().bluetoothName);
pw.println("\nOther state:");
pw.print(" mUseVolumeGroupAliases="); pw.println(mUseVolumeGroupAliases);
pw.print(" mVolumeController="); pw.println(mVolumeController);
mSoundDoseHelper.dump(pw);
pw.print(" sIndependentA11yVolume="); pw.println(sIndependentA11yVolume);