rtmp.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. /**
  2. * Copyright(c) ali-sdk and other contributors.
  3. * MIT Licensed
  4. *
  5. * Authors:
  6. * rockuw <rockuw@gmail.com> (http://rockuw.com)
  7. */
  8. /**
  9. * Module dependencies.
  10. */
  11. const jstoxml = require('jstoxml');
  12. const utility = require('utility');
  13. const copy = require('copy-to');
  14. const urlutil = require('url');
  15. const proto = exports;
  16. /**
  17. * RTMP operations
  18. */
  19. /**
  20. * Create a live channel
  21. * @param {String} id the channel id
  22. * @param {Object} conf the channel configuration
  23. * @param {Object} options
  24. * @return {Object}
  25. */
  26. proto.putChannel = async function putChannel(id, conf, options) {
  27. options = options || {};
  28. options.subres = 'live';
  29. const params = this._objectRequestParams('PUT', id, options);
  30. params.xmlResponse = true;
  31. params.content = jstoxml.toXML({
  32. LiveChannelConfiguration: conf
  33. });
  34. params.successStatuses = [200];
  35. const result = await this.request(params);
  36. let publishUrls = result.data.PublishUrls.Url;
  37. if (!Array.isArray(publishUrls)) {
  38. publishUrls = [publishUrls];
  39. }
  40. let playUrls = result.data.PlayUrls.Url;
  41. if (!Array.isArray(playUrls)) {
  42. playUrls = [playUrls];
  43. }
  44. return {
  45. publishUrls,
  46. playUrls,
  47. res: result.res
  48. };
  49. };
  50. /**
  51. * Get the channel info
  52. * @param {String} id the channel id
  53. * @param {Object} options
  54. * @return {Object}
  55. */
  56. proto.getChannel = async function getChannel(id, options) {
  57. options = options || {};
  58. options.subres = 'live';
  59. const params = this._objectRequestParams('GET', id, options);
  60. params.xmlResponse = true;
  61. params.successStatuses = [200];
  62. const result = await this.request(params);
  63. return {
  64. data: result.data,
  65. res: result.res
  66. };
  67. };
  68. /**
  69. * Delete the channel
  70. * @param {String} id the channel id
  71. * @param {Object} options
  72. * @return {Object}
  73. */
  74. proto.deleteChannel = async function deleteChannel(id, options) {
  75. options = options || {};
  76. options.subres = 'live';
  77. const params = this._objectRequestParams('DELETE', id, options);
  78. params.successStatuses = [204];
  79. const result = await this.request(params);
  80. return {
  81. res: result.res
  82. };
  83. };
  84. /**
  85. * Set the channel status
  86. * @param {String} id the channel id
  87. * @param {String} status the channel status
  88. * @param {Object} options
  89. * @return {Object}
  90. */
  91. proto.putChannelStatus = async function putChannelStatus(id, status, options) {
  92. options = options || {};
  93. options.subres = {
  94. live: null,
  95. status
  96. };
  97. const params = this._objectRequestParams('PUT', id, options);
  98. params.successStatuses = [200];
  99. const result = await this.request(params);
  100. return {
  101. res: result.res
  102. };
  103. };
  104. /**
  105. * Get the channel status
  106. * @param {String} id the channel id
  107. * @param {Object} options
  108. * @return {Object}
  109. */
  110. proto.getChannelStatus = async function getChannelStatus(id, options) {
  111. options = options || {};
  112. options.subres = {
  113. live: null,
  114. comp: 'stat'
  115. };
  116. const params = this._objectRequestParams('GET', id, options);
  117. params.xmlResponse = true;
  118. params.successStatuses = [200];
  119. const result = await this.request(params);
  120. return {
  121. data: result.data,
  122. res: result.res
  123. };
  124. };
  125. /**
  126. * List the channels
  127. * @param {Object} query the query parameters
  128. * filter options:
  129. * - prefix {String}: the channel id prefix (returns channels with this prefix)
  130. * - marker {String}: the channle id marker (returns channels after this id)
  131. * - max-keys {Number}: max number of channels to return
  132. * @param {Object} options
  133. * @return {Object}
  134. */
  135. proto.listChannels = async function listChannels(query, options) {
  136. // prefix, marker, max-keys
  137. options = options || {};
  138. options.subres = 'live';
  139. const params = this._objectRequestParams('GET', '', options);
  140. params.query = query;
  141. params.xmlResponse = true;
  142. params.successStatuses = [200];
  143. const result = await this.request(params);
  144. let channels = result.data.LiveChannel || [];
  145. if (!Array.isArray(channels)) {
  146. channels = [channels];
  147. }
  148. channels = channels.map((x) => {
  149. x.PublishUrls = x.PublishUrls.Url;
  150. if (!Array.isArray(x.PublishUrls)) {
  151. x.PublishUrls = [x.PublishUrls];
  152. }
  153. x.PlayUrls = x.PlayUrls.Url;
  154. if (!Array.isArray(x.PlayUrls)) {
  155. x.PlayUrls = [x.PlayUrls];
  156. }
  157. return x;
  158. });
  159. return {
  160. channels,
  161. nextMarker: result.data.NextMarker || null,
  162. isTruncated: result.data.IsTruncated === 'true',
  163. res: result.res
  164. };
  165. };
  166. /**
  167. * Get the channel history
  168. * @param {String} id the channel id
  169. * @param {Object} options
  170. * @return {Object}
  171. */
  172. proto.getChannelHistory = async function getChannelHistory(id, options) {
  173. options = options || {};
  174. options.subres = {
  175. live: null,
  176. comp: 'history'
  177. };
  178. const params = this._objectRequestParams('GET', id, options);
  179. params.xmlResponse = true;
  180. params.successStatuses = [200];
  181. const result = await this.request(params);
  182. let records = result.data.LiveRecord || [];
  183. if (!Array.isArray(records)) {
  184. records = [records];
  185. }
  186. return {
  187. records,
  188. res: result.res
  189. };
  190. };
  191. /**
  192. * Create vod playlist
  193. * @param {String} id the channel id
  194. * @param {String} name the playlist name
  195. * @param {Object} time the begin and end time
  196. * time:
  197. * - startTime {Number}: the begin time in epoch seconds
  198. * - endTime {Number}: the end time in epoch seconds
  199. * @param {Object} options
  200. * @return {Object}
  201. */
  202. proto.createVod = async function createVod(id, name, time, options) {
  203. options = options || {};
  204. options.subres = {
  205. vod: null
  206. };
  207. copy(time).to(options.subres);
  208. const params = this._objectRequestParams('POST', `${id}/${name}`, options);
  209. params.query = time;
  210. params.successStatuses = [200];
  211. const result = await this.request(params);
  212. return {
  213. res: result.res
  214. };
  215. };
  216. /**
  217. * Get RTMP Url
  218. * @param {String} channelId the channel id
  219. * @param {Object} options
  220. * options:
  221. * - expires {Number}: expire time in seconds
  222. * - params {Object}: the parameters such as 'playlistName'
  223. * @return {String} the RTMP url
  224. */
  225. proto.getRtmpUrl = function (channelId, options) {
  226. options = options || {};
  227. const expires = utility.timestamp() + (options.expires || 1800);
  228. const res = {
  229. bucket: this.options.bucket,
  230. object: this._objectName(`live/${channelId}`)
  231. };
  232. const resource = `/${res.bucket}/${channelId}`;
  233. options.params = options.params || {};
  234. const query = Object.keys(options.params).sort().map(x => `${x}:${options.params[x]}\n`).join('');
  235. const stringToSign = `${expires}\n${query}${resource}`;
  236. const signature = this.signature(stringToSign);
  237. const url = urlutil.parse(this._getReqUrl(res));
  238. url.protocol = 'rtmp:';
  239. url.query = {
  240. OSSAccessKeyId: this.options.accessKeyId,
  241. Expires: expires,
  242. Signature: signature
  243. };
  244. copy(options.params).to(url.query);
  245. return url.format();
  246. };