| /* |
| * Copyright (C) 2016 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 com.google.android.exoplayer2.util; |
| |
| import android.os.SystemClock; |
| import android.text.TextUtils; |
| import android.view.Surface; |
| import androidx.annotation.Nullable; |
| import com.google.android.exoplayer2.C; |
| import com.google.android.exoplayer2.ExoPlaybackException; |
| import com.google.android.exoplayer2.Format; |
| import com.google.android.exoplayer2.PlaybackParameters; |
| import com.google.android.exoplayer2.Player; |
| import com.google.android.exoplayer2.Player.PlaybackSuppressionReason; |
| import com.google.android.exoplayer2.RendererCapabilities; |
| import com.google.android.exoplayer2.RendererCapabilities.AdaptiveSupport; |
| import com.google.android.exoplayer2.Timeline; |
| import com.google.android.exoplayer2.analytics.AnalyticsListener; |
| import com.google.android.exoplayer2.audio.AudioAttributes; |
| import com.google.android.exoplayer2.decoder.DecoderCounters; |
| import com.google.android.exoplayer2.metadata.Metadata; |
| import com.google.android.exoplayer2.source.LoadEventInfo; |
| import com.google.android.exoplayer2.source.MediaLoadData; |
| import com.google.android.exoplayer2.source.TrackGroup; |
| import com.google.android.exoplayer2.source.TrackGroupArray; |
| import com.google.android.exoplayer2.trackselection.MappingTrackSelector; |
| import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo; |
| import com.google.android.exoplayer2.trackselection.TrackSelection; |
| import com.google.android.exoplayer2.trackselection.TrackSelectionArray; |
| import java.io.IOException; |
| import java.text.NumberFormat; |
| import java.util.Locale; |
| |
| /** Logs events from {@link Player} and other core components using {@link Log}. */ |
| @SuppressWarnings("UngroupedOverloads") |
| public class EventLogger implements AnalyticsListener { |
| |
| private static final String DEFAULT_TAG = "EventLogger"; |
| private static final int MAX_TIMELINE_ITEM_LINES = 3; |
| private static final NumberFormat TIME_FORMAT; |
| static { |
| TIME_FORMAT = NumberFormat.getInstance(Locale.US); |
| TIME_FORMAT.setMinimumFractionDigits(2); |
| TIME_FORMAT.setMaximumFractionDigits(2); |
| TIME_FORMAT.setGroupingUsed(false); |
| } |
| |
| @Nullable private final MappingTrackSelector trackSelector; |
| private final String tag; |
| private final Timeline.Window window; |
| private final Timeline.Period period; |
| private final long startTimeMs; |
| |
| /** |
| * Creates event logger. |
| * |
| * @param trackSelector The mapping track selector used by the player. May be null if detailed |
| * logging of track mapping is not required. |
| */ |
| public EventLogger(@Nullable MappingTrackSelector trackSelector) { |
| this(trackSelector, DEFAULT_TAG); |
| } |
| |
| /** |
| * Creates event logger. |
| * |
| * @param trackSelector The mapping track selector used by the player. May be null if detailed |
| * logging of track mapping is not required. |
| * @param tag The tag used for logging. |
| */ |
| public EventLogger(@Nullable MappingTrackSelector trackSelector, String tag) { |
| this.trackSelector = trackSelector; |
| this.tag = tag; |
| window = new Timeline.Window(); |
| period = new Timeline.Period(); |
| startTimeMs = SystemClock.elapsedRealtime(); |
| } |
| |
| // AnalyticsListener |
| |
| @Override |
| public void onIsLoadingChanged(EventTime eventTime, boolean isLoading) { |
| logd(eventTime, "loading", Boolean.toString(isLoading)); |
| } |
| |
| @Override |
| public void onPlaybackStateChanged(EventTime eventTime, @Player.State int state) { |
| logd(eventTime, "state", getStateString(state)); |
| } |
| |
| @Override |
| public void onPlayWhenReadyChanged( |
| EventTime eventTime, boolean playWhenReady, @Player.PlayWhenReadyChangeReason int reason) { |
| logd( |
| eventTime, |
| "playWhenReady", |
| playWhenReady + ", " + getPlayWhenReadyChangeReasonString(reason)); |
| } |
| |
| @Override |
| public void onPlaybackSuppressionReasonChanged( |
| EventTime eventTime, @PlaybackSuppressionReason int playbackSuppressionReason) { |
| logd( |
| eventTime, |
| "playbackSuppressionReason", |
| getPlaybackSuppressionReasonString(playbackSuppressionReason)); |
| } |
| |
| @Override |
| public void onIsPlayingChanged(EventTime eventTime, boolean isPlaying) { |
| logd(eventTime, "isPlaying", Boolean.toString(isPlaying)); |
| } |
| |
| @Override |
| public void onRepeatModeChanged(EventTime eventTime, @Player.RepeatMode int repeatMode) { |
| logd(eventTime, "repeatMode", getRepeatModeString(repeatMode)); |
| } |
| |
| @Override |
| public void onShuffleModeChanged(EventTime eventTime, boolean shuffleModeEnabled) { |
| logd(eventTime, "shuffleModeEnabled", Boolean.toString(shuffleModeEnabled)); |
| } |
| |
| @Override |
| public void onPositionDiscontinuity(EventTime eventTime, @Player.DiscontinuityReason int reason) { |
| logd(eventTime, "positionDiscontinuity", getDiscontinuityReasonString(reason)); |
| } |
| |
| @Override |
| public void onSeekStarted(EventTime eventTime) { |
| logd(eventTime, "seekStarted"); |
| } |
| |
| @Override |
| public void onPlaybackParametersChanged( |
| EventTime eventTime, PlaybackParameters playbackParameters) { |
| logd( |
| eventTime, |
| "playbackParameters", |
| Util.formatInvariant("speed=%.2f", playbackParameters.speed)); |
| } |
| |
| @Override |
| public void onPlaybackSpeedChanged(EventTime eventTime, float playbackSpeed) { |
| logd(eventTime, "playbackSpeed", Float.toString(playbackSpeed)); |
| } |
| |
| @Override |
| public void onTimelineChanged(EventTime eventTime, @Player.TimelineChangeReason int reason) { |
| int periodCount = eventTime.timeline.getPeriodCount(); |
| int windowCount = eventTime.timeline.getWindowCount(); |
| logd( |
| "timeline [" |
| + getEventTimeString(eventTime) |
| + ", periodCount=" |
| + periodCount |
| + ", windowCount=" |
| + windowCount |
| + ", reason=" |
| + getTimelineChangeReasonString(reason)); |
| for (int i = 0; i < Math.min(periodCount, MAX_TIMELINE_ITEM_LINES); i++) { |
| eventTime.timeline.getPeriod(i, period); |
| logd(" " + "period [" + getTimeString(period.getDurationMs()) + "]"); |
| } |
| if (periodCount > MAX_TIMELINE_ITEM_LINES) { |
| logd(" ..."); |
| } |
| for (int i = 0; i < Math.min(windowCount, MAX_TIMELINE_ITEM_LINES); i++) { |
| eventTime.timeline.getWindow(i, window); |
| logd( |
| " " |
| + "window [" |
| + getTimeString(window.getDurationMs()) |
| + ", " |
| + window.isSeekable |
| + ", " |
| + window.isDynamic |
| + "]"); |
| } |
| if (windowCount > MAX_TIMELINE_ITEM_LINES) { |
| logd(" ..."); |
| } |
| logd("]"); |
| } |
| |
| @Override |
| public void onPlayerError(EventTime eventTime, ExoPlaybackException e) { |
| loge(eventTime, "playerFailed", e); |
| } |
| |
| @Override |
| public void onTracksChanged( |
| EventTime eventTime, TrackGroupArray ignored, TrackSelectionArray trackSelections) { |
| MappedTrackInfo mappedTrackInfo = |
| trackSelector != null ? trackSelector.getCurrentMappedTrackInfo() : null; |
| if (mappedTrackInfo == null) { |
| logd(eventTime, "tracks", "[]"); |
| return; |
| } |
| logd("tracks [" + getEventTimeString(eventTime)); |
| // Log tracks associated to renderers. |
| int rendererCount = mappedTrackInfo.getRendererCount(); |
| for (int rendererIndex = 0; rendererIndex < rendererCount; rendererIndex++) { |
| TrackGroupArray rendererTrackGroups = mappedTrackInfo.getTrackGroups(rendererIndex); |
| TrackSelection trackSelection = trackSelections.get(rendererIndex); |
| if (rendererTrackGroups.length == 0) { |
| logd(" " + mappedTrackInfo.getRendererName(rendererIndex) + " []"); |
| } else { |
| logd(" " + mappedTrackInfo.getRendererName(rendererIndex) + " ["); |
| for (int groupIndex = 0; groupIndex < rendererTrackGroups.length; groupIndex++) { |
| TrackGroup trackGroup = rendererTrackGroups.get(groupIndex); |
| String adaptiveSupport = |
| getAdaptiveSupportString( |
| trackGroup.length, |
| mappedTrackInfo.getAdaptiveSupport( |
| rendererIndex, groupIndex, /* includeCapabilitiesExceededTracks= */ false)); |
| logd(" Group:" + groupIndex + ", adaptive_supported=" + adaptiveSupport + " ["); |
| for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) { |
| String status = getTrackStatusString(trackSelection, trackGroup, trackIndex); |
| String formatSupport = |
| RendererCapabilities.getFormatSupportString( |
| mappedTrackInfo.getTrackSupport(rendererIndex, groupIndex, trackIndex)); |
| logd( |
| " " |
| + status |
| + " Track:" |
| + trackIndex |
| + ", " |
| + Format.toLogString(trackGroup.getFormat(trackIndex)) |
| + ", supported=" |
| + formatSupport); |
| } |
| logd(" ]"); |
| } |
| // Log metadata for at most one of the tracks selected for the renderer. |
| if (trackSelection != null) { |
| for (int selectionIndex = 0; selectionIndex < trackSelection.length(); selectionIndex++) { |
| Metadata metadata = trackSelection.getFormat(selectionIndex).metadata; |
| if (metadata != null) { |
| logd(" Metadata ["); |
| printMetadata(metadata, " "); |
| logd(" ]"); |
| break; |
| } |
| } |
| } |
| logd(" ]"); |
| } |
| } |
| // Log tracks not associated with a renderer. |
| TrackGroupArray unassociatedTrackGroups = mappedTrackInfo.getUnmappedTrackGroups(); |
| if (unassociatedTrackGroups.length > 0) { |
| logd(" Unmapped ["); |
| for (int groupIndex = 0; groupIndex < unassociatedTrackGroups.length; groupIndex++) { |
| logd(" Group:" + groupIndex + " ["); |
| TrackGroup trackGroup = unassociatedTrackGroups.get(groupIndex); |
| for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) { |
| String status = getTrackStatusString(false); |
| String formatSupport = |
| RendererCapabilities.getFormatSupportString( |
| RendererCapabilities.FORMAT_UNSUPPORTED_TYPE); |
| logd( |
| " " |
| + status |
| + " Track:" |
| + trackIndex |
| + ", " |
| + Format.toLogString(trackGroup.getFormat(trackIndex)) |
| + ", supported=" |
| + formatSupport); |
| } |
| logd(" ]"); |
| } |
| logd(" ]"); |
| } |
| logd("]"); |
| } |
| |
| @Override |
| public void onMetadata(EventTime eventTime, Metadata metadata) { |
| logd("metadata [" + getEventTimeString(eventTime)); |
| printMetadata(metadata, " "); |
| logd("]"); |
| } |
| |
| @Override |
| public void onDecoderEnabled(EventTime eventTime, int trackType, DecoderCounters counters) { |
| logd(eventTime, "decoderEnabled", Util.getTrackTypeString(trackType)); |
| } |
| |
| @Override |
| public void onAudioSessionId(EventTime eventTime, int audioSessionId) { |
| logd(eventTime, "audioSessionId", Integer.toString(audioSessionId)); |
| } |
| |
| @Override |
| public void onAudioAttributesChanged(EventTime eventTime, AudioAttributes audioAttributes) { |
| logd( |
| eventTime, |
| "audioAttributes", |
| audioAttributes.contentType |
| + "," |
| + audioAttributes.flags |
| + "," |
| + audioAttributes.usage |
| + "," |
| + audioAttributes.allowedCapturePolicy); |
| } |
| |
| @Override |
| public void onSkipSilenceEnabledChanged(EventTime eventTime, boolean skipSilenceEnabled) { |
| logd(eventTime, "skipSilenceEnabled", Boolean.toString(skipSilenceEnabled)); |
| } |
| |
| @Override |
| public void onVolumeChanged(EventTime eventTime, float volume) { |
| logd(eventTime, "volume", Float.toString(volume)); |
| } |
| |
| @Override |
| public void onDecoderInitialized( |
| EventTime eventTime, int trackType, String decoderName, long initializationDurationMs) { |
| logd(eventTime, "decoderInitialized", Util.getTrackTypeString(trackType) + ", " + decoderName); |
| } |
| |
| @Override |
| public void onDecoderInputFormatChanged(EventTime eventTime, int trackType, Format format) { |
| logd( |
| eventTime, |
| "decoderInputFormat", |
| Util.getTrackTypeString(trackType) + ", " + Format.toLogString(format)); |
| } |
| |
| @Override |
| public void onDecoderDisabled(EventTime eventTime, int trackType, DecoderCounters counters) { |
| logd(eventTime, "decoderDisabled", Util.getTrackTypeString(trackType)); |
| } |
| |
| @Override |
| public void onAudioUnderrun( |
| EventTime eventTime, int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) { |
| loge( |
| eventTime, |
| "audioTrackUnderrun", |
| bufferSize + ", " + bufferSizeMs + ", " + elapsedSinceLastFeedMs + "]", |
| null); |
| } |
| |
| @Override |
| public void onDroppedVideoFrames(EventTime eventTime, int count, long elapsedMs) { |
| logd(eventTime, "droppedFrames", Integer.toString(count)); |
| } |
| |
| @Override |
| public void onVideoSizeChanged( |
| EventTime eventTime, |
| int width, |
| int height, |
| int unappliedRotationDegrees, |
| float pixelWidthHeightRatio) { |
| logd(eventTime, "videoSize", width + ", " + height); |
| } |
| |
| @Override |
| public void onRenderedFirstFrame(EventTime eventTime, @Nullable Surface surface) { |
| logd(eventTime, "renderedFirstFrame", String.valueOf(surface)); |
| } |
| |
| @Override |
| public void onMediaPeriodCreated(EventTime eventTime) { |
| logd(eventTime, "mediaPeriodCreated"); |
| } |
| |
| @Override |
| public void onMediaPeriodReleased(EventTime eventTime) { |
| logd(eventTime, "mediaPeriodReleased"); |
| } |
| |
| @Override |
| public void onLoadStarted( |
| EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) { |
| // Do nothing. |
| } |
| |
| @Override |
| public void onLoadError( |
| EventTime eventTime, |
| LoadEventInfo loadEventInfo, |
| MediaLoadData mediaLoadData, |
| IOException error, |
| boolean wasCanceled) { |
| printInternalError(eventTime, "loadError", error); |
| } |
| |
| @Override |
| public void onLoadCanceled( |
| EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) { |
| // Do nothing. |
| } |
| |
| @Override |
| public void onLoadCompleted( |
| EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) { |
| // Do nothing. |
| } |
| |
| @Override |
| public void onReadingStarted(EventTime eventTime) { |
| logd(eventTime, "mediaPeriodReadingStarted"); |
| } |
| |
| @Override |
| public void onBandwidthEstimate( |
| EventTime eventTime, int totalLoadTimeMs, long totalBytesLoaded, long bitrateEstimate) { |
| // Do nothing. |
| } |
| |
| @Override |
| public void onSurfaceSizeChanged(EventTime eventTime, int width, int height) { |
| logd(eventTime, "surfaceSize", width + ", " + height); |
| } |
| |
| @Override |
| public void onUpstreamDiscarded(EventTime eventTime, MediaLoadData mediaLoadData) { |
| logd(eventTime, "upstreamDiscarded", Format.toLogString(mediaLoadData.trackFormat)); |
| } |
| |
| @Override |
| public void onDownstreamFormatChanged(EventTime eventTime, MediaLoadData mediaLoadData) { |
| logd(eventTime, "downstreamFormat", Format.toLogString(mediaLoadData.trackFormat)); |
| } |
| |
| @Override |
| public void onDrmSessionAcquired(EventTime eventTime) { |
| logd(eventTime, "drmSessionAcquired"); |
| } |
| |
| @Override |
| public void onDrmSessionManagerError(EventTime eventTime, Exception e) { |
| printInternalError(eventTime, "drmSessionManagerError", e); |
| } |
| |
| @Override |
| public void onDrmKeysRestored(EventTime eventTime) { |
| logd(eventTime, "drmKeysRestored"); |
| } |
| |
| @Override |
| public void onDrmKeysRemoved(EventTime eventTime) { |
| logd(eventTime, "drmKeysRemoved"); |
| } |
| |
| @Override |
| public void onDrmKeysLoaded(EventTime eventTime) { |
| logd(eventTime, "drmKeysLoaded"); |
| } |
| |
| @Override |
| public void onDrmSessionReleased(EventTime eventTime) { |
| logd(eventTime, "drmSessionReleased"); |
| } |
| |
| /** |
| * Logs a debug message. |
| * |
| * @param msg The message to log. |
| */ |
| protected void logd(String msg) { |
| Log.d(tag, msg); |
| } |
| |
| /** |
| * Logs an error message. |
| * |
| * @param msg The message to log. |
| */ |
| protected void loge(String msg) { |
| Log.e(tag, msg); |
| } |
| |
| // Internal methods |
| |
| private void logd(EventTime eventTime, String eventName) { |
| logd(getEventString(eventTime, eventName, /* eventDescription= */ null, /* throwable= */ null)); |
| } |
| |
| private void logd(EventTime eventTime, String eventName, String eventDescription) { |
| logd(getEventString(eventTime, eventName, eventDescription, /* throwable= */ null)); |
| } |
| |
| private void loge(EventTime eventTime, String eventName, @Nullable Throwable throwable) { |
| loge(getEventString(eventTime, eventName, /* eventDescription= */ null, throwable)); |
| } |
| |
| private void loge( |
| EventTime eventTime, |
| String eventName, |
| String eventDescription, |
| @Nullable Throwable throwable) { |
| loge(getEventString(eventTime, eventName, eventDescription, throwable)); |
| } |
| |
| private void printInternalError(EventTime eventTime, String type, Exception e) { |
| loge(eventTime, "internalError", type, e); |
| } |
| |
| private void printMetadata(Metadata metadata, String prefix) { |
| for (int i = 0; i < metadata.length(); i++) { |
| logd(prefix + metadata.get(i)); |
| } |
| } |
| |
| private String getEventString( |
| EventTime eventTime, |
| String eventName, |
| @Nullable String eventDescription, |
| @Nullable Throwable throwable) { |
| String eventString = eventName + " [" + getEventTimeString(eventTime); |
| if (eventDescription != null) { |
| eventString += ", " + eventDescription; |
| } |
| @Nullable String throwableString = Log.getThrowableString(throwable); |
| if (!TextUtils.isEmpty(throwableString)) { |
| eventString += "\n " + throwableString.replace("\n", "\n ") + '\n'; |
| } |
| eventString += "]"; |
| return eventString; |
| } |
| |
| private String getEventTimeString(EventTime eventTime) { |
| String windowPeriodString = "window=" + eventTime.windowIndex; |
| if (eventTime.mediaPeriodId != null) { |
| windowPeriodString += |
| ", period=" + eventTime.timeline.getIndexOfPeriod(eventTime.mediaPeriodId.periodUid); |
| if (eventTime.mediaPeriodId.isAd()) { |
| windowPeriodString += ", adGroup=" + eventTime.mediaPeriodId.adGroupIndex; |
| windowPeriodString += ", ad=" + eventTime.mediaPeriodId.adIndexInAdGroup; |
| } |
| } |
| return "eventTime=" |
| + getTimeString(eventTime.realtimeMs - startTimeMs) |
| + ", mediaPos=" |
| + getTimeString(eventTime.currentPlaybackPositionMs) |
| + ", " |
| + windowPeriodString; |
| } |
| |
| private static String getTimeString(long timeMs) { |
| return timeMs == C.TIME_UNSET ? "?" : TIME_FORMAT.format((timeMs) / 1000f); |
| } |
| |
| private static String getStateString(int state) { |
| switch (state) { |
| case Player.STATE_BUFFERING: |
| return "BUFFERING"; |
| case Player.STATE_ENDED: |
| return "ENDED"; |
| case Player.STATE_IDLE: |
| return "IDLE"; |
| case Player.STATE_READY: |
| return "READY"; |
| default: |
| return "?"; |
| } |
| } |
| |
| private static String getAdaptiveSupportString( |
| int trackCount, @AdaptiveSupport int adaptiveSupport) { |
| if (trackCount < 2) { |
| return "N/A"; |
| } |
| switch (adaptiveSupport) { |
| case RendererCapabilities.ADAPTIVE_SEAMLESS: |
| return "YES"; |
| case RendererCapabilities.ADAPTIVE_NOT_SEAMLESS: |
| return "YES_NOT_SEAMLESS"; |
| case RendererCapabilities.ADAPTIVE_NOT_SUPPORTED: |
| return "NO"; |
| default: |
| throw new IllegalStateException(); |
| } |
| } |
| |
| // Suppressing reference equality warning because the track group stored in the track selection |
| // must point to the exact track group object to be considered part of it. |
| @SuppressWarnings("ReferenceEquality") |
| private static String getTrackStatusString( |
| @Nullable TrackSelection selection, TrackGroup group, int trackIndex) { |
| return getTrackStatusString(selection != null && selection.getTrackGroup() == group |
| && selection.indexOf(trackIndex) != C.INDEX_UNSET); |
| } |
| |
| private static String getTrackStatusString(boolean enabled) { |
| return enabled ? "[X]" : "[ ]"; |
| } |
| |
| private static String getRepeatModeString(@Player.RepeatMode int repeatMode) { |
| switch (repeatMode) { |
| case Player.REPEAT_MODE_OFF: |
| return "OFF"; |
| case Player.REPEAT_MODE_ONE: |
| return "ONE"; |
| case Player.REPEAT_MODE_ALL: |
| return "ALL"; |
| default: |
| return "?"; |
| } |
| } |
| |
| private static String getDiscontinuityReasonString(@Player.DiscontinuityReason int reason) { |
| switch (reason) { |
| case Player.DISCONTINUITY_REASON_PERIOD_TRANSITION: |
| return "PERIOD_TRANSITION"; |
| case Player.DISCONTINUITY_REASON_SEEK: |
| return "SEEK"; |
| case Player.DISCONTINUITY_REASON_SEEK_ADJUSTMENT: |
| return "SEEK_ADJUSTMENT"; |
| case Player.DISCONTINUITY_REASON_AD_INSERTION: |
| return "AD_INSERTION"; |
| case Player.DISCONTINUITY_REASON_INTERNAL: |
| return "INTERNAL"; |
| default: |
| return "?"; |
| } |
| } |
| |
| private static String getTimelineChangeReasonString(@Player.TimelineChangeReason int reason) { |
| switch (reason) { |
| case Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE: |
| return "SOURCE_UPDATE"; |
| case Player.TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED: |
| return "PLAYLIST_CHANGED"; |
| default: |
| return "?"; |
| } |
| } |
| |
| private static String getPlaybackSuppressionReasonString( |
| @PlaybackSuppressionReason int playbackSuppressionReason) { |
| switch (playbackSuppressionReason) { |
| case Player.PLAYBACK_SUPPRESSION_REASON_NONE: |
| return "NONE"; |
| case Player.PLAYBACK_SUPPRESSION_REASON_TRANSIENT_AUDIO_FOCUS_LOSS: |
| return "TRANSIENT_AUDIO_FOCUS_LOSS"; |
| default: |
| return "?"; |
| } |
| } |
| |
| private static String getPlayWhenReadyChangeReasonString( |
| @Player.PlayWhenReadyChangeReason int reason) { |
| switch (reason) { |
| case Player.PLAY_WHEN_READY_CHANGE_REASON_AUDIO_BECOMING_NOISY: |
| return "AUDIO_BECOMING_NOISY"; |
| case Player.PLAY_WHEN_READY_CHANGE_REASON_AUDIO_FOCUS_LOSS: |
| return "AUDIO_FOCUS_LOSS"; |
| case Player.PLAY_WHEN_READY_CHANGE_REASON_REMOTE: |
| return "REMOTE"; |
| case Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST: |
| return "USER_REQUEST"; |
| case Player.PLAY_WHEN_READY_CHANGE_REASON_END_OF_MEDIA_ITEM: |
| return "END_OF_MEDIA_ITEM"; |
| default: |
| return "?"; |
| } |
| } |
| } |