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
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
media / base / android / media_player_bridge.h [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_BASE_ANDROID_MEDIA_PLAYER_BRIDGE_H_
#define MEDIA_BASE_ANDROID_MEDIA_PLAYER_BRIDGE_H_
#include <jni.h>
#include <stdint.h>
#include <map>
#include <memory>
#include <string>
#include "base/android/scoped_java_ref.h"
#include "base/containers/flat_map.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "media/base/android/media_player_listener.h"
#include "media/base/media_export.h"
#include "media/base/simple_watch_timer.h"
#include "net/cookies/site_for_cookies.h"
#include "net/storage_access_api/status.h"
#include "ui/gl/android/scoped_java_surface.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace media {
class MediaResourceGetter;
class MediaUrlInterceptor;
// This class serves as a bridge between the native code and Android MediaPlayer
// Java class. For more information on Android MediaPlayer, check
// http://developer.android.com/reference/android/media/MediaPlayer.html
// The actual Android MediaPlayer instance is created lazily when Start(),
// Pause(), SeekTo() gets called. As a result, media information may not
// be available until one of those operations is performed. After that, we
// will cache those information in case the mediaplayer gets released.
// The class uses the corresponding MediaPlayerBridge Java class to talk to
// the Android MediaPlayer instance.
class MEDIA_EXPORT MediaPlayerBridge {
public:
class Client {
public:
// Returns a pointer to the MediaResourceGetter object.
virtual MediaResourceGetter* GetMediaResourceGetter() = 0;
// Returns a pointer to the MediaUrlInterceptor object or null.
virtual MediaUrlInterceptor* GetMediaUrlInterceptor() = 0;
// Called when media duration is first detected or changes.
virtual void OnMediaDurationChanged(base::TimeDelta duration) = 0;
// Called when playback completed.
virtual void OnPlaybackComplete() = 0;
// Called when error happens.
virtual void OnError(int error) = 0;
// Called when video size has changed.
virtual void OnVideoSizeChanged(int width, int height) = 0;
};
// Error types for MediaErrorCB.
enum MediaErrorType {
MEDIA_ERROR_FORMAT,
MEDIA_ERROR_DECODE,
MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK,
MEDIA_ERROR_INVALID_CODE,
MEDIA_ERROR_SERVER_DIED,
};
// Construct a MediaPlayerBridge object. This object needs to call `client`'s
// GetMediaResourceGetter() before decoding the media stream. This allows
// `client` to track unused resources and free them when needed.
// MediaPlayerBridge also forwards Android MediaPlayer callbacks to
// the `client` when needed.
MediaPlayerBridge(const GURL& url,
const net::SiteForCookies& site_for_cookies,
const url::Origin& top_frame_origin,
net::StorageAccessApiStatus storage_access_api_status,
const std::string& user_agent,
bool hide_url_log,
Client* client,
bool allow_credentials,
bool is_hls,
const base::flat_map<std::string, std::string> headers);
MediaPlayerBridge(const MediaPlayerBridge&) = delete;
MediaPlayerBridge& operator=(const MediaPlayerBridge&) = delete;
virtual ~MediaPlayerBridge();
// Initialize this object and extract the metadata from the media.
void Initialize();
// Methods to partially expose the underlying MediaPlayer.
void SetVideoSurface(gl::ScopedJavaSurface surface);
void SetPlaybackRate(double playback_rate);
void Pause();
void SeekTo(base::TimeDelta timestamp);
base::TimeDelta GetCurrentTime();
// Starts media playback.
// The first call to this method will call Prepare() and create the underlying
// MediaPlayer for the first time.
void Start();
// The media URL given to the underlying MediaPlayer.
GURL GetUrl();
// The site whose cookies should be given to the MediaPlayer if needed.
const net::SiteForCookies& GetSiteForCookies();
// Set the player volume, and take effect immediately.
// The volume should be between 0.0 and 1.0.
void SetVolume(double volume);
void OnDidSetDataUriDataSource(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
jboolean success);
private:
friend class MediaPlayerListener;
friend class MediaPlayerBridgeTest;
// Releases the resources such as the underlying MediaPlayer and
// MediaPlayerListener.
void Release();
base::TimeDelta GetDuration();
void PropagateDuration(base::TimeDelta time);
bool IsPlaying();
// Prepare the player for playback, asynchronously. When succeeds,
// OnMediaPrepared() will be called. Otherwise, OnMediaError() will
// be called with an error type.
void Prepare();
// MediaPlayerListener callbacks.
void OnVideoSizeChanged(int width, int height);
void OnMediaError(int error_type);
void OnPlaybackComplete();
void OnMediaPrepared();
// Create the corresponding Java class instance.
void CreateJavaMediaPlayerBridge();
// Get allowed operations from the player.
base::android::ScopedJavaLocalRef<jobject> GetAllowedOperations();
// Attach/Detaches `listener_` for listening to all the media events. If
// `j_media_player` is NULL, `listener_` only listens to the system media
// events. Otherwise, it also listens to the events from `j_media_player`.
void AttachListener(const base::android::JavaRef<jobject>& j_media_player);
void DetachListener();
// Set the data source for the media player.
void SetDataSource(const std::string& url);
void SetDataSourceInternal();
// Functions that implements media player control.
void StartInternal();
void PauseInternal();
// Calls Java MediaPlayerBridge's seekTo method, or no-ops if the operation
// is not allowed (based off of `can_seek_forward_` and `can_seek_backward_`).
void SeekInternal(base::TimeDelta time);
// Update allowed operations from the player.
void UpdateAllowedOperations();
// Callback function passed to `resource_getter_`. Called when the cookies
// are retrieved.
void OnCookiesRetrieved(const std::string& cookies);
// Callback function passed to `resource_getter_`. Called when the auth
// credentials are retrieved.
void OnAuthCredentialsRetrieved(const std::u16string& username,
const std::u16string& password);
// Extract the media metadata from a url, asynchronously.
// OnMediaMetadataExtracted() will be called when this call finishes.
void ExtractMediaMetadata(const std::string& url);
void OnMediaMetadataExtracted(base::TimeDelta duration,
int width,
int height,
bool success);
// Returns true if a MediaUrlInterceptor registered by the embedder has
// intercepted the url.
bool InterceptMediaUrl(const std::string& url,
int* fd,
int64_t* offset,
int64_t* size);
// Sets the underlying MediaPlayer's volume.
void UpdateVolumeInternal();
void OnWatchTimerTick();
base::WeakPtr<MediaPlayerBridge> WeakPtrForUIThread();
// Whether the player is prepared for playback.
bool prepared_;
// Whether the player completed playback.
bool playback_completed_;
// Pending play event while player is preparing.
bool pending_play_;
// Pending seek time while player is preparing.
base::TimeDelta pending_seek_;
// Whether a seek should be performed after preparing.
bool should_seek_on_prepare_;
// Url for playback.
GURL url_;
// Used to determine if cookies are accessed in a third-party context.
net::SiteForCookies site_for_cookies_;
// Used to check for cookie content settings.
url::Origin top_frame_origin_;
// Used when determining if first-party cookies may be accessible in a
// third-party context.
net::StorageAccessApiStatus storage_access_api_status_;
// Waiting to retrieve cookies for `url_`.
bool pending_retrieve_cookies_;
// Whether to prepare after cookies retrieved.
bool should_prepare_on_retrieved_cookies_;
// User agent string to be used for media player.
const std::string user_agent_;
// Hide url log from media player.
bool hide_url_log_;
// Stats about the media.
base::TimeDelta duration_;
int width_;
int height_;
bool can_seek_forward_;
bool can_seek_backward_;
// The player volume. Should be between 0.0 and 1.0.
double volume_;
// Cookies for `url_`.
std::string cookies_;
// The surface object currently owned by the player.
gl::ScopedJavaSurface surface_;
// Java MediaPlayerBridge instance.
base::android::ScopedJavaGlobalRef<jobject> j_media_player_bridge_;
// Whether user credentials are allowed to be passed.
bool allow_credentials_;
// Whether the preparation for playback or the playback is currently going on.
// This flag is set in Start() and cleared in Pause() and Release(). Used for
// UMA reporting only.
bool is_active_;
// Whether there has been any errors in the active state.
bool has_error_;
// The flag is set if Start() has been called at least once.
bool has_ever_started_;
// State for watch time reporting.
bool is_hls_;
SimpleWatchTimer watch_timer_;
// HTTP Request Headers
base::flat_map<std::string, std::string> headers_;
// A reference to the owner of `this`.
raw_ptr<Client> client_;
// Listener object that listens to all the media player events.
std::unique_ptr<MediaPlayerListener> listener_;
// Pending playback rate while player is preparing.
std::optional<double> pending_playback_rate_;
// Weak pointer passed to `listener_` for callbacks.
// NOTE: Weak pointers must be invalidated before all other member variables.
base::WeakPtrFactory<MediaPlayerBridge> weak_factory_{this};
};
} // namespace media
#endif // MEDIA_BASE_ANDROID_MEDIA_PLAYER_BRIDGE_H_