UNPKG

@voice-ping/cognitive-services-speech

Version:

VoicePing Cognitive Services Speech SDK for JavaScript forked from Microsoft

1 lines 20.9 kB
{"version":3,"sources":["src/sdk/Audio/AudioInputStream.ts"],"names":[],"mappings":"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","file":"AudioInputStream.d.ts","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT license.\n\nimport {\n connectivity,\n ISpeechConfigAudioDevice,\n type,\n} from \"../../common.speech/Exports\";\nimport {\n AudioSourceEvent,\n AudioSourceInitializingEvent,\n AudioSourceReadyEvent,\n AudioStreamNodeAttachedEvent,\n AudioStreamNodeAttachingEvent,\n AudioStreamNodeDetachedEvent,\n ChunkedArrayBufferStream,\n Deferred,\n Events,\n EventSource,\n IAudioSource,\n IAudioStreamNode,\n IStreamChunk,\n Promise,\n PromiseHelper,\n PromiseResult,\n Stream,\n} from \"../../common/Exports\";\nimport { createNoDashGuid } from \"../../common/Guid\";\nimport { AudioStreamFormat, PullAudioInputStreamCallback } from \"../Exports\";\nimport { AudioStreamFormatImpl } from \"./AudioStreamFormat\";\n\n/**\n * Represents audio input stream used for custom audio input configurations.\n * @class AudioInputStream\n */\nexport abstract class AudioInputStream {\n\n /**\n * Creates and initializes an instance.\n * @constructor\n */\n protected constructor() { }\n\n /**\n * Creates a memory backed PushAudioInputStream with the specified audio format.\n * @member AudioInputStream.createPushStream\n * @function\n * @public\n * @param {AudioStreamFormat} format - The audio data format in which audio will be\n * written to the push audio stream's write() method (Required if format is not 16 kHz 16bit mono PCM).\n * @returns {PushAudioInputStream} The audio input stream being created.\n */\n public static createPushStream(format?: AudioStreamFormat): PushAudioInputStream {\n return PushAudioInputStream.create(format);\n }\n\n /**\n * Creates a PullAudioInputStream that delegates to the specified callback interface for read()\n * and close() methods.\n * @member AudioInputStream.createPullStream\n * @function\n * @public\n * @param {PullAudioInputStreamCallback} callback - The custom audio input object, derived from\n * PullAudioInputStreamCallback\n * @param {AudioStreamFormat} format - The audio data format in which audio will be returned from\n * the callback's read() method (Required if format is not 16 kHz 16bit mono PCM).\n * @returns {PullAudioInputStream} The audio input stream being created.\n */\n public static createPullStream(callback: PullAudioInputStreamCallback, format?: AudioStreamFormat): PullAudioInputStream {\n return PullAudioInputStream.create(callback, format);\n // throw new Error(\"Oops\");\n }\n\n /**\n * Explicitly frees any external resource attached to the object\n * @member AudioInputStream.prototype.close\n * @function\n * @public\n */\n public abstract close(): void;\n}\n\n/**\n * Represents memory backed push audio input stream used for custom audio input configurations.\n * @class PushAudioInputStream\n */\n// tslint:disable-next-line:max-classes-per-file\nexport abstract class PushAudioInputStream extends AudioInputStream {\n\n /**\n * Creates a memory backed PushAudioInputStream with the specified audio format.\n * @member PushAudioInputStream.create\n * @function\n * @public\n * @param {AudioStreamFormat} format - The audio data format in which audio will be written to the\n * push audio stream's write() method (Required if format is not 16 kHz 16bit mono PCM).\n * @returns {PushAudioInputStream} The push audio input stream being created.\n */\n public static create(format?: AudioStreamFormat): PushAudioInputStream {\n return new PushAudioInputStreamImpl(format);\n }\n\n /**\n * Writes the audio data specified by making an internal copy of the data.\n * @member PushAudioInputStream.prototype.write\n * @function\n * @public\n * @param {ArrayBuffer} dataBuffer - The audio buffer of which this function will make a copy.\n */\n public abstract write(dataBuffer: ArrayBuffer): void;\n\n /**\n * Closes the stream.\n * @member PushAudioInputStream.prototype.close\n * @function\n * @public\n */\n public abstract close(): void;\n}\n\n/**\n * Represents memory backed push audio input stream used for custom audio input configurations.\n * @private\n * @class PushAudioInputStreamImpl\n */\n// tslint:disable-next-line:max-classes-per-file\nexport class PushAudioInputStreamImpl extends PushAudioInputStream implements IAudioSource {\n\n private privFormat: AudioStreamFormatImpl;\n private privId: string;\n private privEvents: EventSource<AudioSourceEvent>;\n private privStream: Stream<ArrayBuffer>;\n\n /**\n * Creates and initalizes an instance with the given values.\n * @constructor\n * @param {AudioStreamFormat} format - The audio stream format.\n */\n public constructor(format?: AudioStreamFormat) {\n super();\n if (format === undefined) {\n this.privFormat = AudioStreamFormatImpl.getDefaultInputFormat();\n } else {\n this.privFormat = format as AudioStreamFormatImpl;\n }\n this.privEvents = new EventSource<AudioSourceEvent>();\n this.privId = createNoDashGuid();\n this.privStream = new ChunkedArrayBufferStream(this.privFormat.avgBytesPerSec / 10);\n }\n\n /**\n * Format information for the audio\n */\n public get format(): Promise<AudioStreamFormatImpl> {\n return PromiseHelper.fromResult(this.privFormat);\n }\n\n /**\n * Writes the audio data specified by making an internal copy of the data.\n * @member PushAudioInputStreamImpl.prototype.write\n * @function\n * @public\n * @param {ArrayBuffer} dataBuffer - The audio buffer of which this function will make a copy.\n */\n public write(dataBuffer: ArrayBuffer): void {\n this.privStream.writeStreamChunk({\n buffer: dataBuffer,\n isEnd: false,\n timeReceived: Date.now()\n });\n }\n\n /**\n * Closes the stream.\n * @member PushAudioInputStreamImpl.prototype.close\n * @function\n * @public\n */\n public close(): void {\n this.privStream.close();\n }\n\n public id(): string {\n return this.privId;\n }\n\n public get blob(): Promise<Blob | Buffer> {\n return this.attach(\"id\").onSuccessContinueWithPromise<Blob | Buffer>((audioNode: IAudioStreamNode) => {\n const data: ArrayBuffer[] = [];\n let bufferData = Buffer.from(\"\");\n const readCycle = (): Promise<Blob | Buffer> => {\n return audioNode.read().onSuccessContinueWithPromise<Blob | Buffer>((audioStreamChunk: IStreamChunk<ArrayBuffer>) => {\n if (!audioStreamChunk || audioStreamChunk.isEnd) {\n if (typeof (XMLHttpRequest) !== \"undefined\") {\n return PromiseHelper.fromResult(new Blob(data));\n } else {\n return PromiseHelper.fromResult(Buffer.from(bufferData));\n }\n } else {\n if (typeof (Blob) !== \"undefined\") {\n data.push(audioStreamChunk.buffer);\n } else {\n bufferData = Buffer.concat([bufferData, this.toBuffer(audioStreamChunk.buffer)]);\n }\n return readCycle();\n }\n });\n };\n return readCycle();\n });\n }\n\n public turnOn(): Promise<boolean> {\n this.onEvent(new AudioSourceInitializingEvent(this.privId)); // no stream id\n this.onEvent(new AudioSourceReadyEvent(this.privId));\n return PromiseHelper.fromResult(true);\n }\n\n public attach(audioNodeId: string): Promise<IAudioStreamNode> {\n this.onEvent(new AudioStreamNodeAttachingEvent(this.privId, audioNodeId));\n\n return this.turnOn()\n .onSuccessContinueWith<Stream<ArrayBuffer>>((_: boolean) => {\n // For now we support a single parallel reader of the pushed stream.\n // So we can simiply hand the stream to the recognizer and let it recognize.\n\n return this.privStream;\n })\n .onSuccessContinueWith((stream: Stream<ArrayBuffer>) => {\n this.onEvent(new AudioStreamNodeAttachedEvent(this.privId, audioNodeId));\n\n return {\n detach: () => {\n stream.readEnded();\n this.onEvent(new AudioStreamNodeDetachedEvent(this.privId, audioNodeId));\n this.turnOff();\n },\n id: () => {\n return audioNodeId;\n },\n read: () => {\n return stream.read();\n },\n };\n });\n }\n\n public detach(audioNodeId: string): void {\n this.onEvent(new AudioStreamNodeDetachedEvent(this.privId, audioNodeId));\n }\n\n public turnOff(): Promise<boolean> {\n return PromiseHelper.fromResult(false);\n }\n\n public get events(): EventSource<AudioSourceEvent> {\n return this.privEvents;\n }\n\n public get deviceInfo(): Promise<ISpeechConfigAudioDevice> {\n return PromiseHelper.fromResult({\n bitspersample: this.privFormat.bitsPerSample,\n channelcount: this.privFormat.channels,\n connectivity: connectivity.Unknown,\n manufacturer: \"Speech SDK\",\n model: \"PushStream\",\n samplerate: this.privFormat.samplesPerSec,\n type: type.Stream,\n });\n }\n\n private onEvent = (event: AudioSourceEvent): void => {\n this.privEvents.onEvent(event);\n Events.instance.onEvent(event);\n }\n\n private toBuffer(arrayBuffer: ArrayBuffer): Buffer {\n const buf: Buffer = Buffer.alloc(arrayBuffer.byteLength);\n const view: Uint8Array = new Uint8Array(arrayBuffer);\n for (let i = 0; i < buf.length; ++i) {\n buf[i] = view[i];\n }\n return buf;\n }\n}\n\n/*\n * Represents audio input stream used for custom audio input configurations.\n * @class PullAudioInputStream\n */\n// tslint:disable-next-line:max-classes-per-file\nexport abstract class PullAudioInputStream extends AudioInputStream {\n /**\n * Creates and initializes and instance.\n * @constructor\n */\n protected constructor() { super(); }\n\n /**\n * Creates a PullAudioInputStream that delegates to the specified callback interface for\n * read() and close() methods, using the default format (16 kHz 16bit mono PCM).\n * @member PullAudioInputStream.create\n * @function\n * @public\n * @param {PullAudioInputStreamCallback} callback - The custom audio input object,\n * derived from PullAudioInputStreamCustomCallback\n * @param {AudioStreamFormat} format - The audio data format in which audio will be\n * returned from the callback's read() method (Required if format is not 16 kHz 16bit mono PCM).\n * @returns {PullAudioInputStream} The push audio input stream being created.\n */\n public static create(callback: PullAudioInputStreamCallback, format?: AudioStreamFormat): PullAudioInputStream {\n return new PullAudioInputStreamImpl(callback, format as AudioStreamFormatImpl);\n }\n\n /**\n * Explicitly frees any external resource attached to the object\n * @member PullAudioInputStream.prototype.close\n * @function\n * @public\n */\n public abstract close(): void;\n\n}\n\n/**\n * Represents audio input stream used for custom audio input configurations.\n * @private\n * @class PullAudioInputStreamImpl\n */\n// tslint:disable-next-line:max-classes-per-file\nexport class PullAudioInputStreamImpl extends PullAudioInputStream implements IAudioSource {\n\n private privCallback: PullAudioInputStreamCallback;\n private privFormat: AudioStreamFormatImpl;\n private privId: string;\n private privEvents: EventSource<AudioSourceEvent>;\n private privIsClosed: boolean;\n private privBufferSize: number;\n\n /**\n * Creates a PullAudioInputStream that delegates to the specified callback interface for\n * read() and close() methods, using the default format (16 kHz 16bit mono PCM).\n * @constructor\n * @param {PullAudioInputStreamCallback} callback - The custom audio input object,\n * derived from PullAudioInputStreamCustomCallback\n * @param {AudioStreamFormat} format - The audio data format in which audio will be\n * returned from the callback's read() method (Required if format is not 16 kHz 16bit mono PCM).\n */\n public constructor(callback: PullAudioInputStreamCallback, format?: AudioStreamFormatImpl) {\n super();\n if (undefined === format) {\n this.privFormat = AudioStreamFormat.getDefaultInputFormat() as AudioStreamFormatImpl;\n } else {\n this.privFormat = format;\n }\n this.privEvents = new EventSource<AudioSourceEvent>();\n this.privId = createNoDashGuid();\n this.privCallback = callback;\n this.privIsClosed = false;\n this.privBufferSize = this.privFormat.avgBytesPerSec / 10;\n }\n\n /**\n * Format information for the audio\n */\n public get format(): Promise<AudioStreamFormatImpl> {\n return PromiseHelper.fromResult(this.privFormat);\n }\n\n /**\n * Closes the stream.\n * @member PullAudioInputStreamImpl.prototype.close\n * @function\n * @public\n */\n public close(): void {\n this.privIsClosed = true;\n this.privCallback.close();\n }\n\n public id(): string {\n return this.privId;\n }\n\n public get blob(): Promise<Blob | Buffer> {\n return PromiseHelper.fromError(\"Not implemented\");\n }\n\n public turnOn(): Promise<boolean> {\n this.onEvent(new AudioSourceInitializingEvent(this.privId)); // no stream id\n this.onEvent(new AudioSourceReadyEvent(this.privId));\n return PromiseHelper.fromResult(true);\n }\n\n public attach(audioNodeId: string): Promise<IAudioStreamNode> {\n this.onEvent(new AudioStreamNodeAttachingEvent(this.privId, audioNodeId));\n\n return this.turnOn()\n .onSuccessContinueWith((result: boolean) => {\n this.onEvent(new AudioStreamNodeAttachedEvent(this.privId, audioNodeId));\n\n return {\n detach: () => {\n this.privCallback.close();\n this.onEvent(new AudioStreamNodeDetachedEvent(this.privId, audioNodeId));\n this.turnOff();\n },\n id: () => {\n return audioNodeId;\n },\n read: (): Promise<IStreamChunk<ArrayBuffer>> => {\n let totalBytes: number = 0;\n let transmitBuff: ArrayBuffer;\n\n // Until we have the minimum number of bytes to send in a transmission, keep asking for more.\n while (totalBytes < this.privBufferSize) {\n // Sizing the read buffer to the delta between the perfect size and what's left means we won't ever get too much\n // data back.\n const readBuff: ArrayBuffer = new ArrayBuffer(this.privBufferSize - totalBytes);\n const pulledBytes: number = this.privCallback.read(readBuff);\n\n // If there is no return buffer yet defined, set the return buffer to the that was just populated.\n // This was, if we have enough data there's no copy penalty, but if we don't we have a buffer that's the\n // preferred size allocated.\n if (undefined === transmitBuff) {\n transmitBuff = readBuff;\n } else {\n // Not the first bite at the apple, so fill the return buffer with the data we got back.\n const intView: Int8Array = new Int8Array(transmitBuff);\n intView.set(new Int8Array(readBuff), totalBytes);\n }\n\n // If there are no bytes to read, just break out and be done.\n if (0 === pulledBytes) {\n break;\n }\n\n totalBytes += pulledBytes;\n }\n\n return PromiseHelper.fromResult<IStreamChunk<ArrayBuffer>>({\n buffer: transmitBuff.slice(0, totalBytes),\n isEnd: this.privIsClosed || totalBytes === 0,\n timeReceived: Date.now(),\n });\n },\n };\n });\n }\n\n public detach(audioNodeId: string): void {\n this.onEvent(new AudioStreamNodeDetachedEvent(this.privId, audioNodeId));\n }\n\n public turnOff(): Promise<boolean> {\n return PromiseHelper.fromResult(false);\n }\n\n public get events(): EventSource<AudioSourceEvent> {\n return this.privEvents;\n }\n\n public get deviceInfo(): Promise<ISpeechConfigAudioDevice> {\n return PromiseHelper.fromResult({\n bitspersample: this.privFormat.bitsPerSample,\n channelcount: this.privFormat.channels,\n connectivity: connectivity.Unknown,\n manufacturer: \"Speech SDK\",\n model: \"PullStream\",\n samplerate: this.privFormat.samplesPerSec,\n type: type.Stream,\n });\n }\n\n private onEvent = (event: AudioSourceEvent): void => {\n this.privEvents.onEvent(event);\n Events.instance.onEvent(event);\n }\n}\n"]}