bt_parse.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. import {
  2. BtCmd,
  3. CmdBase,
  4. CmdEarPhone,
  5. CmdRtc,
  6. // CmdRgb,
  7. CmdKwh,
  8. CmdKey,
  9. CmdVoice,
  10. CmdWeek
  11. } from './bt_cmd';
  12. import {
  13. CmdEvent,
  14. EnumCmdEvent,
  15. EnumPlayStatus,
  16. EnumSupplier
  17. } from '../cmd_key_event';
  18. import EventManager from '../../utils/event_bus'
  19. class BtParse {
  20. // 型号名称
  21. // static mateX2 = "MW-Mate X(4G_WIFI)";
  22. // static matePVX = "猫王音响·Mate_PVX";
  23. // static matePVXL = "猫王音响·Mate_PVXL";
  24. // 防止收到另外的消息
  25. static isReceiveCmd = false;
  26. // 如果10ms内获取两个一模一样的就删除一个
  27. static lastCmd = null;
  28. static lastTime = null;
  29. constructor() { }
  30. // 解析命令
  31. static parseTLV(cmd) {
  32. BtCmd.printTLV(cmd, false);
  33. // todo 在线
  34. // if (!PlayDevice.isOnline) {
  35. // return;
  36. // }
  37. // if (!BtParse.isReceiveCmd) {
  38. // return;
  39. // }
  40. if (cmd.length > 5) {
  41. // 指令类别
  42. const type = cmd[6];
  43. if (cmd.length < 9) {
  44. // 杰里、领芯的语音控制指令
  45. BtParse._voiceCmd(cmd);
  46. } else {
  47. // cmd[7]为命令长度
  48. // 命令类型
  49. const value = cmd[8];
  50. // 第二部分走杰理
  51. if (type === CmdVoice.jlReceiveVoiceData) {
  52. BtParse._receiveRecordData(cmd);
  53. }
  54. // 查询版本号后校验设备
  55. else if (type === CmdBase.queryVersion) {
  56. const version = CmdBase.parseVersion(value);
  57. EventManager.fire(CmdEvent.version(version));
  58. EventManager.fire(CmdEvent.getDeviceInfo());
  59. } else if (BtParse._getDataHeader(cmd)) {
  60. // 控制指令
  61. BtParse._controlCmd(cmd);
  62. } else {
  63. console.log("收到不明指令:", cmd);
  64. const manufacturer = "";
  65. // DeviceManager.instance.device?.manufacturer ?? "";
  66. // 山景的语音判断
  67. // if (manufacturer === EnumSupplier.shanJing) {
  68. // const sjCmd = cmd[4];
  69. // if (sjCmd === CmdVoice.sjStartVoice) {
  70. // BtParse._startRecord(EnumSupplier.shanJing);
  71. // } else if (sjCmd === CmdVoice.sjStopVoice) {
  72. // BtParse._stopRecord(EnumSupplier.shanJing);
  73. // }
  74. // // 山景的都要走接收数据
  75. // BtParse._receiveRecordData(cmd);
  76. // } else {
  77. // // b1耳机、领芯、杰里p2第二部分语音数据直接走这里
  78. // BtParse._receiveRecordData(cmd);
  79. // }
  80. }
  81. }
  82. }
  83. }
  84. static _send(cmdEvent) {
  85. EventManager.fire(CmdEvent[cmdEvent]);
  86. }
  87. static _getDataHeader(cmd) {
  88. if (cmd.length < 4) {
  89. return false;
  90. }
  91. ["54", "44", "44", "48", "1", "9", "22", "1", "4"]
  92. const header = [0x54, 0x44, 0x44, 0x48];
  93. let isCmd = cmd[0] === header[0] && cmd[1] === header[1] && cmd[2] === header[2] && cmd[3] === header[3];
  94. // console.log("收到数据头:", cmd[0], header[0], cmd[1], header[1], cmd[2], header[2], cmd[3], header[3],);
  95. return isCmd;
  96. }
  97. // todo 暂时不要
  98. static _voiceCmd(cmd) {
  99. const type = cmd[6];
  100. console.log("收到语音指令:", cmd);
  101. // switch (type) {
  102. // // 杰理语音开始
  103. // case CmdVoice.jlStartVoice:
  104. // BtParse._startRecord(EnumSupplier.jieLi);
  105. // break;
  106. // // 杰理结束
  107. // case CmdVoice.jlStopVoice:
  108. // BtParse._stopRecord(EnumSupplier.jieLi);
  109. // break;
  110. // // 发给插件
  111. // case CmdVoice.jlReceiveVoiceData:
  112. // console.log("发送杰里的p1语音:没有进来过,不走这里的,直接判断0x70 && jieLi");
  113. // BtParse._receiveRecordData(cmd);
  114. // break;
  115. // // 领心语音开始
  116. // case CmdVoice.lxStartVoice:
  117. // BtParse._startRecord(EnumSupplier.lingXin);
  118. // break;
  119. // // 领心语音结束
  120. // case CmdVoice.lxStopVoice:
  121. // BtParse._stopRecord(EnumSupplier.lingXin);
  122. // break;
  123. // default:
  124. // console.log("发送语音:默认发送,不走这里", cmd);
  125. // break;
  126. // }
  127. }
  128. static async _startRecord(supplier) {
  129. console.log("StartVoice======语音开始", supplier);
  130. }
  131. static async _stopRecord(supplier) {
  132. console.log("stopRecord======语音结束", supplier);
  133. }
  134. // 杰理接收设备第二部分 发送给插件
  135. static _receiveRecordData(cmd) {
  136. // todo 暂时不要
  137. // RecordVoiceManager.sendDataToPlugin(cmd);
  138. }
  139. static async _controlCmd(cmd) {
  140. const type = cmd[6];
  141. const value = cmd[8];
  142. // mqttAddDebugCmd("收到蓝牙指令:" + cmd);
  143. console.log("收到控制指令:", cmd, type)
  144. switch (type) {
  145. // 校验设备
  146. case CmdBase.checkDeviceSuccess:
  147. break;
  148. // 按键 短按、长按等
  149. case CmdKey.type:
  150. // IOS的不要了
  151. // if (DeviceUtil.isIOS) {
  152. // if (BtParse.lastCmd && JSON.stringify(BtParse.lastCmd) === JSON.stringify(cmd)) {
  153. // if (BtParse.lastTime) {
  154. // const curTime = TimeUtil.getCurrentMillis();
  155. // if (curTime - BtParse.lastTime < 5) {
  156. // return;
  157. // }
  158. // }
  159. // }
  160. // BtParse.lastCmd = cmd;
  161. // BtParse.lastTime = TimeUtil.getCurrentMillis();
  162. // }
  163. let t = 0;
  164. if (cmd.length > 9) {
  165. t = cmd[9];
  166. }
  167. switch (t) {
  168. // 0x54 44 44 48 01 0a 21 02 01 02
  169. // 54, 44, 44, 48, 1, a, 21, 2, 1(value), 2(type)
  170. // 上一曲
  171. case CmdKey.previousSong:
  172. BtParse._send(EnumCmdEvent.previousSong);
  173. break;
  174. // 下一曲
  175. case CmdKey.nextSong:
  176. BtParse._send(EnumCmdEvent.nextSong);
  177. break;
  178. // 上一频道
  179. case CmdKey.previousChannel:
  180. BtParse._send(EnumCmdEvent.previousChannel);
  181. break;
  182. // 下一频道
  183. case CmdKey.nextChannel:
  184. BtParse._send(EnumCmdEvent.nextChannel);
  185. break;
  186. // 0x02 2
  187. case CmdKey.pressShort:
  188. // 1 下一个频道
  189. if (value === CmdKey.next) {
  190. BtParse._send(EnumCmdEvent.nextChannel);
  191. }
  192. // 2 上一个频道
  193. else if (value === CmdKey.previous) {
  194. BtParse._send(EnumCmdEvent.previousChannel);
  195. }
  196. // 3 单击下一个专辑 或者下一曲
  197. else if (value === CmdKey.changeProgram) {
  198. // if (ProviderUtil.device.mDevice?.clientType === BtParse.mateX2) {
  199. // BtParse._send(EnumCmdEvent.nextAlbum);
  200. // } else {
  201. // BtParse._send(EnumCmdEvent.nextSong);
  202. // }
  203. }
  204. break;
  205. // 0x09 9
  206. case CmdKey.pressDouble:
  207. // 1 双击下一曲
  208. if (value === CmdKey.next) {
  209. BtParse._send(EnumCmdEvent.nextSong);
  210. }
  211. // 2 双击上一曲
  212. else if (value === CmdKey.previous) {
  213. BtParse._send(EnumCmdEvent.previousSong);
  214. }
  215. // 3 单击上一专辑或者上一曲
  216. else if (value === CmdKey.changeProgram) {
  217. // todo
  218. // if (ProviderUtil.device.mDevice?.clientType === BtParse.mateX2) {
  219. // BtParse._send(EnumCmdEvent.previousAlbum);
  220. // } else {
  221. // BtParse._send(EnumCmdEvent.previousSong);
  222. // }
  223. }
  224. break;
  225. // 0x08 8
  226. case CmdKey.pressLong:
  227. if (value === CmdKey.previous) {
  228. console.log("快退");
  229. BtParse._send(EnumCmdEvent.fastback);
  230. } else if (value === CmdKey.next) {
  231. console.log("快进");
  232. BtParse._send(EnumCmdEvent.speed);
  233. }
  234. break;
  235. // 0x04 4
  236. case CmdKey.pressLongUp:
  237. if (value === CmdKey.previous) {
  238. console.log("停止快退");
  239. BtParse._send(EnumCmdEvent.stopFastback);
  240. } else if (value === CmdKey.next) {
  241. console.log("停止快进");
  242. BtParse._send(EnumCmdEvent.stopSpeed);
  243. } else if (value === CmdKey.pressLongUp) {
  244. // [54, 44, 44, 48, 1, a, 21, 2, 4, 4]
  245. console.log("录音结束");
  246. BtParse._send(EnumCmdEvent.stopRecord);
  247. }
  248. break;
  249. }
  250. BtHelper.instance.changeChannelCallBack();
  251. break;
  252. // 音量 54 44 44 48 1 a 32 2 b 0
  253. case CmdBase.queryVolume:
  254. // 手机最大音量 需要获取
  255. const phoneMax = 15;
  256. // todo 音量
  257. //await VolumeUtil.getMaxVolume();
  258. const max = CmdBase.volumeMax;
  259. const d = phoneMax / max;
  260. const result = (d * value).toFixed(2);
  261. var trueVolume = parseFloat(result) ?? 0;
  262. console.log("trueVolume=====", max, "===", d, ",,,,", value, ",,,,", result, ",,,,", trueVolume);
  263. if (trueVolume > phoneMax) {
  264. trueVolume = phoneMax;
  265. }
  266. // 仅用于记录设备音量,播控页面显示用
  267. EventManager.fire(CmdEvent.volume({ volume: trueVolume }));
  268. // if (DeviceUtil.isAndroid) {
  269. // const name = "";
  270. // // todo
  271. // // DeviceManager.instance.name;
  272. // if (name === "猫王·霹雳唱机") {
  273. // // VolumeUtil.setVolume(trueVolume);
  274. // }
  275. // }
  276. break;
  277. // 查询电量
  278. case CmdKwh.queryKwh:
  279. EventManager.fire(CmdEvent.battery({ kwh: value }));
  280. break;
  281. // 自动播放 54, 44, 44, 48, 1, 9, 24, 1, 1
  282. case CmdBase.getAutoPlay:
  283. case CmdBase.setAutoPlay:
  284. setTimeout(() => {
  285. EventManager.fire(CmdEvent.playStatus({
  286. playStatus: value === EnumOpen.open ? EnumPlayStatus.play : EnumPlayStatus.pause,
  287. }));
  288. }, 300);
  289. break;
  290. // 查询低电量设置
  291. case CmdKwh.queryLowKwhWarningTone:
  292. EventManager.fire(CmdEvent.queryLowKwn({ kwh: value }));
  293. break;
  294. // 耳机电量 index0 :左耳机, index1:左耳机 ,index2: 充电盒。value: 0-9代表10-100% 获取不到用-1
  295. // [54, 44, 44, 48, 1, b, b1, 3, 8, 8, 2]
  296. case CmdEarPhone.queryEarPhoneKwh:
  297. const rightKwh = cmd[9];
  298. const boxKwh = cmd[10];
  299. let kwh = 0;
  300. if (value > 0 && rightKwh > 0) {
  301. kwh = Math.min(value, rightKwh);
  302. } else {
  303. kwh = Math.max(value, rightKwh);
  304. }
  305. EventManager.fire(CmdEvent.batteryEarphone({
  306. kwhLeft: value,
  307. kwhBox: boxKwh,
  308. kwhRight: rightKwh,
  309. kwh: kwh,
  310. }));
  311. break;
  312. // EQ [84, 68, 68, 72, 1, 18, 180, 10, 0, 0, 240, 237, 236, 0, 236, 0, 0, 0]
  313. // B5耳机获取EQ
  314. case CmdEarPhone.queryEQ:
  315. if (cmd.length > 15) {
  316. const result = cmd.slice(8, cmd.length);
  317. const list = result.map(element => parseInt(element, 16));
  318. console.log("eq==============", list);
  319. EventManager.fire(CmdEvent.eqs({ eqs: list }));
  320. }
  321. break;
  322. // 低延迟 [54, 44, 44, 48, 1, a, b2, 2, 0, 2]
  323. case CmdEarPhone.queryLowDelayMode:
  324. const lowDelayMode = cmd[9];
  325. EventManager.fire(CmdEvent.lowDelayMode({ lowDelayMode, lowDelayModeOpen: value }));
  326. break;
  327. // 耳机低电量
  328. case CmdEarPhone.queryLowPower:
  329. const lowPowerOpen = cmd[8];
  330. EventManager.fire(CmdEvent.lowPowerOpen({ lowPowerOpen }));
  331. break;
  332. // 查询唤醒闹钟
  333. case CmdRtc.queryAlarm:
  334. const wakeSwitch = cmd[8];
  335. if (cmd.length > 9) {
  336. const week = cmd[9];
  337. const hour = cmd[10];
  338. const minutes = cmd[11];
  339. const wakeCycle = CmdWeek.cmd2Week(week);
  340. console.log("queryAlarm=====", wakeSwitch, "=", wakeCycle);
  341. EventManager.fire(CmdEvent.wake({
  342. wakeSwitch,
  343. wakeCycle,
  344. wakeHour: hour,
  345. wakeMinutes: minutes,
  346. }));
  347. }
  348. break;
  349. // 查询自动休眠状态
  350. case CmdRtc.querySleepAfterPlayPause:
  351. case CmdRtc.setSleepAfterPlayPause:
  352. EventManager.fire(CmdEvent.pauseSleep({ pauseSleep: value }));
  353. break;
  354. // 查询休眠
  355. case CmdRtc.querySleep:
  356. const sleepSwitch = cmd[8];
  357. const hour = cmd[9];
  358. const minutes = cmd[10];
  359. const leftHour = cmd[11];
  360. const leftMinutes = cmd[12];
  361. EventManager.fire(CmdEvent.sleep({
  362. sleepSwitch,
  363. sleepHour: hour,
  364. sleepMinutes: minutes,
  365. }));
  366. break;
  367. // 开始录音
  368. case CmdVoice.startVoice:
  369. console.log("没有意义的开始录音");
  370. // _send(EnumCmdEvent.startRecord);
  371. break;
  372. // 查询 耳机手势
  373. case CmdEarPhone.queryCtrlStatus:
  374. const singleC = cmd[8];
  375. const doubleC = cmd[9];
  376. const longC = cmd[10];
  377. EventManager.fire(CmdEvent.ctrlStatus({ ctrlStatus: [singleC, doubleC, longC] }));
  378. break;
  379. case CmdBase.getMac:
  380. {
  381. var values = []
  382. for (let i = 8; i < cmd.length; i++) {
  383. values.push(cmd[i]);
  384. }
  385. let str = this.hexArrayToString(values);
  386. // getMac===== ?MV-SR1(4G_WIFI)
  387. let device = getApp().globalData.mDeviceList[0] ?? {};
  388. device["trueMac"] = str;
  389. console.log("getMac=====", device)
  390. EventManager.fire(CmdEvent.btMac(str));
  391. }
  392. // [84, 68, 68, 72, 1, 23, 53, 16, 77, 86, 45, 83, 82, 49, 40, 52, 71, 95, 87, 73, 70, 73, 41]
  393. break;
  394. case CmdBase.getClientType:
  395. {
  396. var values = []
  397. for (let i = 8; i < cmd.length; i++) {
  398. values.push(cmd[i]);
  399. }
  400. let str = this.hexArrayToString(values);
  401. let device = getApp().globalData.mDeviceList[0] ?? {};
  402. device["trueClientType"] = str;
  403. console.log("getClientType=====", device)
  404. EventManager.fire(CmdEvent.clientType(str));
  405. }
  406. //  [84, 68, 68, 72, 1, 14, 49, 7, 228, 159, 128, 9, 224, 236]
  407. break;
  408. case CmdBase.getIsConnect:
  409. // [84, 68, 68, 72, 1, 10, 54, 2, 0, 1]
  410. let device = getApp().globalData.mDeviceList[0] ?? {};
  411. device["isConnectMac"] = value;
  412. console.log("getIsConnect=====", device)
  413. break;
  414. default:
  415. console.log("接收到语音:", cmd);
  416. // _receiveRecordData(cmd);
  417. break;
  418. }
  419. }
  420. static hexArrayToString(hexArray) {
  421. let str = '';
  422. for (let i = 0; i < hexArray.length; i++) {
  423. const charCode = hexArray[i];
  424. if (charCode >= 32 && charCode <= 126) { // 可打印的ASCII字符范围
  425. str += String.fromCharCode(charCode);
  426. } else {
  427. str += '?'; // 替换为问号或其他符号
  428. }
  429. }
  430. return str;
  431. }
  432. }
  433. // 导出类
  434. module.exports = BtParse;