diff --git a/.github/workflows/dotnet-demo.yml b/.github/workflows/dotnet-demo.yml
index 0681258..6964b93 100644
--- a/.github/workflows/dotnet-demo.yml
+++ b/.github/workflows/dotnet-demo.yml
@@ -29,11 +29,11 @@ jobs:
os: [ubuntu-latest, windows-latest, macos-latest]
include:
- os: ubuntu-latest
- pv_recorder_platform: linux
+ pv_speaker_platform: linux
- os: windows-latest
- pv_recorder_platform: windows
+ pv_speaker_platform: windows
- os: macos-latest
- pv_recorder_platform: mac
+ pv_speaker_platform: mac
steps:
- uses: actions/checkout@v3
diff --git a/README.md b/README.md
index 76a4e7f..c2a0281 100644
--- a/README.md
+++ b/README.md
@@ -20,10 +20,12 @@ PvSpeaker is an easy-to-use, cross-platform audio player designed for real-time
- [Source Code](#source-code)
- [Demos](#demos)
- [Python](#python-demo)
+ - [.NET](#net-demo)
- [Node.js](#nodejs-demo)
- [C](#c-demo)
- [SDKs](#sdks)
- [Python](#python)
+ - [.NET](#net)
- [Node.js](#nodejs)
## Source Code
@@ -69,6 +71,24 @@ Replace `{INPUT_WAV_PATH}` with the path to the PCM WAV file you wish to play.
For more information about the Python demos go to [demo/python](demo/python).
+### .NET Demo
+
+From [demo/dotnet/PvSpeakerDemo](demo/dotnet/PvSpeakerDemo) run the
+following in the terminal to build the demo:
+
+```console
+dotnet build
+```
+
+Make sure there is a working speaker connected to your device. From [demo/dotnet/PvSpeakerDemo](demo/dotnet/PvSpeakerDemo) run the
+following in the terminal:
+
+```console
+dotnet run -- --input_wav_path ${INPUT_WAV_FILE}
+```
+
+For more information about the .NET demo, go to [demo/dotnet](demo/dotnet).
+
### Node.js Demo
Install the demo package:
@@ -179,6 +199,66 @@ speaker.delete()
For more information about the PvSpeaker Python SDK, go to [binding/python](binding/python).
+### .NET
+
+Install the .NET SDK using NuGet or the dotnet CLI:
+
+```console
+dotnet add package PvSpeaker
+```
+
+## Usage
+
+Initialize and start `PvSpeaker`:
+
+```csharp
+using Pv;
+
+PvSpeaker speaker = PvSpeaker.Create(
+ sampleRate: 22050,
+ bitsPerSample: 16);
+
+speaker.Start();
+```
+
+Write PCM data to the speaker:
+
+```csharp
+public static byte[] GetNextAudioFrame() { }
+
+int writtenLength = speaker.Write(GetNextAudioFrame());
+```
+
+Note: the `Write()` method only writes as much PCM data as the internal circular buffer can currently fit, and returns the number of samples that were successfully written.
+
+When all frames have been written, run `Flush()` to wait for all buffered PCM data (i.e. previously buffered via `Write()`) to be played:
+
+```csharp
+int flushedLength = speaker.Flush();
+```
+
+Note: calling `Flush()` with PCM data as an argument will both write that PCM data and wait for all buffered PCM data to finish.
+
+```csharp
+public static byte[] GetRemainingAudioFrames() { }
+
+int flushedLength = speaker.Flush(GetRemainingAudioFrames());
+```
+
+To stop the audio output device, run `Stop()`:
+
+```csharp
+speaker.Stop();
+```
+
+Once you are done, free the resources acquired by PvSpeaker. You do not have to call `Stop()` before `Dispose()`:
+
+```csharp
+speaker.Dispose();
+```
+
+For more information about the PvSpeaker .NET SDK, go to [binding/dotnet](binding/dotnet).
+
### Node.js
Install Node.js binding:
diff --git a/binding/dotnet/PvSpeaker/PvSpeaker.cs b/binding/dotnet/PvSpeaker/PvSpeaker.cs
index da96b62..b30a852 100644
--- a/binding/dotnet/PvSpeaker/PvSpeaker.cs
+++ b/binding/dotnet/PvSpeaker/PvSpeaker.cs
@@ -207,10 +207,10 @@ public void Stop()
///
/// Synchronous call to write PCM data to the internal circular buffer for audio playback.
/// 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. Call between `Start()` and `Stop()`.
+ /// the number of samples that were successfully written. Call between `Start()` and `Stop()`.
///
/// PCM data to be played.
- /// Length of the PCM data that was successfully written.
+ /// Number of samples that were successfully written.
public int Write(byte[] pcm)
{
GCHandle pinnedArray = GCHandle.Alloc(pcm, GCHandleType.Pinned);
@@ -231,7 +231,7 @@ public int Write(byte[] pcm)
/// Call between `Start()` and `Stop()`.
///
/// PCM data to be played.
- /// Length of the PCM data that was successfully written.
+ /// Number of samples that were successfully written.
public int Flush(byte[] pcm = null)
{
pcm = pcm ?? Array.Empty();
diff --git a/binding/dotnet/README.md b/binding/dotnet/README.md
index f7e6062..0d4bc5c 100644
--- a/binding/dotnet/README.md
+++ b/binding/dotnet/README.md
@@ -64,9 +64,9 @@ public static byte[] GetNextAudioFrame() { }
int writtenLength = speaker.Write(GetNextAudioFrame());
```
-Note: the `Write()` method 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.
+Note: the `Write()` method only writes as much PCM data as the internal circular buffer can currently fit, and returns the number of samples that were successfully written.
-When all frames have been written, run `Write()` to wait for all buffered PCM data (i.e. previously buffered via `Write()`) to be played:
+When all frames have been written, run `Flush()` to wait for all buffered PCM data (i.e. previously buffered via `Write()`) to be played:
```csharp
int flushedLength = speaker.Flush();
diff --git a/demo/dotnet/PvSpeakerDemo/PvSpeakerDemo.cs b/demo/dotnet/PvSpeakerDemo/PvSpeakerDemo.cs
index 0aa85c8..2697fd4 100644
--- a/demo/dotnet/PvSpeakerDemo/PvSpeakerDemo.cs
+++ b/demo/dotnet/PvSpeakerDemo/PvSpeakerDemo.cs
@@ -129,7 +129,7 @@ public static void ShowAudioDevices()
" --audio_device_index: Index of output audio device.\n" +
" --input_wav_path: Path to PCM WAV file to be played.\n" +
" --buffer_size_secs: Size of internal PCM buffer in seconds.\n" +
- " --output_wav_path: Path to the output WAV file where the PCM data passed to PvSpeaker will be written..\n";
+ " --output_wav_path: Path to the output WAV file where the PCM data passed to PvSpeaker will be written.\n";
static void Main(string[] args)
{