Merge "Revert "New APIs for immersive audio"" into sc-v2-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
c3537ee73a
@@ -20181,10 +20181,8 @@ package android.media {
|
|||||||
method public int getAllowedCapturePolicy();
|
method public int getAllowedCapturePolicy();
|
||||||
method public int getContentType();
|
method public int getContentType();
|
||||||
method public int getFlags();
|
method public int getFlags();
|
||||||
method public int getSpatializationBehavior();
|
|
||||||
method public int getUsage();
|
method public int getUsage();
|
||||||
method public int getVolumeControlStream();
|
method public int getVolumeControlStream();
|
||||||
method public boolean isContentSpatialized();
|
|
||||||
method public void writeToParcel(android.os.Parcel, int);
|
method public void writeToParcel(android.os.Parcel, int);
|
||||||
field public static final int ALLOW_CAPTURE_BY_ALL = 1; // 0x1
|
field public static final int ALLOW_CAPTURE_BY_ALL = 1; // 0x1
|
||||||
field public static final int ALLOW_CAPTURE_BY_NONE = 3; // 0x3
|
field public static final int ALLOW_CAPTURE_BY_NONE = 3; // 0x3
|
||||||
@@ -20198,8 +20196,6 @@ package android.media {
|
|||||||
field public static final int FLAG_AUDIBILITY_ENFORCED = 1; // 0x1
|
field public static final int FLAG_AUDIBILITY_ENFORCED = 1; // 0x1
|
||||||
field public static final int FLAG_HW_AV_SYNC = 16; // 0x10
|
field public static final int FLAG_HW_AV_SYNC = 16; // 0x10
|
||||||
field @Deprecated public static final int FLAG_LOW_LATENCY = 256; // 0x100
|
field @Deprecated public static final int FLAG_LOW_LATENCY = 256; // 0x100
|
||||||
field public static final int SPATIALIZATION_BEHAVIOR_AUTO = 0; // 0x0
|
|
||||||
field public static final int SPATIALIZATION_BEHAVIOR_NEVER = 1; // 0x1
|
|
||||||
field public static final int USAGE_ALARM = 4; // 0x4
|
field public static final int USAGE_ALARM = 4; // 0x4
|
||||||
field public static final int USAGE_ASSISTANCE_ACCESSIBILITY = 11; // 0xb
|
field public static final int USAGE_ASSISTANCE_ACCESSIBILITY = 11; // 0xb
|
||||||
field public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12; // 0xc
|
field public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12; // 0xc
|
||||||
@@ -20226,9 +20222,7 @@ package android.media {
|
|||||||
method public android.media.AudioAttributes.Builder setContentType(int);
|
method public android.media.AudioAttributes.Builder setContentType(int);
|
||||||
method public android.media.AudioAttributes.Builder setFlags(int);
|
method public android.media.AudioAttributes.Builder setFlags(int);
|
||||||
method @NonNull public android.media.AudioAttributes.Builder setHapticChannelsMuted(boolean);
|
method @NonNull public android.media.AudioAttributes.Builder setHapticChannelsMuted(boolean);
|
||||||
method @NonNull public android.media.AudioAttributes.Builder setIsContentSpatialized(boolean);
|
|
||||||
method public android.media.AudioAttributes.Builder setLegacyStreamType(int);
|
method public android.media.AudioAttributes.Builder setLegacyStreamType(int);
|
||||||
method @NonNull public android.media.AudioAttributes.Builder setSpatializationBehavior(int);
|
|
||||||
method public android.media.AudioAttributes.Builder setUsage(int);
|
method public android.media.AudioAttributes.Builder setUsage(int);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20453,7 +20447,6 @@ package android.media {
|
|||||||
method public String getProperty(String);
|
method public String getProperty(String);
|
||||||
method public int getRingerMode();
|
method public int getRingerMode();
|
||||||
method @Deprecated public int getRouting(int);
|
method @Deprecated public int getRouting(int);
|
||||||
method @Nullable public android.media.Spatializer getSpatializer();
|
|
||||||
method public int getStreamMaxVolume(int);
|
method public int getStreamMaxVolume(int);
|
||||||
method public int getStreamMinVolume(int);
|
method public int getStreamMinVolume(int);
|
||||||
method public int getStreamVolume(int);
|
method public int getStreamVolume(int);
|
||||||
@@ -23850,17 +23843,6 @@ package android.media {
|
|||||||
method public void onLoadComplete(android.media.SoundPool, int, int);
|
method public void onLoadComplete(android.media.SoundPool, int, int);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Spatializer {
|
|
||||||
method public void addOnSpatializerEnabledChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.Spatializer.OnSpatializerEnabledChangedListener);
|
|
||||||
method public boolean canBeSpatialized(@NonNull android.media.AudioAttributes, @NonNull android.media.AudioFormat);
|
|
||||||
method public boolean isEnabled();
|
|
||||||
method public void removeOnSpatializerEnabledChangedListener(@NonNull android.media.Spatializer.OnSpatializerEnabledChangedListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static interface Spatializer.OnSpatializerEnabledChangedListener {
|
|
||||||
method public void onSpatializerEnabledChanged(boolean);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class SubtitleData {
|
public final class SubtitleData {
|
||||||
ctor public SubtitleData(int, long, long, @NonNull byte[]);
|
ctor public SubtitleData(int, long, long, @NonNull byte[]);
|
||||||
method @NonNull public byte[] getData();
|
method @NonNull public byte[] getData();
|
||||||
|
|||||||
@@ -5372,12 +5372,6 @@ package android.media {
|
|||||||
field public static final android.media.RouteDiscoveryPreference EMPTY;
|
field public static final android.media.RouteDiscoveryPreference EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Spatializer {
|
|
||||||
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addCompatibleAudioDevice(@NonNull android.media.AudioDeviceAttributes);
|
|
||||||
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getCompatibleAudioDevices();
|
|
||||||
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeCompatibleAudioDevice(@NonNull android.media.AudioDeviceAttributes);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
package android.media.audiofx {
|
package android.media.audiofx {
|
||||||
|
|||||||
@@ -447,26 +447,13 @@ public final class AudioAttributes implements Parcelable {
|
|||||||
*/
|
*/
|
||||||
public static final int FLAG_CAPTURE_PRIVATE = 0x1 << 13;
|
public static final int FLAG_CAPTURE_PRIVATE = 0x1 << 13;
|
||||||
|
|
||||||
/**
|
|
||||||
* @hide
|
|
||||||
* Flag indicating the audio content has been processed to provide a virtual multichannel
|
|
||||||
* audio experience
|
|
||||||
*/
|
|
||||||
public static final int FLAG_CONTENT_SPATIALIZED = 0x1 << 14;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @hide
|
|
||||||
* Flag indicating the audio content is to never be spatialized
|
|
||||||
*/
|
|
||||||
public static final int FLAG_NEVER_SPATIALIZE = 0x1 << 15;
|
|
||||||
|
|
||||||
// Note that even though FLAG_MUTE_HAPTIC is stored as a flag bit, it is not here since
|
// Note that even though FLAG_MUTE_HAPTIC is stored as a flag bit, it is not here since
|
||||||
// it is known as a boolean value outside of AudioAttributes.
|
// it is known as a boolean value outside of AudioAttributes.
|
||||||
private static final int FLAG_ALL = FLAG_AUDIBILITY_ENFORCED | FLAG_SECURE | FLAG_SCO
|
private static final int FLAG_ALL = FLAG_AUDIBILITY_ENFORCED | FLAG_SECURE | FLAG_SCO
|
||||||
| FLAG_BEACON | FLAG_HW_AV_SYNC | FLAG_HW_HOTWORD | FLAG_BYPASS_INTERRUPTION_POLICY
|
| FLAG_BEACON | FLAG_HW_AV_SYNC | FLAG_HW_HOTWORD | FLAG_BYPASS_INTERRUPTION_POLICY
|
||||||
| FLAG_BYPASS_MUTE | FLAG_LOW_LATENCY | FLAG_DEEP_BUFFER | FLAG_NO_MEDIA_PROJECTION
|
| FLAG_BYPASS_MUTE | FLAG_LOW_LATENCY | FLAG_DEEP_BUFFER | FLAG_NO_MEDIA_PROJECTION
|
||||||
| FLAG_NO_SYSTEM_CAPTURE | FLAG_CAPTURE_PRIVATE | FLAG_CONTENT_SPATIALIZED
|
| FLAG_NO_SYSTEM_CAPTURE | FLAG_CAPTURE_PRIVATE;
|
||||||
| FLAG_NEVER_SPATIALIZE;
|
|
||||||
private final static int FLAG_ALL_PUBLIC = FLAG_AUDIBILITY_ENFORCED |
|
private final static int FLAG_ALL_PUBLIC = FLAG_AUDIBILITY_ENFORCED |
|
||||||
FLAG_HW_AV_SYNC | FLAG_LOW_LATENCY;
|
FLAG_HW_AV_SYNC | FLAG_LOW_LATENCY;
|
||||||
/* mask of flags that can be set by SDK and System APIs through the Builder */
|
/* mask of flags that can be set by SDK and System APIs through the Builder */
|
||||||
@@ -627,49 +614,6 @@ public final class AudioAttributes implements Parcelable {
|
|||||||
return (mFlags & FLAG_MUTE_HAPTIC) != 0;
|
return (mFlags & FLAG_MUTE_HAPTIC) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return true if the audio content associated with these attributes has already been
|
|
||||||
* spatialized, that is it has already been processed to offer a binaural or transaural
|
|
||||||
* immersive audio experience.
|
|
||||||
* @return {@code true} if the content has been processed
|
|
||||||
*/
|
|
||||||
public boolean isContentSpatialized() {
|
|
||||||
return (mFlags & FLAG_CONTENT_SPATIALIZED) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @hide */
|
|
||||||
@IntDef(flag = false, value = {
|
|
||||||
SPATIALIZATION_BEHAVIOR_AUTO,
|
|
||||||
SPATIALIZATION_BEHAVIOR_NEVER,
|
|
||||||
})
|
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
|
||||||
public @interface SpatializationBehavior {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constant indicating the audio content associated with these attributes will follow the
|
|
||||||
* default platform behavior with regards to which content will be spatialized or not.
|
|
||||||
* @see #getSpatializationBehavior()
|
|
||||||
* @see Spatializer
|
|
||||||
*/
|
|
||||||
public static final int SPATIALIZATION_BEHAVIOR_AUTO = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constant indicating the audio content associated with these attributes should never
|
|
||||||
* be virtualized.
|
|
||||||
* @see #getSpatializationBehavior()
|
|
||||||
* @see Spatializer
|
|
||||||
*/
|
|
||||||
public static final int SPATIALIZATION_BEHAVIOR_NEVER = 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the behavior affecting whether spatialization will be used.
|
|
||||||
* @return the spatialization behavior
|
|
||||||
*/
|
|
||||||
public @SpatializationBehavior int getSpatializationBehavior() {
|
|
||||||
return ((mFlags & FLAG_NEVER_SPATIALIZE) != 0)
|
|
||||||
? SPATIALIZATION_BEHAVIOR_NEVER : SPATIALIZATION_BEHAVIOR_AUTO;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the capture policy.
|
* Return the capture policy.
|
||||||
* @return the capture policy set by {@link Builder#setAllowedCapturePolicy(int)} or
|
* @return the capture policy set by {@link Builder#setAllowedCapturePolicy(int)} or
|
||||||
@@ -713,8 +657,6 @@ public final class AudioAttributes implements Parcelable {
|
|||||||
private int mSource = MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID;
|
private int mSource = MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID;
|
||||||
private int mFlags = 0x0;
|
private int mFlags = 0x0;
|
||||||
private boolean mMuteHapticChannels = true;
|
private boolean mMuteHapticChannels = true;
|
||||||
private boolean mIsContentSpatialized = false;
|
|
||||||
private int mSpatializationBehavior = SPATIALIZATION_BEHAVIOR_AUTO;
|
|
||||||
private HashSet<String> mTags = new HashSet<String>();
|
private HashSet<String> mTags = new HashSet<String>();
|
||||||
private Bundle mBundle;
|
private Bundle mBundle;
|
||||||
private int mPrivacySensitive = PRIVACY_SENSITIVE_DEFAULT;
|
private int mPrivacySensitive = PRIVACY_SENSITIVE_DEFAULT;
|
||||||
@@ -745,8 +687,6 @@ public final class AudioAttributes implements Parcelable {
|
|||||||
mFlags = aa.getAllFlags();
|
mFlags = aa.getAllFlags();
|
||||||
mTags = (HashSet<String>) aa.mTags.clone();
|
mTags = (HashSet<String>) aa.mTags.clone();
|
||||||
mMuteHapticChannels = aa.areHapticChannelsMuted();
|
mMuteHapticChannels = aa.areHapticChannelsMuted();
|
||||||
mIsContentSpatialized = aa.isContentSpatialized();
|
|
||||||
mSpatializationBehavior = aa.getSpatializationBehavior();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -779,12 +719,6 @@ public final class AudioAttributes implements Parcelable {
|
|||||||
if (mMuteHapticChannels) {
|
if (mMuteHapticChannels) {
|
||||||
aa.mFlags |= FLAG_MUTE_HAPTIC;
|
aa.mFlags |= FLAG_MUTE_HAPTIC;
|
||||||
}
|
}
|
||||||
if (mIsContentSpatialized) {
|
|
||||||
aa.mFlags |= FLAG_CONTENT_SPATIALIZED;
|
|
||||||
}
|
|
||||||
if (mSpatializationBehavior == SPATIALIZATION_BEHAVIOR_NEVER) {
|
|
||||||
aa.mFlags |= FLAG_NEVER_SPATIALIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mPrivacySensitive == PRIVACY_SENSITIVE_DEFAULT) {
|
if (mPrivacySensitive == PRIVACY_SENSITIVE_DEFAULT) {
|
||||||
// capturing for camcorder or communication is private by default to
|
// capturing for camcorder or communication is private by default to
|
||||||
@@ -971,35 +905,6 @@ public final class AudioAttributes implements Parcelable {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Specifies whether the content has already been processed for spatialization.
|
|
||||||
* If it has, setting this to true will prevent issues such as double-processing.
|
|
||||||
* @param isSpatialized
|
|
||||||
* @return the same Builder instance
|
|
||||||
*/
|
|
||||||
public @NonNull Builder setIsContentSpatialized(boolean isSpatialized) {
|
|
||||||
mIsContentSpatialized = isSpatialized;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the behavior affecting whether spatialization will be used.
|
|
||||||
* @param sb the spatialization behavior
|
|
||||||
* @return the same Builder instance
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public @NonNull Builder setSpatializationBehavior(@SpatializationBehavior int sb) {
|
|
||||||
switch (sb) {
|
|
||||||
case SPATIALIZATION_BEHAVIOR_NEVER:
|
|
||||||
case SPATIALIZATION_BEHAVIOR_AUTO:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Invalid spatialization behavior " + sb);
|
|
||||||
}
|
|
||||||
mSpatializationBehavior = sb;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hide
|
* @hide
|
||||||
* Replaces flags.
|
* Replaces flags.
|
||||||
@@ -1085,8 +990,6 @@ public final class AudioAttributes implements Parcelable {
|
|||||||
mContentType = attributes.mContentType;
|
mContentType = attributes.mContentType;
|
||||||
mFlags = attributes.getAllFlags();
|
mFlags = attributes.getAllFlags();
|
||||||
mMuteHapticChannels = attributes.areHapticChannelsMuted();
|
mMuteHapticChannels = attributes.areHapticChannelsMuted();
|
||||||
mIsContentSpatialized = attributes.isContentSpatialized();
|
|
||||||
mSpatializationBehavior = attributes.getSpatializationBehavior();
|
|
||||||
mTags = attributes.mTags;
|
mTags = attributes.mTags;
|
||||||
mBundle = attributes.mBundle;
|
mBundle = attributes.mBundle;
|
||||||
mSource = attributes.mSource;
|
mSource = attributes.mSource;
|
||||||
|
|||||||
@@ -805,7 +805,7 @@ public class AudioManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@UnsupportedAppUsage
|
@UnsupportedAppUsage
|
||||||
static IAudioService getService()
|
private static IAudioService getService()
|
||||||
{
|
{
|
||||||
if (sService != null) {
|
if (sService != null) {
|
||||||
return sService;
|
return sService;
|
||||||
@@ -2438,149 +2438,6 @@ public class AudioManager {
|
|||||||
return AudioSystem.getOffloadSupport(format, attributes);
|
return AudioSystem.getOffloadSupport(format, attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
//====================================================================
|
|
||||||
// Immersive audio
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @hide
|
|
||||||
* Returns the level of support for immersive audio from the {@link Spatializer} if
|
|
||||||
* available.
|
|
||||||
* @return the level of immersive audio support through spatialization
|
|
||||||
* @see Spatializer#getImmersiveAudioLevel()
|
|
||||||
*/
|
|
||||||
@Spatializer.ImmersiveAudioLevel int getSpatializerImmersiveAudioLevel() {
|
|
||||||
final IAudioService service = getService();
|
|
||||||
try {
|
|
||||||
return service.getSpatializerImmersiveAudioLevel();
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
return Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a handle to the optional platform's {@link Spatializer}
|
|
||||||
* @return {@code null} if spatialization is not supported, the {@code Spatializer} instance
|
|
||||||
* otherwise.
|
|
||||||
*/
|
|
||||||
public @Nullable Spatializer getSpatializer() {
|
|
||||||
if (getSpatializerImmersiveAudioLevel() == Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return new Spatializer(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @hide
|
|
||||||
* @see Spatializer#isEnabled()
|
|
||||||
* @return {@code true} if spatialization is enabled
|
|
||||||
*/
|
|
||||||
boolean isSpatializerEnabled() {
|
|
||||||
final IAudioService service = getService();
|
|
||||||
try {
|
|
||||||
return service.isSpatializerEnabled();
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, "Error querying isSpatializerEnabled, returning false", e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @hide
|
|
||||||
* @see Spatializer#setEnabled(boolean)
|
|
||||||
* Enable/disable the spatialization wherever supported.
|
|
||||||
* @param enabled {@code true} to enable
|
|
||||||
*/
|
|
||||||
void setSpatializerFeatureEnabled(boolean enabled) {
|
|
||||||
final IAudioService service = getService();
|
|
||||||
try {
|
|
||||||
service.setSpatializerFeatureEnabled(enabled);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, "Error calling setSpatializerFeatureEnabled", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @hide
|
|
||||||
* @see Spatializer#setEnabledForDevice(boolean, AudioDeviceAttributes)
|
|
||||||
* @see Spatializer#setEnabled(boolean)
|
|
||||||
* @param enabled enable/disable for a specific device.
|
|
||||||
* @param device the device concerned with spatializer functionality.
|
|
||||||
*/
|
|
||||||
void setSpatializerEnabledForDevice(boolean enabled,
|
|
||||||
@NonNull AudioDeviceAttributes device) {
|
|
||||||
final IAudioService service = getService();
|
|
||||||
try {
|
|
||||||
service.setSpatializerEnabledForDevice(enabled, device);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, "Error calling setSpatializerEnabledForDevice", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @hide
|
|
||||||
* @see Spatializer#canBeSpatialized(AudioAttributes, AudioFormat)
|
|
||||||
* @param attributes the {@code AudioAttributes} of the content as used for playback
|
|
||||||
* @param format the {@code AudioFormat} of the content as used for playback
|
|
||||||
* @return true if the device is capable of spatializing the combination of audio
|
|
||||||
* format and attributes.
|
|
||||||
*/
|
|
||||||
boolean canBeSpatialized(
|
|
||||||
@NonNull AudioAttributes attributes, @NonNull AudioFormat format) {
|
|
||||||
final IAudioService service = getService();
|
|
||||||
try {
|
|
||||||
return service.canBeSpatialized(attributes, format);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, "Error querying canBeSpatialized for attr:" + attributes
|
|
||||||
+ " format:" + format + " returning false", e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @hide
|
|
||||||
* @see Spatializer#getCompatibleAudioDevices()
|
|
||||||
* @return a non-null list of the spatialization-compatible audio devices
|
|
||||||
*/
|
|
||||||
@NonNull List<AudioDeviceAttributes> getSpatializerCompatibleAudioDevices() {
|
|
||||||
final IAudioService service = getService();
|
|
||||||
try {
|
|
||||||
return service.getSpatializerCompatibleAudioDevices();
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, "Error querying getSpatializerCompatibleAudioDevices(), "
|
|
||||||
+ " returning empty list", e);
|
|
||||||
return new ArrayList<AudioDeviceAttributes>(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @hide
|
|
||||||
* @see Spatializer#addCompatibleAudioDevice(AudioDeviceAttributes)
|
|
||||||
* @param ada the audio device compatible with spatialization
|
|
||||||
*/
|
|
||||||
void addSpatializerCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada) {
|
|
||||||
final IAudioService service = getService();
|
|
||||||
try {
|
|
||||||
service.addSpatializerCompatibleAudioDevice(ada);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, "Error calling addSpatializerCompatibleAudioDevice()", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @hide
|
|
||||||
* @see Spatializer#removeCompatibleAudioDevice(AudioDeviceAttributes)
|
|
||||||
* @param ada the audio device incompatible with spatialization
|
|
||||||
*/
|
|
||||||
void removeSpatializerCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada) {
|
|
||||||
final IAudioService service = getService();
|
|
||||||
try {
|
|
||||||
service.removeSpatializerCompatibleAudioDevice(ada);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, "Error calling removeSpatializerCompatibleAudioDevice()", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//====================================================================
|
//====================================================================
|
||||||
// Bluetooth SCO control
|
// Bluetooth SCO control
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import android.bluetooth.BluetoothDevice;
|
|||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.media.AudioAttributes;
|
import android.media.AudioAttributes;
|
||||||
import android.media.AudioDeviceAttributes;
|
import android.media.AudioDeviceAttributes;
|
||||||
import android.media.AudioFormat;
|
|
||||||
import android.media.AudioFocusInfo;
|
import android.media.AudioFocusInfo;
|
||||||
import android.media.AudioPlaybackConfiguration;
|
import android.media.AudioPlaybackConfiguration;
|
||||||
import android.media.AudioRecordingConfiguration;
|
import android.media.AudioRecordingConfiguration;
|
||||||
@@ -35,7 +34,6 @@ import android.media.IPlaybackConfigDispatcher;
|
|||||||
import android.media.IRecordingConfigDispatcher;
|
import android.media.IRecordingConfigDispatcher;
|
||||||
import android.media.IRingtonePlayer;
|
import android.media.IRingtonePlayer;
|
||||||
import android.media.IStrategyPreferredDevicesDispatcher;
|
import android.media.IStrategyPreferredDevicesDispatcher;
|
||||||
import android.media.ISpatializerCallback;
|
|
||||||
import android.media.IVolumeController;
|
import android.media.IVolumeController;
|
||||||
import android.media.IVolumeController;
|
import android.media.IVolumeController;
|
||||||
import android.media.PlayerBase;
|
import android.media.PlayerBase;
|
||||||
@@ -394,24 +392,4 @@ interface IAudioService {
|
|||||||
void registerModeDispatcher(IAudioModeDispatcher dispatcher);
|
void registerModeDispatcher(IAudioModeDispatcher dispatcher);
|
||||||
|
|
||||||
oneway void unregisterModeDispatcher(IAudioModeDispatcher dispatcher);
|
oneway void unregisterModeDispatcher(IAudioModeDispatcher dispatcher);
|
||||||
|
|
||||||
int getSpatializerImmersiveAudioLevel();
|
|
||||||
|
|
||||||
boolean isSpatializerEnabled();
|
|
||||||
|
|
||||||
void setSpatializerFeatureEnabled(boolean enabled);
|
|
||||||
|
|
||||||
void setSpatializerEnabledForDevice(boolean enabled, in AudioDeviceAttributes device);
|
|
||||||
|
|
||||||
boolean canBeSpatialized(in AudioAttributes aa, in AudioFormat af);
|
|
||||||
|
|
||||||
void registerSpatializerCallback(in ISpatializerCallback callback);
|
|
||||||
|
|
||||||
void unregisterSpatializerCallback(in ISpatializerCallback callback);
|
|
||||||
|
|
||||||
List<AudioDeviceAttributes> getSpatializerCompatibleAudioDevices();
|
|
||||||
|
|
||||||
void addSpatializerCompatibleAudioDevice(in AudioDeviceAttributes ada);
|
|
||||||
|
|
||||||
void removeSpatializerCompatibleAudioDevice(in AudioDeviceAttributes ada);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2021 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 the AudioService to signal Spatializer state changes.
|
|
||||||
*
|
|
||||||
* {@hide}
|
|
||||||
*/
|
|
||||||
oneway interface ISpatializerCallback {
|
|
||||||
|
|
||||||
void dispatchSpatializerStateChanged(boolean enabled);
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,331 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2021 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.annotation.CallbackExecutor;
|
|
||||||
import android.annotation.IntDef;
|
|
||||||
import android.annotation.NonNull;
|
|
||||||
import android.annotation.Nullable;
|
|
||||||
import android.annotation.RequiresPermission;
|
|
||||||
import android.annotation.SystemApi;
|
|
||||||
import android.media.permission.ClearCallingIdentityContext;
|
|
||||||
import android.media.permission.SafeCloseable;
|
|
||||||
import android.os.RemoteException;
|
|
||||||
|
|
||||||
import com.android.internal.annotations.GuardedBy;
|
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Spatializer provides access to querying capabilities and behavior of sound spatialization
|
|
||||||
* on the device.
|
|
||||||
* Sound spatialization simulates sounds originating around the listener as if they were coming
|
|
||||||
* from virtual speakers placed around the listener.<br>
|
|
||||||
* Support for spatialization is optional, use {@link AudioManager#getSpatializer()} to obtain an
|
|
||||||
* instance of this class if the feature is supported.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class Spatializer {
|
|
||||||
|
|
||||||
private final @NonNull AudioManager mAm;
|
|
||||||
|
|
||||||
private final Object mStateListenerLock = new Object();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of listeners for state listener and their associated Executor.
|
|
||||||
* List is lazy-initialized on first registration
|
|
||||||
*/
|
|
||||||
@GuardedBy("mStateListenerLock")
|
|
||||||
private @Nullable ArrayList<StateListenerInfo> mStateListeners;
|
|
||||||
|
|
||||||
@GuardedBy("mStateListenerLock")
|
|
||||||
private SpatializerInfoDispatcherStub mInfoDispatcherStub;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @hide
|
|
||||||
* Constructor with AudioManager acting as proxy to AudioService
|
|
||||||
* @param am a non-null AudioManager
|
|
||||||
*/
|
|
||||||
protected Spatializer(@NonNull AudioManager am) {
|
|
||||||
mAm = Objects.requireNonNull(am);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether spatialization is enabled or not.
|
|
||||||
* A false value can originate from a number of sources, examples are the user electing to
|
|
||||||
* disable the feature, or the use of an audio device that is not compatible with multichannel
|
|
||||||
* audio spatialization (for instance playing audio over a monophonic speaker).
|
|
||||||
* @return {@code true} if spatialization is enabled
|
|
||||||
*/
|
|
||||||
public boolean isEnabled() {
|
|
||||||
return mAm.isSpatializerEnabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @hide */
|
|
||||||
@IntDef(flag = false, value = {
|
|
||||||
SPATIALIZER_IMMERSIVE_LEVEL_NONE,
|
|
||||||
SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL,
|
|
||||||
})
|
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
|
||||||
public @interface ImmersiveAudioLevel {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @hide
|
|
||||||
* Constant indicating there are no spatialization capabilities supported on this device.
|
|
||||||
* @see AudioManager#getImmersiveAudioLevel()
|
|
||||||
*/
|
|
||||||
public static final int SPATIALIZER_IMMERSIVE_LEVEL_NONE = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @hide
|
|
||||||
* Constant indicating the {@link Spatializer} on this device supports multichannel
|
|
||||||
* spatialization.
|
|
||||||
* @see AudioManager#getImmersiveAudioLevel()
|
|
||||||
*/
|
|
||||||
public static final int SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL = 1;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @hide
|
|
||||||
* @param enabled
|
|
||||||
* @param device
|
|
||||||
*/
|
|
||||||
//TODO make as API if needed for UX, remove otherwise
|
|
||||||
//@SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
|
|
||||||
//@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
|
|
||||||
public void setEnabledForDevice(boolean enabled,
|
|
||||||
@NonNull AudioDeviceAttributes device) {
|
|
||||||
Objects.requireNonNull(device);
|
|
||||||
mAm.setSpatializerEnabledForDevice(enabled, device);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @hide
|
|
||||||
* Enables / disables the spatializer effect
|
|
||||||
* @param enabled {@code true} for enabling the effect
|
|
||||||
*/
|
|
||||||
//TODO make as API if needed for UX, remove otherwise
|
|
||||||
//@SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
|
|
||||||
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
|
|
||||||
public void setEnabled(boolean enabled) {
|
|
||||||
mAm.setSpatializerFeatureEnabled(enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An interface to be notified of changes to the state of the spatializer.
|
|
||||||
*/
|
|
||||||
public interface OnSpatializerEnabledChangedListener {
|
|
||||||
/**
|
|
||||||
* Called when the enabled state of the Spatializer changes
|
|
||||||
* @param enabled {@code true} if the Spatializer effect is enabled on the device,
|
|
||||||
* {@code false} otherwise
|
|
||||||
*/
|
|
||||||
void onSpatializerEnabledChanged(boolean enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether audio of the given {@link AudioFormat}, played with the given
|
|
||||||
* {@link AudioAttributes} can be spatialized.
|
|
||||||
* Note that the result reflects the capabilities of the device and may change when
|
|
||||||
* audio accessories are connected/disconnected (e.g. wired headphones plugged in or not).
|
|
||||||
* The result is independent from whether spatialization processing is enabled or not.
|
|
||||||
* @param attributes the {@code AudioAttributes} of the content as used for playback
|
|
||||||
* @param format the {@code AudioFormat} of the content as used for playback
|
|
||||||
* @return true if the device is capable of spatializing the combination of audio format and
|
|
||||||
* attributes.
|
|
||||||
*/
|
|
||||||
public boolean canBeSpatialized(
|
|
||||||
@NonNull AudioAttributes attributes, @NonNull AudioFormat format) {
|
|
||||||
return mAm.canBeSpatialized(
|
|
||||||
Objects.requireNonNull(attributes), Objects.requireNonNull(format));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a listener to be notified of changes to the enabled state of the
|
|
||||||
* {@code Spatializer}.
|
|
||||||
* @see #isEnabled()
|
|
||||||
* @param executor the {@code Executor} handling the callback
|
|
||||||
* @param listener the listener to receive enabled state updates
|
|
||||||
*/
|
|
||||||
public void addOnSpatializerEnabledChangedListener(
|
|
||||||
@NonNull @CallbackExecutor Executor executor,
|
|
||||||
@NonNull OnSpatializerEnabledChangedListener listener) {
|
|
||||||
Objects.requireNonNull(executor);
|
|
||||||
Objects.requireNonNull(listener);
|
|
||||||
synchronized (mStateListenerLock) {
|
|
||||||
if (hasSpatializerStateListener(listener)) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Called addOnSpatializerEnabledChangedListener() "
|
|
||||||
+ "on a previously registered listener");
|
|
||||||
}
|
|
||||||
// lazy initialization of the list of strategy-preferred device listener
|
|
||||||
if (mStateListeners == null) {
|
|
||||||
mStateListeners = new ArrayList<>();
|
|
||||||
}
|
|
||||||
mStateListeners.add(new StateListenerInfo(listener, executor));
|
|
||||||
if (mStateListeners.size() == 1) {
|
|
||||||
// register binder for callbacks
|
|
||||||
if (mInfoDispatcherStub == null) {
|
|
||||||
mInfoDispatcherStub =
|
|
||||||
new SpatializerInfoDispatcherStub();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
mAm.getService().registerSpatializerCallback(
|
|
||||||
mInfoDispatcherStub);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
throw e.rethrowFromSystemServer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes a previously added listener for changes to the enabled state of the
|
|
||||||
* {@code Spatializer}.
|
|
||||||
* @see #isEnabled()
|
|
||||||
* @param listener the listener to receive enabled state updates
|
|
||||||
*/
|
|
||||||
public void removeOnSpatializerEnabledChangedListener(
|
|
||||||
@NonNull OnSpatializerEnabledChangedListener listener) {
|
|
||||||
Objects.requireNonNull(listener);
|
|
||||||
synchronized (mStateListenerLock) {
|
|
||||||
if (!removeStateListener(listener)) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Called removeOnSpatializerEnabledChangedListener() "
|
|
||||||
+ "on an unregistered listener");
|
|
||||||
}
|
|
||||||
if (mStateListeners.size() == 0) {
|
|
||||||
// unregister binder for callbacks
|
|
||||||
try {
|
|
||||||
mAm.getService().unregisterSpatializerCallback(mInfoDispatcherStub);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
throw e.rethrowFromSystemServer();
|
|
||||||
} finally {
|
|
||||||
mInfoDispatcherStub = null;
|
|
||||||
mStateListeners = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @hide
|
|
||||||
* Returns the list of playback devices that are compatible with the playback of multichannel
|
|
||||||
* audio through virtualization
|
|
||||||
* @return a list of devices. An empty list indicates virtualization is not supported.
|
|
||||||
*/
|
|
||||||
@SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
|
|
||||||
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
|
|
||||||
public @NonNull List<AudioDeviceAttributes> getCompatibleAudioDevices() {
|
|
||||||
return mAm.getSpatializerCompatibleAudioDevices();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @hide
|
|
||||||
* Adds a playback device to the list of devices compatible with the playback of multichannel
|
|
||||||
* audio through spatialization.
|
|
||||||
* @see #getCompatibleAudioDevices()
|
|
||||||
* @param ada the audio device compatible with spatialization
|
|
||||||
*/
|
|
||||||
@SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
|
|
||||||
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
|
|
||||||
public void addCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada) {
|
|
||||||
mAm.addSpatializerCompatibleAudioDevice(Objects.requireNonNull(ada));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @hide
|
|
||||||
* Remove a playback device from the list of devices compatible with the playback of
|
|
||||||
* multichannel audio through spatialization.
|
|
||||||
* @see #getCompatibleAudioDevices()
|
|
||||||
* @param ada the audio device incompatible with spatialization
|
|
||||||
*/
|
|
||||||
@SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
|
|
||||||
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
|
|
||||||
public void removeCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada) {
|
|
||||||
mAm.removeSpatializerCompatibleAudioDevice(Objects.requireNonNull(ada));
|
|
||||||
}
|
|
||||||
|
|
||||||
private final class SpatializerInfoDispatcherStub
|
|
||||||
extends ISpatializerCallback.Stub {
|
|
||||||
@Override
|
|
||||||
public void dispatchSpatializerStateChanged(boolean enabled) {
|
|
||||||
// make a shallow copy of listeners so callback is not executed under lock
|
|
||||||
final ArrayList<StateListenerInfo> stateListeners;
|
|
||||||
synchronized (mStateListenerLock) {
|
|
||||||
if (mStateListeners == null || mStateListeners.size() == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
stateListeners = (ArrayList<StateListenerInfo>) mStateListeners.clone();
|
|
||||||
}
|
|
||||||
try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
|
|
||||||
for (StateListenerInfo info : stateListeners) {
|
|
||||||
info.mExecutor.execute(() ->
|
|
||||||
info.mListener.onSpatializerEnabledChanged(enabled));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class StateListenerInfo {
|
|
||||||
final @NonNull OnSpatializerEnabledChangedListener mListener;
|
|
||||||
final @NonNull Executor mExecutor;
|
|
||||||
|
|
||||||
StateListenerInfo(@NonNull OnSpatializerEnabledChangedListener listener,
|
|
||||||
@NonNull Executor exe) {
|
|
||||||
mListener = listener;
|
|
||||||
mExecutor = exe;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@GuardedBy("mStateListenerLock")
|
|
||||||
private boolean hasSpatializerStateListener(OnSpatializerEnabledChangedListener listener) {
|
|
||||||
return getStateListenerInfo(listener) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@GuardedBy("mStateListenerLock")
|
|
||||||
private @Nullable StateListenerInfo getStateListenerInfo(
|
|
||||||
OnSpatializerEnabledChangedListener listener) {
|
|
||||||
if (mStateListeners == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
for (StateListenerInfo info : mStateListeners) {
|
|
||||||
if (info.mListener == listener) {
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@GuardedBy("mStateListenerLock")
|
|
||||||
/**
|
|
||||||
* @return true if the listener was removed from the list
|
|
||||||
*/
|
|
||||||
private boolean removeStateListener(OnSpatializerEnabledChangedListener listener) {
|
|
||||||
final StateListenerInfo infoToRemove = getStateListenerInfo(listener);
|
|
||||||
if (infoToRemove != null) {
|
|
||||||
mStateListeners.remove(infoToRemove);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -93,13 +93,11 @@ import android.media.ICommunicationDeviceDispatcher;
|
|||||||
import android.media.IPlaybackConfigDispatcher;
|
import android.media.IPlaybackConfigDispatcher;
|
||||||
import android.media.IRecordingConfigDispatcher;
|
import android.media.IRecordingConfigDispatcher;
|
||||||
import android.media.IRingtonePlayer;
|
import android.media.IRingtonePlayer;
|
||||||
import android.media.ISpatializerCallback;
|
|
||||||
import android.media.IStrategyPreferredDevicesDispatcher;
|
import android.media.IStrategyPreferredDevicesDispatcher;
|
||||||
import android.media.IVolumeController;
|
import android.media.IVolumeController;
|
||||||
import android.media.MediaMetrics;
|
import android.media.MediaMetrics;
|
||||||
import android.media.MediaRecorder.AudioSource;
|
import android.media.MediaRecorder.AudioSource;
|
||||||
import android.media.PlayerBase;
|
import android.media.PlayerBase;
|
||||||
import android.media.Spatializer;
|
|
||||||
import android.media.VolumePolicy;
|
import android.media.VolumePolicy;
|
||||||
import android.media.audiofx.AudioEffect;
|
import android.media.audiofx.AudioEffect;
|
||||||
import android.media.audiopolicy.AudioMix;
|
import android.media.audiopolicy.AudioMix;
|
||||||
@@ -8226,82 +8224,6 @@ public class AudioService extends IAudioService.Stub
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================================
|
|
||||||
private final SpatializerHelper mSpatializerHelper = new SpatializerHelper();
|
|
||||||
|
|
||||||
/** @see AudioManager#getSpatializerImmersiveAudioLevel() */
|
|
||||||
public int getSpatializerImmersiveAudioLevel() {
|
|
||||||
return Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @see Spatializer#isEnabled() */
|
|
||||||
public boolean isSpatializerEnabled() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @see Spatializer#canBeSpatialized() */
|
|
||||||
public boolean canBeSpatialized(
|
|
||||||
@NonNull AudioAttributes attributes, @NonNull AudioFormat format) {
|
|
||||||
Objects.requireNonNull(attributes);
|
|
||||||
Objects.requireNonNull(format);
|
|
||||||
return mSpatializerHelper.canBeSpatialized(attributes, format);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @see Spatializer.SpatializerInfoDispatcherStub */
|
|
||||||
public void registerSpatializerCallback(
|
|
||||||
@NonNull ISpatializerCallback dispatcher) {
|
|
||||||
Objects.requireNonNull(dispatcher);
|
|
||||||
mSpatializerHelper.registerStateCallback(dispatcher);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @see Spatializer.SpatializerInfoDispatcherStub */
|
|
||||||
public void unregisterSpatializerCallback(
|
|
||||||
@NonNull ISpatializerCallback dispatcher) {
|
|
||||||
Objects.requireNonNull(dispatcher);
|
|
||||||
mSpatializerHelper.unregisterStateCallback(dispatcher);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @see Spatializer#getSpatializerCompatibleAudioDevices() */
|
|
||||||
public @NonNull List<AudioDeviceAttributes> getSpatializerCompatibleAudioDevices() {
|
|
||||||
enforceModifyAudioRoutingPermission();
|
|
||||||
return mSpatializerHelper.getCompatibleAudioDevices();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @see Spatializer#addSpatializerCompatibleAudioDevice(AudioDeviceAttributes) */
|
|
||||||
public void addSpatializerCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada) {
|
|
||||||
enforceModifyAudioRoutingPermission();
|
|
||||||
Objects.requireNonNull(ada);
|
|
||||||
mSpatializerHelper.addCompatibleAudioDevice(ada);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @see Spatializer#removeSpatializerCompatibleAudioDevice(AudioDeviceAttributes) */
|
|
||||||
public void removeSpatializerCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada) {
|
|
||||||
enforceModifyAudioRoutingPermission();
|
|
||||||
Objects.requireNonNull(ada);
|
|
||||||
mSpatializerHelper.removeCompatibleAudioDevice(ada);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @see AudioManager#setSpatializerFeatureEnabled(boolean) */
|
|
||||||
public void setSpatializerFeatureEnabled(boolean enabled) {
|
|
||||||
if (mContext.checkCallingOrSelfPermission(
|
|
||||||
android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS)
|
|
||||||
!= PackageManager.PERMISSION_GRANTED) {
|
|
||||||
throw new SecurityException("Missing MODIFY_DEFAULT_AUDIO_EFFECTS permission");
|
|
||||||
}
|
|
||||||
mSpatializerHelper.setEnabled(enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @see Spatializer#setEnabledForDevice(boolean, AudioDeviceAttributes)
|
|
||||||
* @see Spatializer#setEnabled(boolean)
|
|
||||||
*/
|
|
||||||
public void setSpatializerEnabledForDevice(boolean enabled,
|
|
||||||
@NonNull AudioDeviceAttributes ada) {
|
|
||||||
enforceModifyAudioRoutingPermission();
|
|
||||||
Objects.requireNonNull(ada);
|
|
||||||
mSpatializerHelper.setEnabledForDevice(enabled, ada);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//==========================================================================================
|
//==========================================================================================
|
||||||
private boolean readCameraSoundForced() {
|
private boolean readCameraSoundForced() {
|
||||||
return SystemProperties.getBoolean("audio.camerasound.force", false) ||
|
return SystemProperties.getBoolean("audio.camerasound.force", false) ||
|
||||||
|
|||||||
@@ -1,126 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2021 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 com.android.server.audio;
|
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
|
||||||
import android.annotation.Nullable;
|
|
||||||
import android.media.AudioAttributes;
|
|
||||||
import android.media.AudioDeviceAttributes;
|
|
||||||
import android.media.AudioFormat;
|
|
||||||
import android.media.ISpatializerCallback;
|
|
||||||
import android.os.RemoteCallbackList;
|
|
||||||
import android.os.RemoteException;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A helper class to manage Spatializer related functionality
|
|
||||||
*/
|
|
||||||
public class SpatializerHelper {
|
|
||||||
|
|
||||||
private static final String TAG = "AS.NotificationHelper";
|
|
||||||
|
|
||||||
//---------------------------------------------------------------
|
|
||||||
// audio device compatibility / enabled
|
|
||||||
|
|
||||||
private final ArrayList<AudioDeviceAttributes> mCompatibleAudioDevices = new ArrayList<>(0);
|
|
||||||
private final ArrayList<AudioDeviceAttributes> mEnabledAudioDevices = new ArrayList<>(0);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return a shallow copy of the list of compatible audio devices
|
|
||||||
*/
|
|
||||||
synchronized @NonNull List<AudioDeviceAttributes> getCompatibleAudioDevices() {
|
|
||||||
return (List<AudioDeviceAttributes>) mCompatibleAudioDevices.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized void addCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada) {
|
|
||||||
if (!mCompatibleAudioDevices.contains(ada)) {
|
|
||||||
mCompatibleAudioDevices.add(ada);
|
|
||||||
}
|
|
||||||
// by default, adding a compatible device enables it
|
|
||||||
if (!mEnabledAudioDevices.contains(ada)) {
|
|
||||||
mEnabledAudioDevices.add(ada);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized void removeCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada) {
|
|
||||||
mCompatibleAudioDevices.remove(ada);
|
|
||||||
mEnabledAudioDevices.remove(ada);
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized void setEnabledForDevice(boolean enabled, @NonNull AudioDeviceAttributes ada) {
|
|
||||||
if (enabled) {
|
|
||||||
if (!mEnabledAudioDevices.contains(ada)) {
|
|
||||||
mEnabledAudioDevices.add(ada);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mEnabledAudioDevices.remove(ada);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------
|
|
||||||
// enabled state
|
|
||||||
|
|
||||||
// global state of feature
|
|
||||||
boolean mFeatureEnabled = false;
|
|
||||||
|
|
||||||
synchronized void setEnabled(boolean enabled) {
|
|
||||||
final boolean oldState = mFeatureEnabled;
|
|
||||||
mFeatureEnabled = enabled;
|
|
||||||
if (oldState != enabled) {
|
|
||||||
dispatchState();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final RemoteCallbackList<ISpatializerCallback> mStateCallbacks =
|
|
||||||
new RemoteCallbackList<ISpatializerCallback>();
|
|
||||||
|
|
||||||
synchronized void registerStateCallback(
|
|
||||||
@NonNull ISpatializerCallback callback) {
|
|
||||||
mStateCallbacks.register(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized void unregisterStateCallback(
|
|
||||||
@NonNull ISpatializerCallback callback) {
|
|
||||||
mStateCallbacks.unregister(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
private synchronized void dispatchState() {
|
|
||||||
// TODO check enabled state based on available devices
|
|
||||||
// (current implementation takes state as-is and dispatches it to listeners
|
|
||||||
final int nbCallbacks = mStateCallbacks.beginBroadcast();
|
|
||||||
for (int i = 0; i < nbCallbacks; i++) {
|
|
||||||
try {
|
|
||||||
mStateCallbacks.getBroadcastItem(i)
|
|
||||||
.dispatchSpatializerStateChanged(mFeatureEnabled);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, "Error in dispatchSpatializerStateChanged", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mStateCallbacks.finishBroadcast();
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------
|
|
||||||
// virtualization capabilities
|
|
||||||
synchronized boolean canBeSpatialized(
|
|
||||||
@NonNull AudioAttributes attributes, @NonNull AudioFormat format) {
|
|
||||||
// TODO hook up to spatializer effect for query
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user