summaryrefslogtreecommitdiffstats
path: root/mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java
blob: 69f8cb02c994d11a0672d7575875c39d6a1957d2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
/*
 * Copyright (C) 2018 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 org.mozilla.thirdparty.com.google.android.exoplayer2.source.hls.playlist;

import android.net.Uri;
import androidx.annotation.Nullable;
import org.mozilla.thirdparty.com.google.android.exoplayer2.C;
import org.mozilla.thirdparty.com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
import org.mozilla.thirdparty.com.google.android.exoplayer2.source.hls.HlsDataSourceFactory;
import org.mozilla.thirdparty.com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
import java.io.IOException;

/**
 * Tracks playlists associated to an HLS stream and provides snapshots.
 *
 * <p>The playlist tracker is responsible for exposing the seeking window, which is defined by the
 * segments that one of the playlists exposes. This playlist is called primary and needs to be
 * periodically refreshed in the case of live streams. Note that the primary playlist is one of the
 * media playlists while the master playlist is an optional kind of playlist defined by the HLS
 * specification (RFC 8216).
 *
 * <p>Playlist loads might encounter errors. The tracker may choose to blacklist them to ensure a
 * primary playlist is always available.
 */
public interface HlsPlaylistTracker {

  /** Factory for {@link HlsPlaylistTracker} instances. */
  interface Factory {

    /**
     * Creates a new tracker instance.
     *
     * @param dataSourceFactory The {@link HlsDataSourceFactory} to use for playlist loading.
     * @param loadErrorHandlingPolicy The {@link LoadErrorHandlingPolicy} for playlist load errors.
     * @param playlistParserFactory The {@link HlsPlaylistParserFactory} for playlist parsing.
     */
    HlsPlaylistTracker createTracker(
        HlsDataSourceFactory dataSourceFactory,
        LoadErrorHandlingPolicy loadErrorHandlingPolicy,
        HlsPlaylistParserFactory playlistParserFactory);
  }

  /** Listener for primary playlist changes. */
  interface PrimaryPlaylistListener {

    /**
     * Called when the primary playlist changes.
     *
     * @param mediaPlaylist The primary playlist new snapshot.
     */
    void onPrimaryPlaylistRefreshed(HlsMediaPlaylist mediaPlaylist);
  }

  /** Called on playlist loading events. */
  interface PlaylistEventListener {

    /**
     * Called a playlist changes.
     */
    void onPlaylistChanged();

    /**
     * Called if an error is encountered while loading a playlist.
     *
     * @param url The loaded url that caused the error.
     * @param blacklistDurationMs The duration for which the playlist should be blacklisted. Or
     *     {@link C#TIME_UNSET} if the playlist should not be blacklisted.
     * @return True if blacklisting did not encounter errors. False otherwise.
     */
    boolean onPlaylistError(Uri url, long blacklistDurationMs);
  }

  /** Thrown when a playlist is considered to be stuck due to a server side error. */
  final class PlaylistStuckException extends IOException {

    /** The url of the stuck playlist. */
    public final Uri url;

    /**
     * Creates an instance.
     *
     * @param url See {@link #url}.
     */
    public PlaylistStuckException(Uri url) {
      this.url = url;
    }
  }

  /** Thrown when the media sequence of a new snapshot indicates the server has reset. */
  final class PlaylistResetException extends IOException {

    /** The url of the reset playlist. */
    public final Uri url;

    /**
     * Creates an instance.
     *
     * @param url See {@link #url}.
     */
    public PlaylistResetException(Uri url) {
      this.url = url;
    }
  }

  /**
   * Starts the playlist tracker.
   *
   * <p>Must be called from the playback thread. A tracker may be restarted after a {@link #stop()}
   * call.
   *
   * @param initialPlaylistUri Uri of the HLS stream. Can point to a media playlist or a master
   *     playlist.
   * @param eventDispatcher A dispatcher to notify of events.
   * @param listener A callback for the primary playlist change events.
   */
  void start(
      Uri initialPlaylistUri, EventDispatcher eventDispatcher, PrimaryPlaylistListener listener);

  /**
   * Stops the playlist tracker and releases any acquired resources.
   *
   * <p>Must be called once per {@link #start} call.
   */
  void stop();

  /**
   * Registers a listener to receive events from the playlist tracker.
   *
   * @param listener The listener.
   */
  void addListener(PlaylistEventListener listener);

  /**
   * Unregisters a listener.
   *
   * @param listener The listener to unregister.
   */
  void removeListener(PlaylistEventListener listener);

  /**
   * Returns the master playlist.
   *
   * <p>If the uri passed to {@link #start} points to a media playlist, an {@link HlsMasterPlaylist}
   * with a single variant for said media playlist is returned.
   *
   * @return The master playlist. Null if the initial playlist has yet to be loaded.
   */
  @Nullable
  HlsMasterPlaylist getMasterPlaylist();

  /**
   * Returns the most recent snapshot available of the playlist referenced by the provided {@link
   * Uri}.
   *
   * @param url The {@link Uri} corresponding to the requested media playlist.
   * @param isForPlayback Whether the caller might use the snapshot to request media segments for
   *     playback. If true, the primary playlist may be updated to the one requested.
   * @return The most recent snapshot of the playlist referenced by the provided {@link Uri}. May be
   *     null if no snapshot has been loaded yet.
   */
  @Nullable
  HlsMediaPlaylist getPlaylistSnapshot(Uri url, boolean isForPlayback);

  /**
   * Returns the start time of the first loaded primary playlist, or {@link C#TIME_UNSET} if no
   * media playlist has been loaded.
   */
  long getInitialStartTimeUs();

  /**
   * Returns whether the snapshot of the playlist referenced by the provided {@link Uri} is valid,
   * meaning all the segments referenced by the playlist are expected to be available. If the
   * playlist is not valid then some of the segments may no longer be available.
   *
   * @param url The {@link Uri}.
   * @return Whether the snapshot of the playlist referenced by the provided {@link Uri} is valid.
   */
  boolean isSnapshotValid(Uri url);

  /**
   * If the tracker is having trouble refreshing the master playlist or the primary playlist, this
   * method throws the underlying error. Otherwise, does nothing.
   *
   * @throws IOException The underlying error.
   */
  void maybeThrowPrimaryPlaylistRefreshError() throws IOException;

  /**
   * If the playlist is having trouble refreshing the playlist referenced by the given {@link Uri},
   * this method throws the underlying error.
   *
   * @param url The {@link Uri}.
   * @throws IOException The underyling error.
   */
  void maybeThrowPlaylistRefreshError(Uri url) throws IOException;

  /**
   * Requests a playlist refresh and whitelists it.
   *
   * <p>The playlist tracker may choose the delay the playlist refresh. The request is discarded if
   * a refresh was already pending.
   *
   * @param url The {@link Uri} of the playlist to be refreshed.
   */
  void refreshPlaylist(Uri url);

  /**
   * Returns whether the tracked playlists describe a live stream.
   *
   * @return True if the content is live. False otherwise.
   */
  boolean isLive();
}