Unity editor crashes after playing multiple clips repeatedly

Thanks to your steady support, I’ve made a great progress on my work.
However, there’s one critical blocker.

Due to the nature of my project, there’s a case I have to play multiple samples multiple times simultaneously.
I’ve set up my scene like in the screenshot below, and the name of game objects are identical to their attached components:

But if I rapidly and repeatedly press Z and X key to invoke the playback of the samples (more like fifty to hundred times), Unity crashes at some point and leaves this kind of stacktraces in the Editor log file:

========== OUTPUTTING STACK TRACE ==================

0x00007FFD6EC88A3C (fmodstudioL) FMOD::ChannelControl::stop
0x00007FFD6ED60920 (fmodstudioL) FMOD_System_Update
0x00007FFD6ED60179 (fmodstudioL) FMOD_System_Update
0x00007FFD6ED99B5D (fmodstudioL) FMOD::SystemI::createMemoryFile
0x00007FFD6ED9A2D9 (fmodstudioL) FMOD::SystemI::createMemoryFile
0x00007FFD6ED3A48A (fmodstudioL) FMOD::System::update
SymInit: Symbol-SearchPath: 'C:/Program Files/Unity/Hub/Editor/6000.0.45f1/Editor/Data/Mono;

They definitely look like FMOD DLLs’ native-level internal errors, which make me difficult to dig into any further.

  1. What should I do to run my program stably, without the crash?
  2. This question is optional, but is there a way to create certain channels and limit playbacks within the range? I tried adding a channel group to the master channel but I’m not sure if it’s the right way.

Code for:
<DirectSoundManager.cs>

using UnityEngine;

public class DirectSoundManager : MonoBehaviour
{
    public DirectSoundPlayer soundPlayer;

    public void PlayDownloadedSound()
    {
        const string filePath = @"C:\path_to_sample\sample1.wav";
        soundPlayer.PlayAudioSegment(filePath, 700, 900);
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Z))
        {
            const string filePath = @"C:\path_to_sample\sample2.wav";
            soundPlayer.PlayAudioSegment(filePath, 5000, 6000);
        }
        else if (Input.GetKeyDown(KeyCode.X))
        {
            const string filePath = @"C:\path_to_sample\sample3.wav";
            soundPlayer.PlayAudioSegment(filePath, 20000, 22000);
        }
            
    }
    
    private void OnDestroy()
    {
        FMODUnity.RuntimeManager.CoreSystem.release();
    }
}

And here’s the code for:

<DirectSoundPlayer.cs>

using UnityEngine;
using FMOD;
using FMODUnity;
using System;
using System.Collections.Generic;

public class DirectSoundPlayer : MonoBehaviour
{
    private FMOD.System coreSystem;
    private ChannelGroup masterGroup;
    private uint syncPointIndex;
    private Dictionary<string, Sound> _sounds = new();

    private void Start()
    {
        coreSystem = RuntimeManager.CoreSystem;
        coreSystem.getMasterChannelGroup(out masterGroup);
    }

    public void PlayAudioSegment(string filePath, uint startPos, uint endPos, float pitch = 1.0f)
    {
        Sound sound;
        if (_sounds.ContainsKey(filePath))
            sound = _sounds[filePath];
        else
        {
            coreSystem.createSound(filePath, MODE.DEFAULT, out sound);
            _sounds[filePath] = sound;
        }

        var hasPoint = false;
        sound.getNumSyncPoints(out var count);
        for (int i = 0; i < count; i++)
        {
            sound.getSyncPoint(i, out var point);
            sound.getSyncPointInfo(point, out _, 100, out var offset, TIMEUNIT.MS);
            if (offset == endPos)
            {
                hasPoint = true;
                break;
            }
        }

        if (!hasPoint)
        {
            sound.addSyncPoint(endPos, TIMEUNIT.MS, endPos.ToString(), out var syncPoint);
        }

        coreSystem.playSound(sound, masterGroup, true, out var channel);
        channel.setPosition(startPos, TIMEUNIT.MS);
        channel.setCallback(ChannelStopCallback);
        channel.setPaused(false);
    }

    RESULT ChannelStopCallback(IntPtr channelcontrol, CHANNELCONTROL_TYPE controltype,
        CHANNELCONTROL_CALLBACK_TYPE callbacktype, IntPtr commanddata1, IntPtr commanddata2)
    {
        if (callbacktype == CHANNELCONTROL_CALLBACK_TYPE.SYNCPOINT)
        {
            var channel = new Channel(channelcontrol);
            channel.setVolume(0f);
        }

        return RESULT.OK;
    }
}

Hi,

Thank you for sharing the code and detailed information.

From the code you provided, it looks like the ChannelStopCallback is not marked as static. To avoid crashes, you will need to make the callback static and decorate it with the [AOT.MonoPInvokeCallback(typeof(FMOD.CHANNELCONTROL_CALLBACK))] attribute.

For example:

    [AOT.MonoPInvokeCallback(typeof(CHANNELCONTROL_CALLBACK))]
    static RESULT ChannelStopCallback(IntPtr channelcontrol, CHANNELCONTROL_TYPE controltype,
        CHANNELCONTROL_CALLBACK_TYPE callbacktype, IntPtr commanddata1, IntPtr commanddata2)
    {
        if (callbacktype == CHANNELCONTROL_CALLBACK_TYPE.SYNCPOINT)
        {
            var channel = new Channel(channelcontrol);
            channel.setVolume(0f);
        }

        return RESULT.OK;
    }

Also, for calling System::release in OnDestroy().

    private void OnDestroy()
    {
        FMODUnity.RuntimeManager.CoreSystem.release();
    }

That line is likely contributing to the crash as well since FMOD handles system teardown automatically, so you might need to remove that call.

In addition to your current method, you could also consider using a combination of Channel::setPosition and ChannelControl::setDelay to control playback timing more precisely.

There’s also a helpful discussion on a similar topic here: Playing sound specific range - #9 by jeff_fmod

Hope this helps, let me know if you have questions!

1 Like