/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media3.session;
import static androidx.media3.common.util.Assertions.checkArgument;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.media3.common.Bundleable;
import androidx.media3.common.C;
import androidx.media3.common.Player.PositionInfo;
import androidx.media3.common.util.Util;
import com.google.common.base.Objects;
/**
* Position information to be shared between session and controller.
*
* <p>This class wraps {@link PositionInfo} and group relevant information in one place to
* atomically notify.
*/
/* package */ final class SessionPositionInfo implements Bundleable {
public static final PositionInfo DEFAULT_POSITION_INFO =
new PositionInfo(
/* windowUid= */ null,
/* mediaItemIndex= */ 0,
/* mediaItem= */ null,
/* periodUid= */ null,
/* periodIndex= */ 0,
/* positionMs= */ 0,
/* contentPositionMs= */ 0,
/* adGroupIndex= */ C.INDEX_UNSET,
/* adIndexInAdGroup= */ C.INDEX_UNSET);
public static final SessionPositionInfo DEFAULT =
new SessionPositionInfo(
/* positionInfo= */ DEFAULT_POSITION_INFO,
/* isPlayingAd= */ false,
/* eventTimeMs= */ C.TIME_UNSET,
/* durationMs= */ C.TIME_UNSET,
/* bufferedPositionMs= */ 0,
/* bufferedPercentage= */ 0,
/* totalBufferedDurationMs= */ 0,
/* currentLiveOffsetMs= */ C.TIME_UNSET,
/* contentDurationMs= */ C.TIME_UNSET,
/* contentBufferedPositionMs= */ 0);
public final PositionInfo positionInfo;
public final boolean isPlayingAd;
public final long eventTimeMs;
public final long durationMs;
public final long bufferedPositionMs;
public final int bufferedPercentage;
public final long totalBufferedDurationMs;
public final long currentLiveOffsetMs;
public final long contentDurationMs;
public final long contentBufferedPositionMs;
public SessionPositionInfo(
PositionInfo positionInfo,
boolean isPlayingAd,
long eventTimeMs,
long durationMs,
long bufferedPositionMs,
int bufferedPercentage,
long totalBufferedDurationMs,
long currentLiveOffsetMs,
long contentDurationMs,
long contentBufferedPositionMs) {
checkArgument(isPlayingAd == (positionInfo.adGroupIndex != C.INDEX_UNSET));
this.positionInfo = positionInfo;
this.isPlayingAd = isPlayingAd;
this.eventTimeMs = eventTimeMs;
this.durationMs = durationMs;
this.bufferedPositionMs = bufferedPositionMs;
this.bufferedPercentage = bufferedPercentage;
this.totalBufferedDurationMs = totalBufferedDurationMs;
this.currentLiveOffsetMs = currentLiveOffsetMs;
this.contentDurationMs = contentDurationMs;
this.contentBufferedPositionMs = contentBufferedPositionMs;
}
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
SessionPositionInfo other = (SessionPositionInfo) obj;
return positionInfo.equals(other.positionInfo)
&& isPlayingAd == other.isPlayingAd
&& eventTimeMs == other.eventTimeMs
&& durationMs == other.durationMs
&& bufferedPositionMs == other.bufferedPositionMs
&& bufferedPercentage == other.bufferedPercentage
&& totalBufferedDurationMs == other.totalBufferedDurationMs
&& currentLiveOffsetMs == other.currentLiveOffsetMs
&& contentDurationMs == other.contentDurationMs
&& contentBufferedPositionMs == other.contentBufferedPositionMs;
}
@Override
public int hashCode() {
return Objects.hashCode(positionInfo, isPlayingAd);
}
@Override
public String toString() {
return "SessionPositionInfo {"
+ "PositionInfo {"
+ "mediaItemIndex="
+ positionInfo.mediaItemIndex
+ ", periodIndex="
+ positionInfo.periodIndex
+ ", positionMs="
+ positionInfo.positionMs
+ ", contentPositionMs="
+ positionInfo.contentPositionMs
+ ", adGroupIndex="
+ positionInfo.adGroupIndex
+ ", adIndexInAdGroup="
+ positionInfo.adIndexInAdGroup
+ "}, isPlayingAd="
+ isPlayingAd
+ ", eventTimeMs="
+ eventTimeMs
+ ", durationMs="
+ durationMs
+ ", bufferedPositionMs="
+ bufferedPositionMs
+ ", bufferedPercentage="
+ bufferedPercentage
+ ", totalBufferedDurationMs="
+ totalBufferedDurationMs
+ ", currentLiveOffsetMs="
+ currentLiveOffsetMs
+ ", contentDurationMs="
+ contentDurationMs
+ ", contentBufferedPositionMs="
+ contentBufferedPositionMs
+ "}";
}
// Bundleable implementation.
private static final String FIELD_POSITION_INFO = Util.intToStringMaxRadix(0);
private static final String FIELD_IS_PLAYING_AD = Util.intToStringMaxRadix(1);
private static final String FIELD_EVENT_TIME_MS = Util.intToStringMaxRadix(2);
private static final String FIELD_DURATION_MS = Util.intToStringMaxRadix(3);
private static final String FIELD_BUFFERED_POSITION_MS = Util.intToStringMaxRadix(4);
private static final String FIELD_BUFFERED_PERCENTAGE = Util.intToStringMaxRadix(5);
private static final String FIELD_TOTAL_BUFFERED_DURATION_MS = Util.intToStringMaxRadix(6);
private static final String FIELD_CURRENT_LIVE_OFFSET_MS = Util.intToStringMaxRadix(7);
private static final String FIELD_CONTENT_DURATION_MS = Util.intToStringMaxRadix(8);
private static final String FIELD_CONTENT_BUFFERED_POSITION_MS = Util.intToStringMaxRadix(9);
@Override
public Bundle toBundle() {
return toBundle(/* canAccessCurrentMediaItem= */ true, /* canAccessTimeline= */ true);
}
public Bundle toBundle(boolean canAccessCurrentMediaItem, boolean canAccessTimeline) {
Bundle bundle = new Bundle();
bundle.putBundle(
FIELD_POSITION_INFO, positionInfo.toBundle(canAccessCurrentMediaItem, canAccessTimeline));
bundle.putBoolean(FIELD_IS_PLAYING_AD, canAccessCurrentMediaItem && isPlayingAd);
bundle.putLong(FIELD_EVENT_TIME_MS, eventTimeMs);
bundle.putLong(FIELD_DURATION_MS, canAccessCurrentMediaItem ? durationMs : C.TIME_UNSET);
bundle.putLong(FIELD_BUFFERED_POSITION_MS, canAccessCurrentMediaItem ? bufferedPositionMs : 0);
bundle.putInt(FIELD_BUFFERED_PERCENTAGE, canAccessCurrentMediaItem ? bufferedPercentage : 0);
bundle.putLong(
FIELD_TOTAL_BUFFERED_DURATION_MS, canAccessCurrentMediaItem ? totalBufferedDurationMs : 0);
bundle.putLong(
FIELD_CURRENT_LIVE_OFFSET_MS,
canAccessCurrentMediaItem ? currentLiveOffsetMs : C.TIME_UNSET);
bundle.putLong(
FIELD_CONTENT_DURATION_MS, canAccessCurrentMediaItem ? contentDurationMs : C.TIME_UNSET);
bundle.putLong(
FIELD_CONTENT_BUFFERED_POSITION_MS,
canAccessCurrentMediaItem ? contentBufferedPositionMs : 0);
return bundle;
}
/** Object that can restore {@link SessionPositionInfo} from a {@link Bundle}. */
public static final Creator<SessionPositionInfo> CREATOR = SessionPositionInfo::fromBundle;
private static SessionPositionInfo fromBundle(Bundle bundle) {
@Nullable Bundle positionInfoBundle = bundle.getBundle(FIELD_POSITION_INFO);
PositionInfo positionInfo =
positionInfoBundle == null
? DEFAULT_POSITION_INFO
: PositionInfo.CREATOR.fromBundle(positionInfoBundle);
boolean isPlayingAd = bundle.getBoolean(FIELD_IS_PLAYING_AD, /* defaultValue= */ false);
long eventTimeMs = bundle.getLong(FIELD_EVENT_TIME_MS, /* defaultValue= */ C.TIME_UNSET);
long durationMs = bundle.getLong(FIELD_DURATION_MS, /* defaultValue= */ C.TIME_UNSET);
long bufferedPositionMs = bundle.getLong(FIELD_BUFFERED_POSITION_MS, /* defaultValue= */ 0);
int bufferedPercentage = bundle.getInt(FIELD_BUFFERED_PERCENTAGE, /* defaultValue= */ 0);
long totalBufferedDurationMs =
bundle.getLong(FIELD_TOTAL_BUFFERED_DURATION_MS, /* defaultValue= */ 0);
long currentLiveOffsetMs =
bundle.getLong(FIELD_CURRENT_LIVE_OFFSET_MS, /* defaultValue= */ C.TIME_UNSET);
long contentDurationMs =
bundle.getLong(FIELD_CONTENT_DURATION_MS, /* defaultValue= */ C.TIME_UNSET);
long contentBufferedPositionMs =
bundle.getLong(FIELD_CONTENT_BUFFERED_POSITION_MS, /* defaultValue= */ 0);
return new SessionPositionInfo(
positionInfo,
isPlayingAd,
eventTimeMs,
durationMs,
bufferedPositionMs,
bufferedPercentage,
totalBufferedDurationMs,
currentLiveOffsetMs,
contentDurationMs,
contentBufferedPositionMs);
}
}