diff options
| -rw-r--r-- | core/api/current.txt | 8 | ||||
| -rw-r--r-- | media/java/android/media/AudioManager.java | 88 | ||||
| -rwxr-xr-x | media/java/android/media/IAudioService.aidl | 8 | ||||
| -rw-r--r-- | services/core/java/com/android/server/audio/AudioService.java | 131 |
4 files changed, 223 insertions, 12 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index ece1ce64d928..6d5e58c965b9 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -20215,6 +20215,7 @@ package android.media { 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 @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS) public int getEncodedSurroundMode(); method public java.util.List<android.media.MicrophoneInfo> getMicrophones() throws java.io.IOException; method public int getMode(); method public String getParameters(String); @@ -20237,6 +20238,7 @@ package android.media { method public static boolean isOffloadedPlaybackSupported(@NonNull android.media.AudioFormat, @NonNull android.media.AudioAttributes); method public boolean isSpeakerphoneOn(); method public boolean isStreamMute(int); + method @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS) public boolean isSurroundFormatEnabled(int); method public boolean isVolumeFixed(); method @Deprecated public boolean isWiredHeadsetOn(); method public void loadSoundEffects(); @@ -20256,6 +20258,7 @@ package android.media { method @Deprecated public void setBluetoothA2dpOn(boolean); method public void setBluetoothScoOn(boolean); method public boolean setCommunicationDevice(@NonNull android.media.AudioDeviceInfo); + method @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS) public boolean setEncodedSurroundMode(int); method public void setMicrophoneMute(boolean); method public void setMode(int); method public void setParameters(String); @@ -20265,6 +20268,7 @@ package android.media { method @Deprecated public void setStreamMute(int, boolean); method @Deprecated public void setStreamSolo(int, boolean); method public void setStreamVolume(int, int, int); + method @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS) public boolean setSurroundFormatEnabled(int, boolean); method @Deprecated public void setVibrateSetting(int, int); method @Deprecated public void setWiredHeadsetOn(boolean); method @Deprecated public boolean shouldVibrate(int); @@ -20303,6 +20307,10 @@ package android.media { field public static final int AUDIOFOCUS_REQUEST_FAILED = 0; // 0x0 field public static final int AUDIOFOCUS_REQUEST_GRANTED = 1; // 0x1 field public static final int AUDIO_SESSION_ID_GENERATE = 0; // 0x0 + field public static final int ENCODED_SURROUND_OUTPUT_ALWAYS = 2; // 0x2 + field public static final int ENCODED_SURROUND_OUTPUT_AUTO = 0; // 0x0 + field public static final int ENCODED_SURROUND_OUTPUT_MANUAL = 3; // 0x3 + field public static final int ENCODED_SURROUND_OUTPUT_NEVER = 1; // 0x1 field public static final int ERROR = -1; // 0xffffffff field public static final int ERROR_DEAD_OBJECT = -6; // 0xfffffffa field public static final String EXTRA_AUDIO_PLUG_STATE = "android.media.extra.AUDIO_PLUG_STATE"; diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index ea8356bf9508..8a3deb6aefce 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -568,6 +568,42 @@ public class AudioManager { public static final int FLAG_FROM_KEY = 1 << 12; /** @hide */ + @IntDef(prefix = {"ENCODED_SURROUND_OUTPUT_"}, value = { + ENCODED_SURROUND_OUTPUT_AUTO, + ENCODED_SURROUND_OUTPUT_NEVER, + ENCODED_SURROUND_OUTPUT_ALWAYS, + ENCODED_SURROUND_OUTPUT_MANUAL + }) + @Retention(RetentionPolicy.SOURCE) + public @interface EncodedSurroundOutputMode {} + + /** + * The surround sound formats are available for use if they are detected. This is the default + * mode. + */ + public static final int ENCODED_SURROUND_OUTPUT_AUTO = 0; + + /** + * The surround sound formats are NEVER available, even if they are detected by the hardware. + * Those formats will not be reported. + */ + public static final int ENCODED_SURROUND_OUTPUT_NEVER = 1; + + /** + * The surround sound formats are ALWAYS available, even if they are not detected by the + * hardware. Those formats will be reported as part of the HDMI output capability. + * Applications are then free to use either PCM or encoded output. + */ + public static final int ENCODED_SURROUND_OUTPUT_ALWAYS = 2; + + /** + * Surround sound formats are available according to the choice of user, even if they are not + * detected by the hardware. Those formats will be reported as part of the HDMI output + * capability. Applications are then free to use either PCM or encoded output. + */ + public static final int ENCODED_SURROUND_OUTPUT_MANUAL = 3; + + /** @hide */ @IntDef(flag = true, prefix = "FLAG", value = { FLAG_SHOW_UI, FLAG_ALLOW_RINGER_MODES, @@ -6722,6 +6758,34 @@ public class AudioManager { } /** + * Sets the surround sound mode. + * + * @return true if successful, otherwise false + */ + @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS) + public boolean setEncodedSurroundMode(@EncodedSurroundOutputMode int mode) { + try { + return getService().setEncodedSurroundMode(mode); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Gets the surround sound mode. + * + * @return true if successful, otherwise false + */ + @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS) + public @EncodedSurroundOutputMode int getEncodedSurroundMode() { + try { + return getService().getEncodedSurroundMode(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * @hide * Returns all surround formats. * @return a map where the key is a surround format and @@ -6739,7 +6803,6 @@ public class AudioManager { } /** - * @hide * Set a certain surround format as enabled or not. * @param audioFormat a surround format, the value is one of * {@link AudioFormat#ENCODING_AC3}, {@link AudioFormat#ENCODING_E_AC3}, @@ -6753,10 +6816,29 @@ public class AudioManager { * @param enabled the required surround format state, true for enabled, false for disabled * @return true if successful, otherwise false */ + @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS) public boolean setSurroundFormatEnabled( @AudioFormat.SurroundSoundEncoding int audioFormat, boolean enabled) { - int status = AudioSystem.setSurroundFormatEnabled(audioFormat, enabled); - return status == AudioManager.SUCCESS; + try { + return getService().setSurroundFormatEnabled(audioFormat, enabled); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Gets whether a certain surround format is enabled or not. + * @param audioFormat a surround format + * + * @return whether the required surround format is enabled + */ + @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS) + public boolean isSurroundFormatEnabled(@AudioFormat.SurroundSoundEncoding int audioFormat) { + try { + return getService().isSurroundFormatEnabled(audioFormat); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 4f87fe6c5f8c..ee945d5a715f 100755 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -158,6 +158,14 @@ interface IAudioService { oneway void reloadAudioSettings(); + boolean setSurroundFormatEnabled(int audioFormat, boolean enabled); + + boolean isSurroundFormatEnabled(int audioFormat); + + boolean setEncodedSurroundMode(int mode); + + int getEncodedSurroundMode(); + oneway void avrcpSupportsAbsoluteVolume(String address, boolean support); void setSpeakerphoneOn(IBinder cb, boolean on); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 68f10a5106ef..81b5dc79f28e 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -1815,6 +1815,127 @@ public class AudioService extends IAudioService.Stub } } + /** @see AudioManager#isSurroundFormatEnabled(int) */ + @Override + public boolean isSurroundFormatEnabled(int audioFormat) { + if (!isSurroundFormat(audioFormat)) { + Log.w(TAG, "audioFormat to enable is not a surround format."); + return false; + } + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.WRITE_SETTINGS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Missing WRITE_SETTINGS permission"); + } + + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mSettingsLock) { + HashSet<Integer> enabledFormats = getEnabledFormats(); + return enabledFormats.contains(audioFormat); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + + /** @see AudioManager#setSurroundFormatEnabled(int, boolean) */ + @Override + public boolean setSurroundFormatEnabled(int audioFormat, boolean enabled) { + if (!isSurroundFormat(audioFormat)) { + Log.w(TAG, "audioFormat to enable is not a surround format."); + return false; + } + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.WRITE_SETTINGS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Missing WRITE_SETTINGS permission"); + } + + HashSet<Integer> enabledFormats = getEnabledFormats(); + if (enabled) { + enabledFormats.add(audioFormat); + } else { + enabledFormats.remove(audioFormat); + } + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mSettingsLock) { + Settings.Global.putString(mContentResolver, + Settings.Global.ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS, + TextUtils.join(",", enabledFormats)); + } + } finally { + Binder.restoreCallingIdentity(token); + } + return true; + } + + /** @see AudioManager#setEncodedSurroundMode(int) */ + @Override + public boolean setEncodedSurroundMode(int mode) { + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.WRITE_SETTINGS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Missing WRITE_SETTINGS permission"); + } + + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mSettingsLock) { + Settings.Global.putInt(mContentResolver, + Settings.Global.ENCODED_SURROUND_OUTPUT, + mode); + } + } finally { + Binder.restoreCallingIdentity(token); + } + return true; + } + + /** @see AudioManager#getEncodedSurroundMode() */ + @Override + public int getEncodedSurroundMode() { + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.WRITE_SETTINGS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Missing WRITE_SETTINGS permission"); + } + + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mSettingsLock) { + return Settings.Global.getInt(mContentResolver, + Settings.Global.ENCODED_SURROUND_OUTPUT, + AudioManager.ENCODED_SURROUND_OUTPUT_AUTO); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + + /** @return the formats that are enabled in global settings */ + private HashSet<Integer> getEnabledFormats() { + HashSet<Integer> formats = new HashSet<>(); + String enabledFormats = Settings.Global.getString(mContentResolver, + Settings.Global.ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS); + if (enabledFormats != null) { + try { + Arrays.stream(TextUtils.split(enabledFormats, ",")) + .mapToInt(Integer::parseInt) + .forEach(formats::add); + } catch (NumberFormatException e) { + Log.w(TAG, "ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS misformatted.", e); + } + } + return formats; + } + + private boolean isSurroundFormat(int audioFormat) { + for (int sf : AudioFormat.SURROUND_SOUND_ENCODING) { + if (sf == audioFormat) { + return true; + } + } + return false; + } + private void sendEnabledSurroundFormats(ContentResolver cr, boolean forceUpdate) { if (mEncodedSurroundMode != Settings.Global.ENCODED_SURROUND_OUTPUT_MANUAL) { // Manually enable surround formats only when the setting is in manual mode. @@ -1839,14 +1960,7 @@ public class AudioService extends IAudioService.Stub for (String format : surroundFormats) { try { int audioFormat = Integer.valueOf(format); - boolean isSurroundFormat = false; - for (int sf : AudioFormat.SURROUND_SOUND_ENCODING) { - if (sf == audioFormat) { - isSurroundFormat = true; - break; - } - } - if (isSurroundFormat && !formats.contains(audioFormat)) { + if (isSurroundFormat(audioFormat) && !formats.contains(audioFormat)) { formats.add(audioFormat); } } catch (Exception e) { @@ -7309,7 +7423,6 @@ public class AudioService extends IAudioService.Stub Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO); mContentResolver.registerContentObserver(Settings.Global.getUriFor( Settings.Global.ENCODED_SURROUND_OUTPUT), false, this); - mEnabledSurroundFormats = Settings.Global.getString( mContentResolver, Settings.Global.ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS); mContentResolver.registerContentObserver(Settings.Global.getUriFor( |