Xamarin.Android: на запись файла влияет другая обработка

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

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

Но если я пытаюсь использовать их одновременно, я сталкиваюсь с некоторыми проблемами: файл хорошо написан, но не "правильно". Файл обеспечивает звук, который кажется ускоренным, и где отсутствуют некоторые аудио буферы.

Запись начинается с кнопки на Activity:

((Button)FindViewById(Resource.Id.btnStart)).Click += async delegate
{
    isRecording = true;
    EnableButtons(true);
    audioService = new WavAudioService();
    audioService.samplesUpdated += AudioService_samplesUpdated;
    audioService.StartRecording();
};

в AudioService это запускает AudioRecord:

public async Task StartRecording()
{
    audioRecord = new AudioRecord(AudioSource.Mic, 44100, ChannelIn.Mono, Android.Media.Encoding.Pcm16bit, buffer);                
    if (audioRecord.State == State.Initialized)
    {
        audioRecord.StartRecording();
    }
    isRecording = true;    
    recordingThread = new System.Threading.Thread(new ThreadStart(
        WriteAudioDataToFile
        ));
    recordingThread.Priority = System.Threading.ThreadPriority.Normal;
    recordingThread.Start(); 
}

Файл написан пока AudioRecord записывает:

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);           
            int[] bytesAsInts = Array.ConvertAll(data, c => (int)c);
            // call to FFT
            var res = FFT(bytesAsInts);
            if ((int)RecordStatus.ErrorInvalidOperation != read)
            {
                try
                {
                    fos.Write(data);
                }
                catch (Java.IO.IOException e)
                {
                    // ...
                }
            }
        }

        try
        {
            fos.Close();
        }
        catch (Java.IO.IOException e)
        {
            // ...
        }
    }
}

byte[] превращается в int[] быть использованным FFT() расчет:

public async Task<int[]> FFT(int[] y)
{
    var input = new AForge.Math.Complex[y.Length];
    for (int i = 0; i < y.Length; i++)
    {
        input[i] = new AForge.Math.Complex(y[i], 0);
    }
    FourierTransform.FFT(input, FourierTransform.Direction.Forward);
    var result = new int[y.Length / 2];
    // getting magnitude
    for (int i = 0; i < y.Length / 2 - 1; i++)
    {
        var current = Math.Sqrt(input[i].Re * input[i].Re + input[i].Im * input[i].Im);
        current = Math.Log10(current) * 10;
        result[i] = (int)current;
    }
    samplesUpdated(this, new SamplesUpdatedEventArgs(result));
    return result;
}

Результат отправляется в метод делегата на Activity:

private async void AudioService_samplesUpdated(object sender, System.EventArgs e)
{
    var audioService = (WavAudioService)sender;
    if (token.IsCancellationRequested)
    {
        audioService.StopRecording();
        return;
    }
    var arguments = e as SamplesUpdatedEventArgs;   
    if (arguments != null)
    {
        var samples = arguments.UpdatedSamples;
        if (samples.Length < (samplesCount / 2))
        {
            return;
        }
        UpdateHeatmapDataSeries(samples);       
    }
}

И, наконец, UpdateHeatmapDataSeries() обновляет значения, отображаемые спектрограммой:

public async void UpdateHeatmapDataSeries(int[] data)
{
    var spectrogramSize = width * height;
    var fftSize = data.Length;
    var offset = spectrogramSize - fftSize;
    try
    {
        Array.Copy(Data, fftSize, Data, 0, offset);
        Array.Copy(data, 0, Data, offset, fftSize);
        heatmapSeries.UpdateZValues(Data);  
    }
    catch (System.Exception e)
    {
        // ...
    }
}

Если я удалю звонок UpdateHeatmapDataSeries() от AudioService_samplesUpdated() Я больше не сталкиваюсь с проблемой: файл обеспечивает "правильный" звук.

Я пытался добавить немного Threads управлять FFT() или же UpdateHeatmapDataSeries(), но это ничего не изменило:

private void WriteAudioDataToFile()
{
    // ...
    while (isRecording)
    {
        read = audioRecord.Read(data, 0, bufferSize);           
        int[] bytesAsInts = Array.ConvertAll(data, c => (int)c);
        samplesUpdatedThread = new Thread(() => FFT(bytesAsInts));
        samplesUpdatedThread.Start();
        if ((int)RecordStatus.ErrorInvalidOperation != read)
        {
            try
            {
                fos.Write(data);
            }
            catch (Java.IO.IOException e)
            {
                // ...
            }
        }
    }
    // ...
}


private async void AudioService_samplesUpdated(object sender, System.EventArgs e)
{
    // ...
    var samples = arguments.UpdatedSamples;
    if (samples.Length < (samplesCount / 2))
    {
        return;
    }
    System.Threading.Thread thread = new System.Threading.Thread(() => UpdateHeatmapDataSeries(samples));
    thread.Start(); 
}

Я что-то забыл? Как я мог это исправить?

0 ответов

Другие вопросы по тегам