Xamarin.Android и RecordAudio: как совместить запись файлов и другие задачи - PullRequest
0 голосов
/ 27 июня 2018

Я разрабатываю приложение Xamarin.Android , где мне нужно записать аудиофайл в формате WAV и одновременно отобразить соответствующую спектрограмму .

Я могу выполнять 2 задания отдельно , но не комбинировать их.

Я использую AudioRecord для записи звука через микрофон:

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();
}

Запись файла выполняется в WriteAudioDataToFile() и работает нормально:

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)
        {
        }
    }
}

Я хотел бы выполнить другую задачу после записи файла:

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));
}

Если я позвоню OnNext() из StartRecording(), без записи файла , это нормально работает , и я получу ожидаемые значения для спектрограммы:

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();
    }
}

Но так как мне нужно совместить как запись файла, так и другую задачу, я попытался переместить метод OnNext() после записи файла:

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)
    {
    }
    //...
}

Но это не работает , как и ожидалось:

  • записанный файл кажется " поврежден ": звук "ускоряется", когда я его слышу
  • значения, которые я получаю для спектрограммы не верны : проблема, похоже, связана с преобразованием byte[] в short[]

Я не понимаю, как управлять audioRecord.Read(data, 0, bufferSize):

  • Мне нужно использовать byte[] для записи файла: fos.Write(data);
  • Мне нужно использовать short[] для другой задачи

=> Каким должен быть лучший подход для достижения этой цели?

Edit:

Я уже пробовал эти подходы, но это ничего не изменило:

  • создать второй поток, используя тот же AudioRecord для отображения спектрограммы
  • создать второй поток, используя другую AudioRecord для отображения спектрограммы

Я также посмотрел, возможно ли записать файл после остановки AudioRecord, но это тоже не представляется возможным ...

...