From 7c265dfb3a1d485ab794823f3e2a7344b20b5a47 Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 2 Apr 2019 17:36:52 +0100 Subject: [PATCH] Detect external surround sound on Amazon devices PiperOrigin-RevId: 241544595 --- .../exoplayer2/audio/AudioCapabilities.java | 40 +++++++- .../audio/AudioCapabilitiesReceiver.java | 97 +++++++++++++------ 2 files changed, 106 insertions(+), 31 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioCapabilities.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioCapabilities.java index e7495acd89..25c0e70ae5 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioCapabilities.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioCapabilities.java @@ -22,7 +22,10 @@ import android.content.Intent; import android.content.IntentFilter; import android.media.AudioFormat; import android.media.AudioManager; +import android.net.Uri; +import android.provider.Settings.Global; import androidx.annotation.Nullable; +import com.google.android.exoplayer2.util.Util; import java.util.Arrays; /** Represents the set of audio formats that a device is capable of playing. */ @@ -35,6 +38,17 @@ public final class AudioCapabilities { public static final AudioCapabilities DEFAULT_AUDIO_CAPABILITIES = new AudioCapabilities(new int[] {AudioFormat.ENCODING_PCM_16BIT}, DEFAULT_MAX_CHANNEL_COUNT); + /** Audio capabilities when the device specifies external surround sound. */ + private static final AudioCapabilities EXTERNAL_SURROUND_SOUND_CAPABILITIES = + new AudioCapabilities( + new int[] { + AudioFormat.ENCODING_PCM_16BIT, AudioFormat.ENCODING_AC3, AudioFormat.ENCODING_E_AC3 + }, + DEFAULT_MAX_CHANNEL_COUNT); + + /** Global settings key for devices that can specify external surround sound. */ + private static final String EXTERNAL_SURROUND_SOUND_KEY = "external_surround_sound_enabled"; + /** * Returns the current audio capabilities for the device. * @@ -43,12 +57,18 @@ public final class AudioCapabilities { */ @SuppressWarnings("InlinedApi") public static AudioCapabilities getCapabilities(Context context) { - return getCapabilities( - context.registerReceiver(null, new IntentFilter(AudioManager.ACTION_HDMI_AUDIO_PLUG))); + Intent intent = + context.registerReceiver( + /* receiver= */ null, new IntentFilter(AudioManager.ACTION_HDMI_AUDIO_PLUG)); + return getCapabilities(context, intent); } @SuppressLint("InlinedApi") - /* package */ static AudioCapabilities getCapabilities(@Nullable Intent intent) { + /* package */ static AudioCapabilities getCapabilities(Context context, @Nullable Intent intent) { + if (deviceMaySetExternalSurroundSoundGlobalSetting() + && Global.getInt(context.getContentResolver(), EXTERNAL_SURROUND_SOUND_KEY, 0) == 1) { + return EXTERNAL_SURROUND_SOUND_CAPABILITIES; + } if (intent == null || intent.getIntExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, 0) == 0) { return DEFAULT_AUDIO_CAPABILITIES; } @@ -58,6 +78,17 @@ public final class AudioCapabilities { AudioManager.EXTRA_MAX_CHANNEL_COUNT, /* defaultValue= */ DEFAULT_MAX_CHANNEL_COUNT)); } + /** + * Returns the global settings {@link Uri} used by the device to specify external surround sound, + * or null if the device does not support this functionality. + */ + @Nullable + /* package */ static Uri getExternalSurroundSoundGlobalSettingUri() { + return deviceMaySetExternalSurroundSoundGlobalSetting() + ? Global.getUriFor(EXTERNAL_SURROUND_SOUND_KEY) + : null; + } + private final int[] supportedEncodings; private final int maxChannelCount; @@ -124,4 +155,7 @@ public final class AudioCapabilities { + ", supportedEncodings=" + Arrays.toString(supportedEncodings) + "]"; } + private static boolean deviceMaySetExternalSurroundSoundGlobalSetting() { + return Util.SDK_INT >= 17 && "Amazon".equals(Util.MANUFACTURER); + } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioCapabilitiesReceiver.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioCapabilitiesReceiver.java index ed7a6f91d3..fe84c49656 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioCapabilitiesReceiver.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioCapabilitiesReceiver.java @@ -16,10 +16,13 @@ package com.google.android.exoplayer2.audio; import android.content.BroadcastReceiver; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.database.ContentObserver; import android.media.AudioManager; +import android.net.Uri; import android.os.Handler; import androidx.annotation.Nullable; import com.google.android.exoplayer2.util.Assertions; @@ -46,31 +49,30 @@ public final class AudioCapabilitiesReceiver { } private final Context context; - private final @Nullable Handler handler; private final Listener listener; - private final @Nullable BroadcastReceiver receiver; + private final Handler handler; + @Nullable private final BroadcastReceiver receiver; + @Nullable private final ExternalSurroundSoundSettingObserver externalSurroundSoundSettingObserver; /* package */ @Nullable AudioCapabilities audioCapabilities; + private boolean registered; /** * @param context A context for registering the receiver. * @param listener The listener to notify when audio capabilities change. */ public AudioCapabilitiesReceiver(Context context, Listener listener) { - this(context, /* handler= */ null, listener); - } - - /** - * @param context A context for registering the receiver. - * @param handler The handler to which {@link Listener} events will be posted. If null, listener - * methods are invoked on the main thread. - * @param listener The listener to notify when audio capabilities change. - */ - public AudioCapabilitiesReceiver(Context context, @Nullable Handler handler, Listener listener) { - this.context = Assertions.checkNotNull(context); - this.handler = handler; + context = context.getApplicationContext(); + this.context = context; this.listener = Assertions.checkNotNull(listener); - this.receiver = Util.SDK_INT >= 21 ? new HdmiAudioPlugBroadcastReceiver() : null; + handler = new Handler(Util.getLooper()); + receiver = Util.SDK_INT >= 21 ? new HdmiAudioPlugBroadcastReceiver() : null; + Uri externalSurroundSoundUri = AudioCapabilities.getExternalSurroundSoundGlobalSettingUri(); + externalSurroundSoundSettingObserver = + externalSurroundSoundUri != null + ? new ExternalSurroundSoundSettingObserver( + handler, context.getContentResolver(), externalSurroundSoundUri) + : null; } /** @@ -82,18 +84,21 @@ public final class AudioCapabilitiesReceiver { */ @SuppressWarnings("InlinedApi") public AudioCapabilities register() { + if (registered) { + return Assertions.checkNotNull(audioCapabilities); + } + registered = true; + if (externalSurroundSoundSettingObserver != null) { + externalSurroundSoundSettingObserver.register(); + } Intent stickyIntent = null; if (receiver != null) { IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_HDMI_AUDIO_PLUG); - if (handler != null) { - stickyIntent = - context.registerReceiver( - receiver, intentFilter, /* broadcastPermission= */ null, handler); - } else { - stickyIntent = context.registerReceiver(receiver, intentFilter); - } + stickyIntent = + context.registerReceiver( + receiver, intentFilter, /* broadcastPermission= */ null, handler); } - audioCapabilities = AudioCapabilities.getCapabilities(stickyIntent); + audioCapabilities = AudioCapabilities.getCapabilities(context, stickyIntent); return audioCapabilities; } @@ -102,9 +107,24 @@ public final class AudioCapabilitiesReceiver { * changes occur. */ public void unregister() { + if (!registered) { + return; + } + audioCapabilities = null; if (receiver != null) { context.unregisterReceiver(receiver); } + if (externalSurroundSoundSettingObserver != null) { + externalSurroundSoundSettingObserver.unregister(); + } + registered = false; + } + + private void onNewAudioCapabilities(AudioCapabilities newAudioCapabilities) { + if (registered && !newAudioCapabilities.equals(audioCapabilities)) { + audioCapabilities = newAudioCapabilities; + listener.onAudioCapabilitiesChanged(newAudioCapabilities); + } } private final class HdmiAudioPlugBroadcastReceiver extends BroadcastReceiver { @@ -112,14 +132,35 @@ public final class AudioCapabilitiesReceiver { @Override public void onReceive(Context context, Intent intent) { if (!isInitialStickyBroadcast()) { - AudioCapabilities newAudioCapabilities = AudioCapabilities.getCapabilities(intent); - if (!newAudioCapabilities.equals(audioCapabilities)) { - audioCapabilities = newAudioCapabilities; - listener.onAudioCapabilitiesChanged(newAudioCapabilities); - } + onNewAudioCapabilities(AudioCapabilities.getCapabilities(context, intent)); } } + } + private final class ExternalSurroundSoundSettingObserver extends ContentObserver { + + private final ContentResolver resolver; + private final Uri settingUri; + + public ExternalSurroundSoundSettingObserver( + Handler handler, ContentResolver resolver, Uri settingUri) { + super(handler); + this.resolver = resolver; + this.settingUri = settingUri; + } + + public void register() { + resolver.registerContentObserver(settingUri, /* notifyForDescendants= */ false, this); + } + + public void unregister() { + resolver.unregisterContentObserver(this); + } + + @Override + public void onChange(boolean selfChange) { + onNewAudioCapabilities(AudioCapabilities.getCapabilities(context)); + } } }