Home | History | Annotate | Download | only in android
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/renderer/media/android/webmediaplayer_android.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/command_line.h"
      9 #include "base/files/file_path.h"
     10 #include "base/logging.h"
     11 #include "base/metrics/histogram.h"
     12 #include "base/strings/string_number_conversions.h"
     13 #include "cc/layers/video_layer.h"
     14 #include "content/renderer/media/android/proxy_media_keys.h"
     15 #include "content/renderer/media/android/renderer_media_player_manager.h"
     16 #include "content/renderer/media/android/webmediaplayer_proxy_android.h"
     17 #include "content/renderer/media/crypto/key_systems.h"
     18 #include "content/renderer/media/webmediaplayer_delegate.h"
     19 #include "content/renderer/media/webmediaplayer_util.h"
     20 #include "gpu/GLES2/gl2extchromium.h"
     21 #include "media/base/android/media_player_android.h"
     22 #include "media/base/bind_to_loop.h"
     23 #include "media/base/media_switches.h"
     24 #include "media/base/video_frame.h"
     25 #include "net/base/mime_util.h"
     26 #include "third_party/WebKit/public/platform/WebString.h"
     27 #include "third_party/WebKit/public/web/WebDocument.h"
     28 #include "third_party/WebKit/public/web/WebFrame.h"
     29 #include "third_party/WebKit/public/web/WebMediaPlayerClient.h"
     30 #include "third_party/WebKit/public/web/WebMediaSource.h"
     31 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
     32 #include "third_party/WebKit/public/web/WebView.h"
     33 #include "webkit/renderer/compositor_bindings/web_layer_impl.h"
     34 
     35 #if defined(GOOGLE_TV)
     36 #include "content/renderer/media/media_stream_audio_renderer.h"
     37 #include "content/renderer/media/media_stream_client.h"
     38 #endif
     39 
     40 static const uint32 kGLTextureExternalOES = 0x8D65;
     41 
     42 using WebKit::WebMediaPlayer;
     43 using WebKit::WebMediaSource;
     44 using WebKit::WebSize;
     45 using WebKit::WebString;
     46 using WebKit::WebTimeRanges;
     47 using WebKit::WebURL;
     48 using media::MediaPlayerAndroid;
     49 using media::VideoFrame;
     50 
     51 namespace {
     52 // Prefix for histograms related to Encrypted Media Extensions.
     53 const char* kMediaEme = "Media.EME.";
     54 }  // namespace
     55 
     56 namespace content {
     57 
     58 #define BIND_TO_RENDER_LOOP(function) \
     59   media::BindToLoop(main_loop_, base::Bind(function, AsWeakPtr()))
     60 
     61 WebMediaPlayerAndroid::WebMediaPlayerAndroid(
     62     WebKit::WebFrame* frame,
     63     WebKit::WebMediaPlayerClient* client,
     64     base::WeakPtr<WebMediaPlayerDelegate> delegate,
     65     RendererMediaPlayerManager* manager,
     66     WebMediaPlayerProxyAndroid* proxy,
     67     StreamTextureFactory* factory,
     68     const scoped_refptr<base::MessageLoopProxy>& media_loop,
     69     media::MediaLog* media_log)
     70     : frame_(frame),
     71       client_(client),
     72       delegate_(delegate),
     73       buffered_(1u),
     74       main_loop_(base::MessageLoopProxy::current()),
     75       media_loop_(media_loop),
     76       ignore_metadata_duration_change_(false),
     77       pending_seek_(0),
     78       seeking_(false),
     79       did_loading_progress_(false),
     80       manager_(manager),
     81       network_state_(WebMediaPlayer::NetworkStateEmpty),
     82       ready_state_(WebMediaPlayer::ReadyStateHaveNothing),
     83       texture_id_(0),
     84       texture_mailbox_sync_point_(0),
     85       stream_id_(0),
     86       is_playing_(false),
     87       needs_establish_peer_(true),
     88       stream_texture_proxy_initialized_(false),
     89       has_size_info_(false),
     90       has_media_metadata_(false),
     91       has_media_info_(false),
     92       stream_texture_factory_(factory),
     93       needs_external_surface_(false),
     94       video_frame_provider_client_(NULL),
     95 #if defined(GOOGLE_TV)
     96       external_surface_threshold_(-1),
     97       demuxer_(NULL),
     98       media_stream_client_(NULL),
     99 #endif  // defined(GOOGLE_TV)
    100       source_type_(MediaPlayerAndroid::SOURCE_TYPE_URL),
    101       proxy_(proxy),
    102       current_time_(0),
    103       media_log_(media_log) {
    104   DCHECK(proxy_);
    105   DCHECK(manager_);
    106 
    107   // We want to be notified of |main_loop_| destruction.
    108   base::MessageLoop::current()->AddDestructionObserver(this);
    109 
    110   player_id_ = manager_->RegisterMediaPlayer(this);
    111 
    112 #if defined(GOOGLE_TV)
    113   if (CommandLine::ForCurrentProcess()->HasSwitch(
    114       switches::kUseExternalVideoSurfaceThresholdInPixels)) {
    115     if (!base::StringToInt(
    116         CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
    117             switches::kUseExternalVideoSurfaceThresholdInPixels),
    118         &external_surface_threshold_)) {
    119       external_surface_threshold_ = -1;
    120     }
    121   }
    122 
    123   // Defer stream texture creation until we are sure it's necessary.
    124   stream_id_ = 0;
    125   needs_establish_peer_ = false;
    126   current_frame_ = VideoFrame::CreateBlackFrame(gfx::Size(1, 1));
    127 #endif
    128   TryCreateStreamTextureProxyIfNeeded();
    129 
    130   if (WebKit::WebRuntimeFeatures::isLegacyEncryptedMediaEnabled()) {
    131     // TODO(xhwang): Report an error when there is encrypted stream but EME is
    132     // not enabled. Currently the player just doesn't start and waits for ever.
    133     decryptor_.reset(new ProxyDecryptor(
    134 #if defined(ENABLE_PEPPER_CDMS)
    135         client,
    136         frame,
    137 #else
    138         proxy_,
    139         player_id_,  // TODO(xhwang): Use media_keys_id when MediaKeys are
    140                      // separated from WebMediaPlayer.
    141 #endif // defined(ENABLE_PEPPER_CDMS)
    142         // |decryptor_| is owned, so Unretained() is safe here.
    143         base::Bind(&WebMediaPlayerAndroid::OnKeyAdded, base::Unretained(this)),
    144         base::Bind(&WebMediaPlayerAndroid::OnKeyError, base::Unretained(this)),
    145         base::Bind(&WebMediaPlayerAndroid::OnKeyMessage,
    146                    base::Unretained(this))));
    147   }
    148 }
    149 
    150 WebMediaPlayerAndroid::~WebMediaPlayerAndroid() {
    151   SetVideoFrameProviderClient(NULL);
    152   client_->setWebLayer(NULL);
    153 
    154   if (proxy_)
    155     proxy_->DestroyPlayer(player_id_);
    156 
    157   if (stream_id_)
    158     stream_texture_factory_->DestroyStreamTexture(texture_id_);
    159 
    160   if (manager_)
    161     manager_->UnregisterMediaPlayer(player_id_);
    162 
    163   if (base::MessageLoop::current())
    164     base::MessageLoop::current()->RemoveDestructionObserver(this);
    165 
    166   if (source_type_ == MediaPlayerAndroid::SOURCE_TYPE_MSE && delegate_)
    167     delegate_->PlayerGone(this);
    168 
    169 #if defined(GOOGLE_TV)
    170   if (audio_renderer_) {
    171     if (audio_renderer_->IsLocalRenderer()) {
    172       audio_renderer_->Stop();
    173     } else if (!paused()) {
    174       // The |audio_renderer_| can be shared by multiple remote streams, and
    175       // it will be stopped when WebRtcAudioDeviceImpl goes away. So we simply
    176       // pause the |audio_renderer_| here to avoid re-creating the
    177       // |audio_renderer_|.
    178       audio_renderer_->Pause();
    179     }
    180   }
    181   if (demuxer_ && !destroy_demuxer_cb_.is_null()) {
    182     media_source_delegate_.reset();
    183     destroy_demuxer_cb_.Run();
    184   }
    185 #endif
    186 }
    187 
    188 void WebMediaPlayerAndroid::load(const WebURL& url, CORSMode cors_mode) {
    189   load(url, NULL, cors_mode);
    190 }
    191 
    192 void WebMediaPlayerAndroid::load(const WebURL& url,
    193                                  WebMediaSource* media_source,
    194                                  CORSMode cors_mode) {
    195   source_type_ = MediaPlayerAndroid::SOURCE_TYPE_URL;
    196   has_media_metadata_ = false;
    197   has_media_info_ = false;
    198 
    199   if (media_source)
    200     source_type_ = MediaPlayerAndroid::SOURCE_TYPE_MSE;
    201 #if defined(GOOGLE_TV)
    202   if (media_stream_client_) {
    203     DCHECK(!media_source);
    204     source_type_ = MediaPlayerAndroid::SOURCE_TYPE_STREAM;
    205   }
    206 #endif
    207 
    208   media::SetDecryptorReadyCB set_decryptor_ready_cb;
    209   if (decryptor_) {  // |decryptor_| can be NULL is EME if not enabled.
    210     set_decryptor_ready_cb = base::Bind(&ProxyDecryptor::SetDecryptorReadyCB,
    211                                         base::Unretained(decryptor_.get()));
    212   }
    213 
    214   if (source_type_ != MediaPlayerAndroid::SOURCE_TYPE_URL) {
    215     has_media_info_ = true;
    216     media_source_delegate_.reset(
    217         new MediaSourceDelegate(proxy_, player_id_, media_loop_, media_log_));
    218     // |media_source_delegate_| is owned, so Unretained() is safe here.
    219     if (source_type_ == MediaPlayerAndroid::SOURCE_TYPE_MSE) {
    220       media_source_delegate_->InitializeMediaSource(
    221           media_source,
    222           base::Bind(&WebMediaPlayerAndroid::OnNeedKey, base::Unretained(this)),
    223           set_decryptor_ready_cb,
    224           base::Bind(&WebMediaPlayerAndroid::UpdateNetworkState,
    225                      base::Unretained(this)),
    226           BIND_TO_RENDER_LOOP(&WebMediaPlayerAndroid::OnDurationChange));
    227     }
    228 #if defined(GOOGLE_TV)
    229     // TODO(xhwang): Pass set_decryptor_ready_cb in InitializeMediaStream() to
    230     // enable ClearKey support for Google TV.
    231     if (source_type_ == MediaPlayerAndroid::SOURCE_TYPE_STREAM) {
    232       media_source_delegate_->InitializeMediaStream(
    233           demuxer_,
    234           base::Bind(&WebMediaPlayerAndroid::UpdateNetworkState,
    235                      base::Unretained(this)));
    236       audio_renderer_ = media_stream_client_->GetAudioRenderer(url);
    237       if (audio_renderer_)
    238         audio_renderer_->Start();
    239     }
    240 #endif
    241   } else {
    242     info_loader_.reset(
    243         new MediaInfoLoader(
    244             url,
    245             cors_mode,
    246             base::Bind(&WebMediaPlayerAndroid::DidLoadMediaInfo,
    247                        base::Unretained(this))));
    248     info_loader_->Start(frame_);
    249   }
    250 
    251   InitializeMediaPlayer(url);
    252 }
    253 
    254 void WebMediaPlayerAndroid::InitializeMediaPlayer(const WebURL& url) {
    255   url_ = url;
    256   GURL first_party_url = frame_->document().firstPartyForCookies();
    257   proxy_->Initialize(player_id_, url, source_type_, first_party_url);
    258   if (manager_->IsInFullscreen(frame_))
    259     proxy_->EnterFullscreen(player_id_);
    260 
    261   UpdateNetworkState(WebMediaPlayer::NetworkStateLoading);
    262   UpdateReadyState(WebMediaPlayer::ReadyStateHaveNothing);
    263 }
    264 
    265 void WebMediaPlayerAndroid::DidLoadMediaInfo(
    266     MediaInfoLoader::Status status) {
    267   DCHECK(!media_source_delegate_);
    268   if (status == MediaInfoLoader::kFailed) {
    269     info_loader_.reset();
    270     UpdateNetworkState(WebMediaPlayer::NetworkStateNetworkError);
    271     return;
    272   }
    273 
    274   has_media_info_ = true;
    275   if (has_media_metadata_ &&
    276       ready_state_ != WebMediaPlayer::ReadyStateHaveEnoughData) {
    277     UpdateReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
    278     UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
    279   }
    280 }
    281 
    282 void WebMediaPlayerAndroid::play() {
    283 #if defined(GOOGLE_TV)
    284   if (hasVideo() && needs_external_surface_ &&
    285       !manager_->IsInFullscreen(frame_)) {
    286     DCHECK(!needs_establish_peer_);
    287     proxy_->RequestExternalSurface(player_id_, last_computed_rect_);
    288   }
    289   if (audio_renderer_ && paused())
    290     audio_renderer_->Play();
    291 #endif
    292 
    293   TryCreateStreamTextureProxyIfNeeded();
    294   if (hasVideo() && needs_establish_peer_)
    295     EstablishSurfaceTexturePeer();
    296 
    297   if (paused())
    298     proxy_->Start(player_id_);
    299   UpdatePlayingState(true);
    300 }
    301 
    302 void WebMediaPlayerAndroid::pause() {
    303 #if defined(GOOGLE_TV)
    304   if (audio_renderer_ && !paused())
    305     audio_renderer_->Pause();
    306 #endif
    307   proxy_->Pause(player_id_);
    308   UpdatePlayingState(false);
    309 }
    310 
    311 void WebMediaPlayerAndroid::seek(double seconds) {
    312   pending_seek_ = seconds;
    313   seeking_ = true;
    314 
    315   base::TimeDelta seek_time = ConvertSecondsToTimestamp(seconds);
    316   proxy_->Seek(player_id_, seek_time);
    317 }
    318 
    319 bool WebMediaPlayerAndroid::supportsFullscreen() const {
    320   return true;
    321 }
    322 
    323 bool WebMediaPlayerAndroid::supportsSave() const {
    324   return false;
    325 }
    326 
    327 void WebMediaPlayerAndroid::setRate(double rate) {
    328   NOTIMPLEMENTED();
    329 }
    330 
    331 void WebMediaPlayerAndroid::setVolume(double volume) {
    332   proxy_->SetVolume(player_id_, volume);
    333 }
    334 
    335 bool WebMediaPlayerAndroid::hasVideo() const {
    336   // If we have obtained video size information before, use it.
    337   if (has_size_info_)
    338     return !natural_size_.isEmpty();
    339 
    340   // TODO(qinmin): need a better method to determine whether the current media
    341   // content contains video. Android does not provide any function to do
    342   // this.
    343   // We don't know whether the current media content has video unless
    344   // the player is prepared. If the player is not prepared, we fall back
    345   // to the mime-type. There may be no mime-type on a redirect URL.
    346   // In that case, we conservatively assume it contains video so that
    347   // enterfullscreen call will not fail.
    348   if (!url_.has_path())
    349     return false;
    350   std::string mime;
    351   if(!net::GetMimeTypeFromFile(base::FilePath(url_.path()), &mime))
    352     return true;
    353   return mime.find("audio/") == std::string::npos;
    354 }
    355 
    356 bool WebMediaPlayerAndroid::hasAudio() const {
    357   // TODO(hclam): Query status of audio and return the actual value.
    358   return true;
    359 }
    360 
    361 bool WebMediaPlayerAndroid::paused() const {
    362   return !is_playing_;
    363 }
    364 
    365 bool WebMediaPlayerAndroid::seeking() const {
    366   return seeking_;
    367 }
    368 
    369 double WebMediaPlayerAndroid::duration() const {
    370   // HTML5 spec requires duration to be NaN if readyState is HAVE_NOTHING
    371   if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
    372     return std::numeric_limits<double>::quiet_NaN();
    373 
    374   // TODO(wolenetz): Correctly handle durations that MediaSourcePlayer
    375   // considers unseekable, including kInfiniteDuration().
    376   // See http://crbug.com/248396
    377   return duration_.InSecondsF();
    378 }
    379 
    380 double WebMediaPlayerAndroid::currentTime() const {
    381   // If the player is pending for a seek, return the seek time.
    382   if (seeking())
    383     return pending_seek_;
    384   return current_time_;
    385 }
    386 
    387 WebSize WebMediaPlayerAndroid::naturalSize() const {
    388   return natural_size_;
    389 }
    390 
    391 WebMediaPlayer::NetworkState WebMediaPlayerAndroid::networkState() const {
    392   return network_state_;
    393 }
    394 
    395 WebMediaPlayer::ReadyState WebMediaPlayerAndroid::readyState() const {
    396   return ready_state_;
    397 }
    398 
    399 const WebTimeRanges& WebMediaPlayerAndroid::buffered() {
    400   if (media_source_delegate_)
    401     return media_source_delegate_->Buffered();
    402   return buffered_;
    403 }
    404 
    405 double WebMediaPlayerAndroid::maxTimeSeekable() const {
    406   // If we haven't even gotten to ReadyStateHaveMetadata yet then just
    407   // return 0 so that the seekable range is empty.
    408   if (ready_state_ < WebMediaPlayer::ReadyStateHaveMetadata)
    409     return 0.0;
    410 
    411   // TODO(hclam): If this stream is not seekable this should return 0.
    412   return duration();
    413 }
    414 
    415 bool WebMediaPlayerAndroid::didLoadingProgress() const {
    416   bool ret = did_loading_progress_;
    417   did_loading_progress_ = false;
    418   return ret;
    419 }
    420 
    421 void WebMediaPlayerAndroid::paint(WebKit::WebCanvas* canvas,
    422                                   const WebKit::WebRect& rect,
    423                                   unsigned char alpha) {
    424   NOTIMPLEMENTED();
    425 }
    426 
    427 bool WebMediaPlayerAndroid::copyVideoTextureToPlatformTexture(
    428     WebKit::WebGraphicsContext3D* web_graphics_context,
    429     unsigned int texture,
    430     unsigned int level,
    431     unsigned int internal_format,
    432     unsigned int type,
    433     bool premultiply_alpha,
    434     bool flip_y) {
    435   if (!texture_id_)
    436     return false;
    437 
    438   // For hidden video element (with style "display:none"), ensure the texture
    439   // size is set.
    440   if (cached_stream_texture_size_.width != natural_size_.width ||
    441       cached_stream_texture_size_.height != natural_size_.height) {
    442     stream_texture_factory_->SetStreamTextureSize(
    443         stream_id_, gfx::Size(natural_size_.width, natural_size_.height));
    444     cached_stream_texture_size_ = natural_size_;
    445   }
    446 
    447   // Ensure the target of texture is set before copyTextureCHROMIUM, otherwise
    448   // an invalid texture target may be used for copy texture.
    449   web_graphics_context->bindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id_);
    450 
    451   // The video is stored in an unmultiplied format, so premultiply if
    452   // necessary.
    453   web_graphics_context->pixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM,
    454                                     premultiply_alpha);
    455 
    456   // Application itself needs to take care of setting the right flip_y
    457   // value down to get the expected result.
    458   // flip_y==true means to reverse the video orientation while
    459   // flip_y==false means to keep the intrinsic orientation.
    460   web_graphics_context->pixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, flip_y);
    461   web_graphics_context->copyTextureCHROMIUM(GL_TEXTURE_2D, texture_id_,
    462                                             texture, level, internal_format,
    463                                             type);
    464   web_graphics_context->pixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, false);
    465   web_graphics_context->pixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM,
    466                                     false);
    467 
    468   web_graphics_context->bindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
    469   return true;
    470 }
    471 
    472 bool WebMediaPlayerAndroid::hasSingleSecurityOrigin() const {
    473   if (info_loader_)
    474     return info_loader_->HasSingleOrigin();
    475   // The info loader may have failed.
    476   if (source_type_ == MediaPlayerAndroid::SOURCE_TYPE_URL)
    477     return false;
    478   return true;
    479 }
    480 
    481 bool WebMediaPlayerAndroid::didPassCORSAccessCheck() const {
    482   if (info_loader_)
    483     return info_loader_->DidPassCORSAccessCheck();
    484   return false;
    485 }
    486 
    487 double WebMediaPlayerAndroid::mediaTimeForTimeValue(double timeValue) const {
    488   return ConvertSecondsToTimestamp(timeValue).InSecondsF();
    489 }
    490 
    491 unsigned WebMediaPlayerAndroid::decodedFrameCount() const {
    492   if (media_source_delegate_)
    493     return media_source_delegate_->DecodedFrameCount();
    494   NOTIMPLEMENTED();
    495   return 0;
    496 }
    497 
    498 unsigned WebMediaPlayerAndroid::droppedFrameCount() const {
    499   if (media_source_delegate_)
    500     return media_source_delegate_->DroppedFrameCount();
    501   NOTIMPLEMENTED();
    502   return 0;
    503 }
    504 
    505 unsigned WebMediaPlayerAndroid::audioDecodedByteCount() const {
    506   if (media_source_delegate_)
    507     return media_source_delegate_->AudioDecodedByteCount();
    508   NOTIMPLEMENTED();
    509   return 0;
    510 }
    511 
    512 unsigned WebMediaPlayerAndroid::videoDecodedByteCount() const {
    513   if (media_source_delegate_)
    514     return media_source_delegate_->VideoDecodedByteCount();
    515   NOTIMPLEMENTED();
    516   return 0;
    517 }
    518 
    519 void WebMediaPlayerAndroid::OnMediaMetadataChanged(
    520     base::TimeDelta duration, int width, int height, bool success) {
    521   bool need_to_signal_duration_changed = false;
    522 
    523   if (url_.SchemeIs("file"))
    524     UpdateNetworkState(WebMediaPlayer::NetworkStateLoaded);
    525 
    526   // Update duration, if necessary, prior to ready state updates that may
    527   // cause duration() query.
    528   // TODO(wolenetz): Correctly handle durations that MediaSourcePlayer
    529   // considers unseekable, including kInfiniteDuration().
    530   // See http://crbug.com/248396
    531   if (!ignore_metadata_duration_change_ && duration_ != duration) {
    532     duration_ = duration;
    533 
    534     // Client readyState transition from HAVE_NOTHING to HAVE_METADATA
    535     // already triggers a durationchanged event. If this is a different
    536     // transition, remember to signal durationchanged.
    537     // Do not ever signal durationchanged on metadata change in MSE case
    538     // because OnDurationChange() handles this.
    539     if (ready_state_ > WebMediaPlayer::ReadyStateHaveNothing &&
    540         source_type_ != MediaPlayerAndroid::SOURCE_TYPE_MSE) {
    541       need_to_signal_duration_changed = true;
    542     }
    543   }
    544 
    545   has_media_metadata_ = true;
    546   if (has_media_info_ &&
    547       ready_state_ != WebMediaPlayer::ReadyStateHaveEnoughData) {
    548     UpdateReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
    549     UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
    550   }
    551 
    552   // TODO(wolenetz): Should we just abort early and set network state to an
    553   // error if success == false? See http://crbug.com/248399
    554   if (success)
    555     OnVideoSizeChanged(width, height);
    556 
    557   if (hasVideo() && !video_weblayer_ && client_->needsWebLayerForVideo()) {
    558     video_weblayer_.reset(
    559         new webkit::WebLayerImpl(cc::VideoLayer::Create(this)));
    560     client_->setWebLayer(video_weblayer_.get());
    561   }
    562 
    563   if (need_to_signal_duration_changed)
    564     client_->durationChanged();
    565 }
    566 
    567 void WebMediaPlayerAndroid::OnPlaybackComplete() {
    568   // When playback is about to finish, android media player often stops
    569   // at a time which is smaller than the duration. This makes webkit never
    570   // know that the playback has finished. To solve this, we set the
    571   // current time to media duration when OnPlaybackComplete() get called.
    572   OnTimeUpdate(duration_);
    573   client_->timeChanged();
    574 }
    575 
    576 void WebMediaPlayerAndroid::OnBufferingUpdate(int percentage) {
    577   buffered_[0].end = duration() * percentage / 100;
    578   did_loading_progress_ = true;
    579 }
    580 
    581 void WebMediaPlayerAndroid::OnSeekComplete(base::TimeDelta current_time) {
    582   seeking_ = false;
    583 
    584   OnTimeUpdate(current_time);
    585 
    586   UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
    587 
    588   client_->timeChanged();
    589 }
    590 
    591 void WebMediaPlayerAndroid::OnMediaError(int error_type) {
    592   switch (error_type) {
    593     case MediaPlayerAndroid::MEDIA_ERROR_FORMAT:
    594       UpdateNetworkState(WebMediaPlayer::NetworkStateFormatError);
    595       break;
    596     case MediaPlayerAndroid::MEDIA_ERROR_DECODE:
    597       UpdateNetworkState(WebMediaPlayer::NetworkStateDecodeError);
    598       break;
    599     case MediaPlayerAndroid::MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK:
    600       UpdateNetworkState(WebMediaPlayer::NetworkStateFormatError);
    601       break;
    602     case MediaPlayerAndroid::MEDIA_ERROR_INVALID_CODE:
    603       break;
    604   }
    605   client_->repaint();
    606 }
    607 
    608 void WebMediaPlayerAndroid::OnVideoSizeChanged(int width, int height) {
    609   has_size_info_ = true;
    610   if (natural_size_.width == width && natural_size_.height == height)
    611     return;
    612 
    613 #if defined(GOOGLE_TV)
    614   if ((external_surface_threshold_ >= 0 &&
    615        external_surface_threshold_ <= width * height) ||
    616       // Use H/W surface for MSE as the content is protected.
    617       media_source_delegate_) {
    618     needs_external_surface_ = true;
    619     if (!paused() && !manager_->IsInFullscreen(frame_))
    620       proxy_->RequestExternalSurface(player_id_, last_computed_rect_);
    621   } else if (stream_texture_factory_ && !stream_texture_proxy_) {
    622     // Do deferred stream texture creation finally.
    623     if (paused()) {
    624       DoCreateStreamTexture();
    625       SetNeedsEstablishPeer(true);
    626     } else {
    627       EstablishSurfaceTexturePeer();
    628     }
    629   }
    630 #endif
    631 
    632   natural_size_.width = width;
    633   natural_size_.height = height;
    634   ReallocateVideoFrame();
    635 }
    636 
    637 void WebMediaPlayerAndroid::OnTimeUpdate(base::TimeDelta current_time) {
    638   current_time_ = current_time.InSecondsF();
    639 }
    640 
    641 void WebMediaPlayerAndroid::OnDidEnterFullscreen() {
    642   if (!manager_->IsInFullscreen(frame_)) {
    643     frame_->view()->willEnterFullScreen();
    644     frame_->view()->didEnterFullScreen();
    645     manager_->DidEnterFullscreen(frame_);
    646   }
    647 }
    648 
    649 void WebMediaPlayerAndroid::OnDidExitFullscreen() {
    650   // |needs_external_surface_| is always false on non-TV devices.
    651   if (!needs_external_surface_)
    652     SetNeedsEstablishPeer(true);
    653   // We had the fullscreen surface connected to Android MediaPlayer,
    654   // so reconnect our surface texture for embedded playback.
    655   if (!paused() && needs_establish_peer_)
    656     EstablishSurfaceTexturePeer();
    657 
    658 #if defined(GOOGLE_TV)
    659   if (!paused() && needs_external_surface_)
    660     proxy_->RequestExternalSurface(player_id_, last_computed_rect_);
    661 #endif
    662 
    663   frame_->view()->willExitFullScreen();
    664   frame_->view()->didExitFullScreen();
    665   manager_->DidExitFullscreen();
    666   client_->repaint();
    667 }
    668 
    669 void WebMediaPlayerAndroid::OnMediaPlayerPlay() {
    670   UpdatePlayingState(true);
    671   client_->playbackStateChanged();
    672 }
    673 
    674 void WebMediaPlayerAndroid::OnMediaPlayerPause() {
    675   UpdatePlayingState(false);
    676   client_->playbackStateChanged();
    677 }
    678 
    679 void WebMediaPlayerAndroid::OnMediaSeekRequest(base::TimeDelta time_to_seek,
    680                                                unsigned seek_request_id) {
    681   if (!media_source_delegate_)
    682     return;
    683 
    684   media_source_delegate_->Seek(time_to_seek, seek_request_id);
    685   OnTimeUpdate(time_to_seek);
    686 }
    687 
    688 void WebMediaPlayerAndroid::OnMediaConfigRequest() {
    689   if (!media_source_delegate_)
    690     return;
    691 
    692   media_source_delegate_->OnMediaConfigRequest();
    693 }
    694 
    695 void WebMediaPlayerAndroid::OnDurationChange(const base::TimeDelta& duration) {
    696   // Only MSE |source_type_| registers this callback.
    697   DCHECK(source_type_ == MediaPlayerAndroid::SOURCE_TYPE_MSE);
    698 
    699   // Cache the new duration value and trust it over any subsequent duration
    700   // values received in OnMediaMetadataChanged().
    701   // TODO(wolenetz): Correctly handle durations that MediaSourcePlayer
    702   // considers unseekable, including kInfiniteDuration().
    703   // See http://crbug.com/248396
    704   duration_ = duration;
    705   ignore_metadata_duration_change_ = true;
    706 
    707   // Send message to Android MediaSourcePlayer to update duration.
    708   if (proxy_)
    709     proxy_->DurationChanged(player_id_, duration_);
    710 
    711   // Notify MediaPlayerClient that duration has changed, if > HAVE_NOTHING.
    712   if (ready_state_ > WebMediaPlayer::ReadyStateHaveNothing)
    713     client_->durationChanged();
    714 }
    715 
    716 void WebMediaPlayerAndroid::UpdateNetworkState(
    717     WebMediaPlayer::NetworkState state) {
    718   if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing &&
    719       (state == WebMediaPlayer::NetworkStateNetworkError ||
    720        state == WebMediaPlayer::NetworkStateDecodeError)) {
    721     // Any error that occurs before reaching ReadyStateHaveMetadata should
    722     // be considered a format error.
    723     network_state_ = WebMediaPlayer::NetworkStateFormatError;
    724   } else {
    725     network_state_ = state;
    726   }
    727   client_->networkStateChanged();
    728 }
    729 
    730 void WebMediaPlayerAndroid::UpdateReadyState(
    731     WebMediaPlayer::ReadyState state) {
    732   ready_state_ = state;
    733   client_->readyStateChanged();
    734 }
    735 
    736 void WebMediaPlayerAndroid::OnPlayerReleased() {
    737   // |needs_external_surface_| is always false on non-TV devices.
    738   if (!needs_external_surface_)
    739     needs_establish_peer_ = true;
    740 
    741 #if defined(GOOGLE_TV)
    742   last_computed_rect_ = gfx::RectF();
    743 #endif
    744 }
    745 
    746 void WebMediaPlayerAndroid::ReleaseMediaResources() {
    747   switch (network_state_) {
    748     // Pause the media player and inform WebKit if the player is in a good
    749     // shape.
    750     case WebMediaPlayer::NetworkStateIdle:
    751     case WebMediaPlayer::NetworkStateLoading:
    752     case WebMediaPlayer::NetworkStateLoaded:
    753       pause();
    754       client_->playbackStateChanged();
    755       break;
    756     // If a WebMediaPlayer instance has entered into one of these states,
    757     // the internal network state in HTMLMediaElement could be set to empty.
    758     // And calling playbackStateChanged() could get this object deleted.
    759     case WebMediaPlayer::NetworkStateEmpty:
    760     case WebMediaPlayer::NetworkStateFormatError:
    761     case WebMediaPlayer::NetworkStateNetworkError:
    762     case WebMediaPlayer::NetworkStateDecodeError:
    763       break;
    764   }
    765   proxy_->ReleaseResources(player_id_);
    766   OnPlayerReleased();
    767 }
    768 
    769 void WebMediaPlayerAndroid::WillDestroyCurrentMessageLoop() {
    770   if (manager_)
    771     manager_->UnregisterMediaPlayer(player_id_);
    772   Detach();
    773 }
    774 
    775 void WebMediaPlayerAndroid::Detach() {
    776   if (stream_id_) {
    777     stream_texture_factory_->DestroyStreamTexture(texture_id_);
    778     stream_id_ = 0;
    779   }
    780 
    781   media_source_delegate_.reset();
    782   current_frame_ = NULL;
    783   manager_ = NULL;
    784   proxy_ = NULL;
    785 }
    786 
    787 void WebMediaPlayerAndroid::ReallocateVideoFrame() {
    788   if (needs_external_surface_) {
    789     // VideoFrame::CreateHoleFrame is only defined under GOOGLE_TV.
    790 #if defined(GOOGLE_TV)
    791     if (!natural_size_.isEmpty()) {
    792       current_frame_ = VideoFrame::CreateHoleFrame(natural_size_);
    793       // Force the client to grab the hole frame.
    794       client_->repaint();
    795     }
    796 #else
    797     NOTIMPLEMENTED() << "Hole punching not supported outside of Google TV";
    798 #endif
    799   } else if (texture_id_) {
    800     current_frame_ = VideoFrame::WrapNativeTexture(
    801         new VideoFrame::MailboxHolder(
    802             texture_mailbox_,
    803             texture_mailbox_sync_point_,
    804             VideoFrame::MailboxHolder::TextureNoLongerNeededCallback()),
    805         kGLTextureExternalOES, natural_size_,
    806         gfx::Rect(natural_size_), natural_size_, base::TimeDelta(),
    807         VideoFrame::ReadPixelsCB(),
    808         base::Closure());
    809   }
    810 }
    811 
    812 void WebMediaPlayerAndroid::SetVideoFrameProviderClient(
    813     cc::VideoFrameProvider::Client* client) {
    814   // This is called from both the main renderer thread and the compositor
    815   // thread (when the main thread is blocked).
    816   if (video_frame_provider_client_)
    817     video_frame_provider_client_->StopUsingProvider();
    818   video_frame_provider_client_ = client;
    819 
    820   // Set the callback target when a frame is produced.
    821   if (stream_texture_proxy_)
    822     stream_texture_proxy_->SetClient(client);
    823 }
    824 
    825 scoped_refptr<media::VideoFrame> WebMediaPlayerAndroid::GetCurrentFrame() {
    826   if (!stream_texture_proxy_initialized_ && stream_texture_proxy_ &&
    827       stream_id_ && !needs_external_surface_) {
    828     gfx::Size natural_size = current_frame_->natural_size();
    829     stream_texture_proxy_->BindToCurrentThread(stream_id_);
    830     stream_texture_factory_->SetStreamTextureSize(stream_id_, natural_size);
    831     stream_texture_proxy_initialized_ = true;
    832     cached_stream_texture_size_ = natural_size;
    833   }
    834   return current_frame_;
    835 }
    836 
    837 void WebMediaPlayerAndroid::PutCurrentFrame(
    838     const scoped_refptr<media::VideoFrame>& frame) {
    839 }
    840 
    841 void WebMediaPlayerAndroid::TryCreateStreamTextureProxyIfNeeded() {
    842   // Already created.
    843   if (stream_texture_proxy_)
    844     return;
    845 
    846   // No factory to create proxy.
    847   if (!stream_texture_factory_)
    848     return;
    849 
    850   stream_texture_proxy_.reset(stream_texture_factory_->CreateProxy());
    851   if (needs_establish_peer_ && stream_texture_proxy_) {
    852     DoCreateStreamTexture();
    853     ReallocateVideoFrame();
    854   }
    855 
    856   if (stream_texture_proxy_ && video_frame_provider_client_)
    857     stream_texture_proxy_->SetClient(video_frame_provider_client_);
    858 }
    859 
    860 void WebMediaPlayerAndroid::EstablishSurfaceTexturePeer() {
    861   if (!stream_texture_proxy_)
    862     return;
    863 
    864   if (media_source_delegate_ && stream_texture_factory_) {
    865     // MediaCodec will release the old surface when it goes away, we need to
    866     // recreate a new one each time this is called.
    867     stream_texture_factory_->DestroyStreamTexture(texture_id_);
    868     stream_id_ = 0;
    869     texture_id_ = 0;
    870     texture_mailbox_ = gpu::Mailbox();
    871     texture_mailbox_sync_point_ = 0;
    872     DoCreateStreamTexture();
    873     ReallocateVideoFrame();
    874     stream_texture_proxy_initialized_ = false;
    875   }
    876   if (stream_texture_factory_.get() && stream_id_)
    877     stream_texture_factory_->EstablishPeer(stream_id_, player_id_);
    878   needs_establish_peer_ = false;
    879 }
    880 
    881 void WebMediaPlayerAndroid::DoCreateStreamTexture() {
    882   DCHECK(!stream_id_);
    883   DCHECK(!texture_id_);
    884   DCHECK(!texture_mailbox_sync_point_);
    885   stream_id_ = stream_texture_factory_->CreateStreamTexture(
    886       kGLTextureExternalOES,
    887       &texture_id_,
    888       &texture_mailbox_,
    889       &texture_mailbox_sync_point_);
    890 }
    891 
    892 void WebMediaPlayerAndroid::SetNeedsEstablishPeer(bool needs_establish_peer) {
    893   needs_establish_peer_ = needs_establish_peer;
    894 }
    895 
    896 void WebMediaPlayerAndroid::UpdatePlayingState(bool is_playing) {
    897   is_playing_ = is_playing;
    898   if (!delegate_)
    899     return;
    900   if (is_playing)
    901     delegate_->DidPlay(this);
    902   else
    903     delegate_->DidPause(this);
    904 }
    905 
    906 #if defined(GOOGLE_TV)
    907 bool WebMediaPlayerAndroid::RetrieveGeometryChange(gfx::RectF* rect) {
    908   if (!video_weblayer_)
    909     return false;
    910 
    911   // Compute the geometry of video frame layer.
    912   cc::Layer* layer = video_weblayer_->layer();
    913   rect->set_size(layer->bounds());
    914   while (layer) {
    915     rect->Offset(layer->position().OffsetFromOrigin());
    916     layer = layer->parent();
    917   }
    918 
    919   // Return false when the geometry hasn't been changed from the last time.
    920   if (last_computed_rect_ == *rect)
    921     return false;
    922 
    923   // Store the changed geometry information when it is actually changed.
    924   last_computed_rect_ = *rect;
    925   return true;
    926 }
    927 #endif
    928 
    929 // The following EME related code is copied from WebMediaPlayerImpl.
    930 // TODO(xhwang): Remove duplicate code between WebMediaPlayerAndroid and
    931 // WebMediaPlayerImpl.
    932 // TODO(kjyoun): Update Google TV EME implementation to use IPC.
    933 
    934 // Helper functions to report media EME related stats to UMA. They follow the
    935 // convention of more commonly used macros UMA_HISTOGRAM_ENUMERATION and
    936 // UMA_HISTOGRAM_COUNTS. The reason that we cannot use those macros directly is
    937 // that UMA_* macros require the names to be constant throughout the process'
    938 // lifetime.
    939 static void EmeUMAHistogramEnumeration(const WebKit::WebString& key_system,
    940                                        const std::string& method,
    941                                        int sample,
    942                                        int boundary_value) {
    943   base::LinearHistogram::FactoryGet(
    944       kMediaEme + KeySystemNameForUMA(key_system) + "." + method,
    945       1, boundary_value, boundary_value + 1,
    946       base::Histogram::kUmaTargetedHistogramFlag)->Add(sample);
    947 }
    948 
    949 static void EmeUMAHistogramCounts(const WebKit::WebString& key_system,
    950                                   const std::string& method,
    951                                   int sample) {
    952   // Use the same parameters as UMA_HISTOGRAM_COUNTS.
    953   base::Histogram::FactoryGet(
    954       kMediaEme + KeySystemNameForUMA(key_system) + "." + method,
    955       1, 1000000, 50, base::Histogram::kUmaTargetedHistogramFlag)->Add(sample);
    956 }
    957 
    958 // Helper enum for reporting generateKeyRequest/addKey histograms.
    959 enum MediaKeyException {
    960   kUnknownResultId,
    961   kSuccess,
    962   kKeySystemNotSupported,
    963   kInvalidPlayerState,
    964   kMaxMediaKeyException
    965 };
    966 
    967 static MediaKeyException MediaKeyExceptionForUMA(
    968     WebMediaPlayer::MediaKeyException e) {
    969   switch (e) {
    970     case WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported:
    971       return kKeySystemNotSupported;
    972     case WebMediaPlayer::MediaKeyExceptionInvalidPlayerState:
    973       return kInvalidPlayerState;
    974     case WebMediaPlayer::MediaKeyExceptionNoError:
    975       return kSuccess;
    976     default:
    977       return kUnknownResultId;
    978   }
    979 }
    980 
    981 // Helper for converting |key_system| name and exception |e| to a pair of enum
    982 // values from above, for reporting to UMA.
    983 static void ReportMediaKeyExceptionToUMA(
    984     const std::string& method,
    985     const WebString& key_system,
    986     WebMediaPlayer::MediaKeyException e) {
    987   MediaKeyException result_id = MediaKeyExceptionForUMA(e);
    988   DCHECK_NE(result_id, kUnknownResultId) << e;
    989   EmeUMAHistogramEnumeration(
    990       key_system, method, result_id, kMaxMediaKeyException);
    991 }
    992 
    993 WebMediaPlayer::MediaKeyException WebMediaPlayerAndroid::generateKeyRequest(
    994     const WebString& key_system,
    995     const unsigned char* init_data,
    996     unsigned init_data_length) {
    997   WebMediaPlayer::MediaKeyException e =
    998       GenerateKeyRequestInternal(key_system, init_data, init_data_length);
    999   ReportMediaKeyExceptionToUMA("generateKeyRequest", key_system, e);
   1000   return e;
   1001 }
   1002 
   1003 WebMediaPlayer::MediaKeyException
   1004 WebMediaPlayerAndroid::GenerateKeyRequestInternal(
   1005     const WebString& key_system,
   1006     const unsigned char* init_data,
   1007     unsigned init_data_length) {
   1008   DVLOG(1) << "generateKeyRequest: " << key_system.utf8().data() << ": "
   1009            << std::string(reinterpret_cast<const char*>(init_data),
   1010                           static_cast<size_t>(init_data_length));
   1011 
   1012   if (!IsSupportedKeySystem(key_system))
   1013     return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
   1014 
   1015   // We do not support run-time switching between key systems for now.
   1016   if (current_key_system_.isEmpty()) {
   1017     if (!decryptor_->InitializeCDM(key_system.utf8()))
   1018       return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
   1019     current_key_system_ = key_system;
   1020   } else if (key_system != current_key_system_) {
   1021     return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
   1022   }
   1023 
   1024   // TODO(xhwang): We assume all streams are from the same container (thus have
   1025   // the same "type") for now. In the future, the "type" should be passed down
   1026   // from the application.
   1027   if (!decryptor_->GenerateKeyRequest(init_data_type_,
   1028                                       init_data, init_data_length)) {
   1029     current_key_system_.reset();
   1030     return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
   1031   }
   1032 
   1033   return WebMediaPlayer::MediaKeyExceptionNoError;
   1034 }
   1035 
   1036 WebMediaPlayer::MediaKeyException WebMediaPlayerAndroid::addKey(
   1037     const WebString& key_system,
   1038     const unsigned char* key,
   1039     unsigned key_length,
   1040     const unsigned char* init_data,
   1041     unsigned init_data_length,
   1042     const WebString& session_id) {
   1043   WebMediaPlayer::MediaKeyException e = AddKeyInternal(
   1044       key_system, key, key_length, init_data, init_data_length, session_id);
   1045   ReportMediaKeyExceptionToUMA("addKey", key_system, e);
   1046   return e;
   1047 }
   1048 
   1049 WebMediaPlayer::MediaKeyException WebMediaPlayerAndroid::AddKeyInternal(
   1050     const WebString& key_system,
   1051     const unsigned char* key,
   1052     unsigned key_length,
   1053     const unsigned char* init_data,
   1054     unsigned init_data_length,
   1055     const WebString& session_id) {
   1056   DCHECK(key);
   1057   DCHECK_GT(key_length, 0u);
   1058   DVLOG(1) << "addKey: " << key_system.utf8().data() << ": "
   1059            << std::string(reinterpret_cast<const char*>(key),
   1060                           static_cast<size_t>(key_length)) << ", "
   1061            << std::string(reinterpret_cast<const char*>(init_data),
   1062                           static_cast<size_t>(init_data_length))
   1063            << " [" << session_id.utf8().data() << "]";
   1064 
   1065   if (!IsSupportedKeySystem(key_system))
   1066     return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
   1067 
   1068   if (current_key_system_.isEmpty() || key_system != current_key_system_)
   1069     return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
   1070 
   1071   decryptor_->AddKey(key, key_length, init_data, init_data_length,
   1072                      session_id.utf8());
   1073   return WebMediaPlayer::MediaKeyExceptionNoError;
   1074 }
   1075 
   1076 WebMediaPlayer::MediaKeyException WebMediaPlayerAndroid::cancelKeyRequest(
   1077     const WebString& key_system,
   1078     const WebString& session_id) {
   1079   WebMediaPlayer::MediaKeyException e =
   1080       CancelKeyRequestInternal(key_system, session_id);
   1081   ReportMediaKeyExceptionToUMA("cancelKeyRequest", key_system, e);
   1082   return e;
   1083 }
   1084 
   1085 WebMediaPlayer::MediaKeyException
   1086 WebMediaPlayerAndroid::CancelKeyRequestInternal(
   1087     const WebString& key_system,
   1088     const WebString& session_id) {
   1089   if (!IsSupportedKeySystem(key_system))
   1090     return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
   1091 
   1092   if (current_key_system_.isEmpty() || key_system != current_key_system_)
   1093     return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
   1094 
   1095   decryptor_->CancelKeyRequest(session_id.utf8());
   1096   return WebMediaPlayer::MediaKeyExceptionNoError;
   1097 }
   1098 
   1099 void WebMediaPlayerAndroid::OnKeyAdded(const std::string& session_id) {
   1100   EmeUMAHistogramCounts(current_key_system_, "KeyAdded", 1);
   1101 
   1102   if (media_source_delegate_)
   1103     media_source_delegate_->NotifyKeyAdded(current_key_system_.utf8());
   1104 
   1105   client_->keyAdded(current_key_system_, WebString::fromUTF8(session_id));
   1106 }
   1107 
   1108 void WebMediaPlayerAndroid::OnKeyError(const std::string& session_id,
   1109                                        media::MediaKeys::KeyError error_code,
   1110                                        int system_code) {
   1111   EmeUMAHistogramEnumeration(current_key_system_, "KeyError",
   1112                              error_code, media::MediaKeys::kMaxKeyError);
   1113 
   1114   client_->keyError(
   1115       current_key_system_,
   1116       WebString::fromUTF8(session_id),
   1117       static_cast<WebKit::WebMediaPlayerClient::MediaKeyErrorCode>(error_code),
   1118       system_code);
   1119 }
   1120 
   1121 void WebMediaPlayerAndroid::OnKeyMessage(const std::string& session_id,
   1122                                          const std::vector<uint8>& message,
   1123                                          const std::string& destination_url) {
   1124   const GURL destination_url_gurl(destination_url);
   1125   DLOG_IF(WARNING, !destination_url.empty() && !destination_url_gurl.is_valid())
   1126       << "Invalid URL in destination_url: " << destination_url;
   1127 
   1128   client_->keyMessage(current_key_system_,
   1129                       WebString::fromUTF8(session_id),
   1130                       message.empty() ? NULL : &message[0],
   1131                       message.size(),
   1132                       destination_url_gurl);
   1133 }
   1134 
   1135 void WebMediaPlayerAndroid::OnNeedKey(const std::string& session_id,
   1136                                       const std::string& type,
   1137                                       scoped_ptr<uint8[]> init_data,
   1138                                       int init_data_size) {
   1139   // Do not fire NeedKey event if encrypted media is not enabled.
   1140   if (!WebKit::WebRuntimeFeatures::isEncryptedMediaEnabled() &&
   1141       !WebKit::WebRuntimeFeatures::isLegacyEncryptedMediaEnabled()) {
   1142     return;
   1143   }
   1144 
   1145   UMA_HISTOGRAM_COUNTS(kMediaEme + std::string("NeedKey"), 1);
   1146 
   1147   DCHECK(init_data_type_.empty() || type.empty() || type == init_data_type_);
   1148   if (init_data_type_.empty())
   1149     init_data_type_ = type;
   1150 
   1151   client_->keyNeeded(WebString(),
   1152                      WebString::fromUTF8(session_id),
   1153                      init_data.get(),
   1154                      init_data_size);
   1155 }
   1156 
   1157 #if defined(GOOGLE_TV)
   1158 bool WebMediaPlayerAndroid::InjectMediaStream(
   1159     MediaStreamClient* media_stream_client,
   1160     media::Demuxer* demuxer,
   1161     const base::Closure& destroy_demuxer_cb) {
   1162   DCHECK(!demuxer);
   1163   media_stream_client_ = media_stream_client;
   1164   demuxer_ = demuxer;
   1165   destroy_demuxer_cb_ = destroy_demuxer_cb;
   1166   return true;
   1167 }
   1168 #endif
   1169 
   1170 void WebMediaPlayerAndroid::OnReadFromDemuxer(media::DemuxerStream::Type type) {
   1171   if (media_source_delegate_)
   1172     media_source_delegate_->OnReadFromDemuxer(type);
   1173   else
   1174     NOTIMPLEMENTED();
   1175 }
   1176 
   1177 void WebMediaPlayerAndroid::enterFullscreen() {
   1178   if (manager_->CanEnterFullscreen(frame_)) {
   1179     proxy_->EnterFullscreen(player_id_);
   1180     SetNeedsEstablishPeer(false);
   1181   }
   1182 }
   1183 
   1184 void WebMediaPlayerAndroid::exitFullscreen() {
   1185   proxy_->ExitFullscreen(player_id_);
   1186 }
   1187 
   1188 bool WebMediaPlayerAndroid::canEnterFullscreen() const {
   1189   return manager_->CanEnterFullscreen(frame_);
   1190 }
   1191 
   1192 }  // namespace content
   1193