#region License // // The Open Toolkit Library License // // Copyright (c) 2006 - 2009 the Open Toolkit library. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights to // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of // the Software, and to permit persons to whom the Software is furnished to do // so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // #endregion using System; using System.Collections.Generic; using System.Diagnostics; using System.Threading; using System.Runtime.InteropServices; using OpenTK; using OpenTK.Audio; using OpenTK.Audio.OpenAL; namespace Examples { /// /// A text-based diagnosis program for OpenAL. /// The constructors will call the OpenAL commands, the Print() methods just show the information. /// [Example("OpenAL diagnostics", ExampleCategory.OpenAL, "Test", 0, true)] class OpenALDiagnostics { public static void checkForErrors() { { IntPtr device = Alc.GetContextsDevice(Alc.GetCurrentContext()); AlcError error = Alc.GetError(device); if (error != AlcError.NoError) Trace.WriteLine("ALC ERROR: (" + error + ") " + Alc.GetString(device, (AlcGetString)error)); } { ALError error = AL.GetError(); if (error != ALError.NoError) Trace.WriteLine("AL ERROR: (" + error + ") " + AL.GetErrorString(error)); } } [STAThread] static void Main() { Trace.Listeners.RemoveAt(0); Trace.Listeners.Add(new ConsoleTraceListener()); Trace.WriteLine("This application is currently running as " + (IntPtr.Size == 4 ? "x86" : "x64")); DeviceDiagnostic DevDiag = new DeviceDiagnostic(); DevDiag.Print(); DevDiag = null; using (AudioContext A = new AudioContext()) { AlcDiagnostic AlcDiag = new AlcDiagnostic(Alc.GetContextsDevice(Alc.GetCurrentContext())); checkForErrors(); AlcDiag.Print(); AlcDiag = null; ALDiagnostic ALdiag = new ALDiagnostic(A); checkForErrors(); ALdiag.Print(); ALdiag = null; EfxDiagnostic EfxDiag = new EfxDiagnostic(); checkForErrors(); EfxDiag.Print(); EfxDiag = null; XRamDiagnostic XRamDiag = new XRamDiagnostic(); checkForErrors(); XRamDiag.Print(); XRamDiag = null; RecorderDiagnostic rec = new RecorderDiagnostic(); rec.Print(); rec = null; } // Trace.WriteLine("All done. Press Enter to exit."); // Console.ReadLine(); } } class DeviceDiagnostic { #region Fields public readonly IList AllPlaybackDevices; public readonly IList AllRecordingDevices; public readonly string DefaultPlaybackDevice; public readonly string DefaultRecordingDevice; #endregion Fields public DeviceDiagnostic() { Trace.WriteLine("--- Device related errors ---"); AllPlaybackDevices = AudioContext.AvailableDevices; AllRecordingDevices = AudioCapture.AvailableDevices; DefaultPlaybackDevice = AudioContext.DefaultDevice; DefaultRecordingDevice = AudioCapture.DefaultDevice; } public void Print() { Trace.WriteLine("--- Device related analysis ---"); Trace.Indent(); { Trace.WriteLine("Default playback device: " + DefaultPlaybackDevice); Trace.WriteLine("All known playback devices:"); Trace.Indent(); { foreach (string s in AllPlaybackDevices) Trace.WriteLine(s); } Trace.Unindent(); Trace.WriteLine("Default recording device: " + DefaultRecordingDevice); Trace.WriteLine("All known recording devices:"); Trace.Indent(); { foreach (string s in AllRecordingDevices) Trace.WriteLine(s); } Trace.Unindent(); } Trace.Unindent(); } } class AlcDiagnostic { #region Fields private string[] Alc_Extension_C_Names = new string[] { "ALC_ENUMERATE_ALL_EXT", "ALC_ENUMERATION_EXT", "ALC_EXT_ASA", "ALC_EXT_ASA_DISTORTION", "ALC_EXT_ASA_ROGER_BEEP", "ALC_EXT_BRS_GAME_LICENSE_REQUIRED", "ALC_EXT_capture", "ALC_EXT_DEDICATED", "ALC_EXT_EFX", }; public readonly int MajorVersion; public readonly int MinorVersion; public readonly int EfxMajorVersion; public readonly int EfxMinorVersion; public readonly int EfxMaxAuxiliarySends; public readonly string ExtensionString; public readonly Dictionary Extensions = new Dictionary(); #endregion Fields public AlcDiagnostic(IntPtr dev) { Trace.WriteLine("--- Alc related errors ---"); Alc.GetInteger(dev, AlcGetInteger.MajorVersion, 1, out MajorVersion); Alc.GetInteger(dev, AlcGetInteger.MinorVersion, 1, out MinorVersion); Alc.GetInteger(dev, AlcGetInteger.EfxMajorVersion, 1, out EfxMajorVersion); Alc.GetInteger(dev, AlcGetInteger.EfxMinorVersion, 1, out EfxMinorVersion); Alc.GetInteger(dev, AlcGetInteger.EfxMaxAuxiliarySends, 1, out EfxMaxAuxiliarySends); ExtensionString = Alc.GetString(dev, AlcGetString.Extensions); foreach (string s in Alc_Extension_C_Names) Extensions.Add(s, Alc.IsExtensionPresent(dev, s)); } public void Print() { Trace.WriteLine("--- Alc related analysis ---"); Trace.Indent(); { Trace.WriteLine("Alc Version: " + MajorVersion + "." + MinorVersion); Trace.WriteLine("Efx Version: " + EfxMajorVersion + "." + EfxMinorVersion); Trace.WriteLine("Efx max. Auxiliary sends: " + EfxMaxAuxiliarySends); Trace.WriteLine("Alc Extension string: " + ExtensionString); Trace.WriteLine("Confirmed Alc Extensions:"); Trace.Indent(); { foreach (KeyValuePair pair in Extensions) Trace.WriteLine(pair.Key + ": " + pair.Value); } Trace.Unindent(); } Trace.Unindent(); } } class ALDiagnostic { #region Fields private string[] AL_Extension_Names = new string[] { "AL_EXT_ALAW", "AL_EXT_BFORMAT", "AL_EXT_double", "AL_EXT_EXPONENT_DISTANCE", "AL_EXT_float32", "AL_EXT_FOLDBACK", "AL_EXT_IMA4", "AL_EXT_LINEAR_DISTANCE", "AL_EXT_MCFORMATS", "AL_EXT_mp3", "AL_EXT_MULAW", "AL_EXT_OFFSET", "AL_EXT_vorbis", "AL_LOKI_quadriphonic", "EAX-RAM", "EAX", "EAX1.0", "EAX2.0", "EAX3.0", "EAX3.0EMULATED", "EAX4.0", "EAX4.0EMULATED", "EAX5.0" }; public readonly Dictionary Extensions = new Dictionary(); public readonly string DeviceName; public readonly float SpeedOfSound; public readonly string ExtensionString; public readonly string Renderer; public readonly string Vendor; public readonly string Version; public readonly ALDistanceModel DistanceModel; const uint MaxSourcesLimit = 128; public readonly uint MaxSources; #endregion Fields public ALDiagnostic(AudioContext ac) { Trace.WriteLine("--- AL related errors ---"); DeviceName = ac.CurrentDevice; ExtensionString = AL.Get(ALGetString.Extensions); Renderer = AL.Get(ALGetString.Renderer); Vendor = AL.Get(ALGetString.Vendor); Version = AL.Get(ALGetString.Version); SpeedOfSound = AL.Get(ALGetFloat.SpeedOfSound); DistanceModel = AL.GetDistanceModel(); foreach (string s in AL_Extension_Names) Extensions.Add(s, AL.IsExtensionPresent(s)); AL.GetError(); // clear it, need this for the source counting to work properly uint[] dummy_sources = new uint[MaxSourcesLimit]; for (MaxSources = 0; MaxSources < MaxSourcesLimit; MaxSources++) { AL.GenSource(out dummy_sources[MaxSources]); if (AL.GetError() != ALError.NoError) break; } for (int i = 0; i < MaxSources; i++) AL.DeleteSource(ref dummy_sources[i]); } public void Print() { Trace.WriteLine("--- AL related analysis ---"); Trace.Indent(); { Trace.WriteLine("Used Device: "+DeviceName); Trace.WriteLine("AL Renderer: " + Renderer); Trace.WriteLine("AL Vendor: " + Vendor); Trace.WriteLine("AL Version: " + Version); Trace.WriteLine("AL Speed of sound: " + SpeedOfSound); Trace.WriteLine("AL Distance Model: " + DistanceModel.ToString()); Trace.WriteLine("AL Maximum simultanous Sources: " + MaxSources); Trace.WriteLine("AL Extension string: " + ExtensionString); Trace.WriteLine("Confirmed AL Extensions:"); Trace.Indent(); { foreach (KeyValuePair pair in Extensions) Trace.WriteLine(pair.Key + ": " + pair.Value); } Trace.Unindent(); } Trace.Unindent(); } } class EfxDiagnostic { #region Fields private EfxEffectType[] EffectNames = new EfxEffectType[] { EfxEffectType.Autowah, EfxEffectType.Chorus, EfxEffectType.Compressor, EfxEffectType.Distortion, EfxEffectType.EaxReverb, EfxEffectType.Echo, EfxEffectType.Equalizer, EfxEffectType.Flanger, EfxEffectType.FrequencyShifter, EfxEffectType.PitchShifter, EfxEffectType.Reverb, EfxEffectType.RingModulator, EfxEffectType.VocalMorpher, }; private EfxFilterType[] FilterNames = new EfxFilterType[] { EfxFilterType.Bandpass, EfxFilterType.Highpass, EfxFilterType.Lowpass, }; public readonly Dictionary Effects = new Dictionary(); public readonly Dictionary Filters = new Dictionary(); const uint MaxAuxiliaryEffectSlotsLimit = 4; public readonly uint MaxAuxiliaryEffectSlots; #endregion Fields public EfxDiagnostic() { Trace.WriteLine("--- Efx related errors ---"); EffectsExtension Efx = new EffectsExtension(); Trace.Assert(Efx.IsInitialized); #region Test for available Effects uint effect; Efx.GenEffect(out effect); AL.GetError(); foreach (EfxEffectType e in EffectNames) { Efx.BindEffect(effect, e); Effects.Add(e.ToString(), AL.GetError() == ALError.NoError); } Efx.DeleteEffect(ref effect); #endregion Test for available Effects #region Test for available Filters uint filter; Efx.GenFilter(out filter); AL.GetError(); foreach (EfxFilterType f in FilterNames) { Efx.Filter(filter, EfxFilteri.FilterType, (int)f); Filters.Add(f.ToString(), AL.GetError() == ALError.NoError); } Efx.DeleteFilter(ref filter); #endregion Test for available Filters AL.GetError(); uint[] dummy_slots = new uint[MaxAuxiliaryEffectSlotsLimit]; for (MaxAuxiliaryEffectSlots = 0; MaxAuxiliaryEffectSlots < MaxAuxiliaryEffectSlotsLimit; MaxAuxiliaryEffectSlots++) { Efx.GenAuxiliaryEffectSlot(out dummy_slots[MaxAuxiliaryEffectSlots]); if (AL.GetError() != ALError.NoError) break; } for (uint i = 0; i < MaxAuxiliaryEffectSlots; i++) Efx.DeleteAuxiliaryEffectSlot(ref dummy_slots[i]); } public void Print() { Trace.WriteLine("--- Efx related analysis ---"); Trace.Indent(); { Trace.WriteLine("Efx Effects supported:"); Trace.Indent(); { foreach (KeyValuePair pair in Effects) Trace.WriteLine(pair.Key + ": " + pair.Value); } Trace.Unindent(); Trace.WriteLine("Efx Filters supported:"); Trace.Indent(); { foreach (KeyValuePair pair in Filters) Trace.WriteLine(pair.Key + ": " + pair.Value); } Trace.Unindent(); Trace.WriteLine("Efx max. Auxiliary Effect Slots: " + MaxAuxiliaryEffectSlots); } Trace.Unindent(); } } class XRamDiagnostic { #region Fields private XRamExtension.XRamStorage[] storagemodes = new XRamExtension.XRamStorage[] { XRamExtension.XRamStorage.Hardware, XRamExtension.XRamStorage.Accessible, XRamExtension.XRamStorage.Automatic, }; public readonly bool XRamFound; public readonly int RamTotal; public readonly int RamFree; public readonly Dictionary BufferModes = new Dictionary(); #endregion Fields public XRamDiagnostic() { Trace.WriteLine("--- X-RAM related errors ---"); XRamExtension XRam = new XRamExtension(); if (XRam.IsInitialized) { XRamFound = true; RamTotal = XRam.GetRamSize; RamFree = XRam.GetRamFree; uint buffer; AL.GenBuffer(out buffer); foreach (XRamExtension.XRamStorage m in storagemodes) { bool result = XRam.SetBufferMode(1, ref buffer, m); BufferModes.Add(m.ToString(), m == XRam.GetBufferMode(ref buffer)); } AL.DeleteBuffer(ref buffer); } else XRamFound = false; } public void Print() { Trace.WriteLine("--- X-RAM related analysis ---"); if (XRamFound) { Trace.Indent(); // * Trace.WriteLine("X-RAM extension found."); } else { Trace.Indent(); { Trace.WriteLine("X-RAM extension is not available, skipping test."); } Trace.Unindent(); return; } Trace.WriteLine("Ram status (free/total) in bytes: " + RamFree + "/" + RamTotal); Trace.WriteLine("Available buffer modes:"); Trace.Indent(); { foreach (KeyValuePair pair in BufferModes) Trace.WriteLine(pair.Key + ": " + pair.Value); } Trace.Unindent(); Trace.Unindent(); // * } } class RecorderDiagnostic { #region Fields bool IsDeviceAvailable; bool BufferContentsAllZero; short MaxSample = short.MinValue; short MinSample = short.MaxValue; private AudioCapture r; Dictionary Errorlist = new Dictionary(); string DeviceName; #endregion Fields private void CheckRecorderError(string location) { AlcError err = r.CurrentError; if (err != AlcError.NoError) Errorlist.Add(location, err); } public RecorderDiagnostic() { Trace.WriteLine("--- AudioCapture related errors ---"); IsDeviceAvailable = false; try { r = new AudioCapture(AudioCapture.DefaultDevice, 16000, ALFormat.Mono16, 4096); } catch (AudioDeviceException ade) { Trace.WriteLine("AudioCapture Exception caught: " + ade.Message); return; } IsDeviceAvailable = true; DeviceName = r.CurrentDevice; CheckRecorderError("Alc.CaptureOpenDevice"); r.Start(); CheckRecorderError("Alc.CaptureStart"); Thread.Sleep(100); r.Stop(); CheckRecorderError("Alc.CaptureStop"); byte[] Buffer = new byte[8192]; Thread.Sleep(10); // Wait for a few samples to become available. int SamplesBefore = r.AvailableSamples; CheckRecorderError("Alc.GetInteger(...CaptureSamples...)"); r.ReadSamples(Buffer, (SamplesBefore > 4096 ? 4096 : SamplesBefore)); CheckRecorderError("Alc.CaptureSamples"); int SamplesCaptured = SamplesBefore - r.AvailableSamples; uint ZeroCounter = 0; for (int i = 0; i < SamplesCaptured * 2; i++) { if (Buffer[i] == 0) ZeroCounter++; } for (int i = 0; i < SamplesCaptured; i++) { short sample = BitConverter.ToInt16(Buffer, i * 2); if (sample > MaxSample) MaxSample = sample; if (sample < MinSample) MinSample = sample; } if (ZeroCounter < SamplesCaptured * 2 && SamplesCaptured > 0) BufferContentsAllZero = false; else BufferContentsAllZero = true; r.Dispose(); CheckRecorderError("Alc.CaptureCloseDevice"); // no playback test needed due to Parrot test app. /* uint buf; AL.GenBuffer(out buf); AL.BufferData(buf, ALFormat.Mono16, BufferPtr, SamplesCaptured * 2, 16000); uint src; AL.GenSource(out src); AL.BindBufferToSource(src, buf); AL.Listener(ALListenerf.Gain, 16.0f); AL.SourcePlay(src); while (AL.GetSourceState(src) == ALSourceState.Playing) { Thread.Sleep(0); } AL.SourceStop(src); AL.DeleteSource(ref src); AL.DeleteBuffer(ref buf); */ } public void Print() { Trace.WriteLine("--- AudioCapture related analysis ---"); if (!IsDeviceAvailable) { Trace.WriteLine("Capture Device could not be initlialized (no microphone plugged into the jack?). Skipping test."); return; } Trace.Indent(); { Trace.WriteLine("Using capture device: " + DeviceName); if (Errorlist.Count > 0) { Trace.WriteLine("Found Alc Errors:"); Trace.Indent(); { foreach (KeyValuePair pair in Errorlist) Trace.WriteLine(pair.Key + ": " + pair.Value); } Trace.Unindent(); } Trace.WriteLine("Buffer contents after capture was all 0's: " + BufferContentsAllZero); Trace.WriteLine("Sample min/max in recorded data: " + MinSample + " / " + MaxSample); } Trace.Unindent(); } } }