UNPKG

@kmamal/sdl

Version:
124 lines (92 loc) 4.08 kB
const Globals = require('../globals') const Bindings = require('../bindings') const Enums = require('../enums') const { EventsViaPoll } = require('../events/events-via-poll') const { AudioFormatHelpers } = require('./format-helpers') const validEvents = [ 'close' ] class AudioInstance extends EventsViaPoll { constructor (device, options) { super(validEvents) const { name, type } = device const { channels = 1, frequency = 48000, format = 'f32', buffered = 4096, } = options if (name !== undefined && name !== null && typeof name !== 'string') { throw Object.assign(new Error("device.name must be a string"), { name }) } // We already tested device.type in sdl.audio.openDevice() if (!Number.isInteger(channels)) { throw Object.assign(new Error("channels must be an integer"), { channels }) } if (![ 1, 2, 4, 6 ].includes(channels)) { throw Object.assign(new Error("invalid channels"), { channels }) } if (!Number.isInteger(frequency)) { throw Object.assign(new Error("frequency must be an integer"), { frequency }) } if (frequency <= 0) { throw Object.assign(new Error("invalid frequency"), { frequency }) } if (typeof format !== 'string') { throw Object.assign(new Error("format must be a string"), { format }) } if (!Number.isInteger(buffered)) { throw Object.assign(new Error("buffered must be an integer"), { buffered }) } if (buffered <= 0) { throw Object.assign(new Error("invalid buffered"), { buffered }) } if (buffered !== 2 ** (32 - Math.clz32(buffered) - 1)) { throw Object.assign(new Error("invalid buffered"), { buffered }) } const _format = Enums.audioFormat[format] if (_format === undefined) { throw Object.assign(new Error("invalid format"), { format }) } this._id = Bindings.audio_open(name ?? null, type === 'recording', frequency, _format, channels, buffered) this._device = device this._name = name this._buffered = buffered this._channels = channels this._format = format this._frequency = frequency this._playing = false this._closed = false const helper = AudioFormatHelpers[this._format] this._bytesPerSample = helper.bytesPerSample this._minSampleValue = helper.minSampleValue this._maxSampleValue = helper.maxSampleValue this._zeroSampleValue = helper.zeroSampleValue this._reader = helper.reader this._writer = helper.writer Globals.audioInstances.set(this._id, this) } get id () { return this._id } get device () { return this._device } get name () { return this._name } get channels () { return this._channels } get frequency () { return this._frequency } get format () { return this._format } get bytesPerSample () { return this._bytesPerSample } get minSampleValue () { return this._minSampleValue } get maxSampleValue () { return this._maxSampleValue } get zeroSampleValue () { return this._zeroSampleValue } readSample (buffer, offset) { return this._reader.call(buffer, offset) } writeSample (buffer, value, offset) { return this._writer.call(buffer, value, offset) } get buffered () { return this._buffered } get playing () { return this._playing } play (play = true) { if (this._closed) { throw Object.assign(new Error("instance is closed"), { id: this._id }) } if (typeof play !== 'boolean') { throw Object.assign(new Error("play must be a boolean"), { play }) } Bindings.audio_play(this._id, play) this._playing = play } pause () { this.play(false) } get queued () { if (this._closed) { throw Object.assign(new Error("instance is closed"), { id: this._id }) } return Bindings.audio_getQueueSize(this._id) } clearQueue () { if (this._closed) { throw Object.assign(new Error("instance is closed"), { id: this._id }) } Bindings.audio_clearQueue(this._id) } get closed () { return this._closed } close () { if (this._closed) { throw Object.assign(new Error("instance is closed"), { id: this._id }) } this.emit('close') this.removeAllListeners() this._closed = true Bindings.audio_close(this._id) Globals.audioInstances.delete(this._id) } } module.exports = { AudioInstance }