I am capturing audio in a .NET 7 MAUI application using the Android AudioRecord library. I am dependency-injecting my service, which contains the Android AudioRecord, into my ViewModel.
The Scenario: In my app, I want to click a button to start the audio recording and then click another button to stop the recording. After that, I want to be able to click the start button again to resume audio recording.
The Problem: When I click "start" the first time, I receive an audio stream from the microphone as desired. However, after stopping the audio and starting it again, I don't receive anything.
What I Have Tried:
I have tried registering the service as Transient, Scoped, and Singleton. I have attempted to initialize the AudioRecord both in the constructor and each time the "start" button is pressed. I've pinpointed the problem to the audioRecord.Stop() method. When I comment this out, everything works fine. I have tried to implement the AudioRecord directly inside the viewModel. Everything works just fine with the .stop() method then.
The code:
#if ANDROID
using Android.Media;
namespace Neuron.Nexus.Services;
public interface IAndroidAudioRecordService : IDisposable
{
void StartRecording();
void StopRecording();
Task<(byte[] buffer, int bytesRead)> GetAudioStream();
bool IsRecording { get; }
}
public class AndroidAudioRecordService : IAndroidAudioRecordService
{
private AudioRecord audioRecord;
private readonly int sampleRate = 44100;
private readonly int bufferSize = 1024;
private readonly ChannelIn channelConfig = ChannelIn.Mono;
private readonly Encoding audioFormat = Encoding.Pcm16bit;
private readonly byte[] audioBuffer;
public bool IsRecording { get; private set; }
public AndroidAudioRecordService()
{
audioBuffer = new byte[bufferSize];
}
public void StartRecording()
{
if (audioRecord != null)
{
audioRecord.Stop();
audioRecord.Release();
audioRecord.Dispose();
audioRecord = null;
}
audioRecord = new AudioRecord(AudioSource.Mic, sampleRate, channelConfig, audioFormat, bufferSize);
if (audioRecord != null && audioRecord.State == State.Initialized)
{
audioRecord.StartRecording();
IsRecording = true;
}
}
public void StopRecording()
{
if (audioRecord != null && audioRecord.RecordingState == RecordState.Recording)
{
audioRecord.Stop();
IsRecording = false;
}
}
public async Task<(byte[] buffer, int bytesRead)> GetAudioStream()
{
if (audioRecord == null)
{
throw new InvalidOperationException("AudioRecord is not initialized or not in recording state.");
}
int bytesRead = await audioRecord.ReadAsync(audioBuffer, 0, audioBuffer.Length);
return (audioBuffer, bytesRead);
}
public void Dispose()
{
if (audioRecord != null)
{
if (IsRecording)
{
audioRecord.Stop();
}
audioRecord.Release();
audioRecord.Dispose();
audioRecord = null;
IsRecording = false;
}
}
}
#endif
If I have missed to share anything please let me know.