Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

<script>
function init() {
window.player = new RadioKitToolkitPlayback.Channel.Player("fd9a7d1c-a387-40a0-b876-2799668d6f9d", "123");
window.player = new RadioKitToolkitPlayback.Channel.Player("3d49ef93-a010-4649-b3ed-b0f99fe96173", "123", {targets: ["da0db47f-a653-4df3-b167-12c3ba398818", "144ca21d-b10e-476e-8f19-aa12082542d7"]});
window.player.on('track-playback-started', function(track) {
document.getElementById('track-id').innerHTML = 'TRACK ID: ' + track.getId();

Expand Down
264 changes: 233 additions & 31 deletions dist/browser/radiokit-toolkit-playback.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/browser/radiokit-toolkit-playback.js.map

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions lib/Base.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Base = (function () {
function Base() {
this.__events = {};
Expand Down
16 changes: 11 additions & 5 deletions lib/audio/AudioManager.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
"use strict";
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var Factory_1 = require("./Factory");
var Base_1 = require("../Base");
var AudioManager = (function (_super) {
Expand Down
1 change: 1 addition & 0 deletions lib/audio/Factory.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var HTMLPlayer_1 = require("./HTMLPlayer");
var Factory = (function () {
function Factory() {
Expand Down
16 changes: 11 additions & 5 deletions lib/audio/HTMLPlayer.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
"use strict";
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var Base_1 = require("../Base");
var FADE_OUT_INTERVAL = 25;
var HTMLPlayer = (function (_super) {
Expand Down
1 change: 1 addition & 0 deletions lib/audio/IAudioPlayer.js
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
16 changes: 11 additions & 5 deletions lib/audio/StreamManager.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
"use strict";
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var Base_1 = require("../Base");
var StreamManager = (function (_super) {
__extends(StreamManager, _super);
Expand Down
88 changes: 82 additions & 6 deletions lib/channel/Player.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
"use strict";
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __assign = (this && this.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
Expand All @@ -12,34 +17,41 @@ var __assign = (this && this.__assign) || Object.assign || function(t) {
}
return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
var Base_1 = require("../Base");
var SyncClock_1 = require("../clock/SyncClock");
var PlaylistFetcher_1 = require("../channel/PlaylistFetcher");
var AudioManager_1 = require("../audio/AudioManager");
var StreamManager_1 = require("../audio/StreamManager");
var StatsSender_1 = require("../channel/StatsSender");
var Fingerprint2 = require("fingerprintjs2");
var Player = (function (_super) {
__extends(Player, _super);
function Player(channelId, accessToken, options) {
if (options === void 0) { options = {}; }
var _this = _super.call(this) || this;
_this.__fetchTimeoutId = 0;
_this.__statsTimeoutId = 0;
_this.__playbackStartedEmitted = false;
_this.__playlist = null;
_this.__clock = null;
_this.__fetching = false;
_this.__playlistFetcher = null;
_this.__statsSender = null;
_this.__volume = 1.0;
_this.__options = { from: 20, to: 600 };
_this.__options = { from: 20, to: 600, targets: [] };
_this.__options = __assign({}, _this.__options, options);
_this.__started = false;
_this.__channelId = channelId;
_this.__accessToken = accessToken;
_this.__generateUserFingerprint();
return _this;
}
Player.prototype.start = function () {
if (!this.__started) {
this.__startFetching();
this.__started = true;
this.__startSendingStats();
this.__playbackStartedEmitted = false;
if (this.__supportsAudioManager()) {
this.debug("Using AudioManager");
Expand All @@ -61,6 +73,7 @@ var Player = (function (_super) {
Player.prototype.stop = function () {
if (this.__started) {
this.__started = false;
this.__stopSendingStats();
if (this.__audioManager) {
this.__audioManager.offAll();
this.__audioManager.cleanup();
Expand Down Expand Up @@ -183,6 +196,63 @@ var Player = (function (_super) {
_this.__scheduleNextFetch();
});
};
Player.prototype.__stopSendingStats = function () {
if (this.__statsTimeoutId !== 0) {
clearTimeout(this.__statsTimeoutId);
this.__statsTimeoutId = 0;
this.__statsSender = null;
}
};
Player.prototype.__startSendingStats = function () {
if (!this.__statsSender) {
this.__statsSender = new StatsSender_1.StatsSender(this.__accessToken, this.__channelId, this.__userFingerprint, this.__options);
}
this.__sendStats();
};
Player.prototype.__sendStats = function () {
var _this = this;
var promise = new Promise(function (resolve, reject) {
_this.__sendStatsPromise(resolve, reject);
});
promise
.then(function (responseStatus) {
if (responseStatus === "OK") {
_this.debug("Stats sent successfully.");
}
else {
_this.debug("Unable to send stats. Response code: " + responseStatus);
}
_this.__scheduleNextSending();
})
.catch(function (error) {
_this.__scheduleNextSending();
});
};
Player.prototype.__scheduleNextSending = function () {
var _this = this;
if (this.__started) {
var timeout = 15000 + Math.round(Math.random() * 250);
this.debug("Stats Sender: Scheduling next send in " + timeout + " ms");
this.__statsTimeoutId = setTimeout(function () {
_this.__statsTimeoutId = 0;
_this.__sendStats();
}, timeout);
}
};
Player.prototype.__sendStatsPromise = function (resolve, reject) {
var _this = this;
this.debug("Start sending stats.");
this.__statsSender.sendAsync()
.then(function (requestResponse) {
_this.debug("Sending stats done.");
resolve(requestResponse);
})
.catch(function (error) {
_this.warn("Send stats error: Unable to send stats (" + error.message + ")");
_this._trigger('error-network');
reject(new Error("Unable to send stats (" + error.message + ")"));
});
};
Player.prototype.__scheduleNextFetch = function () {
var _this = this;
if (this.__fetching) {
Expand Down Expand Up @@ -213,6 +283,12 @@ var Player = (function (_super) {
this.__playbackStartedEmitted = true;
}
};
Player.prototype.__generateUserFingerprint = function () {
var _this = this;
new Fingerprint2().get(function (fingerprint) {
_this.__userFingerprint = fingerprint;
});
};
return Player;
}(Base_1.Base));
exports.Player = Player;
85 changes: 81 additions & 4 deletions lib/channel/Player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { Track } from '../channel/Track';
import { PlaylistFetcher } from '../channel/PlaylistFetcher';
import { AudioManager } from '../audio/AudioManager';
import { StreamManager } from '../audio/StreamManager';

import { StatsSender } from '../channel/StatsSender';
import * as Fingerprint2 from 'fingerprintjs2';

/**
* This class represents a single channel (stream) that is broadcasted from
Expand All @@ -23,6 +24,7 @@ export class Player extends Base {
private __channelId: string;
private __accessToken: string;
private __fetchTimeoutId: number = 0;
private __statsTimeoutId: number = 0;
private __audioManager: AudioManager;
private __streamManager: StreamManager;
private __playbackStartedEmitted: boolean = false;
Expand All @@ -31,8 +33,10 @@ export class Player extends Base {
private __clock?: SyncClock = null;
private __fetching: boolean = false;
private __playlistFetcher?: PlaylistFetcher = null;
private __statsSender?: StatsSender = null;
private __volume: number = 1.0;
private __options: any = { from: 20, to: 600 };
private __options: any = { from: 20, to: 600, targets: [] };
private __userFingerprint: string;


constructor(channelId: string, accessToken: string, options = {}) {
Expand All @@ -45,6 +49,7 @@ export class Player extends Base {
this.__started = false;
this.__channelId = channelId;
this.__accessToken = accessToken;
this.__generateUserFingerprint();
}


Expand All @@ -53,6 +58,8 @@ export class Player extends Base {
this.__startFetching();

this.__started = true;
this.__startSendingStats();

this.__playbackStartedEmitted = false;

if(this.__supportsAudioManager()) {
Expand All @@ -78,6 +85,7 @@ export class Player extends Base {
public stop() : Player {
if(this.__started) {
this.__started = false;
this.__stopSendingStats();

if(this.__audioManager) {
// Remove all event handlers to avoid memory leaks
Expand Down Expand Up @@ -250,6 +258,71 @@ export class Player extends Base {
}


private __stopSendingStats() : void {
if(this.__statsTimeoutId !== 0) {
clearTimeout(this.__statsTimeoutId);
this.__statsTimeoutId = 0;
this.__statsSender = null;
}
}

private __startSendingStats() : void {
if (!this.__statsSender) {
this.__statsSender = new StatsSender(
this.__accessToken,
this.__channelId,
this.__userFingerprint,
this.__options,
);
}

this.__sendStats();
}

private __sendStats() : void {
const promise = new Promise<string>((resolve: any, reject: any) => {
this.__sendStatsPromise(resolve, reject);
});

promise
.then((responseStatus) => {
if (responseStatus === "OK") {
this.debug(`Stats sent successfully.`);
} else {
this.debug(`Unable to send stats. Response code: ${responseStatus}`);
}
this.__scheduleNextSending();
})
.catch((error) => {
this.__scheduleNextSending();
});
}

private __scheduleNextSending() : void {
if(this.__started) {
const timeout = 15000 + Math.round(Math.random() * 250);
this.debug(`Stats Sender: Scheduling next send in ${timeout} ms`);
this.__statsTimeoutId = setTimeout(() => {
this.__statsTimeoutId = 0;
this.__sendStats();
}, timeout);
}
}

private __sendStatsPromise(resolve: any, reject: any) : void {
this.debug("Start sending stats.");
this.__statsSender.sendAsync()
.then((requestResponse) => {
this.debug("Sending stats done.");
resolve(requestResponse);
})
.catch((error) => {
this.warn(`Send stats error: Unable to send stats (${error.message})`);
this._trigger('error-network');
reject(new Error(`Unable to send stats (${error.message})`));
});
}

private __scheduleNextFetch() : void {
if(this.__fetching) {
const timeout = 2000 + Math.round(Math.random() * 250);
Expand All @@ -269,7 +342,6 @@ export class Player extends Base {
this._trigger('track-position', track, position, duration);
}


private __onAudioManagerPlaybackStarted(track: Track) : void {
if(!this.__playbackStartedEmitted) {
this._trigger('playback-started');
Expand All @@ -279,11 +351,16 @@ export class Player extends Base {
this._trigger('track-playback-started', track);
}


private __onStreamManagerPlaybackStarted() : void {
if(!this.__playbackStartedEmitted) {
this._trigger('playback-started');
this.__playbackStartedEmitted = true;
}
}

private __generateUserFingerprint() : void {
new Fingerprint2().get((fingerprint) => {
this.__userFingerprint = fingerprint;
});
}
}
1 change: 1 addition & 0 deletions lib/channel/Playlist.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Track_1 = require("./Track");
var Playlist = (function () {
function Playlist(tracks) {
Expand Down
Loading