Skip to content
This repository was archived by the owner on Feb 28, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 22 additions & 6 deletions src/Drastic.AudioRecorder/AudioRecorderService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public partial class AudioRecorderService
private DateTime? silenceTime;
private DateTime? startTime;
private TaskCompletionSource<string> recordTask;
FileStream fileStream;

/// <summary>
/// Initializes a new instance of the <see cref="AudioRecorderService"/> class.
Expand Down Expand Up @@ -92,24 +93,37 @@ public AudioRecorderService()
/// <remarks>Defaults to .15. Value should be between 0 and 1.</remarks>
public float SilenceThreshold { get; set; } = .15f;

/// <summary>
/// Gets/sets a value indicating if headers will be written to the file/stream.
/// </summary>
/// <remarks>Defaults to <c>true</c></remarks>
public bool WriteHeaders { get; set; } = true;

/// <summary>
/// Starts recording audio.
/// </summary>
/// <param name="recordStream"><c>null</c> (default) Optional stream to write audio data to, if null, a file will be created.</param>
/// <returns>A <see cref="Task"/> 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.</returns>
public async Task<Task<string>> StartRecording()
public async Task<Task<string>> 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();
this.OnRecordingStarting();

this.InitializeStream(this.PreferredSampleRate);

await this.recorder.StartRecorder(this.audioStream, this.FilePath);
await this.recorder.StartRecorder(this.audioStream, recordStream, WriteHeaders);

this.AudioStreamDetails = new AudioStreamDetails
{
Expand All @@ -134,7 +148,8 @@ public async Task<Task<string>> StartRecording()
/// <returns>A <see cref="Stream"/> object that can be used to read the audio file from the beginning.</returns>
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);
}

/// <summary>
Expand All @@ -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)
Expand Down
37 changes: 14 additions & 23 deletions src/Drastic.AudioRecorder/WaveRecorder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/// <summary>
/// Starts recording WAVE format audio from the audio stream.
/// </summary>
/// <param name="stream">A <see cref="IAudioStream"/> that provides the audio data.</param>
/// <param name="recordStream">The stream the audio will be written to.</param>
/// <param name="filePath">The full path of the file to record audio to.</param>
/// <param name="writeHeaders"><c>false</c> (default) Write WAV headers to stream at the end of recording.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
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
Expand All @@ -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;
Expand All @@ -62,16 +65,6 @@ public async Task StartRecorder(IAudioStream stream, string filePath)
}
}

/// <summary>
/// Gets a new <see cref="Stream"/> to the audio file in readonly mode.
/// </summary>
/// <returns>A <see cref="Stream"/> object that can be used to read the audio file from the beginning.</returns>
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);
}

/// <summary>
/// Stops recording WAV audio from the underlying <see cref="IAudioStream"/> and finishes writing the WAV file.
/// </summary>
Expand All @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down