cast_video_element.js revision 5f1c94371a64b3196d4be9466099bb892df9b88e
15f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// found in the LICENSE file.
45f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
55f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)'use strict';
65f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)/**
85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * Inverval for updating media info (in ms).
95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * @type {number}
105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * @const
115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) */
125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)var MEDIA_UPDATE_INTERVAL = 250;
135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)/**
155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * The namespace for communication between the cast and the player.
165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * @type {string}
175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * @const
185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) */
195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)var CAST_MESSAGE_NAMESPACE = 'urn:x-cast:com.google.chromeos.videoplayer';
205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)/**
225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * This class is the dummy class which has same interface as VideoElement. This
235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * behaves like VideoElement, and is used for making Chromecast player
245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * controlled instead of the true Video Element tag.
255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) *
265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * @param {MediaManager} media Media manager with the media to play.
275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * @param {chrome.cast.Session} session Session to play a video on.
285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * @constructor
295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) */
305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)function CastVideoElement(media, session) {
315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.mediaManager_ = media;
325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.mediaInfo_ = null;
335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.castMedia_ = null;
355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.castSession_ = session;
365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.currentTime_ = null;
375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.src_ = '';
385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.volume_ = 100;
395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.currentMediaPlayerState_ = null;
405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.currentMediaCurrentTime_ = null;
415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.currentMediaDuration_ = null;
425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.playInProgress_ = false;
435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.pauseInProgress_ = false;
445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.onMessageBound_ = this.onMessage_.bind(this);
465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.onCastMediaUpdatedBound_ = this.onCastMediaUpdated_.bind(this);
475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.castSession_.addMessageListener(
485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      CAST_MESSAGE_NAMESPACE, this.onMessageBound_);
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)CastVideoElement.prototype = {
525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  __proto__: cr.EventTarget.prototype,
535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * Prepares for unloading this objects.
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  dispose: function() {
585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.unloadMedia_();
595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.castSession_.removeMessageListener(
605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        CAST_MESSAGE_NAMESPACE, this.onMessageBound_);
615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * Returns a parent node. This must always be null.
655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @type {Element}
665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  get parentNode() {
685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return null;
695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * The total time of the video (in sec).
735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @type {?number}
745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  get duration() {
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return this.currentMediaDuration_;
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * The current timestamp of the video (in sec).
815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @type {?number}
825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  get currentTime() {
845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (this.castMedia_) {
855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (this.castMedia_.idleReason === chrome.cast.media.IdleReason.FINISHED)
865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return this.currentMediaDuration_;  // Returns the duration.
875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      else
885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return this.castMedia_.getEstimatedTime();
895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    } else {
905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return null;
915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  set currentTime(currentTime) {
945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // TODO(yoshiki): Support seek.
955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * If this video is pauses or not.
995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @type {boolean}
1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  get paused() {
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (!this.castMedia_)
1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return false;
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return !this.playInProgress_ &&
1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        (this.pauseInProgress_ ||
1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)         this.castMedia_.playerState === chrome.cast.media.PlayerState.PAUSED);
1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * If this video is ended or not.
1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @type {boolean}
1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  get ended() {
1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (!this.castMedia_)
1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return true;
1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   return this.castMedia_.idleReason === chrome.cast.media.IdleReason.FINISHED;
1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * If this video is seelable or not.
1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @type {boolean}
1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  get seekable() {
1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // TODO(yoshiki): Support seek.
1275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
1285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
1295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
1315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * Value of the volume
1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @type {number}
1335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
1345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  get volume() {
1355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return this.castSession_.receiver.volume.muted ?
1365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)               0 :
1375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)               this.castSession_.receiver.volume.level;
1385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
1395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  set volume(volume) {
1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    var VOLUME_EPS = 0.01;  // Threshold for ignoring a small change.
1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // Ignores < 1% change.
1435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (Math.abs(this.castSession_.receiver.volume.level - volume) < VOLUME_EPS)
1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return;
1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (this.castSession_.receiver.volume.muted) {
1475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (volume < VOLUME_EPS)
1485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return;
1495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // Unmute before setting volume.
1515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.castSession_.setReceiverMuted(false,
1525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          function() {},
1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.onCastCommandError_.wrap(this));
1545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.castSession_.setReceiverVolumeLevel(volume,
1565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          function() {},
1575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.onCastCommandError_.wrap(this));
1585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    } else {
1595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (volume < VOLUME_EPS) {
1605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        this.castSession_.setReceiverMuted(true,
1615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            function() {},
1625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            this.onCastCommandError_.wrap(this));
1635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return;
1645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
1655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.castSession_.setReceiverVolumeLevel(volume,
1675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          function() {},
1685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.onCastCommandError_.wrap(this));
1695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
1705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
1715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
1735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * Returns the source of the current video.
1745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @type {?string}
1755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
1765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  get src() {
1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return null;
1785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
1795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  set src(value) {
1805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // Do nothing.
1815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
1825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
1845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * Plays the video.
1855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
1865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  play: function() {
1875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    var play = function() {
1885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.castMedia_.play(null,
1895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          function() {
1905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            this.playInProgress_ = false;
1915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          }.wrap(this),
1925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          function(error) {
1935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            this.playInProgress_ = false;
1945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            this.onCastCommandError_(error);
1955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          }.wrap(this));
1965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }.wrap(this);
1975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.playInProgress_ = true;
1995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (!this.castMedia_)
2015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.load(play);
2025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    else
2035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      play();
2045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
2055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
2075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * Pauses the video.
2085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
2095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  pause: function() {
2105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (!this.castMedia_)
2115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return;
2125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.pauseInProgress_ = true;
2145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.castMedia_.pause(null,
2155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        function() {
2165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.pauseInProgress_ = false;
2175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }.wrap(this),
2185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        function(error) {
2195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.pauseInProgress_ = false;
2205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.onCastCommandError_(error);
2215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }.wrap(this));
2225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
2235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
2255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * Loads the video.
2265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
2275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  load: function(opt_callback) {
2285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    var sendTokenPromise = this.mediaManager_.getToken().then(function(token) {
2295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.token_ = token;
2305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.sendMessage_({message: 'push-token', token: token});
2315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }.bind(this));
2325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    Promise.all([
2345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      sendTokenPromise,
2355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.mediaManager_.getUrl(),
2365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.mediaManager_.getMime(),
2375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.mediaManager_.getThumbnail()]).
2385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        then(function(results) {
2395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          var url = results[1];
2405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          var mime = results[2];
2415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          var thumbnailUrl = results[3];
2425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.mediaInfo_ = new chrome.cast.media.MediaInfo(url);
2445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.mediaInfo_.contentType = mime;
2455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.mediaInfo_.customData = {
2465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            tokenRequired: true,
2475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            thumbnailUrl: thumbnailUrl,
2485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          };
2495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          var request = new chrome.cast.media.LoadRequest(this.mediaInfo_);
2515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          return new Promise(
2525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)              this.castSession_.loadMedia.bind(this.castSession_, request)).
2535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)              then(function(media) {
2545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                this.onMediaDiscovered_(media);
2555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                if (opt_callback)
2565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                  opt_callback();
2575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)              }.bind(this));
2585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }.bind(this)).catch(function(error) {
2595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.unloadMedia_();
2605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.dispatchEvent(new Event('error'));
2615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          console.error('Cast failed.', error.stack || error);
2625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }.bind(this));
2635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
2645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
2665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * Unloads the video.
2675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @private
2685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
2695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  unloadMedia_: function() {
2705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (this.castMedia_) {
2715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.castMedia_.stop(null,
2725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          function() {},
2735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          function(error) {
2745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            // Ignores session error, since session may already be closed.
2755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if (error.code !== chrome.cast.ErrorCode.SESSION_ERROR)
2765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)              this.onCastCommandError_(error);
2775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          }.wrap(this));
2785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.castMedia_.removeUpdateListener(this.onCastMediaUpdatedBound_);
2805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.castMedia_ = null;
2815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
2825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    clearInterval(this.updateTimerId_);
2835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
2845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
2865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * Sends the message to cast.
2875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @param {Object} message Message to be sent (Must be JSON-able object).
2885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @private
2895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
2905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  sendMessage_: function(message) {
2915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.castSession_.sendMessage(CAST_MESSAGE_NAMESPACE, message);
2925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
2935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
2955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * Invoked when receiving a message from the cast.
2965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @param {string} namespace Namespace of the message.
2975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @param {string} messageAsJson Content of message as json format.
2985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @private
2995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
3005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  onMessage_: function(namespace, messageAsJson) {
3015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (namespace !== CAST_MESSAGE_NAMESPACE || !messageAsJson)
3025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return;
3035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    var message = JSON.parse(messageAsJson);
3055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (message['message'] === 'request-token') {
3065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (message['previousToken'] === this.token_) {
3075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.mediaManager_.getToken().then(function(token) {
3085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            this.sendMessage_({message: 'push-token', token: token});
3095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            // TODO(yoshiki): Revokes the previous token.
3105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          }.bind(this)).catch(function(error) {
3115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            // Send an empty token as an error.
3125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            this.sendMessage_({message: 'push-token', token: ''});
3135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            // TODO(yoshiki): Revokes the previous token.
3145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            console.error(error.stack || error);
3155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          });
3165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      } else {
3175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        console.error(
3185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            'New token is requested, but the previous token mismatches.');
3195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
3205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
3215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
3225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
3245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * This method is called periodically to update media information while the
3255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * media is loaded.
3265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @private
3275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
3285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  onPeriodicalUpdateTimer_: function() {
3295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (!this.castMedia_)
3305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return;
3315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (this.castMedia_.playerState === chrome.cast.media.PlayerState.PLAYING)
3335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.onCastMediaUpdated_(true);
3345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
3355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
3375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * This method should be called when a media file is loaded.
3385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @param {chrome.cast.Media} media Media object which was discovered.
3395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @private
3405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
3415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  onMediaDiscovered_: function(media) {
3425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (this.castMedia_ !== null) {
3435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.unloadMedia_();
3445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      console.info('New media is found and the old media is overridden.');
3455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
3465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.castMedia_ = media;
3485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.onCastMediaUpdated_(true);
3495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // Notify that the metadata of the video is ready.
3505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.dispatchEvent(new Event('loadedmetadata'));
3515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    media.addUpdateListener(this.onCastMediaUpdatedBound_);
3535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.updateTimerId_ = setInterval(this.onPeriodicalUpdateTimer_.bind(this),
3545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                      MEDIA_UPDATE_INTERVAL);
3555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
3565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
3585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * This method should be called when a media command to cast is failed.
3595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @param {Object} error Object representing the error.
3605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @private
3615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
3625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  onCastCommandError_: function(error) {
3635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.unloadMedia_();
3645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.dispatchEvent(new Event('error'));
3655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    console.error('Error on sending command to cast.', error.stack || error);
3665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
3675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
3695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * This is called when any media data is updated and by the periodical timer
3705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * is fired.
3715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   *
3725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @param {boolean} alive Media availability. False if it's unavailable.
3735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @private
3745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
3755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  onCastMediaUpdated_: function(alive) {
3765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (!this.castMedia_)
3775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return;
3785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    var media = this.castMedia_;
3805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (this.currentMediaPlayerState_ !== media.playerState) {
3815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      var oldPlayState = false;
3825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      var oldState = this.currentMediaPlayerState_;
3835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (oldState === chrome.cast.media.PlayerState.BUFFERING ||
3845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          oldState === chrome.cast.media.PlayerState.PLAYING) {
3855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        oldPlayState = true;
3865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
3875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      var newPlayState = false;
3885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      var newState = media.playerState;
3895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (newState === chrome.cast.media.PlayerState.BUFFERING ||
3905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          newState === chrome.cast.media.PlayerState.PLAYING) {
3915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        newPlayState = true;
3925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
3935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (!oldPlayState && newPlayState)
3945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        this.dispatchEvent(new Event('play'));
3955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (oldPlayState && !newPlayState)
3965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        this.dispatchEvent(new Event('pause'));
3975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.currentMediaPlayerState_ = newState;
3995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
4005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (this.currentMediaCurrentTime_ !== media.getEstimatedTime()) {
4015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.currentMediaCurrentTime_ = media.getEstimatedTime();
4025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.dispatchEvent(new Event('timeupdate'));
4035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
4045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (this.currentMediaDuration_ !== media.media.duration) {
4065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.currentMediaDuration_ = media.media.duration;
4075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.dispatchEvent(new Event('durationchange'));
4085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
4095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // Media is being unloaded.
4115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (!alive) {
4125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.unloadMedia_();
4135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return;
4145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
4155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
4165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)};
417