| this.audioReadableSignal = audioReadableSignal; | this.audioReadableSignal = audioReadableSignal; | ||||
| this.audioReadableSignal.onabort = (e) => console.log(e.type); | this.audioReadableSignal.onabort = (e) => console.log(e.type); | ||||
| this.abortHandler = async (e) => { | this.abortHandler = async (e) => { | ||||
| await this.disconnect(true); | |||||
| try { | |||||
| await this.disconnect(true); | |||||
| } catch (err) { | |||||
| console.warn(err.message); | |||||
| } | |||||
| console.log( | console.log( | ||||
| `readOffset:${this.readOffset}, duration:${this.duration}, ac.currentTime:${this.ac.currentTime}`, | `readOffset:${this.readOffset}, duration:${this.duration}, ac.currentTime:${this.ac.currentTime}`, | ||||
| `generator.readyState:${this.generator.readyState}, audioWriter.desiredSize:${this.audioWriter.desiredSize}`, | `generator.readyState:${this.generator.readyState}, audioWriter.desiredSize:${this.audioWriter.desiredSize}`, | ||||
| this.osc.disconnect(); | this.osc.disconnect(); | ||||
| this.outputSource.disconnect(); | this.outputSource.disconnect(); | ||||
| this.track.stop(); | this.track.stop(); | ||||
| await this.audioWriter.close(); | |||||
| await this.audioWriter.closed; | |||||
| await this.inputReader.cancel(); | |||||
| try { | |||||
| await this.audioWriter.close(); | |||||
| await this.audioWriter.closed; | |||||
| await this.inputReader.cancel(); | |||||
| } catch (err) { | |||||
| throw err; | |||||
| } | |||||
| this.generator.stop(); | this.generator.stop(); | ||||
| if (this.recorder && this.recorder.state === 'recording') { | if (this.recorder && this.recorder.state === 'recording') { | ||||
| this.recorder.stop(); | this.recorder.stop(); | ||||
| this.init = true; | this.init = true; | ||||
| i = 44; | i = 44; | ||||
| } | } | ||||
| for (; | |||||
| i < value.buffer.byteLength; | |||||
| i++, this.readOffset++ | |||||
| ) { | |||||
| for (; i < value.buffer.byteLength; i++, this.readOffset++) { | |||||
| if (channelData.length === this.channelDataLength) { | if (channelData.length === this.channelDataLength) { | ||||
| this.inputController.enqueue(new Uint8Array(channelData)); | |||||
| channelData.length = 0; | |||||
| this.inputController.enqueue( | |||||
| new Uint8Array( | |||||
| channelData.splice(0, this.channelDataLength) | |||||
| ) | |||||
| ); | |||||
| } | } | ||||
| channelData.push(value[i]); | channelData.push(value[i]); | ||||
| } | } | ||||
| close: async () => { | close: async () => { | ||||
| console.log('Done writing input stream.'); | console.log('Done writing input stream.'); | ||||
| if (channelData.length) { | if (channelData.length) { | ||||
| this.inputController.enqueue(channelData); | |||||
| this.inputController.enqueue(new Uint8Array(channelData)); | |||||
| } | } | ||||
| this.inputController.close(); | this.inputController.close(); | ||||
| this.source.postMessage('Done writing input stream.', '*'); | this.source.postMessage('Done writing input stream.', '*'); | ||||
| this.audioReadable.pipeTo( | this.audioReadable.pipeTo( | ||||
| new WritableStream({ | new WritableStream({ | ||||
| write: async ({ timestamp }) => { | write: async ({ timestamp }) => { | ||||
| if (this.inputController.desiredSize === 0) { | |||||
| await this.disconnect(); | |||||
| const { value, done } = await this.inputReader.read(); | |||||
| if (done) { | |||||
| await this.inputReader.closed; | |||||
| try { | |||||
| await this.disconnect(); | |||||
| } catch (err) { | |||||
| console.warn(err.message); | |||||
| } | |||||
| console.log( | console.log( | ||||
| `readOffset:${this.readOffset}, duration:${this.duration}, ac.currentTime:${this.ac.currentTime}`, | `readOffset:${this.readOffset}, duration:${this.duration}, ac.currentTime:${this.ac.currentTime}`, | ||||
| `generator.readyState:${this.generator.readyState}, audioWriter.desiredSize:${this.audioWriter.desiredSize}` | `generator.readyState:${this.generator.readyState}, audioWriter.desiredSize:${this.audioWriter.desiredSize}` | ||||
| new Promise((resolve) => (this.ac.onstatechange = resolve)), | new Promise((resolve) => (this.ac.onstatechange = resolve)), | ||||
| ]); | ]); | ||||
| } | } | ||||
| const { value, done } = await this.inputReader.read(); | |||||
| if (done) { | |||||
| console.log({ done }); | |||||
| } | |||||
| const uint16 = new Uint16Array(value.buffer); | const uint16 = new Uint16Array(value.buffer); | ||||
| // https://stackoverflow.com/a/35248852 | // https://stackoverflow.com/a/35248852 | ||||
| const floats = new Float32Array(this.channelDataLength / 2); | const floats = new Float32Array(this.channelDataLength / 2); | ||||
| int >= 0x8000 ? -(0x10000 - int) / 0x8000 : int / 0x7fff; | int >= 0x8000 ? -(0x10000 - int) / 0x8000 : int / 0x7fff; | ||||
| floats[i] = float; | floats[i] = float; | ||||
| } | } | ||||
| const buffer = new AudioBuffer({ | |||||
| numberOfChannels: this.numberOfChannels, | |||||
| length: floats.length, | |||||
| sampleRate: this.sampleRate, | |||||
| }); | |||||
| buffer.getChannelData(0).set(floats); | |||||
| this.duration += buffer.duration; | |||||
| const frame = new AudioData({ | const frame = new AudioData({ | ||||
| format:'FLTP', | |||||
| format: 'FLTP', | |||||
| sampleRate: 22050, | sampleRate: 22050, | ||||
| numberOfChannels: 1, | numberOfChannels: 1, | ||||
| numberOfFrames: 220, | numberOfFrames: 220, | ||||
| timestamp, | timestamp, | ||||
| data: buffer.getChannelData(0), | |||||
| data: floats, | |||||
| }); | }); | ||||
| await this.audioWriter.write(frame); | |||||
| this.duration += (frame.duration / 10**6); | |||||
| if (this.recorder && this.recorder.state === 'inactive') { | if (this.recorder && this.recorder.state === 'inactive') { | ||||
| this.recorder.start(); | this.recorder.start(); | ||||
| } | } | ||||
| await this.audioWriter.write(frame); | |||||
| }, | }, | ||||
| abort(e) { | abort(e) { | ||||
| console.error(e.message); | console.error(e.message); | ||||
| ), | ), | ||||
| ]); | ]); | ||||
| this.resolve( | this.resolve( | ||||
| this.recorder ? await this.data.arrayBuffer() : 'Done streaming.' | |||||
| this.recorder | |||||
| ? this.data && (await this.data.arrayBuffer()) | |||||
| : 'Done streaming.' | |||||
| ); | ); | ||||
| return this.promise; | return this.promise; | ||||
| } catch (err) { | } catch (err) { |