Forum Xamarin.Android

Xamarin.Android and RecordAudio: how to combine file writing and other task

PacodosoPacodoso FRUniversity ✭✭✭

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[] to short[] 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

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...

=> What should be the better approach to achieve this?

Answers

  • BillyLiuBillyLiu Member, Xamarin Team Xamurai
    edited July 2018

    Hi @Pierre-ChristopheDus ,

    the values I get for the spectrogram are not correct: the problem seems to come from the byte[] to short[] conversion

    You could try to use BitConverter to convert byte to short. Or you could use Convert.ToByte() to make short convert to byte.

    Does the recorded file still corrupted after you using another thread? Could you provide a demo project?

  • PacodosoPacodoso FRUniversity ✭✭✭

    Hi @BillyLiu

    I've already tried to convert byteto short, this didn't work. I think that the problem comes that there are parallel treatments:

    • the file writing
    • the data calculations that are done in SamplesUpdatedEventArgs()
  • PacodosoPacodoso FRUniversity ✭✭✭

    You can found the demo project link there.
    But you will have to create a SciChart trial license to launch the app....

Sign In or Register to comment.