skyriver
Version:
SkyRiver Streaming Cloud server-side library for NodeJS
237 lines (197 loc) • 5.88 kB
JavaScript
'use strict';
var fmt = require('util')
, urlUtil = require('url')
, util = require('./util')
, API = require('./api')
, config = require('./config');
var ORIGIN = config.const.ORIGIN;
function Stream(credentials, params) {
this.host = config.API_HOST;
this.port = config.API_PORT;
this.credentials = credentials;
this.id = params.id;
this.createdAt = params.createdAt;
this.updatedAt = params.updatedAt;
this.title = params.title;
this.hub = params.hub || config.const.DEFAULT_HUB;
this.publishKey = params.publishKey;
this.record = params.record || 0;
this.publishSecurity = params.publishSecurity;
if (params.disabled) {
this.disabled = params.disabled;
} else {
this.disabled = false;
}
this.connect = params.connect || 0; // 推流状态
if (params.profiles == null || params.profiles == 'undefined') {
this.profiles = null;
} else {
this.profiles = params.profiles;
}
this.hosts = params.hosts;
}
/**
* Stream operations
*/
Stream.prototype.update = function(options, fn) {
API.updateStream(this.credentials, this.id, options, fn);
}
Stream.prototype.enable = function(fn) {
var options = {
disabled: false
};
API.updateStream(this.credentials, this.id, options, fn);
}
Stream.prototype.disable = function(fn) {
var options = {
disabled: true
};
API.updateStream(this.credentials, this.id, options, fn);
}
Stream.prototype.delete = function(fn) {
API.deleteStream(this.credentials, this.id, fn);
}
Stream.prototype.deleteRecord = function(key, fn) {
API.deleteRecord(this.credentials, this.id, key, fn);
}
Stream.prototype.startPull = function(pullUrl, notifyUrl, fn) {
var options = {
action: 'start',
pullUrl: pullUrl,
notifyUrl: notifyUrl
};
API.noftifyPullStream(this.credentials, this.id, options, fn);
}
Stream.prototype.stopPull = function(notifyUrl, fn) {
var options = {
action: 'stop',
notifyUrl: notifyUrl
};
API.noftifyPullStream(this.credentials, this.id, options, fn);
}
Stream.prototype.status = function(fn) {
API.getStreamStatus(this.credentials, this.id, fn);
}
/**
* 向服务请求实际播放地址
* @param fn
*/
Stream.prototype.getPlayUrl = function(fn) {
var playUrl = this.playUrl();
var hosts = fmt.format('%s:%s/v1', this.host, this.port);
var path = playUrl.replace(hosts, '');
API.getPlayURL(this.credentials, path, fn);
}
/**
* 向天河服务器重新请求推流服务器地址
* @param fn
*/
Stream.prototype.getPublishUrl = function(fn) {
API.getReceiver(this.credentials, this.id, fn);
}
/**
* 向服务请求实际点播地址
* @param fn
*/
Stream.prototype.getVodUrl = function(options, fn) {
var vodUrl = this.vodUrl(options);
var hosts = fmt.format('%s:%s/v1', this.host, this.port);
var path = vodUrl.replace(hosts, '');
API.getVodURL(this.credentials, path, fn);
}
Stream.prototype.segments = function(options, fn) {
API.getStreamSegments(this.credentials, this.id, options, fn);
}
Stream.prototype.records = function(fn) {
API.getRecords(this.credentials, this.id, fn);
}
Stream.prototype.snapshot = function(name, format, options, fn) {
API.snapshotStream(this.credentials, this.id, name, format, options, fn);
}
function replacer(key, value) {
if (key == 'credentials') {
return undefined;
} else if (key == 'play') {
return undefined;
} else {
return value;
}
}
Stream.prototype.toJSONString = function() {
return JSON.stringify(this, replacer);
}
Stream.prototype.saveAs = function(key, name, format, options, fn) {
API.saveStreamAs(this.credentials, this.id, key, name, format, options, fn);
}
/**
* URL generators
*/
Stream.prototype.publishServerUrl = function() {
return fmt.format('%s', this.hosts.playback);
};
Stream.prototype.rtmpPublishUrl = function() {
var url = '';
var rtmpPublishHost = this.hosts.publish;
switch (this.publishSecurity) {
case 'static':
url = this._staticUrl(rtmpPublishHost);
break;
case 'dynamic':
url = this._dynamicUrl(rtmpPublishHost);
break;
}
return url;
}
/**
* 生成请求播放地址接口
*/
Stream.prototype.playUrl = function() {
var pullUrl = fmt.format('%s:%s/v1/streams/%s/playurl', this.host, this.port, this.id);
return this._withToken(pullUrl);
}
/**
* 生成请求点播地址接口
*/
Stream.prototype.vodUrl = function(options) {
var vodUrl = fmt.format('%s:%s/v1/streams/%s/vodurl', this.host, this.port, this.id);
vodUrl = this._withToken(vodUrl);
if (options && options.name) {
vodUrl += '&name=' + options.name;
}
return vodUrl;
}
Stream.prototype._withToken = function(parmsUrl) {
var url = '';
switch (this.publishSecurity) {
case 'static':
url = fmt.format('%s?nonce=%d&token=%s', parmsUrl, this._nonceValue(), this.publishKey);
break;
case 'dynamic':
url = fmt.format('%s?nonce=%d&token=%s', parmsUrl, this._nonceValue(), this._token(parmsUrl));
break;
}
return url;
}
Stream.prototype._staticUrl = function(rtmpPublishHost) {
var url = fmt.format('rtmp://%s/live/%s?nonce=%d&token=%s', rtmpPublishHost, this.id, this._nonceValue(), this.publishKey);
return url;
}
Stream.prototype._dynamicUrl = function(rtmpPublishHost) {
this.nonce = 0;
var url = fmt.format('rtmp://%s/live/?nonce=%d&token=%s', rtmpPublishHost, this._nonceValue(), this._token(rtmpPublishHost));
return url;
}
Stream.prototype._nonceValue = function() {
if (!this.nonce) {
this.nonce = Date.now() / 1000 | 0;
}
return parseInt(this.nonce, 10);
}
Stream.prototype._token = function(rtmpPublishHost) {
var urlObject = urlUtil.parse(rtmpPublishHost);
var path = urlObject.path + '?nonce=' + this.nonce;
var digest = util.hmacSha1(path, this.publishKey);
var token = util.base64ToUrlSafe(digest);
return token;
}
module.exports = Stream;