Skip to content

Commit 53e18a2

Browse files
committed
Make MediaControllerImplBase local binder aware
The session->controller data flow already nicely avoids bundling if we don't have to bundle by skipping the entire PlayerInfo object which contains almost everything. But in the controller->session data flow, some complex objects (MediaMetadata, MediaItem and TrackSelectionParameters) were always bundled even if we don't have to. This change skips bundling for these object and should improve performance significantly when sending large lists of MediaItems to a session in the same process.
1 parent 006dd06 commit 53e18a2

File tree

8 files changed

+223
-54
lines changed

8 files changed

+223
-54
lines changed

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

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,12 @@
2222
import static com.google.common.base.Preconditions.checkState;
2323

2424
import android.net.Uri;
25+
import android.os.Binder;
2526
import android.os.Bundle;
27+
import android.os.IBinder;
2628
import androidx.annotation.IntRange;
2729
import androidx.annotation.Nullable;
30+
import androidx.annotation.RestrictTo;
2831
import androidx.annotation.VisibleForTesting;
2932
import androidx.media3.common.util.BundleCollectionUtil;
3033
import androidx.media3.common.util.UnstableApi;
@@ -2393,6 +2396,7 @@ public int hashCode() {
23932396
private static final String FIELD_CLIPPING_PROPERTIES = Util.intToStringMaxRadix(3);
23942397
private static final String FIELD_REQUEST_METADATA = Util.intToStringMaxRadix(4);
23952398
private static final String FIELD_LOCAL_CONFIGURATION = Util.intToStringMaxRadix(5);
2399+
private static final String FIELD_IN_PROCESS_BINDER = Util.intToStringMaxRadix(6);
23962400

23972401
@UnstableApi
23982402
private Bundle toBundle(boolean includeLocalConfiguration, int interfaceVersion) {
@@ -2471,6 +2475,17 @@ public static MediaItem fromBundle(Bundle bundle) {
24712475
return fromBundle(bundle, MediaLibraryInfo.INTERFACE_VERSION);
24722476
}
24732477

2478+
/**
2479+
* Returns a {@link Bundle} containing the entirety of this {@link #MediaItem} object without
2480+
* bundling it, for use in local process communication only.
2481+
*/
2482+
@UnstableApi
2483+
public Bundle toBundleIncludeLocalConfigurationForLocalProcess() {
2484+
Bundle bundle = new Bundle();
2485+
bundle.putBinder(FIELD_IN_PROCESS_BINDER, new InProcessBinder());
2486+
return bundle;
2487+
}
2488+
24742489
/**
24752490
* Restores a {@code MediaItem} from a {@link Bundle}.
24762491
*
@@ -2480,6 +2495,10 @@ public static MediaItem fromBundle(Bundle bundle) {
24802495
@UnstableApi
24812496
@SuppressWarnings("deprecation") // Unbundling to ClippingProperties while it still exists.
24822497
public static MediaItem fromBundle(Bundle bundle, int interfaceVersion) {
2498+
IBinder inProcessBinder = bundle.getBinder(FIELD_IN_PROCESS_BINDER);
2499+
if (inProcessBinder instanceof InProcessBinder) {
2500+
return ((InProcessBinder) inProcessBinder).getMediaItem();
2501+
}
24832502
String mediaId = checkNotNull(bundle.getString(FIELD_MEDIA_ID, DEFAULT_MEDIA_ID));
24842503
@Nullable Bundle liveConfigurationBundle = bundle.getBundle(FIELD_LIVE_CONFIGURATION);
24852504
LiveConfiguration liveConfiguration;
@@ -2524,4 +2543,24 @@ public static MediaItem fromBundle(Bundle bundle, int interfaceVersion) {
25242543
mediaMetadata,
25252544
requestMetadata);
25262545
}
2546+
2547+
private final class InProcessBinder extends Binder {
2548+
public MediaItem getMediaItem() {
2549+
return MediaItem.this;
2550+
}
2551+
}
2552+
2553+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
2554+
@UnstableApi
2555+
public static final class ListInProcessBinder extends Binder {
2556+
private final ImmutableList<MediaItem> theList;
2557+
2558+
public ListInProcessBinder(List<MediaItem> theList) {
2559+
this.theList = ImmutableList.copyOf(theList);
2560+
}
2561+
2562+
public ImmutableList<MediaItem> getMediaItemList() {
2563+
return theList;
2564+
}
2565+
}
25272566
}

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
import static java.lang.annotation.ElementType.TYPE_USE;
2424

2525
import android.net.Uri;
26+
import android.os.Binder;
2627
import android.os.Bundle;
28+
import android.os.IBinder;
2729
import androidx.annotation.IntDef;
2830
import androidx.annotation.IntRange;
2931
import androidx.annotation.Nullable;
@@ -1343,6 +1345,7 @@ public int hashCode() {
13431345
private static final String FIELD_IS_BROWSABLE = Util.intToStringMaxRadix(32);
13441346
private static final String FIELD_DURATION_MS = Util.intToStringMaxRadix(33);
13451347
private static final String FIELD_SUPPORTED_COMMANDS = Util.intToStringMaxRadix(34);
1348+
private static final String FIELD_IN_PROCESS_BINDER = Util.intToStringMaxRadix(35);
13461349
private static final String FIELD_EXTRAS = Util.intToStringMaxRadix(1000);
13471350

13481351
// Use a fairly lenient threshold for sending byte array to legacy processes that don't support
@@ -1486,6 +1489,17 @@ public Bundle toBundle(int interfaceVersion) {
14861489
return bundle;
14871490
}
14881491

1492+
/**
1493+
* Returns a {@link Bundle} containing the entirety of this {@link #MediaMetadata} object without
1494+
* bundling it, for use in local process communication only.
1495+
*/
1496+
@UnstableApi
1497+
public Bundle toBundleForLocalProcess() {
1498+
Bundle bundle = new Bundle();
1499+
bundle.putBinder(FIELD_IN_PROCESS_BINDER, new InProcessBinder());
1500+
return bundle;
1501+
}
1502+
14891503
/**
14901504
* @deprecated Use {@link #fromBundle(Bundle, int)}.
14911505
*/
@@ -1505,6 +1519,10 @@ public static MediaMetadata fromBundle(Bundle bundle) {
15051519
@UnstableApi
15061520
@SuppressWarnings("deprecation") // Unbundling deprecated fields.
15071521
public static MediaMetadata fromBundle(Bundle bundle, int interfaceVersion) {
1522+
IBinder inProcessBinder = bundle.getBinder(FIELD_IN_PROCESS_BINDER);
1523+
if (inProcessBinder instanceof InProcessBinder) {
1524+
return ((InProcessBinder) inProcessBinder).getMediaMetadata();
1525+
}
15081526
Builder builder = new Builder();
15091527
builder
15101528
.setTitle(bundle.getCharSequence(FIELD_TITLE))
@@ -1677,4 +1695,10 @@ public static MediaMetadata fromBundle(Bundle bundle, int interfaceVersion) {
16771695
return MEDIA_TYPE_FOLDER_MIXED;
16781696
}
16791697
}
1698+
1699+
private final class InProcessBinder extends Binder {
1700+
public MediaMetadata getMediaMetadata() {
1701+
return MediaMetadata.this;
1702+
}
1703+
}
16801704
}

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222
import static java.lang.annotation.RetentionPolicy.SOURCE;
2323

2424
import android.content.Context;
25+
import android.os.Binder;
2526
import android.os.Bundle;
27+
import android.os.IBinder;
2628
import android.view.accessibility.CaptioningManager;
2729
import androidx.annotation.CallSuper;
2830
import androidx.annotation.IntDef;
@@ -1597,6 +1599,7 @@ public int hashCode() {
15971599
private static final String FIELD_PREFERRED_VIDEO_LABELS = Util.intToStringMaxRadix(36);
15981600
private static final String FIELD_PREFERRED_AUDIO_LABELS = Util.intToStringMaxRadix(37);
15991601
private static final String FIELD_PREFERRED_TEXT_LABELS = Util.intToStringMaxRadix(38);
1602+
private static final String FIELD_IN_PROCESS_BINDER = Util.intToStringMaxRadix(39);
16001603

16011604
/**
16021605
* Defines a minimum field ID value for subclasses to use when implementing {@link #toBundle()}
@@ -1675,8 +1678,29 @@ public Bundle toBundle() {
16751678
return bundle;
16761679
}
16771680

1681+
/**
1682+
* Returns a {@link Bundle} containing the entirety of this {@link #TrackSelectionParameters}
1683+
* object without bundling it, for use in local process communication only.
1684+
*/
1685+
@UnstableApi
1686+
public Bundle toBundleForLocalProcess() {
1687+
Bundle bundle = new Bundle();
1688+
bundle.putBinder(FIELD_IN_PROCESS_BINDER, new InProcessBinder());
1689+
return bundle;
1690+
}
1691+
16781692
/** Construct an instance from a {@link Bundle} produced by {@link #toBundle()}. */
16791693
public static TrackSelectionParameters fromBundle(Bundle bundle) {
1694+
IBinder inProcessBinder = bundle.getBinder(FIELD_IN_PROCESS_BINDER);
1695+
if (inProcessBinder instanceof InProcessBinder) {
1696+
return ((InProcessBinder) inProcessBinder).getTrackSelectionParameters();
1697+
}
16801698
return new Builder(bundle).build();
16811699
}
1700+
1701+
private final class InProcessBinder extends Binder {
1702+
public TrackSelectionParameters getTrackSelectionParameters() {
1703+
return TrackSelectionParameters.this;
1704+
}
1705+
}
16821706
}

libraries/common/src/test/java/androidx/media3/common/MediaItemTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,6 +1024,16 @@ public void buildUpon_wholeObjectSetters_equalsToOriginal() {
10241024
assertThat(copy).isEqualTo(mediaItem);
10251025
}
10261026

1027+
@Test
1028+
public void roundTripViaBundleForLocalProcess_yieldsSameInstance() {
1029+
MediaItem mediaItem = new MediaItem.Builder().setUri(URI_STRING).build();
1030+
MediaItem unbundledItem =
1031+
MediaItem.fromBundle(mediaItem.toBundleIncludeLocalConfigurationForLocalProcess(),
1032+
MediaLibraryInfo.INTERFACE_VERSION);
1033+
1034+
assertThat(mediaItem == unbundledItem).isTrue();
1035+
}
1036+
10271037
@Test
10281038
public void roundTripViaBundle_withoutLocalConfiguration_yieldsEqualInstance() {
10291039
MediaItem mediaItem =

libraries/common/src/test/java/androidx/media3/common/MediaMetadataTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,15 @@ public void roundTripViaBundle_withInterfaceVersionBelow9AndLargeArtworkData_doe
233233
assertThat(restoredMetadata.artworkData).isNull();
234234
}
235235

236+
public void roundTripViaBundleForLocalProcess_yieldsSameInstance() {
237+
MediaMetadata mediaMetadata = new MediaMetadata.Builder().setGenre("hi").build();
238+
MediaMetadata unbundledMetadata =
239+
MediaMetadata.fromBundle(mediaMetadata.toBundleForLocalProcess(),
240+
MediaLibraryInfo.INTERFACE_VERSION);
241+
242+
assertThat(mediaMetadata == unbundledMetadata).isTrue();
243+
}
244+
236245
@SuppressWarnings("deprecation") // Testing deprecated setter.
237246
@Test
238247
public void builderSetFolderType_toNone_setsIsBrowsableToFalse() {

libraries/common/src/test/java/androidx/media3/common/TrackSelectionParametersTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,16 @@ public void roundTripViaBundle_withOverride_yieldsEqualInstance() {
239239
.containsExactly(override.mediaTrackGroup, override);
240240
}
241241

242+
@Test
243+
public void roundTripViaBundleForLocalProcess_yieldsSameInstance() {
244+
TrackSelectionParameters parameters =
245+
new TrackSelectionParameters.Builder().setMaxVideoSizeSd().build();
246+
TrackSelectionParameters unbundledParameters =
247+
TrackSelectionParameters.fromBundle(parameters.toBundleForLocalProcess());
248+
249+
assertThat(parameters == unbundledParameters).isTrue();
250+
}
251+
242252
@Test
243253
public void roundTripViaBundle_withLegacyPreferenceFields_yieldsEqualInstance() {
244254
TrackSelectionParameters trackSelectionParameters =

libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -831,7 +831,9 @@ public void setMediaItem(MediaItem mediaItem) {
831831
iSession.setMediaItem(
832832
controllerStub,
833833
seq,
834-
mediaItem.toBundleIncludeLocalConfiguration(getSessionInterfaceVersion())));
834+
iSession instanceof MediaSessionStub
835+
? mediaItem.toBundleIncludeLocalConfigurationForLocalProcess()
836+
: mediaItem.toBundleIncludeLocalConfiguration(getSessionInterfaceVersion())));
835837

836838
setMediaItemsInternal(
837839
Collections.singletonList(mediaItem),
@@ -851,7 +853,9 @@ public void setMediaItem(MediaItem mediaItem, long startPositionMs) {
851853
iSession.setMediaItemWithStartPosition(
852854
controllerStub,
853855
seq,
854-
mediaItem.toBundleIncludeLocalConfiguration(getSessionInterfaceVersion()),
856+
iSession instanceof MediaSessionStub
857+
? mediaItem.toBundleIncludeLocalConfigurationForLocalProcess()
858+
: mediaItem.toBundleIncludeLocalConfiguration(getSessionInterfaceVersion()),
855859
startPositionMs));
856860

857861
setMediaItemsInternal(
@@ -872,7 +876,9 @@ public void setMediaItem(MediaItem mediaItem, boolean resetPosition) {
872876
iSession.setMediaItemWithResetPosition(
873877
controllerStub,
874878
seq,
875-
mediaItem.toBundleIncludeLocalConfiguration(getSessionInterfaceVersion()),
879+
iSession instanceof MediaSessionStub
880+
? mediaItem.toBundleIncludeLocalConfigurationForLocalProcess()
881+
: mediaItem.toBundleIncludeLocalConfiguration(getSessionInterfaceVersion()),
876882
resetPosition));
877883

878884
setMediaItemsInternal(
@@ -893,7 +899,9 @@ public void setMediaItems(List<MediaItem> mediaItems) {
893899
iSession.setMediaItems(
894900
controllerStub,
895901
seq,
896-
new BundleListRetriever(
902+
iSession instanceof MediaSessionStub
903+
? new MediaItem.ListInProcessBinder(mediaItems)
904+
: new BundleListRetriever(
897905
BundleCollectionUtil.toBundleList(
898906
mediaItems,
899907
item ->
@@ -918,7 +926,9 @@ public void setMediaItems(List<MediaItem> mediaItems, boolean resetPosition) {
918926
iSession.setMediaItemsWithResetPosition(
919927
controllerStub,
920928
seq,
921-
new BundleListRetriever(
929+
iSession instanceof MediaSessionStub
930+
? new MediaItem.ListInProcessBinder(mediaItems)
931+
: new BundleListRetriever(
922932
BundleCollectionUtil.toBundleList(
923933
mediaItems,
924934
item ->
@@ -943,7 +953,9 @@ public void setMediaItems(List<MediaItem> mediaItems, int startIndex, long start
943953
iSession.setMediaItemsWithStartIndex(
944954
controllerStub,
945955
seq,
946-
new BundleListRetriever(
956+
iSession instanceof MediaSessionStub
957+
? new MediaItem.ListInProcessBinder(mediaItems)
958+
: new BundleListRetriever(
947959
BundleCollectionUtil.toBundleList(
948960
mediaItems,
949961
item ->
@@ -964,7 +976,11 @@ public void setPlaylistMetadata(MediaMetadata playlistMetadata) {
964976
dispatchRemoteSessionTaskWithPlayerCommand(
965977
(iSession, seq) ->
966978
iSession.setPlaylistMetadata(
967-
controllerStub, seq, playlistMetadata.toBundle(getSessionInterfaceVersion())));
979+
controllerStub,
980+
seq,
981+
iSession instanceof MediaSessionStub
982+
? playlistMetadata.toBundleForLocalProcess()
983+
: playlistMetadata.toBundle(getSessionInterfaceVersion())));
968984

969985
if (!playerInfo.playlistMetadata.equals(playlistMetadata)) {
970986
playerInfo = playerInfo.copyWithPlaylistMetadata(playlistMetadata);
@@ -991,7 +1007,9 @@ public void addMediaItem(MediaItem mediaItem) {
9911007
iSession.addMediaItem(
9921008
controllerStub,
9931009
seq,
994-
mediaItem.toBundleIncludeLocalConfiguration(getSessionInterfaceVersion())));
1010+
iSession instanceof MediaSessionStub
1011+
? mediaItem.toBundleIncludeLocalConfigurationForLocalProcess()
1012+
: mediaItem.toBundleIncludeLocalConfiguration(getSessionInterfaceVersion())));
9951013

9961014
addMediaItemsInternal(
9971015
getCurrentTimeline().getWindowCount(), Collections.singletonList(mediaItem));
@@ -1010,7 +1028,9 @@ public void addMediaItem(int index, MediaItem mediaItem) {
10101028
controllerStub,
10111029
seq,
10121030
index,
1013-
mediaItem.toBundleIncludeLocalConfiguration(getSessionInterfaceVersion())));
1031+
iSession instanceof MediaSessionStub
1032+
? mediaItem.toBundleIncludeLocalConfigurationForLocalProcess()
1033+
: mediaItem.toBundleIncludeLocalConfiguration(getSessionInterfaceVersion())));
10141034

10151035
addMediaItemsInternal(index, Collections.singletonList(mediaItem));
10161036
}
@@ -1026,7 +1046,9 @@ public void addMediaItems(List<MediaItem> mediaItems) {
10261046
iSession.addMediaItems(
10271047
controllerStub,
10281048
seq,
1029-
new BundleListRetriever(
1049+
iSession instanceof MediaSessionStub
1050+
? new MediaItem.ListInProcessBinder(mediaItems)
1051+
: new BundleListRetriever(
10301052
BundleCollectionUtil.toBundleList(
10311053
mediaItems,
10321054
item ->
@@ -1049,7 +1071,9 @@ public void addMediaItems(int index, List<MediaItem> mediaItems) {
10491071
controllerStub,
10501072
seq,
10511073
index,
1052-
new BundleListRetriever(
1074+
iSession instanceof MediaSessionStub
1075+
? new MediaItem.ListInProcessBinder(mediaItems)
1076+
: new BundleListRetriever(
10531077
BundleCollectionUtil.toBundleList(
10541078
mediaItems,
10551079
item ->
@@ -1407,7 +1431,9 @@ public void replaceMediaItem(int index, MediaItem mediaItem) {
14071431
controllerStub,
14081432
seq,
14091433
index,
1410-
mediaItem.toBundleIncludeLocalConfiguration(getSessionInterfaceVersion()));
1434+
iSession instanceof MediaSessionStub
1435+
? mediaItem.toBundleIncludeLocalConfigurationForLocalProcess()
1436+
: mediaItem.toBundleIncludeLocalConfiguration(getSessionInterfaceVersion()));
14111437
} else {
14121438
iSession.addMediaItemWithIndex(
14131439
controllerStub,
@@ -1431,7 +1457,9 @@ public void replaceMediaItems(int fromIndex, int toIndex, List<MediaItem> mediaI
14311457
dispatchRemoteSessionTaskWithPlayerCommand(
14321458
(iSession, seq) -> {
14331459
IBinder mediaItemsBundleBinder =
1434-
new BundleListRetriever(
1460+
iSession instanceof MediaSessionStub
1461+
? new MediaItem.ListInProcessBinder(mediaItems)
1462+
: new BundleListRetriever(
14351463
BundleCollectionUtil.toBundleList(
14361464
mediaItems,
14371465
item ->
@@ -2145,7 +2173,12 @@ public void setTrackSelectionParameters(TrackSelectionParameters parameters) {
21452173

21462174
dispatchRemoteSessionTaskWithPlayerCommand(
21472175
(iSession, seq) ->
2148-
iSession.setTrackSelectionParameters(controllerStub, seq, parameters.toBundle()));
2176+
iSession.setTrackSelectionParameters(
2177+
controllerStub,
2178+
seq,
2179+
iSession instanceof MediaSessionStub
2180+
? parameters.toBundleForLocalProcess()
2181+
: parameters.toBundle()));
21492182

21502183
if (parameters != playerInfo.trackSelectionParameters) {
21512184
playerInfo = playerInfo.copyWithTrackSelectionParameters(parameters);

0 commit comments

Comments
 (0)