mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Detect external surround sound on Amazon devices
PiperOrigin-RevId: 241544595
This commit is contained in:
parent
9b064fb9d5
commit
7c265dfb3a
2 changed files with 106 additions and 31 deletions
|
|
@ -22,7 +22,10 @@ import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.media.AudioFormat;
|
import android.media.AudioFormat;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.provider.Settings.Global;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
/** Represents the set of audio formats that a device is capable of playing. */
|
/** 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 =
|
public static final AudioCapabilities DEFAULT_AUDIO_CAPABILITIES =
|
||||||
new AudioCapabilities(new int[] {AudioFormat.ENCODING_PCM_16BIT}, DEFAULT_MAX_CHANNEL_COUNT);
|
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.
|
* Returns the current audio capabilities for the device.
|
||||||
*
|
*
|
||||||
|
|
@ -43,12 +57,18 @@ public final class AudioCapabilities {
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("InlinedApi")
|
@SuppressWarnings("InlinedApi")
|
||||||
public static AudioCapabilities getCapabilities(Context context) {
|
public static AudioCapabilities getCapabilities(Context context) {
|
||||||
return getCapabilities(
|
Intent intent =
|
||||||
context.registerReceiver(null, new IntentFilter(AudioManager.ACTION_HDMI_AUDIO_PLUG)));
|
context.registerReceiver(
|
||||||
|
/* receiver= */ null, new IntentFilter(AudioManager.ACTION_HDMI_AUDIO_PLUG));
|
||||||
|
return getCapabilities(context, intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("InlinedApi")
|
@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) {
|
if (intent == null || intent.getIntExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, 0) == 0) {
|
||||||
return DEFAULT_AUDIO_CAPABILITIES;
|
return DEFAULT_AUDIO_CAPABILITIES;
|
||||||
}
|
}
|
||||||
|
|
@ -58,6 +78,17 @@ public final class AudioCapabilities {
|
||||||
AudioManager.EXTRA_MAX_CHANNEL_COUNT, /* defaultValue= */ DEFAULT_MAX_CHANNEL_COUNT));
|
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[] supportedEncodings;
|
||||||
private final int maxChannelCount;
|
private final int maxChannelCount;
|
||||||
|
|
||||||
|
|
@ -124,4 +155,7 @@ public final class AudioCapabilities {
|
||||||
+ ", supportedEncodings=" + Arrays.toString(supportedEncodings) + "]";
|
+ ", supportedEncodings=" + Arrays.toString(supportedEncodings) + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean deviceMaySetExternalSurroundSoundGlobalSetting() {
|
||||||
|
return Util.SDK_INT >= 17 && "Amazon".equals(Util.MANUFACTURER);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,13 @@
|
||||||
package com.google.android.exoplayer2.audio;
|
package com.google.android.exoplayer2.audio;
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
|
import android.database.ContentObserver;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
|
|
@ -46,31 +49,30 @@ public final class AudioCapabilitiesReceiver {
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final @Nullable Handler handler;
|
|
||||||
private final Listener listener;
|
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;
|
/* package */ @Nullable AudioCapabilities audioCapabilities;
|
||||||
|
private boolean registered;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param context A context for registering the receiver.
|
* @param context A context for registering the receiver.
|
||||||
* @param listener The listener to notify when audio capabilities change.
|
* @param listener The listener to notify when audio capabilities change.
|
||||||
*/
|
*/
|
||||||
public AudioCapabilitiesReceiver(Context context, Listener listener) {
|
public AudioCapabilitiesReceiver(Context context, Listener listener) {
|
||||||
this(context, /* handler= */ null, listener);
|
context = context.getApplicationContext();
|
||||||
}
|
this.context = context;
|
||||||
|
|
||||||
/**
|
|
||||||
* @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;
|
|
||||||
this.listener = Assertions.checkNotNull(listener);
|
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")
|
@SuppressWarnings("InlinedApi")
|
||||||
public AudioCapabilities register() {
|
public AudioCapabilities register() {
|
||||||
|
if (registered) {
|
||||||
|
return Assertions.checkNotNull(audioCapabilities);
|
||||||
|
}
|
||||||
|
registered = true;
|
||||||
|
if (externalSurroundSoundSettingObserver != null) {
|
||||||
|
externalSurroundSoundSettingObserver.register();
|
||||||
|
}
|
||||||
Intent stickyIntent = null;
|
Intent stickyIntent = null;
|
||||||
if (receiver != null) {
|
if (receiver != null) {
|
||||||
IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_HDMI_AUDIO_PLUG);
|
IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_HDMI_AUDIO_PLUG);
|
||||||
if (handler != null) {
|
stickyIntent =
|
||||||
stickyIntent =
|
context.registerReceiver(
|
||||||
context.registerReceiver(
|
receiver, intentFilter, /* broadcastPermission= */ null, handler);
|
||||||
receiver, intentFilter, /* broadcastPermission= */ null, handler);
|
|
||||||
} else {
|
|
||||||
stickyIntent = context.registerReceiver(receiver, intentFilter);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
audioCapabilities = AudioCapabilities.getCapabilities(stickyIntent);
|
audioCapabilities = AudioCapabilities.getCapabilities(context, stickyIntent);
|
||||||
return audioCapabilities;
|
return audioCapabilities;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -102,9 +107,24 @@ public final class AudioCapabilitiesReceiver {
|
||||||
* changes occur.
|
* changes occur.
|
||||||
*/
|
*/
|
||||||
public void unregister() {
|
public void unregister() {
|
||||||
|
if (!registered) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
audioCapabilities = null;
|
||||||
if (receiver != null) {
|
if (receiver != null) {
|
||||||
context.unregisterReceiver(receiver);
|
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 {
|
private final class HdmiAudioPlugBroadcastReceiver extends BroadcastReceiver {
|
||||||
|
|
@ -112,14 +132,35 @@ public final class AudioCapabilitiesReceiver {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
if (!isInitialStickyBroadcast()) {
|
if (!isInitialStickyBroadcast()) {
|
||||||
AudioCapabilities newAudioCapabilities = AudioCapabilities.getCapabilities(intent);
|
onNewAudioCapabilities(AudioCapabilities.getCapabilities(context, intent));
|
||||||
if (!newAudioCapabilities.equals(audioCapabilities)) {
|
|
||||||
audioCapabilities = newAudioCapabilities;
|
|
||||||
listener.onAudioCapabilitiesChanged(newAudioCapabilities);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue