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)/**
86e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * Interval 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;
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  this.loop_ = false;
405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.currentMediaPlayerState_ = null;
415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.currentMediaCurrentTime_ = null;
425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.currentMediaDuration_ = null;
435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.playInProgress_ = false;
445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.pauseInProgress_ = false;
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  this.errorCode_ = 0;
465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.onMessageBound_ = this.onMessage_.bind(this);
485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.onCastMediaUpdatedBound_ = this.onCastMediaUpdated_.bind(this);
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.castSession_.addMessageListener(
505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      CAST_MESSAGE_NAMESPACE, this.onMessageBound_);
515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)CastVideoElement.prototype = {
545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  __proto__: cr.EventTarget.prototype,
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * Prepares for unloading this objects.
585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  dispose: function() {
605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.unloadMedia_();
615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.castSession_.removeMessageListener(
625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        CAST_MESSAGE_NAMESPACE, this.onMessageBound_);
635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * Returns a parent node. This must always be null.
675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @type {Element}
685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  get parentNode() {
705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return null;
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * The total time of the video (in sec).
755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @type {?number}
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  get duration() {
785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return this.currentMediaDuration_;
795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * The current timestamp of the video (in sec).
835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @type {?number}
845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  get currentTime() {
865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (this.castMedia_) {
875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (this.castMedia_.idleReason === chrome.cast.media.IdleReason.FINISHED)
885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return this.currentMediaDuration_;  // Returns the duration.
895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      else
905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return this.castMedia_.getEstimatedTime();
915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    } else {
925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return null;
935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  set currentTime(currentTime) {
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    var seekRequest = new chrome.cast.media.SeekRequest();
971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    seekRequest.currentTime = currentTime;
981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.castMedia_.seek(seekRequest,
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        function() {},
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        this.onCastCommandError_.wrap(this));
1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * If this video is pauses or not.
1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @type {boolean}
1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  get paused() {
1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (!this.castMedia_)
1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return false;
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return !this.playInProgress_ &&
1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        (this.pauseInProgress_ ||
1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)         this.castMedia_.playerState === chrome.cast.media.PlayerState.PAUSED);
1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * If this video is ended or not.
1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @type {boolean}
1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  get ended() {
1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (!this.castMedia_)
1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return true;
1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return !this.playInProgress &&
1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci           this.castMedia_.idleReason === chrome.cast.media.IdleReason.FINISHED;
1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
1275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * TimeRange object that represents the seekable ranges of the media
1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * resource.
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * @type {TimeRanges}
1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
1335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  get seekable() {
1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return {
1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      length: 1,
1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      start: function(index) { return 0; },
1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      end: function(index) { return this.currentMediaDuration_; },
1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    };
1395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * Value of the volume
1435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @type {number}
1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  get volume() {
1465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return this.castSession_.receiver.volume.muted ?
1475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)               0 :
1485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)               this.castSession_.receiver.volume.level;
1495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
1505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  set volume(volume) {
1515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    var VOLUME_EPS = 0.01;  // Threshold for ignoring a small change.
1525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (this.castSession_.receiver.volume.muted) {
1555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (volume < VOLUME_EPS)
1565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return;
1575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // Unmute before setting volume.
1595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.castSession_.setReceiverMuted(false,
1605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          function() {},
1615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.onCastCommandError_.wrap(this));
1625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.castSession_.setReceiverVolumeLevel(volume,
1645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          function() {},
1655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.onCastCommandError_.wrap(this));
1665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    } else {
1671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      // Ignores < 1% change.
1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      var diff = this.castSession_.receiver.volume.level - volume;
1691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if (Math.abs(diff) < VOLUME_EPS)
1701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        return;
1711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (volume < VOLUME_EPS) {
1735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        this.castSession_.setReceiverMuted(true,
1745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            function() {},
1755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            this.onCastCommandError_.wrap(this));
1765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return;
1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
1785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.castSession_.setReceiverVolumeLevel(volume,
1805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          function() {},
1815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.onCastCommandError_.wrap(this));
1825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
1835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
1845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
1865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * Returns the source of the current video.
1875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @type {?string}
1885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
1895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  get src() {
1905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return null;
1915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
1925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  set src(value) {
1935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // Do nothing.
1945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
1955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
1971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * Returns the flag if the video loops at end or not.
1981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * @type {boolean}
1991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   */
2001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  get loop() {
2011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return this.loop_;
2021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  },
2031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  set loop(value) {
2041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.loop_ = !!value;
2051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  },
2061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  /**
2081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * Returns the error object if available.
2091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * @type {?Object}
2101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   */
2111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  get error() {
2121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (this.errorCode_ === 0)
2131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return null;
2141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return {code: this.errorCode_};
2161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  },
2171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  /**
2195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * Plays the video.
2201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * @param {boolean=} opt_seeking True when seeking. False otherwise.
2215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
2221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  play: function(opt_seeking) {
2231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (this.playInProgress_)
2241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return;
2251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    var play = function() {
22734680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)      // If the casted media is already playing and a pause request is not in
22834680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)      // progress, we can skip this play request.
2291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if (this.castMedia_.playerState ===
23034680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)              chrome.cast.media.PlayerState.PLAYING &&
23134680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)          !this.pauseInProgress_) {
23234680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)        this.playInProgress_ = false;
2331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        return;
2341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      }
2351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      var playRequest = new chrome.cast.media.PlayRequest();
2371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      playRequest.customData = {seeking: !!opt_seeking};
2381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      this.castMedia_.play(
2401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          playRequest,
2415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          function() {
2425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            this.playInProgress_ = false;
2435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          }.wrap(this),
2445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          function(error) {
2455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            this.playInProgress_ = false;
2465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            this.onCastCommandError_(error);
2475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          }.wrap(this));
2485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }.wrap(this);
2495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.playInProgress_ = true;
2515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (!this.castMedia_)
2535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.load(play);
2545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    else
2555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      play();
2565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
2575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
2595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * Pauses the video.
2601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * @param {boolean=} opt_seeking True when seeking. False otherwise.
2615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
2621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  pause: function(opt_seeking) {
2635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (!this.castMedia_)
2645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return;
2655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (this.pauseInProgress_ ||
2671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        this.castMedia_.playerState === chrome.cast.media.PlayerState.PAUSED) {
2681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return;
2691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
2701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    var pauseRequest = new chrome.cast.media.PauseRequest();
2721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    pauseRequest.customData = {seeking: !!opt_seeking};
2731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.pauseInProgress_ = true;
2751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.castMedia_.pause(
2761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        pauseRequest,
2775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        function() {
2785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.pauseInProgress_ = false;
2795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }.wrap(this),
2805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        function(error) {
2815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.pauseInProgress_ = false;
2825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.onCastCommandError_(error);
2835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }.wrap(this));
2845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
2855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
2875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * Loads the video.
2885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
2895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  load: function(opt_callback) {
2905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    var sendTokenPromise = this.mediaManager_.getToken().then(function(token) {
2915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.token_ = token;
2925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.sendMessage_({message: 'push-token', token: token});
2935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }.bind(this));
2945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Resets the error code.
2961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.errorCode_ = 0;
2971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    Promise.all([
2995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      sendTokenPromise,
3005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.mediaManager_.getUrl(),
3015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.mediaManager_.getMime(),
3025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.mediaManager_.getThumbnail()]).
3035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        then(function(results) {
3045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          var url = results[1];
3051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          var mime = results[2];  // maybe empty
3061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          var thumbnailUrl = results[3];  // maybe empty
3075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.mediaInfo_ = new chrome.cast.media.MediaInfo(url);
3095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.mediaInfo_.contentType = mime;
3105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.mediaInfo_.customData = {
3115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            tokenRequired: true,
3125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            thumbnailUrl: thumbnailUrl,
3135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          };
3145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          var request = new chrome.cast.media.LoadRequest(this.mediaInfo_);
3165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          return new Promise(
3175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)              this.castSession_.loadMedia.bind(this.castSession_, request)).
3185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)              then(function(media) {
3195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                this.onMediaDiscovered_(media);
3205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                if (opt_callback)
3215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                  opt_callback();
3225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)              }.bind(this));
3235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }.bind(this)).catch(function(error) {
3245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.unloadMedia_();
3255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.dispatchEvent(new Event('error'));
3265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          console.error('Cast failed.', error.stack || error);
3275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }.bind(this));
3285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
3295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
3315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * Unloads the video.
3325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @private
3335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
3345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  unloadMedia_: function() {
3355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (this.castMedia_) {
3365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.castMedia_.stop(null,
3375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          function() {},
3385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          function(error) {
3395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            // Ignores session error, since session may already be closed.
3405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if (error.code !== chrome.cast.ErrorCode.SESSION_ERROR)
3415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)              this.onCastCommandError_(error);
3425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          }.wrap(this));
3435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.castMedia_.removeUpdateListener(this.onCastMediaUpdatedBound_);
3455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.castMedia_ = null;
3465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
3471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    clearInterval(this.updateTimerId_);
3495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
3505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
3525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * Sends the message to cast.
3535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @param {Object} message Message to be sent (Must be JSON-able object).
3545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @private
3555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
3565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  sendMessage_: function(message) {
3575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.castSession_.sendMessage(CAST_MESSAGE_NAMESPACE, message);
3585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
3595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
3615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * Invoked when receiving a message from the cast.
3625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @param {string} namespace Namespace of the message.
3635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @param {string} messageAsJson Content of message as json format.
3645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @private
3655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
3665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  onMessage_: function(namespace, messageAsJson) {
3675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (namespace !== CAST_MESSAGE_NAMESPACE || !messageAsJson)
3685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return;
3695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    var message = JSON.parse(messageAsJson);
3715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (message['message'] === 'request-token') {
3725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (message['previousToken'] === this.token_) {
3731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        this.mediaManager_.getToken(true).then(function(token) {
3741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          this.token_ = token;
3751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          this.sendMessage_({message: 'push-token', token: token});
3761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          // TODO(yoshiki): Revokes the previous token.
3771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        }.bind(this)).catch(function(error) {
3781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          // Send an empty token as an error.
3791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          this.sendMessage_({message: 'push-token', token: ''});
3801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          // TODO(yoshiki): Revokes the previous token.
3811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          console.error(error.stack || error);
3821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        });
3835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      } else {
3845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        console.error(
3855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            'New token is requested, but the previous token mismatches.');
3865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
3871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    } else if (message['message'] === 'playback-error') {
3881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if (message['detail'] === 'src-not-supported')
3891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        this.errorCode_ = MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED;
3905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
3915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
3925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
3945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * This method is called periodically to update media information while the
3955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * media is loaded.
3965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @private
3975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
3985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  onPeriodicalUpdateTimer_: function() {
3995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (!this.castMedia_)
4005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return;
4015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (this.castMedia_.playerState === chrome.cast.media.PlayerState.PLAYING)
4035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.onCastMediaUpdated_(true);
4045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
4055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
4075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * This method should be called when a media file is loaded.
4085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @param {chrome.cast.Media} media Media object which was discovered.
4095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @private
4105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
4115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  onMediaDiscovered_: function(media) {
4125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (this.castMedia_ !== null) {
4135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.unloadMedia_();
4145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      console.info('New media is found and the old media is overridden.');
4155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
4165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.castMedia_ = media;
4185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.onCastMediaUpdated_(true);
4195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // Notify that the metadata of the video is ready.
4205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.dispatchEvent(new Event('loadedmetadata'));
4215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    media.addUpdateListener(this.onCastMediaUpdatedBound_);
4235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.updateTimerId_ = setInterval(this.onPeriodicalUpdateTimer_.bind(this),
4245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                      MEDIA_UPDATE_INTERVAL);
4255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
4265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
4285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * This method should be called when a media command to cast is failed.
4295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @param {Object} error Object representing the error.
4305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @private
4315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
4325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  onCastCommandError_: function(error) {
4335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.unloadMedia_();
4345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.dispatchEvent(new Event('error'));
4355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    console.error('Error on sending command to cast.', error.stack || error);
4365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
4375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
4395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * This is called when any media data is updated and by the periodical timer
4405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * is fired.
4415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   *
4425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @param {boolean} alive Media availability. False if it's unavailable.
4435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @private
4445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
4455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  onCastMediaUpdated_: function(alive) {
4465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (!this.castMedia_)
4475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return;
4485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    var media = this.castMedia_;
4501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (this.loop_ &&
4511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        media.idleReason === chrome.cast.media.IdleReason.FINISHED &&
4521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        !alive) {
4531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      // Resets the previous media silently.
4541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      this.castMedia_ = null;
4551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      // Replay the current media.
4571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      this.currentMediaPlayerState_ = chrome.cast.media.PlayerState.BUFFERING;
4581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      this.currentMediaCurrentTime_ = 0;
4591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      this.dispatchEvent(new Event('play'));
4601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      this.dispatchEvent(new Event('timeupdate'));
4611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      this.play();
4621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return;
4631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
4641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (this.currentMediaPlayerState_ !== media.playerState) {
4665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      var oldPlayState = false;
4675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      var oldState = this.currentMediaPlayerState_;
4685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (oldState === chrome.cast.media.PlayerState.BUFFERING ||
4695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          oldState === chrome.cast.media.PlayerState.PLAYING) {
4705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        oldPlayState = true;
4715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
4725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      var newPlayState = false;
4735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      var newState = media.playerState;
4745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (newState === chrome.cast.media.PlayerState.BUFFERING ||
4755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          newState === chrome.cast.media.PlayerState.PLAYING) {
4765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        newPlayState = true;
4775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
4785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (!oldPlayState && newPlayState)
4795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        this.dispatchEvent(new Event('play'));
4805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (oldPlayState && !newPlayState)
4815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        this.dispatchEvent(new Event('pause'));
4825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.currentMediaPlayerState_ = newState;
4845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
4855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (this.currentMediaCurrentTime_ !== media.getEstimatedTime()) {
4865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.currentMediaCurrentTime_ = media.getEstimatedTime();
4875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.dispatchEvent(new Event('timeupdate'));
4885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
4895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (this.currentMediaDuration_ !== media.media.duration) {
4915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.currentMediaDuration_ = media.media.duration;
4925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.dispatchEvent(new Event('durationchange'));
4935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
4945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // Media is being unloaded.
4965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (!alive) {
4975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.unloadMedia_();
4985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return;
4995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
5005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  },
5015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)};
502