blob: 3d4bb1f7ef595a4858b450bdd26a7d21a037c0f2 [file] [log] [blame]
// Copyright 2015 The Cobalt Authors. All Rights Reserved.
//
// 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.
#ifndef COBALT_DOM_HTML_MEDIA_ELEMENT_H_
#define COBALT_DOM_HTML_MEDIA_ELEMENT_H_
#include <memory>
#include <string>
#include "base/memory/ref_counted.h"
#include "base/optional.h"
#include "base/threading/thread_checker.h"
#include "base/timer/timer.h"
#include "cobalt/dom/eme/media_keys.h"
#include "cobalt/dom/event_queue.h"
#include "cobalt/dom/html_element.h"
#include "cobalt/dom/media_error.h"
#include "cobalt/dom/time_ranges.h"
#include "cobalt/loader/image/image_cache.h"
#include "cobalt/media/player/web_media_player.h"
#include "cobalt/script/exception_state.h"
#include "cobalt/script/typed_arrays.h"
#include "url/gurl.h"
namespace cobalt {
namespace dom {
class MediaSource;
typedef media::ChunkDemuxer ChunkDemuxer;
typedef media::WebMediaPlayer WebMediaPlayer;
typedef media::WebMediaPlayerClient WebMediaPlayerClient;
// The HTMLMediaElement is the base of HTMLAudioElement and HTMLVideoElement.
// https://www.w3.org/TR/html50/embedded-content-0.html#media-element
class HTMLMediaElement : public HTMLElement, private WebMediaPlayerClient {
public:
HTMLMediaElement(Document* document, base::Token tag_name);
~HTMLMediaElement() override;
// Web API: HTMLMediaElement
//
// Error state
scoped_refptr<MediaError> error() const;
// Custom, not in any spec
//
// From HTMLElement
scoped_refptr<HTMLMediaElement> AsHTMLMediaElement() override { return this; }
// Network state
std::string src() const;
void set_src(const std::string& src);
const std::string& current_src() const { return current_src_; }
base::Optional<std::string> cross_origin() const;
void set_cross_origin(const base::Optional<std::string>& value);
enum NetworkState {
kNetworkEmpty,
kNetworkIdle,
kNetworkLoading,
kNetworkNoSource
};
uint16_t network_state() const;
scoped_refptr<TimeRanges> buffered() const;
void Load();
std::string CanPlayType(const std::string& mime_type);
std::string CanPlayType(const std::string& mime_type,
const std::string& key_system);
const EventListenerScriptValue* onencrypted() const;
void set_onencrypted(const EventListenerScriptValue& event_listener);
const scoped_refptr<eme::MediaKeys>& media_keys() const {
return media_keys_;
}
typedef script::ScriptValue<script::Promise<void>> VoidPromiseValue;
script::Handle<script::Promise<void>> SetMediaKeys(
const scoped_refptr<eme::MediaKeys>& media_keys);
// Ready state
enum ReadyState {
kHaveNothing = WebMediaPlayer::kReadyStateHaveNothing,
kHaveMetadata = WebMediaPlayer::kReadyStateHaveMetadata,
kHaveCurrentData = WebMediaPlayer::kReadyStateHaveCurrentData,
kHaveFutureData = WebMediaPlayer::kReadyStateHaveFutureData,
kHaveEnoughData = WebMediaPlayer::kReadyStateHaveEnoughData,
};
uint16_t ready_state() const;
bool seeking() const;
// Playback state
float current_time(script::ExceptionState* exception_state) const;
void set_current_time(float time, script::ExceptionState* exception_state);
float duration() const;
base::Time GetStartDate() const;
bool paused() const;
bool resume_frozen_flag() const;
float default_playback_rate() const;
void set_default_playback_rate(float rate);
float playback_rate() const;
void set_playback_rate(float rate);
const scoped_refptr<TimeRanges>& played();
scoped_refptr<TimeRanges> seekable() const;
bool ended() const;
bool autoplay() const;
void set_autoplay(bool autoplay);
bool loop() const;
void set_loop(bool loop);
void Play();
void Pause();
void set_resume_frozen_flag(bool resume_frozen_flag);
// Controls
bool controls() const;
void set_controls(bool controls);
float volume(script::ExceptionState* exception_state) const;
void set_volume(float volume, script::ExceptionState* exception_state);
bool muted() const;
void set_muted(bool muted);
// Custom, not in any spec
//
// From Node
void OnInsertedIntoDocument() override;
// Called by MediaSource
void DurationChanged(double duration, bool request_seek);
// Let other objects add event to the EventQueue of HTMLMediaElement. This
// function won't modify the target of the |event| passed in.
void ScheduleEvent(const scoped_refptr<Event>& event);
// Set max video capabilities.
void SetMaxVideoCapabilities(const std::string& max_video_capabilities,
script::ExceptionState* exception_state);
DEFINE_WRAPPABLE_TYPE(HTMLMediaElement);
void TraceMembers(script::Tracer* tracer) override;
protected:
WebMediaPlayer* player() { return player_.get(); }
const WebMediaPlayer* player() const { return player_.get(); }
private:
static const char kMediaSourceUrlProtocol[];
static const double kMaxTimeupdateEventFrequency;
// Loading
void CreateMediaPlayer();
void ScheduleLoad();
void PrepareForLoad();
void LoadInternal();
void LoadResource(const GURL& initial_url, const std::string& content_type,
const std::string& key_system);
void ClearMediaPlayer();
void NoneSupported(const std::string& message);
void MediaLoadingFailed(WebMediaPlayer::NetworkState error,
const std::string& message);
// Timers
void OnLoadTimer();
void OnProgressEventTimer();
void OnPlaybackProgressTimer();
void StartPlaybackProgressTimer();
void StartProgressEventTimer();
void StopPeriodicTimers();
// Events
void ScheduleTimeupdateEvent(bool periodic_event);
void ScheduleOwnEvent(base::Token event_name);
void CancelPendingEventsAndCallbacks();
bool ProcessingMediaPlayerCallback() const {
return processing_media_player_callback_ > 0;
}
void BeginProcessingMediaPlayerCallback() {
++processing_media_player_callback_;
}
void EndProcessingMediaPlayerCallback() {
DCHECK(processing_media_player_callback_);
--processing_media_player_callback_;
}
// States
void SetReadyState(WebMediaPlayer::ReadyState state);
void SetNetworkState(WebMediaPlayer::NetworkState state);
void SetNetworkError(WebMediaPlayer::NetworkState state,
const std::string& message);
void ChangeNetworkStateFromLoadingToIdle();
// Playback
void Seek(float time);
void FinishSeek();
void AddPlayedRange(float start, float end);
void UpdateVolume();
void UpdatePlayState();
bool PotentiallyPlaying() const;
bool EndedPlayback() const;
bool StoppedDueToErrors() const;
bool CouldPlayIfEnoughData() const;
void ConfigureMediaControls();
// Error report
void MediaEngineError(scoped_refptr<MediaError> error);
// WebMediaPlayerClient methods
void NetworkStateChanged() override;
void NetworkError(const std::string& message) override;
void ReadyStateChanged() override;
void TimeChanged(bool eos_played) override;
void DurationChanged() override;
void OutputModeChanged() override;
void ContentSizeChanged() override;
void PlaybackStateChanged() override;
void SawUnsupportedTracks() override;
float Volume() const override;
void SourceOpened(ChunkDemuxer* chunk_demuxer) override;
std::string SourceURL() const override;
std::string MaxVideoCapabilities() const override;
bool PreferDecodeToTexture() override;
void EncryptedMediaInitDataEncountered(
media::EmeInitDataType init_data_type, const unsigned char* init_data,
unsigned int init_data_length) override;
void ClearMediaSource();
std::unique_ptr<WebMediaPlayer> player_;
std::string current_src_;
std::string max_video_capabilities_;
// Loading state.
enum LoadState { kWaitingForSource, kLoadingFromSrcAttr };
LoadState load_state_;
EventQueue event_queue_;
base::OneShotTimer load_timer_;
base::RepeatingTimer progress_event_timer_;
base::RepeatingTimer playback_progress_timer_;
scoped_refptr<TimeRanges> played_time_ranges_;
float playback_rate_;
float default_playback_rate_;
NetworkState network_state_;
WebMediaPlayer::ReadyState ready_state_;
WebMediaPlayer::ReadyState ready_state_maximum_;
float volume_;
float last_seek_time_;
double previous_progress_time_;
double duration_;
base::Time start_date_;
bool playing_;
bool have_fired_loaded_data_;
bool autoplaying_;
bool muted_;
bool paused_;
// https://wicg.github.io/page-lifecycle/#htmlmediaelement-resume-frozen-flag
bool resume_frozen_flag_;
bool seeking_;
bool controls_;
// The last time a timeupdate event was sent in movie time.
double last_time_update_event_movie_time_;
// Counter incremented while processing a callback from the media player, so
// we can avoid calling the low level player recursively.
int processing_media_player_callback_;
GURL media_source_url_;
scoped_refptr<MediaSource> media_source_;
bool pending_load_;
// Data has not been loaded since sending a "stalled" event.
bool sent_stalled_event_;
// Time has not changed since sending an "ended" event.
bool sent_end_event_;
scoped_refptr<MediaError> error_;
// Helper object to reduce the image capacity while a video is playing.
base::Optional<loader::image::ReducedCacheCapacityManager::Request>
reduced_image_cache_capacity_request_;
scoped_refptr<eme::MediaKeys> media_keys_;
loader::RequestMode request_mode_;
DISALLOW_COPY_AND_ASSIGN(HTMLMediaElement);
};
} // namespace dom
} // namespace cobalt
#endif // COBALT_DOM_HTML_MEDIA_ELEMENT_H_