UNPKG

@euirim/microsoft-cognitiveservices-speech-sdk

Version:
1 lines 5.69 kB
{"version":3,"sources":["src/common.browser/PCMRecorder.ts"],"names":[],"mappings":"AAGA,OAAO,EAAkB,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,qBAAa,WAAY,YAAW,SAAS;IACzC,OAAO,CAAC,kBAAkB,CAAkB;IAC5C,OAAO,CAAC,yBAAyB,CAAS;IAEnC,MAAM,+FAyFZ;IAEM,qBAAqB,kCAY3B;IAEM,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;CAG1C","file":"PCMRecorder.d.ts","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT license.\n\nimport { RiffPcmEncoder, Stream } from \"../common/Exports\";\nimport { IRecorder } from \"./IRecorder\";\n\nexport class PcmRecorder implements IRecorder {\n private privMediaResources: IMediaResources;\n private privSpeechProcessorScript: string; // speech-processor.js Url\n\n public record = (context: AudioContext, mediaStream: MediaStream, outputStream: Stream<ArrayBuffer>): void => {\n const desiredSampleRate = 16000;\n\n const scriptNode = (() => {\n let bufferSize = 0;\n try {\n return context.createScriptProcessor(bufferSize, 1, 1);\n } catch (error) {\n // Webkit (<= version 31) requires a valid bufferSize.\n bufferSize = 2048;\n let audioSampleRate = context.sampleRate;\n while (bufferSize < 16384 && audioSampleRate >= (2 * desiredSampleRate)) {\n bufferSize <<= 1;\n audioSampleRate >>= 1;\n }\n return context.createScriptProcessor(bufferSize, 1, 1);\n }\n })();\n\n const waveStreamEncoder = new RiffPcmEncoder(context.sampleRate, desiredSampleRate);\n let needHeader: boolean = true;\n const that = this;\n scriptNode.onaudioprocess = (event: AudioProcessingEvent) => {\n const inputFrame = event.inputBuffer.getChannelData(0);\n\n if (outputStream && !outputStream.isClosed) {\n const waveFrame = waveStreamEncoder.encode(needHeader, inputFrame);\n if (!!waveFrame) {\n outputStream.writeStreamChunk({\n buffer: waveFrame,\n isEnd: false,\n timeReceived: Date.now(),\n });\n needHeader = false;\n }\n }\n };\n\n const micInput = context.createMediaStreamSource(mediaStream);\n\n // https://webaudio.github.io/web-audio-api/#audioworklet\n // Using AudioWorklet to improve audio quality and avoid audio glitches due to blocking the UI thread\n\n if (!!this.privSpeechProcessorScript && !!context.audioWorklet) {\n context.audioWorklet\n .addModule(this.privSpeechProcessorScript)\n .then(() => {\n const workletNode = new AudioWorkletNode(context, \"speech-processor\");\n workletNode.port.onmessage = (ev: MessageEvent) => {\n const inputFrame: Float32Array = ev.data as Float32Array;\n\n if (outputStream && !outputStream.isClosed) {\n const waveFrame = waveStreamEncoder.encode(needHeader, inputFrame);\n if (!!waveFrame) {\n outputStream.writeStreamChunk({\n buffer: waveFrame,\n isEnd: false,\n timeReceived: Date.now(),\n });\n needHeader = false;\n }\n }\n };\n micInput.connect(workletNode);\n workletNode.connect(context.destination);\n this.privMediaResources = {\n scriptProcessorNode: workletNode,\n source: micInput,\n stream: mediaStream,\n };\n })\n .catch(() => {\n micInput.connect(scriptNode);\n scriptNode.connect(context.destination);\n this.privMediaResources = {\n scriptProcessorNode: scriptNode,\n source: micInput,\n stream: mediaStream,\n };\n });\n } else {\n micInput.connect(scriptNode);\n scriptNode.connect(context.destination);\n this.privMediaResources = {\n scriptProcessorNode: scriptNode,\n source: micInput,\n stream: mediaStream,\n };\n }\n }\n\n public releaseMediaResources = (context: AudioContext): void => {\n if (this.privMediaResources) {\n if (this.privMediaResources.scriptProcessorNode) {\n this.privMediaResources.scriptProcessorNode.disconnect(context.destination);\n this.privMediaResources.scriptProcessorNode = null;\n }\n if (this.privMediaResources.source) {\n this.privMediaResources.source.disconnect();\n this.privMediaResources.stream.getTracks().forEach((track: any) => track.stop());\n this.privMediaResources.source = null;\n }\n }\n }\n\n public setWorkletUrl(url: string): void {\n this.privSpeechProcessorScript = url;\n }\n}\n\ninterface IMediaResources {\n source: MediaStreamAudioSourceNode;\n scriptProcessorNode: ScriptProcessorNode | AudioWorkletNode;\n stream: MediaStream;\n}\n"]}