public void AddLinkedSource(NetworkAudioSource audioSource, float dampingFactor, bool bidirectionalLink = false)
    {
        if (bidirectionalLink)
        {
            audioSource.AddLinkedSource(this, dampingFactor, false);
        }

        RpcAddLinkedSource(audioSource.myIdentifier, dampingFactor);
    }
    private static void OnReceiveNetworkAudioSourceMessage(NetworkMessage message, bool isServer)
    {
        NetworkAudioSourceMessage networkAudioSourceMessage = message.ReadMessage <NetworkAudioSourceMessage>();

        if (isServer && message.conn != NetworkManager.singleton.client.connection)
        {
            NetworkServer.SendToAll(NetworkAudioSourceMessageIdentifier, networkAudioSourceMessage);
        }
        else
        {
            if (!NetworkedAudioSources.ContainsKey(networkAudioSourceMessage.NetworkAudioSourceIdentifier))
            {
                Debug.Log($"{networkAudioSourceMessage.NetworkAudioSourceIdentifier} not found, maybe game has not finished initialising.");
                return;
            }

            NetworkAudioSource targetAudioSource = NetworkedAudioSources[networkAudioSourceMessage.NetworkAudioSourceIdentifier];

            foreach (Tuple <NetworkAudioSource, float> audioSourceVolumePair in targetAudioSource.LinkedAudioSources)
            {
                NetworkAudioSource audioSource = audioSourceVolumePair.Item1;
                float dampingFactor            = audioSourceVolumePair.Item2;

                switch (networkAudioSourceMessage.CallIdentifier)
                {
                case (byte)CallIdentifier.Pause:
                    audioSource.NetworkedAudioSource.Pause();
                    break;

                case (byte)CallIdentifier.Stop:
                    audioSource.NetworkedAudioSource.Stop();
                    break;

                case (byte)CallIdentifier.UnPause:
                    audioSource.NetworkedAudioSource.UnPause();
                    break;

                case (byte)CallIdentifier.Play:
                    ulong playDelay = BitConverter.ToUInt64(networkAudioSourceMessage.Payload, 0);
                    audioSource.SetVolume(audioSource.originalVolume * dampingFactor, true);
                    audioSource.NetworkedAudioSource.Play(playDelay);
                    break;

                case (byte)CallIdentifier.PlayDelayed:
                    float playDelayedDelay = BitConverter.ToSingle(networkAudioSourceMessage.Payload, 0);
                    audioSource.NetworkedAudioSource.PlayDelayed(playDelayedDelay);
                    break;

                case (byte)CallIdentifier.PlayScheduled:
                    double playScheduledTime = BitConverter.ToDouble(networkAudioSourceMessage.Payload, 0);
                    audioSource.NetworkedAudioSource.PlayScheduled(playScheduledTime);
                    break;

                case (byte)CallIdentifier.PlayOneShot:
                    int   clipUid     = BitConverter.ToInt32(networkAudioSourceMessage.Payload, 0);
                    float volumeScale = BitConverter.ToSingle(networkAudioSourceMessage.Payload, 4) * dampingFactor;
                    if (!IdToAudioClip.ContainsKey(clipUid))
                    {
                        Debug.Log("Clip not contained in NetworkAudioSource");
                    }
                    else
                    {
                        AudioClip clip = IdToAudioClip[clipUid];
                        audioSource.NetworkedAudioSource.PlayOneShot(clip, volumeScale);
                    }
                    break;

                case (byte)CallIdentifier.Volume:
                    uint volume = BitConverter.ToUInt32(networkAudioSourceMessage.Payload, 0);
                    audioSource.SetVolume(volume, false);
                    break;

                case (byte)CallIdentifier.FadeOut:
                    float fadeTime = BitConverter.ToSingle(networkAudioSourceMessage.Payload, 0);
                    audioSource.StartCoroutine(audioSource.FadeOutRoutine(fadeTime, audioSource.originalVolume * dampingFactor));
                    break;

                case (byte)CallIdentifier.FadeIn:
                    float targetVol  = BitConverter.ToSingle(networkAudioSourceMessage.Payload, 0);
                    float fadeInTime = BitConverter.ToSingle(networkAudioSourceMessage.Payload, 4);
                    audioSource.StartCoroutine(audioSource.FadeInRoutine(targetVol, fadeInTime, audioSource.originalVolume * dampingFactor));
                    break;

                case (byte)CallIdentifier.Clip:
                    int clipId = BitConverter.ToInt32(networkAudioSourceMessage.Payload, 0);
                    if (!IdToAudioClip.ContainsKey(clipId))
                    {
                        Debug.Log("Clip not contained in NetworkAudioSource");
                    }
                    else
                    {
                        AudioClip clip = IdToAudioClip[clipId];
                        audioSource.NetworkedAudioSource.clip = clip;
                    }
                    break;

                case (byte)CallIdentifier.DopplerLevel:
                    float dopplerLevel = BitConverter.ToSingle(networkAudioSourceMessage.Payload, 0);
                    audioSource.NetworkedAudioSource.dopplerLevel = dopplerLevel;
                    break;

                case (byte)CallIdentifier.IgnoreListenerPause:
                    bool ignoreListenerPause = BitConverter.ToBoolean(networkAudioSourceMessage.Payload, 0);
                    audioSource.NetworkedAudioSource.ignoreListenerPause = ignoreListenerPause;
                    break;

                case (byte)CallIdentifier.IgnoreListenerVolume:
                    bool ignoreListenerVolume = BitConverter.ToBoolean(networkAudioSourceMessage.Payload, 0);
                    audioSource.NetworkedAudioSource.ignoreListenerVolume = ignoreListenerVolume;
                    break;

                case (byte)CallIdentifier.Loop:
                    bool loop = BitConverter.ToBoolean(networkAudioSourceMessage.Payload, 0);
                    audioSource.NetworkedAudioSource.loop = loop;
                    break;

                case (byte)CallIdentifier.Pitch:
                    float pitch = BitConverter.ToSingle(networkAudioSourceMessage.Payload, 0);
                    audioSource.NetworkedAudioSource.pitch = pitch;
                    break;

                case (byte)CallIdentifier.Time:
                    float time = BitConverter.ToSingle(networkAudioSourceMessage.Payload, 0);
                    audioSource.NetworkedAudioSource.time = time;
                    break;

                case (byte)CallIdentifier.TimeSamples:
                    int timeSamples = BitConverter.ToInt32(networkAudioSourceMessage.Payload, 0);
                    audioSource.NetworkedAudioSource.timeSamples = timeSamples;
                    break;
                }
            }
        }
    }