305 lines
9.7 KiB
JavaScript
305 lines
9.7 KiB
JavaScript
"use strict";
|
|
|
|
var Uint64 = require("../wType/uint64");
|
|
var Address = require("../wType/address");
|
|
|
|
var Controller = require("./controller");
|
|
var Button = require("./button");
|
|
var ImageById = require("./imageById");
|
|
var Vocabulary = require("./vocabulary");
|
|
var Audio = require("./file/audio");
|
|
|
|
var Enum = require("../utils/enum");
|
|
var StateMachine = require("../utils/stateMachine");
|
|
|
|
var Source = AV.EventEmitter.extend(function() {
|
|
this.prototype.start = function(){}
|
|
this.prototype.pause = function(){}
|
|
this.prototype.reset = function(){}
|
|
});
|
|
|
|
var Player = Controller.inherit({
|
|
className: "Player",
|
|
constructor: function(addr) {
|
|
Controller.fn.constructor.call(this, addr);
|
|
|
|
this.controls = Object.create(null);
|
|
this.views = Object.create(null);
|
|
this.mode = PlayerMode.straight.playback;
|
|
this._audio = null;
|
|
this._source = new Source();
|
|
this._asset = new AV.Asset(this._source);
|
|
this._player = new AV.Player(this._asset);
|
|
this._player.play();
|
|
this._createStateMachine();
|
|
|
|
this.addHandler("get");
|
|
this.addHandler("viewsChange");
|
|
this.addHandler("play");
|
|
this.addHandler("pause");
|
|
},
|
|
destructor: function() {
|
|
this._fsm.destructor();
|
|
this._player.stop();
|
|
|
|
Controller.fn.destructor.call(this);
|
|
},
|
|
_addControl: function(type, address) {
|
|
var t = type.valueOf();
|
|
|
|
if (this.controls[t] !== undefined) {
|
|
throw new Error("An attempt to add multiple instances of " + ItemType.reversed[t] + " into Player");
|
|
}
|
|
|
|
if (ItemType.reversed[t] !== undefined) {
|
|
switch (t) {
|
|
case ItemType.straight.playPause:
|
|
var btn = new Button(address.clone());
|
|
btn.itemType = t;
|
|
this.controls[t] = btn;
|
|
this.addController(btn);
|
|
this.trigger("newElement", btn, t);
|
|
break;
|
|
default:
|
|
this.trigger("serviceMessage", "An attempt to add ItemType " + ItemType.reversed[t] + " to controls of the Player, but it's not qualified to be a control");
|
|
}
|
|
} else {
|
|
this.trigger("serviceMessage", "An unrecgnized item ItemType in Player: " + t);
|
|
}
|
|
},
|
|
_addView: function(type, address) {
|
|
var t = type.valueOf();
|
|
var ctrl;
|
|
var supported = false;
|
|
|
|
if (this.views[t] !== undefined) {
|
|
throw new Error("An attempt to add multiple instances of " + ItemType.reversed[t] + " into Player");
|
|
}
|
|
|
|
if (ItemType.reversed[t] !== undefined) {
|
|
switch (t) {
|
|
case ItemType.straight.queue:
|
|
this.trigger("serviceMessage", "Queue is not supported yet in Player");
|
|
break;
|
|
case ItemType.straight.currentPlayback:
|
|
ctrl = new Vocabulary(address.clone());
|
|
ctrl.on("newElement", this._onNewPlayBackElement, this);
|
|
ctrl.on("removeElement", this._onNewRemoveBackElement, this);
|
|
supported = true;
|
|
break;
|
|
case ItemType.straight.picture:
|
|
ctrl = new ImageById(null, address.back());
|
|
ctrl.ItemType = t;
|
|
this.views[t] = ctrl;
|
|
|
|
this.trigger("newElement", ctrl, t);
|
|
supported = false; //just to avoid adding with addController, since ImageById is not a controller
|
|
break;
|
|
default:
|
|
this.trigger("serviceMessage", "An attempt to add ItemType " + ItemType.reversed[t] + " to views of the Player, but it's not qualified to be a view");
|
|
}
|
|
} else {
|
|
this.trigger("serviceMessage", "An unrecgnized item ItemType in Player: " + t);
|
|
}
|
|
|
|
if (supported) {
|
|
ctrl.ItemType = t;
|
|
this.views[t] = ctrl;
|
|
this.addController(ctrl);
|
|
|
|
this.trigger("newElement", ctrl, t);
|
|
}
|
|
},
|
|
_createStateMachine: function() {
|
|
this._fsm = new StateMachine("initial", graphs[this.mode]);
|
|
this._fsm.on("stateChanged", this._onStateChanged, this);
|
|
},
|
|
_h_get: function(ev) {
|
|
var data = ev.getData();
|
|
|
|
var controls = data.at("controls");
|
|
var views = data.at("views");
|
|
var mode = data.at("mode").valueOf();
|
|
var size, i, vc;
|
|
|
|
size = controls.length();
|
|
for (i = 0; i < size; ++i) {
|
|
vc = controls.at(i);
|
|
this._addControl(vc.at("type"), vc.at("address"));
|
|
}
|
|
|
|
size = views.length();
|
|
for (i = 0; i < size; ++i) {
|
|
vc = views.at(i);
|
|
this._addView(vc.at("type"), vc.at("address"));
|
|
}
|
|
|
|
if (this.mode !== mode) {
|
|
if (PlayerMode.reversed[mode] === undefined) {
|
|
throw new Error("Unsupported mode of player: " + mode);
|
|
}
|
|
this.mode = mode;
|
|
}
|
|
|
|
this.initialized = true;
|
|
this.trigger("data");
|
|
},
|
|
_h_pause: function(ev) {
|
|
this._fsm.manipulation("pause");
|
|
},
|
|
_h_play: function(ev) {
|
|
this._fsm.manipulation("play");
|
|
},
|
|
_h_viewsChange: function(ev) {
|
|
var data = ev.getData();
|
|
|
|
var add = data.at("add");
|
|
var remove = data.at("remove");
|
|
var size, i, vc;
|
|
|
|
size = remove.length();
|
|
for (i = 0; i < size; ++i) {
|
|
this._removeView(remove.at(i));
|
|
}
|
|
|
|
size = add.length();
|
|
for (i = 0; i < size; ++i) {
|
|
vc = add.at(i);
|
|
this._addView(vc.at("type"), vc.at("address"));
|
|
}
|
|
},
|
|
_onAudioNewFrames: function(frames) {
|
|
var data = new Uint8Array(frames);
|
|
this._source.emit("data", new AV.Buffer(data));
|
|
|
|
this._fsm.manipulation("newFrames");
|
|
if (this._audio.hasMore()) {
|
|
this._audio.requestMore();
|
|
} else {
|
|
this._fsm.manipulation("noMoreFrames");
|
|
}
|
|
},
|
|
_onNewPlayBackElement: function(key, element) {
|
|
switch (key) {
|
|
case "image":
|
|
var address = new Address(["images", element.toString()]);
|
|
this._addView(new Uint64(ItemType.straight.picture), address);
|
|
address.destructor();
|
|
break;
|
|
case "audio":
|
|
if (this.mode === PlayerMode.straight.playback) {
|
|
this._audio = new Audio(new Address(["music", element.toString()]));
|
|
this.addForeignController("Corax", this._audio);
|
|
this._audio.on("newFrames", this._onAudioNewFrames, this);
|
|
this._fsm.manipulation("controller");
|
|
}
|
|
break;
|
|
}
|
|
},
|
|
_onNewRemoveBackElement: function(key) {
|
|
switch (key) {
|
|
case "image":
|
|
this._removeView(new Uint64(ItemType.straight.picture));
|
|
break;
|
|
case "audio":
|
|
this.removeForeignController(this._audio);
|
|
this._audio.destructor();
|
|
this._audio = null;
|
|
}
|
|
},
|
|
_onStateChanged: function(e) {
|
|
switch (e.newState) {
|
|
case "initial":
|
|
break;
|
|
case "initialPlaying":
|
|
break;
|
|
case "hasController":
|
|
break;
|
|
case "hasControllerPlaying":
|
|
if (this._audio.hasMore()) {
|
|
this._audio.requestMore();
|
|
} else {
|
|
this._fsm.manipulation("noMoreFrames");
|
|
}
|
|
break;
|
|
case "paused":
|
|
switch (e.oldState) {
|
|
case "playing":
|
|
this._player.pause();
|
|
break;
|
|
}
|
|
break;
|
|
case "pausedAllLoaded":
|
|
switch (e.oldState) {
|
|
case "playingAllLoaded":
|
|
this._player.pause();
|
|
break;
|
|
}
|
|
break;
|
|
case "playing":
|
|
this._player.play();
|
|
break;
|
|
case "playingAllLoaded":
|
|
switch (e.oldState) {
|
|
case "pausedAllLoaded":
|
|
this._player.play();
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
},
|
|
_removeControl: function(type) {
|
|
//TODO
|
|
},
|
|
_removeView: function(type) {
|
|
//TODO
|
|
}
|
|
});
|
|
|
|
var ItemType = new Enum("ItemType");
|
|
ItemType.add("playPause");
|
|
ItemType.add("currentPlayback");
|
|
ItemType.add("queue");
|
|
ItemType.add("picture");
|
|
|
|
var PlayerMode = new Enum("PlayerMode");
|
|
PlayerMode.add("playback");
|
|
|
|
Player.ItemType = ItemType;
|
|
|
|
var graphs = Object.create(null);
|
|
graphs[PlayerMode.straight.playback] = {
|
|
"initial": {
|
|
controller: "hasController",
|
|
play: "initialPlaying"
|
|
},
|
|
"initialPlaying": {
|
|
pause: "initial",
|
|
controller: "hasControllerPlaying"
|
|
},
|
|
"hasController": {
|
|
newFrames: "paused",
|
|
play: "hasControllerPlaying"
|
|
},
|
|
"hasControllerPlaying": {
|
|
newFrames: "playing",
|
|
pause: "hasController"
|
|
},
|
|
"paused": {
|
|
play: "playing",
|
|
noMoreFrames: "pausedAllLoaded"
|
|
},
|
|
"pausedAllLoaded": {
|
|
play: "playingAllLoaded"
|
|
},
|
|
"playing": {
|
|
pause: "paused",
|
|
noMoreFrames: "playingAllLoaded"
|
|
},
|
|
"playingAllLoaded": {
|
|
pause: "pausedAllLoaded"
|
|
}
|
|
}
|
|
|
|
module.exports = Player;
|