Created
October 23, 2024 20:36
-
-
Save Exorion1er/b56b4e2d6e9b4bd43063afb69e1cbb0b to your computer and use it in GitHub Desktop.
NAudio and Concentus Record -> Encode -> Decode -> Playback trivial example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Concentus; | |
using Concentus.Enums; | |
using NAudio.Wave; | |
internal class Program { | |
private static bool stopFlag = false; | |
private static List<short> pcmAccumulationBuffer = new List<short>(); | |
private static IOpusEncoder encoder; | |
private static IOpusDecoder decoder; | |
private static BufferedWaveProvider waveProvider; | |
private static WaveInEvent waveIn; | |
private static WaveOutEvent waveOut; | |
private const int FrameSize = 960; // 20ms frame for Opus at 48kHz | |
private static void Main(string[] args) { | |
Console.WriteLine("Recording, encoding, decoding, and playing back. Press Enter to stop."); | |
Initialize(); | |
StartRecording(); | |
// Wait for user input to stop recording | |
Console.ReadLine(); | |
StopRecording(); | |
} | |
private static void Initialize() { | |
// Initialize encoder and decoder | |
encoder = OpusCodecFactory.CreateEncoder(48000, 1, OpusApplication.OPUS_APPLICATION_AUDIO); | |
decoder = OpusCodecFactory.CreateDecoder(48000, 1); | |
// Initialize audio devices | |
waveIn = new WaveInEvent { | |
DeviceNumber = 0, // Use default recording device | |
WaveFormat = new WaveFormat(48000, 1) // 48kHz, Mono | |
}; | |
waveProvider = new BufferedWaveProvider(waveIn.WaveFormat) { | |
BufferDuration = TimeSpan.FromSeconds(5), // Buffer duration | |
DiscardOnBufferOverflow = false | |
}; | |
waveOut = new WaveOutEvent(); | |
waveOut.Init(waveProvider); | |
} | |
private static void StartRecording() { | |
waveIn.DataAvailable += OnDataAvailable; | |
waveOut.Play(); | |
try { | |
waveIn.StartRecording(); | |
Console.WriteLine("Recording started..."); | |
} catch (Exception ex) { | |
Console.WriteLine($"Error starting recording: {ex.Message}"); | |
} | |
} | |
private static void StopRecording() { | |
stopFlag = true; | |
waveIn.StopRecording(); | |
Console.WriteLine("Recording stopped."); | |
// Wait until playback completes | |
while (waveOut.PlaybackState == PlaybackState.Playing || waveProvider.BufferedBytes > 0) { | |
Thread.Sleep(100); | |
} | |
Console.WriteLine("Playback finished."); | |
// Cleanup | |
waveIn.Dispose(); | |
waveOut.Dispose(); | |
} | |
private static void OnDataAvailable(object sender, WaveInEventArgs a) { | |
if (stopFlag) | |
return; | |
// Convert buffer to short PCM samples and accumulate | |
AddPcmDataToBuffer(a.Buffer, a.BytesRecorded); | |
ProcessAudioFrames(); | |
} | |
private static void AddPcmDataToBuffer(byte[] buffer, int bytesRecorded) { | |
var pcmBuffer = new short[bytesRecorded / 2]; | |
Buffer.BlockCopy(buffer, 0, pcmBuffer, 0, bytesRecorded); | |
pcmAccumulationBuffer.AddRange(pcmBuffer); | |
} | |
private static void ProcessAudioFrames() { | |
// Process accumulated PCM data in chunks of frameSize | |
while (pcmAccumulationBuffer.Count >= FrameSize) { | |
var frame = pcmAccumulationBuffer.GetRange(0, FrameSize).ToArray(); | |
pcmAccumulationBuffer.RemoveRange(0, FrameSize); | |
EncodeDecodeAndPlay(frame); | |
} | |
} | |
private static void EncodeDecodeAndPlay(short[] frame) { | |
byte[] encoded = new byte[4000]; | |
try { | |
int encodedLength = encoder.Encode(frame, FrameSize, encoded, encoded.Length); | |
DecodeAndPlay(encoded, encodedLength); | |
} catch (Exception ex) { | |
Console.WriteLine($"Error during encoding: {ex.Message}"); | |
} | |
} | |
private static void DecodeAndPlay(byte[] encoded, int encodedLength) { | |
short[] decodedBuffer = new short[FrameSize]; | |
try { | |
int decodedLength = decoder.Decode(encoded.AsSpan(0, encodedLength), decodedBuffer.AsSpan(), FrameSize); | |
// Add decoded audio to the wave provider | |
var byteBuffer = new byte[decodedLength * sizeof(short)]; | |
Buffer.BlockCopy(decodedBuffer, 0, byteBuffer, 0, byteBuffer.Length); | |
waveProvider.AddSamples(byteBuffer, 0, byteBuffer.Length); | |
} catch (Exception ex) { | |
Console.WriteLine($"Error during decoding: {ex.Message}"); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment