| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 | //-----------------------------------------------------------------------------// Copyright 2015-2023 RenderHeads Ltd.  All rights reserved.//-----------------------------------------------------------------------------using System.Collections.Generic;using UnityEngine;using System;namespace RenderHeads.Media.AVProVideo{	/// <summary>	/// A singleton to handle multiple instances of the AudioOutput component	/// </summary>	public class AudioOutputManager	{		private static AudioOutputManager _instance = null;		public static AudioOutputManager Instance		{			get			{				if (_instance == null)				{					_instance = new AudioOutputManager();				}				return _instance;			}		}		protected class PlayerInstance		{			public HashSet<AudioOutput> outputs;			public float[] pcmData;			public bool isPcmDataReady;		}		private Dictionary<MediaPlayer, PlayerInstance> _instances;		private AudioOutputManager()		{			_instances = new Dictionary<MediaPlayer, PlayerInstance>();		}		public void RequestAudio(AudioOutput outputComponent, MediaPlayer mediaPlayer, float[] audioData, int audioChannelCount, int channelMask, AudioOutput.AudioOutputMode audioOutputMode, bool supportPositionalAudio)		{			if (mediaPlayer == null || mediaPlayer.Control == null)			{				if (supportPositionalAudio)				{					ZeroAudio(audioData, 0);				}				return;			}			int channels = mediaPlayer.Control.GetAudioChannelCount();			if (channels <= 0)			{				if (supportPositionalAudio)				{					ZeroAudio(audioData, 0);				}				return;			}			// total samples requested should be multiple of channels			Debug.Assert(audioData.Length % audioChannelCount == 0);			// Find or create an instance			PlayerInstance instance = null;			if (!_instances.TryGetValue(mediaPlayer, out instance))			{				instance = _instances[mediaPlayer] = new PlayerInstance()				{					outputs = new HashSet<AudioOutput>(),					pcmData = null				};			}			// requests data if it hasn't been requested yet for the current cycle			if (instance.outputs.Count == 0 || instance.outputs.Contains(outputComponent) || instance.pcmData == null)			{				instance.outputs.Clear();				int actualDataRequired = (audioData.Length * channels) / audioChannelCount;				if (instance.pcmData == null || actualDataRequired != instance.pcmData.Length)				{					instance.pcmData = new float[actualDataRequired];				}				instance.isPcmDataReady = GrabAudio(mediaPlayer, instance.pcmData, channels);				instance.outputs.Add(outputComponent);			}			if (instance.isPcmDataReady)			{				// calculate how many samples and what channels are needed and then copy over the data				int samples = Math.Min(audioData.Length / audioChannelCount, instance.pcmData.Length / channels);				int storedPos = 0;				int requestedPos = 0;				// multiple mode, copies over audio from desired channels into the same channels on the audiosource				if (audioOutputMode == AudioOutput.AudioOutputMode.MultipleChannels)				{					int lesserChannels = Math.Min(channels, audioChannelCount);					if (!supportPositionalAudio)					{						for (int i = 0; i < samples; ++i)						{							for (int j = 0; j < lesserChannels; ++j)							{								if ((1 << j & channelMask) > 0)								{									audioData[requestedPos + j] = instance.pcmData[storedPos + j];								}							}							storedPos += channels;							requestedPos += audioChannelCount;						}					}					else					{						for (int i = 0; i < samples; ++i)						{							for (int j = 0; j < lesserChannels; ++j)							{								if ((1 << j & channelMask) > 0)								{									audioData[requestedPos + j] *= instance.pcmData[storedPos + j];								}							}							storedPos += channels;							requestedPos += audioChannelCount;						}					}				}				//Mono mode, copies over single channel to all output channels				else if (audioOutputMode == AudioOutput.AudioOutputMode.OneToAllChannels)				{					int desiredChannel = 0;					for (int i = 0; i < 8; ++i)					{						if ((channelMask & (1 << i)) > 0)						{							desiredChannel = i;							break;						}					}					if (desiredChannel < channels)					{						if (!supportPositionalAudio)						{							for (int i = 0; i < samples; ++i)							{								for (int j = 0; j < audioChannelCount; ++j)								{									audioData[requestedPos + j] = instance.pcmData[storedPos + desiredChannel];								}								storedPos += channels;								requestedPos += audioChannelCount;							}						}						else						{							for (int i = 0; i < samples; ++i)							{								for (int j = 0; j < audioChannelCount; ++j)								{									audioData[requestedPos + j] *= instance.pcmData[storedPos + desiredChannel];								}								storedPos += channels;								requestedPos += audioChannelCount;							}						}					}				}				// If there is left over audio				if (supportPositionalAudio && requestedPos != audioData.Length)				{					// Zero the remaining audio data otherwise there are pops					ZeroAudio(audioData, requestedPos);				}			}			else			{				if (supportPositionalAudio)				{					// Zero the remaining audio data otherwise there are pops					ZeroAudio(audioData, 0);				}			}		}		private void ZeroAudio(float[] audioData, int startPosition)		{			for (int i = startPosition; i < audioData.Length; i++)			{				audioData[i] = 0f;			}		}		private bool GrabAudio(MediaPlayer player, float[] audioData, int channelCount)		{			return (0 != player.Control.GrabAudio(audioData, audioData.Length, channelCount));		}	}}
 |