From 8706e767affc6bdc8cb7a67ca3a20a62779ff048 Mon Sep 17 00:00:00 2001
From: 雾聪 <wucong.lyb@alibaba-inc.com>
Date: 星期三, 17 五月 2023 15:45:46 +0800
Subject: [PATCH] Merge branch 'main' of https://github.com/alibaba-damo-academy/FunASR into main
---
funasr/runtime/onnxruntime/readme.md | 13
funasr/runtime/onnxruntime/src/funasr-onnx-offline-rtf.cpp | 20
funasr/runtime/html5/static/wsconnecter.js | 81 ++
docs/runtime/html5.md | 1
funasr/runtime/html5/readme.md | 109 ++
funasr/runtime/html5/static/pcm.js | 96 ++
docs/index.rst | 6
funasr/runtime/html5/static/index.html | 43 +
funasr/runtime/html5/server.crt | 15
funasr/runtime/python/websocket/ws_server_online.py | 18
funasr/runtime/html5/requirement.txt | 3
README.md | 5
funasr/runtime/html5/server.key | 15
funasr/runtime/html5/static/wav.js | 86 ++
funasr/runtime/html5/demo.gif | 0
funasr/runtime/html5/static/recorder-core.js | 1493 +++++++++++++++++++++++++++++++++++++
funasr/runtime/python/websocket/parse_args.py | 12
funasr/runtime/html5/readme_cn.md | 109 ++
docs/images/aihealthx.png | 0
funasr/runtime/html5/h5Server.py | 65 +
funasr/runtime/html5/static/main.js | 167 ++++
21 files changed, 2,345 insertions(+), 12 deletions(-)
diff --git a/README.md b/README.md
index e9c6ef9..996cde4 100644
--- a/README.md
+++ b/README.md
@@ -75,8 +75,8 @@
## Contributors
-| <div align="left"><img src="docs/images/damo.png" width="180"/> | <div align="left"><img src="docs/images/nwpu.png" width="260"/> | <img src="docs/images/China_Telecom.png" width="200"/> </div> | <img src="docs/images/RapidAI.png" width="200"/> </div> | <img src="docs/images/DeepScience.png" width="200"/> </div> |
-|:---------------------------------------------------------------:|:---------------------------------------------------------------:|:--------------------------------------------------------------:|:-------------------------------------------------------:|:-----------------------------------------------------------:|
+| <div align="left"><img src="docs/images/damo.png" width="180"/> | <div align="left"><img src="docs/images/nwpu.png" width="260"/> | <img src="docs/images/China_Telecom.png" width="200"/> </div> | <img src="docs/images/RapidAI.png" width="200"/> </div> | <img src="docs/images/DeepScience.png" width="200"/> </div> | <img src="docs/images/aihealthx.png" width="200"/> </div> |
+|:---------------------------------------------------------------:|:---------------------------------------------------------------:|:--------------------------------------------------------------:|:-------------------------------------------------------:|:-----------------------------------------------------------:|:-----------------------------------------------------------:|
## Acknowledge
@@ -86,6 +86,7 @@
4. We acknowledge [ChinaTelecom](https://github.com/zhuzizyf/damo-fsmn-vad-infer-httpserver) for contributing the VAD runtime.
5. We acknowledge [RapidAI](https://github.com/RapidAI) for contributing the Paraformer and CT_Transformer-punc runtime.
6. We acknowledge [DeepScience](https://www.deepscience.cn) for contributing the grpc service.
+6. We acknowledge [AiHealthx](http://www.aihealthx.com/) for contributing the websocket service and html5.
## License
This project is licensed under the [The MIT License](https://opensource.org/licenses/MIT). FunASR also contains various third-party components and some code modified from other repos under other open source licenses.
diff --git a/docs/images/aihealthx.png b/docs/images/aihealthx.png
new file mode 100644
index 0000000..5727c5b
--- /dev/null
+++ b/docs/images/aihealthx.png
Binary files differ
diff --git a/docs/index.rst b/docs/index.rst
index c2656bd..cb98f35 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -68,10 +68,12 @@
./runtime/onnxruntime_python.md
./runtime/onnxruntime_cpp.md
./runtime/libtorch_python.md
- ./runtime/grpc_python.md
- ./runtime/grpc_cpp.md
+ ./runtime/html5.md
./runtime/websocket_python.md
./runtime/websocket_cpp.md
+ ./runtime/grpc_python.md
+ ./runtime/grpc_cpp.md
+
.. toctree::
:maxdepth: 1
diff --git a/docs/runtime/html5.md b/docs/runtime/html5.md
new file mode 120000
index 0000000..bf47840
--- /dev/null
+++ b/docs/runtime/html5.md
@@ -0,0 +1 @@
+../../funasr/runtime/html5/readme.md
\ No newline at end of file
diff --git a/funasr/runtime/html5/demo.gif b/funasr/runtime/html5/demo.gif
new file mode 100644
index 0000000..f487f2c
--- /dev/null
+++ b/funasr/runtime/html5/demo.gif
Binary files differ
diff --git a/funasr/runtime/html5/h5Server.py b/funasr/runtime/html5/h5Server.py
new file mode 100644
index 0000000..fa79430
--- /dev/null
+++ b/funasr/runtime/html5/h5Server.py
@@ -0,0 +1,65 @@
+# -*- coding: utf-8 -*-
+###
+### Copyright FunASR (https://github.com/alibaba-damo-academy/FunASR). All Rights
+### Reserved. MIT License (https://opensource.org/licenses/MIT)
+###
+### 2022-2023 by zhaoming,mali aihealthx.com
+
+
+from flask import Flask,render_template,request,send_from_directory,jsonify
+#from gevent.pywsgi import WSGIServer
+
+import datetime
+import random
+import string
+import time
+import argparse
+
+
+app = Flask(__name__,static_folder='static',static_url_path="/static")
+
+@app.route('/')
+def homePage():
+ return render_template('recorderapp_test.html')
+
+
+parser = argparse.ArgumentParser()
+parser.add_argument("--host",
+ type=str,
+ default="0.0.0.0",
+ required=False,
+ help="host ip, localhost, 0.0.0.0")
+parser.add_argument("--port",
+ type=int,
+ default=1337,
+ required=False,
+ help="html5 server port")
+
+parser.add_argument("--certfile",
+ type=str,
+ default="server.crt",
+ required=False,
+ help="certfile for ssl")
+
+parser.add_argument("--keyfile",
+ type=str,
+ default="server.key",
+ required=False,
+ help="keyfile for ssl")
+
+if __name__ == '__main__':
+ args = parser.parse_args()
+ port=args.port
+
+ #WSGIServer
+ #ssl = {
+ # 'certfile': 'server.crt',
+ # 'keyfile': 'server.key'
+ #}
+ #httpsServer = WSGIServer(("0.0.0.0",port), app, **ssl)
+ #httpsServer.serve_forever()
+
+ #flask
+ print("srv run on ",port)
+
+ app.run(debug=True,host=args.host,port=port, ssl_context=(args.certfile,args.keyfile))
diff --git a/funasr/runtime/html5/readme.md b/funasr/runtime/html5/readme.md
new file mode 100644
index 0000000..5dd462b
--- /dev/null
+++ b/funasr/runtime/html5/readme.md
@@ -0,0 +1,109 @@
+# online asr demo for html5
+
+## requirement
+### python
+```shell
+flask
+gevent
+pyOpenSSL
+```
+
+### javascript
+[html5 recorder.js](https://github.com/xiangyuecn/Recorder)
+```shell
+Recorder
+```
+
+### demo
+
+
+## wss or ws protocol for ws_server_online
+1) wss: browser microphone data --> html5 demo server --> js wss api --> wss asr online srv #for certificate generation just look back
+
+2) ws: browser microphone data --> html5 demo server --> js wss api --> nginx wss server --> ws asr online srv
+
+## 1.html5 demo start
+### ssl certificate is required
+
+```shell
+usage: h5Server.py [-h] [--host HOST] [--port PORT] [--certfile CERTFILE]
+ [--keyfile KEYFILE]
+python h5Server.py --port 1337
+```
+## 2.asr online srv start
+[detail for online asr](https://github.com/alibaba-damo-academy/FunASR/tree/main/funasr/runtime/python/websocket)
+Online asr provides wss or ws way. if started in ws way, nginx is required for relay.
+### wss way, ssl certificate is required
+```shell
+python ws_server_online.py --certfile server.crt --keyfile server.key --port 5921
+```
+### ws way
+```shell
+python ws_server_online.py --port 5921
+```
+## 3.modify asr address in wsconnecter.js according to your environment
+asr address in wsconnecter.js must be wss, just like
+var Uri = "wss://xxx:xxx/"
+
+## 4.open browser to access html5 demo
+https://youraddress:port/static/index.html
+
+
+
+
+## certificate generation by yourself
+generated certificate may not suitable for all browsers due to security concerns. you'd better buy or download an authenticated ssl certificate from authorized agency.
+
+```shell
+### 1) Generate a private key
+openssl genrsa -des3 -out server.key 1024
+
+### 2) Generate a csr file
+openssl req -new -key server.key -out server.csr
+
+### 3) Remove pass
+cp server.key server.key.org
+openssl rsa -in server.key.org -out server.key
+
+### 4) Generated a crt file, valid for 1 year
+openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
+```
+
+## nginx configuration (you can skip it if you known)
+https and wss protocol are required by browsers when want to open microphone and websocket.
+if [online asr](https://github.com/alibaba-damo-academy/FunASR/tree/main/funasr/runtime/python/websocket) run in ws way, you should use nginx to convert wss to ws.
+### nginx wss->ws configuration example
+```shell
+events { [0/1548]
+ worker_connections 1024;
+ accept_mutex on;
+ }
+http {
+ error_log error.log;
+ access_log access.log;
+ server {
+
+ listen 5921 ssl http2; # nginx listen port for wss
+ server_name www.test.com;
+
+ ssl_certificate /funasr/server.crt;
+ ssl_certificate_key /funasr/server.key;
+ ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
+ ssl_ciphers HIGH:!aNULL:!MD5;
+
+ location /wss/ {
+
+
+ proxy_pass http://127.0.0.1:1111/; # asr online model ws address and port
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+ proxy_read_timeout 600s;
+
+ }
+ }
+```
+
+## Acknowledge
+1. This project is maintained by [FunASR community](https://github.com/alibaba-damo-academy/FunASR).
+2. We acknowledge [AiHealthx](http://www.aihealthx.com/) for contributing the html5 demo.
\ No newline at end of file
diff --git a/funasr/runtime/html5/readme_cn.md b/funasr/runtime/html5/readme_cn.md
new file mode 100644
index 0000000..612dc20
--- /dev/null
+++ b/funasr/runtime/html5/readme_cn.md
@@ -0,0 +1,109 @@
+# online asr demo for html5
+
+## requirement
+### python
+```shell
+flask
+gevent
+pyOpenSSL
+```
+
+### javascript
+[html5褰曢煶](https://github.com/xiangyuecn/Recorder)
+```shell
+Recorder
+```
+
+### demo椤甸潰濡備笅
+
+
+## 涓ょws_server_online杩炴帴妯″紡
+### 1)鐩存帴杩炴帴妯″紡锛屾祻瑙堝櫒https楹﹀厠椋� --> html5 demo鏈嶅姟 --> js wss鎺ュ彛 --> wss asr online srv(璇佷功鐢熸垚璇峰線鍚庣湅)
+
+### 2)nginx涓浆锛屾祻瑙堝櫒https楹﹀厠椋� --> html5 demo鏈嶅姟 --> js wss鎺ュ彛 --> nginx鏈嶅姟 --> ws asr online srv
+
+## 1.html5 demo鏈嶅姟鍚姩
+### 鍚姩html5鏈嶅姟锛岄渶瑕乻sl璇佷功(鑷繁鐢熸垚璇峰線鍚庣湅)
+
+```shell
+usage: h5Server.py [-h] [--host HOST] [--port PORT] [--certfile CERTFILE]
+ [--keyfile KEYFILE]
+python h5Server.py --port 1337
+```
+## 2.鍚姩ws or wss asr online srv
+[鍏蜂綋璇风湅online asr](https://github.com/alibaba-damo-academy/FunASR/tree/main/funasr/runtime/python/websocket)
+online asr鎻愪緵涓ょws鍜寃ss妯″紡锛寃ss妯″紡鍙互鐩存帴鍚姩锛屾棤闇�nginx涓浆銆傚惁鍒欓渶瑕侀�氳繃nginx灏唚ss杞彂鍒拌online asr鐨剋s绔彛涓�
+### wss鏂瑰紡
+```shell
+python ws_server_online.py --certfile server.crt --keyfile server.key --port 5921
+```
+### ws鏂瑰紡
+```shell
+python ws_server_online.py --port 5921
+```
+## 3.淇敼wsconnecter.js閲宎sr鎺ュ彛鍦板潃
+wsconnecter.js閲岄厤缃畂nline asr鏈嶅姟鍦板潃璺緞锛岃繖閲岄厤缃殑鏄痺ss绔彛
+var Uri = "wss://xxx:xxx/"
+
+## 4.娴忚鍣ㄦ墦寮�鍦板潃娴嬭瘯
+https://127.0.0.1:1337/static/index.html
+
+
+
+
+## 鑷鐢熸垚璇佷功
+鐢熸垚璇佷功(娉ㄦ剰杩欑璇佷功骞朵笉鑳借鎵�鏈夋祻瑙堝櫒璁ゅ彲锛岄儴鍒嗘墜鍔ㄦ巿鏉冨彲浠ヨ闂�,鏈�濂戒娇鐢ㄥ叾浠栬璇佺殑瀹樻柟ssl璇佷功)
+
+```shell
+### 1)鐢熸垚绉侀挜锛屾寜鐓ф彁绀哄~鍐欏唴瀹�
+openssl genrsa -des3 -out server.key 1024
+
+### 2)鐢熸垚csr鏂囦欢 锛屾寜鐓ф彁绀哄~鍐欏唴瀹�
+openssl req -new -key server.key -out server.csr
+
+### 鍘绘帀pass
+cp server.key server.key.org
+openssl rsa -in server.key.org -out server.key
+
+### 鐢熸垚crt鏂囦欢锛屾湁鏁堟湡1骞达紙365澶╋級
+openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
+```
+
+## nginx閰嶇疆璇存槑(浜嗚В鐨勫彲浠ヨ烦杩�)
+h5鎵撳紑楹﹀厠椋庨渶瑕乭ttps鍗忚锛屽悓鏃跺悗绔殑asr websocket涔熷繀椤绘槸wss鍗忚锛屽鏋淸online asr](https://github.com/alibaba-damo-academy/FunASR/tree/main/funasr/runtime/python/websocket)浠s鏂瑰紡杩愯锛屾垜浠彲浠ラ�氳繃nginx閰嶇疆瀹炵幇wss鍗忚鍒皐s鍗忚鐨勮浆鎹€��
+
+### nginx杞彂閰嶇疆绀轰緥
+```shell
+events { [0/1548]
+ worker_connections 1024;
+ accept_mutex on;
+ }
+http {
+ error_log error.log;
+ access_log access.log;
+ server {
+
+ listen 5921 ssl http2; # nginx listen port for wss
+ server_name www.test.com;
+
+ ssl_certificate /funasr/server.crt;
+ ssl_certificate_key /funasr/server.key;
+ ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
+ ssl_ciphers HIGH:!aNULL:!MD5;
+
+ location /wss/ {
+
+
+ proxy_pass http://127.0.0.1:1111/; # asr online model ws address and port
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+ proxy_read_timeout 600s;
+
+ }
+ }
+```
+
+## Acknowledge
+1. This project is maintained by [FunASR community](https://github.com/alibaba-damo-academy/FunASR).
+2. We acknowledge [AiHealthx](http://www.aihealthx.com/) for contributing the html5 demo.
\ No newline at end of file
diff --git a/funasr/runtime/html5/requirement.txt b/funasr/runtime/html5/requirement.txt
new file mode 100644
index 0000000..7f8721a
--- /dev/null
+++ b/funasr/runtime/html5/requirement.txt
@@ -0,0 +1,3 @@
+flask
+gevent
+pyOpenSSL
diff --git a/funasr/runtime/html5/server.crt b/funasr/runtime/html5/server.crt
new file mode 100644
index 0000000..808b73e
--- /dev/null
+++ b/funasr/runtime/html5/server.crt
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICSDCCAbECFCObiVAMkMlCGmMDGDFx5Nx3XYvOMA0GCSqGSIb3DQEBCwUAMGMx
+CzAJBgNVBAYTAkNOMRAwDgYDVQQIDAdCZWlqaW5nMRAwDgYDVQQHDAdCZWlqaW5n
+MRAwDgYDVQQKDAdhbGliYWJhMQwwCgYDVQQLDANhc3IxEDAOBgNVBAMMB2FsaWJh
+YmEwHhcNMjMwNTEyMTQzNjAxWhcNMjQwNTExMTQzNjAxWjBjMQswCQYDVQQGEwJD
+TjEQMA4GA1UECAwHQmVpamluZzEQMA4GA1UEBwwHQmVpamluZzEQMA4GA1UECgwH
+YWxpYmFiYTEMMAoGA1UECwwDYXNyMRAwDgYDVQQDDAdhbGliYWJhMIGfMA0GCSqG
+SIb3DQEBAQUAA4GNADCBiQKBgQDEINLLMasJtJQPoesCfcwJsjiUkx3hLnoUyETS
+NBrrRfjbBv6ucAgZIF+/V15IfJZR6u2ULpJN0wUg8xNQReu4kdpjSdNGuQ0aoWbc
+38+VLo9UjjsoOeoeCro6b0u+GosPoEuI4t7Ky09zw+FBibD95daJ3GDY1DGCbDdL
+mV/toQIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAB5KNWF1XIIYD1geMsyT6/ZRnGNA
+dmeUyMcwYvIlQG3boSipNk/JI4W5fFOg1O2sAqflYHmwZfmasAQsC2e5bSzHZ+PB
+uMJhKYxfj81p175GumHTw5Lbp2CvFSLrnuVB0ThRdcCqEh1MDt0D3QBuBr/ZKgGS
+hXtozVCgkSJzX6uD
+-----END CERTIFICATE-----
diff --git a/funasr/runtime/html5/server.key b/funasr/runtime/html5/server.key
new file mode 100644
index 0000000..aac8b26
--- /dev/null
+++ b/funasr/runtime/html5/server.key
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDEINLLMasJtJQPoesCfcwJsjiUkx3hLnoUyETSNBrrRfjbBv6u
+cAgZIF+/V15IfJZR6u2ULpJN0wUg8xNQReu4kdpjSdNGuQ0aoWbc38+VLo9Ujjso
+OeoeCro6b0u+GosPoEuI4t7Ky09zw+FBibD95daJ3GDY1DGCbDdLmV/toQIDAQAB
+AoGARpA0pwygp+ZDWvh7kDLoZRitCK+BkZHiNHX1ZNeAU+Oh7FOw79u43ilqqXHq
+pxPEFYb7oVO8Kanhb4BlE32EmApBlvhd3SW07kn0dS7WVGsTvPFwKKpF88W8E+pc
+2i8At5tr2O1DZhvqNdIN7r8FRrGQ/Hpm3ItypUdz2lZnMwECQQD3dILOMJ84O2JE
+NxUwk8iOYefMJftQUO57Gm7XBVke/i3r9uajSqB2xmOvUaSyaHoJfx/mmfgfxYcD
+M+Re6mERAkEAyuaV5+eD82eG2I8PgxJ2p5SOb1x5F5qpb4KuKAlfHEkdolttMwN3
+7vl1ZWUZLVu2rHnUmvbYV2gkQO1os7/DkQJBAIDYfbN2xbC12vjB5ZqhmG/qspMt
+w6mSOlqG7OewtTLaDncq2/RySxMNQaJr1GHA3KpNMwMTcIq6gw472tFBIMECQF0z
+fjiASEROkcp4LI/ws0BXJPZSa+1DxgDK7mTFqUK88zfY91gvh6/mNt7UibQkJM0l
+SVvFd6ru03hflXC77YECQQDDQrB9ApwVOMGQw+pwbxn9p8tPYVi3oBiUfYgd1RDO
+uhcRgxv7gT4BSiyI4nFBMCYyI28azTLlUiJhMr9MNUpB
+-----END RSA PRIVATE KEY-----
diff --git a/funasr/runtime/html5/static/index.html b/funasr/runtime/html5/static/index.html
new file mode 100644
index 0000000..1cdc7d7
--- /dev/null
+++ b/funasr/runtime/html5/static/index.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width,initial-scale=1" />
+ <title>璇煶璇嗗埆</title>
+
+ </head>
+ <body style="margin-left: 3%">
+ <script src="recorder-core.js" charset="UTF-8"></script>
+ <script src="wav.js" charset="UTF-8"></script>
+ <script src="pcm.js" charset="UTF-8"></script>
+
+
+
+
+ <div class="div_class_topArea">
+
+ <div class="div_class_recordControl">
+ 璇煶璇嗗埆缁撴灉鏄剧ず锛�
+ <br>
+
+ <textarea rows="10" id="varArea" readonly="true" style=" width: 100%;height:100%" ></textarea>
+ <br>
+ <div id="info_div">璇风偣鍑诲紑濮�</div>
+ <div class="div_class_buttons">
+ <button id="btnStart">寮�濮�</button>
+ <button id="btnStop">鍋滄</button>
+
+ </div>
+
+ <audio id="audio_record" type="audio/wav" controls style="margin-top: 12px; width: 100%;"></audio>
+ </div>
+ </div>
+
+ <script src="wsconnecter.js" charset="utf-8"></script>
+ <script src="main.js" charset="utf-8"></script>
+
+
+
+
+ </body>
+</html>
diff --git a/funasr/runtime/html5/static/main.js b/funasr/runtime/html5/static/main.js
new file mode 100644
index 0000000..5f6bb10
--- /dev/null
+++ b/funasr/runtime/html5/static/main.js
@@ -0,0 +1,167 @@
+/**
+ * Copyright FunASR (https://github.com/alibaba-damo-academy/FunASR). All Rights
+ * Reserved. MIT License (https://opensource.org/licenses/MIT)
+ */
+/* 2022-2023 by zhaoming,mali aihealthx.com */
+
+
+// 杩炴帴; 瀹氫箟socket杩炴帴绫诲璞′笌璇煶瀵硅薄
+var wsconnecter = new WebSocketConnectMethod({msgHandle:getJsonMessage,stateHandle:getConnState});
+var audioBlob;
+
+// 褰曢煶; 瀹氫箟褰曢煶瀵硅薄,wav鏍煎紡
+var rec = Recorder({
+ type:"pcm",
+ bitRate:16,
+ sampleRate:16000,
+ onProcess:recProcess
+});
+
+
+
+
+var sampleBuf=new Int16Array();
+// 瀹氫箟鎸夐挳鍝嶅簲浜嬩欢
+var btnStart = document.getElementById('btnStart');
+btnStart.onclick = start;
+var btnStop = document.getElementById('btnStop');
+btnStop.onclick = stop;
+btnStop.disabled = true;
+
+
+
+var rec_text=""
+var info_div = document.getElementById('info_div');
+
+
+// 璇煶璇嗗埆缁撴灉; 瀵筳sonMsg鏁版嵁瑙f瀽,灏嗚瘑鍒粨鏋滈檮鍔犲埌缂栬緫妗嗕腑
+function getJsonMessage( jsonMsg ) {
+ console.log( "message: " + JSON.parse(jsonMsg.data)['text'] );
+ var rectxt=""+JSON.parse(jsonMsg.data)['text'];
+ var varArea=document.getElementById('varArea');
+ rec_text=rec_text+rectxt.replace(/ +/g,"");
+ varArea.value=rec_text;
+
+
+}
+
+// 杩炴帴鐘舵�佸搷搴�
+function getConnState( connState ) {
+ if ( connState === 0 ) {
+
+ rec.open( function(){
+ rec.start();
+ console.log("寮�濮嬪綍闊�");
+
+ });
+ } else if ( connState === 1 ) {
+ //stop();
+ } else if ( connState === 2 ) {
+ stop();
+ console.log( 'connecttion error' );
+ setTimeout(function(){btnStart.disabled = true;info_div.innerHTML='connecttion error';}, 4000 );
+ }
+}
+
+
+// 璇嗗埆鍚姩銆佸仠姝€�佹竻绌烘搷浣�
+function start() {
+ info_div.innerHTML="姝e湪杩炴帴asr鏈嶅姟鍣紝璇风瓑寰�...";
+ // 娓呴櫎鏄剧ず
+ clear();
+ //鎺т欢鐘舵�佹洿鏂�
+
+ isRec = true;
+ btnStart.disabled = true;
+ btnStop.disabled = false;
+ //鍚姩杩炴帴
+ wsconnecter.wsStart();
+}
+
+
+function stop() {
+ var chunk_size = new Array( 5, 10, 5 );
+ var request = {
+ "chunk_size": chunk_size,
+ "wav_name": "h5",
+ "is_speaking": false,
+ "chunk_interval":10,
+ };
+ if(sampleBuf.length>0){
+ wsconnecter.wsSend(sampleBuf,false);
+ console.log("sampleBuf.length"+sampleBuf.length);
+ sampleBuf=new Int16Array();
+ }
+ wsconnecter.wsSend( JSON.stringify(request) ,false);
+
+
+
+
+
+
+ // 鎺т欢鐘舵�佹洿鏂�
+ isRec = false;
+ info_div.innerHTML="璇风瓑鍊�...";
+ btnStop.disabled = true;
+ setTimeout(function(){btnStart.disabled = false;info_div.innerHTML="璇风偣鍑诲紑濮�";}, 3000 );
+ rec.stop(function(blob,duration){
+
+ console.log(blob);
+ var audioBlob = Recorder.pcm2wav(data = {sampleRate:16000, bitRate:16, blob:blob},
+ function(theblob,duration){
+ console.log(theblob);
+ var audio_record = document.getElementById('audio_record');
+ audio_record.src = (window.URL||webkitURL).createObjectURL(theblob);
+ audio_record.controls=true;
+ audio_record.play();
+
+
+ } ,function(msg){
+ console.log(msg);
+ }
+ );
+
+
+
+ },function(errMsg){
+ console.log("errMsg: " + errMsg);
+ });
+ // 鍋滄杩炴帴
+
+
+
+}
+
+function clear() {
+
+ var varArea=document.getElementById('varArea');
+
+ varArea.value="";
+ rec_text="";
+
+}
+
+
+function recProcess( buffer, powerLevel, bufferDuration, bufferSampleRate,newBufferIdx,asyncEnd ) {
+ if ( isRec === true ) {
+ var data_48k = buffer[buffer.length-1];
+
+ var array_48k = new Array(data_48k);
+ var data_16k=Recorder.SampleData(array_48k,bufferSampleRate,16000).data;
+
+ sampleBuf = Int16Array.from([...sampleBuf, ...data_16k]);
+ var chunk_size=960; // for asr chunk_size [5, 10, 5]
+ info_div.innerHTML=""+bufferDuration/1000+"s";
+ while(sampleBuf.length>=chunk_size){
+ sendBuf=sampleBuf.slice(0,chunk_size);
+ sampleBuf=sampleBuf.slice(chunk_size,sampleBuf.length);
+ wsconnecter.wsSend(sendBuf,false);
+
+
+
+ }
+
+
+
+ }
+}
\ No newline at end of file
diff --git a/funasr/runtime/html5/static/pcm.js b/funasr/runtime/html5/static/pcm.js
new file mode 100644
index 0000000..51c1efe
--- /dev/null
+++ b/funasr/runtime/html5/static/pcm.js
@@ -0,0 +1,96 @@
+/*
+pcm缂栫爜鍣�+缂栫爜寮曟搸
+https://github.com/xiangyuecn/Recorder
+
+缂栫爜鍘熺悊锛氭湰缂栫爜鍣ㄨ緭鍑虹殑pcm鏍煎紡鏁版嵁鍏跺疄灏辨槸Recorder涓殑buffers鍘熷鏁版嵁锛堢粡杩囦簡閲嶆柊閲囨牱锛夛紝16浣嶆椂涓篖E灏忕妯″紡锛圠ittle Endian锛夛紝骞舵湭缁忚繃浠讳綍缂栫爜澶勭悊
+
+缂栫爜鐨勪唬鐮佸拰wav.js鍖哄埆涓嶅ぇ锛宲cm鍔犱笂涓�涓�44瀛楄妭wav澶村嵆鎴恮av鏂囦欢锛涙墍浠ヨ鎾斁pcm灏卞緢绠�鍗曚簡锛岀洿鎺ヨ浆鎴恮av鏂囦欢鏉ユ挱鏀撅紝宸叉彁渚涜浆鎹㈠嚱鏁� Recorder.pcm2wav
+*/
+(function(){
+"use strict";
+
+Recorder.prototype.enc_pcm={
+ stable:true
+ ,testmsg:"pcm涓烘湭灏佽鐨勫師濮嬮煶棰戞暟鎹紝pcm鏁版嵁鏂囦欢鏃犳硶鐩存帴鎾斁锛涙敮鎸佷綅鏁�8浣嶃��16浣嶏紙濉湪姣旂壒鐜囬噷闈級锛岄噰鏍风巼鍙栧�兼棤闄愬埗"
+};
+Recorder.prototype.pcm=function(res,True,False){
+ var This=this,set=This.set
+ ,size=res.length
+ ,bitRate=set.bitRate==8?8:16;
+
+ var buffer=new ArrayBuffer(size*(bitRate/8));
+ var data=new DataView(buffer);
+ var offset=0;
+
+ // 鍐欏叆閲囨牱鏁版嵁
+ if(bitRate==8) {
+ for(var i=0;i<size;i++,offset++) {
+ //16杞�8鎹鏄浄闇勯獏鐨� https://blog.csdn.net/sevennight1989/article/details/85376149 缁嗚妭姣攂lqw鐨勬寜姣斾緥鐨勭畻娉曟竻鏅扮偣锛岃櫧鐒堕兘鏈夋槑鏄炬潅闊�
+ var val=(res[i]>>8)+128;
+ data.setInt8(offset,val,true);
+ };
+ }else{
+ for (var i=0;i<size;i++,offset+=2){
+ data.setInt16(offset,res[i],true);
+ };
+ };
+
+
+ True(new Blob([data.buffer],{type:"audio/pcm"}));
+ };
+
+
+
+
+
+/**pcm鐩存帴杞爜鎴恮av锛屽彲浠ョ洿鎺ョ敤鏉ユ挱鏀撅紱闇�鍚屾椂寮曞叆wav.js
+data: {
+ sampleRate:16000 pcm鐨勯噰鏍风巼
+ bitRate:16 pcm鐨勪綅鏁� 鍙栧�硷細8 鎴� 16
+ blob:blob瀵硅薄
+ }
+ data濡傛灉鐩存帴鎻愪緵鐨刡lob灏嗛粯璁や娇鐢�16浣�16khz鐨勯厤缃紝浠呯敤浜庢祴璇�
+True(wavBlob,duration)
+False(msg)
+**/
+Recorder.pcm2wav=function(data,True,False){
+ if(data.slice && data.type!=null){//Blob 娴嬭瘯鐢�
+ data={blob:data};
+ };
+ var sampleRate=data.sampleRate||16000,bitRate=data.bitRate||16;
+ if(!data.sampleRate || !data.bitRate){
+ console.warn("pcm2wav蹇呴』鎻愪緵sampleRate鍜宐itRate");
+ };
+ if(!Recorder.prototype.wav){
+ False("pcm2wav蹇呴』鍏堝姞杞絯av缂栫爜鍣╳av.js");
+ return;
+ };
+
+ var reader=new FileReader();
+ reader.onloadend=function(){
+ var pcm;
+ if(bitRate==8){
+ //8浣嶈浆鎴�16浣�
+ var u8arr=new Uint8Array(reader.result);
+ pcm=new Int16Array(u8arr.length);
+ for(var j=0;j<u8arr.length;j++){
+ pcm[j]=(u8arr[j]-128)<<8;
+ };
+ }else{
+ pcm=new Int16Array(reader.result);
+ };
+
+ Recorder({
+ type:"wav"
+ ,sampleRate:sampleRate
+ ,bitRate:bitRate
+ }).mock(pcm,sampleRate).stop(function(wavBlob,duration){
+ True(wavBlob,duration);
+ },False);
+ };
+ reader.readAsArrayBuffer(data.blob);
+};
+
+
+
+})();
\ No newline at end of file
diff --git a/funasr/runtime/html5/static/recorder-core.js b/funasr/runtime/html5/static/recorder-core.js
new file mode 100644
index 0000000..97ec12c
--- /dev/null
+++ b/funasr/runtime/html5/static/recorder-core.js
@@ -0,0 +1,1493 @@
+/*
+褰曢煶
+https://github.com/xiangyuecn/Recorder
+*/
+(function(factory){
+ factory(window);
+ //umd returnExports.js
+ if(typeof(define)=='function' && define.amd){
+ define(function(){
+ return Recorder;
+ });
+ };
+ if(typeof(module)=='object' && module.exports){
+ module.exports=Recorder;
+ };
+}(function(window){
+"use strict";
+
+var NOOP=function(){};
+
+var Recorder=function(set){
+ return new initFn(set);
+};
+Recorder.LM="2023-02-01 18:05";
+var RecTxt="Recorder";
+var getUserMediaTxt="getUserMedia";
+var srcSampleRateTxt="srcSampleRate";
+var sampleRateTxt="sampleRate";
+var CatchTxt="catch";
+
+
+//鏄惁宸茬粡鎵撳紑浜嗗叏灞�鐨勯害鍏嬮褰曢煶锛屾墍鏈夊伐浣滈兘宸茬粡鍑嗗濂戒簡锛屽氨绛夋帴鏀堕煶棰戞暟鎹簡
+Recorder.IsOpen=function(){
+ var stream=Recorder.Stream;
+ if(stream){
+ var tracks=stream.getTracks&&stream.getTracks()||stream.audioTracks||[];
+ var track=tracks[0];
+ if(track){
+ var state=track.readyState;
+ return state=="live"||state==track.LIVE;
+ };
+ };
+ return false;
+};
+/*H5褰曢煶鏃剁殑AudioContext缂撳啿澶у皬銆備細褰卞搷H5褰曢煶鏃剁殑onProcess璋冪敤閫熺巼锛岀浉瀵逛簬AudioContext.sampleRate=48000鏃讹紝4096鎺ヨ繎12甯�/s锛岃皟鑺傛鍙傛暟鍙敓鎴愭瘮杈冩祦鐣呯殑鍥炶皟鍔ㄧ敾銆�
+ 鍙栧��256, 512, 1024, 2048, 4096, 8192, or 16384
+ 娉ㄦ剰锛屽彇鍊间笉鑳借繃浣庯紝2048寮�濮嬩笉鍚屾祻瑙堝櫒鍙兘鍥炶皟閫熺巼璺熶笉涓婇�犳垚闊宠川闂銆�
+ 涓�鑸棤闇�璋冩暣锛岃皟鏁村悗闇�瑕佸厛close鎺夊凡鎵撳紑鐨勫綍闊筹紝鍐峯pen鏃舵墠浼氱敓鏁堛��
+*/
+Recorder.BufferSize=4096;
+//閿�姣佸凡鎸佹湁鐨勬墍鏈夊叏灞�璧勬簮锛屽綋瑕佸交搴曠Щ闄ecorder鏃堕渶瑕佹樉寮忕殑璋冪敤姝ゆ柟娉�
+Recorder.Destroy=function(){
+ CLog(RecTxt+" Destroy");
+ Disconnect();//鏂紑鍙兘瀛樺湪鐨勫叏灞�Stream銆佽祫婧�
+
+ for(var k in DestroyList){
+ DestroyList[k]();
+ };
+};
+var DestroyList={};
+//鐧昏涓�涓渶瑕侀攢姣佸叏灞�璧勬簮鐨勫鐞嗘柟娉�
+Recorder.BindDestroy=function(key,call){
+ DestroyList[key]=call;
+};
+//鍒ゆ柇娴忚鍣ㄦ槸鍚︽敮鎸佸綍闊筹紝闅忔椂鍙互璋冪敤銆傛敞鎰忥細浠呬粎鏄娴嬫祻瑙堝櫒鏀寔鎯呭喌锛屼笉浼氬垽鏂拰璋冭捣鐢ㄦ埛鎺堟潈锛屼笉浼氬垽鏂槸鍚︽敮鎸佺壒瀹氭牸寮忓綍闊炽��
+Recorder.Support=function(){
+ var scope=navigator.mediaDevices||{};
+ if(!scope[getUserMediaTxt]){
+ scope=navigator;
+ scope[getUserMediaTxt]||(scope[getUserMediaTxt]=scope.webkitGetUserMedia||scope.mozGetUserMedia||scope.msGetUserMedia);
+ };
+ if(!scope[getUserMediaTxt]){
+ return false;
+ };
+ Recorder.Scope=scope;
+
+ if(!Recorder.GetContext()){
+ return false;
+ };
+ return true;
+};
+//鑾峰彇鍏ㄥ眬鐨凙udioContext瀵硅薄锛屽鏋滄祻瑙堝櫒涓嶆敮鎸佸皢杩斿洖null
+Recorder.GetContext=function(){
+ var AC=window.AudioContext;
+ if(!AC){
+ AC=window.webkitAudioContext;
+ };
+ if(!AC){
+ return null;
+ };
+
+ if(!Recorder.Ctx||Recorder.Ctx.state=="closed"){
+ //涓嶈兘鍙嶅鏋勯�狅紝浣庣増鏈琻umber of hardware contexts reached maximum (6)
+ Recorder.Ctx=new AC();
+
+ Recorder.BindDestroy("Ctx",function(){
+ var ctx=Recorder.Ctx;
+ if(ctx&&ctx.close){//鑳藉叧鎺夊氨鍏虫帀锛屽叧涓嶆帀灏变繚鐣欑潃
+ ctx.close();
+ Recorder.Ctx=0;
+ };
+ });
+ };
+ return Recorder.Ctx;
+};
+
+
+/*鏄惁鍚敤MediaRecorder.WebM.PCM鏉ヨ繘琛岄煶棰戦噰闆嗚繛鎺ワ紙濡傛灉娴忚鍣ㄦ敮鎸佺殑璇濓級锛岄粯璁ゅ惎鐢紝绂佺敤鎴栬�呬笉鏀寔鏃跺皢浣跨敤AudioWorklet鎴朣criptProcessor鏉ヨ繛鎺ワ紱MediaRecorder閲囬泦鍒扮殑闊抽鏁版嵁姣斿叾浠栨柟寮忔洿濂斤紝鍑犱箮涓嶅瓨鍦ㄤ涪甯х幇璞★紝鎵�浠ラ煶璐ㄦ槑鏄句細濂藉緢澶氾紝寤鸿淇濇寔寮�鍚�*/
+var ConnectEnableWebM="ConnectEnableWebM";
+Recorder[ConnectEnableWebM]=true;
+
+/*鏄惁鍚敤AudioWorklet鐗规�ф潵杩涜闊抽閲囬泦杩炴帴锛堝鏋滄祻瑙堝櫒鏀寔鐨勮瘽锛夛紝榛樿绂佺敤锛岀鐢ㄦ垨涓嶆敮鎸佹椂灏嗕娇鐢ㄨ繃鏃剁殑ScriptProcessor鏉ヨ繛鎺ワ紙濡傛灉鏂规硶杩樺湪鐨勮瘽锛夛紝褰撳墠AudioWorklet鐨勫疄鐜板湪绉诲姩绔病鏈塖criptProcessor绋冲仴锛汣onnectEnableWebM濡傛灉鍚敤骞朵笖鏈夋晥鏃讹紝鏈弬鏁板皢涓嶈捣浣滅敤*/
+var ConnectEnableWorklet="ConnectEnableWorklet";
+Recorder[ConnectEnableWorklet]=false;
+
+/*鍒濆鍖朒5闊抽閲囬泦杩炴帴銆傚鏋滆嚜琛屾彁渚涗簡sourceStream灏嗗彧杩涜涓�娆$畝鍗曠殑杩炴帴澶勭悊銆傚鏋滄槸鏅�氶害鍏嬮褰曢煶锛屾鏃剁殑Stream鏄叏灞�鐨勶紝Safari涓婃柇寮�鍚庡氨鏃犳硶鍐嶆杩涜杩炴帴浣跨敤锛岃〃鐜颁负闈欓煶锛屽洜姝や娇鐢ㄥ叏閮ㄤ娇鐢ㄥ叏灞�澶勭悊閬垮厤璋冪敤鍒癲isconnect锛涘叏灞�澶勭悊涔熸湁鍒╀簬灞忚斀搴曞眰缁嗚妭锛宻tart鏃舵棤闇�鍐嶈皟鐢ㄥ簳灞傛帴鍙o紝鎻愬崌鍏煎銆佸彲闈犳�с��*/
+var Connect=function(streamStore,isUserMedia){
+ var bufferSize=streamStore.BufferSize||Recorder.BufferSize;
+
+ var ctx=Recorder.Ctx,stream=streamStore.Stream;
+ var mediaConn=function(node){
+ var media=stream._m=ctx.createMediaStreamSource(stream);
+ var ctxDest=ctx.destination,cmsdTxt="createMediaStreamDestination";
+ if(ctx[cmsdTxt]){
+ ctxDest=ctx[cmsdTxt]();
+ };
+ media.connect(node);
+ node.connect(ctxDest);
+ }
+ var isWebM,isWorklet,badInt,webMTips="";
+ var calls=stream._call;
+
+ //娴忚鍣ㄥ洖浼犵殑闊抽鏁版嵁澶勭悊
+ var onReceive=function(float32Arr){
+ for(var k0 in calls){//has item
+ var size=float32Arr.length;
+
+ var pcm=new Int16Array(size);
+ var sum=0;
+ for(var j=0;j<size;j++){//floatTo16BitPCM
+ var s=Math.max(-1,Math.min(1,float32Arr[j]));
+ s=s<0?s*0x8000:s*0x7FFF;
+ pcm[j]=s;
+ sum+=Math.abs(s);
+ };
+
+ for(var k in calls){
+ calls[k](pcm,sum);
+ };
+
+ return;
+ };
+ };
+
+ var scriptProcessor="ScriptProcessor";//涓�鍫嗗瓧绗︿覆鍚嶅瓧锛屾湁鍒╀簬鍘嬬缉js
+ var audioWorklet="audioWorklet";
+ var recAudioWorklet=RecTxt+" "+audioWorklet;
+ var RecProc="RecProc";
+ var MediaRecorderTxt="MediaRecorder";
+ var MRWebMPCM=MediaRecorderTxt+".WebM.PCM";
+
+
+//===================杩炴帴鏂瑰紡涓�=========================
+ //鍙よ懀绾у埆鐨� ScriptProcessor 澶勭悊锛岀洰鍓嶆墍鏈夋祻瑙堝櫒鍧囧吋瀹癸紝铏界劧鏄繃鏃剁殑鏂规硶锛屼絾鏇寸ǔ鍋ワ紝绉诲姩绔�ц兘姣擜udioWorklet寮�
+ var oldFn=ctx.createScriptProcessor||ctx.createJavaScriptNode;
+ var oldIsBest="銆傜敱浜�"+audioWorklet+"鍐呴儴1绉�375娆″洖璋冿紝鍦ㄧЩ鍔ㄧ鍙兘浼氭湁鎬ц兘闂瀵艰嚧鍥炶皟涓㈠け褰曢煶鍙樼煭锛孭C绔棤褰卞搷锛屾殏涓嶅缓璁紑鍚�"+audioWorklet+"銆�";
+ var oldScript=function(){
+ isWorklet=stream.isWorklet=false;
+ _Disconn_n(stream);
+ CLog("Connect閲囩敤鑰佺殑"+scriptProcessor+"锛�"+(Recorder[ConnectEnableWorklet]?"浣嗗凡":"鍙�")+"璁剧疆"+RecTxt+"."+ConnectEnableWorklet+"=true灏濊瘯鍚敤"+audioWorklet+webMTips+oldIsBest,3);
+
+ var process=stream._p=oldFn.call(ctx,bufferSize,1,1);//鍗曞0閬擄紝鐪佺殑鏁版嵁澶勭悊澶嶆潅
+ mediaConn(process);
+
+ var _DsetTxt="_D220626",_Dset=Recorder[_DsetTxt];if(_Dset)CLog("Use "+RecTxt+"."+_DsetTxt,3);
+ process.onaudioprocess=function(e){
+ var arr=e.inputBuffer.getChannelData(0);
+ if(_Dset){//涓存椂璋冭瘯鐢ㄧ殑鍙傛暟锛屾湭鏉ヤ細琚垹闄�
+ arr=new Float32Array(arr);//鍧楁槸鍏变韩鐨勶紝蹇呴』澶嶅埗鍑烘潵
+ setTimeout(function(){ onReceive(arr) });//绔嬪嵆閫�鍑哄洖璋冿紝璇曞浘鍑忓皯瀵规祻瑙堝櫒褰曢煶鐨勫奖鍝�
+ }else{
+ onReceive(arr);
+ };
+ };
+ };
+
+
+//===================杩炴帴鏂瑰紡浜�=========================
+var connWorklet=function(){
+ //灏濊瘯寮�鍚疉udioWorklet澶勭悊
+ isWebM=stream.isWebM=false;
+ _Disconn_r(stream);
+
+ isWorklet=stream.isWorklet=!oldFn || Recorder[ConnectEnableWorklet];
+ var AwNode=window.AudioWorkletNode;
+ if(!(isWorklet && ctx[audioWorklet] && AwNode)){
+ oldScript();//琚鐢� 鎴� 涓嶆敮鎸侊紝鐩存帴浣跨敤鑰佺殑
+ return;
+ };
+ var clazzUrl=function(){
+ var xf=function(f){return f.toString().replace(/^function|DEL_/g,"").replace(/\$RA/g,recAudioWorklet)};
+ var clazz='class '+RecProc+' extends AudioWorkletProcessor{';
+ clazz+="constructor "+xf(function(option){
+ DEL_super(option);
+ var This=this,bufferSize=option.processorOptions.bufferSize;
+ This.bufferSize=bufferSize;
+ This.buffer=new Float32Array(bufferSize*2);//涔辩粰size鎼炰贡缂撳啿鍖轰笉绠�
+ This.pos=0;
+ This.port.onmessage=function(e){
+ if(e.data.kill){
+ This.kill=true;
+ console.log("$RA kill call");
+ }
+ };
+ console.log("$RA .ctor call", option);
+ });
+
+ //https://developer.mozilla.org/en-US/docs/Web/API/AudioWorkletProcessor/process 姣忔鍥炶皟128涓噰鏍锋暟鎹紝1绉�375娆″洖璋冿紝楂橀瀵艰嚧绉诲姩绔�ц兘闂锛岀粨鏋滃氨鏄洖璋冩鏁扮己鏂ゅ皯涓わ紝杩涜�屽鑷翠涪澶辨暟鎹紝PC绔技涔庢病鏈夋�ц兘闂
+ clazz+="process "+xf(function(input,b,c){//闇�瑕佺瓑鍒癱tx婵�娲诲悗鎵嶄細鏈夊洖璋�
+ var This=this,bufferSize=This.bufferSize;
+ var buffer=This.buffer,pos=This.pos;
+ input=(input[0]||[])[0]||[];
+ if(input.length){
+ buffer.set(input,pos);
+ pos+=input.length;
+
+ var len=~~(pos/bufferSize)*bufferSize;
+ if(len){
+ this.port.postMessage({ val: buffer.slice(0,len) });
+
+ var more=buffer.subarray(len,pos);
+ buffer=new Float32Array(bufferSize*2);
+ buffer.set(more);
+ pos=more.length;
+ This.buffer=buffer;
+ }
+ This.pos=pos;
+ }
+ return !This.kill;
+ });
+ clazz+='}'
+ +'try{'
+ +'registerProcessor("'+RecProc+'", '+RecProc+')'
+ +'}catch(e){'
+ +'console.error("'+recAudioWorklet+'娉ㄥ唽澶辫触",e)'
+ +'}';
+ //URL.createObjectURL 鏈湴鏈変簺娴忚鍣ㄤ細鎶� Not allowed to load local resource锛岀洿鎺ョ敤dataurl
+ return "data:text/javascript;base64,"+btoa(unescape(encodeURIComponent(clazz)));
+ };
+
+ var awNext=function(){//鍙互缁х画锛屾病鏈夎皟鐢ㄦ柇寮�
+ return isWorklet && stream._na;
+ };
+ var nodeAlive=stream._na=function(){
+ //start鏃朵細璋冪敤锛屽彧瑕佹病鏈夋敹鍒版暟鎹氨鏂畾AudioWorklet鏈夐棶棰橈紝鎭㈠鐢ㄨ�佺殑
+ if(badInt!==""){//娌℃湁鍥炶皟杩囨暟鎹�
+ clearTimeout(badInt);
+ badInt=setTimeout(function(){
+ badInt=0;
+ if(awNext()){
+ CLog(audioWorklet+"鏈繑鍥炰换浣曢煶棰戯紝鎭㈠浣跨敤"+scriptProcessor,3);
+ oldFn&&oldScript();//鏈潵娌℃湁鑰佺殑锛屽彲鑳芥槸璇垽
+ };
+ },500);
+ };
+ };
+ var createNode=function(){
+ if(!awNext())return;
+ var node=stream._n=new AwNode(ctx, RecProc, {
+ processorOptions:{bufferSize:bufferSize}
+ });
+ mediaConn(node);
+ node.port.onmessage=function(e){
+ if(badInt){
+ clearTimeout(badInt);badInt="";
+ };
+ if(awNext()){
+ onReceive(e.data.val);
+ }else if(!isWorklet){
+ CLog(audioWorklet+"澶氫綑鍥炶皟",3);
+ };
+ };
+ CLog("Connect閲囩敤"+audioWorklet+"锛岃缃�"+RecTxt+"."+ConnectEnableWorklet+"=false鍙仮澶嶈�佸紡"+scriptProcessor+webMTips+oldIsBest,3);
+ };
+
+ //濡傛灉start鏃剁殑resume鍜屼笅闈㈢殑鏋勯�爊ode鍚屾椂杩涜锛屽皢浼氬鑷撮儴鍒嗘祻瑙堝櫒宕╂簝锛屾簮鐮乤ssets涓� ztest_chrome_bug_AudioWorkletNode.html 鍙祴璇曘�傛墍浠ワ紝灏嗘墍鏈変唬鐮佸鍒皉esume閲岄潰锛堜笉绠atch锛夛紝閬垮厤鍑虹幇杩欎釜闂
+ ctx.resume()[calls&&"finally"](function(){//娉ㄩ噴鎺夎繖琛� 瑙傛懇娴忚鍣ㄥ穿婧� STATUS_ACCESS_VIOLATION
+ if(!awNext())return;
+ if(ctx[RecProc]){
+ createNode();
+ return;
+ };
+ var url=clazzUrl();
+ ctx[audioWorklet].addModule(url).then(function(e){
+ if(!awNext())return;
+ ctx[RecProc]=1;
+ createNode();
+ if(badInt){//閲嶆柊璁℃椂
+ nodeAlive();
+ };
+ })[CatchTxt](function(e){ //fix 鍏抽敭瀛楋紝淇濊瘉catch鍘嬬缉鏃朵繚鎸佸瓧绗︿覆褰㈠紡
+ CLog(audioWorklet+".addModule澶辫触",1,e);
+ awNext()&&oldScript();
+ });
+ });
+};
+
+
+//===================杩炴帴鏂瑰紡涓�=========================
+var connWebM=function(){
+ //灏濊瘯寮�鍚疢ediaRecorder褰曞埗webm+pcm澶勭悊
+ var MR=window[MediaRecorderTxt];
+ var onData="ondataavailable";
+ var webmType="audio/webm; codecs=pcm";
+ isWebM=stream.isWebM=Recorder[ConnectEnableWebM];
+
+ var supportMR=MR && (onData in MR.prototype) && MR.isTypeSupported(webmType);
+ webMTips=supportMR?"":"锛堟娴忚鍣ㄤ笉鏀寔"+MRWebMPCM+"锛�";
+ if(!isUserMedia || !isWebM || !supportMR){
+ connWorklet(); //闈為害鍏嬮褰曢煶锛圡ediaRecorder閲囨牱鐜囦笉鍙帶锛� 鎴� 琚鐢� 鎴� 涓嶆敮鎸丮ediaRecorder 鎴� 涓嶆敮鎸亀ebm+pcm
+ return;
+ }
+
+ var mrNext=function(){//鍙互缁х画锛屾病鏈夎皟鐢ㄦ柇寮�
+ return isWebM && stream._ra;
+ };
+ var mrAlive=stream._ra=function(){
+ //start鏃朵細璋冪敤锛屽彧瑕佹病鏈夋敹鍒版暟鎹氨鏂畾MediaRecorder鏈夐棶棰橈紝闄嶇骇澶勭悊
+ if(badInt!==""){//娌℃湁鍥炶皟杩囨暟鎹�
+ clearTimeout(badInt);
+ badInt=setTimeout(function(){
+ //badInt=0; 淇濈暀缁檔odeAlive缁х画鍒ゆ柇
+ if(mrNext()){
+ CLog(MediaRecorderTxt+"鏈繑鍥炰换浣曢煶棰戯紝闄嶇骇浣跨敤"+audioWorklet,3);
+ connWorklet();
+ };
+ },500);
+ };
+ };
+
+ var mrSet=Object.assign({mimeType:webmType}, Recorder.ConnectWebMOptions);
+ var mr=stream._r=new MR(stream, mrSet);
+ var webmData=stream._rd={sampleRate:ctx[sampleRateTxt]};
+ mr[onData]=function(e){
+ //鎻愬彇webm涓殑pcm鏁版嵁锛屾彁鍙栧け璐ュ氨绛夌潃badInt瓒呮椂闄嶇骇澶勭悊
+ var reader=new FileReader();
+ reader.onloadend=function(){
+ if(mrNext()){
+ var f32arr=WebM_Extract(new Uint8Array(reader.result),webmData);
+ if(!f32arr)return;
+ if(f32arr==-1){//鏃犳硶鎻愬彇锛岀珛鍗抽檷绾�
+ connWorklet();
+ return;
+ };
+
+ if(badInt){
+ clearTimeout(badInt);badInt="";
+ };
+ onReceive(f32arr);
+ }else if(!isWebM){
+ CLog(MediaRecorderTxt+"澶氫綑鍥炶皟",3);
+ };
+ };
+ reader.readAsArrayBuffer(e.data);
+ };
+ mr.start(~~(bufferSize/48));//鎸�48k鏃剁殑鍥炶皟闂撮殧
+ CLog("Connect閲囩敤"+MRWebMPCM+"锛岃缃�"+RecTxt+"."+ConnectEnableWebM+"=false鍙仮澶嶄娇鐢�"+audioWorklet+"鎴栬�佸紡"+scriptProcessor);
+};
+
+ connWebM();
+};
+var ConnAlive=function(stream){
+ if(stream._na) stream._na(); //妫�鏌udioWorklet杩炴帴鏄惁鏈夋晥锛屾棤鏁堝氨鍥炴粴鍒拌�佺殑ScriptProcessor
+ if(stream._ra) stream._ra(); //妫�鏌ediaRecorder杩炴帴鏄惁鏈夋晥锛屾棤鏁堝氨闄嶇骇澶勭悊
+};
+var _Disconn_n=function(stream){
+ stream._na=null;
+ if(stream._n){
+ stream._n.port.postMessage({kill:true});
+ stream._n.disconnect();
+ stream._n=null;
+ };
+};
+var _Disconn_r=function(stream){
+ stream._ra=null;
+ if(stream._r){
+ stream._r.stop();
+ stream._r=null;
+ };
+};
+var Disconnect=function(streamStore){
+ streamStore=streamStore||Recorder;
+ var isGlobal=streamStore==Recorder;
+
+ var stream=streamStore.Stream;
+ if(stream){
+ if(stream._m){
+ stream._m.disconnect();
+ stream._m=null;
+ };
+ if(stream._p){
+ stream._p.disconnect();
+ stream._p.onaudioprocess=stream._p=null;
+ };
+ _Disconn_n(stream);
+ _Disconn_r(stream);
+
+ if(isGlobal){//鍏ㄥ眬鐨勬椂鍊欙紝瑕佹妸娴佸叧鎺夛紙楹﹀厠椋庯級锛岀洿鎺ユ彁渚涚殑娴佷笉澶勭悊
+ var tracks=stream.getTracks&&stream.getTracks()||stream.audioTracks||[];
+ for(var i=0;i<tracks.length;i++){
+ var track=tracks[i];
+ track.stop&&track.stop();
+ };
+ stream.stop&&stream.stop();
+ };
+ };
+ streamStore.Stream=0;
+};
+
+/*瀵筽cm鏁版嵁鐨勯噰鏍风巼杩涜杞崲
+pcmDatas: [[Int16,...]] pcm鐗囨鍒楄〃
+pcmSampleRate:48000 pcm鏁版嵁鐨勯噰鏍风巼
+newSampleRate:16000 闇�瑕佽浆鎹㈡垚鐨勯噰鏍风巼锛宯ewSampleRate>=pcmSampleRate鏃朵笉浼氳繘琛屼换浣曞鐞嗭紝灏忎簬鏃朵細杩涜閲嶆柊閲囨牱
+prevChunkInfo:{} 鍙�夛紝涓婃璋冪敤鏃剁殑杩斿洖鍊硷紝鐢ㄤ簬杩炵画杞崲锛屾湰娆¤皟鐢ㄥ皢浠庝笂娆$粨鏉熶綅缃紑濮嬭繘琛屽鐞嗐�傛垨鍙嚜琛屽畾涔変竴涓狢hunkInfo浠巔cmDatas鎸囧畾鐨勪綅缃紑濮嬭繘琛岃浆鎹�
+option:{ 鍙�夛紝閰嶇疆椤�
+ frameSize:123456 甯уぇ灏忥紝姣忓抚鐨凱CM Int16鐨勬暟閲忥紝閲囨牱鐜囪浆鎹㈠悗鐨刾cm闀垮害涓篺rameSize鐨勬暣鏁板�嶏紝鐢ㄤ簬杩炵画杞崲銆傜洰鍓嶄粎鍦╩p3鏍煎紡鏃舵墠鏈夌敤锛宖rameSize鍙栧�间负1152锛岃繖鏍风紪鐮佸嚭鏉ョ殑mp3鏃堕暱鍜宲cm鐨勬椂闀垮畬鍏ㄤ竴鑷达紝鍚﹀垯浼氬洜涓簃p3鏈�鍚庝竴甯у綍闊充笉澶熷~婊℃椂娣诲姞濉厖鏁版嵁瀵艰嚧mp3鐨勬椂闀垮彉闀裤��
+ frameType:"" 甯х被鍨嬶紝涓�鑸负rec.set.type锛屾彁渚涙鍙傛暟鏃舵棤闇�鎻愪緵frameSize锛屼細鑷姩浣跨敤鏈�浣崇殑鍊肩粰frameSize璧嬪�硷紝鐩墠浠呮敮鎸乵p3=1152(MPEG1 Layer3鐨勬瘡甯ч噰閲囨牱鏁�)锛屽叾浠栫被鍨�=1銆�
+ 浠ヤ笂涓や釜鍙傛暟鐢ㄤ簬杩炵画杞崲鏃朵娇鐢紝鏈�澶氫娇鐢ㄤ竴涓紝涓嶆彁渚涙椂涓嶈繘琛屽抚鐨勭壒娈婂鐞嗭紝鎻愪緵鏃跺繀椤诲悓鏃舵彁渚沺revChunkInfo鎵嶆湁浣滅敤銆傛渶鍚庝竴娈垫暟鎹鐞嗘椂鏃犻渶鎻愪緵甯уぇ灏忎互渚胯緭鍑烘渶鍚庝竴涓佺偣娈嬬暀鏁版嵁銆�
+ }
+
+杩斿洖ChunkInfo:{
+ //鍙畾涔夛紝浠庢寚瀹氫綅缃紑濮嬭浆鎹㈠埌缁撳熬
+ index:0 pcmDatas宸插鐞嗗埌鐨勭储寮�
+ offset:0.0 宸插鐞嗗埌鐨刬ndex瀵瑰簲鐨刾cm涓殑鍋忕Щ鐨勪笅涓�涓綅缃�
+
+ //浠呬綔涓鸿繑鍥炲��
+ frameNext:null||[Int16,...] 涓嬩竴甯х殑閮ㄥ垎鏁版嵁锛宖rameSize璁剧疆浜嗙殑鏃跺�欐墠鍙兘浼氭湁
+ sampleRate:16000 缁撴灉鐨勯噰鏍风巼锛�<=newSampleRate
+ data:[Int16,...] 杞崲鍚庣殑PCM缁撴灉锛涘鏋滄槸杩炵画杞崲锛屽苟涓攑cmDatas涓苟娌℃湁鏂版暟鎹椂锛宒ata鐨勯暱搴﹀彲鑳戒负0
+}
+*/
+Recorder.SampleData=function(pcmDatas,pcmSampleRate,newSampleRate,prevChunkInfo,option){
+ prevChunkInfo||(prevChunkInfo={});
+ var index=prevChunkInfo.index||0;
+ var offset=prevChunkInfo.offset||0;
+
+ var frameNext=prevChunkInfo.frameNext||[];
+ option||(option={});
+ var frameSize=option.frameSize||1;
+ if(option.frameType){
+ frameSize=option.frameType=="mp3"?1152:1;
+ };
+
+ var nLen=pcmDatas.length;
+ if(index>nLen+1){
+ CLog("SampleData浼间箮浼犲叆浜嗘湭閲嶇疆chunk "+index+">"+nLen,3);
+ };
+ var size=0;
+ for(var i=index;i<nLen;i++){
+ size+=pcmDatas[i].length;
+ };
+ size=Math.max(0,size-Math.floor(offset));
+
+ //閲囨牱 https://www.cnblogs.com/blqw/p/3782420.html
+ var step=pcmSampleRate/newSampleRate;
+ if(step>1){//鏂伴噰鏍蜂綆浜庡綍闊抽噰鏍凤紝杩涜鎶芥牱
+ size=Math.floor(size/step);
+ }else{//鏂伴噰鏍烽珮浜庡綍闊抽噰鏍蜂笉澶勭悊锛岀渷鍘讳簡鎻掑�煎鐞�
+ step=1;
+ newSampleRate=pcmSampleRate;
+ };
+
+ size+=frameNext.length;
+ var res=new Int16Array(size);
+ var idx=0;
+ //娣诲姞涓婁竴娆′笉澶熶竴甯х殑鍓╀綑鏁版嵁
+ for(var i=0;i<frameNext.length;i++){
+ res[idx]=frameNext[i];
+ idx++;
+ };
+ //澶勭悊鏁版嵁
+ for (;index<nLen;index++) {
+ var o=pcmDatas[index];
+ var i=offset,il=o.length;
+ while(i<il){
+ //res[idx]=o[Math.round(i)]; 鐩存帴绠�鍗曟娊鏍�
+
+ //https://www.cnblogs.com/xiaoqi/p/6993912.html
+ //褰撳墠鐐�=褰撳墠鐐�+鍒板悗闈竴涓偣涔嬮棿鐨勫閲忥紝闊宠川姣旂洿鎺ョ畝鍗曟娊鏍峰ソ浜�
+ var before = Math.floor(i);
+ var after = Math.ceil(i);
+ var atPoint = i - before;
+
+ var beforeVal=o[before];
+ var afterVal=after<il ? o[after]
+ : (//鍚庝釜鐐硅秺鐣屼簡锛屾煡鎵句笅涓�涓暟缁�
+ (pcmDatas[index+1]||[beforeVal])[0]||0
+ );
+ res[idx]=beforeVal+(afterVal-beforeVal)*atPoint;
+
+ idx++;
+ i+=step;//鎶芥牱
+ };
+ offset=i-il;
+ };
+ //甯у鐞�
+ frameNext=null;
+ var frameNextSize=res.length%frameSize;
+ if(frameNextSize>0){
+ var u8Pos=(res.length-frameNextSize)*2;
+ frameNext=new Int16Array(res.buffer.slice(u8Pos));
+ res=new Int16Array(res.buffer.slice(0,u8Pos));
+ };
+
+ return {
+ index:index
+ ,offset:offset
+
+ ,frameNext:frameNext
+ ,sampleRate:newSampleRate
+ ,data:res
+ };
+};
+
+
+/*璁$畻闊抽噺鐧惧垎姣旂殑涓�涓柟娉�
+pcmAbsSum: pcm Int16鎵�鏈夐噰鏍风殑缁濆鍊肩殑鍜�
+pcmLength: pcm闀垮害
+杩斿洖鍊硷細0-100锛屼富瑕佸綋鍋氱櫨鍒嗘瘮鐢�
+娉ㄦ剰锛氳繖涓笉鏄垎璐濓紝鍥犳娌$敤volume褰撳仛鍚嶇О*/
+Recorder.PowerLevel=function(pcmAbsSum,pcmLength){
+ /*璁$畻闊抽噺 https://blog.csdn.net/jody1989/article/details/73480259
+ 鏇撮珮鐏垫晱搴︾畻娉�:
+ 闄愬畾鏈�澶ф劅搴斿��10000
+ 绾挎�ф洸绾匡細浣庨煶閲忎笉鍙嬪ソ
+ power/10000*100
+ 瀵规暟鏇茬嚎锛氫綆闊抽噺鍙嬪ソ锛屼絾闇�闄愬畾鏈�浣庢劅搴斿��
+ (1+Math.log10(power/10000))*100
+ */
+ var power=(pcmAbsSum/pcmLength) || 0;//NaN
+ var level;
+ if(power<1251){//1250鐨勭粨鏋�10%锛屾洿灏忕殑闊抽噺閲囩敤绾挎�у彇鍊�
+ level=Math.round(power/1250*10);
+ }else{
+ level=Math.round(Math.min(100,Math.max(0,(1+Math.log(power/10000)/Math.log(10))*100)));
+ };
+ return level;
+};
+
+/*璁$畻闊抽噺锛屽崟浣峝BFS锛堟弧鍒诲害鐩稿鐢靛钩锛�
+maxSample: 涓�16浣峱cm閲囨牱鐨勭粷瀵瑰�间腑鏈�澶х殑涓�涓紙璁$畻宄板�奸煶閲忥級锛屾垨鑰呬负pcm涓墍鏈夐噰鏍风殑缁濆鍊肩殑骞冲眬鍊�
+杩斿洖鍊硷細-100~0 锛堟渶澶у��0dB锛屾渶灏忓��-100浠f浛-鈭烇級
+*/
+Recorder.PowerDBFS=function(maxSample){
+ var val=Math.max(0.1, maxSample||0),Pref=0x7FFF;
+ val=Math.min(val,Pref);
+ //https://www.logiclocmusic.com/can-you-tell-the-decibel/
+ //https://blog.csdn.net/qq_17256689/article/details/120442510
+ val=20*Math.log(val/Pref)/Math.log(10);
+ return Math.max(-100,Math.round(val));
+};
+
+
+
+
+//甯︽椂闂寸殑鏃ュ織杈撳嚭锛屽彲璁句负涓�涓┖鍑芥暟鏉ュ睆钄芥棩蹇楄緭鍑�
+//CLog(msg,errOrLogMsg, logMsg...) err涓烘暟瀛楁椂浠h〃鏃ュ織绫诲瀷1:error 2:log榛樿 3:warn锛屽惁鍒欏綋鍋氬唴瀹硅緭鍑猴紝绗竴涓弬鏁颁笉鑳芥槸瀵硅薄鍥犱负瑕佹嫾鎺ユ椂闂达紝鍚庨潰鍙互鎺ユ棤鏁颁釜杈撳嚭鍙傛暟
+Recorder.CLog=function(msg,err){
+ var now=new Date();
+ var t=("0"+now.getMinutes()).substr(-2)
+ +":"+("0"+now.getSeconds()).substr(-2)
+ +"."+("00"+now.getMilliseconds()).substr(-3);
+ var recID=this&&this.envIn&&this.envCheck&&this.id;
+ var arr=["["+t+" "+RecTxt+(recID?":"+recID:"")+"]"+msg];
+ var a=arguments,console=window.console||{};
+ var i=2,fn=console.log;
+ if(typeof(err)=="number"){
+ fn=err==1?console.error:err==3?console.warn:fn;
+ }else{
+ i=1;
+ };
+ for(;i<a.length;i++){
+ arr.push(a[i]);
+ };
+ if(IsLoser){//鍙よ懀娴忚鍣紝浠呬繚璇佸熀鏈殑鍙墽琛屼笉浠g爜寮傚父
+ fn&&fn("[IsLoser]"+arr[0],arr.length>1?arr:"");
+ }else{
+ fn.apply(console,arr);
+ };
+};
+var CLog=function(){ Recorder.CLog.apply(this,arguments); };
+var IsLoser=true;try{IsLoser=!console.log.apply;}catch(e){};
+
+
+
+
+var ID=0;
+function initFn(set){
+ this.id=++ID;
+
+ //濡傛灉寮�鍚簡娴侀噺缁熻锛岃繖閲屽皢鍙戦�佷竴涓浘鐗囪姹�
+ Traffic();
+
+
+ var o={
+ type:"mp3" //杈撳嚭绫诲瀷锛歮p3,wav锛寃av杈撳嚭鏂囦欢灏哄瓒呭ぇ涓嶆帹鑽愪娇鐢紝浣唌p3缂栫爜鏀寔浼氬鑷磈s鏂囦欢瓒呭ぇ锛屽鏋滀笉闇�鏀寔mp3鍙互浣縥s鏂囦欢澶у箙鍑忓皬
+ ,bitRate:16 //姣旂壒鐜� wav:16鎴�8浣嶏紝MP3锛�8kbps 1k/s锛�8kbps 2k/s 褰曢煶鏂囦欢寰堝皬
+
+ ,sampleRate:16000 //閲囨牱鐜囷紝wav鏍煎紡澶у皬=sampleRate*鏃堕棿锛沵p3姝ら」瀵逛綆姣旂壒鐜囨湁褰卞搷锛岄珮姣旂壒鐜囧嚑涔庢棤褰卞搷銆�
+ //wav浠绘剰鍊硷紝mp3鍙栧�艰寖鍥达細48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000
+ //閲囨牱鐜囧弬鑰僪ttps://www.cnblogs.com/devin87/p/mp3-recorder.html
+
+ ,onProcess:NOOP //fn(buffers,powerLevel,bufferDuration,bufferSampleRate,newBufferIdx,asyncEnd) buffers=[[Int16,...],...]锛氱紦鍐茬殑PCM鏁版嵁锛屼负浠庡紑濮嬪綍闊冲埌鐜板湪鐨勬墍鏈塸cm鐗囨锛沺owerLevel锛氬綋鍓嶇紦鍐茬殑闊抽噺绾у埆0-100锛宐ufferDuration锛氬凡缂撳啿鏃堕暱锛宐ufferSampleRate锛氱紦鍐蹭娇鐢ㄧ殑閲囨牱鐜囷紙褰搕ype鏀寔杈瑰綍杈硅浆鐮�(Worker)鏃讹紝姝ら噰鏍风巼鍜岃缃殑閲囨牱鐜囩浉鍚岋紝鍚﹀垯涓嶄竴瀹氱浉鍚岋級锛沶ewBufferIdx:鏈鍥炶皟鏂板鐨刡uffer璧峰绱㈠紩锛沘syncEnd:fn() 濡傛灉onProcess鏄紓姝ョ殑(杩斿洖鍊间负true鏃�)锛屽鐞嗗畬鎴愭椂闇�瑕佽皟鐢ㄦ鍥炶皟锛屽鏋滀笉鏄紓姝ョ殑璇峰拷鐣ユ鍙傛暟锛屾鏂规硶鍥炶皟鏃跺繀椤绘槸鐪熷紓姝ワ紙涓嶈兘鐪熷紓姝ユ椂闇�鐢╯etTimeout鍖呰9锛夈�俹nProcess杩斿洖鍊硷細濡傛灉杩斿洖true浠h〃寮�鍚紓姝ユā寮忥紝鍦ㄦ煇浜涘ぇ閲忚繍绠楃殑鍦哄悎寮傛鏄繀椤荤殑锛屽繀椤诲湪寮傛澶勭悊瀹屾垚鏃惰皟鐢╝syncEnd(涓嶈兘鐪熷紓姝ユ椂闇�鐢╯etTimeout鍖呰9)锛屽湪onProcess鎵ц鍚庢柊澧炵殑buffer浼氬叏閮ㄦ浛鎹㈡垚绌烘暟缁勶紝鍥犳鏈洖璋冨紑澶村簲绔嬪嵆灏唍ewBufferIdx鍒版湰娆″洖璋冪粨灏句綅缃殑buffer鍏ㄩ儴淇濆瓨鍒板彟澶栦竴涓暟缁勫唴锛屽鐞嗗畬鎴愬悗鍐欏洖buffers涓湰娆″洖璋冪殑缁撳熬浣嶇疆銆�
+
+ //*******楂樼骇璁剧疆******
+ //,sourceStream:MediaStream Object
+ //鍙�夌洿鎺ユ彁渚涗竴涓獟浣撴祦锛屼粠杩欎釜娴佷腑褰曞埗銆佸疄鏃跺鐞嗛煶棰戞暟鎹紙褰撳墠Recorder瀹炰緥鐙韩姝ゆ祦锛夛紱涓嶆彁渚涙椂涓烘櫘閫氱殑楹﹀厠椋庡綍闊筹紝鐢眊etUserMedia鎻愪緵闊抽娴侊紙鎵�鏈塕ecorder瀹炰緥鍏变韩鍚屼竴涓祦锛�
+ //姣斿锛歛udio銆乿ideo鏍囩dom鑺傜偣鐨刢aptureStream鏂规硶锛堝疄楠岀壒鎬э紝涓嶅悓娴忚鍣ㄦ敮鎸佺▼搴︿笉楂橈級杩斿洖鐨勬祦锛沇ebRTC涓殑remote娴侊紱鑷繁鍒涘缓鐨勬祦绛�
+ //娉ㄦ剰锛氭祦鍐呭繀椤昏嚦灏戝瓨鍦ㄤ竴鏉¢煶杞�(Audio Track)锛屾瘮濡俛udio鏍囩蹇呴』绛夊緟鍒板彲浠ュ紑濮嬫挱鏀惧悗鎵嶄細鏈夐煶杞紝鍚﹀垯open浼氬け璐�
+
+ //,audioTrackSet:{ deviceId:"",groupId:"", autoGainControl:true, echoCancellation:true, noiseSuppression:true }
+ //鏅�氶害鍏嬮褰曢煶鏃秅etUserMedia鏂规硶鐨刟udio閰嶇疆鍙傛暟锛屾瘮濡傛寚瀹氳澶噄d锛屽洖澹版秷闄ゃ�侀檷鍣紑鍏筹紱娉ㄦ剰锛氭彁渚涚殑浠讳綍閰嶇疆鍊奸兘涓嶄竴瀹氫細鐢熸晥
+ //鐢变簬楹﹀厠椋庢槸鍏ㄥ眬鍏变韩鐨勶紝鎵�浠ユ柊閰嶇疆鍚庨渶瑕乧lose鎺変互鍓嶇殑鍐嶉噸鏂皁pen
+ //鏇村鍙傝��: https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints
+
+ //,disableEnvInFix:false 鍐呴儴鍙傛暟锛岀鐢ㄨ澶囧崱椤挎椂闊抽杈撳叆涓㈠け琛ュ伩鍔熻兘
+
+ //,takeoffEncodeChunk:NOOP //fn(chunkBytes) chunkBytes=[Uint8,...]锛氬疄鏃剁紪鐮佺幆澧冧笅鎺ョ缂栫爜鍣ㄨ緭鍑猴紝褰撶紪鐮佸櫒瀹炴椂缂栫爜鍑轰竴鍧楁湁鏁堢殑浜岃繘鍒堕煶棰戞暟鎹椂瀹炴椂鍥炶皟姝ゆ柟娉曪紱鍙傛暟涓轰簩杩涘埗鐨刄int8Array锛屽氨鏄紪鐮佸嚭鏉ョ殑闊抽鏁版嵁鐗囨锛屾墍鏈夌殑chunkBytes鎷兼帴鍦ㄤ竴璧峰嵆涓哄畬鏁撮煶棰戙�傛湰瀹炵幇鐨勬兂娉曟渶鍒濈敱QQ2543775048鎻愬嚭
+ //褰撴彁渚涙鍥炶皟鏂规硶鏃讹紝灏嗘帴绠$紪鐮佸櫒鐨勬暟鎹緭鍑猴紝缂栫爜鍣ㄥ唴閮ㄥ皢鏀惧純瀛樺偍鐢熸垚鐨勯煶棰戞暟鎹紱鐜瑕佹眰姣旇緝鑻涘埢锛氬鏋滃綋鍓嶇幆澧冧笉鏀寔瀹炴椂缂栫爜澶勭悊锛屽皢鍦╫pen鏃剁洿鎺ヨ蛋fail閫昏緫
+ //鍥犳鎻愪緵姝ゅ洖璋冨悗璋冪敤stop鏂规硶灏嗘棤娉曡幏寰楁湁鏁堢殑闊抽鏁版嵁锛屽洜涓虹紪鐮佸櫒鍐呮病鏈夐煶棰戞暟鎹紝鍥犳stop鏃惰繑鍥炵殑blob灏嗘槸涓�涓瓧鑺傞暱搴︿负0鐨刡lob
+ //鐩墠鍙湁mp3鏍煎紡瀹炵幇浜嗗疄鏃剁紪鐮侊紝鍦ㄦ敮鎸佸疄鏃跺鐞嗙殑鐜涓皢浼氬疄鏃剁殑灏嗙紪鐮佸嚭鏉ョ殑mp3鐗囨閫氳繃姝ゆ柟娉曞洖璋冿紝鎵�鏈夌殑chunkBytes鎷兼帴鍒颁竴璧峰嵆涓哄畬鏁寸殑mp3锛屾绉嶆嫾鎺ョ殑缁撴灉姣攎ock鏂规硶瀹炴椂鐢熸垚鐨勯煶璐ㄦ洿鍔狅紝鍥犱负澶╃劧閬垮厤浜嗛灏剧殑闈欓粯
+ //鐩墠闄p3澶栧叾浠栨牸寮忎笉鍙互鎻愪緵姝ゅ洖璋冿紝鎻愪緵浜嗗皢鍦╫pen鏃剁洿鎺ヨ蛋fail閫昏緫
+ };
+
+ for(var k in set){
+ o[k]=set[k];
+ };
+ this.set=o;
+
+ this._S=9;//stop鍚屾閿侊紝stop鍙互闃绘open杩囩▼涓繕鏈繍琛岀殑start
+ this.Sync={O:9,C:9};//鍜孯ecorder.Sync涓�鑷达紝鍙笉杩囪繖涓槸闈炲叏灞�鐨勶紝浠呯敤鏉ョ畝鍖栦唬鐮侀�昏緫锛屾棤瀹為檯浣滅敤
+};
+//鍚屾閿侊紝鎺у埗瀵筍tream鐨勭珵浜夛紱鐢ㄤ簬close鏃朵腑鏂紓姝ョ殑open锛涗竴涓璞pen濡傛灉鍙樺寲浜嗛兘瑕侀樆姝lose锛孲tream鐨勬帶鍒舵潈浜や釜鏂扮殑瀵硅薄
+Recorder.Sync={/*open*/O:9,/*close*/C:9};
+
+Recorder.prototype=initFn.prototype={
+ CLog:CLog
+
+ //娴佺浉鍏崇殑鏁版嵁瀛樺偍鍦ㄥ摢涓璞¢噷闈紱濡傛灉鎻愪緵浜唖ourceStream锛屾暟鎹洿鎺ュ瓨鍌ㄥ湪褰撳墠瀵硅薄涓紝鍚﹀垯瀛樺偍鍦ㄥ叏灞�
+ ,_streamStore:function(){
+ if(this.set.sourceStream){
+ return this;
+ }else{
+ return Recorder;
+ }
+ }
+
+ //鎵撳紑褰曢煶璧勬簮True(),False(msg,isUserNotAllow)锛岄渶瑕佽皟鐢╟lose銆傛敞鎰忥細姝ゆ柟娉曟槸寮傛鐨勶紱涓�鑸娇鐢ㄦ椂鎵撳紑锛岀敤瀹岀珛鍗冲叧闂紱鍙噸澶嶈皟鐢紝鍙敤鏉ユ祴璇曟槸鍚﹁兘褰曢煶
+ ,open:function(True,False){
+ var This=this,streamStore=This._streamStore();
+ True=True||NOOP;
+ var failCall=function(errMsg,isUserNotAllow){
+ isUserNotAllow=!!isUserNotAllow;
+ This.CLog("褰曢煶open澶辫触锛�"+errMsg+",isUserNotAllow:"+isUserNotAllow,1);
+ False&&False(errMsg,isUserNotAllow);
+ };
+
+ var ok=function(){
+ This.CLog("open ok id:"+This.id);
+ True();
+
+ This._SO=0;//瑙i櫎stop瀵筼pen涓殑start璋冪敤鐨勯樆姝�
+ };
+
+
+ //鍚屾閿�
+ var Lock=streamStore.Sync;
+ var lockOpen=++Lock.O,lockClose=Lock.C;
+ This._O=This._O_=lockOpen;//璁颁綇褰撳墠鐨刼pen锛屽鏋滃彉鍖栦簡瑕侀樆姝lose锛岃繖閲屽亣瀹氫簡鏂板璞″凡鍙栦唬褰撳墠瀵硅薄骞朵笖涓嶅啀浣跨敤
+ This._SO=This._S;//璁颁綇open杩囩▼涓殑stop锛屼腑閫斾换浣晄top璋冪敤鍚庨兘涓嶈兘缁х画open涓殑start
+ var lockFail=function(){
+ //鍏佽澶氭open锛屼絾涓嶅厑璁镐换浣曚竴娆lose锛屾垨鑰呰嚜韬凡缁忚皟鐢ㄤ簡鍏抽棴
+ if(lockClose!=Lock.C || !This._O){
+ var err="open琚彇娑�";
+ if(lockOpen==Lock.O){
+ //鏃犳柊鐨刼pen锛屽凡缁忚皟鐢ㄤ簡close杩涜鍙栨秷锛屾澶勫簲璁╀笂娆$殑close鏄庣‘鐢熸晥
+ This.close();
+ }else{
+ err="open琚腑鏂�";
+ };
+ failCall(err);
+ return true;
+ };
+ };
+
+ //鐜閰嶇疆妫�鏌�
+ var checkMsg=This.envCheck({envName:"H5",canProcess:true});
+ if(checkMsg){
+ failCall("涓嶈兘褰曢煶锛�"+checkMsg);
+ return;
+ };
+
+
+ //***********宸茬洿鎺ユ彁渚涗簡闊抽娴�************
+ if(This.set.sourceStream){
+ if(!Recorder.GetContext()){
+ failCall("涓嶆敮鎸佹娴忚鍣ㄤ粠娴佷腑鑾峰彇褰曢煶");
+ return;
+ };
+
+ Disconnect(streamStore);//鍙兘宸瞣pen杩囷紝鐩存帴鍏堝皾璇曟柇寮�
+ This.Stream=This.set.sourceStream;
+ This.Stream._call={};
+
+ try{
+ Connect(streamStore);
+ }catch(e){
+ failCall("浠庢祦涓墦寮�褰曢煶澶辫触锛�"+e.message);
+ return;
+ }
+ ok();
+ return;
+ };
+
+
+ //***********鎵撳紑楹﹀厠椋庡緱鍒板叏灞�鐨勯煶棰戞祦************
+ var codeFail=function(code,msg){
+ try{//璺ㄥ煙鐨勪紭鍏堟娴嬩竴涓�
+ window.top.a;
+ }catch(e){
+ failCall('鏃犳潈褰曢煶(璺ㄥ煙锛岃灏濊瘯缁檌frame娣诲姞楹﹀厠椋庤闂瓥鐣ワ紝濡俛llow="camera;microphone")');
+ return;
+ };
+
+ if(/Permission|Allow/i.test(code)){
+ failCall("鐢ㄦ埛鎷掔粷浜嗗綍闊虫潈闄�",true);
+ }else if(window.isSecureContext===false){
+ failCall("娴忚鍣ㄧ姝笉瀹夊叏椤甸潰褰曢煶锛屽彲寮�鍚痟ttps瑙e喅");
+ }else if(/Found/i.test(code)){//鍙兘鏄潪瀹夊叏鐜瀵艰嚧鐨勬病鏈夎澶�
+ failCall(msg+"锛屾棤鍙敤楹﹀厠椋�");
+ }else{
+ failCall(msg);
+ };
+ };
+
+
+ //濡傛灉宸叉墦寮�骞朵笖鏈夋晥灏变笉瑕佸啀鎵撳紑浜�
+ if(Recorder.IsOpen()){
+ ok();
+ return;
+ };
+ if(!Recorder.Support()){
+ codeFail("","姝ゆ祻瑙堝櫒涓嶆敮鎸佸綍闊�");
+ return;
+ };
+
+ //璇锋眰鏉冮檺锛屽鏋滀粠鏈巿鏉冿紝涓�鑸祻瑙堝櫒浼氬脊鍑烘潈闄愯姹傚脊妗�
+ var f1=function(stream){
+ //https://github.com/xiangyuecn/Recorder/issues/14 鑾峰彇鍒扮殑track.readyState!="live"锛屽垰鍒氬洖璋冩椂鍙兘鏄甯哥殑锛屼絾杩囦竴涓嬪彲鑳藉氨琚叧鎺変簡锛屽師鍥犱笉鏄庛�傚欢杩熶竴涓嬩繚璇佺湡寮傛銆傚姝e父娴忚鍣ㄤ笉褰卞搷
+ setTimeout(function(){
+ stream._call={};
+ var oldStream=Recorder.Stream;
+ if(oldStream){
+ Disconnect(); //鐩存帴鏂紑宸插瓨鍦ㄧ殑锛屾棫鐨凜onnect鏈畬鎴愪細鑷姩缁堟
+ stream._call=oldStream._call;
+ };
+ Recorder.Stream=stream;
+ if(lockFail())return;
+
+ if(Recorder.IsOpen()){
+ if(oldStream)This.CLog("鍙戠幇鍚屾椂澶氭璋冪敤open",1);
+
+ Connect(streamStore,1);
+ ok();
+ }else{
+ failCall("褰曢煶鍔熻兘鏃犳晥锛氭棤闊抽娴�");
+ };
+ },100);
+ };
+ var f2=function(e){
+ var code=e.name||e.message||e.code+":"+e;
+ This.CLog("璇锋眰褰曢煶鏉冮檺閿欒",1,e);
+
+ codeFail(code,"鏃犳硶褰曢煶锛�"+code);
+ };
+
+ var trackSet={
+ noiseSuppression:false //榛樿绂佺敤闄嶅櫔锛屽師澹板綍鍒讹紝鍏嶅緱绉诲姩绔〃鐜版�紓锛堝寘鎷郴缁熸挱鏀惧0闊冲彉灏忥級
+ ,echoCancellation:false //鍥炲0娑堥櫎
+ };
+ var trackSet2=This.set.audioTrackSet;
+ for(var k in trackSet2)trackSet[k]=trackSet2[k];
+ trackSet.sampleRate=Recorder.Ctx.sampleRate;//蹇呴』鎸囨槑閲囨牱鐜囷紝涓嶇劧鎵嬫満涓奙ediaRecorder閲囨牱鐜�16k
+
+ try{
+ var pro=Recorder.Scope[getUserMediaTxt]({audio:trackSet},f1,f2);
+ }catch(e){//涓嶈兘璁剧疆trackSet灏辩畻浜�
+ This.CLog(getUserMediaTxt,3,e);
+ pro=Recorder.Scope[getUserMediaTxt]({audio:true},f1,f2);
+ };
+ if(pro&&pro.then){
+ pro.then(f1)[CatchTxt](f2); //fix 鍏抽敭瀛楋紝淇濊瘉catch鍘嬬缉鏃朵繚鎸佸瓧绗︿覆褰㈠紡
+ };
+ }
+ //鍏抽棴閲婃斁褰曢煶璧勬簮
+ ,close:function(call){
+ call=call||NOOP;
+
+ var This=this,streamStore=This._streamStore();
+ This._stop();
+
+ var Lock=streamStore.Sync;
+ This._O=0;
+ if(This._O_!=Lock.O){
+ //鍞竴璧勬簮Stream鐨勬帶鍒舵潈宸蹭氦缁欐柊瀵硅薄锛岃繖閲屼笉鑳藉叧闂�傛澶勫湪姣忔閮藉脊鏉冮檺鐨勬祻瑙堝櫒鍐呭彲鑳藉瓨鍦ㄦ硠婕忥紝鏂板璞¤鎷掔粷鏉冮檺鍙兘涓嶄細璋冪敤close锛屽拷鐣ヨ繖绉嶄笉澶勭悊
+ This.CLog("close琚拷鐣ワ紙鍥犱负鍚屾椂open浜嗗涓猺ec锛屽彧鏈夋渶鍚庝竴涓細鐪熸close锛�",3);
+ call();
+ return;
+ };
+ Lock.C++;//鑾峰緱鎺у埗鏉�
+
+ Disconnect(streamStore);
+
+ This.CLog("close");
+ call();
+ }
+
+
+
+
+
+ /*妯℃嫙涓�娈靛綍闊虫暟鎹紝鍚庨潰鍙互璋冪敤stop杩涜缂栫爜锛岄渶鎻愪緵pcm鏁版嵁[1,2,3...]锛宲cm鐨勯噰鏍风巼*/
+ ,mock:function(pcmData,pcmSampleRate){
+ var This=this;
+ This._stop();//娓呯悊鎺夊凡鏈夌殑璧勬簮
+
+ This.isMock=1;
+ This.mockEnvInfo=null;
+ This.buffers=[pcmData];
+ This.recSize=pcmData.length;
+ This[srcSampleRateTxt]=pcmSampleRate;
+ return This;
+ }
+ ,envCheck:function(envInfo){//骞冲彴鐜涓嬬殑鍙敤鎬ф鏌ワ紝浠讳綍鏃跺�欓兘鍙互璋冪敤妫�鏌ワ紝杩斿洖errMsg:""姝e父锛�"澶辫触鍘熷洜"
+ //envInfo={envName:"H5",canProcess:true}
+ var errMsg,This=this,set=This.set;
+
+ //妫�娴婥PU鐨勬暟瀛楀瓧鑺傚簭锛孴ypedArray瀛楄妭搴忔槸涓糠锛岀洿鎺ユ嫆缁濈綍瑙佺殑澶х妯″紡锛屽洜涓烘壘涓嶅埌杩欑CPU杩涜娴嬭瘯
+ var tag="CPU_BE";
+ if(!errMsg && !Recorder[tag] && window.Int8Array && !new Int8Array(new Int32Array([1]).buffer)[0]){
+ Traffic(tag); //濡傛灉寮�鍚簡娴侀噺缁熻锛岃繖閲屽皢鍙戦�佷竴涓浘鐗囪姹�
+ errMsg="涓嶆敮鎸�"+tag+"鏋舵瀯";
+ };
+
+ //缂栫爜鍣ㄦ鏌ョ幆澧冧笅閰嶇疆鏄惁鍙敤
+ if(!errMsg){
+ var type=set.type;
+ if(This[type+"_envCheck"]){//缂栫爜鍣ㄥ凡瀹炵幇鐜妫�鏌�
+ errMsg=This[type+"_envCheck"](envInfo,set);
+ }else{//鏈疄鐜版鏌ョ殑鎵嬪姩妫�鏌ラ厤缃槸鍚︽湁鏁�
+ if(set.takeoffEncodeChunk){
+ errMsg=type+"绫诲瀷"+(This[type]?"":"(鏈姞杞界紪鐮佸櫒)")+"涓嶆敮鎸佽缃畉akeoffEncodeChunk";
+ };
+ };
+ };
+
+ return errMsg||"";
+ }
+ ,envStart:function(mockEnvInfo,sampleRate){//骞冲彴鐜鐩稿叧鐨剆tart璋冪敤
+ var This=this,set=This.set;
+ This.isMock=mockEnvInfo?1:0;//闈濰5鐜闇�瑕佸惎鐢╩ock锛屽苟鎻愪緵envCheck闇�瑕佺殑鐜淇℃伅
+ This.mockEnvInfo=mockEnvInfo;
+ This.buffers=[];//鏁版嵁缂撳啿
+ This.recSize=0;//鏁版嵁澶у皬
+
+ This.envInLast=0;//envIn鎺ユ敹鍒版渶鍚庡綍闊冲唴瀹圭殑鏃堕棿
+ This.envInFirst=0;//envIn鎺ユ敹鍒扮殑棣栦釜褰曢煶鍐呭鐨勫綍鍒舵椂闂�
+ This.envInFix=0;//琛ュ伩鐨勬�绘椂闂�
+ This.envInFixTs=[];//琛ュ伩璁℃暟鍒楄〃
+
+ //engineCtx闇�瑕佹彁鍓嶇‘瀹氭渶缁堢殑閲囨牱鐜�
+ var setSr=set[sampleRateTxt];
+ if(setSr>sampleRate){
+ set[sampleRateTxt]=sampleRate;
+ }else{ setSr=0 }
+ This[srcSampleRateTxt]=sampleRate;
+ This.CLog(srcSampleRateTxt+": "+sampleRate+" set."+sampleRateTxt+": "+set[sampleRateTxt]+(setSr?" 蹇界暐"+setSr:""), setSr?3:0);
+
+ This.engineCtx=0;
+ //姝ょ被鍨嬫湁杈瑰綍杈硅浆鐮�(Worker)鏀寔
+ if(This[set.type+"_start"]){
+ var engineCtx=This.engineCtx=This[set.type+"_start"](set);
+ if(engineCtx){
+ engineCtx.pcmDatas=[];
+ engineCtx.pcmSize=0;
+ };
+ };
+ }
+ ,envResume:function(){//鍜屽钩鍙扮幆澧冩棤鍏崇殑鎭㈠褰曢煶
+ //閲嶆柊寮�濮嬭鏁�
+ this.envInFixTs=[];
+ }
+ ,envIn:function(pcm,sum){//鍜屽钩鍙扮幆澧冩棤鍏崇殑pcm[Int16]杈撳叆
+ var This=this,set=This.set,engineCtx=This.engineCtx;
+ var bufferSampleRate=This[srcSampleRateTxt];
+ var size=pcm.length;
+ var powerLevel=Recorder.PowerLevel(sum,size);
+
+ var buffers=This.buffers;
+ var bufferFirstIdx=buffers.length;//涔嬪墠鐨刡uffer閮芥槸缁忚繃onProcess澶勭悊濂界殑锛屼笉鍏佽鍐嶄慨鏀�
+ buffers.push(pcm);
+
+ //鏈塭ngineCtx鏃朵細琚鐩栵紝杩欓噷淇濆瓨涓�浠�
+ var buffersThis=buffers;
+ var bufferFirstIdxThis=bufferFirstIdx;
+
+ //鍗¢】涓㈠け琛ュ伩锛氬洜涓鸿澶囧緢鍗$殑鏃跺�欏鑷碒5鎺ユ敹鍒扮殑鏁版嵁閲忎笉澶熼�犳垚鎾斁鏃跺�欏彉閫燂紝缁撴灉姣斿疄闄呯殑鏃堕暱瑕佺煭锛屾澶勪繚璇佷簡涓嶄細鍙樼煭锛屼絾涓嶈兘淇涓㈠け鐨勯煶棰戞暟鎹�犳垚闊宠川鍙樺樊銆傚綋鍓嶇畻娉曢噰鐢ㄨ緭鍏ユ椂闂翠睛娴嬩笅涓�甯ф槸鍚﹂渶瑕佹坊鍔犺ˉ鍋垮抚锛岄渶瑕�(6娆¤緭鍏|瓒呰繃1绉�)浠ヤ笂鎵嶄細寮�濮嬩睛娴嬶紝濡傛灉婊戝姩绐楀彛鍐呬涪澶辫秴杩�1/3灏变細杩涜琛ュ伩
+ var now=Date.now();
+ var pcmTime=Math.round(size/bufferSampleRate*1000);
+ This.envInLast=now;
+ if(This.buffers.length==1){//璁颁笅棣栦釜褰曢煶鏁版嵁鐨勫綍鍒舵椂闂�
+ This.envInFirst=now-pcmTime;
+ };
+ var envInFixTs=This.envInFixTs;
+ envInFixTs.splice(0,0,{t:now,d:pcmTime});
+ //淇濈暀3绉掔殑璁℃暟婊戝姩绐楀彛锛屽彟澶栬秴杩�3绉掔殑鍋滈】涓嶈ˉ鍋�
+ var tsInStart=now,tsPcm=0;
+ for(var i=0;i<envInFixTs.length;i++){
+ var o=envInFixTs[i];
+ if(now-o.t>3000){
+ envInFixTs.length=i;
+ break;
+ };
+ tsInStart=o.t;
+ tsPcm+=o.d;
+ };
+ //杈惧埌闇�瑕佺殑鏁版嵁閲忥紝寮�濮嬩睛娴嬫槸鍚﹂渶瑕佽ˉ鍋�
+ var tsInPrev=envInFixTs[1];
+ var tsIn=now-tsInStart;
+ var lost=tsIn-tsPcm;
+ if( lost>tsIn/3 && (tsInPrev&&tsIn>1000 || envInFixTs.length>=6) ){
+ //涓㈠け杩囧锛屽紑濮嬫墽琛岃ˉ鍋�
+ var addTime=now-tsInPrev.t-pcmTime;//璺濈涓婃杈撳叆涓㈠け杩欎箞澶歮s
+ if(addTime>pcmTime/5){//涓㈠け瓒呰繃鏈抚鐨�1/5
+ var fixOpen=!set.disableEnvInFix;
+ This.CLog("["+now+"]"+(fixOpen?"":"鏈�")+"琛ュ伩"+addTime+"ms",3);
+ This.envInFix+=addTime;
+
+ //鐢ㄩ潤榛樿繘琛岃ˉ鍋�
+ if(fixOpen){
+ var addPcm=new Int16Array(addTime*bufferSampleRate/1000);
+ size+=addPcm.length;
+ buffers.push(addPcm);
+ };
+ };
+ };
+
+
+ var sizeOld=This.recSize,addSize=size;
+ var bufferSize=sizeOld+addSize;
+ This.recSize=bufferSize;//姝ゅ�煎湪onProcess鍚庨渶瑕佷慨姝o紝鍙兘鏂版暟鎹淇敼
+
+
+ //姝ょ被鍨嬫湁杈瑰綍杈硅浆鐮�(Worker)鏀寔锛屽紑鍚疄鏃惰浆鐮�
+ if(engineCtx){
+ //杞崲鎴恠et鐨勯噰鏍风巼
+ var chunkInfo=Recorder.SampleData(buffers,bufferSampleRate,set[sampleRateTxt],engineCtx.chunkInfo);
+ engineCtx.chunkInfo=chunkInfo;
+
+ sizeOld=engineCtx.pcmSize;
+ addSize=chunkInfo.data.length;
+ bufferSize=sizeOld+addSize;
+ engineCtx.pcmSize=bufferSize;//姝ゅ�煎湪onProcess鍚庨渶瑕佷慨姝o紝鍙兘鏂版暟鎹淇敼
+
+ buffers=engineCtx.pcmDatas;
+ bufferFirstIdx=buffers.length;
+ buffers.push(chunkInfo.data);
+ bufferSampleRate=chunkInfo[sampleRateTxt];
+ };
+
+ var duration=Math.round(bufferSize/bufferSampleRate*1000);
+ var bufferNextIdx=buffers.length;
+ var bufferNextIdxThis=buffersThis.length;
+
+ //鍏佽寮傛澶勭悊buffer鏁版嵁
+ var asyncEnd=function(){
+ //閲嶆柊璁$畻size锛屽紓姝ョ殑鏃╁凡鍑忓幓娣诲姞鐨勶紝鍚屾鐨勯渶鍘绘帀鏈娣诲姞鐨勭劧鍚庨噸鏂拌绠�
+ var num=asyncBegin?0:-addSize;
+ var hasClear=buffers[0]==null;
+ for(var i=bufferFirstIdx;i<bufferNextIdx;i++){
+ var buffer=buffers[i];
+ if(buffer==null){//宸茶涓诲姩閲婃斁鍐呭瓨锛屾瘮濡傞暱鏃堕棿瀹炴椂浼犺緭褰曢煶鏃�
+ hasClear=1;
+ }else{
+ num+=buffer.length;
+
+ //鎺ㄥ叆鍚庡彴杈瑰綍杈硅浆鐮�
+ if(engineCtx&&buffer.length){
+ This[set.type+"_encode"](engineCtx,buffer);
+ };
+ };
+ };
+
+ //鍚屾娓呯悊This.buffers锛屼笉绠uffers鍒板簳娓呬簡澶氬皯涓紝buffersThis鏄娇鐢ㄤ笉鍒扮殑杩涜鍏ㄦ竻
+ if(hasClear && engineCtx){
+ var i=bufferFirstIdxThis;
+ if(buffersThis[0]){
+ i=0;
+ };
+ for(;i<bufferNextIdxThis;i++){
+ buffersThis[i]=null;
+ };
+ };
+
+ //缁熻淇敼鍚庣殑size锛屽鏋滃紓姝ュ彂鐢焎lear瑕佸師鏍峰姞鍥炴潵锛屽悓姝ョ殑鏃犻渶鎿嶄綔
+ if(hasClear){
+ num=asyncBegin?addSize:0;
+
+ buffers[0]=null;//褰诲簳琚竻鐞�
+ };
+ if(engineCtx){
+ engineCtx.pcmSize+=num;
+ }else{
+ This.recSize+=num;
+ };
+ };
+ //瀹炴椂鍥炶皟澶勭悊鏁版嵁锛屽厑璁镐慨鏀规垨鏇挎崲涓婃鍥炶皟浠ユ潵鏂板鐨勬暟鎹� 锛屼絾鏄笉鍏佽淇敼宸插鐞嗚繃鐨勶紝涓嶅厑璁稿鍒犵涓�缁存暟缁� 锛屽厑璁稿皢绗簩缁存暟缁勪换鎰忎慨鏀规浛鎹㈡垚绌烘暟缁勪篃鍙互
+ var asyncBegin=0,procTxt="rec.set.onProcess";
+ try{
+ asyncBegin=set.onProcess(buffers,powerLevel,duration,bufferSampleRate,bufferFirstIdx,asyncEnd);
+ }catch(e){
+ //姝ら敊璇樉绀轰笉瑕佺敤CLog锛岃繖鏍锋帶鍒跺彴鍐呯浉鍚屽唴瀹逛笉浼氶噸澶嶆墦鍗�
+ console.error(procTxt+"鍥炶皟鍑洪敊鏄笉鍏佽鐨勶紝闇�淇濊瘉涓嶄細鎶涘紓甯�",e);
+ };
+
+ var slowT=Date.now()-now;
+ if(slowT>10 && This.envInFirst-now>1000){ //1绉掑悗寮�濮媜nProcess鎬ц兘鐩戞祴
+ This.CLog(procTxt+"浣庢�ц兘锛岃�楁椂"+slowT+"ms",3);
+ };
+
+ if(asyncBegin===true){
+ //寮�鍚簡寮傛妯″紡锛宱nProcess宸叉帴绠uffers鏂版暟鎹紝绔嬪嵆娓呯┖锛岄伩鍏嶅嚭鐜版湭澶勭悊鐨勬暟鎹�
+ var hasClear=0;
+ for(var i=bufferFirstIdx;i<bufferNextIdx;i++){
+ if(buffers[i]==null){//宸茶涓诲姩閲婃斁鍐呭瓨锛屾瘮濡傞暱鏃堕棿瀹炴椂浼犺緭褰曢煶鏃� 锛屼絾鍙堣寮�鍚紓姝ユā寮忥紝姝ょ鎯呭喌鏄潪娉曠殑
+ hasClear=1;
+ }else{
+ buffers[i]=new Int16Array(0);
+ };
+ };
+
+ if(hasClear){
+ This.CLog("鏈繘鍏ュ紓姝ュ墠涓嶈兘娓呴櫎buffers",3);
+ }else{
+ //杩樺師size锛屽紓姝ョ粨鏉熷悗鍐嶇粺璁′粎淇敼鍚庣殑size锛屽鏋滃彂鐢焎lear瑕佸師鏍峰姞鍥炴潵
+ if(engineCtx){
+ engineCtx.pcmSize-=addSize;
+ }else{
+ This.recSize-=addSize;
+ };
+ };
+ }else{
+ asyncEnd();
+ };
+ }
+
+
+
+
+ //寮�濮嬪綍闊筹紝闇�鍏堣皟鐢╫pen锛涘彧瑕乷pen鎴愬姛鏃讹紝璋冪敤姝ゆ柟娉曟槸瀹夊叏鐨勶紝濡傛灉鏈猳pen寮鸿璋冪敤瀵艰嚧鐨勫唴閮ㄩ敊璇皢涓嶄細鏈変换浣曟彁绀猴紝stop鏃惰嚜鐒惰兘寰楀埌閿欒
+ ,start:function(){
+ var This=this,ctx=Recorder.Ctx;
+
+ var isOpen=1;
+ if(This.set.sourceStream){//鐩存帴鎻愪緵浜嗘祦锛屼粎鍒ゆ柇鏄惁璋冪敤浜唎pen
+ if(!This.Stream){
+ isOpen=0;
+ }
+ }else if(!Recorder.IsOpen()){//鐩戞祴鍏ㄥ眬楹﹀厠椋庢槸鍚︽墦寮�骞朵笖鏈夋晥
+ isOpen=0;
+ };
+ if(!isOpen){
+ This.CLog("鏈猳pen",1);
+ return;
+ };
+ This.CLog("寮�濮嬪綍闊�");
+
+ This._stop();
+ This.state=3;//0鏈綍闊� 1褰曢煶涓� 2鏆傚仠 3绛夊緟ctx婵�娲�
+ This.envStart(null, ctx[sampleRateTxt]);
+
+ //妫�鏌pen杩囩▼涓璼top鏄惁宸茬粡璋冪敤杩�
+ if(This._SO&&This._SO+1!=This._S){//涓婇潰璋冪敤杩囦竴娆� _stop
+ //open鏈畬鎴愬氨璋冪敤浜唖top锛屾绉嶆儏鍐电粓姝tart銆備篃搴斿敖閲忛伩鍏嶅嚭鐜版鎯呭喌
+ This.CLog("start琚腑鏂�",3);
+ return;
+ };
+ This._SO=0;
+
+ var end=function(){
+ if(This.state==3){
+ This.state=1;
+ This.resume();
+ }
+ };
+ if(ctx.state=="suspended"){
+ var tag="AudioContext resume: ";
+ This.CLog(tag+"wait...");
+ ctx.resume().then(function(){
+ This.CLog(tag+ctx.state);
+ end();
+ })[CatchTxt](function(e){ //姣旇緝灏戣锛屽彲鑳藉褰曢煶娌℃湁褰卞搷
+ This.CLog(tag+ctx.state+" 鍙兘鏃犳硶褰曢煶锛�"+e.message,1,e);
+ end();
+ });
+ }else{
+ end();
+ };
+ }
+ /*鏆傚仠褰曢煶*/
+ ,pause:function(){
+ var This=this;
+ if(This.state){
+ This.state=2;
+ This.CLog("pause");
+ delete This._streamStore().Stream._call[This.id];
+ };
+ }
+ /*鎭㈠褰曢煶*/
+ ,resume:function(){
+ var This=this;
+ if(This.state){
+ This.state=1;
+ This.CLog("resume");
+ This.envResume();
+
+ var stream=This._streamStore().Stream;
+ stream._call[This.id]=function(pcm,sum){
+ if(This.state==1){
+ This.envIn(pcm,sum);
+ };
+ };
+ ConnAlive(stream);//AudioWorklet鍙細鍦╟tx婵�娲诲悗杩愯
+ };
+ }
+
+
+
+
+ ,_stop:function(keepEngine){
+ var This=this,set=This.set;
+ if(!This.isMock){
+ This._S++;
+ };
+ if(This.state){
+ This.pause();
+ This.state=0;
+ };
+ if(!keepEngine && This[set.type+"_stop"]){
+ This[set.type+"_stop"](This.engineCtx);
+ This.engineCtx=0;
+ };
+ }
+ /*
+ 缁撴潫褰曢煶骞惰繑鍥炲綍闊虫暟鎹産lob瀵硅薄
+ True(blob,duration) blob锛氬綍闊虫暟鎹產udio/mp3|wav鏍煎紡
+ duration锛氬綍闊虫椂闀匡紝鍗曚綅姣
+ False(msg)
+ autoClose:false 鍙�夛紝鏄惁鑷姩璋冪敤close锛岄粯璁や负false
+ */
+ ,stop:function(True,False,autoClose){
+ var This=this,set=This.set,t1;
+ var envInMS=This.envInLast-This.envInFirst, envInLen=envInMS&&This.buffers.length; //鍙兘鏈猻tart
+ This.CLog("stop 鍜宻tart鏃跺樊"+(envInMS?envInMS+"ms 琛ュ伩"+This.envInFix+"ms"+" envIn:"+envInLen+" fps:"+(envInLen/envInMS*1000).toFixed(1):"-"));
+
+ var end=function(){
+ This._stop();//褰诲簳鍏虫帀engineCtx
+ if(autoClose){
+ This.close();
+ };
+ };
+ var err=function(msg){
+ This.CLog("缁撴潫褰曢煶澶辫触锛�"+msg,1);
+ False&&False(msg);
+ end();
+ };
+ var ok=function(blob,duration){
+ This.CLog("缁撴潫褰曢煶 缂栫爜鑺�"+(Date.now()-t1)+"ms 闊抽鏃堕暱"+duration+"ms 鏂囦欢澶у皬"+blob.size+"b");
+ if(set.takeoffEncodeChunk){//鎺ョ浜嗚緭鍑猴紝姝ゆ椂blob闀垮害涓�0
+ This.CLog("鍚敤takeoffEncodeChunk鍚巗top杩斿洖鐨刡lob闀垮害涓�0涓嶆彁渚涢煶棰戞暟鎹�",3);
+ }else if(blob.size<Math.max(100,duration/2)){//1绉掑皬浜�0.5k锛�
+ err("鐢熸垚鐨�"+set.type+"鏃犳晥");
+ return;
+ };
+ True&&True(blob,duration);
+ end();
+ };
+ if(!This.isMock){
+ var isCtxWait=This.state==3;
+ if(!This.state || isCtxWait){
+ err("鏈紑濮嬪綍闊�"+(isCtxWait?"锛屽紑濮嬪綍闊冲墠鏃犵敤鎴蜂氦浜掑鑷碅udioContext鏈繍琛�":""));
+ return;
+ };
+ This._stop(true);
+ };
+ var size=This.recSize;
+ if(!size){
+ err("鏈噰闆嗗埌褰曢煶");
+ return;
+ };
+ if(!This.buffers[0]){
+ err("闊抽buffers琚噴鏀�");
+ return;
+ };
+ if(!This[set.type]){
+ err("鏈姞杞�"+set.type+"缂栫爜鍣�");
+ return;
+ };
+
+ //鐜閰嶇疆妫�鏌ワ紝姝ゅ浠呴拡瀵筸ock璋冪敤锛屽洜涓簅pen宸茬粡妫�鏌ヨ繃浜�
+ if(This.isMock){
+ var checkMsg=This.envCheck(This.mockEnvInfo||{envName:"mock",canProcess:false});//娌℃湁鎻愪緵鐜淇℃伅鐨刴ock鏃舵病鏈塷nProcess鍥炶皟
+ if(checkMsg){
+ err("褰曢煶閿欒锛�"+checkMsg);
+ return;
+ };
+ };
+
+ //姝ょ被鍨嬫湁杈瑰綍杈硅浆鐮�(Worker)鏀寔
+ var engineCtx=This.engineCtx;
+ if(This[set.type+"_complete"]&&engineCtx){
+ var duration=Math.round(engineCtx.pcmSize/set[sampleRateTxt]*1000);//閲囩敤鍚庣殑鏁版嵁闀垮害鍜宐uffers鐨勯暱搴﹀彲鑳藉井灏忕殑涓嶄竴鑷达紝鏄噰鏍风巼杩炵画杞崲鐨勭簿搴﹂棶棰�
+
+ t1=Date.now();
+ This[set.type+"_complete"](engineCtx,function(blob){
+ ok(blob,duration);
+ },err);
+ return;
+ };
+
+ //鏍囧噯UI绾跨▼杞爜锛岃皟鏁撮噰鏍风巼
+ t1=Date.now();
+ var chunk=Recorder.SampleData(This.buffers,This[srcSampleRateTxt],set[sampleRateTxt]);
+
+ set[sampleRateTxt]=chunk[sampleRateTxt];
+ var res=chunk.data;
+ var duration=Math.round(res.length/set[sampleRateTxt]*1000);
+
+ This.CLog("閲囨牱"+size+"->"+res.length+" 鑺�:"+(Date.now()-t1)+"ms");
+
+ setTimeout(function(){
+ t1=Date.now();
+ This[set.type](res,function(blob){
+ ok(blob,duration);
+ },function(msg){
+ err(msg);
+ });
+ });
+ }
+
+};
+
+if(window[RecTxt]){
+ CLog("閲嶅寮曞叆"+RecTxt,3);
+ window[RecTxt].Destroy();
+};
+window[RecTxt]=Recorder;
+
+
+
+
+//=======浠嶹ebM瀛楄妭娴佷腑鎻愬彇pcm鏁版嵁锛屾彁鍙栨垚鍔熻繑鍥濬loat32Array锛屽け璐ヨ繑鍥瀗ull||-1=====
+var WebM_Extract=function(inBytes, scope){
+ if(!scope.pos){
+ scope.pos=[0]; scope.tracks={}; scope.bytes=[];
+ };
+ var tracks=scope.tracks, position=[scope.pos[0]];
+ var endPos=function(){ scope.pos[0]=position[0] };
+
+ var sBL=scope.bytes.length;
+ var bytes=new Uint8Array(sBL+inBytes.length);
+ bytes.set(scope.bytes); bytes.set(inBytes,sBL);
+ scope.bytes=bytes;
+
+ //鍏堣鍙栨枃浠跺ご鍜孴rack淇℃伅
+ if(!scope._ht){
+ readMatroskaVInt(bytes, position);//EBML Header
+ readMatroskaBlock(bytes, position);//璺宠繃EBML Header鍐呭
+ if(!BytesEq(readMatroskaVInt(bytes, position), [0x18,0x53,0x80,0x67])){
+ return;//鏈瘑鍒埌Segment
+ }
+ readMatroskaVInt(bytes, position);//璺宠繃Segment闀垮害鍊�
+ while(position[0]<bytes.length){
+ var eid0=readMatroskaVInt(bytes, position);
+ var bytes0=readMatroskaBlock(bytes, position);
+ var pos0=[0],audioIdx=0;
+ if(!bytes0)return;//鏁版嵁涓嶅叏锛岀瓑寰呯紦鍐�
+ //Track瀹屾暣鏁版嵁锛屽惊鐜鍙朤rackEntry
+ if(BytesEq(eid0, [0x16,0x54,0xAE,0x6B])){
+ while(pos0[0]<bytes0.length){
+ var eid1=readMatroskaVInt(bytes0, pos0);
+ var bytes1=readMatroskaBlock(bytes0, pos0);
+ var pos1=[0],track={channels:0,sampleRate:0};
+ if(BytesEq(eid1, [0xAE])){//TrackEntry
+ while(pos1[0]<bytes1.length){
+ var eid2=readMatroskaVInt(bytes1, pos1);
+ var bytes2=readMatroskaBlock(bytes1, pos1);
+ var pos2=[0];
+ if(BytesEq(eid2, [0xD7])){//Track Number
+ var val=BytesInt(bytes2);
+ track.number=val;
+ tracks[val]=track;
+ }else if(BytesEq(eid2, [0x83])){//Track Type
+ var val=BytesInt(bytes2);
+ if(val==1) track.type="video";
+ else if(val==2) {
+ track.type="audio";
+ if(!audioIdx) scope.track0=track;
+ track.idx=audioIdx++;
+ }else track.type="Type-"+val;
+ }else if(BytesEq(eid2, [0x86])){//Track Codec
+ var str="";
+ for(var i=0;i<bytes2.length;i++){
+ str+=String.fromCharCode(bytes2[i]);
+ }
+ track.codec=str;
+ }else if(BytesEq(eid2, [0xE1])){
+ while(pos2[0]<bytes2.length){//寰幆璇诲彇 Audio 灞炴��
+ var eid3=readMatroskaVInt(bytes2, pos2);
+ var bytes3=readMatroskaBlock(bytes2, pos2);
+ //閲囨牱鐜囥�佷綅鏁般�佸0閬撴暟
+ if(BytesEq(eid3, [0xB5])){
+ var val=0,arr=new Uint8Array(bytes3.reverse()).buffer;
+ if(bytes3.length==4) val=new Float32Array(arr)[0];
+ else if(bytes3.length==8) val=new Float64Array(arr)[0];
+ else CLog("WebM Track !Float",1,bytes3);
+ track[sampleRateTxt]=Math.round(val);
+ }else if(BytesEq(eid3, [0x62,0x64])) track.bitDepth=BytesInt(bytes3);
+ else if(BytesEq(eid3, [0x9F])) track.channels=BytesInt(bytes3);
+ }
+ }
+ }
+ }
+ };
+ scope._ht=1;
+ CLog("WebM Tracks",tracks);
+ endPos();
+ break;
+ }
+ }
+ }
+
+ //鏍¢獙闊抽鍙傛暟淇℃伅锛屽鏋滀笉绗﹀悎浠g爜瑕佹眰锛岀粺缁熸嫆缁濆鐞�
+ var track0=scope.track0;
+ if(!track0)return;
+ if(track0.bitDepth==16 && /FLOAT/i.test(track0.codec)){
+ track0.bitDepth=32; //chrome v66 瀹為檯涓烘诞鐐规暟
+ CLog("WebM 16鏀�32浣�",3);
+ }
+ if(track0[sampleRateTxt]!=scope[sampleRateTxt] || track0.bitDepth!=32 || track0.channels<1 || !/(\b|_)PCM\b/i.test(track0.codec)){
+ scope.bytes=[];//鏍煎紡闈為鏈� 鏃犳硶澶勭悊锛屾竻绌虹紦鍐叉暟鎹�
+ if(!scope.bad)CLog("WebM Track闈為鏈�",3,scope);
+ scope.bad=1;
+ return -1;
+ }
+
+ //寰幆璇诲彇Cluster鍐呯殑SimpleBlock
+ var datas=[],dataLen=0;
+ while(position[0]<bytes.length){
+ var eid1=readMatroskaVInt(bytes, position);
+ var bytes1=readMatroskaBlock(bytes, position);
+ if(!bytes1)break;//鏁版嵁涓嶅叏锛岀瓑寰呯紦鍐�
+ if(BytesEq(eid1, [0xA3])){//SimpleBlock瀹屾暣鏁版嵁
+ var trackNo=bytes1[0]&0xf;
+ var track=tracks[trackNo];
+ if(!track){//涓嶅彲鑳芥病鏈夛紝鏁版嵁鍑洪敊锛�
+ CLog("WebM !Track"+trackNo,1,tracks);
+ }else if(track.idx===0){
+ var u8arr=new Uint8Array(bytes1.length-4);
+ for(var i=4;i<bytes1.length;i++){
+ u8arr[i-4]=bytes1[i];
+ }
+ datas.push(u8arr); dataLen+=u8arr.length;
+ }
+ }
+ endPos();
+ }
+
+ if(dataLen){
+ var more=new Uint8Array(bytes.length-scope.pos[0]);
+ more.set(bytes.subarray(scope.pos[0]));
+ scope.bytes=more; //娓呯悊宸茶鍙栦簡鐨勭紦鍐叉暟鎹�
+ scope.pos[0]=0;
+
+ var u8arr=new Uint8Array(dataLen); //宸茶幏鍙栫殑闊抽鏁版嵁
+ for(var i=0,i2=0;i<datas.length;i++){
+ u8arr.set(datas[i],i2);
+ i2+=datas[i].length;
+ }
+ var arr=new Float32Array(u8arr.buffer);
+
+ if(track0.channels>1){//澶氬0閬擄紝鎻愬彇涓�涓0閬�
+ var arr2=[];
+ for(var i=0;i<arr.length;){
+ arr2.push(arr[i]);
+ i+=track0.channels;
+ }
+ arr=new Float32Array(arr2);
+ };
+ return arr;
+ }
+};
+//涓や釜瀛楄妭鏁扮粍鍐呭鏄惁鐩稿悓
+var BytesEq=function(bytes1,bytes2){
+ if(!bytes1 || bytes1.length!=bytes2.length) return false;
+ if(bytes1.length==1) return bytes1[0]==bytes2[0];
+ for(var i=0;i<bytes1.length;i++){
+ if(bytes1[i]!=bytes2[i]) return false;
+ }
+ return true;
+};
+//瀛楄妭鏁扮粍BE杞垚int鏁板瓧
+var BytesInt=function(bytes){
+ var s="";//0-8瀛楄妭锛宩s浣嶈繍绠楀彧鏀寔4瀛楄妭
+ for(var i=0;i<bytes.length;i++){var n=bytes[i];s+=(n<16?"0":"")+n.toString(16)};
+ return parseInt(s,16)||0;
+};
+//璇诲彇涓�涓彲鍙橀暱鏁板�煎瓧鑺傛暟缁�
+var readMatroskaVInt=function(arr,pos,trim){
+ var i=pos[0];
+ if(i>=arr.length)return;
+ var b0=arr[i],b2=("0000000"+b0.toString(2)).substr(-8);
+ var m=/^(0*1)(\d*)$/.exec(b2);
+ if(!m)return;
+ var len=m[1].length, val=[];
+ if(i+len>arr.length)return;
+ for(var i2=0;i2<len;i2++){ val[i2]=arr[i]; i++; }
+ if(trim) val[0]=parseInt(m[2]||'0',2);
+ pos[0]=i;
+ return val;
+};
+//璇诲彇涓�涓嚜甯﹂暱搴︾殑鍐呭瀛楄妭鏁扮粍
+var readMatroskaBlock=function(arr,pos){
+ var lenVal=readMatroskaVInt(arr,pos,1);
+ if(!lenVal)return;
+ var len=BytesInt(lenVal);
+ var i=pos[0], val=[];
+ if(len<0x7FFFFFFF){ //瓒呭ぇ鍊间唬琛ㄦ病鏈夐暱搴�
+ if(i+len>arr.length)return;
+ for(var i2=0;i2<len;i2++){ val[i2]=arr[i]; i++; }
+ }
+ pos[0]=i;
+ return val;
+};
+//=====End WebM璇诲彇=====
+
+
+
+
+//娴侀噺缁熻鐢�1鍍忕礌鍥剧墖鍦板潃锛岃缃负绌哄皢涓嶅弬涓庣粺璁�
+Recorder.TrafficImgUrl="//ia.51.la/go1?id=20469973&pvFlag=1";
+var Traffic=Recorder.Traffic=function(report){
+ report=report?"/"+RecTxt+"/Report/"+report:"";
+ var imgUrl=Recorder.TrafficImgUrl;
+ if(imgUrl){
+ var data=Recorder.Traffic;
+ var m=/^(https?:..[^\/#]*\/?)[^#]*/i.exec(location.href)||[];
+ var host=(m[1]||"http://file/");
+ var idf=(m[0]||host)+report;
+
+ if(imgUrl.indexOf("//")==0){
+ //缁檜rl鍔犱笂http鍓嶇紑锛屽鏋滄槸file鍗忚涓嬶紝涓嶅姞鍓嶇紑娌℃硶鐢�
+ if(/^https:/i.test(idf)){
+ imgUrl="https:"+imgUrl;
+ }else{
+ imgUrl="http:"+imgUrl;
+ };
+ };
+ if(report){
+ imgUrl=imgUrl+"&cu="+encodeURIComponent(host+report);
+ };
+
+ if(!data[idf]){
+ data[idf]=1;
+
+ var img=new Image();
+ img.src=imgUrl;
+ CLog("Traffic Analysis Image: "+(report||RecTxt+".TrafficImgUrl="+Recorder.TrafficImgUrl));
+ };
+ };
+};
+
+}));
\ No newline at end of file
diff --git a/funasr/runtime/html5/static/wav.js b/funasr/runtime/html5/static/wav.js
new file mode 100644
index 0000000..1123a05
--- /dev/null
+++ b/funasr/runtime/html5/static/wav.js
@@ -0,0 +1,86 @@
+/*
+wav缂栫爜鍣�+缂栫爜寮曟搸
+https://github.com/xiangyuecn/Recorder
+
+褰撶劧鏈�浣虫帹鑽愪娇鐢╩p3銆亀av鏍煎紡锛屼唬鐮佷篃鏄紭鍏堢収椤捐繖涓ょ鏍煎紡
+娴忚鍣ㄦ敮鎸佹儏鍐�
+https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats
+
+缂栫爜鍘熺悊锛氱粰pcm鏁版嵁鍔犱笂涓�涓�44鐩存帴鐨剋av澶村嵆鎴恮av鏂囦欢锛沺cm鏁版嵁灏辨槸Recorder涓殑buffers鍘熷鏁版嵁锛堥噸鏂伴噰鏍凤級锛�16浣嶆椂涓篖E灏忕妯″紡锛圠ittle Endian锛夛紝瀹炶川涓婃槸鏈粡杩囦换浣曠紪鐮佸鐞�
+*/
+(function(){
+"use strict";
+
+Recorder.prototype.enc_wav={
+ stable:true
+ ,testmsg:"鏀寔浣嶆暟8浣嶃��16浣嶏紙濉湪姣旂壒鐜囬噷闈級锛岄噰鏍风巼鍙栧�兼棤闄愬埗"
+};
+Recorder.prototype.wav=function(res,True,False){
+ var This=this,set=This.set
+ ,size=res.length
+ ,sampleRate=set.sampleRate
+ ,bitRate=set.bitRate==8?8:16;
+
+ //缂栫爜鏁版嵁 https://github.com/mattdiamond/Recorderjs https://www.cnblogs.com/blqw/p/3782420.html https://www.cnblogs.com/xiaoqi/p/6993912.html
+ var dataLength=size*(bitRate/8);
+ var buffer=new ArrayBuffer(44+dataLength);
+ var data=new DataView(buffer);
+
+ var offset=0;
+ var writeString=function(str){
+ for (var i=0;i<str.length;i++,offset++) {
+ data.setUint8(offset,str.charCodeAt(i));
+ };
+ };
+ var write16=function(v){
+ data.setUint16(offset,v,true);
+ offset+=2;
+ };
+ var write32=function(v){
+ data.setUint32(offset,v,true);
+ offset+=4;
+ };
+
+ /* RIFF identifier */
+ writeString('RIFF');
+ /* RIFF chunk length */
+ write32(36+dataLength);
+ /* RIFF type */
+ writeString('WAVE');
+ /* format chunk identifier */
+ writeString('fmt ');
+ /* format chunk length */
+ write32(16);
+ /* sample format (raw) */
+ write16(1);
+ /* channel count */
+ write16(1);
+ /* sample rate */
+ write32(sampleRate);
+ /* byte rate (sample rate * block align) */
+ write32(sampleRate*(bitRate/8));// *1 澹伴亾
+ /* block align (channel count * bytes per sample) */
+ write16(bitRate/8);// *1 澹伴亾
+ /* bits per sample */
+ write16(bitRate);
+ /* data chunk identifier */
+ writeString('data');
+ /* data chunk length */
+ write32(dataLength);
+ // 鍐欏叆閲囨牱鏁版嵁
+ if(bitRate==8) {
+ for(var i=0;i<size;i++,offset++) {
+ //16杞�8鎹鏄浄闇勯獏鐨� https://blog.csdn.net/sevennight1989/article/details/85376149 缁嗚妭姣攂lqw鐨勬寜姣斾緥鐨勭畻娉曟竻鏅扮偣锛岃櫧鐒堕兘鏈夋槑鏄炬潅闊�
+ var val=(res[i]>>8)+128;
+ data.setInt8(offset,val,true);
+ };
+ }else{
+ for (var i=0;i<size;i++,offset+=2){
+ data.setInt16(offset,res[i],true);
+ };
+ };
+
+
+ True(new Blob([data.buffer],{type:"audio/wav"}));
+ }
+})();
\ No newline at end of file
diff --git a/funasr/runtime/html5/static/wsconnecter.js b/funasr/runtime/html5/static/wsconnecter.js
new file mode 100644
index 0000000..4b22e8f
--- /dev/null
+++ b/funasr/runtime/html5/static/wsconnecter.js
@@ -0,0 +1,81 @@
+/**
+ * Copyright FunASR (https://github.com/alibaba-damo-academy/FunASR). All Rights
+ * Reserved. MIT License (https://opensource.org/licenses/MIT)
+ */
+/* 2021-2023 by zhaoming,mali aihealthx.com */
+
+function WebSocketConnectMethod( config ) { //瀹氫箟socket杩炴帴鏂规硶绫�
+ var Uri = "wss://111.205.137.58:5821/wss/" //璁剧疆wss asr online鎺ュ彛鍦板潃 濡� wss://X.X.X.X:port/wss/
+ var speechSokt;
+ var connKeeperID;
+
+ var msgHandle = config.msgHandle;
+ var stateHandle = config.stateHandle;
+
+ this.wsStart = function () {
+
+ if ( 'WebSocket' in window ) {
+ speechSokt = new WebSocket( Uri ); // 瀹氫箟socket杩炴帴瀵硅薄
+ speechSokt.onopen = function(e){onOpen(e);}; // 瀹氫箟鍝嶅簲鍑芥暟
+ speechSokt.onclose = function(e){onClose(e);};
+ speechSokt.onmessage = function(e){onMessage(e);};
+ speechSokt.onerror = function(e){onError(e);};
+ }
+ else {
+ alert('褰撳墠娴忚鍣ㄤ笉鏀寔 WebSocket');
+ }
+ };
+
+ // 瀹氫箟鍋滄涓庡彂閫佸嚱鏁�
+ this.wsStop = function () {
+ if(speechSokt != undefined) {
+ speechSokt.close();
+ }
+ };
+
+ this.wsSend = function ( oneData,stop ) {
+
+ if(speechSokt == undefined) return;
+ if ( speechSokt.readyState === 1 ) { // 0:CONNECTING, 1:OPEN, 2:CLOSING, 3:CLOSED
+
+ speechSokt.send( oneData );
+ if(stop){
+ setTimeout(speechSokt.close(), 3000 );
+
+ }
+
+ }
+ };
+
+ // SOCEKT杩炴帴涓殑娑堟伅涓庣姸鎬佸搷搴�
+ function onOpen( e ) {
+ // 鍙戦�乯son
+ var chunk_size = new Array( 5, 10, 5 );
+ var request = {
+ "chunk_size": chunk_size,
+ "wav_name": "h5",
+ "is_speaking": true,
+ "chunk_interval":10,
+ };
+ speechSokt.send( JSON.stringify(request) );
+ console.log("杩炴帴鎴愬姛");
+ stateHandle(0);
+ }
+
+ function onClose( e ) {
+ stateHandle(1);
+ }
+
+ function onMessage( e ) {
+
+ msgHandle( e );
+ }
+
+ function onError( e ) {
+ info_div.innerHTML="杩炴帴"+e;
+ console.log(e);
+ stateHandle(2);
+ }
+
+
+}
\ No newline at end of file
diff --git a/funasr/runtime/onnxruntime/readme.md b/funasr/runtime/onnxruntime/readme.md
index 3e34a67..4ed184f 100644
--- a/funasr/runtime/onnxruntime/readme.md
+++ b/funasr/runtime/onnxruntime/readme.md
@@ -127,6 +127,8 @@
### funasr-onnx-offline-rtf
```shell
./funasr-onnx-offline-rtf --model-dir <string> [--quantize <string>]
+ [--vad-dir <string>] [--vad-quant <string>]
+ [--punc-dir <string>] [--punc-quant <string>]
--wav-path <string> --thread-num <int32_t>
[--] [--version] [-h]
Where:
@@ -136,6 +138,17 @@
(required) the model path, which contains model.onnx, config.yaml, am.mvn
--quantize <string>
false (Default), load the model of model.onnx in model_dir. If set true, load the model of model_quant.onnx in model_dir
+
+ --vad-dir <string>
+ the vad model path, which contains model.onnx, vad.yaml, vad.mvn
+ --vad-quant <string>
+ false (Default), load the model of model.onnx in vad_dir. If set true, load the model of model_quant.onnx in vad_dir
+
+ --punc-dir <string>
+ the punc model path, which contains model.onnx, punc.yaml
+ --punc-quant <string>
+ false (Default), load the model of model.onnx in punc_dir. If set true, load the model of model_quant.onnx in punc_dir
+
--wav-path <string>
(required) the input could be:
wav_path, e.g.: asr_example.wav;
diff --git a/funasr/runtime/onnxruntime/src/funasr-onnx-offline-rtf.cpp b/funasr/runtime/onnxruntime/src/funasr-onnx-offline-rtf.cpp
index 6ba65c6..cf1469d 100644
--- a/funasr/runtime/onnxruntime/src/funasr-onnx-offline-rtf.cpp
+++ b/funasr/runtime/onnxruntime/src/funasr-onnx-offline-rtf.cpp
@@ -39,7 +39,7 @@
// warm up
for (size_t i = 0; i < 1; i++)
{
- FUNASR_RESULT result=FunASRInfer(asr_handle, wav_list[0].c_str(), RASR_NONE, NULL, 16000);
+ FUNASR_RESULT result=FunOfflineInfer(asr_handle, wav_list[0].c_str(), RASR_NONE, NULL, 16000);
}
while (true) {
@@ -50,7 +50,7 @@
}
gettimeofday(&start, NULL);
- FUNASR_RESULT result=FunASRInfer(asr_handle, wav_list[i].c_str(), RASR_NONE, NULL, 16000);
+ FUNASR_RESULT result=FunOfflineInfer(asr_handle, wav_list[i].c_str(), RASR_NONE, NULL, 16000);
gettimeofday(&end, NULL);
seconds = (end.tv_sec - start.tv_sec);
@@ -102,12 +102,20 @@
TCLAP::CmdLine cmd("funasr-onnx-offline-rtf", ' ', "1.0");
TCLAP::ValueArg<std::string> model_dir("", MODEL_DIR, "the model path, which contains model.onnx, config.yaml, am.mvn", true, "", "string");
TCLAP::ValueArg<std::string> quantize("", QUANTIZE, "false (Default), load the model of model.onnx in model_dir. If set true, load the model of model_quant.onnx in model_dir", false, "false", "string");
+ TCLAP::ValueArg<std::string> vad_dir("", VAD_DIR, "the vad model path, which contains model.onnx, vad.yaml, vad.mvn", false, "", "string");
+ TCLAP::ValueArg<std::string> vad_quant("", VAD_QUANT, "false (Default), load the model of model.onnx in vad_dir. If set true, load the model of model_quant.onnx in vad_dir", false, "false", "string");
+ TCLAP::ValueArg<std::string> punc_dir("", PUNC_DIR, "the punc model path, which contains model.onnx, punc.yaml", false, "", "string");
+ TCLAP::ValueArg<std::string> punc_quant("", PUNC_QUANT, "false (Default), load the model of model.onnx in punc_dir. If set true, load the model of model_quant.onnx in punc_dir", false, "false", "string");
TCLAP::ValueArg<std::string> wav_path("", WAV_PATH, "the input could be: wav_path, e.g.: asr_example.wav; pcm_path, e.g.: asr_example.pcm; wav.scp, kaldi style wav list (wav_id \t wav_path)", true, "", "string");
TCLAP::ValueArg<std::int32_t> thread_num("", THREAD_NUM, "multi-thread num for rtf", true, 0, "int32_t");
cmd.add(model_dir);
cmd.add(quantize);
+ cmd.add(vad_dir);
+ cmd.add(vad_quant);
+ cmd.add(punc_dir);
+ cmd.add(punc_quant);
cmd.add(wav_path);
cmd.add(thread_num);
cmd.parse(argc, argv);
@@ -115,11 +123,15 @@
std::map<std::string, std::string> model_path;
GetValue(model_dir, MODEL_DIR, model_path);
GetValue(quantize, QUANTIZE, model_path);
+ GetValue(vad_dir, VAD_DIR, model_path);
+ GetValue(vad_quant, VAD_QUANT, model_path);
+ GetValue(punc_dir, PUNC_DIR, model_path);
+ GetValue(punc_quant, PUNC_QUANT, model_path);
GetValue(wav_path, WAV_PATH, model_path);
struct timeval start, end;
gettimeofday(&start, NULL);
- FUNASR_HANDLE asr_handle=FunASRInit(model_path, 1);
+ FUNASR_HANDLE asr_handle=FunOfflineInit(model_path, 1);
if (!asr_handle)
{
@@ -132,7 +144,7 @@
long modle_init_micros = ((seconds * 1000000) + end.tv_usec) - (start.tv_usec);
LOG(INFO) << "Model initialization takes " << (double)modle_init_micros / 1000000 << " s";
- // read wav_scp
+ // read wav_path
vector<string> wav_list;
string wav_path_ = model_path.at(WAV_PATH);
if(is_target_file(wav_path_, "wav") || is_target_file(wav_path_, "pcm")){
diff --git a/funasr/runtime/python/websocket/parse_args.py b/funasr/runtime/python/websocket/parse_args.py
index d170be8..bfa5a87 100644
--- a/funasr/runtime/python/websocket/parse_args.py
+++ b/funasr/runtime/python/websocket/parse_args.py
@@ -35,6 +35,16 @@
type=int,
default=1,
help="cpu cores")
-
+parser.add_argument("--certfile",
+ type=str,
+ default="",
+ required=False,
+ help="certfile for ssl")
+
+parser.add_argument("--keyfile",
+ type=str,
+ default="",
+ required=False,
+ help="keyfile for ssl")
args = parser.parse_args()
print(args)
\ No newline at end of file
diff --git a/funasr/runtime/python/websocket/ws_server_online.py b/funasr/runtime/python/websocket/ws_server_online.py
index a35b127..16a3abe 100644
--- a/funasr/runtime/python/websocket/ws_server_online.py
+++ b/funasr/runtime/python/websocket/ws_server_online.py
@@ -7,7 +7,7 @@
import logging
import tracemalloc
import numpy as np
-
+import ssl
from parse_args import args
from modelscope.pipelines import pipeline
from modelscope.utils.constant import Tasks
@@ -53,6 +53,9 @@
if "is_speaking" in messagejson:
websocket.is_speaking = messagejson["is_speaking"]
websocket.param_dict_asr_online["is_final"] = not websocket.is_speaking
+ # need to fire engine manually if no data received any more
+ if not websocket.is_speaking:
+ await async_asr_online(websocket,b"")
if "chunk_interval" in messagejson:
websocket.chunk_interval=messagejson["chunk_interval"]
if "wav_name" in messagejson:
@@ -82,7 +85,7 @@
async def async_asr_online(websocket,audio_in):
- if len(audio_in) > 0:
+ if len(audio_in) >=0:
audio_in = load_bytes(audio_in)
rec_result = inference_pipeline_asr_online(audio_in=audio_in,
param_dict=websocket.param_dict_asr_online)
@@ -94,7 +97,16 @@
await websocket.send(message)
+if len(args.certfile)>0:
+ ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
-start_server = websockets.serve(ws_serve, args.host, args.port, subprotocols=["binary"], ping_interval=None)
+ # Generate with Lets Encrypt, copied to this location, chown to current user and 400 permissions
+ ssl_cert = args.certfile
+ ssl_key = args.keyfile
+
+ ssl_context.load_cert_chain(ssl_cert, keyfile=ssl_key)
+ start_server = websockets.serve(ws_serve, args.host, args.port, subprotocols=["binary"], ping_interval=None,ssl=ssl_context)
+else:
+ start_server = websockets.serve(ws_serve, args.host, args.port, subprotocols=["binary"], ping_interval=None)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
\ No newline at end of file
--
Gitblit v1.9.1