445 lines
15 KiB
JavaScript
445 lines
15 KiB
JavaScript
if (typeof Promise !== "undefined" && !Promise.prototype.finally) {
|
||
Promise.prototype.finally = function(callback) {
|
||
const promise = this.constructor;
|
||
return this.then(
|
||
(value) => promise.resolve(callback()).then(() => value),
|
||
(reason) => promise.resolve(callback()).then(() => {
|
||
throw reason;
|
||
})
|
||
);
|
||
};
|
||
}
|
||
;
|
||
if (typeof uni !== "undefined" && uni && uni.requireGlobal) {
|
||
const global = uni.requireGlobal();
|
||
ArrayBuffer = global.ArrayBuffer;
|
||
Int8Array = global.Int8Array;
|
||
Uint8Array = global.Uint8Array;
|
||
Uint8ClampedArray = global.Uint8ClampedArray;
|
||
Int16Array = global.Int16Array;
|
||
Uint16Array = global.Uint16Array;
|
||
Int32Array = global.Int32Array;
|
||
Uint32Array = global.Uint32Array;
|
||
Float32Array = global.Float32Array;
|
||
Float64Array = global.Float64Array;
|
||
BigInt64Array = global.BigInt64Array;
|
||
BigUint64Array = global.BigUint64Array;
|
||
}
|
||
;
|
||
if (uni.restoreGlobal) {
|
||
uni.restoreGlobal(Vue, weex, plus, setTimeout, clearTimeout, setInterval, clearInterval);
|
||
}
|
||
(function(vue) {
|
||
"use strict";
|
||
function formatAppLog(type, filename, ...args) {
|
||
if (uni.__log__) {
|
||
uni.__log__(type, filename, ...args);
|
||
} else {
|
||
console[type].apply(console, [...args, filename]);
|
||
}
|
||
}
|
||
function resolveEasycom(component, easycom) {
|
||
return typeof component === "string" ? easycom : component;
|
||
}
|
||
const block0$1 = (Comp) => {
|
||
(Comp.$renderjs || (Comp.$renderjs = [])).push("record");
|
||
(Comp.$renderjsModules || (Comp.$renderjsModules = {}))["record"] = "1e54c19a";
|
||
};
|
||
const _export_sfc = (sfc, props) => {
|
||
const target = sfc.__vccOpts || sfc;
|
||
for (const [key, val] of props) {
|
||
target[key] = val;
|
||
}
|
||
return target;
|
||
};
|
||
const _sfc_main$3 = {
|
||
data() {
|
||
return {
|
||
options: null,
|
||
status: null,
|
||
onFrameRecorded: () => {
|
||
},
|
||
onDecibels: () => {
|
||
}
|
||
};
|
||
},
|
||
methods: {
|
||
start(option) {
|
||
this.options = option;
|
||
this.status = "start";
|
||
if (option.onFrameRecorded && typeof option.onFrameRecorded === "function") {
|
||
this.onFrameRecorded = option.onFrameRecorded;
|
||
}
|
||
if (option.onDecibels && typeof option.onDecibels === "function") {
|
||
this.onDecibels = option.onDecibels;
|
||
}
|
||
},
|
||
stop() {
|
||
this.status = "stop";
|
||
this.options = null;
|
||
},
|
||
frameRecorded({
|
||
isLastFrame,
|
||
frameBuffer
|
||
}) {
|
||
this.onFrameRecorded({
|
||
isLastFrame,
|
||
frameBuffer: this.base64ToUint8Array(frameBuffer)
|
||
});
|
||
},
|
||
decibels(value) {
|
||
this.onDecibels(value);
|
||
},
|
||
base64ToUint8Array(base64) {
|
||
const binaryString = atob(base64.split(",")[1] || base64);
|
||
const len = binaryString.length;
|
||
const bytes = new Uint8Array(len);
|
||
for (let i = 0; i < len; i++) {
|
||
bytes[i] = binaryString.charCodeAt(i);
|
||
}
|
||
return bytes;
|
||
},
|
||
toShowToast() {
|
||
uni.showToast({
|
||
title: "发生错误,请检查是否有麦克风权限",
|
||
icon: "none"
|
||
});
|
||
this.stop();
|
||
},
|
||
recordedChunks(base64) {
|
||
this.$emit("onStop", base64);
|
||
}
|
||
}
|
||
};
|
||
function _sfc_render$2(_ctx, _cache, $props, $setup, $data, $options) {
|
||
return vue.openBlock(), vue.createElementBlock("view", {
|
||
options: vue.wp($data.options),
|
||
"change:options": _ctx.record.startRecord,
|
||
status: vue.wp($data.status),
|
||
"change:status": _ctx.record.onStop
|
||
}, null, 8, ["options", "change:options", "status", "change:status"]);
|
||
}
|
||
if (typeof block0$1 === "function")
|
||
block0$1(_sfc_main$3);
|
||
const __easycom_0 = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["render", _sfc_render$2], ["__file", "C:/Users/1/Desktop/testAudio/测试流式传输uniapp/uni_modules/yao-RecordFrame/components/yao-RecordFrame/yao-RecordFrame.vue"]]);
|
||
const block0 = (Comp) => {
|
||
(Comp.$renderjs || (Comp.$renderjs = [])).push("renderJS");
|
||
(Comp.$renderjsModules || (Comp.$renderjsModules = {}))["renderJS"] = "5f91482f";
|
||
};
|
||
const _sfc_main$2 = {
|
||
data() {
|
||
return {
|
||
currBuffer: null,
|
||
isStop: false,
|
||
isStreamPlaying: false
|
||
};
|
||
},
|
||
methods: {
|
||
connect() {
|
||
this.ws = uni.connectSocket({
|
||
url: "ws://172.16.89.58:8000/ws/audio",
|
||
complete: () => {
|
||
formatAppLog("log", "at uni_modules/sdx-StreamPlayer/components/sdx-StreamPlayer/sdx-StreamPlayer.vue:27", "complete");
|
||
},
|
||
success: () => {
|
||
formatAppLog("log", "at uni_modules/sdx-StreamPlayer/components/sdx-StreamPlayer/sdx-StreamPlayer.vue:30", "web");
|
||
this.ws.onOpen((res) => {
|
||
formatAppLog("log", "at uni_modules/sdx-StreamPlayer/components/sdx-StreamPlayer/sdx-StreamPlayer.vue:32", "WebSocket连接已打开", res);
|
||
this.ws.onMessage((res2) => {
|
||
let messageData = res2.data;
|
||
if (typeof messageData === "string") {
|
||
try {
|
||
const parsedData = JSON.parse(messageData);
|
||
this.handleMessage(parsedData);
|
||
} catch (e) {
|
||
this.handleMessage(messageData);
|
||
}
|
||
} else if (messageData instanceof ArrayBuffer) {
|
||
this.isStreamPlaying = true;
|
||
this.currBuffer = uni.arrayBufferToBase64(messageData);
|
||
}
|
||
});
|
||
});
|
||
}
|
||
});
|
||
},
|
||
end() {
|
||
this.isStop = !this.isStop;
|
||
},
|
||
changeStreamPlaying(e) {
|
||
this.isStreamPlaying = e.type;
|
||
},
|
||
appendBuffer(messageData) {
|
||
this.isStreamPlaying = true;
|
||
this.currBuffer = uni.arrayBufferToBase64(messageData);
|
||
}
|
||
}
|
||
};
|
||
function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) {
|
||
return vue.openBlock(), vue.createElementBlock(
|
||
vue.Fragment,
|
||
null,
|
||
[
|
||
vue.createElementVNode("button", {
|
||
type: "default",
|
||
onClick: _cache[0] || (_cache[0] = (...args) => $options.connect && $options.connect(...args))
|
||
}, "播放音频"),
|
||
vue.createElementVNode("button", {
|
||
type: "default",
|
||
onClick: _cache[1] || (_cache[1] = (...args) => $options.end && $options.end(...args))
|
||
}, "结束播放"),
|
||
vue.createCommentVNode(" 逻辑层和renderjs的交互需要通过这种方式传递数据,具体看文档 "),
|
||
vue.createElementVNode("view", {
|
||
isStop: vue.wp($data.isStop),
|
||
"change:isStop": _ctx.renderJS.stop,
|
||
prop: vue.wp($data.currBuffer),
|
||
"change:prop": _ctx.renderJS.playTTS,
|
||
type: "renderjs",
|
||
module: "renderJS"
|
||
}, null, 8, ["isStop", "change:isStop", "prop", "change:prop"])
|
||
],
|
||
64
|
||
/* STABLE_FRAGMENT */
|
||
);
|
||
}
|
||
if (typeof block0 === "function")
|
||
block0(_sfc_main$2);
|
||
const __easycom_1 = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["render", _sfc_render$1], ["__file", "C:/Users/1/Desktop/testAudio/测试流式传输uniapp/uni_modules/sdx-StreamPlayer/components/sdx-StreamPlayer/sdx-StreamPlayer.vue"]]);
|
||
const _sfc_main$1 = {
|
||
data() {
|
||
return {
|
||
status: "未录音",
|
||
currentDecibels: 0,
|
||
isRecording: false,
|
||
ws: null,
|
||
// WebSocket 实例
|
||
audioContext: null,
|
||
// 音频上下文
|
||
scriptProcessor: null,
|
||
// 音频处理节点
|
||
audioBufferSource: null,
|
||
// 音频源节点
|
||
frameBufferList: [],
|
||
// 缓存音频帧
|
||
wsUrl: "ws://172.16.89.58:8000/ws/audio"
|
||
// 替换为实际后端地址
|
||
};
|
||
},
|
||
onUnload() {
|
||
this.stopRecordAndClean();
|
||
},
|
||
methods: {
|
||
// 申请录音权限
|
||
async applyRecordPermission() {
|
||
try {
|
||
const res = await uni.requestPermissions({
|
||
scope: "scope.record"
|
||
});
|
||
const isGranted = res[0].grantStatus === 1;
|
||
if (!isGranted) {
|
||
uni.showToast({
|
||
title: "请授予录音权限",
|
||
icon: "none"
|
||
});
|
||
}
|
||
return isGranted;
|
||
} catch (e) {
|
||
formatAppLog("error", "at pages/index/index.vue:51", "申请权限失败:", e);
|
||
return false;
|
||
}
|
||
},
|
||
// ArrayBuffer 转字符串
|
||
// 兼容的 ArrayBuffer 转字符串方法
|
||
arrayBufferToStringCompat(buffer) {
|
||
const uint8Array = new Uint8Array(buffer);
|
||
let str = "";
|
||
for (let i = 0; i < uint8Array.length; i++) {
|
||
str += String.fromCharCode(uint8Array[i]);
|
||
}
|
||
return str;
|
||
},
|
||
// 开始录音
|
||
async onStartRecord() {
|
||
this.ws = uni.connectSocket({
|
||
url: this.wsUrl,
|
||
//仅为示例,并非真实接口地址。
|
||
complete: () => {
|
||
formatAppLog("log", "at pages/index/index.vue:77", "complete");
|
||
},
|
||
success: () => {
|
||
formatAppLog("log", "at pages/index/index.vue:80", "web");
|
||
this.ws.onOpen((res) => {
|
||
formatAppLog("log", "at pages/index/index.vue:82", "WebSocket连接已打开", res);
|
||
this.ws.onMessage((res2) => {
|
||
let messageData = res2.data;
|
||
if (typeof messageData === "string") {
|
||
try {
|
||
const parsedData = JSON.parse(messageData);
|
||
this.handleMessage(parsedData);
|
||
} catch (e) {
|
||
this.handleMessage(messageData);
|
||
}
|
||
} else if (messageData instanceof ArrayBuffer) {
|
||
try {
|
||
this.$refs.aaa.appendBuffer(messageData);
|
||
} catch (e) {
|
||
formatAppLog("log", "at pages/index/index.vue:104", "二进制数据解析失败:", e);
|
||
}
|
||
}
|
||
});
|
||
});
|
||
},
|
||
fail: () => {
|
||
formatAppLog("log", "at pages/index/index.vue:111", "fail");
|
||
}
|
||
});
|
||
try {
|
||
this.$refs.recordFrame.start({
|
||
sampleRate: 16e3,
|
||
frameSize: 1024,
|
||
gain: 1,
|
||
onFrameRecorded: ({
|
||
isLastFrame,
|
||
frameBuffer
|
||
}) => {
|
||
this.ws.send({
|
||
data: frameBuffer
|
||
});
|
||
},
|
||
onDecibels: (decibels) => {
|
||
this.currentDecibels = decibels;
|
||
}
|
||
});
|
||
this.isRecording = true;
|
||
this.status = "录音中...";
|
||
} catch (e) {
|
||
formatAppLog("error", "at pages/index/index.vue:142", "启动录音失败:", e);
|
||
this.status = "启动录音失败";
|
||
this.isRecording = false;
|
||
}
|
||
},
|
||
// 停止录音
|
||
onStopRecord() {
|
||
this.stopRecordAndClean();
|
||
},
|
||
// 停止录音并清理资源
|
||
stopRecordAndClean() {
|
||
if (this.isRecording) {
|
||
this.$refs.recordFrame.stop();
|
||
this.isRecording = false;
|
||
this.status = "已停止录音";
|
||
}
|
||
if (this.ws) {
|
||
this.ws.close();
|
||
this.ws = null;
|
||
}
|
||
if (this.audioContext) {
|
||
this.audioContext.close();
|
||
this.audioContext = null;
|
||
this.scriptProcessor = null;
|
||
this.frameBufferList = [];
|
||
}
|
||
this.currentDecibels = 0;
|
||
},
|
||
// 接收音频帧并处理
|
||
frameRecorded({
|
||
isLastFrame,
|
||
frameBuffer
|
||
}) {
|
||
if (this.ws) {
|
||
try {
|
||
this.ws.send({
|
||
data: frameBuffer
|
||
});
|
||
} catch (e) {
|
||
formatAppLog("error", "at pages/index/index.vue:194", "发送音频帧失败:", e);
|
||
}
|
||
}
|
||
},
|
||
// 监听分贝值
|
||
onCurrentDecibels(decibels) {
|
||
},
|
||
// 录音停止回调
|
||
stopIt(base64) {
|
||
this.stopRecordAndClean();
|
||
formatAppLog("log", "at pages/index/index.vue:210", "录音停止,最终音频Base64:", (base64 == null ? void 0 : base64.substring(0, 50)) + "...");
|
||
}
|
||
}
|
||
};
|
||
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
||
const _component_yao_RecordFrame = resolveEasycom(vue.resolveDynamicComponent("yao-RecordFrame"), __easycom_0);
|
||
const _component_sdx_StreamPlayer = resolveEasycom(vue.resolveDynamicComponent("sdx-StreamPlayer"), __easycom_1);
|
||
return vue.openBlock(), vue.createElementBlock("view", { class: "container" }, [
|
||
vue.createElementVNode("button", {
|
||
onClick: _cache[0] || (_cache[0] = (...args) => $options.onStartRecord && $options.onStartRecord(...args)),
|
||
disabled: $data.isRecording
|
||
}, "开始录音", 8, ["disabled"]),
|
||
vue.createElementVNode("button", {
|
||
onClick: _cache[1] || (_cache[1] = (...args) => $options.onStopRecord && $options.onStopRecord(...args)),
|
||
disabled: !$data.isRecording
|
||
}, "停止录音", 8, ["disabled"]),
|
||
vue.createElementVNode(
|
||
"view",
|
||
{ class: "tip" },
|
||
vue.toDisplayString($data.status),
|
||
1
|
||
/* TEXT */
|
||
),
|
||
vue.createElementVNode(
|
||
"view",
|
||
{ class: "tip" },
|
||
"当前分贝:" + vue.toDisplayString($data.currentDecibels),
|
||
1
|
||
/* TEXT */
|
||
),
|
||
vue.createVNode(_component_yao_RecordFrame, {
|
||
ref: "recordFrame",
|
||
onOnFrameRecorded: $options.frameRecorded,
|
||
onCurrentDecibels: $options.onCurrentDecibels,
|
||
onOnStop: $options.stopIt
|
||
}, null, 8, ["onOnFrameRecorded", "onCurrentDecibels", "onOnStop"]),
|
||
vue.createVNode(
|
||
_component_sdx_StreamPlayer,
|
||
{ ref: "aaa" },
|
||
{
|
||
default: vue.withCtx(() => [
|
||
vue.createTextVNode("xx")
|
||
]),
|
||
_: 1
|
||
/* STABLE */
|
||
},
|
||
512
|
||
/* NEED_PATCH */
|
||
)
|
||
]);
|
||
}
|
||
const PagesIndexIndex = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["render", _sfc_render], ["__scopeId", "data-v-1cf27b2a"], ["__file", "C:/Users/1/Desktop/testAudio/测试流式传输uniapp/pages/index/index.vue"]]);
|
||
__definePage("pages/index/index", PagesIndexIndex);
|
||
const _sfc_main = {
|
||
onLaunch: function() {
|
||
formatAppLog("log", "at App.vue:4", "App Launch");
|
||
},
|
||
onShow: function() {
|
||
formatAppLog("log", "at App.vue:7", "App Show");
|
||
},
|
||
onHide: function() {
|
||
formatAppLog("log", "at App.vue:10", "App Hide");
|
||
}
|
||
};
|
||
const App = /* @__PURE__ */ _export_sfc(_sfc_main, [["__file", "C:/Users/1/Desktop/testAudio/测试流式传输uniapp/App.vue"]]);
|
||
function createApp() {
|
||
const app = vue.createVueApp(App);
|
||
return {
|
||
app
|
||
};
|
||
}
|
||
const { app: __app__, Vuex: __Vuex__, Pinia: __Pinia__ } = createApp();
|
||
uni.Vuex = __Vuex__;
|
||
uni.Pinia = __Pinia__;
|
||
__app__.provide("__globalStyles", __uniConfig.styles);
|
||
__app__._component.mpType = "app";
|
||
__app__._component.render = () => {
|
||
};
|
||
__app__.mount("#app");
|
||
})(Vue);
|