bt_parse.js 15 KB

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