UP-Viagg-io/Viagg-io/Assets/Packages/AVProVideo/Runtime/Scripts/Internal/AudioOutputManager.cs

215 lines
5.5 KiB
C#
Raw Normal View History

//-----------------------------------------------------------------------------
// 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));
}
}
}