You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
296 lines
6.6 KiB
296 lines
6.6 KiB
4 weeks ago
|
/**
|
||
|
* Copyright(c) ali-sdk and other contributors.
|
||
|
* MIT Licensed
|
||
|
*
|
||
|
* Authors:
|
||
|
* rockuw <rockuw@gmail.com> (http://rockuw.com)
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* Module dependencies.
|
||
|
*/
|
||
|
|
||
|
const jstoxml = require('jstoxml');
|
||
|
const utility = require('utility');
|
||
|
const copy = require('copy-to');
|
||
|
const urlutil = require('url');
|
||
|
|
||
|
const proto = exports;
|
||
|
|
||
|
/**
|
||
|
* RTMP operations
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* Create a live channel
|
||
|
* @param {String} id the channel id
|
||
|
* @param {Object} conf the channel configuration
|
||
|
* @param {Object} options
|
||
|
* @return {Object}
|
||
|
*/
|
||
|
proto.putChannel = async function putChannel(id, conf, options) {
|
||
|
options = options || {};
|
||
|
options.subres = 'live';
|
||
|
|
||
|
const params = this._objectRequestParams('PUT', id, options);
|
||
|
params.xmlResponse = true;
|
||
|
params.content = jstoxml.toXML({
|
||
|
LiveChannelConfiguration: conf
|
||
|
});
|
||
|
params.successStatuses = [200];
|
||
|
|
||
|
const result = await this.request(params);
|
||
|
|
||
|
let publishUrls = result.data.PublishUrls.Url;
|
||
|
if (!Array.isArray(publishUrls)) {
|
||
|
publishUrls = [publishUrls];
|
||
|
}
|
||
|
let playUrls = result.data.PlayUrls.Url;
|
||
|
if (!Array.isArray(playUrls)) {
|
||
|
playUrls = [playUrls];
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
publishUrls,
|
||
|
playUrls,
|
||
|
res: result.res
|
||
|
};
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Get the channel info
|
||
|
* @param {String} id the channel id
|
||
|
* @param {Object} options
|
||
|
* @return {Object}
|
||
|
*/
|
||
|
proto.getChannel = async function getChannel(id, options) {
|
||
|
options = options || {};
|
||
|
options.subres = 'live';
|
||
|
|
||
|
const params = this._objectRequestParams('GET', id, options);
|
||
|
params.xmlResponse = true;
|
||
|
params.successStatuses = [200];
|
||
|
|
||
|
const result = await this.request(params);
|
||
|
|
||
|
return {
|
||
|
data: result.data,
|
||
|
res: result.res
|
||
|
};
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Delete the channel
|
||
|
* @param {String} id the channel id
|
||
|
* @param {Object} options
|
||
|
* @return {Object}
|
||
|
*/
|
||
|
proto.deleteChannel = async function deleteChannel(id, options) {
|
||
|
options = options || {};
|
||
|
options.subres = 'live';
|
||
|
|
||
|
const params = this._objectRequestParams('DELETE', id, options);
|
||
|
params.successStatuses = [204];
|
||
|
|
||
|
const result = await this.request(params);
|
||
|
|
||
|
return {
|
||
|
res: result.res
|
||
|
};
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Set the channel status
|
||
|
* @param {String} id the channel id
|
||
|
* @param {String} status the channel status
|
||
|
* @param {Object} options
|
||
|
* @return {Object}
|
||
|
*/
|
||
|
proto.putChannelStatus = async function putChannelStatus(id, status, options) {
|
||
|
options = options || {};
|
||
|
options.subres = {
|
||
|
live: null,
|
||
|
status
|
||
|
};
|
||
|
|
||
|
const params = this._objectRequestParams('PUT', id, options);
|
||
|
params.successStatuses = [200];
|
||
|
|
||
|
const result = await this.request(params);
|
||
|
|
||
|
return {
|
||
|
res: result.res
|
||
|
};
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Get the channel status
|
||
|
* @param {String} id the channel id
|
||
|
* @param {Object} options
|
||
|
* @return {Object}
|
||
|
*/
|
||
|
proto.getChannelStatus = async function getChannelStatus(id, options) {
|
||
|
options = options || {};
|
||
|
options.subres = {
|
||
|
live: null,
|
||
|
comp: 'stat'
|
||
|
};
|
||
|
|
||
|
const params = this._objectRequestParams('GET', id, options);
|
||
|
params.xmlResponse = true;
|
||
|
params.successStatuses = [200];
|
||
|
|
||
|
const result = await this.request(params);
|
||
|
|
||
|
return {
|
||
|
data: result.data,
|
||
|
res: result.res
|
||
|
};
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* List the channels
|
||
|
* @param {Object} query the query parameters
|
||
|
* filter options:
|
||
|
* - prefix {String}: the channel id prefix (returns channels with this prefix)
|
||
|
* - marker {String}: the channle id marker (returns channels after this id)
|
||
|
* - max-keys {Number}: max number of channels to return
|
||
|
* @param {Object} options
|
||
|
* @return {Object}
|
||
|
*/
|
||
|
proto.listChannels = async function listChannels(query, options) {
|
||
|
// prefix, marker, max-keys
|
||
|
|
||
|
options = options || {};
|
||
|
options.subres = 'live';
|
||
|
|
||
|
const params = this._objectRequestParams('GET', '', options);
|
||
|
params.query = query;
|
||
|
params.xmlResponse = true;
|
||
|
params.successStatuses = [200];
|
||
|
|
||
|
const result = await this.request(params);
|
||
|
|
||
|
let channels = result.data.LiveChannel || [];
|
||
|
if (!Array.isArray(channels)) {
|
||
|
channels = [channels];
|
||
|
}
|
||
|
|
||
|
channels = channels.map(x => {
|
||
|
x.PublishUrls = x.PublishUrls.Url;
|
||
|
if (!Array.isArray(x.PublishUrls)) {
|
||
|
x.PublishUrls = [x.PublishUrls];
|
||
|
}
|
||
|
x.PlayUrls = x.PlayUrls.Url;
|
||
|
if (!Array.isArray(x.PlayUrls)) {
|
||
|
x.PlayUrls = [x.PlayUrls];
|
||
|
}
|
||
|
|
||
|
return x;
|
||
|
});
|
||
|
|
||
|
return {
|
||
|
channels,
|
||
|
nextMarker: result.data.NextMarker || null,
|
||
|
isTruncated: result.data.IsTruncated === 'true',
|
||
|
res: result.res
|
||
|
};
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Get the channel history
|
||
|
* @param {String} id the channel id
|
||
|
* @param {Object} options
|
||
|
* @return {Object}
|
||
|
*/
|
||
|
proto.getChannelHistory = async function getChannelHistory(id, options) {
|
||
|
options = options || {};
|
||
|
options.subres = {
|
||
|
live: null,
|
||
|
comp: 'history'
|
||
|
};
|
||
|
|
||
|
const params = this._objectRequestParams('GET', id, options);
|
||
|
params.xmlResponse = true;
|
||
|
params.successStatuses = [200];
|
||
|
|
||
|
const result = await this.request(params);
|
||
|
|
||
|
let records = result.data.LiveRecord || [];
|
||
|
if (!Array.isArray(records)) {
|
||
|
records = [records];
|
||
|
}
|
||
|
return {
|
||
|
records,
|
||
|
res: result.res
|
||
|
};
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Create vod playlist
|
||
|
* @param {String} id the channel id
|
||
|
* @param {String} name the playlist name
|
||
|
* @param {Object} time the begin and end time
|
||
|
* time:
|
||
|
* - startTime {Number}: the begin time in epoch seconds
|
||
|
* - endTime {Number}: the end time in epoch seconds
|
||
|
* @param {Object} options
|
||
|
* @return {Object}
|
||
|
*/
|
||
|
proto.createVod = async function createVod(id, name, time, options) {
|
||
|
options = options || {};
|
||
|
options.subres = {
|
||
|
vod: null
|
||
|
};
|
||
|
copy(time).to(options.subres);
|
||
|
|
||
|
const params = this._objectRequestParams('POST', `${id}/${name}`, options);
|
||
|
params.query = time;
|
||
|
params.successStatuses = [200];
|
||
|
|
||
|
const result = await this.request(params);
|
||
|
|
||
|
return {
|
||
|
res: result.res
|
||
|
};
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Get RTMP Url
|
||
|
* @param {String} channelId the channel id
|
||
|
* @param {Object} options
|
||
|
* options:
|
||
|
* - expires {Number}: expire time in seconds
|
||
|
* - params {Object}: the parameters such as 'playlistName'
|
||
|
* @return {String} the RTMP url
|
||
|
*/
|
||
|
proto.getRtmpUrl = function (channelId, options) {
|
||
|
options = options || {};
|
||
|
const expires = utility.timestamp() + (options.expires || 1800);
|
||
|
const res = {
|
||
|
bucket: this.options.bucket,
|
||
|
object: this._objectName(`live/${channelId}`)
|
||
|
};
|
||
|
const resource = `/${res.bucket}/${channelId}`;
|
||
|
|
||
|
options.params = options.params || {};
|
||
|
const query = Object.keys(options.params)
|
||
|
.sort()
|
||
|
.map(x => `${x}:${options.params[x]}\n`)
|
||
|
.join('');
|
||
|
|
||
|
const stringToSign = `${expires}\n${query}${resource}`;
|
||
|
const signature = this.signature(stringToSign);
|
||
|
|
||
|
const url = urlutil.parse(this._getReqUrl(res));
|
||
|
url.protocol = 'rtmp:';
|
||
|
url.query = {
|
||
|
OSSAccessKeyId: this.options.accessKeyId,
|
||
|
Expires: expires,
|
||
|
Signature: signature
|
||
|
};
|
||
|
copy(options.params).to(url.query);
|
||
|
|
||
|
return url.format();
|
||
|
};
|