【问题标题】:UWP AudioGraph : Garbage Collector causes clicks in the audio outputUWP AudioGraph:垃圾收集器导致音频输出中的点击
【发布时间】:2019-02-08 18:32:29
【问题描述】:

我有一个使用 AudioGraph API 的 C# UWP 应用程序。

我在MediaSourceAudioInputNode 上使用自定义效果。

我按照此页面上的示例进行操作: https://docs.microsoft.com/en-us/windows/uwp/audio-video-camera/custom-audio-effects

它可以工作,但是当自定义效果运行时,我可以在扬声器中每秒听到多次点击声。

这是我的ProcessFrame 方法的代码:

    public unsafe void ProcessFrame(ProcessAudioFrameContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        AudioFrame frame = context.InputFrame;

        using (AudioBuffer inputBuffer = frame.LockBuffer(AudioBufferAccessMode.Read))
        using (IMemoryBufferReference inputReference = inputBuffer.CreateReference())
        {
            ((IMemoryBufferByteAccess)inputReference).GetBuffer(out byte* inputDataInBytes, out uint inputCapacity);
            Span<float> samples = new Span<float>(inputDataInBytes, (int)inputCapacity / sizeof(float));

            for (int i = 0; i < samples.Length; i++)
            {
                float sample = samples[i];

                // sample processing...

                samples[i] = sample;
            }
        }
    }

我使用 Visual Studio 分析器来确定问题的原因。 很明显存在内存问题。垃圾收集每秒运行几次。在每次垃圾回收时,我都能听到咔哒声。

Visual Studio 分析器显示垃圾收集的对象类型为 ProcessAudioFrameContext

这些对象在进入ProcessFrame 方法之前由AudioGraph API 创建并作为参数传递给该方法。

我可以做些什么来避免这些频繁的垃圾收集吗?

【问题讨论】:

标签: c# audio uwp


【解决方案1】:

这个问题不是特定于自定义效果,而是AudioGraph的普遍问题(当前SDK是1809)。 垃圾回收会暂停 AudioGraph 线程过长的时间(超过 10 毫秒,这是音频缓冲区的默认大小)。结果是可以在音频输出中听到咔嗒声。 自定义效果的使用给垃圾收集器带来了很大的压力。

我找到了一个很好的解决方法。它使用GC.TryStartNoGCRegion 方法。

调用此方法后,点击完全消失。但是在调用GC.EndNoGCRegion 方法之前,应用程序的内存一直在增长。

// at the beginning of playback...
// 240 Mb is the amount of memory that can be allocated before a GC occurs
GC.TryStartNoGCRegion(240 * 1024 * 1024, true);

// ... at the end of playback
GC.EndNoGCRegion();

MSDN 文档: https://docs.microsoft.com/fr-fr/dotnet/api/system.gc.trystartnogcregion?view=netframework-4.7.2

还有一篇好文章: https://mattwarren.org/2016/08/16/Preventing-dotNET-Garbage-Collections-with-the-TryStartNoGCRegion-API/

【讨论】:

    【解决方案2】:

    垃圾收集器可能对您每帧初始化示例临时内存做出反应,然后在该帧之后释放,尝试在启动代码中分配用于保存示例的内存,然后每帧重用它。

    【讨论】:

    • 问题是我做不到(或者我不知道怎么做)。 AudioGraph API 为我创建了 ProcessAudioFrameContext。我很乐意重用 AudioFrame 对象。但是除了官方的,我找不到任何示例代码...
    • 我说的是 span samples= new 的 GC .. 这会创建内存,当你的框架完成 GC 时必须清理它。
    • 根据我对 Span 的理解,它是对非托管内存(字节* inputDataInBytes)的类型化视图。它在堆栈上分配。所以它对垃圾收集没有影响。我在使用 Span 之前遇到了问题...
    猜你喜欢
    • 2017-03-10
    • 1970-01-01
    • 1970-01-01
    • 2016-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-14
    • 1970-01-01
    相关资源
    最近更新 更多