# Unity thread error and freeze when playing Programmer Sound

**URL:** <https://qa.fmod.com/t/unity-thread-error-and-freeze-when-playing-programmer-sound/20980>\
**Category:** Unity\
**Created:** [December 12, 2023, 6:57am UTC](https://qa.fmod.com/t/unity-thread-error-and-freeze-when-playing-programmer-sound/20980 "2023-12-12T06:57:32Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![wooway](https://avatars.discourse-cdn.com/v4/letter/w/eb8c5e/32.png) [@wooway](https://qa.fmod.com/u/wooway)\
**Post date:** [December 12, 2023, 6:57am UTC](https://qa.fmod.com/t/unity-thread-error-and-freeze-when-playing-programmer-sound/20980/1 "2023-12-12T06:57:32Z")

</div>

I’ve modified the Programmer Sound example to try and play a WAV file generated by a TTS library. The sound file is generated fine and the path appears correct, but FMOD errors out and freezes while trying to play the sound.

I’m using Unity 2022.2.9f1 and FMOD 2.02

```auto
using System;
using System.Collections.Generic;
using UnityEngine;
using Crosstales.RTVoice;
using System.Runtime.InteropServices;
using FMODUnity;

public class TextToSpeech : MonoBehaviour
{
    private static string soundFolder = "TTS";
    private static string soundName = "tts_file";
    public EventReference eventName;

    FMOD.Studio.EVENT_CALLBACK ttsCallback;

    private static string path;

    private void Start()
    {
        ttsCallback = new FMOD.Studio.EVENT_CALLBACK(TTSEventCallback);
        path = Application.persistentDataPath + "/" + soundFolder + "/";
    }
    
    public void SayText(string text)
    {
        Speaker.Instance.Generate(text, path + soundName, Speaker.Instance.VoiceForName("Reed"));
        Debug.Log(path);
        
        var ttsInstance = FMODUnity.RuntimeManager.CreateInstance(eventName);
        
        // Pin the key string in memory and pass a pointer through the user data
        GCHandle stringHandle = GCHandle.Alloc(soundName + ".wav");
        ttsInstance.setUserData(GCHandle.ToIntPtr(stringHandle));

        ttsInstance.setCallback(ttsCallback);
        ttsInstance.start();
        ttsInstance.release();
    }
    
    [AOT.MonoPInvokeCallback(typeof(FMOD.Studio.EVENT_CALLBACK))]
    static FMOD.RESULT TTSEventCallback(FMOD.Studio.EVENT_CALLBACK_TYPE type, IntPtr instancePtr, IntPtr parameterPtr)
    {
        FMOD.Studio.EventInstance instance = new FMOD.Studio.EventInstance(instancePtr);

        // Retrieve the user data
        IntPtr stringPtr;
        instance.getUserData(out stringPtr);

        // Get the string object
        GCHandle stringHandle = GCHandle.FromIntPtr(stringPtr);
        String key = stringHandle.Target as String;

        switch (type)
        {
            case FMOD.Studio.EVENT_CALLBACK_TYPE.CREATE_PROGRAMMER_SOUND:
            {
                FMOD.MODE soundMode = FMOD.MODE.LOOP_NORMAL | FMOD.MODE.CREATECOMPRESSEDSAMPLE | FMOD.MODE.NONBLOCKING;
                var parameter = (FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES)Marshal.PtrToStructure(parameterPtr, typeof(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES));

                if (key.Contains("."))
                {
                    FMOD.Sound dialogueSound;
                    var soundResult = FMODUnity.RuntimeManager.CoreSystem.createSound(path + key, soundMode, out dialogueSound);
                    if (soundResult == FMOD.RESULT.OK)
                    {
                        parameter.sound = dialogueSound.handle;
                        parameter.subsoundIndex = -1;
                        Marshal.StructureToPtr(parameter, parameterPtr, false);
                    }
                }
                else
                {
                    FMOD.Studio.SOUND_INFO dialogueSoundInfo;
                    var keyResult = FMODUnity.RuntimeManager.StudioSystem.getSoundInfo(key, out dialogueSoundInfo);
                    if (keyResult != FMOD.RESULT.OK)
                    {
                        break;
                    }
                    FMOD.Sound dialogueSound;
                    var soundResult = FMODUnity.RuntimeManager.CoreSystem.createSound(dialogueSoundInfo.name_or_data, soundMode | dialogueSoundInfo.mode, ref dialogueSoundInfo.exinfo, out dialogueSound);
                    if (soundResult == FMOD.RESULT.OK)
                    {
                        parameter.sound = dialogueSound.handle;
                        parameter.subsoundIndex = dialogueSoundInfo.subsoundindex;
                        Marshal.StructureToPtr(parameter, parameterPtr, false);
                    }
                }
                break;
            }
            case FMOD.Studio.EVENT_CALLBACK_TYPE.DESTROY_PROGRAMMER_SOUND:
            {
                var parameter = (FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES)Marshal.PtrToStructure(parameterPtr, typeof(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES));
                var sound = new FMOD.Sound(parameter.sound);
                sound.release();

                break;
            }
            case FMOD.Studio.EVENT_CALLBACK_TYPE.DESTROYED:
            {
                // Now the event has been destroyed, unpin the string memory so it can be garbage collected
                stringHandle.Free();

                break;
            }
        }
        return FMOD.RESULT.OK;
    }
}

```

It appears to be crashing on this line.

```auto
var soundResult = FMODUnity.RuntimeManager.CoreSystem.createSound(path + key, soundMode, out dialogueSound);

```

The error:

```auto
UnityException: get_isPlaying can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread when loading a scene.
Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.
  at (wrapper managed-to-native) UnityEngine.Application.get_isPlaying()
  at FMODUnity.RuntimeManager.get_Instance () [0x00014] in /Assets/Plugins/FMOD/src/RuntimeManager.cs:122 
  at FMODUnity.RuntimeManager.get_CoreSystem () [0x00001] in /Assets/Plugins/FMOD/src/RuntimeManager.cs:199 
  at TextToSpeech.TTSEventCallback (FMOD.Studio.EVENT_CALLBACK_TYPE type, System.IntPtr instancePtr, System.IntPtr parameterPtr) [0x00085] in /Assets/Scripts/Accessibility/TextToSpeech.cs:64 
  at (wrapper native-to-managed) TextToSpeech.TTSEventCallback(FMOD.Studio.EVENT_CALLBACK_TYPE,intptr,intptr)
UnityEngine.DebugLogHandler:Internal_LogException(Exception, Object)
UnityEngine.DebugLogHandler:LogException(Exception, Object)
UnityEngine.Logger:LogException(Exception, Object)
UnityEngine.Debug:LogException(Exception)
UnityEngine.<>c:<RegisterUECatcher>b__0_0(Object, UnhandledExceptionEventArgs) (at /Users/bokken/build/output/unity/unity/Runtime/Export/Scripting/UnhandledExceptionHandler.bindings.cs:46)
UnityEngine.Application:get_isPlaying()
FMODUnity.RuntimeManager:get_Instance() (at Assets/Plugins/FMOD/src/RuntimeManager.cs:122)
FMODUnity.RuntimeManager:get_CoreSystem() (at Assets/Plugins/FMOD/src/RuntimeManager.cs:199)
TextToSpeech:TTSEventCallback(EVENT_CALLBACK_TYPE, IntPtr, IntPtr) (at Assets/Scripts/Accessibility/TextToSpeech.cs:64)

(Filename: Assets/Plugins/FMOD/src/RuntimeManager.cs Line: 122)

```

---

<div class="post-metadata">

**Author:** ![Connor\_FMOD](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/connor_fmod/32/3685_2.png) [@Connor\_FMOD](https://qa.fmod.com/u/Connor_FMOD)\
**Post date:** [December 14, 2023, 4:43am UTC](https://qa.fmod.com/t/unity-thread-error-and-freeze-when-playing-programmer-sound/20980/2 "2023-12-14T04:43:05Z")

</div>

Hi,

Unfortunately, I was not able to reproduce the issue loading a `.wav` file I had on disk. Could get the directory or full path of a `.wav` file you are trying to load? It may be an issue with the location of the file. Is it ever able to run the `createSound()` function or is it always breaking on that line?

Could you please enable `API Error logging` and `Memory Tracking` and let me know if you get any other errors?

---

<div class="post-metadata">

**Author:** ![wooway](https://avatars.discourse-cdn.com/v4/letter/w/eb8c5e/32.png) [@wooway](https://qa.fmod.com/u/wooway)\
**Post date:** [December 14, 2023, 5:30am UTC](https://qa.fmod.com/t/unity-thread-error-and-freeze-when-playing-programmer-sound/20980/3 "2023-12-14T05:30:55Z")

</div>

I’ve enabled those settings and there are no additional errors. The file exists and the path is correct. I get the same error when using the static file path from a previously generated file. The error happens when trying to retrieve the “CoreSystem”. It never makes it to the createSound call.

It seems to have trouble retrieving the FMOD instance from the static callback function.

> [@wooway](#):
>
> `FMODUnity.RuntimeManager.CoreSystem`

```auto
UnityEngine.Application:get_isPlaying()
FMODUnity.RuntimeManager:get_Instance() (at Assets/Plugins/FMOD/src/RuntimeManager.cs:122)
FMODUnity.RuntimeManager:get_CoreSystem() (at Assets/Plugins/FMOD/src/RuntimeManager.cs:199)

```

I’m running this on a Mac OS version 13.6.1.

---

<div class="post-metadata">

**Author:** ![Connor\_FMOD](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/connor_fmod/32/3685_2.png) [@Connor\_FMOD](https://qa.fmod.com/u/Connor_FMOD)\
**Post date:** [December 19, 2023, 12:59am UTC](https://qa.fmod.com/t/unity-thread-error-and-freeze-when-playing-programmer-sound/20980/4 "2023-12-19T00:59:50Z")

</div>

Hi,

I tried reproducing on Mac and I still had no luck.

Would it be possible to get a copy of your project or a stripped-down version displaying the issue [uploaded](https://fmod.com/profile#uploads) to your [profile](https://fmod.com/profile)? Please note you will have to register a project with us before you can upload files.

---

<div class="post-metadata">

**Author:** ![wooway](https://avatars.discourse-cdn.com/v4/letter/w/eb8c5e/32.png) [@wooway](https://qa.fmod.com/u/wooway)\
**Post date:** [December 19, 2023, 1:57am UTC](https://qa.fmod.com/t/unity-thread-error-and-freeze-when-playing-programmer-sound/20980/5 "2023-12-19T01:57:15Z")

</div>

I’ve been able to make it work by caching the system instance outside the static call back function. Is this ok to do or will it cause problems?

I’ve replaced this line in the static callback function.

```auto
var soundResult = FMODUnity.RuntimeManager.CoreSystem.createSound(path + key, soundMode, out dialogueSound);

```

With a static member variable at the top of the class.

```auto
private static FMOD.System system;

```

Then caching it in Start().

```auto
system = FMODUnity.RuntimeManager.CoreSystem;

```

And then calling the cached instance from the static call back function.

```auto
var soundResult = system.createSound(path + key, soundMode, out dialogueSound);

```

Are there any issues using FMOD like this?

Also, is there something that needs to be set in the project for it to work from the static callback function? FMOD seems to be working everywhere else for sound in the project. I’ve only had a problem using the callback with programmer sounds.

---

<div class="post-metadata">

**Author:** ![Connor\_FMOD](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/connor_fmod/32/3685_2.png) [@Connor\_FMOD](https://qa.fmod.com/u/Connor_FMOD)\
**Post date:** [December 26, 2023, 10:02pm UTC](https://qa.fmod.com/t/unity-thread-error-and-freeze-when-playing-programmer-sound/20980/6 "2023-12-26T22:02:37Z")

</div>

Hi,

Apologies for the delayed response.

Just to confirm, is this happening while the editor is running or outside of the game?

---

<div class="post-metadata">

**Author:** ![wooway](https://avatars.discourse-cdn.com/v4/letter/w/eb8c5e/32.png) [@wooway](https://qa.fmod.com/u/wooway)\
**Post date:** [January 3, 2024, 3:30am UTC](https://qa.fmod.com/t/unity-thread-error-and-freeze-when-playing-programmer-sound/20980/7 "2024-01-03T03:30:57Z")

</div>

It freezes in the editor and just crashes in a build when trying to get an instance of the core system.

---

<div class="post-metadata">

**Author:** ![Connor\_FMOD](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/connor_fmod/32/3685_2.png) [@Connor\_FMOD](https://qa.fmod.com/u/Connor_FMOD)\
**Post date:** [January 5, 2024, 1:26am UTC](https://qa.fmod.com/t/unity-thread-error-and-freeze-when-playing-programmer-sound/20980/8 "2024-01-05T01:26:21Z")

</div>

Hi,

Would it be possible to get a copy of your project or a stripped-down version displaying the issue [uploaded](https://fmod.com/profile#uploads) to your [profile](https://fmod.com/profile)? Please note you will have to register a project with us before you can upload files.

It is confusing why caching the core system is not causing the issue while accessing the system directly is. If I could test it on my side I may be able to resolve the issue.

---

<div class="post-metadata">

**Author:** ![wooway](https://avatars.discourse-cdn.com/v4/letter/w/eb8c5e/32.png) [@wooway](https://qa.fmod.com/u/wooway)\
**Post date:** [March 22, 2024, 4:57am UTC](https://qa.fmod.com/t/unity-thread-error-and-freeze-when-playing-programmer-sound/20980/9 "2024-03-22T04:57:13Z")

</div>

Unfortunately this is a large complex project and it’s not easy to simplify and upload.

Can you let me know if there are any issues with my current work around? Will it cause any problems with FMOD?

---

<div class="post-metadata">

**Author:** ![Connor\_FMOD](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/connor_fmod/32/3685_2.png) [@Connor\_FMOD](https://qa.fmod.com/u/Connor_FMOD)\
**Post date:** [March 24, 2024, 11:21pm UTC](https://qa.fmod.com/t/unity-thread-error-and-freeze-when-playing-programmer-sound/20980/10 "2024-03-24T23:21:01Z")

</div>

Hi,

I understand, would it be possible to get the full script that reproduces the behavior instead?

As this is not a normal way to interact with the FMOD Core system there may be unexpected behavior. I would suggest adding some extra error-checking when interacting with your cached system. Ensure the Core System has a valid handle: `System.hasHandle();` and regularly check the result of function FMOD functions as you are doing now.

---

<div class="post-metadata">

**Author:** ![wooway](https://avatars.discourse-cdn.com/v4/letter/w/eb8c5e/32.png) [@wooway](https://qa.fmod.com/u/wooway)\
**Post date:** [April 3, 2024, 4:48am UTC](https://qa.fmod.com/t/unity-thread-error-and-freeze-when-playing-programmer-sound/20980/11 "2024-04-03T04:48:34Z")

</div>

You can find an example script with error message in the first post of this thread. I’m loading the wav files from the Unity persistent data paths for Mac as documented here: [Unity - Scripting API: Application.persistentDataPath](https://docs.unity3d.com/ScriptReference/Application-persistentDataPath.html)

Trying to get a handle to the CoreSystem via “FMODUnity.RuntimeManager.CoreSystem” inside the callback function causes Unity to freeze and then crash.

You can see the detailed error message in the first post.

---

<div class="post-metadata">

**Author:** ![Connor\_FMOD](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/connor_fmod/32/3685_2.png) [@Connor\_FMOD](https://qa.fmod.com/u/Connor_FMOD)\
**Post date:** [April 9, 2024, 3:05am UTC](https://qa.fmod.com/t/unity-thread-error-and-freeze-when-playing-programmer-sound/20980/12 "2024-04-09T03:05:57Z")

</div>

Hi,

My apologies for missing that.

If you do experience any more issues, please let me know.

---

<div class="post-metadata">

**Author:** ![wooway](https://avatars.discourse-cdn.com/v4/letter/w/eb8c5e/32.png) [@wooway](https://qa.fmod.com/u/wooway)\
**Post date:** [April 11, 2024, 10:33am UTC](https://qa.fmod.com/t/unity-thread-error-and-freeze-when-playing-programmer-sound/20980/13 "2024-04-11T10:33:49Z")

</div>

My work around eventually fails after some time. So my solution isn’t working.

Have you tried the script example on an intel mac to see if it freezes and crashes for you?

Can you tell from the error message what might be the issue or how I might try and resolve it?

The game is in production at this point and I really need to find a solution.

---

<div class="post-metadata">

**Author:** ![Connor\_FMOD](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/connor_fmod/32/3685_2.png) [@Connor\_FMOD](https://qa.fmod.com/u/Connor_FMOD)\
**Post date:** [April 14, 2024, 11:32pm UTC](https://qa.fmod.com/t/unity-thread-error-and-freeze-when-playing-programmer-sound/20980/14 "2024-04-14T23:32:24Z")

</div>

Hi,

Unfortunately, I still cannot reproduce the error.

Could you try passing the `CoreSystem` to the `UserData()` rather than keeping it as a static variable:

```auto
using System;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.InteropServices;
using FMODUnity;
using FMOD;

class UserData
{
	public FMOD.System coreSystem;
	public string soundName;
}

public class TextToSpeech : MonoBehaviour
{
	private static string soundFolder = "TTS";
	private static string soundName = "tts_file";
	public EventReference eventName;

	FMOD.Studio.EVENT_CALLBACK ttsCallback;

	private static string path;

	UserData userData;

	private void Start()
	{
		ttsCallback = new FMOD.Studio.EVENT_CALLBACK(TTSEventCallback);
		path = Application.persistentDataPath + "/" + soundFolder + "/";
	}

	public void SayText(string text)
	{
		//Speaker.Instance.Generate(text, path + soundName, Speaker.Instance.VoiceForName("Reed"));
		//Debug.Log(path);

		var ttsInstance = FMODUnity.RuntimeManager.CreateInstance(eventName);

		userData.soundName = soundName + ".wav";
		userData.coreSystem = FMODUnity.RuntimeManager.CoreSystem;

		// Pin the key string in memory and pass a pointer through the user data
		GCHandle userDataHandle = GCHandle.Alloc(userData);
		ttsInstance.setUserData(GCHandle.ToIntPtr(userDataHandle));

		ttsInstance.setCallback(ttsCallback);
		ttsInstance.start();
		ttsInstance.release();
	}

	[AOT.MonoPInvokeCallback(typeof(FMOD.Studio.EVENT_CALLBACK))]
	static FMOD.RESULT TTSEventCallback(FMOD.Studio.EVENT_CALLBACK_TYPE type, IntPtr instancePtr, IntPtr parameterPtr)
	{
		FMOD.Studio.EventInstance instance = new FMOD.Studio.EventInstance(instancePtr);

		// Retrieve the user data
		IntPtr userDataPtr;
		instance.getUserData(out userDataPtr);

		// Get the string object
		GCHandle userDataHandle = GCHandle.FromIntPtr(userDataPtr);
		UserData key = userDataHandle.Target as UserData;

		switch (type)
		{
			case FMOD.Studio.EVENT_CALLBACK_TYPE.CREATE_PROGRAMMER_SOUND:
				{
					FMOD.MODE soundMode = FMOD.MODE.LOOP_NORMAL | FMOD.MODE.CREATECOMPRESSEDSAMPLE | FMOD.MODE.NONBLOCKING;
					var parameter = (FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES)Marshal.PtrToStructure(parameterPtr, typeof(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES));

					if (key.soundName.Contains("."))
					{
						FMOD.Sound dialogueSound;
						var soundResult = key.coreSystem.createSound(path + key, soundMode, out dialogueSound);
						if (soundResult == FMOD.RESULT.OK)
						{
							parameter.sound = dialogueSound.handle;
							parameter.subsoundIndex = -1;
							Marshal.StructureToPtr(parameter, parameterPtr, false);
						}
					}
					else
					{
						FMOD.Studio.SOUND_INFO dialogueSoundInfo;
						var keyResult = FMODUnity.RuntimeManager.StudioSystem.getSoundInfo(key.soundName, out dialogueSoundInfo);
						if (keyResult != FMOD.RESULT.OK)
						{
							break;
						}
						FMOD.Sound dialogueSound;
						var soundResult = FMODUnity.RuntimeManager.CoreSystem.createSound(dialogueSoundInfo.name_or_data, soundMode | dialogueSoundInfo.mode, ref dialogueSoundInfo.exinfo, out dialogueSound);
						if (soundResult == FMOD.RESULT.OK)
						{
							parameter.sound = dialogueSound.handle;
							parameter.subsoundIndex = dialogueSoundInfo.subsoundindex;
							Marshal.StructureToPtr(parameter, parameterPtr, false);
						}
					}
					break;
				}
			case FMOD.Studio.EVENT_CALLBACK_TYPE.DESTROY_PROGRAMMER_SOUND:
				{
					var parameter = (FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES)Marshal.PtrToStructure(parameterPtr, typeof(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES));
					var sound = new FMOD.Sound(parameter.sound);
					sound.release();

					break;
				}
			case FMOD.Studio.EVENT_CALLBACK_TYPE.DESTROYED:
				{
					// Now the event has been destroyed, unpin the string memory so it can be garbage collected
					userDataHandle.Free();

					break;
				}
		}
		return FMOD.RESULT.OK;
	}
}

```

I made a few changes to use the `UserData` class.

Hope this helps.
