{"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"]}