first commit
This commit is contained in:
180
Assets/AVProVideo/Runtime/Scripts/Components/AudioOutput.cs
Normal file
180
Assets/AVProVideo/Runtime/Scripts/Components/AudioOutput.cs
Normal file
@@ -0,0 +1,180 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright 2015-2026 RenderHeads Ltd. All rights reserved.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace RenderHeads.Media.AVProVideo
|
||||
{
|
||||
/// <summary>
|
||||
/// Audio is grabbed from the MediaPlayer and rendered via Unity AudioSource
|
||||
/// This allows audio to have 3D spatial control, effects applied and to be spatialised for VR
|
||||
/// Currently supported on Windows and UWP (Media Foundation API only), macOS, iOS, tvOS and Android (ExoPlayer API only)
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(AudioSource))]
|
||||
[AddComponentMenu("AVPro Video/Audio Output", 400)]
|
||||
[HelpURL("https://www.renderheads.com/products/avpro-video/")]
|
||||
public class AudioOutput : MonoBehaviour
|
||||
{
|
||||
public enum AudioOutputMode
|
||||
{
|
||||
OneToAllChannels,
|
||||
MultipleChannels
|
||||
}
|
||||
|
||||
[SerializeField] MediaPlayer _mediaPlayer = null;
|
||||
[SerializeField] AudioOutputMode _audioOutputMode = AudioOutputMode.MultipleChannels;
|
||||
[HideInInspector, SerializeField] int _channelMask = 0xffff;
|
||||
[SerializeField] bool _supportPositionalAudio = false;
|
||||
|
||||
private int _mediaPlayerInstanceID = 0;
|
||||
|
||||
public MediaPlayer Player
|
||||
{
|
||||
get { return _mediaPlayer; }
|
||||
set { ChangeMediaPlayer(value); }
|
||||
}
|
||||
|
||||
public AudioOutputMode OutputMode
|
||||
{
|
||||
get { return _audioOutputMode; }
|
||||
set { _audioOutputMode = value; }
|
||||
}
|
||||
|
||||
public int ChannelMask
|
||||
{
|
||||
get { return _channelMask; }
|
||||
set { _channelMask = value; }
|
||||
}
|
||||
|
||||
public bool SupportPositionalAudio
|
||||
{
|
||||
get { return _supportPositionalAudio; }
|
||||
set { _supportPositionalAudio = value; }
|
||||
}
|
||||
|
||||
private AudioSource _audioSource;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
_audioSource = this.GetComponent<AudioSource>();
|
||||
Debug.Assert(_audioSource != null);
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
AudioSettings.OnAudioConfigurationChanged += OnAudioConfigurationChanged;
|
||||
ChangeMediaPlayer(_mediaPlayer);
|
||||
}
|
||||
|
||||
void OnAudioConfigurationChanged(bool deviceChanged)
|
||||
{
|
||||
if (_mediaPlayer == null || _mediaPlayer.Control == null)
|
||||
return;
|
||||
_mediaPlayer.Control.AudioConfigurationChanged(deviceChanged);
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
ChangeMediaPlayer(null);
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (_mediaPlayer != null && _mediaPlayer.Control != null && _mediaPlayer.Control.IsPlaying())
|
||||
{
|
||||
ApplyAudioSettings(_mediaPlayer, _audioSource);
|
||||
}
|
||||
}
|
||||
|
||||
public AudioSource GetAudioSource()
|
||||
{
|
||||
return _audioSource;
|
||||
}
|
||||
public void SetAudioSource(AudioSource source)
|
||||
{
|
||||
_audioSource = source;
|
||||
if (_mediaPlayer)
|
||||
_mediaPlayer.AudioSource = source;
|
||||
}
|
||||
|
||||
public void ChangeMediaPlayer(MediaPlayer newPlayer)
|
||||
{
|
||||
// When changing the media player, handle event subscriptions
|
||||
if (_mediaPlayer != null)
|
||||
{
|
||||
_mediaPlayer.AudioSource = null;
|
||||
_mediaPlayer.Events.RemoveListener(OnMediaPlayerEvent);
|
||||
AudioOutputManager.Instance.RemovePlayerInstance(_mediaPlayerInstanceID);
|
||||
_mediaPlayer = null;
|
||||
_mediaPlayerInstanceID = 0;
|
||||
}
|
||||
|
||||
_mediaPlayer = newPlayer;
|
||||
if (_mediaPlayer != null)
|
||||
{
|
||||
_mediaPlayer.Events.AddListener(OnMediaPlayerEvent);
|
||||
_mediaPlayer.AudioSource = _audioSource;
|
||||
_mediaPlayerInstanceID = _mediaPlayer.GetInstanceID();
|
||||
AudioOutputManager.Instance.AddPlayerInstance(_mediaPlayerInstanceID);
|
||||
}
|
||||
|
||||
if (_supportPositionalAudio)
|
||||
{
|
||||
if (_audioSource.clip == null)
|
||||
{
|
||||
// Position audio is implemented from hints found on this thread:
|
||||
// https://forum.unity.com/threads/onaudiofilterread-sound-spatialisation.362782/
|
||||
int frameCount = 2048 * 10;
|
||||
int sampleCount = frameCount * Helper.GetUnityAudioSpeakerCount();
|
||||
AudioClip clip = AudioClip.Create("dummy", frameCount, Helper.GetUnityAudioSpeakerCount(), Helper.GetUnityAudioSampleRate(), false);
|
||||
float[] samples = new float[sampleCount];
|
||||
for (int i = 0; i < samples.Length; i++) { samples[i] = 1f; }
|
||||
clip.SetData(samples, 0);
|
||||
_audioSource.clip = clip;
|
||||
_audioSource.loop = true;
|
||||
}
|
||||
}
|
||||
else if (_audioSource.clip != null)
|
||||
{
|
||||
_audioSource.clip = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Callback function to handle events
|
||||
private void OnMediaPlayerEvent(MediaPlayer mp, MediaPlayerEvent.EventType et, ErrorCode errorCode)
|
||||
{
|
||||
switch (et)
|
||||
{
|
||||
case MediaPlayerEvent.EventType.Closing:
|
||||
_audioSource.Stop();
|
||||
break;
|
||||
case MediaPlayerEvent.EventType.Started:
|
||||
ApplyAudioSettings(_mediaPlayer, _audioSource);
|
||||
_audioSource.Play();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void ApplyAudioSettings(MediaPlayer player, AudioSource audioSource)
|
||||
{
|
||||
// Apply volume and mute from the MediaPlayer to the AudioSource
|
||||
if (audioSource != null && player != null && player.Control != null)
|
||||
{
|
||||
float volume = player.Control.GetVolume();
|
||||
bool isMuted = player.Control.IsMuted();
|
||||
float rate = player.Control.GetPlaybackRate();
|
||||
audioSource.volume = volume;
|
||||
audioSource.mute = isMuted;
|
||||
audioSource.pitch = rate;
|
||||
}
|
||||
}
|
||||
|
||||
#if (UNITY_EDITOR_WIN || UNITY_EDITOR_OSX) || (!UNITY_EDITOR && (UNITY_STANDALONE_WIN || UNITY_WSA_10_0 || UNITY_STANDALONE_OSX || UNITY_IOS || UNITY_TVOS || UNITY_VISIONOS || UNITY_ANDROID))
|
||||
void OnAudioFilterRead(float[] audioData, int channelCount)
|
||||
{
|
||||
AudioOutputManager.Instance.RequestAudio(this, _mediaPlayer, _mediaPlayerInstanceID, audioData, channelCount, _channelMask, _audioOutputMode, _supportPositionalAudio);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user