Skip to content

Commit fc558f6

Browse files
committed
Selected automatically audio role flag from AccessibilityManager
1 parent 7cdd4ea commit fc558f6

File tree

3 files changed

+96
-6
lines changed

3 files changed

+96
-6
lines changed

demos/main/src/main/assets/media.exolist.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,19 @@
725725
}
726726
]
727727
},
728+
{
729+
"name": "Audio description",
730+
"samples": [
731+
{
732+
"name": "DASH unified streaming - Audio description (ENG)",
733+
"uri": "https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel-desc-aud.ism/.mpd"
734+
},
735+
{
736+
"name": "HLS The Morning Show - Change: Season 2",
737+
"uri": "https://play-edge.itunes.apple.com/WebObjects/MZPlayLocal.woa/hls/subscription/playlist.m3u8?cc=CH&svcId=tvs.vds.4021&a=1568297173&isExternal=true&brandId=tvs.sbd.4000&id=518034010&l=en-GB&aec=UHD"
738+
}
739+
]
740+
},
728741
{
729742
"name": "Progressive",
730743
"samples": [

libraries/common/src/main/java/androidx/media3/common/TrackSelectionParameters.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ public static class Builder {
9595
private ImmutableList<String> preferredAudioLanguages;
9696
private ImmutableList<String> preferredAudioLabels;
9797
private @C.RoleFlags int preferredAudioRoleFlags;
98+
private boolean usePreferredAudioRoleFlagsFromAccessibilityManager;
9899
private int maxAudioChannelCount;
99100
private int maxAudioBitrate;
100101
private ImmutableList<String> preferredAudioMimeTypes;
@@ -134,6 +135,7 @@ public Builder() {
134135
preferredAudioLanguages = ImmutableList.of();
135136
preferredAudioLabels = ImmutableList.of();
136137
preferredAudioRoleFlags = 0;
138+
usePreferredAudioRoleFlagsFromAccessibilityManager = true;
137139
maxAudioChannelCount = Integer.MAX_VALUE;
138140
maxAudioBitrate = Integer.MAX_VALUE;
139141
preferredAudioMimeTypes = ImmutableList.of();
@@ -213,6 +215,9 @@ protected Builder(Bundle bundle) {
213215
firstNonNull(bundle.getStringArray(FIELD_PREFERRED_AUDIO_LABELS), new String[0]));
214216
preferredAudioRoleFlags =
215217
bundle.getInt(FIELD_PREFERRED_AUDIO_ROLE_FLAGS, DEFAULT.preferredAudioRoleFlags);
218+
usePreferredAudioRoleFlagsFromAccessibilityManager = bundle.getBoolean(
219+
FIELD_USE_PREFERRED_AUDI_ROLE_FLAGS_FROM_ACCESSIBILITY_MANAGER,
220+
DEFAULT.usePreferredAudioRoleFlagsFromAccessibilityManager);
216221
maxAudioChannelCount =
217222
bundle.getInt(FIELD_MAX_AUDIO_CHANNEL_COUNT, DEFAULT.maxAudioChannelCount);
218223
maxAudioBitrate = bundle.getInt(FIELD_MAX_AUDIO_BITRATE, DEFAULT.maxAudioBitrate);
@@ -329,6 +334,7 @@ private void init(@UnknownInitialization Builder this, TrackSelectionParameters
329334
// Audio
330335
preferredAudioLanguages = parameters.preferredAudioLanguages;
331336
preferredAudioRoleFlags = parameters.preferredAudioRoleFlags;
337+
usePreferredAudioRoleFlagsFromAccessibilityManager = parameters.usePreferredAudioRoleFlagsFromAccessibilityManager;
332338
preferredAudioLabels = parameters.preferredAudioLabels;
333339
maxAudioChannelCount = parameters.maxAudioChannelCount;
334340
maxAudioBitrate = parameters.maxAudioBitrate;
@@ -635,6 +641,19 @@ public Builder setPreferredAudioLanguages(String... preferredAudioLanguages) {
635641
@CanIgnoreReturnValue
636642
public Builder setPreferredAudioRoleFlags(@C.RoleFlags int preferredAudioRoleFlags) {
637643
this.preferredAudioRoleFlags = preferredAudioRoleFlags;
644+
this.usePreferredAudioRoleFlagsFromAccessibilityManager = false;
645+
return this;
646+
}
647+
648+
/**
649+
* Set preferred audio role flag from accessibility manager
650+
*
651+
* @return This builder.
652+
*/
653+
@CanIgnoreReturnValue
654+
public Builder setPreferredAudioRoleFlagsFromAccessibilityManager() {
655+
this.usePreferredAudioRoleFlagsFromAccessibilityManager = true;
656+
this.preferredAudioRoleFlags = 0;
638657
return this;
639658
}
640659

@@ -1299,6 +1318,8 @@ public static TrackSelectionParameters getDefaults(Context context) {
12991318
*/
13001319
public final @C.RoleFlags int preferredAudioRoleFlags;
13011320

1321+
public final boolean usePreferredAudioRoleFlagsFromAccessibilityManager;
1322+
13021323
/**
13031324
* Maximum allowed audio channel count. The default value is {@link Integer#MAX_VALUE} (i.e. no
13041325
* constraint).
@@ -1427,6 +1448,7 @@ protected TrackSelectionParameters(Builder builder) {
14271448
// Audio
14281449
this.preferredAudioLanguages = builder.preferredAudioLanguages;
14291450
this.preferredAudioRoleFlags = builder.preferredAudioRoleFlags;
1451+
this.usePreferredAudioRoleFlagsFromAccessibilityManager = builder.usePreferredAudioRoleFlagsFromAccessibilityManager;
14301452
this.maxAudioChannelCount = builder.maxAudioChannelCount;
14311453
this.preferredAudioLabels = builder.preferredAudioLabels;
14321454
this.maxAudioBitrate = builder.maxAudioBitrate;
@@ -1485,6 +1507,8 @@ public boolean equals(@Nullable Object obj) {
14851507
&& preferredVideoRoleFlags == other.preferredVideoRoleFlags
14861508
// Audio
14871509
&& preferredAudioLanguages.equals(other.preferredAudioLanguages)
1510+
&& usePreferredAudioRoleFlagsFromAccessibilityManager
1511+
== other.usePreferredAudioRoleFlagsFromAccessibilityManager
14881512
&& preferredAudioRoleFlags == other.preferredAudioRoleFlags
14891513
&& maxAudioChannelCount == other.maxAudioChannelCount
14901514
&& preferredAudioLabels.equals(other.preferredAudioLabels)
@@ -1532,6 +1556,7 @@ public int hashCode() {
15321556
// Audio
15331557
result = 31 * result + preferredAudioLanguages.hashCode();
15341558
result = 31 * result + preferredAudioRoleFlags;
1559+
result = 31 * result + (usePreferredAudioRoleFlagsFromAccessibilityManager ? 1 : 0);
15351560
result = 31 * result + maxAudioChannelCount;
15361561
result = 31 * result + preferredAudioLabels.hashCode();
15371562
result = 31 * result + maxAudioBitrate;
@@ -1597,6 +1622,9 @@ public int hashCode() {
15971622
private static final String FIELD_PREFERRED_VIDEO_LABELS = Util.intToStringMaxRadix(36);
15981623
private static final String FIELD_PREFERRED_AUDIO_LABELS = Util.intToStringMaxRadix(37);
15991624
private static final String FIELD_PREFERRED_TEXT_LABELS = Util.intToStringMaxRadix(38);
1625+
private static final String
1626+
FIELD_USE_PREFERRED_AUDI_ROLE_FLAGS_FROM_ACCESSIBILITY_MANAGER =
1627+
Util.intToStringMaxRadix(39);
16001628

16011629
/**
16021630
* Defines a minimum field ID value for subclasses to use when implementing {@link #toBundle()}
@@ -1638,6 +1666,9 @@ public Bundle toBundle() {
16381666
bundle.putStringArray(
16391667
FIELD_PREFERRED_AUDIO_LANGUAGES, preferredAudioLanguages.toArray(new String[0]));
16401668
bundle.putInt(FIELD_PREFERRED_AUDIO_ROLE_FLAGS, preferredAudioRoleFlags);
1669+
bundle.putBoolean(
1670+
FIELD_USE_PREFERRED_AUDI_ROLE_FLAGS_FROM_ACCESSIBILITY_MANAGER,
1671+
usePreferredAudioRoleFlagsFromAccessibilityManager);
16411672
bundle.putInt(FIELD_MAX_AUDIO_CHANNEL_COUNT, maxAudioChannelCount);
16421673
bundle.putInt(FIELD_MAX_AUDIO_BITRATE, maxAudioBitrate);
16431674
bundle.putStringArray(

libraries/exoplayer/src/main/java/androidx/media3/exoplayer/trackselection/DefaultTrackSelector.java

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
package androidx.media3.exoplayer.trackselection;
1717

1818
import static android.os.Build.VERSION.SDK_INT;
19+
import static androidx.media3.common.C.ROLE_FLAG_DESCRIBES_MUSIC_AND_SOUND;
20+
import static androidx.media3.common.C.ROLE_FLAG_DESCRIBES_VIDEO;
1921
import static androidx.media3.common.TrackSelectionParameters.AudioOffloadPreferences.AUDIO_OFFLOAD_MODE_DISABLED;
2022
import static androidx.media3.common.TrackSelectionParameters.AudioOffloadPreferences.AUDIO_OFFLOAD_MODE_REQUIRED;
2123
import static androidx.media3.common.util.Assertions.checkNotNull;
@@ -34,13 +36,15 @@
3436
import android.media.AudioFormat;
3537
import android.media.AudioManager;
3638
import android.media.Spatializer;
39+
import android.os.Build;
3740
import android.os.Bundle;
3841
import android.os.Handler;
3942
import android.os.Looper;
4043
import android.text.TextUtils;
4144
import android.util.Pair;
4245
import android.util.SparseArray;
4346
import android.util.SparseBooleanArray;
47+
import android.view.accessibility.AccessibilityManager;
4448
import android.view.accessibility.CaptioningManager;
4549
import androidx.annotation.GuardedBy;
4650
import androidx.annotation.IntDef;
@@ -410,6 +414,14 @@ public ParametersBuilder setPreferredAudioRoleFlags(@C.RoleFlags int preferredAu
410414
return this;
411415
}
412416

417+
@SuppressWarnings("deprecation") // Intentionally returning deprecated type
418+
@CanIgnoreReturnValue
419+
@Override
420+
public ParametersBuilder setPreferredAudioRoleFlagsFromAccessibilityManager() {
421+
delegate.setPreferredAudioRoleFlagsFromAccessibilityManager();
422+
return this;
423+
}
424+
413425
@SuppressWarnings("deprecation") // Intentionally returning deprecated type
414426
@CanIgnoreReturnValue
415427
@Override
@@ -1264,6 +1276,13 @@ public Builder setPreferredAudioRoleFlags(@C.RoleFlags int preferredAudioRoleFla
12641276
return this;
12651277
}
12661278

1279+
@CanIgnoreReturnValue
1280+
@Override
1281+
public Builder setPreferredAudioRoleFlagsFromAccessibilityManager() {
1282+
super.setPreferredAudioRoleFlagsFromAccessibilityManager();
1283+
return this;
1284+
}
1285+
12671286
@CanIgnoreReturnValue
12681287
@Override
12691288
public Builder setPreferredAudioLabels(String... preferredAudioLabels) {
@@ -2910,7 +2929,13 @@ protected Pair<ExoTrackSelection.Definition, Integer> selectAudioTrack(
29102929
break;
29112930
}
29122931
}
2932+
2933+
@RoleFlags int preferredRoleFlagFromAccessibilityManager = 0;
2934+
if (SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
2935+
preferredRoleFlagFromAccessibilityManager = getPreferredRoleFlagFromAccessibilityManager(context);
2936+
}
29132937
boolean hasVideoRendererWithMappedTracksFinal = hasVideoRendererWithMappedTracks;
2938+
@RoleFlags int preferredRoleFlagFromAccessibilityManagerFinal = preferredRoleFlagFromAccessibilityManager;
29142939
return selectTracksForType(
29152940
C.TRACK_TYPE_AUDIO,
29162941
mappedTrackInfo,
@@ -2923,7 +2948,8 @@ protected Pair<ExoTrackSelection.Definition, Integer> selectAudioTrack(
29232948
support,
29242949
hasVideoRendererWithMappedTracksFinal,
29252950
format -> isAudioFormatWithinAudioChannelCountConstraints(format, params),
2926-
rendererMixedMimeTypeAdaptationSupports[rendererIndex]),
2951+
rendererMixedMimeTypeAdaptationSupports[rendererIndex],
2952+
preferredRoleFlagFromAccessibilityManagerFinal),
29272953
AudioTrackInfo::compareSelections);
29282954
}
29292955

@@ -3601,6 +3627,21 @@ private static String getPreferredLanguageFromCaptioningManager(@Nullable Contex
36013627
return Util.getLocaleLanguageTag(preferredLocale);
36023628
}
36033629

3630+
@RequiresApi(api = Build.VERSION_CODES.TIRAMISU)
3631+
private static @RoleFlags int getPreferredRoleFlagFromAccessibilityManager(
3632+
@Nullable Context context) {
3633+
if (context == null) {
3634+
return 0;
3635+
}
3636+
AccessibilityManager accessibilityManager = (AccessibilityManager) context.getSystemService(
3637+
Context.ACCESSIBILITY_SERVICE);
3638+
if (accessibilityManager != null) {
3639+
return accessibilityManager.isAudioDescriptionRequested() ? ROLE_FLAG_DESCRIBES_VIDEO
3640+
| ROLE_FLAG_DESCRIBES_MUSIC_AND_SOUND : 0;
3641+
}
3642+
return 0;
3643+
}
3644+
36043645
/** Base class for track selection information of a {@link Format}. */
36053646
private abstract static class TrackInfo<T extends TrackInfo<T>> {
36063647
/** Factory for {@link TrackInfo} implementations for a given {@link TrackGroup}. */
@@ -3910,7 +3951,8 @@ public static ImmutableList<AudioTrackInfo> createForTrackGroup(
39103951
@Capabilities int[] formatSupport,
39113952
boolean hasMappedVideoTracks,
39123953
Predicate<Format> withinAudioChannelCountConstraints,
3913-
@AdaptiveSupport int mixedMimeTypeAdaptationSupport) {
3954+
@AdaptiveSupport int mixedMimeTypeAdaptationSupport,
3955+
@RoleFlags int preferredRoleFlagFromAccessibilityManager) {
39143956
ImmutableList.Builder<AudioTrackInfo> listBuilder = ImmutableList.builder();
39153957
for (int i = 0; i < trackGroup.length; i++) {
39163958
listBuilder.add(
@@ -3922,7 +3964,8 @@ public static ImmutableList<AudioTrackInfo> createForTrackGroup(
39223964
formatSupport[i],
39233965
hasMappedVideoTracks,
39243966
withinAudioChannelCountConstraints,
3925-
mixedMimeTypeAdaptationSupport));
3967+
mixedMimeTypeAdaptationSupport,
3968+
preferredRoleFlagFromAccessibilityManager));
39263969
}
39273970
return listBuilder.build();
39283971
}
@@ -3957,7 +4000,8 @@ public AudioTrackInfo(
39574000
@Capabilities int formatSupport,
39584001
boolean hasMappedVideoTracks,
39594002
Predicate<Format> withinAudioChannelCountConstraints,
3960-
@AdaptiveSupport int mixedMimeTypeAdaptationSupport) {
4003+
@AdaptiveSupport int mixedMimeTypeAdaptationSupport,
4004+
@RoleFlags int preferredRoleFlagFromAccessibilityManager) {
39614005
super(rendererIndex, trackGroup, trackIndex);
39624006
this.parameters = parameters;
39634007
@SuppressLint("WrongConstant")
@@ -3988,8 +4032,10 @@ public AudioTrackInfo(
39884032
}
39894033
preferredLanguageIndex = bestLanguageIndex;
39904034
preferredLanguageScore = bestLanguageScore;
3991-
preferredRoleFlagsScore =
3992-
getRoleFlagMatchScore(format.roleFlags, parameters.preferredAudioRoleFlags);
4035+
@RoleFlags int preferredAudioRoleFlags =
4036+
preferredRoleFlagFromAccessibilityManager == 0 ? parameters.preferredAudioRoleFlags
4037+
: preferredRoleFlagFromAccessibilityManager;
4038+
preferredRoleFlagsScore = getRoleFlagMatchScore(format.roleFlags, preferredAudioRoleFlags);
39934039
preferredLabelMatchIndex = getBestLabelMatchIndex(format, parameters.preferredAudioLabels);
39944040
hasMainOrNoRoleFlag = format.roleFlags == 0 || (format.roleFlags & C.ROLE_FLAG_MAIN) != 0;
39954041
isDefaultSelectionFlag = (format.selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0;

0 commit comments

Comments
 (0)