@lambo-design-mobile/lambo-js-bridge 1.0.0-beta.22 → 1.0.0-beta.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/README.md +56 -49
- package/demo/index.vue +56 -31
- package/package.json +1 -1
- package/src/sdk/LamboJsBridge.js +4 -0
- package/src/sdk/YunTuAdapter.js +72 -132
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
|
+
## [1.0.0-beta.23](http://git.inspur.com/ecbh/lambo-design/lambo-design/-/compare/@lambo-design-mobile/lambo-js-bridge@1.0.0-beta.22...@lambo-design-mobile/lambo-js-bridge@1.0.0-beta.23) (2025-02-28)
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
### ✨ Features | 新功能
|
|
6
|
+
|
|
7
|
+
* **@lambo-design-mobile/js-bridge:** 更改录音功能调用方式 ([2aa9dd0](http://git.inspur.com/ecbh/lambo-design/lambo-design/-/commit/2aa9dd033c77b2cdb8f14787f3420f903da7e961))
|
|
8
|
+
|
|
2
9
|
## [1.0.0-beta.22](http://git.inspur.com/ecbh/lambo-design/lambo-design/-/compare/@lambo-design-mobile/lambo-js-bridge@1.0.0-beta.21...@lambo-design-mobile/lambo-js-bridge@1.0.0-beta.22) (2025-02-21)
|
|
3
10
|
|
|
4
11
|
|
package/README.md
CHANGED
|
@@ -324,50 +324,66 @@ async openLocation() {
|
|
|
324
324
|
data() {
|
|
325
325
|
return {
|
|
326
326
|
audioUrl: null, // 用于存储录音文件的 URL
|
|
327
|
-
fileName: '', // 录音文件名
|
|
328
|
-
fileSize: 0, // 录音文件大小
|
|
329
|
-
fileType: '', // 录音文件类型
|
|
330
327
|
recordingStatus: "not started", // 用于记录当前录音状态
|
|
331
|
-
recordingOptions: {
|
|
332
|
-
isAuto: false, // 是否自动录音
|
|
333
|
-
fftSize: 512, // FFT 大小
|
|
334
|
-
fileName: 'audio.ogg', // 默认录音文件名
|
|
335
|
-
silenceThreshold: 100, // 静音检测音量阈值
|
|
336
|
-
silenceDuration: 1000, // 静音持续时长
|
|
337
|
-
silenceDelay: 2000 // 静音检测延迟
|
|
338
|
-
}
|
|
339
328
|
};
|
|
340
329
|
},
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
330
|
+
method:{
|
|
331
|
+
// 开始手动录音
|
|
332
|
+
async startRecording() {
|
|
333
|
+
// 清空之前的录音数据
|
|
334
|
+
this.audioUrl = null;
|
|
335
|
+
this.recordingStatus = 'recording';
|
|
336
|
+
try {
|
|
337
|
+
// 传入 { auto: false } 表示手动录音
|
|
338
|
+
const result = await this.$lamboJsBridge.startRecording({ auto: false });
|
|
339
|
+
console.log("录音开始成功:", result);
|
|
340
|
+
} catch (error) {
|
|
341
|
+
console.error("录音开始失败:", error);
|
|
342
|
+
this.recordingStatus = 'failed';
|
|
343
|
+
}
|
|
344
|
+
},
|
|
345
|
+
|
|
346
|
+
// 开始自动录音
|
|
347
|
+
async startAutoRecording() {
|
|
348
|
+
// 清空之前的录音数据
|
|
349
|
+
this.audioUrl = null;
|
|
350
|
+
this.recordingStatus = 'recording';
|
|
351
|
+
try {
|
|
352
|
+
// 传入 { auto: true } 表示启用自动录音
|
|
353
|
+
const result = await this.$lamboJsBridge.startRecording({ auto: true });
|
|
354
|
+
console.log("自动录音开始成功:", result);
|
|
355
|
+
} catch (error) {
|
|
356
|
+
console.error("自动录音开始失败:", error);
|
|
357
|
+
this.recordingStatus = 'failed';
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
|
|
361
|
+
// 停止录音
|
|
362
|
+
async stopRecording() {
|
|
363
|
+
try {
|
|
364
|
+
const result = await this.$lamboJsBridge.stopRecording();
|
|
365
|
+
console.log("录音停止成功:", result);
|
|
366
|
+
this.recordingStatus = 'stopped';
|
|
367
|
+
// 更新录音文件信息
|
|
368
|
+
this.audioUrl = result.fileUrl || result.msg;
|
|
369
|
+
// 如果你非要用全局函数更新,也可以调用它
|
|
370
|
+
this.updateAudioDisplay(result);
|
|
371
|
+
} catch (error) {
|
|
372
|
+
console.error("录音停止失败:", error);
|
|
373
|
+
this.recordingStatus = 'failed';
|
|
374
|
+
}
|
|
375
|
+
},
|
|
376
|
+
|
|
377
|
+
// 如果你希望借助类似全局函数的形式更新页面,可以这样定义:
|
|
378
|
+
updateAudioDisplay(data) {
|
|
379
|
+
// 更新组件中的数据,页面会自动响应
|
|
380
|
+
this.recordingStatus = 'stopped';
|
|
381
|
+
this.audioUrl = data.fileUrl;
|
|
382
|
+
},
|
|
359
383
|
},
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
await this.$lamboJsBridge.stopRecording(); // 调用接口停止录音
|
|
363
|
-
this.recordingStatus = 'stopped'; // 设置录音状态为停止
|
|
364
|
-
console.log('录音已停止');
|
|
365
|
-
} catch (error) {
|
|
366
|
-
console.error('停止录音失败:', error);
|
|
367
|
-
this.recordingStatus = 'failed'; // 设置录音状态为失败
|
|
368
|
-
}
|
|
384
|
+
mounted() {
|
|
385
|
+
window.updateAudioDisplay = this.updateAudioDisplay;
|
|
369
386
|
},
|
|
370
|
-
|
|
371
387
|
```
|
|
372
388
|
|
|
373
389
|
### 参数说明
|
|
@@ -377,11 +393,6 @@ async stopRecording() {
|
|
|
377
393
|
| 属性 | 类型 | 默认值 | 必填 | 支持平台 | 说明 |
|
|
378
394
|
|-----------|--|----------|-----|----------|-------------------------------------------------------------|
|
|
379
395
|
| isAuto | boolean | false | 否 | Yuntu | 是否开启自动录音。若为 true,则自动开始录音。 |
|
|
380
|
-
| fftSize | number | 512 | 否 | Yuntu | FFT大小,用于声音信号处理。 |
|
|
381
|
-
| fileName | string | 录音文件.ogg | 否 | Yuntu | 录音文件的默认文件名。 |
|
|
382
|
-
| silenceThreshold | number | 20 | 否 | Yuntu | 静音检测音量阈值。 |
|
|
383
|
-
| silenceDuration | number | 3000 | 否 | Yuntu | 静音持续时长。|
|
|
384
|
-
| silenceDelay | number | 1000 | 否 | Yuntu | 静音检测延迟。 |
|
|
385
396
|
|
|
386
397
|
|
|
387
398
|
### 返回说明
|
|
@@ -390,11 +401,7 @@ async stopRecording() {
|
|
|
390
401
|
|
|
391
402
|
| 属性 | 类型 | 默认值 | 必填 | 支持平台 | 说明 |
|
|
392
403
|
|-----------|--|----------|-----|----------|-----------------|
|
|
393
|
-
| audioUrl | string | | 是 | Yuntu | 录音文件的
|
|
394
|
-
| file | Object | | 是 | Yuntu | 录音文件的详细信息 |
|
|
395
|
-
| file.name | string | | 是 | Yuntu | 录音文件的名称 |
|
|
396
|
-
| file.size | number | | 是 | Yuntu | 录音文件的大小,单位为字节 |
|
|
397
|
-
| file.type | string | | 是 | Yuntu | 录音文件的类型 |
|
|
404
|
+
| audioUrl | string | | 是 | Yuntu | 录音文件的fileURL |
|
|
398
405
|
<br>
|
|
399
406
|
|
|
400
407
|
**录音状态** <br>
|
package/demo/index.vue
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
<pre v-show="openLocationResult"><code>{{ openLocationResult }}</code></pre>
|
|
30
30
|
</demo-block>
|
|
31
31
|
<demo-block title="文件预览">
|
|
32
|
-
<a href="javascript:void(0);" @click="
|
|
32
|
+
<a href="javascript:void(0);" @click="filePreview">点击这里预览文件</a>
|
|
33
33
|
</demo-block>
|
|
34
34
|
<demo-block title="录音(仅在Flutter环境下可用)">
|
|
35
35
|
<van-button @click="startRecording">开始录音</van-button>
|
|
@@ -50,12 +50,12 @@
|
|
|
50
50
|
<div v-if="audioUrl">
|
|
51
51
|
<h3>录音已完成</h3>
|
|
52
52
|
<audio :src="audioUrl" controls></audio>
|
|
53
|
-
<p>录音文件: {{ fileName }}</p>
|
|
54
|
-
<p>文件大小: {{ fileSize }} 字节</p>
|
|
55
|
-
<p>文件类型: {{ fileType }}</p>
|
|
56
53
|
<p>文件地址:{{ audioUrl }}</p>
|
|
57
54
|
</div>
|
|
58
55
|
</demo-block>
|
|
56
|
+
<demo-block title="下载">
|
|
57
|
+
<van-button @click="downloadFile">下载文件</van-button>
|
|
58
|
+
</demo-block>
|
|
59
59
|
|
|
60
60
|
|
|
61
61
|
|
|
@@ -90,18 +90,8 @@ export default {
|
|
|
90
90
|
photoPreviews: [],
|
|
91
91
|
initKeyMessage: '', // 用于存储 initKey 的返回消息
|
|
92
92
|
audioUrl: null, // 用于存储录音文件的 URL
|
|
93
|
-
fileName: '', // 录音文件名
|
|
94
|
-
fileSize: 0, // 录音文件大小
|
|
95
|
-
fileType: '', // 录音文件类型
|
|
96
93
|
recordingStatus: "not started", // 用于记录当前录音状态
|
|
97
|
-
|
|
98
|
-
isAuto: false, // 是否自动录音
|
|
99
|
-
fftSize: 512, // FFT 大小
|
|
100
|
-
fileName: 'audio.ogg', // 默认录音文件名
|
|
101
|
-
silenceThreshold: 100, // 静音检测音量阈值
|
|
102
|
-
silenceDuration: 1000, // 静音持续时长
|
|
103
|
-
silenceDelay: 2000 // 静音检测延迟
|
|
104
|
-
}
|
|
94
|
+
downloadLink : null,
|
|
105
95
|
};
|
|
106
96
|
},
|
|
107
97
|
computed: {
|
|
@@ -128,7 +118,7 @@ export default {
|
|
|
128
118
|
weComId:this.weComId,
|
|
129
119
|
agentId:this.agentId,
|
|
130
120
|
dingTalkId:this.dingTalkId,
|
|
131
|
-
pluginConfig:["localAuthPlugin","amapPlugin","tabBarPlugin","scanCodePlugin","filePreviewPlugin"],
|
|
121
|
+
pluginConfig:["localAuthPlugin","amapPlugin","tabBarPlugin","scanCodePlugin","filePreviewPlugin","autoRecordPlugin"],
|
|
132
122
|
};
|
|
133
123
|
this.$lamboJsBridge = new LamboJsBridge(options);
|
|
134
124
|
await this.getPlatform();
|
|
@@ -144,40 +134,72 @@ export default {
|
|
|
144
134
|
console.error('Error getting init info:', error);
|
|
145
135
|
}
|
|
146
136
|
},
|
|
137
|
+
|
|
138
|
+
// 开始手动录音
|
|
147
139
|
async startRecording() {
|
|
140
|
+
// 清空之前的录音数据
|
|
141
|
+
this.audioUrl = null;
|
|
142
|
+
this.recordingStatus = 'recording';
|
|
148
143
|
try {
|
|
149
|
-
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
this.fileName = file.name;
|
|
153
|
-
this.fileSize = file.size;
|
|
154
|
-
this.fileType = file.type;
|
|
155
|
-
console.log(this.recordingOptions.isAuto ? '自动录音已开始' : '录音已开始');
|
|
144
|
+
// 传入 { auto: false } 表示手动录音
|
|
145
|
+
const result = await this.$lamboJsBridge.startRecording({ auto: false });
|
|
146
|
+
console.log("录音开始成功:", result);
|
|
156
147
|
} catch (error) {
|
|
157
|
-
console.error(
|
|
148
|
+
console.error("录音开始失败:", error);
|
|
158
149
|
this.recordingStatus = 'failed';
|
|
159
150
|
}
|
|
160
151
|
},
|
|
161
152
|
|
|
162
153
|
// 开始自动录音
|
|
163
154
|
async startAutoRecording() {
|
|
164
|
-
//
|
|
165
|
-
this.
|
|
166
|
-
|
|
155
|
+
// 清空之前的录音数据
|
|
156
|
+
this.audioUrl = null;
|
|
157
|
+
this.recordingStatus = 'recording';
|
|
158
|
+
try {
|
|
159
|
+
// 传入 { auto: true } 表示启用自动录音
|
|
160
|
+
const result = await this.$lamboJsBridge.startRecording({ auto: true });
|
|
161
|
+
console.log("自动录音开始成功:", result);
|
|
162
|
+
} catch (error) {
|
|
163
|
+
console.error("自动录音开始失败:", error);
|
|
164
|
+
this.recordingStatus = 'failed';
|
|
165
|
+
}
|
|
167
166
|
},
|
|
168
167
|
|
|
169
168
|
// 停止录音
|
|
170
169
|
async stopRecording() {
|
|
171
170
|
try {
|
|
172
|
-
await this.$lamboJsBridge.stopRecording();
|
|
171
|
+
const result = await this.$lamboJsBridge.stopRecording();
|
|
172
|
+
console.log("录音停止成功:", result);
|
|
173
173
|
this.recordingStatus = 'stopped';
|
|
174
|
-
|
|
174
|
+
// 更新录音文件信息
|
|
175
|
+
this.audioUrl = result.fileUrl || result.msg;
|
|
176
|
+
// 如果你非要用全局函数更新,也可以调用它
|
|
177
|
+
this.updateAudioDisplay(result);
|
|
175
178
|
} catch (error) {
|
|
176
|
-
console.error(
|
|
179
|
+
console.error("录音停止失败:", error);
|
|
177
180
|
this.recordingStatus = 'failed';
|
|
178
181
|
}
|
|
179
182
|
},
|
|
180
183
|
|
|
184
|
+
// 如果你希望借助类似全局函数的形式更新页面,可以这样定义:
|
|
185
|
+
updateAudioDisplay(data) {
|
|
186
|
+
// 更新组件中的数据,页面会自动响应
|
|
187
|
+
this.recordingStatus = 'stopped';
|
|
188
|
+
this.audioUrl = data.fileUrl;
|
|
189
|
+
},
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
async downloadFile(){
|
|
193
|
+
try {
|
|
194
|
+
const fileUrl = 'http://10.110.34.27/yc_scrm.apk'; // 你要下载的文件 URL
|
|
195
|
+
const fileName = '下载文件'; // 文件名
|
|
196
|
+
await this.$lamboJsBridge.downloadFile({ fileUrl, fileName });
|
|
197
|
+
console.log('Download initiated');
|
|
198
|
+
} catch (error){
|
|
199
|
+
console.error('Download failed:', error);
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
|
|
181
203
|
async getLocation() {
|
|
182
204
|
try {
|
|
183
205
|
const options ={
|
|
@@ -259,7 +281,7 @@ export default {
|
|
|
259
281
|
console.error('Error opening location:', error);
|
|
260
282
|
}
|
|
261
283
|
},
|
|
262
|
-
async
|
|
284
|
+
async filePreview() {
|
|
263
285
|
try {
|
|
264
286
|
const options = {
|
|
265
287
|
title: '预览文件.txt', // 文件的标题
|
|
@@ -283,6 +305,9 @@ export default {
|
|
|
283
305
|
}
|
|
284
306
|
},
|
|
285
307
|
},
|
|
308
|
+
mounted() {
|
|
309
|
+
window.updateAudioDisplay = this.updateAudioDisplay;
|
|
310
|
+
},
|
|
286
311
|
beforeRouteEnter (to, from, next) {
|
|
287
312
|
next(vm => {
|
|
288
313
|
if (from.name !== null) {
|
package/package.json
CHANGED
package/src/sdk/LamboJsBridge.js
CHANGED
package/src/sdk/YunTuAdapter.js
CHANGED
|
@@ -6,12 +6,7 @@ class YunTuAdapter {
|
|
|
6
6
|
this.isInitialized = false;
|
|
7
7
|
this.audioUrl = null; // 录音文件的 URL
|
|
8
8
|
this.fileName = ''; // 录音文件名称
|
|
9
|
-
this.fileSize = 0; // 录音文件大小
|
|
10
9
|
this.fileType = ''; // 录音文件类型
|
|
11
|
-
this.errorMessage = ''; // 错误信息
|
|
12
|
-
this.recorder = null; // MediaRecorder 实例
|
|
13
|
-
this.streams = null; // 音频流
|
|
14
|
-
this.chunks = []; // 录音数据块
|
|
15
10
|
this.initializePlugin(options.pluginConfig);
|
|
16
11
|
}
|
|
17
12
|
|
|
@@ -33,144 +28,89 @@ class YunTuAdapter {
|
|
|
33
28
|
}
|
|
34
29
|
}
|
|
35
30
|
|
|
36
|
-
//
|
|
37
|
-
async startRecording({
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
// 创建音频分析器
|
|
58
|
-
this.analyser = this.audioContext.createAnalyser();
|
|
59
|
-
console.log("创建音频分析器:", this.analyser);
|
|
60
|
-
|
|
61
|
-
const microphone = this.audioContext.createMediaStreamSource(stream);
|
|
62
|
-
microphone.connect(this.analyser);
|
|
63
|
-
this.analyser.fftSize = fftSize;
|
|
64
|
-
console.log("音频分析器配置完成,FFT Size:", this.analyser.fftSize);
|
|
65
|
-
|
|
66
|
-
// 创建 MediaRecorder 实例
|
|
67
|
-
this.recorder = new MediaRecorder(stream);
|
|
68
|
-
console.log("创建 MediaRecorder 实例:", this.recorder);
|
|
69
|
-
|
|
70
|
-
// 监听数据可用事件
|
|
71
|
-
this.recorder.ondataavailable = (e) => {
|
|
72
|
-
console.log("收到录音数据块,大小:", e.data.size, "字节");
|
|
73
|
-
this.chunks.push(e.data);
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
// 返回 Promise
|
|
77
|
-
return new Promise((resolve, reject) => {
|
|
78
|
-
// 监听录音停止事件
|
|
79
|
-
this.recorder.onstop = () => {
|
|
80
|
-
console.log("录音停止,生成音频文件...");
|
|
81
|
-
const blob = new Blob(this.chunks, { type: 'audio/ogg' });
|
|
82
|
-
this.audioUrl = URL.createObjectURL(blob); // 生成录音文件 URL
|
|
83
|
-
const file = new File([blob], fileName, { type: 'audio/ogg' });
|
|
84
|
-
this.fileName = file.name;
|
|
85
|
-
this.fileSize = file.size;
|
|
86
|
-
this.fileType = file.type;
|
|
87
|
-
console.log("生成的音频文件:", file);
|
|
88
|
-
|
|
89
|
-
// 返回包含音频 URL 和文件对象的对象
|
|
90
|
-
resolve({
|
|
91
|
-
audioUrl: this.audioUrl,
|
|
92
|
-
file: file
|
|
93
|
-
});
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
// 启动静音检测
|
|
97
|
-
this.startSilenceDetection({
|
|
98
|
-
silenceThreshold,
|
|
99
|
-
silenceDuration,
|
|
100
|
-
silenceDelay
|
|
101
|
-
});
|
|
31
|
+
// 录音:开始录音(支持自动和手动模式)
|
|
32
|
+
async startRecording(options = { auto: false }) {
|
|
33
|
+
return new Promise((resolve, reject) => {
|
|
34
|
+
if (window.autoRecord && typeof window.autoRecord.startRecording === 'function') {
|
|
35
|
+
window.autoRecord.startRecording(
|
|
36
|
+
(result) => {
|
|
37
|
+
console.log("录音开始:", result);
|
|
38
|
+
resolve(result);
|
|
39
|
+
},
|
|
40
|
+
(error) => {
|
|
41
|
+
console.error("录音错误:", error);
|
|
42
|
+
reject(error);
|
|
43
|
+
},
|
|
44
|
+
JSON.stringify(options) // 传入参数:{auto: false} 表示手动录音,{auto: true} 表示自动录音
|
|
45
|
+
);
|
|
46
|
+
} else {
|
|
47
|
+
reject(new Error("autoRecord 接口不可用"));
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
102
51
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
52
|
+
// 录音:结束录音,并返回录音结果
|
|
53
|
+
async stopRecording() {
|
|
54
|
+
return new Promise((resolve, reject) => {
|
|
55
|
+
if (window.autoRecord && typeof window.autoRecord.stopRecording === 'function') {
|
|
56
|
+
window.autoRecord.stopRecording(
|
|
57
|
+
(result) => {
|
|
58
|
+
console.log("录音停止,返回结果:", result);
|
|
59
|
+
// 如果返回数据为字符串,则尝试解析为对象
|
|
60
|
+
try {
|
|
61
|
+
if (typeof result === "string") {
|
|
62
|
+
result = JSON.parse(result);
|
|
63
|
+
}
|
|
64
|
+
} catch (e) {
|
|
65
|
+
console.error("JSON.parse error:", e);
|
|
66
|
+
}
|
|
67
|
+
resolve(result);
|
|
68
|
+
},
|
|
69
|
+
(error) => {
|
|
70
|
+
console.error("录音结束错误:", error);
|
|
71
|
+
// 同样尝试解析错误信息
|
|
72
|
+
try {
|
|
73
|
+
if (typeof error === "string") {
|
|
74
|
+
error = JSON.parse(error);
|
|
75
|
+
}
|
|
76
|
+
} catch (e) {
|
|
77
|
+
console.error("JSON.parse error:", e);
|
|
78
|
+
}
|
|
79
|
+
reject(error);
|
|
80
|
+
}
|
|
81
|
+
);
|
|
82
|
+
} else {
|
|
83
|
+
reject(new Error("autoRecord 接口不可用"));
|
|
84
|
+
}
|
|
85
|
+
});
|
|
112
86
|
}
|
|
113
87
|
|
|
114
|
-
//
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const bufferLength = this.analyser.frequencyBinCount;
|
|
122
|
-
const dataArray = new Uint8Array(bufferLength);
|
|
123
|
-
let silenceStart = Date.now();
|
|
124
|
-
let isSpeaking = false;
|
|
88
|
+
// 新增下载文件接口
|
|
89
|
+
async downloadFile({ fileUrl, fileName = 'downloadedFile' }) {
|
|
90
|
+
try {
|
|
91
|
+
const response = await fetch(fileUrl);
|
|
92
|
+
if (!response.ok) {
|
|
93
|
+
throw new Error(`Failed to fetch file from ${fileUrl}`);
|
|
94
|
+
}
|
|
125
95
|
|
|
126
|
-
|
|
127
|
-
this.analyser.getByteFrequencyData(dataArray);
|
|
128
|
-
const volume = Math.max(...dataArray);
|
|
129
|
-
console.debug("当前音量:", volume);
|
|
96
|
+
const fileBlob = await response.blob();
|
|
130
97
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
isSpeaking = true;
|
|
134
|
-
silenceStart = Date.now();
|
|
135
|
-
} else if (isSpeaking && Date.now() - silenceStart > silenceDuration) {
|
|
136
|
-
// 超过指定静音时长
|
|
137
|
-
console.log(`检测到持续 ${silenceDuration / 1000} 秒静音,停止录音`);
|
|
138
|
-
this.stopRecording();
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
98
|
+
// 创建一个下载的 Blob URL
|
|
99
|
+
const downloadUrl = URL.createObjectURL(fileBlob);
|
|
141
100
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
}
|
|
145
|
-
};
|
|
101
|
+
// 通过 window.open 来触发文件下载(无 <a> 标签)
|
|
102
|
+
window.open(downloadUrl, '_blank');
|
|
146
103
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if (this.recorder && this.recorder.state === 'recording') {
|
|
150
|
-
console.log("静音检测正式开始");
|
|
151
|
-
requestAnimationFrame(checkVolume);
|
|
152
|
-
}
|
|
153
|
-
}, silenceDelay);
|
|
154
|
-
}
|
|
104
|
+
// 清理临时 URL
|
|
105
|
+
URL.revokeObjectURL(downloadUrl);
|
|
155
106
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
if (this.recorder && this.recorder.state === 'recording') {
|
|
160
|
-
this.recorder.stop();
|
|
161
|
-
console.log("录音已停止");
|
|
162
|
-
}
|
|
163
|
-
if (this.streams) {
|
|
164
|
-
this.streams.getTracks().forEach((track) => {
|
|
165
|
-
track.stop();
|
|
166
|
-
console.log("停止音频轨道:", track);
|
|
167
|
-
});
|
|
107
|
+
console.log(`File "${fileName}" downloaded successfully.`);
|
|
108
|
+
} catch (error) {
|
|
109
|
+
console.error('Download failed:', error);
|
|
168
110
|
}
|
|
169
|
-
this.chunks = []; // 清空录音数据块
|
|
170
|
-
this.audioContext.close();
|
|
171
|
-
console.log("音频上下文已关闭");
|
|
172
111
|
}
|
|
173
112
|
|
|
113
|
+
|
|
174
114
|
async getPlatform() {
|
|
175
115
|
return {
|
|
176
116
|
platform: 'Yuntu'
|