diff --git a/src/Drastic.AudioRecorder/AudioRecorderService.cs b/src/Drastic.AudioRecorder/AudioRecorderService.cs index 618dbd0..ec4fb66 100644 --- a/src/Drastic.AudioRecorder/AudioRecorderService.cs +++ b/src/Drastic.AudioRecorder/AudioRecorderService.cs @@ -22,6 +22,7 @@ public partial class AudioRecorderService private DateTime? silenceTime; private DateTime? startTime; private TaskCompletionSource recordTask; + FileStream fileStream; /// /// Initializes a new instance of the class. @@ -92,16 +93,29 @@ public AudioRecorderService() /// Defaults to .15. Value should be between 0 and 1. public float SilenceThreshold { get; set; } = .15f; + /// + /// Gets/sets a value indicating if headers will be written to the file/stream. + /// + /// Defaults to true + public bool WriteHeaders { get; set; } = true; + /// /// Starts recording audio. /// + /// null (default) Optional stream to write audio data to, if null, a file will be created. /// A that will complete when recording is finished. /// The task result will be the path to the recorded audio file, or null if no audio was recorded. - public async Task> StartRecording() + public async Task> StartRecording(Stream recordStream = null) { - if (this.FilePath == null) + if (recordStream == null) { - this.FilePath = await this.GetDefaultFilePath(); + if (this.FilePath == null) + { + this.FilePath = await this.GetDefaultFilePath(); + } + + fileStream = new FileStream(FilePath, FileMode.Create, FileAccess.Write, FileShare.Read); + recordStream = fileStream; } this.ResetAudioDetection(); @@ -109,7 +123,7 @@ public async Task> StartRecording() this.InitializeStream(this.PreferredSampleRate); - await this.recorder.StartRecorder(this.audioStream, this.FilePath); + await this.recorder.StartRecorder(this.audioStream, recordStream, WriteHeaders); this.AudioStreamDetails = new AudioStreamDetails { @@ -134,7 +148,8 @@ public async Task> StartRecording() /// A object that can be used to read the audio file from the beginning. public Stream GetAudioFileStream() { - return this.recorder.GetAudioFileStream(); + //return a new stream to the same audio file, in Read mode + return new FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); } /// @@ -159,11 +174,12 @@ public async Task StopRecording(bool continueProcessing = true) Debug.WriteLine("Error in StopRecording: {0}", ex); } + fileStream?.Dispose(); this.OnRecordingStopped(); var returnedFilePath = this.GetAudioFilePath(); - // complete the recording Task for anthing waiting on this + // complete the recording Task for anything waiting on this this.recordTask.TrySetResult(returnedFilePath); if (continueProcessing) diff --git a/src/Drastic.AudioRecorder/WaveRecorder.cs b/src/Drastic.AudioRecorder/WaveRecorder.cs index 09997fd..5f0ff8f 100644 --- a/src/Drastic.AudioRecorder/WaveRecorder.cs +++ b/src/Drastic.AudioRecorder/WaveRecorder.cs @@ -9,26 +9,33 @@ namespace Drastic.AudioRecorder; internal class WaveRecorder : IDisposable { - private string audioFilePath; - private FileStream fileStream; - private StreamWriter streamWriter; private BinaryWriter writer; private int byteCount; private IAudioStream audioStream; + bool writeHeadersToStream; /// /// Starts recording WAVE format audio from the audio stream. /// /// A that provides the audio data. + /// The stream the audio will be written to. /// The full path of the file to record audio to. + /// false (default) Write WAV headers to stream at the end of recording. /// A representing the asynchronous operation. - public async Task StartRecorder(IAudioStream stream, string filePath) + public async Task StartRecorder(IAudioStream stream, Stream recordStream, bool writeHeaders = false) { if (stream == null) { throw new ArgumentNullException(nameof(stream)); } + if (recordStream == null) + { + throw new ArgumentNullException(nameof(recordStream)); + } + + writeHeadersToStream = writeHeaders; + try { // if we're restarting, let's see if we have an existing stream configured that can be stopped @@ -37,12 +44,8 @@ public async Task StartRecorder(IAudioStream stream, string filePath) await this.audioStream.Stop(); } - this.audioFilePath = filePath; this.audioStream = stream; - - this.fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Read); - this.streamWriter = new StreamWriter(this.fileStream); - this.writer = new BinaryWriter(this.streamWriter.BaseStream, Encoding.UTF8); + this.writer = new BinaryWriter(recordStream, Encoding.UTF8); this.byteCount = 0; this.audioStream.OnBroadcast += this.OnStreamBroadcast; @@ -62,16 +65,6 @@ public async Task StartRecorder(IAudioStream stream, string filePath) } } - /// - /// Gets a new to the audio file in readonly mode. - /// - /// A object that can be used to read the audio file from the beginning. - public Stream GetAudioFileStream() - { - // return a new stream to the same audio file, in Read mode - return new FileStream(this.audioFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - } - /// /// Stops recording WAV audio from the underlying and finishes writing the WAV file. /// @@ -87,7 +80,7 @@ public void StopRecorder() if (this.writer != null) { - if (this.streamWriter.BaseStream.CanWrite) + if (writeHeadersToStream && this.writer.BaseStream.CanWrite && this.writer.BaseStream.CanSeek) { // now that audio is finished recording, write a WAV/RIFF header at the beginning of the file this.writer.Seek(0, SeekOrigin.Begin); @@ -96,8 +89,6 @@ public void StopRecorder() this.writer.Dispose(); // this should properly close/dispose the underlying stream as well this.writer = null; - this.fileStream = null; - this.streamWriter = null; } this.audioStream = null; @@ -127,7 +118,7 @@ private void OnStreamBroadcast(object sender, byte[] bytes) { try { - if (this.writer != null && this.streamWriter != null) + if (this.writer != null) { this.writer.Write(bytes); this.byteCount += bytes.Length;