Skip to content

Commit

Permalink
cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
albho committed Jul 25, 2024
1 parent fec1efd commit 6650d58
Show file tree
Hide file tree
Showing 7 changed files with 43 additions and 42 deletions.
15 changes: 11 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,8 @@ const { PvSpeaker } = require("@picovoice/pvspeaker-node");

const sampleRate = 22050;
const bitsPerSample = 16;
const speaker = new PvSpeaker(sampleRate, bitsPerSample);
const deviceIndex = 0;
const speaker = new PvSpeaker(sampleRate, bitsPerSample, deviceIndex);

speaker.start()
```
Expand All @@ -198,16 +199,22 @@ function getNextAudioFrame(): ArrayBuffer {
speaker.write(getNextAudioFrame())
```

To stop recording, call `stop()` on the instance:
When all frames have been written, run `flush()` to wait for all buffered PCM data to be played:

```typescript
speaker.flush()
```

To stop playing audio, run `stop()`:

```typescript
speaker.stop();
```

Once you are done, free the resources acquired by PvSpeaker. You do not have to call `stop()` before `release()`:
Once you are done (i.e. no longer need PvSpeaker to write and/or play PCM), free the resources acquired by PvSpeaker by calling `release`. You do not have to call `stop` before `release`:

```typescript
speaker.release();
```

For more information about the PvSpeaker Node.js SDK, go to [binding/nodejs](binding/nodejs).
For more information about the PvSpeaker Node.js SDK, go to [binding/nodejs](binding/nodejs).
12 changes: 9 additions & 3 deletions binding/nodejs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,18 +57,24 @@ function getNextAudioFrame(): ArrayBuffer {
speaker.write(getNextAudioFrame())
```

To stop recording, call `stop()` on the instance:
When all frames have been written, run `flush()` to wait for all buffered PCM data to be played:

```typescript
speaker.flush()
```

To stop playing audio, run `stop()`:

```typescript
speaker.stop();
```

Once you are done, free the resources acquired by PvSpeaker. You do not have to call `stop()` before `release()`:
Once you are done (i.e. no longer need PvSpeaker to write and/or play PCM), free the resources acquired by PvSpeaker by calling `release`. You do not have to call `stop` before `release`:

```typescript
speaker.release();
```

## Demos

[@picovoice/pvspeaker-demo](https://www.npmjs.com/package/@picovoice/pvspeaker-demo) provides command-line utilities for playing audio from a file.
[@picovoice/pvspeaker-demo](https://www.npmjs.com/package/@picovoice/pvspeaker-demo) provides command-line utilities for playing audio from a file.
15 changes: 9 additions & 6 deletions binding/nodejs/src/pv_speaker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ class PvSpeaker {
}

/**
* Starts the audio output device. After starting, PCM frames can be sent to the audio output device via `write`.
* Starts the audio output device. After starting, PCM frames can be sent to the audio output device via `write` and/or `flush`.
*/
public start(): void {
const status = PvSpeaker._pvSpeaker.start(this._handle);
Expand All @@ -126,12 +126,13 @@ class PvSpeaker {
* Only writes as much PCM data as the internal circular buffer can currently fit, and
* returns the length of the PCM data that was successfully written.
*
* @returns {number}
* @param {ArrayBuffer} pcm PCM data to be played.
* @returns {number} The length of the PCM data that was successfully written.
*/
public write(pcm: ArrayBuffer): number {
const result = PvSpeaker._pvSpeaker.write(this._handle, this._bitsPerSample, pcm);
if (result.status !== PvSpeakerStatus.SUCCESS) {
throw pvSpeakerStatusToException(result.status, "PvSpeaker failed to write audio data frame.");
throw pvSpeakerStatusToException(result.status, "PvSpeaker failed to write PCM data.");
}

return result.written_length;
Expand All @@ -140,20 +141,22 @@ class PvSpeaker {
/**
* Synchronous call to write PCM data to the internal circular buffer for audio playback.
* This call blocks the thread until all PCM data has been successfully written and played.
* To simply wait for previously written PCM data to finish playing, call `flush` with no arguments.
*
* @returns {number}
* @param {ArrayBuffer} pcm PCM data to be played.
* @returns {number} The length of the PCM data that was successfully written.
*/
public flush(pcm: ArrayBuffer = new ArrayBuffer(0)): number {
const result = PvSpeaker._pvSpeaker.flush(this._handle, this._bitsPerSample, pcm);
if (result.status !== PvSpeakerStatus.SUCCESS) {
throw pvSpeakerStatusToException(result.status, "PvSpeaker failed to flush audio data frame.");
throw pvSpeakerStatusToException(result.status, "PvSpeaker failed to flush PCM data.");
}

return result.written_length;
}

/**
* Returns the name of the selected device used to capture audio.
* Returns the name of the selected device used to play audio.
*
* @returns {string} Name of the selected audio device.
*/
Expand Down
9 changes: 3 additions & 6 deletions binding/nodejs/test/pv_speaker.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ describe("Test PvSpeaker", () => {

test("start stop", async () => {
expect(() => {
const pcm = new ArrayBuffer(SAMPLE_RATE);
const speaker = new PvSpeaker(SAMPLE_RATE, BITS_PER_SAMPLE);

speaker.start();
const pcm = new ArrayBuffer(SAMPLE_RATE);
speaker.write(pcm);
speaker.flush(pcm);
speaker.flush();
Expand All @@ -48,17 +49,15 @@ describe("Test PvSpeaker", () => {
const bytesPerSample = (BITS_PER_SAMPLE / 8)

Check warning on line 49 in binding/nodejs/test/pv_speaker.test.ts

View workflow job for this annotation

GitHub Actions / check-nodejs-codestyle

Missing semicolon
const pcm = new ArrayBuffer(circularBufferSize * bytesPerSample + bytesPerSample);
const pcmLength = pcm.byteLength / bytesPerSample;

const speaker = new PvSpeaker(SAMPLE_RATE, BITS_PER_SAMPLE, { bufferSizeSecs });
speaker.start();

speaker.start();
let writeCount = speaker.write(pcm);
expect(writeCount).toBe(circularBufferSize);
writeCount = speaker.flush(pcm);
expect(writeCount).toBe(pcmLength);
writeCount = speaker.flush();
expect(writeCount).toBe(0);

speaker.release();
});

Expand All @@ -67,10 +66,8 @@ describe("Test PvSpeaker", () => {

speaker.start();
expect(speaker.isStarted).toBeTruthy();

speaker.stop();
expect(speaker.isStarted).toBeFalsy();

speaker.release();
});

Expand Down
30 changes: 11 additions & 19 deletions demo/nodejs/demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,15 @@ if (process.argv.length < 2) {
}
program.parse(process.argv);

function splitList(inputArrayBuffer, maxSublistLength) {
const inputArray = new Uint8Array(inputArrayBuffer);
function splitArrayBuffer(arrBuf, maxSize) {
const inputArray = new Uint8Array(arrBuf);
const result = [];
for (let i = 0; i < inputArray.length; i += maxSublistLength) {
let endIndex = Math.min(i + maxSublistLength, inputArray.length);
for (let i = 0; i < inputArray.length; i += maxSize) {
let endIndex = Math.min(i + maxSize, inputArray.length);
const chunk = new Uint8Array(inputArray.slice(i, endIndex));
result.push(chunk.buffer);
}

return result;
}

Expand All @@ -65,7 +65,6 @@ async function runDemo() {
}
} else {
const wavBuffer = fs.readFileSync(inputWavPath);

if (wavBuffer.toString('utf8', 0, 4) !== 'RIFF' || wavBuffer.toString('utf8', 8, 12) !== 'WAVE') {
throw new Error('Invalid WAV file');
}
Expand All @@ -83,31 +82,25 @@ async function runDemo() {
throw new Error('WAV file must have a single channel (MONO)');
}

const dataChunkOffset = wavBuffer.indexOf('data', formatChunkOffset + 24);
if (dataChunkOffset === -1) {
throw new Error('Invalid WAV file: data chunk not found');
}

const headerSize = 44;
const pcmBuffer = wavBuffer.buffer.slice(headerSize);

let speaker = null;
try {
speaker = new PvSpeaker(sampleRate, bitsPerSample, { bufferSizeSecs, deviceIndex });
const speaker = new PvSpeaker(sampleRate, bitsPerSample, { bufferSizeSecs, deviceIndex });
console.log(`Using PvSpeaker version: ${speaker.version}`);
console.log(`Using device: ${speaker.getSelectedDevice()}`);

speaker.start();

console.log("Playing audio...");
const bytesPerSample = bitsPerSample / 8;
const pcmList = splitList(pcmBuffer, sampleRate * bytesPerSample);
const pcmChunks = splitArrayBuffer(pcmBuffer, sampleRate * bytesPerSample);

pcmList.forEach(pcmSublist => {
let sublistLength = pcmSublist.byteLength / bytesPerSample;
pcmChunks.forEach(pcmChunk => {
let sublistLength = pcmChunk.byteLength / bytesPerSample;
let totalWrittenLength = 0;
while (totalWrittenLength < sublistLength) {
let remainingBuffer = pcmSublist.slice(totalWrittenLength);
let remainingBuffer = pcmChunk.slice(totalWrittenLength);
let writtenLength = speaker.write(remainingBuffer);
totalWrittenLength += writtenLength;
}
Expand All @@ -118,10 +111,9 @@ async function runDemo() {

console.log("Finished playing audio...");
speaker.stop();
speaker.release();
} catch (e) {
console.log(e.message);
} finally {
speaker?.release();
}
}
}
Expand Down
1 change: 0 additions & 1 deletion project/Testing/Temporary/CTestCostData.txt

This file was deleted.

3 changes: 0 additions & 3 deletions project/Testing/Temporary/LastTest.log

This file was deleted.

0 comments on commit 6650d58

Please sign in to comment.