wasmapi.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. var printCharBuffers = [null, [], []]
  2. var UTF8Decoder = typeof TextDecoder !== 'undefined' ? new TextDecoder('utf8') : undefined
  3. var HEAP8 = null // Int8Array
  4. var HEAPU8 = null // Uint8Array
  5. var HEAP16 = null // Int16Array
  6. var HEAPU16 = null // Uint16Array
  7. var HEAP32 = null // Int32Array
  8. var HEAPU32 = null // Uint32Array
  9. var HEAPF32 = null // Float32Array
  10. var HEAPF64 = null // Float64Array
  11. //注入函数,打印字符串,C代码中打印字符串需要以\n结束
  12. function printChar(stream, curr) {
  13. var buffer = printCharBuffers[stream];
  14. //assert(buffer);
  15. if (curr === 0 || curr === 10) {
  16. //(stream === 1 ? out : err)(this.UTF8ArrayToString(buffer, 0));
  17. //buffer.length = 0;
  18. let str = UTF8ArrayToString(buffer, 0)
  19. console.log(str)//打印字符串
  20. buffer.length = 0;
  21. } else {
  22. buffer.push(curr);
  23. }
  24. }
  25. //注入函数,将字节数组转成字符数组
  26. function UTF8ArrayToString(heapOrArray, idx, maxBytesToRead) {
  27. var endIdx = idx + maxBytesToRead;
  28. var endPtr = idx;
  29. // TextDecoder needs to know the byte length in advance, it doesn't stop on
  30. // null terminator by itself. Also, use the length info to avoid running tiny
  31. // strings through TextDecoder, since .subarray() allocates garbage.
  32. // (As a tiny code save trick, compare endPtr against endIdx using a negation,
  33. // so that undefined means Infinity)
  34. while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr;
  35. if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) {
  36. return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr));
  37. }
  38. var str = '';
  39. // If building with TextDecoder, we have already computed the string length
  40. // above, so test loop end condition against that
  41. while (idx < endPtr) {
  42. // For UTF8 byte structure, see:
  43. // http://en.wikipedia.org/wiki/UTF-8#Description
  44. // https://www.ietf.org/rfc/rfc2279.txt
  45. // https://tools.ietf.org/html/rfc3629
  46. var u0 = heapOrArray[idx++];
  47. if (!(u0 & 0x80)) { str += String.fromCharCode(u0); continue; }
  48. var u1 = heapOrArray[idx++] & 63;
  49. if ((u0 & 0xE0) == 0xC0) { str += String.fromCharCode(((u0 & 31) << 6) | u1); continue; }
  50. var u2 = heapOrArray[idx++] & 63;
  51. if ((u0 & 0xF0) == 0xE0) {
  52. u0 = ((u0 & 15) << 12) | (u1 << 6) | u2;
  53. } else {
  54. //if ((u0 & 0xF8) != 0xF0) warnOnce('Invalid UTF-8 leading byte ' + ptrToString(u0) + ' encountered when deserializing a UTF-8 string in wasm memory to a JS string!');
  55. u0 = ((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | (heapOrArray[idx++] & 63);
  56. }
  57. if (u0 < 0x10000) {
  58. str += String.fromCharCode(u0);
  59. } else {
  60. var ch = u0 - 0x10000;
  61. str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
  62. }
  63. }
  64. return str;
  65. }
  66. const wasmapi = {
  67. wasmInstance: null,//wasm实例
  68. wasmFuncs: null,//wasm导出函数
  69. wasmDataPtr: {//wasm模块的数据指针
  70. installBtsDataPtr: 0,//安装基站数据指针
  71. bleBtsDataPtr: 0,//蓝牙基站数据指针
  72. audioDataPtr: 0,//音频数据指针
  73. currentLocationCoordPtr: 0,//定位坐标数据指针
  74. accDataPtr: 0,//加速度指针
  75. },
  76. data: {
  77. audioDataList: [],//音频数据队列
  78. oneFrameLen: 12000,//一帧音频数据长度
  79. bleBtsMonitorSuccessFlag: false,//蓝牙基站监听成功标识符
  80. bleBtsDataList: [], //蓝牙基站队列
  81. installBtsInjectFlag: false,//安装基站已注入标识符
  82. accDataList: [],//加速度数据队列
  83. },
  84. ////wasm注入函数,将数据从源地址src拷贝长度为num的数据到目的地址dest
  85. _emscripten_memcpy_js(dest, src, num) {
  86. HEAPU8.copyWithin(dest, src, src + num)
  87. },
  88. _emscripten_resize_heap(requestedSize) {
  89. let oldSize = HEAPU8.length
  90. // With CAN_ADDRESS_2GB or MEMORY64, pointers are already unsigned.
  91. requestedSize >>>= 0
  92. this.abortOnCannotGrowMemory(requestedSize)
  93. },
  94. abortOnCannotGrowMemory(requestedSize) {
  95. abort(`Cannot enlarge memory arrays to size ${requestedSize} bytes (OOM). Either (1) compile with -sINITIAL_MEMORY=X with X higher than the current value ${HEAP8.length}, (2) compile with -sALLOW_MEMORY_GROWTH which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -sABORTING_MALLOC=0`);
  96. },
  97. _fd_write(fd, iov, iovcnt, pnum) {
  98. let num = 0
  99. for (let i = 0; i < iovcnt; i++) {
  100. let ptr = HEAP32[((iov) >> 2)]
  101. let len = HEAP32[(((iov) + (4)) >> 2)]
  102. iov += 8
  103. for (let j = 0; j < len; j++) {
  104. printChar(fd, HEAPU8[ptr + j])
  105. }
  106. num += len
  107. }
  108. HEAP32[((pnum) >> 2)] = num
  109. return 0
  110. },
  111. _fd_close(fd) {
  112. abort('fd_close called without SYSCALLS_REQUIRE_FILESYSTEM');
  113. return 0
  114. },
  115. _fd_seek(fd, offset_low, offset_high, whence, newOffset) {
  116. abort('it should not be possible to operate on streams when !SYSCALLS_REQUIRE_FILESYSTEM')
  117. return 0;
  118. },
  119. _emscripten_date_now() {
  120. return new Date().getTime()
  121. },
  122. // __emscripten_get_now_is_monotonic() {
  123. // return 1
  124. // },
  125. // _emscripten_get_now() {
  126. // return new Date().getTime()
  127. // },
  128. //加载微信wasm模块
  129. loadWxWasm() {
  130. let self = this
  131. let configParam = {}
  132. configParam.emscripten_memcpy_js = this._emscripten_memcpy_js
  133. configParam.emscripten_resize_heap = this._emscripten_resize_heap
  134. configParam.fd_write = this._fd_write
  135. configParam.fd_close = this._fd_close
  136. configParam.fd_seek = this._fd_seek
  137. configParam.emscripten_date_now = this._emscripten_date_now
  138. // configParam._emscripten_get_now_is_monotonic = this.__emscripten_get_now_is_monotonic
  139. // configParam.emscripten_get_now = this._emscripten_get_now
  140. let importObject = {}
  141. importObject.env = configParam
  142. importObject.wasi_snapshot_preview1 = configParam
  143. //返回值res:{instance{}, Module{}}:包含instance和Module对象,instance中也包含Module。
  144. //js使用instance或者Module中Exports对象中的函数(包括用户自定义的函数和系统函数)完成既定功能
  145. //instantiate的第一个参数为绝对路径
  146. WXWebAssembly.instantiate("wasm/aplm8000sdk.wasm", importObject).then((res) => {
  147. self.wasmInstance = res.instance
  148. self.wasmFuncs = this.wasmInstance.exports
  149. if (self.wasmInstance.exports['memory']) {//初始化内存
  150. let buf = self.wasmInstance.exports['memory'].buffer
  151. HEAP8 = new Int8Array(buf)
  152. HEAPU8 = new Uint8Array(buf)
  153. HEAP16 = new Int16Array(buf)
  154. HEAPU16 = new Uint16Array(buf)
  155. HEAP32 = new Int32Array(buf)
  156. HEAPU32 = new Uint32Array(buf)
  157. HEAPF32 = new Float32Array(buf)
  158. HEAPF64 = new Float64Array(buf)
  159. }
  160. //wasm模块初始化
  161. self.wasmFuncs.main()
  162. //获得wasm模块路由基站数据指针
  163. self.wasmDataPtr.bleBtsDataPtr = self.wasmFuncs.exchange_js_get_route_bts_save_address()
  164. //获得wasm模块安装基站的数据指针
  165. self.wasmDataPtr.installBtsDataPtr = self.wasmFuncs.exchange_js_get_install_bts_save_address()
  166. //获得wasm模块音频数据指针
  167. self.wasmDataPtr.audioDataPtr = self.wasmFuncs.exchange_js_get_audio_data_save_address()
  168. //获得wasm模块定位坐标数据指针
  169. self.wasmDataPtr.currentLocationCoordPtr = self.wasmFuncs.exchange_js_get_current_location_coord_save_address()
  170. //获得wasm模块加速度数据指针
  171. self.wasmDataPtr.accDataPtr = self.wasmFuncs.exchange_js_get_acc_save_address()
  172. //通知主控模块开始监听蓝牙基站
  173. worker.postMessage({
  174. message: 'WORKER_MAIN_START_MONITOR_BLE_BTS',
  175. data: ''
  176. })
  177. // //通知主控模块开始录音
  178. // worker.postMessage({
  179. // message: 'WORKER_MAIN_START_REC',
  180. // data: ''
  181. // })
  182. // //通知主控模块开始读取本地文件
  183. // worker.postMessage({
  184. // message: 'WORKER_MAIN_NOTICE_DOWNLOAD_AUDIO_FILE',
  185. // data: ''
  186. // })
  187. }).catch((err) => {
  188. console.log("加载wasm对象出错", err)
  189. })
  190. },
  191. //保存蓝牙基站数据至本地
  192. saveBleBtsDataToLocal(dataList) {
  193. if (!dataList || dataList.length < 4) {
  194. return
  195. }
  196. //蓝牙基站监听成功,保存数据
  197. this.data.bleBtsMonitorSuccessFlag = true//蓝牙基站监听成功
  198. this.data.bleBtsDataList.splice(0, this.data.bleBtsDataList.length)
  199. this.data.bleBtsDataList = dataList
  200. //通知主控模块注入安装基站数据(只注入一次)
  201. if (!this.data.installBtsInjectFlag) {
  202. worker.postMessage({
  203. message: 'WORKER_MAIN_ORGANIZE_INSTALL_BTS_DATA',//通知主线程组织安装基站数据
  204. data: ''
  205. })
  206. }
  207. },
  208. //清除蓝牙基站设备(没有监听到本系统的蓝牙基站)
  209. clearBleBtsData() {
  210. this.data.bleBtsMonitorSuccessFlag = false//蓝牙基站监听失败
  211. this.data.bleBtsDataList.splice(0, this.data.bleBtsDataList.length)
  212. },
  213. //发送蓝牙基站数据至wasm模块
  214. sendBleBtsDataToWasm() {
  215. let dataList = []
  216. //监听蓝牙基站失败
  217. if (!this.data.bleBtsMonitorSuccessFlag) {
  218. return
  219. }
  220. //将数据保存至wasm模块
  221. dataList = this.data.bleBtsDataList
  222. let dataLen = dataList.length
  223. if (this.wasmDataPtr.bleBtsDataPtr > 0) {
  224. let ptr = this.wasmDataPtr.bleBtsDataPtr / 4//蓝牙基站数据在wasm模块按4字节存储
  225. for (let i = 0; i < dataLen; i++) {
  226. HEAP32[ptr + i] = dataList[i]//写入数据
  227. }
  228. } else {
  229. console.log("蓝牙指针尚未初始化")
  230. }
  231. //清除本地蓝牙基站数据
  232. this.data.bleBtsDataList.splice(0, this.data.bleBtsDataList.length)
  233. this.data.bleBtsMonitorSuccessFlag = false
  234. // // //TODO,打印一下看看效果,正式版本要去掉
  235. // if (this.wasmFuncs != null) {
  236. // this.wasmFuncs.exchange_js_notice_wasm_show_route_bts();
  237. // }
  238. },
  239. //发送安装基站数据至wasm模块
  240. sendInstallBtsDataToWasm(dataList) {
  241. //将数据保存至wasm模块
  242. if (this.wasmDataPtr.installBtsDataPtr > 0) {
  243. this.data.installBtsInjectFlag = true//注入标识符置1
  244. //向wasm模块注入数据
  245. let ptr = this.wasmDataPtr.installBtsDataPtr / 4//蓝牙基站数据在wasm模块按4字节存储
  246. for (let i = 0; i < dataList.length; i++) {
  247. HEAP32[ptr + i] = dataList[i]
  248. }
  249. ////TODO 打印看看效果
  250. //this.wasmFuncs.exchange_js_notice_wasm_show_install_bts()
  251. //向主线程发消息开始录音
  252. worker.postMessage({
  253. message: 'WORKER_MAIN_START_REC',
  254. data: ''
  255. })
  256. }
  257. // // TODO,打印一下看看效果,正式版本要去掉
  258. // if (this.wasmFuncs != null) {
  259. // this.wasmFuncs.exchange_js_notice_wasm_show_install_bts()
  260. // }
  261. },
  262. //处理音频数据,实施定位操作
  263. //buffer:录音数据,为二进制单字节(byte)数据数组
  264. processAudioData(buffer) {
  265. //注入蓝牙基站数据
  266. this.sendBleBtsDataToWasm()
  267. ////创建数据视图。
  268. //录音数据是arraryBuffer类型,该类型数据为二进制单字节(byte)数据数组,不能直接读写,需要在buffer上创建数据视图后方可操作数据
  269. const dataView = new DataView(buffer);//创建一个数据视图
  270. //遍历数据视图
  271. let sample = 0
  272. let dataLen = Math.floor(dataView.byteLength / 2) //一个采样点为两个字节
  273. if (dataLen > 0) {
  274. //把数据插入全局队列,以便实施成帧处理
  275. for (let i = 0; i < dataLen; i++) {
  276. sample = dataView.getInt16(2 * i, true)//数据大小端模式,true:小端模式,false:大端模式
  277. this.data.audioDataList.push(sample)
  278. }
  279. //计算全局队列中数据的帧数
  280. let frameCounter = Math.floor(this.data.audioDataList.length / this.data.oneFrameLen)
  281. if (frameCounter) {//至少有一帧数据
  282. //截取音频数据帧(可能是1帧,也可能是多帧。若是多帧,有可能导致处理超时)
  283. const dataList = this.data.audioDataList.splice(0, frameCounter * this.data.oneFrameLen)
  284. //把音频数据逐帧注入wasm模块
  285. let ptr = this.wasmDataPtr.audioDataPtr / 2//音频数据在wasm模块中按2字节存储
  286. for (let i = 0; i < frameCounter; i++) {
  287. //let beginTime = new Date().getTime()//开始计时
  288. //1、把数据注入wasm模块
  289. let baseIndex = i * this.data.oneFrameLen
  290. for (let j = 0; j < this.data.oneFrameLen; j++) {
  291. let item = dataList[baseIndex + j]
  292. HEAP16[ptr + j] = item//把音频数据注入wasm模块
  293. }
  294. //2、注入加速度数据
  295. let oneFrameAccDataList = []
  296. oneFrameAccDataList = this.organizeOneFrameAccData()//组织一秒加速度数据
  297. this.injectAccDataToWasm(oneFrameAccDataList)//注入数据
  298. //3、通知wasm模块处理音频数据
  299. let result = this.wasmFuncs.exchange_js_notice_wasm_start_work()
  300. //let stopTime = new Date().getTime() - beginTime//结束计时
  301. //console.log("耗时:", stopTime)
  302. //4、获取wasm模块处理音频数据的结果
  303. if (result != 1) {
  304. console.log("音频数据处理错误")
  305. } else {
  306. let item = []
  307. //定位坐标数据在wasm模块中按4字节存储
  308. let locationCoordPtr = this.wasmDataPtr.currentLocationCoordPtr / 4
  309. //a、从wasm模块读取音频数据处理结果
  310. for (let i = 0; i < 18; i++) {
  311. item.push(HEAP32[locationCoordPtr + i])
  312. }
  313. //TODO,b、使用定位结果这部分,需要二次开放商根据业务需求,做定制开发
  314. //使用定位结果
  315. if (item[0] === 1 && item[1] === 1) {
  316. let coord = {}
  317. coord.x = item[2]
  318. coord.y = item[3]
  319. //imu移动标识符
  320. const imuMoveFlag = item[17]//0:惯导计算出错,1:惯导计算成功,但手机未移动,50:惯导计算能成功,手机有移动
  321. if (imuMoveFlag == 50) {//手机有移动
  322. //将定位坐标发送至主线程
  323. worker.postMessage({
  324. message: 'WORKER_MAIN_CURRENT_LOCATION_COORD',
  325. data: coord
  326. })
  327. } else {//手机未移动或者出错
  328. console.log("imu move flag:", imuMoveFlag)
  329. }
  330. }
  331. // //向主线程发消息,通知读取音频文件
  332. // worker.postMessage({
  333. // message: 'WORKER_MAIN_NOTICE_READ_AUDIO_FILE',//读取音频文件
  334. // data: ''
  335. // })
  336. }
  337. }
  338. }
  339. }
  340. return
  341. },
  342. //缓存加速度数据
  343. storeAccData(oneAccData) {
  344. let item = {}
  345. item.timestamp = oneAccData.timestamp
  346. item.x = oneAccData.x
  347. item.y = oneAccData.y
  348. item.z = oneAccData.z
  349. this.data.accDataList.push(item)//缓存加速度
  350. },
  351. //组织一帧加速度数据(约250毫秒)
  352. organizeOneFrameAccData() {
  353. let oneFrameAccData = [] //一帧加速度数据
  354. if (this.data.accDataList.length > 0) {
  355. let stopTimestamp = this.data.accDataList[0].timestamp + 260//250毫秒的数据
  356. let accCounter = 0//计数器
  357. for (let k = 0; k < this.data.accDataList.length; k++) {
  358. let oneAcc = {}
  359. oneAcc = this.data.accDataList[k]
  360. if (oneAcc.timestamp <= stopTimestamp) {
  361. oneFrameAccData.push(oneAcc)
  362. accCounter++
  363. } else {
  364. break
  365. }
  366. }
  367. this.data.accDataList = this.data.accDataList.slice(accCounter)//截取加速度队列
  368. }
  369. return oneFrameAccData
  370. },
  371. //注入加速度到wasm模块
  372. injectAccDataToWasm(dataList) {
  373. let ptr = this.wasmDataPtr.accDataPtr / 4//加速度数据在wasm模块中按4字节存储
  374. let wLen = dataList.length;
  375. let item = {}
  376. if (wLen > 0) {
  377. //注入队列长度
  378. HEAPU32[ptr] = wLen //加速度队列长度
  379. ptr++
  380. //注入3轴加速度
  381. for (let i = 0; i < wLen; i++) {
  382. item = dataList[i]
  383. ptr = ptr + i * 3//修改数据指针
  384. HEAPF32[ptr] = item.x//x轴加速度
  385. HEAPF32[ptr + 1] = item.y//y轴加速度
  386. HEAPF32[ptr + 2] = item.z//z轴加速度
  387. }
  388. //保存数据
  389. this.wasmFuncs.exchange_js_notice_wasm_save_acc()
  390. }
  391. },
  392. //通知wasm模块释放内存
  393. noticeWasmFreeMemory() {
  394. this.wasmFuncs.exchange_js_notice_wasm_free_memory()
  395. }
  396. }
  397. export default wasmapi