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/browser/media/android/browser_media_player_manager.h"
6
7#include "base/android/scoped_java_ref.h"
8#include "base/command_line.h"
9#include "content/browser/android/content_view_core_impl.h"
10#include "content/browser/media/android/browser_demuxer_android.h"
11#include "content/browser/media/android/media_resource_getter_impl.h"
12#include "content/browser/renderer_host/render_view_host_impl.h"
13#include "content/browser/web_contents/web_contents_view_android.h"
14#include "content/common/media/media_player_messages_android.h"
15#include "content/public/browser/android/content_view_core.h"
16#include "content/public/browser/android/external_video_surface_container.h"
17#include "content/public/browser/browser_context.h"
18#include "content/public/browser/content_browser_client.h"
19#include "content/public/browser/render_frame_host.h"
20#include "content/public/browser/render_process_host.h"
21#include "content/public/browser/render_view_host.h"
22#include "content/public/browser/storage_partition.h"
23#include "content/public/browser/web_contents.h"
24#include "content/public/browser/web_contents_delegate.h"
25#include "content/public/common/content_client.h"
26#include "content/public/common/content_switches.h"
27#include "media/base/android/media_player_bridge.h"
28#include "media/base/android/media_source_player.h"
29#include "media/base/android/media_url_interceptor.h"
30#include "media/base/media_switches.h"
31
32using media::MediaPlayerAndroid;
33using media::MediaPlayerBridge;
34using media::MediaPlayerManager;
35using media::MediaSourcePlayer;
36
37namespace content {
38
39// Threshold on the number of media players per renderer before we start
40// attempting to release inactive media players.
41const int kMediaPlayerThreshold = 1;
42
43static BrowserMediaPlayerManager::Factory g_factory = NULL;
44static media::MediaUrlInterceptor* media_url_interceptor_ = NULL;
45
46// static
47void BrowserMediaPlayerManager::RegisterFactory(Factory factory) {
48  g_factory = factory;
49}
50
51// static
52void BrowserMediaPlayerManager::RegisterMediaUrlInterceptor(
53    media::MediaUrlInterceptor* media_url_interceptor) {
54  media_url_interceptor_ = media_url_interceptor;
55}
56
57// static
58BrowserMediaPlayerManager* BrowserMediaPlayerManager::Create(
59    RenderFrameHost* rfh) {
60  if (g_factory)
61    return g_factory(rfh);
62  return new BrowserMediaPlayerManager(rfh);
63}
64
65ContentViewCoreImpl* BrowserMediaPlayerManager::GetContentViewCore() const {
66  return ContentViewCoreImpl::FromWebContents(web_contents());
67}
68
69MediaPlayerAndroid* BrowserMediaPlayerManager::CreateMediaPlayer(
70    const MediaPlayerHostMsg_Initialize_Params& media_player_params,
71    bool hide_url_log,
72    MediaPlayerManager* manager,
73    BrowserDemuxerAndroid* demuxer) {
74  switch (media_player_params.type) {
75    case MEDIA_PLAYER_TYPE_URL: {
76      const std::string user_agent = GetContentClient()->GetUserAgent();
77      MediaPlayerBridge* media_player_bridge = new MediaPlayerBridge(
78          media_player_params.player_id,
79          media_player_params.url,
80          media_player_params.first_party_for_cookies,
81          user_agent,
82          hide_url_log,
83          manager,
84          base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesRequested,
85                     weak_ptr_factory_.GetWeakPtr()),
86          media_player_params.frame_url,
87          media_player_params.allow_credentials);
88      BrowserMediaPlayerManager* browser_media_player_manager =
89          static_cast<BrowserMediaPlayerManager*>(manager);
90      ContentViewCoreImpl* content_view_core_impl =
91          static_cast<ContentViewCoreImpl*>(ContentViewCore::FromWebContents(
92              browser_media_player_manager->web_contents_));
93      if (!content_view_core_impl) {
94        // May reach here due to prerendering. Don't extract the metadata
95        // since it is expensive.
96        // TODO(qinmin): extract the metadata once the user decided to load
97        // the page.
98        browser_media_player_manager->OnMediaMetadataChanged(
99            media_player_params.player_id, base::TimeDelta(), 0, 0, false);
100      } else if (!content_view_core_impl->ShouldBlockMediaRequest(
101            media_player_params.url)) {
102        media_player_bridge->Initialize();
103      }
104      return media_player_bridge;
105    }
106
107    case MEDIA_PLAYER_TYPE_MEDIA_SOURCE: {
108      return new MediaSourcePlayer(
109          media_player_params.player_id,
110          manager,
111          base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesRequested,
112                     weak_ptr_factory_.GetWeakPtr()),
113          demuxer->CreateDemuxer(media_player_params.demuxer_client_id),
114          media_player_params.frame_url);
115    }
116  }
117
118  NOTREACHED();
119  return NULL;
120}
121
122BrowserMediaPlayerManager::BrowserMediaPlayerManager(
123    RenderFrameHost* render_frame_host)
124    : render_frame_host_(render_frame_host),
125      fullscreen_player_id_(-1),
126      fullscreen_player_is_released_(false),
127      web_contents_(WebContents::FromRenderFrameHost(render_frame_host)),
128      weak_ptr_factory_(this) {
129}
130
131BrowserMediaPlayerManager::~BrowserMediaPlayerManager() {
132  // During the tear down process, OnDestroyPlayer() may or may not be called
133  // (e.g. the WebContents may be destroyed before the render process). So
134  // we cannot DCHECK(players_.empty()) here. Instead, all media players in
135  // |players_| will be destroyed here because |player_| is a ScopedVector.
136}
137
138void BrowserMediaPlayerManager::FullscreenPlayerPlay() {
139  MediaPlayerAndroid* player = GetFullscreenPlayer();
140  if (player) {
141    if (fullscreen_player_is_released_) {
142      video_view_->OpenVideo();
143      fullscreen_player_is_released_ = false;
144    }
145    player->Start();
146    Send(new MediaPlayerMsg_DidMediaPlayerPlay(RoutingID(),
147                                               fullscreen_player_id_));
148  }
149}
150
151void BrowserMediaPlayerManager::FullscreenPlayerPause() {
152  MediaPlayerAndroid* player = GetFullscreenPlayer();
153  if (player) {
154    player->Pause(true);
155    Send(new MediaPlayerMsg_DidMediaPlayerPause(RoutingID(),
156                                                fullscreen_player_id_));
157  }
158}
159
160void BrowserMediaPlayerManager::FullscreenPlayerSeek(int msec) {
161  MediaPlayerAndroid* player = GetFullscreenPlayer();
162  if (player) {
163    // TODO(kbalazs): if |fullscreen_player_is_released_| is true
164    // at this point, player->GetCurrentTime() will be wrong until
165    // FullscreenPlayerPlay (http://crbug.com/322798).
166    OnSeekRequest(fullscreen_player_id_,
167                  base::TimeDelta::FromMilliseconds(msec));
168  }
169}
170
171void BrowserMediaPlayerManager::ExitFullscreen(bool release_media_player) {
172  if (WebContentsDelegate* delegate = web_contents_->GetDelegate())
173    delegate->ToggleFullscreenModeForTab(web_contents_, false);
174  if (RenderWidgetHostViewAndroid* view_android =
175      static_cast<RenderWidgetHostViewAndroid*>(
176          web_contents_->GetRenderWidgetHostView())) {
177    view_android->SetOverlayVideoMode(false);
178  }
179
180  Send(
181      new MediaPlayerMsg_DidExitFullscreen(RoutingID(), fullscreen_player_id_));
182  video_view_.reset();
183  MediaPlayerAndroid* player = GetFullscreenPlayer();
184  fullscreen_player_id_ = -1;
185  if (!player)
186    return;
187  if (release_media_player)
188    ReleaseFullscreenPlayer(player);
189  else
190    player->SetVideoSurface(gfx::ScopedJavaSurface());
191}
192
193void BrowserMediaPlayerManager::OnTimeUpdate(
194    int player_id,
195    base::TimeDelta current_timestamp,
196    base::TimeTicks current_time_ticks) {
197  Send(new MediaPlayerMsg_MediaTimeUpdate(
198      RoutingID(), player_id, current_timestamp, current_time_ticks));
199}
200
201void BrowserMediaPlayerManager::SetVideoSurface(
202    gfx::ScopedJavaSurface surface) {
203  MediaPlayerAndroid* player = GetFullscreenPlayer();
204  if (!player)
205    return;
206
207  bool empty_surface = surface.IsEmpty();
208  player->SetVideoSurface(surface.Pass());
209  if (empty_surface)
210    return;
211
212  Send(new MediaPlayerMsg_DidEnterFullscreen(RoutingID(), player->player_id()));
213  if (RenderWidgetHostViewAndroid* view_android =
214      static_cast<RenderWidgetHostViewAndroid*>(
215          web_contents_->GetRenderWidgetHostView())) {
216    view_android->SetOverlayVideoMode(true);
217  }
218}
219
220void BrowserMediaPlayerManager::OnMediaMetadataChanged(
221    int player_id, base::TimeDelta duration, int width, int height,
222    bool success) {
223  Send(new MediaPlayerMsg_MediaMetadataChanged(
224      RoutingID(), player_id, duration, width, height, success));
225  if (fullscreen_player_id_ == player_id)
226    video_view_->UpdateMediaMetadata();
227}
228
229void BrowserMediaPlayerManager::OnPlaybackComplete(int player_id) {
230  Send(new MediaPlayerMsg_MediaPlaybackCompleted(RoutingID(), player_id));
231  if (fullscreen_player_id_ == player_id)
232    video_view_->OnPlaybackComplete();
233}
234
235void BrowserMediaPlayerManager::OnMediaInterrupted(int player_id) {
236  // Tell WebKit that the audio should be paused, then release all resources
237  Send(new MediaPlayerMsg_MediaPlayerReleased(RoutingID(), player_id));
238  OnReleaseResources(player_id);
239}
240
241void BrowserMediaPlayerManager::OnBufferingUpdate(
242    int player_id, int percentage) {
243  Send(new MediaPlayerMsg_MediaBufferingUpdate(
244      RoutingID(), player_id, percentage));
245  if (fullscreen_player_id_ == player_id)
246    video_view_->OnBufferingUpdate(percentage);
247}
248
249void BrowserMediaPlayerManager::OnSeekRequest(
250    int player_id,
251    const base::TimeDelta& time_to_seek) {
252  Send(new MediaPlayerMsg_SeekRequest(RoutingID(), player_id, time_to_seek));
253}
254
255void BrowserMediaPlayerManager::ReleaseAllMediaPlayers() {
256  for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
257      it != players_.end(); ++it) {
258    if ((*it)->player_id() == fullscreen_player_id_)
259      fullscreen_player_is_released_ = true;
260    (*it)->Release();
261  }
262}
263
264void BrowserMediaPlayerManager::OnSeekComplete(
265    int player_id,
266    const base::TimeDelta& current_time) {
267  Send(new MediaPlayerMsg_SeekCompleted(RoutingID(), player_id, current_time));
268}
269
270void BrowserMediaPlayerManager::OnError(int player_id, int error) {
271  Send(new MediaPlayerMsg_MediaError(RoutingID(), player_id, error));
272  if (fullscreen_player_id_ == player_id)
273    video_view_->OnMediaPlayerError(error);
274}
275
276void BrowserMediaPlayerManager::OnVideoSizeChanged(
277    int player_id, int width, int height) {
278  Send(new MediaPlayerMsg_MediaVideoSizeChanged(RoutingID(), player_id,
279      width, height));
280  if (fullscreen_player_id_ == player_id)
281    video_view_->OnVideoSizeChanged(width, height);
282}
283
284media::MediaResourceGetter*
285BrowserMediaPlayerManager::GetMediaResourceGetter() {
286  if (!media_resource_getter_.get()) {
287    RenderProcessHost* host = web_contents()->GetRenderProcessHost();
288    BrowserContext* context = host->GetBrowserContext();
289    StoragePartition* partition = host->GetStoragePartition();
290    storage::FileSystemContext* file_system_context =
291        partition ? partition->GetFileSystemContext() : NULL;
292    // Eventually this needs to be fixed to pass the correct frame rather
293    // than just using the main frame.
294    media_resource_getter_.reset(new MediaResourceGetterImpl(
295        context,
296        file_system_context,
297        host->GetID(),
298        web_contents()->GetMainFrame()->GetRoutingID()));
299  }
300  return media_resource_getter_.get();
301}
302
303media::MediaUrlInterceptor*
304BrowserMediaPlayerManager::GetMediaUrlInterceptor() {
305  return media_url_interceptor_;
306}
307
308MediaPlayerAndroid* BrowserMediaPlayerManager::GetFullscreenPlayer() {
309  return GetPlayer(fullscreen_player_id_);
310}
311
312MediaPlayerAndroid* BrowserMediaPlayerManager::GetPlayer(int player_id) {
313  for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
314      it != players_.end(); ++it) {
315    if ((*it)->player_id() == player_id)
316      return *it;
317  }
318  return NULL;
319}
320
321void BrowserMediaPlayerManager::RequestFullScreen(int player_id) {
322  if (fullscreen_player_id_ == player_id)
323    return;
324
325  if (fullscreen_player_id_ != -1) {
326    // TODO(qinmin): Determine the correct error code we should report to WMPA.
327    OnError(player_id, MediaPlayerAndroid::MEDIA_ERROR_DECODE);
328    return;
329  }
330
331  Send(new MediaPlayerMsg_RequestFullscreen(RoutingID(), player_id));
332}
333
334#if defined(VIDEO_HOLE)
335bool
336BrowserMediaPlayerManager::ShouldUseVideoOverlayForEmbeddedEncryptedVideo() {
337  RendererPreferences* prefs = web_contents_->GetMutableRendererPrefs();
338  return prefs->use_video_overlay_for_embedded_encrypted_video;
339}
340
341void BrowserMediaPlayerManager::AttachExternalVideoSurface(int player_id,
342                                                           jobject surface) {
343  MediaPlayerAndroid* player = GetPlayer(player_id);
344  if (player) {
345    player->SetVideoSurface(
346        gfx::ScopedJavaSurface::AcquireExternalSurface(surface));
347  }
348}
349
350void BrowserMediaPlayerManager::DetachExternalVideoSurface(int player_id) {
351  MediaPlayerAndroid* player = GetPlayer(player_id);
352  if (player)
353    player->SetVideoSurface(gfx::ScopedJavaSurface());
354}
355
356void BrowserMediaPlayerManager::OnFrameInfoUpdated() {
357  if (external_video_surface_container_)
358    external_video_surface_container_->OnFrameInfoUpdated();
359}
360
361void BrowserMediaPlayerManager::OnNotifyExternalSurface(
362    int player_id, bool is_request, const gfx::RectF& rect) {
363  if (!web_contents_)
364    return;
365
366  if (is_request) {
367    OnRequestExternalSurface(player_id, rect);
368  }
369  if (external_video_surface_container_) {
370    external_video_surface_container_->OnExternalVideoSurfacePositionChanged(
371        player_id, rect);
372  }
373}
374
375void BrowserMediaPlayerManager::OnRequestExternalSurface(
376    int player_id, const gfx::RectF& rect) {
377  if (!external_video_surface_container_) {
378    ContentBrowserClient* client = GetContentClient()->browser();
379    external_video_surface_container_.reset(
380        client->OverrideCreateExternalVideoSurfaceContainer(web_contents_));
381  }
382  // It's safe to use base::Unretained(this), because the callbacks will not
383  // be called after running ReleaseExternalVideoSurface().
384  if (external_video_surface_container_) {
385    external_video_surface_container_->RequestExternalVideoSurface(
386        player_id,
387        base::Bind(&BrowserMediaPlayerManager::AttachExternalVideoSurface,
388                   base::Unretained(this)),
389        base::Bind(&BrowserMediaPlayerManager::DetachExternalVideoSurface,
390                   base::Unretained(this)));
391  }
392}
393#endif  // defined(VIDEO_HOLE)
394
395void BrowserMediaPlayerManager::OnEnterFullscreen(int player_id) {
396  DCHECK_EQ(fullscreen_player_id_, -1);
397#if defined(VIDEO_HOLE)
398  if (external_video_surface_container_)
399    external_video_surface_container_->ReleaseExternalVideoSurface(player_id);
400#endif  // defined(VIDEO_HOLE)
401  if (video_view_.get()) {
402    fullscreen_player_id_ = player_id;
403    video_view_->OpenVideo();
404    return;
405  } else if (!ContentVideoView::GetInstance()) {
406    // In Android WebView, two ContentViewCores could both try to enter
407    // fullscreen video, we just ignore the second one.
408    video_view_.reset(new ContentVideoView(this));
409    base::android::ScopedJavaLocalRef<jobject> j_content_video_view =
410        video_view_->GetJavaObject(base::android::AttachCurrentThread());
411    if (!j_content_video_view.is_null()) {
412      fullscreen_player_id_ = player_id;
413      return;
414    }
415  }
416
417  // Force the second video to exit fullscreen.
418  // TODO(qinmin): There is no need to send DidEnterFullscreen message.
419  // However, if we don't send the message, page layers will not be
420  // correctly restored. http:crbug.com/367346.
421  Send(new MediaPlayerMsg_DidEnterFullscreen(RoutingID(), player_id));
422  Send(new MediaPlayerMsg_DidExitFullscreen(RoutingID(), player_id));
423  video_view_.reset();
424}
425
426void BrowserMediaPlayerManager::OnExitFullscreen(int player_id) {
427  if (fullscreen_player_id_ == player_id) {
428    MediaPlayerAndroid* player = GetPlayer(player_id);
429    if (player)
430      player->SetVideoSurface(gfx::ScopedJavaSurface());
431    video_view_->OnExitFullscreen();
432  }
433}
434
435void BrowserMediaPlayerManager::OnInitialize(
436    const MediaPlayerHostMsg_Initialize_Params& media_player_params) {
437  DCHECK(media_player_params.type != MEDIA_PLAYER_TYPE_MEDIA_SOURCE ||
438      media_player_params.demuxer_client_id > 0)
439      << "Media source players must have positive demuxer client IDs: "
440      << media_player_params.demuxer_client_id;
441
442  RemovePlayer(media_player_params.player_id);
443
444  RenderProcessHostImpl* host = static_cast<RenderProcessHostImpl*>(
445      web_contents()->GetRenderProcessHost());
446  MediaPlayerAndroid* player = CreateMediaPlayer(
447      media_player_params,
448
449      host->GetBrowserContext()->IsOffTheRecord(), this,
450      host->browser_demuxer_android());
451
452  if (!player)
453    return;
454
455  AddPlayer(player);
456}
457
458void BrowserMediaPlayerManager::OnStart(int player_id) {
459  MediaPlayerAndroid* player = GetPlayer(player_id);
460  if (!player)
461    return;
462  player->Start();
463  if (fullscreen_player_id_ == player_id && fullscreen_player_is_released_) {
464    video_view_->OpenVideo();
465    fullscreen_player_is_released_ = false;
466  }
467}
468
469void BrowserMediaPlayerManager::OnSeek(
470    int player_id,
471    const base::TimeDelta& time) {
472  MediaPlayerAndroid* player = GetPlayer(player_id);
473  if (player)
474    player->SeekTo(time);
475}
476
477void BrowserMediaPlayerManager::OnPause(
478    int player_id,
479    bool is_media_related_action) {
480  MediaPlayerAndroid* player = GetPlayer(player_id);
481  if (player)
482    player->Pause(is_media_related_action);
483}
484
485void BrowserMediaPlayerManager::OnSetVolume(int player_id, double volume) {
486  MediaPlayerAndroid* player = GetPlayer(player_id);
487  if (player)
488    player->SetVolume(volume);
489}
490
491void BrowserMediaPlayerManager::OnSetPoster(int player_id, const GURL& url) {
492  // To be overridden by subclasses.
493}
494
495void BrowserMediaPlayerManager::OnReleaseResources(int player_id) {
496  MediaPlayerAndroid* player = GetPlayer(player_id);
497  if (player)
498    ReleasePlayer(player);
499  if (player_id == fullscreen_player_id_)
500    fullscreen_player_is_released_ = true;
501}
502
503void BrowserMediaPlayerManager::OnDestroyPlayer(int player_id) {
504  RemovePlayer(player_id);
505  if (fullscreen_player_id_ == player_id)
506    fullscreen_player_id_ = -1;
507}
508
509void BrowserMediaPlayerManager::OnRequestRemotePlayback(int /* player_id */) {
510  // Does nothing if we don't have a remote player
511}
512
513void BrowserMediaPlayerManager::OnRequestRemotePlaybackControl(
514    int /* player_id */) {
515  // Does nothing if we don't have a remote player
516}
517
518void BrowserMediaPlayerManager::AddPlayer(MediaPlayerAndroid* player) {
519  DCHECK(!GetPlayer(player->player_id()));
520  players_.push_back(player);
521}
522
523void BrowserMediaPlayerManager::RemovePlayer(int player_id) {
524  for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
525      it != players_.end(); ++it) {
526    if ((*it)->player_id() == player_id) {
527      ReleaseMediaResources(player_id);
528      players_.erase(it);
529      break;
530    }
531  }
532}
533
534scoped_ptr<media::MediaPlayerAndroid> BrowserMediaPlayerManager::SwapPlayer(
535      int player_id, media::MediaPlayerAndroid* player) {
536  media::MediaPlayerAndroid* previous_player = NULL;
537  for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
538      it != players_.end(); ++it) {
539    if ((*it)->player_id() == player_id) {
540      previous_player = *it;
541      ReleaseMediaResources(player_id);
542      players_.weak_erase(it);
543      players_.push_back(player);
544      break;
545    }
546  }
547  return scoped_ptr<media::MediaPlayerAndroid>(previous_player);
548}
549
550int BrowserMediaPlayerManager::RoutingID() {
551  return render_frame_host_->GetRoutingID();
552}
553
554bool BrowserMediaPlayerManager::Send(IPC::Message* msg) {
555  return render_frame_host_->Send(msg);
556}
557
558void BrowserMediaPlayerManager::ReleaseFullscreenPlayer(
559    MediaPlayerAndroid* player) {
560  ReleasePlayer(player);
561}
562
563void BrowserMediaPlayerManager::OnMediaResourcesRequested(int player_id) {
564  int num_active_player = 0;
565  ScopedVector<MediaPlayerAndroid>::iterator it;
566  for (it = players_.begin(); it != players_.end(); ++it) {
567    if (!(*it)->IsPlayerReady())
568      continue;
569
570    // The player is already active, ignore it.
571    if ((*it)->player_id() == player_id)
572      return;
573    else
574      num_active_player++;
575  }
576
577  // Number of active players are less than the threshold, do nothing.
578  if (num_active_player < kMediaPlayerThreshold)
579    return;
580
581  for (it = players_.begin(); it != players_.end(); ++it) {
582    if ((*it)->IsPlayerReady() && !(*it)->IsPlaying() &&
583        fullscreen_player_id_ != (*it)->player_id()) {
584      ReleasePlayer(*it);
585      Send(new MediaPlayerMsg_MediaPlayerReleased(RoutingID(),
586                                                  (*it)->player_id()));
587    }
588  }
589}
590
591void BrowserMediaPlayerManager::ReleaseMediaResources(int player_id) {
592#if defined(VIDEO_HOLE)
593  if (external_video_surface_container_)
594    external_video_surface_container_->ReleaseExternalVideoSurface(player_id);
595#endif  // defined(VIDEO_HOLE)
596}
597
598void BrowserMediaPlayerManager::ReleasePlayer(MediaPlayerAndroid* player) {
599  player->Release();
600  ReleaseMediaResources(player->player_id());
601}
602
603}  // namespace content
604