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) {