using NAudio.CoreAudioApi.Interfaces;
using System;
using System.Globalization;
using System.Runtime.InteropServices;
namespace NAudio.CoreAudioApi
{
///
/// Manages the AudioStreamVolume for the .
///
public class AudioStreamVolume : IDisposable
{
IAudioStreamVolume audioStreamVolumeInterface;
internal AudioStreamVolume(IAudioStreamVolume audioStreamVolumeInterface)
{
this.audioStreamVolumeInterface = audioStreamVolumeInterface;
}
///
/// Verify that the channel index is valid.
///
///
///
private void CheckChannelIndex(int channelIndex, string parameter)
{
int channelCount = ChannelCount;
if (channelIndex >= channelCount)
{
throw new ArgumentOutOfRangeException(parameter, "You must supply a valid channel index < current count of channels: " + channelCount.ToString());
}
}
///
/// Return the current stream volumes for all channels
///
/// An array of volume levels between 0.0 and 1.0 for each channel in the audio stream.
public float[] GetAllVolumes()
{
Marshal.ThrowExceptionForHR(audioStreamVolumeInterface.GetChannelCount(out var channels));
var levels = new float[channels];
Marshal.ThrowExceptionForHR(audioStreamVolumeInterface.GetAllVolumes(channels, levels));
return levels;
}
///
/// Returns the current number of channels in this audio stream.
///
public int ChannelCount
{
get
{
Marshal.ThrowExceptionForHR(audioStreamVolumeInterface.GetChannelCount(out var channels));
unchecked
{
return (int)channels;
}
}
}
///
/// Return the current volume for the requested channel.
///
/// The 0 based index into the channels.
/// The volume level for the channel between 0.0 and 1.0.
public float GetChannelVolume(int channelIndex)
{
CheckChannelIndex(channelIndex, "channelIndex");
uint index;
unchecked
{
index = (uint)channelIndex;
}
Marshal.ThrowExceptionForHR(audioStreamVolumeInterface.GetChannelVolume(index, out var level));
return level;
}
///
/// Set the volume level for each channel of the audio stream.
///
/// An array of volume levels (between 0.0 and 1.0) one for each channel.
///
/// A volume level MUST be supplied for reach channel in the audio stream.
///
///
/// Thrown when does not contain elements.
///
public void SetAllVolumes(float[] levels)
{
// Make friendly Net exceptions for common problems:
int channelCount = ChannelCount;
if (levels == null)
{
throw new ArgumentNullException(nameof(levels));
}
if (levels.Length != channelCount)
{
throw new ArgumentOutOfRangeException(
nameof(levels),
String.Format(CultureInfo.InvariantCulture, "SetAllVolumes MUST be supplied with a volume level for ALL channels. The AudioStream has {0} channels and you supplied {1} channels.",
channelCount, levels.Length));
}
for (int i = 0; i < levels.Length; i++)
{
float level = levels[i];
if (level < 0.0f) throw new ArgumentOutOfRangeException(nameof(levels), "All volumes must be between 0.0 and 1.0. Invalid volume at index: " + i.ToString());
if (level > 1.0f) throw new ArgumentOutOfRangeException(nameof(levels), "All volumes must be between 0.0 and 1.0. Invalid volume at index: " + i.ToString());
}
unchecked
{
Marshal.ThrowExceptionForHR(audioStreamVolumeInterface.SetAllVoumes((uint)channelCount, levels));
}
}
///
/// Sets the volume level for one channel in the audio stream.
///
/// The 0-based index into the channels to adjust the volume of.
/// The volume level between 0.0 and 1.0 for this channel of the audio stream.
public void SetChannelVolume(int index, float level)
{
CheckChannelIndex(index, "index");
if (level < 0.0f) throw new ArgumentOutOfRangeException(nameof(level), "Volume must be between 0.0 and 1.0");
if (level > 1.0f) throw new ArgumentOutOfRangeException(nameof(level), "Volume must be between 0.0 and 1.0");
unchecked
{
Marshal.ThrowExceptionForHR(audioStreamVolumeInterface.SetChannelVolume((uint)index, level));
}
}
#region IDisposable Members
///
/// Dispose
///
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
///
/// Release/cleanup objects during Dispose/finalization.
///
/// True if disposing and false if being finalized.
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (audioStreamVolumeInterface != null)
{
// although GC would do this for us, we want it done now
Marshal.ReleaseComObject(audioStreamVolumeInterface);
audioStreamVolumeInterface = null;
}
}
}
#endregion
}
}