I develop a Xamarin.Android app where I need to record an audio file in a .wav and to display the related spectrogram in the same time.
I'm able to perform the 2 tasks separately but not to combine them.
I use an AudioRecord
to record the sound through the microphone:
public async Task StartRecording()
{
audioRecord = new AudioRecord(AudioSource.Mic, 44100, ChannelIn.Mono, Android.Media.Encoding.Pcm16bit, bufferSize);
if (audioRecord.State == State.Initialized)
audioRecord.StartRecording();
isRecording = true;
recordingThread = new System.Threading.Thread(new ThreadStart(
WriteAudioDataToFile
));
recordingThread.Start();
}
The file writing is done in WriteAudioDataToFile()
and works fine:
private void WriteAudioDataToFile()
{
byte[] data = new byte[bufferSize];
string filename = GetTempFilename();
FileOutputStream fos = null;
try
{
fos = new FileOutputStream(filename);
}
catch (Java.IO.FileNotFoundException e)
{
}
int read = 0;
if (null != fos)
{
while (isRecording)
{
read = audioRecord.Read(data, 0, bufferSize);
if ((int)RecordStatus.ErrorInvalidOperation != read)
{
try
{
fos.Write(data);
}
catch (Java.IO.IOException e)
{
}
}
}
try
{
fos.Close();
}
catch (Java.IO.IOException e)
{
}
}
}
I would like to do the other task after the file is written:
void OnNext()
{
short[] audioBuffer = new short[2048];
audioRecord.Read(audioBuffer, 0, audioBuffer.Length);
int[] result = new int[audioBuffer.Length];
for (int i = 0; i < audioBuffer.Length; i++)
{
result[i] = (int)audioBuffer[i];
}
samplesUpdated(this, new SamplesUpdatedEventArgs(result));
}
If I call OnNext()
from StartRecording()
, without writing the file this works fine and I get the expected values for the spectrogram:
public async Task StartRecording()
{
audioRecord = new AudioRecord(AudioSource.Mic, 44100, ChannelIn.Mono, Android.Media.Encoding.Pcm16bit, bufferSize);
if (audioRecord.State == State.Initialized)
audioRecord.StartRecording();
isRecording = true;
while (audioRecord.RecordingState == RecordState.Recording)
{
OnNext();
}
}
But as I need to combine both file writing and other task, I tried to move the OnNext()
method after the file writing:
private void WriteAudioDataToFile()
{
//...
try
{
fos.Write(data);
short[] dataShort = new short[bufferSize];
dataShort = Array.ConvertAll(data, d => (short)d);
int[] result = new int[dataShort.Length];
for (int i = 0; i < dataShort.Length; i++)
{
result[i] = (int)dataShort[i];
}
samplesUpdated(this, new SamplesUpdatedEventArgs(result));
}
catch (Java.IO.IOException e)
{
}
//...
}
But this doesn't work at all as expected:
- the recorded file seems to be "corrupted": the sound is "accelerated" when I hear it
- the values I get for the spectrogram are not correct: the problem seems to come from the
byte[]
toshort[]
conversion
I don't see how to manage audioRecord.Read(data, 0, bufferSize)
:
- I need to use
byte[]
for the file writing:fos.Write(data);
- I need to use
short[]
for the other task
=> What should be the better approach to achieve this?
Edit:
I've already tried these approaches but this didn't change anything:
- create a second Thread using the same AudioRecord to display the spectrogram
- create a second Thread using another AudioRecord to display the spectrogram
I've also looked if it is possible to wirte the file after the AudioRecord has stopped, but it doesn't seem possible too...