Hello support,
using Unity 6000.1.14f1
using FMOD Plugin Version 2.02.20
Sometimes when playing the game I am working on I get errors like this when I control my character:
[FMOD] ChannelControl::isPlaying(000000EB8A57EFA0:false) returned ERR_CHANNEL_STOLEN for CHANNELCONTROL (0x7FE0005).
UnityEngine.Debug:LogError (object)
FMODUnity.RuntimeUtils:DebugLogError (string) (at Assets/Plugins/FMOD/src/RuntimeUtils.cs:580)
FMODUnity.RuntimeManager:ERROR_CALLBACK (intptr,FMOD.SYSTEM_CALLBACK_TYPE,intptr,intptr,intptr) (at Assets/Plugins/FMOD/src/RuntimeManager.cs:142)[FMOD] ChannelControl::isPlaying(000000EB8A57F000:false) returned ERR_CHANNEL_STOLEN for CHANNELCONTROL (0x7FE0005).
UnityEngine.Debug:LogError (object)
FMODUnity.RuntimeUtils:DebugLogError (string) (at Assets/Plugins/FMOD/src/RuntimeUtils.cs:580)
FMODUnity.RuntimeManager:ERROR_CALLBACK (intptr,FMOD.SYSTEM_CALLBACK_TYPE,intptr,intptr,intptr) (at Assets/Plugins/FMOD/src/RuntimeManager.cs:142)[FMOD] ChannelControl::stop() returned ERR_CHANNEL_STOLEN for CHANNELCONTROL (0x7FE0005).
UnityEngine.Debug:LogError (object)
FMODUnity.RuntimeUtils:DebugLogError (string) (at Assets/Plugins/FMOD/src/RuntimeUtils.cs:580)
FMODUnity.RuntimeManager:ERROR_CALLBACK (intptr,FMOD.SYSTEM_CALLBACK_TYPE,intptr,intptr,intptr) (at Assets/Plugins/FMOD/src/RuntimeManager.cs:142)[FMOD] ChannelControl::setDelay(99328, 119457, true) returned ERR_CHANNEL_STOLEN for CHANNELCONTROL (0x7FC0011).
UnityEngine.Debug:LogError (object)
FMODUnity.RuntimeUtils:DebugLogError (string) (at Assets/Plugins/FMOD/src/RuntimeUtils.cs:580)
FMODUnity.RuntimeManager:ERROR_CALLBACK (intptr,FMOD.SYSTEM_CALLBACK_TYPE,intptr,intptr,intptr) (at Assets/Plugins/FMOD/src/RuntimeManager.cs:142)[FMOD] ChannelControl::setFadePointRamp(119457, 0) returned ERR_CHANNEL_STOLEN for CHANNELCONTROL (0x7FC0011).
UnityEngine.Debug:LogError (object)
FMODUnity.RuntimeUtils:DebugLogError (string) (at Assets/Plugins/FMOD/src/RuntimeUtils.cs:580)
FMODUnity.RuntimeManager:ERROR_CALLBACK (intptr,FMOD.SYSTEM_CALLBACK_TYPE,intptr,intptr,intptr) (at Assets/Plugins/FMOD/src/RuntimeManager.cs:142)[FMOD] Channel::getLoopCount(000000EB8A57EB40:0) returned ERR_CHANNEL_STOLEN for CHANNEL (0x7FC0011).
UnityEngine.Debug:LogError (object)
FMODUnity.RuntimeUtils:DebugLogError (string) (at Assets/Plugins/FMOD/src/RuntimeUtils.cs:580)
FMODUnity.RuntimeManager:ERROR_CALLBACK (intptr,FMOD.SYSTEM_CALLBACK_TYPE,intptr,intptr,intptr) (at Assets/Plugins/FMOD/src/RuntimeManager.cs:142)[FMOD] ChannelControl::isPlaying(000000EB8A57EFA0:false) returned ERR_CHANNEL_STOLEN for CHANNELCONTROL (0x7FC0011).
UnityEngine.Debug:LogError (object)
FMODUnity.RuntimeUtils:DebugLogError (string) (at Assets/Plugins/FMOD/src/RuntimeUtils.cs:580)
FMODUnity.RuntimeManager:ERROR_CALLBACK (intptr,FMOD.SYSTEM_CALLBACK_TYPE,intptr,intptr,intptr) (at Assets/Plugins/FMOD/src/RuntimeManager.cs:142)[FMOD] ChannelControl::isPlaying(000000EB8A57F000:false) returned ERR_CHANNEL_STOLEN for CHANNELCONTROL (0x7FC0011).
UnityEngine.Debug:LogError (object)
FMODUnity.RuntimeUtils:DebugLogError (string) (at Assets/Plugins/FMOD/src/RuntimeUtils.cs:580)
FMODUnity.RuntimeManager:ERROR_CALLBACK (intptr,FMOD.SYSTEM_CALLBACK_TYPE,intptr,intptr,intptr) (at Assets/Plugins/FMOD/src/RuntimeManager.cs:142)[FMOD] ChannelControl::stop() returned ERR_CHANNEL_STOLEN for CHANNELCONTROL (0x7FC0011).
UnityEngine.Debug:LogError (object)
FMODUnity.RuntimeUtils:DebugLogError (string) (at Assets/Plugins/FMOD/src/RuntimeUtils.cs:580)
FMODUnity.RuntimeManager:ERROR_CALLBACK (intptr,FMOD.SYSTEM_CALLBACK_TYPE,intptr,intptr,intptr) (at Assets/Plugins/FMOD/src/RuntimeManager.cs:142)
Now I play audio in centralised way. I have this script which basically handles registering audio events:
using System.Collections.Generic;
using FMOD.Studio;
using FMODUnity;
using Sirenix.OdinInspector;
using UnityEngine;
using EventReference = FMODUnity.EventReference;
using STOP_MODE = FMOD.Studio.STOP_MODE;
namespace BTSMOH.Game.Audio
{
public class AudioRegistry : MonoBehaviour
{
[ReadOnly]
[ShowInInspector]
private Dictionary<EventReference, AudioEventInfo> registry = new Dictionary<EventReference, AudioEventInfo>();
private void Awake()
{
registry = new Dictionary<EventReference, AudioEventInfo>();
}
public void Register(EventReference reference, EventReleaseType releaseType, bool canBePaused)
{
EventInstance instance = RuntimeManager.CreateInstance(reference.Guid);
AudioEventInfo info = new AudioEventInfo(instance, releaseType, canBePaused);
registry.TryAdd(reference, info);
}
public void Play(EventReference reference, bool stopBeforePlaying)
{
if (IsSoundEventValid(reference, out AudioEventInfo info))
{
if (IsEventInstanceValid(info.EventInstance))
{
if (IsInstancePlaying(info.EventInstance) && stopBeforePlaying)
{
info.EventInstance.stop(STOP_MODE.IMMEDIATE);
}
info.EventInstance.start();
if (info.EventReleaseType == EventReleaseType.AFTERPLAY)
{
info.EventInstance.release();
}
}
}
}
/// <summary>
/// PauseState determines if we pause a soundevent
/// True -> Pause
/// False -> Resume
/// </summary>
/// <param name="reference"></param>
/// <param name="pauseState"></param>
public void Pause(EventReference reference, bool pauseState)
{
if (IsSoundEventValid(reference, out AudioEventInfo info))
{
if (IsEventInstanceValid(info.EventInstance))
{
if (info.CanBePaused)
{
info.EventInstance.setPaused(pauseState);
}
}
}
}
public void PauseAll()
{
foreach (KeyValuePair<EventReference, AudioEventInfo> kvp in registry)
{
Pause(kvp.Key, true);
}
}
public void ResumeAll()
{
foreach (KeyValuePair<EventReference, AudioEventInfo> kvp in registry)
{
Pause(kvp.Key, false);
}
}
public void Stop(EventReference reference, STOP_MODE stopMode)
{
if (IsSoundEventValid(reference, out AudioEventInfo info))
{
if (IsEventInstanceValid(info.EventInstance))
{
info.EventInstance.stop(stopMode);
if (info.EventReleaseType == EventReleaseType.AFTERSTOP)
{
info.EventInstance.release();
}
}
}
}
private bool IsSoundEventValid(EventReference reference, out AudioEventInfo info)
{
info = new AudioEventInfo();
if (reference.IsNull)
{
return false;
}
if (registry.TryGetValue(reference, out AudioEventInfo value))
{
info = value;
return true;
}
return false;
}
private bool IsEventInstanceValid(EventInstance instance)
{
return instance.isValid();
}
public bool IsPlaying(EventReference reference)
{
if (IsSoundEventValid(reference, out AudioEventInfo info))
{
return IsInstancePlaying(info.EventInstance);
}
return false;
}
private bool IsInstancePlaying(EventInstance instance)
{
if (IsEventInstanceValid(instance))
{
PLAYBACK_STATE playbackState;
instance.getPlaybackState(out playbackState);
return playbackState == PLAYBACK_STATE.STARTING || playbackState == PLAYBACK_STATE.PLAYING;
}
return false;
}
public bool IsFinished(EventReference reference)
{
if (IsSoundEventValid(reference, out AudioEventInfo info))
{
return IsInstanceFinished(info.EventInstance);
}
return false;
}
private bool IsInstanceFinished(EventInstance instance)
{
if (IsEventInstanceValid(instance))
{
PLAYBACK_STATE playbackState;
instance.getPlaybackState(out playbackState);
return playbackState == PLAYBACK_STATE.STOPPED;
}
return false;
}
public void Unregister(EventReference reference)
{
if (registry.ContainsKey(reference))
{
if (IsSoundEventValid(reference, out AudioEventInfo info))
{
if (IsEventInstanceValid(info.EventInstance))
{
info.EventInstance.stop(STOP_MODE.IMMEDIATE);
if (info.EventReleaseType == EventReleaseType.AFTERUNREGISTER)
{
info.EventInstance.release();
}
registry.Remove(reference);
}
}
}
}
public void UnregisterAll()
{
List<EventReference> keys = new List<EventReference>(registry.Keys);
foreach (EventReference reference in keys)
{
Unregister(reference);
}
registry.Clear();
}
public void Dispose()
{
UnregisterAll();
}
private void OnDisable()
{
Dispose();
}
}
}
Like for example when I walk around with one of my characters the errors above are thrown.
This is the script that handles character audio:
using System.Collections.Generic;
using BTSMOH.Game.Audio;
using BTSMOH.Game.Entities.Animation;
using FMOD.Studio;
using FMODUnity;
using Sirenix.OdinInspector;
using UnityEngine;
using STOP_MODE = FMOD.Studio.STOP_MODE;
namespace BTSMOH.Game.Entities.Audio
{
public class CharacterAudible : MonoBehaviour,
IEntityAudible
{
[SerializeField]
private EntitySoundData entitySoundData;
[ReadOnly]
[ShowInInspector]
private EntityAnimationState currentAnimationState;
private EntityStateSoundInfo currentStateSoundInfo;
private EventReference currentSoundEvent;
private EventInstance currentEventInstance;
public EntitySoundData EntitySoundData
{
get => entitySoundData;
set => entitySoundData = value;
}
private void Awake()
{
currentAnimationState = ScriptableObject.CreateInstance<EntityAnimationState>();
foreach (KeyValuePair<EntityAnimationState, EntityStateSoundInfo> kvp in entitySoundData.SoundInfo)
{
if (!kvp.Value.EventReference.IsNull)
{
GameHandler.AudioRegistry.Register(kvp.Value.EventReference, EventReleaseType.AFTERUNREGISTER, true);
}
}
}
public void Play(EntityAnimationState state, bool forcePlay)
{
// Set entityAnimation state first before play
if (state == null)
{
return;
}
if (currentAnimationState != state)
{
GameHandler.AudioRegistry.Stop(currentStateSoundInfo.EventReference, STOP_MODE.IMMEDIATE);
currentAnimationState = state;
entitySoundData.SoundInfo.TryGetValue(currentAnimationState, out currentStateSoundInfo);
currentSoundEvent = currentStateSoundInfo.EventReference;
}
if (forcePlay)
{
GameHandler.AudioRegistry.Play(currentSoundEvent, false);
}
else
{
if (!GameHandler.AudioRegistry.IsPlaying(currentSoundEvent))
{
GameHandler.AudioRegistry.Play(currentSoundEvent, false);
}
}
}
public void Pause()
{
GameHandler.AudioRegistry.Pause(currentSoundEvent, true);
}
public void Resume()
{
GameHandler.AudioRegistry.Pause(currentSoundEvent, false);
}
public void Stop()
{
GameHandler.AudioRegistry.Stop(currentSoundEvent, STOP_MODE.IMMEDIATE);
}
private void OnDisable()
{
if (GameHandler.AudioRegistry != null)
{
foreach (KeyValuePair<EntityAnimationState, EntityStateSoundInfo> kvp in entitySoundData.SoundInfo)
{
GameHandler.AudioRegistry.Unregister(kvp.Value.EventReference);
}
}
}
}
}
I read that this error specifically “ERR_CHANNEL_STOLEN for CHANNELCONTROL” means a virtual voice has its channel stolen and if there is a voice cutoff I should increase the virtual channel count int the fmod settings. But the count is set to 1024 and I feel this should suffice, especially if like just two characters are just walking around, no?
Any idea or suggestion where I should look in order to further investigate this issue?