No Description
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.

amf.js 26KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184
  1. /**
  2. * Created by delian on 3/12/14.
  3. * This module provides encoding and decoding of the AMF0 and AMF3 format
  4. */
  5. const Logger = require('./logger');
  6. const amf3dRules = {
  7. 0x00: amf3decUndefined,
  8. 0x01: amf3decNull,
  9. 0x02: amf3decFalse,
  10. 0x03: amf3decTrue,
  11. 0x04: amf3decInteger,
  12. 0x05: amf3decDouble,
  13. 0x06: amf3decString,
  14. 0x07: amf3decXmlDoc,
  15. 0x08: amf3decDate,
  16. 0x09: amf3decArray,
  17. 0x0A: amf3decObject,
  18. 0x0B: amf3decXml,
  19. 0x0C: amf3decByteArray //,
  20. // 0x0D: amf3decVecInt,
  21. // 0x0E: amf3decVecUInt,
  22. // 0x0F: amf3decVecDouble,
  23. // 0x10: amf3decVecObject,
  24. // 0x11: amf3decDict // No dictionary support for the moment!
  25. };
  26. const amf3eRules = {
  27. 'string': amf3encString,
  28. 'integer': amf3encInteger,
  29. 'double': amf3encDouble,
  30. 'xml': amf3encXmlDoc,
  31. 'object': amf3encObject,
  32. 'array': amf3encArray,
  33. 'sarray': amf3encArray,
  34. 'binary': amf3encByteArray,
  35. 'true': amf3encTrue,
  36. 'false': amf3encFalse,
  37. 'undefined': amf3encUndefined,
  38. 'null': amf3encNull
  39. };
  40. const amf0dRules = {
  41. 0x00: amf0decNumber,
  42. 0x01: amf0decBool,
  43. 0x02: amf0decString,
  44. 0x03: amf0decObject,
  45. // 0x04: amf0decMovie, // Reserved
  46. 0x05: amf0decNull,
  47. 0x06: amf0decUndefined,
  48. 0x07: amf0decRef,
  49. 0x08: amf0decArray,
  50. // 0x09: amf0decObjEnd, // Should never happen normally
  51. 0x0A: amf0decSArray,
  52. 0x0B: amf0decDate,
  53. 0x0C: amf0decLongString,
  54. // 0x0D: amf0decUnsupported, // Has been never originally implemented by Adobe!
  55. // 0x0E: amf0decRecSet, // Has been never originally implemented by Adobe!
  56. 0x0F: amf0decXmlDoc,
  57. 0x10: amf0decTypedObj,
  58. 0x11: amf0decSwitchAmf3
  59. };
  60. const amf0eRules = {
  61. 'string': amf0encString,
  62. 'integer': amf0encNumber,
  63. 'double': amf0encNumber,
  64. 'xml': amf0encXmlDoc,
  65. 'object': amf0encObject,
  66. 'array': amf0encArray,
  67. 'sarray': amf0encSArray,
  68. 'binary': amf0encString,
  69. 'true': amf0encBool,
  70. 'false': amf0encBool,
  71. 'undefined': amf0encUndefined,
  72. 'null': amf0encNull
  73. };
  74. function amfType(o) {
  75. let jsType = typeof o;
  76. if (o === null) return 'null';
  77. if (jsType == 'undefined') return 'undefined';
  78. if (jsType == 'number') {
  79. if (parseInt(o) == o) return 'integer';
  80. return 'double';
  81. }
  82. if (jsType == 'boolean') return o ? 'true' : 'false';
  83. if (jsType == 'string') return 'string';
  84. if (jsType == 'object') {
  85. if (o instanceof Array) {
  86. if (o.sarray) return 'sarray';
  87. return 'array';
  88. }
  89. return 'object';
  90. }
  91. throw new Error('Unsupported type!')
  92. }
  93. // AMF3 implementation
  94. /**
  95. * AMF3 Decode undefined value
  96. * @returns {{len: number, value: undefined}}
  97. */
  98. function amf3decUndefined() {
  99. return { len: 1, value: undefined }
  100. }
  101. /**
  102. * AMF3 Encode undefined value
  103. * @returns {Buffer}
  104. */
  105. function amf3encUndefined() {
  106. let buf = Buffer.alloc(1);
  107. buf.writeUInt8(0x00);
  108. return buf;
  109. }
  110. /**
  111. * AMF3 Decode null
  112. * @returns {{len: number, value: null}}
  113. */
  114. function amf3decNull() {
  115. return { len: 1, value: null }
  116. }
  117. /**
  118. * AMF3 Encode null
  119. * @returns {Buffer}
  120. */
  121. function amf3encNull() {
  122. let buf = Buffer.alloc(1);
  123. buf.writeUInt8(0x01);
  124. return buf;
  125. }
  126. /**
  127. * AMF3 Decode false
  128. * @returns {{len: number, value: boolean}}
  129. */
  130. function amf3decFalse() {
  131. return { len: 1, value: false }
  132. }
  133. /**
  134. * AMF3 Encode false
  135. * @returns {Buffer}
  136. */
  137. function amf3encFalse() {
  138. let buf = Buffer.alloc(1);
  139. buf.writeUInt8(0x02);
  140. return buf;
  141. }
  142. /**
  143. * AMF3 Decode true
  144. * @returns {{len: number, value: boolean}}
  145. */
  146. function amf3decTrue() {
  147. return { len: 1, value: true }
  148. }
  149. /**
  150. * AMF3 Encode true
  151. * @returns {Buffer}
  152. */
  153. function amf3encTrue() {
  154. let buf = Buffer.alloc(1);
  155. buf.writeUInt8(0x03);
  156. return buf;
  157. }
  158. /**
  159. * Generic decode of AMF3 UInt29 values
  160. * @param buf
  161. * @returns {{len: number, value: number}}
  162. */
  163. function amf3decUI29(buf) {
  164. let val = 0;
  165. let len = 1;
  166. let b;
  167. do {
  168. b = buf.readUInt8(len++);
  169. val = (val << 7) + (b & 0x7F);
  170. } while (len < 5 || b > 0x7F);
  171. if (len == 5) val = val | b; // Preserve the major bit of the last byte
  172. return { len: len, value: val }
  173. }
  174. /**
  175. * Generic encode of AMF3 UInt29 value
  176. * @param num
  177. * @returns {Buffer}
  178. */
  179. function amf3encUI29(num) {
  180. let len = 0;
  181. if (num < 0x80) len = 1;
  182. if (num < 0x4000) len = 2;
  183. if (num < 0x200000) len = 3;
  184. if (num >= 0x200000) len = 4;
  185. let buf = Buffer.alloc(len);
  186. switch (len) {
  187. case 1:
  188. buf.writeUInt8(num, 0);
  189. break;
  190. case 2:
  191. buf.writeUInt8(num & 0x7F, 0);
  192. buf.writeUInt8((num >> 7) | 0x80, 1);
  193. break;
  194. case 3:
  195. buf.writeUInt8(num & 0x7F, 0);
  196. buf.writeUInt8((num >> 7) & 0x7F, 1);
  197. buf.writeUInt8((num >> 14) | 0x80, 2);
  198. break;
  199. case 4:
  200. buf.writeUInt8(num & 0xFF, 0);
  201. buf.writeUInt8((num >> 8) & 0x7F, 1);
  202. buf.writeUInt8((num >> 15) | 0x7F, 2);
  203. buf.writeUInt8((num >> 22) | 0x7F, 3);
  204. break;
  205. }
  206. return buf;
  207. }
  208. /**
  209. * AMF3 Decode an integer
  210. * @param buf
  211. * @returns {{len: number, value: number}}
  212. */
  213. function amf3decInteger(buf) { // Invert the integer
  214. let resp = amf3decUI29(buf);
  215. if (resp.value > 0x0FFFFFFF) resp.value = (resp.value & 0x0FFFFFFF) - 0x10000000;
  216. return resp;
  217. }
  218. /**
  219. * AMF3 Encode an integer
  220. * @param num
  221. * @returns {Buffer}
  222. */
  223. function amf3encInteger(num) {
  224. let buf = Buffer.alloc(1);
  225. buf.writeUInt8(0x4, 0);
  226. return Buffer.concat([buf, amf3encUI29(num & 0x3FFFFFFF)]); // This AND will auto convert the sign bit!
  227. }
  228. /**
  229. * AMF3 Decode String
  230. * @param buf
  231. * @returns {{len: *, value: (*|String)}}
  232. */
  233. function amf3decString(buf) {
  234. let sLen = amf3decUI29(buf);
  235. let s = sLen & 1;
  236. sLen = sLen >> 1; // The real length without the lowest bit
  237. if (s) return { len: sLen.value + 5, value: buf.slice(5, sLen.value + 5).toString('utf8') };
  238. throw new Error("Error, we have a need to decode a String that is a Reference"); // TODO: Implement references!
  239. }
  240. /**
  241. * AMF3 Encode String
  242. * @param str
  243. * @returns {Buffer}
  244. */
  245. function amf3encString(str) {
  246. let sLen = amf3encUI29(str.length << 1);
  247. let buf = Buffer.alloc(1);
  248. buf.writeUInt8(0x6, 0);
  249. return Buffer.concat([buf, sLen, Buffer.from(str, 'utf8')]);
  250. }
  251. /**
  252. * AMF3 Decode XMLDoc
  253. * @param buf
  254. * @returns {{len: *, value: (*|String)}}
  255. */
  256. function amf3decXmlDoc(buf) {
  257. let sLen = amf3decUI29(buf);
  258. let s = sLen & 1;
  259. sLen = sLen >> 1; // The real length without the lowest bit
  260. if (s) return { len: sLen.value + 5, value: buf.slice(5, sLen.value + 5).toString('utf8') };
  261. throw new Error("Error, we have a need to decode a String that is a Reference"); // TODO: Implement references!
  262. }
  263. /**
  264. * AMF3 Encode XMLDoc
  265. * @param str
  266. * @returns {Buffer}
  267. */
  268. function amf3encXmlDoc(str) {
  269. let sLen = amf3encUI29(str.length << 1);
  270. let buf = Buffer.alloc(1);
  271. buf.writeUInt8(0x7, 0);
  272. return Buffer.concat([buf, sLen, Buffer.from(str, 'utf8')]);
  273. }
  274. /**
  275. * AMF3 Decode Generic XML
  276. * @param buf
  277. * @returns {{len: *, value: (*|String)}}
  278. */
  279. function amf3decXml(buf) {
  280. let sLen = amf3decUI29(buf);
  281. let s = sLen & 1;
  282. sLen = sLen >> 1; // The real length without the lowest bit
  283. if (s) return { len: sLen.value + 5, value: buf.slice(5, sLen.value + 5).toString('utf8') };
  284. throw new Error("Error, we have a need to decode a String that is a Reference"); // TODO: Implement references!
  285. }
  286. /**
  287. * AMF3 Encode Generic XML
  288. * @param str
  289. * @returns {Buffer}
  290. */
  291. function amf3encXml(str) {
  292. let sLen = amf3encUI29(str.length << 1);
  293. let buf = Buffer.alloc(1);
  294. buf.writeUInt8(0x0B, 0);
  295. return Buffer.concat([buf, sLen, Buffer.from(str, 'utf8')]);
  296. }
  297. /**
  298. * AMF3 Decide Byte Array
  299. * @param buf
  300. * @returns {{len: *, value: (Array|string|*|Buffer|Blob)}}
  301. */
  302. function amf3decByteArray(buf) {
  303. let sLen = amf3decUI29(buf);
  304. let s = sLen & 1; // TODO: Check if we follow the same rule!
  305. sLen = sLen >> 1; // The real length without the lowest bit
  306. if (s) return { len: sLen.value + 5, value: buf.slice(5, sLen.value + 5) };
  307. throw new Error("Error, we have a need to decode a String that is a Reference"); // TODO: Implement references!
  308. }
  309. /**
  310. * AMF3 Encode Byte Array
  311. * @param str
  312. * @returns {Buffer}
  313. */
  314. function amf3encByteArray(str) {
  315. let sLen = amf3encUI29(str.length << 1);
  316. let buf = Buffer.alloc(1);
  317. buf.writeUInt8(0x0C, 0);
  318. return Buffer.concat([buf, sLen, (typeof str == 'string') ? Buffer.from(str, 'binary') : str]);
  319. }
  320. /**
  321. * AMF3 Decode Double
  322. * @param buf
  323. * @returns {{len: number, value: (*|Number)}}
  324. */
  325. function amf3decDouble(buf) {
  326. return { len: 9, value: buf.readDoubleBE(1) }
  327. }
  328. /**
  329. * AMF3 Encode Double
  330. * @param num
  331. * @returns {Buffer}
  332. */
  333. function amf3encDouble(num) {
  334. let buf = Buffer.alloc(9);
  335. buf.writeUInt8(0x05, 0);
  336. buf.writeDoubleBE(num, 1);
  337. return buf;
  338. }
  339. /**
  340. * AMF3 Decode Date
  341. * @param buf
  342. * @returns {{len: *, value: (*|Number)}}
  343. */
  344. function amf3decDate(buf) { // The UI29 should be 1
  345. let uTz = amf3decUI29(buf);
  346. let ts = buf.readDoubleBE(uTz.len);
  347. return { len: uTz.len + 8, value: ts }
  348. }
  349. /**
  350. * AMF3 Encode Date
  351. * @param ts
  352. * @returns {Buffer}
  353. */
  354. function amf3encDate(ts) {
  355. let buf = Buffer.alloc(1);
  356. buf.writeUInt8(0x8, 0);
  357. let tsBuf = Buffer.alloc(8);
  358. tsBuf.writeDoubleBE(ts, 0);
  359. return Buffer.concat([buf, amf3encUI29(1), tsBuf]); // We always do 1
  360. }
  361. /**
  362. * AMF3 Decode Array
  363. * @param buf
  364. * @returns {{len: *, value: *}}
  365. */
  366. function amf3decArray(buf) {
  367. let count = amf3decUI29(buf.slice(1));
  368. let obj = amf3decObject(buf.slice(count.len));
  369. if (count.value % 2 == 1) throw new Error("This is a reference to another array, which currently we don't support!");
  370. return { len: count.len + obj.len, value: obj.value }
  371. }
  372. /**
  373. * AMF3 Encode Array
  374. */
  375. function amf3encArray() {
  376. throw new Error('Encoding arrays is not supported yet!'); // TODO: Implement encoding of arrays
  377. }
  378. /**
  379. * AMF3 Decode Object
  380. * @param buf
  381. */
  382. function amf3decObject(buf) {
  383. let obj = {};
  384. let pos = 0;
  385. return obj;
  386. }
  387. /**
  388. * AMF3 Encode Object
  389. * @param o
  390. */
  391. function amf3encObject(o) {
  392. }
  393. // AMF0 Implementation
  394. /**
  395. * AMF0 Decode Number
  396. * @param buf
  397. * @returns {{len: number, value: (*|Number)}}
  398. */
  399. function amf0decNumber(buf) {
  400. return { len: 9, value: buf.readDoubleBE(1) }
  401. }
  402. /**
  403. * AMF0 Encode Number
  404. * @param num
  405. * @returns {Buffer}
  406. */
  407. function amf0encNumber(num) {
  408. let buf = Buffer.alloc(9);
  409. buf.writeUInt8(0x00, 0);
  410. buf.writeDoubleBE(num, 1);
  411. return buf;
  412. }
  413. /**
  414. * AMF0 Decode Boolean
  415. * @param buf
  416. * @returns {{len: number, value: boolean}}
  417. */
  418. function amf0decBool(buf) {
  419. return { len: 2, value: (buf.readUInt8(1) != 0) }
  420. }
  421. /**
  422. * AMF0 Encode Boolean
  423. * @param num
  424. * @returns {Buffer}
  425. */
  426. function amf0encBool(num) {
  427. let buf = Buffer.alloc(2);
  428. buf.writeUInt8(0x01, 0);
  429. buf.writeUInt8((num ? 1 : 0), 1);
  430. return buf;
  431. }
  432. /**
  433. * AMF0 Decode Null
  434. * @returns {{len: number, value: null}}
  435. */
  436. function amf0decNull() {
  437. return { len: 1, value: null }
  438. }
  439. /**
  440. * AMF0 Encode Null
  441. * @returns {Buffer}
  442. */
  443. function amf0encNull() {
  444. let buf = Buffer.alloc(1);
  445. buf.writeUInt8(0x05, 0);
  446. return buf;
  447. }
  448. /**
  449. * AMF0 Decode Undefined
  450. * @returns {{len: number, value: undefined}}
  451. */
  452. function amf0decUndefined() {
  453. return { len: 1, value: undefined }
  454. }
  455. /**
  456. * AMF0 Encode Undefined
  457. * @returns {Buffer}
  458. */
  459. function amf0encUndefined() {
  460. let buf = Buffer.alloc(1);
  461. buf.writeUInt8(0x06, 0);
  462. return buf;
  463. }
  464. /**
  465. * AMF0 Decode Date
  466. * @param buf
  467. * @returns {{len: number, value: (*|Number)}}
  468. */
  469. function amf0decDate(buf) {
  470. // let s16 = buf.readInt16BE(1);
  471. let ts = buf.readDoubleBE(3);
  472. return { len: 11, value: ts }
  473. }
  474. /**
  475. * AMF0 Encode Date
  476. * @param ts
  477. * @returns {Buffer}
  478. */
  479. function amf0encDate(ts) {
  480. let buf = Buffer.alloc(11);
  481. buf.writeUInt8(0x0B, 0);
  482. buf.writeInt16BE(0, 1);
  483. buf.writeDoubleBE(ts, 3);
  484. return buf;
  485. }
  486. /**
  487. * AMF0 Decode Object
  488. * @param buf
  489. * @returns {{len: number, value: {}}}
  490. */
  491. function amf0decObject(buf) { // TODO: Implement references!
  492. let obj = {};
  493. let iBuf = buf.slice(1);
  494. let len = 1;
  495. // Logger.debug('ODec',iBuf.readUInt8(0));
  496. while (iBuf.readUInt8(0) != 0x09) {
  497. // Logger.debug('Field', iBuf.readUInt8(0), iBuf);
  498. let prop = amf0decUString(iBuf);
  499. // Logger.debug('Got field for property', prop);
  500. len += prop.len;
  501. if(iBuf.length < prop.len) {
  502. break;
  503. }
  504. if (iBuf.slice(prop.len).readUInt8(0) == 0x09) {
  505. len++;
  506. // Logger.debug('Found the end property');
  507. break;
  508. } // END Object as value, we shall leave
  509. if (prop.value == '') break;
  510. let val = amf0DecodeOne(iBuf.slice(prop.len));
  511. // Logger.debug('Got field for value', val);
  512. obj[prop.value] = val.value;
  513. len += val.len;
  514. iBuf = iBuf.slice(prop.len + val.len);
  515. }
  516. return { len: len, value: obj }
  517. }
  518. /**
  519. * AMF0 Encode Object
  520. */
  521. function amf0encObject(o) {
  522. if (typeof o !== 'object') return;
  523. let data = Buffer.alloc(1);
  524. data.writeUInt8(0x03, 0); // Type object
  525. let k;
  526. for (k in o) {
  527. data = Buffer.concat([data, amf0encUString(k), amf0EncodeOne(o[k])]);
  528. }
  529. let termCode = Buffer.alloc(1);
  530. termCode.writeUInt8(0x09, 0);
  531. return Buffer.concat([data, amf0encUString(''), termCode]);
  532. }
  533. /**
  534. * AMF0 Decode Reference
  535. * @param buf
  536. * @returns {{len: number, value: string}}
  537. */
  538. function amf0decRef(buf) {
  539. let index = buf.readUInt16BE(1);
  540. return { len: 3, value: 'ref' + index }
  541. }
  542. /**
  543. * AMF0 Encode Reference
  544. * @param index
  545. * @returns {Buffer}
  546. */
  547. function amf0encRef(index) {
  548. let buf = Buffer.alloc(3);
  549. buf.writeUInt8(0x07, 0);
  550. buf.writeUInt16BE(index, 1);
  551. return buf;
  552. }
  553. /**
  554. * AMF0 Decode String
  555. * @param buf
  556. * @returns {{len: *, value: (*|string|String)}}
  557. */
  558. function amf0decString(buf) {
  559. let sLen = buf.readUInt16BE(1);
  560. return { len: 3 + sLen, value: buf.toString('utf8', 3, 3 + sLen) }
  561. }
  562. /**
  563. * AMF0 Decode Untyped (without the type byte) String
  564. * @param buf
  565. * @returns {{len: *, value: (*|string|String)}}
  566. */
  567. function amf0decUString(buf) {
  568. let sLen = buf.readUInt16BE(0);
  569. return { len: 2 + sLen, value: buf.toString('utf8', 2, 2 + sLen) }
  570. }
  571. /**
  572. * Do AMD0 Encode of Untyped String
  573. * @param s
  574. * @returns {Buffer}
  575. */
  576. function amf0encUString(str) {
  577. let data = Buffer.from(str, 'utf8');
  578. let sLen = Buffer.alloc(2);
  579. sLen.writeUInt16BE(data.length, 0);
  580. return Buffer.concat([sLen, data]);
  581. }
  582. /**
  583. * AMF0 Encode String
  584. * @param str
  585. * @returns {Buffer}
  586. */
  587. function amf0encString(str) {
  588. let buf = Buffer.alloc(3);
  589. buf.writeUInt8(0x02, 0);
  590. buf.writeUInt16BE(str.length, 1);
  591. return Buffer.concat([buf, Buffer.from(str, 'utf8')]);
  592. }
  593. /**
  594. * AMF0 Decode Long String
  595. * @param buf
  596. * @returns {{len: *, value: (*|string|String)}}
  597. */
  598. function amf0decLongString(buf) {
  599. let sLen = buf.readUInt32BE(1);
  600. return { len: 5 + sLen, value: buf.toString('utf8', 5, 5 + sLen) }
  601. }
  602. /**
  603. * AMF0 Encode Long String
  604. * @param str
  605. * @returns {Buffer}
  606. */
  607. function amf0encLongString(str) {
  608. let buf = Buffer.alloc(5);
  609. buf.writeUInt8(0x0C, 0);
  610. buf.writeUInt32BE(str.length, 1);
  611. return Buffer.concat([buf, Buffer.from(str, 'utf8')]);
  612. }
  613. /**
  614. * AMF0 Decode Array
  615. * @param buf
  616. * @returns {{len: *, value: ({}|*)}}
  617. */
  618. function amf0decArray(buf) {
  619. // let count = buf.readUInt32BE(1);
  620. let obj = amf0decObject(buf.slice(4));
  621. return { len: 5 + obj.len, value: obj.value }
  622. }
  623. /**
  624. * AMF0 Encode Array
  625. */
  626. function amf0encArray(a) {
  627. let l = 0;
  628. if (a instanceof Array) l = a.length; else l = Object.keys(a).length;
  629. Logger.debug('Array encode', l, a);
  630. let buf = Buffer.alloc(5);
  631. buf.writeUInt8(8, 0);
  632. buf.writeUInt32BE(l, 1);
  633. let data = amf0encObject(a);
  634. return Buffer.concat([buf, data.slice(1)]);
  635. }
  636. /**
  637. * AMF0 Encode Binary Array into binary Object
  638. * @param aData
  639. * @returns {Buffer}
  640. */
  641. function amf0cnletray2Object(aData) {
  642. let buf = Buffer.alloc(1);
  643. buf.writeUInt8(0x3, 0); // Object id
  644. return Buffer.concat([buf, aData.slice(5)]);
  645. }
  646. /**
  647. * AMF0 Encode Binary Object into binary Array
  648. * @param oData
  649. * @returns {Buffer}
  650. */
  651. function amf0cnvObject2Array(oData) {
  652. let buf = Buffer.alloc(5);
  653. let o = amf0decObject(oData);
  654. let l = Object.keys(o).length;
  655. buf.writeUInt32BE(l, 1);
  656. return Buffer.concat([buf, oData.slice(1)]);
  657. }
  658. /**
  659. * AMF0 Decode XMLDoc
  660. * @param buf
  661. * @returns {{len: *, value: (*|string|String)}}
  662. */
  663. function amf0decXmlDoc(buf) {
  664. let sLen = buf.readUInt16BE(1);
  665. return { len: 3 + sLen, value: buf.toString('utf8', 3, 3 + sLen) }
  666. }
  667. /**
  668. * AMF0 Encode XMLDoc
  669. * @param str
  670. * @returns {Buffer}
  671. */
  672. function amf0encXmlDoc(str) { // Essentially it is the same as string
  673. let buf = Buffer.alloc(3);
  674. buf.writeUInt8(0x0F, 0);
  675. buf.writeUInt16BE(str.length, 1);
  676. return Buffer.concat([buf, Buffer.from(str, 'utf8')]);
  677. }
  678. /**
  679. * AMF0 Decode Strict Array
  680. * @param buf
  681. * @returns {{len: number, value: Array}}
  682. */
  683. function amf0decSArray(buf) {
  684. let a = [];
  685. let len = 5;
  686. let ret;
  687. for (let count = buf.readUInt32BE(1); count; count--) {
  688. ret = amf0DecodeOne(buf.slice(len));
  689. a.push(ret.value);
  690. len += ret.len;
  691. }
  692. return { len: len, value: amf0markSArray(a) }
  693. }
  694. /**
  695. * AMF0 Encode Strict Array
  696. * @param a Array
  697. */
  698. function amf0encSArray(a) {
  699. Logger.debug('Do strict array!');
  700. let buf = Buffer.alloc(5);
  701. buf.writeUInt8(0x0A, 0);
  702. buf.writeUInt32BE(a.length, 1);
  703. let i;
  704. for (i = 0; i < a.length; i++) {
  705. buf = Buffer.concat([buf, amf0EncodeOne(a[i])]);
  706. }
  707. return buf;
  708. }
  709. function amf0markSArray(a) {
  710. Object.defineProperty(a, 'sarray', { value: true });
  711. return a;
  712. }
  713. /**
  714. * AMF0 Decode Typed Object
  715. * @param buf
  716. * @returns {{len: number, value: ({}|*)}}
  717. */
  718. function amf0decTypedObj(buf) {
  719. let className = amf0decString(buf);
  720. let obj = amf0decObject(buf.slice(className.len - 1));
  721. obj.value.__className__ = className.value;
  722. return { len: className.len + obj.len - 1, value: obj.value }
  723. }
  724. /**
  725. * AMF0 Decode Switch AMF3 Object
  726. * @param buf
  727. * @returns {{len: number, value: ({}|*)}}
  728. */
  729. function amf0decSwitchAmf3(buf) {
  730. let r = amf3DecodeOne(buf.slice(1));
  731. return r;
  732. }
  733. /**
  734. * AMF0 Encode Typed Object
  735. */
  736. function amf0encTypedObj() {
  737. throw new Error("Error: SArray encoding is not yet implemented!"); // TODO: Error
  738. }
  739. /**
  740. * Decode one value from the Buffer according to the applied rules
  741. * @param rules
  742. * @param buffer
  743. * @returns {*}
  744. */
  745. function amfXDecodeOne(rules, buffer) {
  746. if (!rules[buffer.readUInt8(0)]) {
  747. Logger.error('Unknown field', buffer.readUInt8(0));
  748. return null;
  749. }
  750. return rules[buffer.readUInt8(0)](buffer);
  751. }
  752. /**
  753. * Decode one AMF0 value
  754. * @param buffer
  755. * @returns {*}
  756. */
  757. function amf0DecodeOne(buffer) {
  758. return amfXDecodeOne(amf0dRules, buffer);
  759. }
  760. /**
  761. * Decode one AMF3 value
  762. * @param buffer
  763. * @returns {*}
  764. */
  765. function amf3DecodeOne(buffer) {
  766. return amfXDecodeOne(amf3dRules, buffer);
  767. }
  768. /**
  769. * Decode a whole buffer of AMF values according to rules and return in array
  770. * @param rules
  771. * @param buffer
  772. * @returns {Array}
  773. */
  774. function amfXDecode(rules, buffer) {
  775. // We shall receive clean buffer and will respond with an array of values
  776. let resp = [];
  777. let res;
  778. for (let i = 0; i < buffer.length;) {
  779. res = amfXDecodeOne(rules, buffer.slice(i));
  780. i += res.len;
  781. resp.push(res.value); // Add the response
  782. }
  783. return resp;
  784. }
  785. /**
  786. * Decode a buffer of AMF3 values
  787. * @param buffer
  788. * @returns {Array}
  789. */
  790. function amf3Decode(buffer) {
  791. return amfXDecode(amf3dRules, buffer);
  792. }
  793. /**
  794. * Decode a buffer of AMF0 values
  795. * @param buffer
  796. * @returns {Array}
  797. */
  798. function amf0Decode(buffer) {
  799. return amfXDecode(amf0dRules, buffer);
  800. }
  801. /**
  802. * Encode one AMF value according to rules
  803. * @param rules
  804. * @param o
  805. * @returns {*}
  806. */
  807. function amfXEncodeOne(rules, o) {
  808. // Logger.debug('amfXEncodeOne type',o,amfType(o),rules[amfType(o)]);
  809. let f = rules[amfType(o)];
  810. if (f) return f(o);
  811. throw new Error('Unsupported type for encoding!');
  812. }
  813. /**
  814. * Encode one AMF0 value
  815. * @param o
  816. * @returns {*}
  817. */
  818. function amf0EncodeOne(o) {
  819. return amfXEncodeOne(amf0eRules, o);
  820. }
  821. /**
  822. * Encode one AMF3 value
  823. * @param o
  824. * @returns {*}
  825. */
  826. function amf3EncodeOne(o) {
  827. return amfXEncodeOne(amf3eRules, o);
  828. }
  829. /**
  830. * Encode an array of values into a buffer
  831. * @param a
  832. * @returns {Buffer}
  833. */
  834. function amf3Encode(a) {
  835. let buf = Buffer.alloc(0);
  836. a.forEach(function (o) {
  837. buf = Buffer.concat([buf, amf3EncodeOne(o)]);
  838. });
  839. return buf;
  840. }
  841. /**
  842. * Encode an array of values into a buffer
  843. * @param a
  844. * @returns {Buffer}
  845. */
  846. function amf0Encode(a) {
  847. let buf = Buffer.alloc(0);
  848. a.forEach(function (o) {
  849. buf = Buffer.concat([buf, amf0EncodeOne(o)]);
  850. });
  851. return buf;
  852. }
  853. const rtmpCmdCode = {
  854. "_result": ["transId", "cmdObj", "info"],
  855. "_error": ["transId", "cmdObj", "info", "streamId"], // Info / Streamid are optional
  856. "onStatus": ["transId", "cmdObj", "info"],
  857. "releaseStream": ["transId", "cmdObj", "streamName"],
  858. "getStreamLength": ["transId", "cmdObj", "streamId"],
  859. "getMovLen": ["transId", "cmdObj", "streamId"],
  860. "FCPublish": ["transId", "cmdObj", "streamName"],
  861. "FCUnpublish": ["transId", "cmdObj", "streamName"],
  862. "onFCPublish": ["transId", "cmdObj", "info"],
  863. "connect": ["transId", "cmdObj", "args"],
  864. "call": ["transId", "cmdObj", "args"],
  865. "createStream": ["transId", "cmdObj"],
  866. "close": ["transId", "cmdObj"],
  867. "play": ["transId", "cmdObj", "streamName", "start", "duration", "reset"],
  868. "play2": ["transId", "cmdObj", "params"],
  869. "deleteStream": ["transId", "cmdObj", "streamId"],
  870. "closeStream": ["transId", "cmdObj"],
  871. "receiveAudio": ["transId", "cmdObj", "bool"],
  872. "receiveVideo": ["transId", "cmdObj", "bool"],
  873. "publish": ["transId", "cmdObj", "streamName", "type"],
  874. "seek": ["transId", "cmdObj", "ms"],
  875. "pause": ["transId", "cmdObj", "pause", "ms"]
  876. };
  877. const rtmpDataCode = {
  878. "@setDataFrame": ["method", "dataObj"],
  879. "onMetaData": ["dataObj"],
  880. "|RtmpSampleAccess": ["bool1", "bool2"],
  881. };
  882. /**
  883. * Decode a data!
  884. * @param dbuf
  885. * @returns {{cmd: (*|string|String|*), value: *}}
  886. */
  887. function decodeAmf0Data(dbuf) {
  888. let buffer = dbuf;
  889. let resp = {};
  890. let cmd = amf0DecodeOne(buffer);
  891. if(cmd) {
  892. resp.cmd = cmd.value;
  893. buffer = buffer.slice(cmd.len);
  894. if (rtmpDataCode[cmd.value]) {
  895. rtmpDataCode[cmd.value].forEach(function (n) {
  896. if (buffer.length > 0) {
  897. let r = amf0DecodeOne(buffer);
  898. if(r) {
  899. buffer = buffer.slice(r.len);
  900. resp[n] = r.value;
  901. }
  902. }
  903. });
  904. } else {
  905. Logger.error('Unknown command', resp);
  906. }
  907. }
  908. return resp
  909. }
  910. /**
  911. * Decode a command!
  912. * @param dbuf
  913. * @returns {{cmd: (*|string|String|*), value: *}}
  914. */
  915. function decodeAMF0Cmd(dbuf) {
  916. let buffer = dbuf;
  917. let resp = {};
  918. let cmd = amf0DecodeOne(buffer);
  919. resp.cmd = cmd.value;
  920. buffer = buffer.slice(cmd.len);
  921. if (rtmpCmdCode[cmd.value]) {
  922. rtmpCmdCode[cmd.value].forEach(function (n) {
  923. if (buffer.length > 0) {
  924. let r = amf0DecodeOne(buffer);
  925. buffer = buffer.slice(r.len);
  926. resp[n] = r.value;
  927. }
  928. });
  929. } else {
  930. Logger.error('Unknown command', resp);
  931. }
  932. return resp
  933. }
  934. /**
  935. * Encode AMF0 Command
  936. * @param opt
  937. * @returns {*}
  938. */
  939. function encodeAMF0Cmd(opt) {
  940. let data = amf0EncodeOne(opt.cmd);
  941. if (rtmpCmdCode[opt.cmd]) {
  942. rtmpCmdCode[opt.cmd].forEach(function (n) {
  943. if (opt.hasOwnProperty(n))
  944. data = Buffer.concat([data, amf0EncodeOne(opt[n])]);
  945. });
  946. } else {
  947. Logger.error('Unknown command', opt);
  948. }
  949. // Logger.debug('Encoded as',data.toString('hex'));
  950. return data
  951. }
  952. function encodeAMF0Data(opt) {
  953. let data = amf0EncodeOne(opt.cmd);
  954. if (rtmpDataCode[opt.cmd]) {
  955. rtmpDataCode[opt.cmd].forEach(function (n) {
  956. if (opt.hasOwnProperty(n))
  957. data = Buffer.concat([data, amf0EncodeOne(opt[n])]);
  958. });
  959. } else {
  960. Logger.error('Unknown data', opt);
  961. }
  962. // Logger.debug('Encoded as',data.toString('hex'));
  963. return data
  964. }
  965. /**
  966. *
  967. * @param dbuf
  968. * @returns {{}}
  969. */
  970. function decodeAMF3Cmd(dbuf) {
  971. let buffer = dbuf;
  972. let resp = {};
  973. let cmd = amf3DecodeOne(buffer);
  974. resp.cmd = cmd.value;
  975. buffer = buffer.slice(cmd.len);
  976. if (rtmpCmdCode[cmd.value]) {
  977. rtmpCmdCode[cmd.value].forEach(function (n) {
  978. if (buffer.length > 0) {
  979. let r = amf3DecodeOne(buffer);
  980. buffer = buffer.slice(r.len);
  981. resp[n] = r.value;
  982. }
  983. });
  984. } else {
  985. Logger.error('Unknown command', resp);
  986. }
  987. return resp
  988. }
  989. /**
  990. * Encode AMF3 Command
  991. * @param opt
  992. * @returns {*}
  993. */
  994. function encodeAMF3Cmd(opt) {
  995. let data = amf0EncodeOne(opt.cmd);
  996. if (rtmpCmdCode[opt.cmd]) {
  997. rtmpCmdCode[opt.cmd].forEach(function (n) {
  998. if (opt.hasOwnProperty(n))
  999. data = Buffer.concat([data, amf3EncodeOne(opt[n])]);
  1000. });
  1001. } else {
  1002. Logger.error('Unknown command', opt);
  1003. }
  1004. return data
  1005. }
  1006. module.exports = {
  1007. decodeAmf3Cmd: decodeAMF3Cmd,
  1008. encodeAmf3Cmd: encodeAMF3Cmd,
  1009. decodeAmf0Cmd: decodeAMF0Cmd,
  1010. encodeAmf0Cmd: encodeAMF0Cmd,
  1011. decodeAmf0Data: decodeAmf0Data,
  1012. encodeAmf0Data: encodeAMF0Data,
  1013. amfType: amfType,
  1014. amf0Encode: amf0Encode,
  1015. amf0EncodeOne: amf0EncodeOne,
  1016. amf0Decode: amf0Decode,
  1017. amf0DecodeOne: amf0DecodeOne,
  1018. amf3Encode: amf3Encode,
  1019. amf3EncodeOne: amf3EncodeOne,
  1020. amf3Decode: amf3Decode,
  1021. amf3DecodeOne: amf3DecodeOne,
  1022. amf0cnvA2O: amf0cnletray2Object,
  1023. amf0cnvO2A: amf0cnvObject2Array,
  1024. amf0markSArray: amf0markSArray,
  1025. amf0decArray: amf0decArray,
  1026. amf0decBool: amf0decBool,
  1027. amf0decDate: amf0decDate,
  1028. amf0decLongString: amf0decLongString,
  1029. amf0decNull: amf0decNull,
  1030. amf0decNumber: amf0decNumber,
  1031. amf0decObject: amf0decObject,
  1032. amf0decRef: amf0decRef,
  1033. amf0decSArray: amf0decSArray,
  1034. amf0decString: amf0decString,
  1035. amf0decTypedObj: amf0decTypedObj,
  1036. amf0decUndefined: amf0decUndefined,
  1037. amf0decXmlDoc: amf0decXmlDoc,
  1038. amf0encArray: amf0encArray,
  1039. amf0encBool: amf0encBool,
  1040. amf0encDate: amf0encDate,
  1041. amf0encLongString: amf0encLongString,
  1042. amf0encNull: amf0encNull,
  1043. amf0encNumber: amf0encNumber,
  1044. amf0encObject: amf0encObject,
  1045. amf0encRef: amf0encRef,
  1046. amf0encSArray: amf0encSArray,
  1047. amf0encString: amf0encString,
  1048. amf0encTypedObj: amf0encTypedObj,
  1049. amf0encUndefined: amf0encUndefined,
  1050. amf0encXmlDoc: amf0encXmlDoc,
  1051. amf3decArray: amf3decArray,
  1052. amf3decByteArray: amf3decByteArray,
  1053. amf3decDate: amf3decDate,
  1054. amf3decDouble: amf3decDouble,
  1055. amf3decFalse: amf3decFalse,
  1056. amf3decInteger: amf3decInteger,
  1057. amf3decNull: amf3decNull,
  1058. amf3decObject: amf3decObject,
  1059. amf3decString: amf3decString,
  1060. amf3decTrue: amf3decTrue,
  1061. amf3decUI29: amf3decUI29,
  1062. amf3decUndefined: amf3decUndefined,
  1063. amf3decXml: amf3decXml,
  1064. amf3decXmlDoc: amf3decXmlDoc,
  1065. amf3encArray: amf3encArray,
  1066. amf3encByteArray: amf3encByteArray,
  1067. amf3encDate: amf3encDate,
  1068. amf3encDouble: amf3encDouble,
  1069. amf3encFalse: amf3encFalse,
  1070. amf3encInteger: amf3encInteger,
  1071. amf3encNull: amf3encNull,
  1072. amf3encObject: amf3encObject,
  1073. amf3encString: amf3encString,
  1074. amf3encTrue: amf3encTrue,
  1075. amf3encUI29: amf3encUI29,
  1076. amf3encUndefined: amf3encUndefined,
  1077. amf3encXml: amf3encXml,
  1078. amf3encXmlDoc: amf3encXmlDoc
  1079. };