{"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\n/* eslint-disable max-classes-per-file */\n\nimport {\n    connectivity,\n    ISpeechConfigAudioDevice,\n    type,\n} from \"../../common.speech/Exports.js\";\nimport {\n    AudioSourceEvent,\n    AudioSourceInitializingEvent,\n    AudioSourceReadyEvent,\n    AudioStreamNodeAttachedEvent,\n    AudioStreamNodeAttachingEvent,\n    AudioStreamNodeDetachedEvent,\n    ChunkedArrayBufferStream,\n    Events,\n    EventSource,\n    IAudioSource,\n    IAudioStreamNode,\n    IStreamChunk,\n    Stream,\n} from \"../../common/Exports.js\";\nimport { createNoDashGuid } from \"../../common/Guid.js\";\nimport { AudioStreamFormat, PullAudioInputStreamCallback } from \"../Exports.js\";\nimport { AudioStreamFormatImpl } from \"./AudioStreamFormat.js\";\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        return;\n    }\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 */\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 */\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 Promise.resolve(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 turnOn(): Promise<void> {\n        this.onEvent(new AudioSourceInitializingEvent(this.privId)); // no stream id\n        this.onEvent(new AudioSourceReadyEvent(this.privId));\n        return;\n    }\n\n    public async attach(audioNodeId: string): Promise<IAudioStreamNode> {\n        this.onEvent(new AudioStreamNodeAttachingEvent(this.privId, audioNodeId));\n\n        await this.turnOn();\n        const stream = this.privStream;\n        this.onEvent(new AudioStreamNodeAttachedEvent(this.privId, audioNodeId));\n        return {\n            detach: async (): Promise<void> => {\n                this.onEvent(new AudioStreamNodeDetachedEvent(this.privId, audioNodeId));\n                return this.turnOff();\n            },\n            id: (): string => audioNodeId,\n            read: (): Promise<IStreamChunk<ArrayBuffer>> => stream.read(),\n        };\n    }\n\n    public detach(audioNodeId: string): void {\n        this.onEvent(new AudioStreamNodeDetachedEvent(this.privId, audioNodeId));\n    }\n\n    public turnOff(): Promise<void> {\n        return;\n    }\n\n    public get events(): EventSource<AudioSourceEvent> {\n        return this.privEvents;\n    }\n\n    public get deviceInfo(): Promise<ISpeechConfigAudioDevice> {\n        return Promise.resolve({\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 */\nexport abstract class PullAudioInputStream extends AudioInputStream {\n    /**\n     * Creates and initializes and instance.\n     * @constructor\n     */\n    protected constructor() {\n super();\n}\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 */\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 Promise.resolve(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 turnOn(): Promise<void> {\n        this.onEvent(new AudioSourceInitializingEvent(this.privId)); // no stream id\n        this.onEvent(new AudioSourceReadyEvent(this.privId));\n        return;\n    }\n\n    public async attach(audioNodeId: string): Promise<IAudioStreamNode> {\n        this.onEvent(new AudioStreamNodeAttachingEvent(this.privId, audioNodeId));\n\n        await this.turnOn();\n        this.onEvent(new AudioStreamNodeAttachedEvent(this.privId, audioNodeId));\n        return {\n            detach: (): Promise<void> => {\n                this.privCallback.close();\n                this.onEvent(new AudioStreamNodeDetachedEvent(this.privId, audioNodeId));\n                return this.turnOff();\n            },\n            id: (): string => audioNodeId,\n            read: (): Promise<IStreamChunk<ArrayBuffer>> => {\n                let totalBytes: number = 0;\n                let transmitBuff: ArrayBuffer;\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                    // 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                    // If there are no bytes to read, just break out and be done.\n                    if (0 === pulledBytes) {\n                        break;\n                    }\n                    totalBytes += pulledBytes;\n                }\n                return Promise.resolve<IStreamChunk<ArrayBuffer>>({\n                    buffer: transmitBuff.slice(0, totalBytes),\n                    isEnd: this.privIsClosed || totalBytes === 0,\n                    timeReceived: Date.now(),\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<void> {\n        return;\n    }\n\n    public get events(): EventSource<AudioSourceEvent> {\n        return this.privEvents;\n    }\n\n    public get deviceInfo(): Promise<ISpeechConfigAudioDevice> {\n        return Promise.resolve({\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"]}