How do I get the parent from a AudioMixerGroup Object

The title says it all.

I have a SoundSource that plays into an AudioMixerGroup. I can get the MixerGroups’ mixer with AudioMixerGroup.audioMixer but I would like to walk the complete tree of all MixerGroups up↑ to the Master.

something like this: GroupA1 → GroupA → Master

Getting groups with AudioMixer.FindMatchingGroups(output.name) doesn’t help because I have to know what they are called for that.

Blockquote

Hi @MrFuzzzy i know is a little bit late, but in case you have not found a solution for this (or if some else needs a solution for this same issue) I am posting my solution. So here is what I did to get the “hierarchy” of MixerSoundGroups:

private class GD //FYI, GD stands for GroupData
{
    public GD Parent;
    public AudioMixerGroup Group;
    public List<GD> Children;
    public int Depth;

    public GD(AudioMixerGroup group, GD parent, int depth)
    {
         Group = group;
         Children = new List<GD>();
         Parent = parent;
         Depth = depth;
     }
}

private GD GetGroupsData(AudioMixer mixer)
{
    AudioMixerGroup[] groups = mixer.FindMatchingGroups("Master");
    GD masterData = new GD(groups[0], null, 0);
    SetChildren(masterData, mixer);
    return masterData;
}

private void SetChildren(GD parent, AudioMixer mixer)
{
    if (parent== null)
        return;

    AudioMixerGroup[] children = mixer.FindMatchingGroups(parent.Group.name).Skip(1).ToArray();

    if (children.Length != 0)
    {
        int i = 0;
        while (i < children.Length)
        {
            GD child = new GD(children*, parent, parent.Depth + 1);*

parent.Children.Add(child);
SetChildren(child, mixer);
int subChildrenCount = mixer.FindMatchingGroups(child.Group.name).Skip(1).ToArray().Length
i += subChildrenCount > 0 ? subChildrenCount + 1 : 1;
}
}
}

//Somwhere in your code call ‘GetGroupsData’ like this:
GD masterData = GetGroupsData(youAudioMixerInstance);

I wrote another one that handles hierarchies with duplicated names and sub-branches.

using System;
using System.Collections.Generic;
using UnityEngine.Audio;

public static class AudioMixerGroupExtensions
{
    /// <summary>
    /// This method resolves the 'Hierarchy' of the AudioMixer's AudioMixerGroups.
    /// It resolves the correct hierarchy even if AudioMixerGroup names or even
    /// whole branches are duplicated. It can do this because AudioMixer.FindMatchingGroups returns
    /// it's results in a depth-first order.
    /// </summary>
    /// <param name="mixer">The <see cref="AudioMixer"/> to resolve the hierarchy for.</param>
    /// <returns>A AudioMixerGroupHierarchy</returns>
    public static IAudioMixerGroupHierarchy GetMixerGroupHierarchy(this AudioMixer mixer)
    {
        return AudioMixerGroupHierarchy.ResolveHierarchy(mixer);
    }
    
    private class AudioMixerGroupHierarchy : IAudioMixerGroupHierarchy
    {
        private readonly AudioMixerGroupHierarchy parent;
        private readonly AudioMixerGroup mixerGroup;
        private readonly List<AudioMixerGroupHierarchy> children;
        private readonly string path;
        private readonly int depth;

        private AudioMixerGroupHierarchy(AudioMixerGroup mixerGroup, AudioMixerGroupHierarchy parent, int depth)
        {
            this.mixerGroup = mixerGroup;
            this.parent = parent;
            this.depth = depth;
            path = $"{parent?.path}/{mixerGroup.name}";
            children = new List<AudioMixerGroupHierarchy>();
        }

        internal static IAudioMixerGroupHierarchy ResolveHierarchy(AudioMixer mixer)
        {
            // We are relying on the fact that FindMatchingGroups returns
            // the mixers in a depth-first order, meaning as we iterate
            // the list we will never see an element whose parent we have
            // not seen before
            var depthFirstOrderedMixerGroups = mixer.FindMatchingGroups("");
            var root = new AudioMixerGroupHierarchy(depthFirstOrderedMixerGroups[0], null, 0);
            
            var ancestorStack = new Stack<AudioMixerGroupHierarchy>();
            ancestorStack.Push(root);
        
            // Iterate over all mixerGroups, resolving the hierarchy by 
            // testing results of mixer.FindMatchingGroups(searchPath)
            // against the mixerGroup we are iterating on.
            // Skip the first element which is the root. 
            for (var i = 1; i < depthFirstOrderedMixerGroups.Length; i++)
            {
                var subMixer = depthFirstOrderedMixerGroups*;*

RETEST_ELEMENT:
var parent = ancestorStack.Peek();
var searchPath = $“{parent.path}/{subMixer.name}”;
var searchPathResults = mixer.FindMatchingGroups(searchPath);

var index = Array.IndexOf(searchPathResults, subMixer);
if (index < 0)
{
// If the entry was not found in this searchPath, then search in the previous parent
ancestorStack.Pop();
// Debug.LogWarning($“Entry not at {searchPath}, back-track to previous parent {ancestorStack.Peek().Path} and re-iterate”);
goto RETEST_ELEMENT; // ← WARNING GOTO
}

var isProbableNode = searchPathResults.Length != 1;
// A LEAF may be falsely detected as a NODE:
// If the path of this node is a partial path of another deeper path
// there is no way to verify it is a LEAF before the whole tree has been resolved
// The only side-effect is an extra iteration, where we test the leaf-node
// for children before back-tracking.

var node = new AudioMixerGroupHierarchy(subMixer, parent, ancestorStack.Count);
parent.children.Add(node);
if (isProbableNode)
{
ancestorStack.Push(node);
}
}

return root;
}

IAudioMixerGroupHierarchy IAudioMixerGroupHierarchy.Parent => parent;

AudioMixerGroup IAudioMixerGroupHierarchy.Group => mixerGroup;

IReadOnlyList IAudioMixerGroupHierarchy.Children => children;

int IAudioMixerGroupHierarchy.Depth => depth;

string IAudioMixerGroupHierarchy.Path => path;
}
}

public interface IAudioMixerGroupHierarchy
{
public IAudioMixerGroupHierarchy Parent { get; }

public AudioMixerGroup Group { get; }

public IReadOnlyList Children { get; }

public int Depth { get; }

public string Path { get; }
}