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);