Subversion Repositories AndroidProjects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1452 chris 1
#region License
2
//
3
// The Open Toolkit Library License
4
//
5
// Copyright (c) 2006 - 2009 the Open Toolkit library.
6
//
7
// Permission is hereby granted, free of charge, to any person obtaining a copy
8
// of this software and associated documentation files (the "Software"), to deal
9
// in the Software without restriction, including without limitation the rights to 
10
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11
// the Software, and to permit persons to whom the Software is furnished to do
12
// so, subject to the following conditions:
13
//
14
// The above copyright notice and this permission notice shall be included in all
15
// copies or substantial portions of the Software.
16
//
17
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24
// OTHER DEALINGS IN THE SOFTWARE.
25
//
26
#endregion
27
 
28
 
29
using System;
30
using System.Collections.Generic;
31
using System.Text;
32
using System.Diagnostics;
33
 
34
using OpenTK.Audio.OpenAL;
35
 
36
namespace OpenTK.Audio
37
{
38
    /// <summary>
39
    /// Provides methods to instantiate, use and destroy an audio context for playback.
40
    /// Static methods are provided to list available devices known by the driver.
41
    /// </summary>
42
    public sealed class AudioContext : IDisposable
43
    {
44
        #region --- Fields ---
45
 
46
        bool disposed;
47
        bool is_processing, is_synchronized;
48
        IntPtr device_handle;
49
        ContextHandle context_handle;
50
        bool context_exists;
51
 
52
        string device_name;
53
        static object audio_context_lock = new object();
54
        static Dictionary<ContextHandle, AudioContext> available_contexts = new Dictionary<ContextHandle, AudioContext>();
55
 
56
        #endregion
57
 
58
        #region --- Constructors ---
59
 
60
        #region static AudioContext()
61
 
62
        /// \internal
63
        /// <summary>
64
        /// Runs before the actual class constructor, to load available devices.
65
        /// </summary>
66
        static AudioContext()
67
        {
68
            if (AudioDeviceEnumerator.IsOpenALSupported) // forces enumeration
69
            { }
70
        }
71
 
72
        #endregion static AudioContext()
73
 
74
        #region public AudioContext()
75
 
76
        /// <summary>Constructs a new AudioContext, using the default audio device.</summary>
77
        public AudioContext()
78
            : this(null, 0, 0, false, true, MaxAuxiliarySends.UseDriverDefault) { }
79
 
80
        #endregion
81
 
82
        #region public AudioContext(string device)
83
 
84
        /// <summary>
85
        /// Constructs a new AudioContext instance.
86
        /// </summary>
87
        /// <param name="device">The device name that will host this instance.</param>
88
        public AudioContext(string device) : this(device, 0, 0, false, true, MaxAuxiliarySends.UseDriverDefault) { }
89
 
90
        #endregion
91
 
92
        #region public AudioContext(string device, int freq)
93
 
94
        /// <summary>Constructs a new AudioContext, using the specified audio device and device parameters.</summary>
95
        /// <param name="device">The name of the audio device to use.</param>
96
        /// <param name="freq">Frequency for mixing output buffer, in units of Hz. Pass 0 for driver default.</param>
97
        /// <remarks>
98
        /// Use AudioContext.AvailableDevices to obtain a list of all available audio devices.
99
        /// devices.
100
        /// </remarks>
101
        public AudioContext(string device, int freq) : this(device, freq, 0, false, true, MaxAuxiliarySends.UseDriverDefault) { }
102
 
103
        #endregion
104
 
105
        #region public AudioContext(string device, int freq, int refresh)
106
 
107
        /// <summary>Constructs a new AudioContext, using the specified audio device and device parameters.</summary>
108
        /// <param name="device">The name of the audio device to use.</param>
109
        /// <param name="freq">Frequency for mixing output buffer, in units of Hz. Pass 0 for driver default.</param>
110
        /// <param name="refresh">Refresh intervals, in units of Hz. Pass 0 for driver default.</param>
111
        /// <remarks>
112
        /// Use AudioContext.AvailableDevices to obtain a list of all available audio devices.
113
        /// devices.
114
        /// </remarks>
115
        public AudioContext(string device, int freq, int refresh)
116
            : this(device, freq, refresh, false, true, MaxAuxiliarySends.UseDriverDefault) { }
117
 
118
        #endregion
119
 
120
        #region public AudioContext(string device, int freq, int refresh, bool sync)
121
 
122
        /// <summary>Constructs a new AudioContext, using the specified audio device and device parameters.</summary>
123
        /// <param name="device">The name of the audio device to use.</param>
124
        /// <param name="freq">Frequency for mixing output buffer, in units of Hz. Pass 0 for driver default.</param>
125
        /// <param name="refresh">Refresh intervals, in units of Hz. Pass 0 for driver default.</param>
126
        /// <param name="sync">Flag, indicating a synchronous context.</param>
127
        /// <remarks>
128
        /// Use AudioContext.AvailableDevices to obtain a list of all available audio devices.
129
        /// devices.
130
        /// </remarks>
131
        public AudioContext(string device, int freq, int refresh, bool sync)
132
            : this(AudioDeviceEnumerator.AvailablePlaybackDevices[0], freq, refresh, sync, true) { }
133
 
134
        #endregion
135
 
136
        #region public AudioContext(string device, int freq, int refresh, bool sync, bool enableEfx)
137
 
138
        /// <summary>Creates the audio context using the specified device and device parameters.</summary>
139
        /// <param name="device">The device descriptor obtained through AudioContext.AvailableDevices.</param>
140
        /// <param name="freq">Frequency for mixing output buffer, in units of Hz. Pass 0 for driver default.</param>
141
        /// <param name="refresh">Refresh intervals, in units of Hz. Pass 0 for driver default.</param>
142
        /// <param name="sync">Flag, indicating a synchronous context.</param>
143
        /// <param name="enableEfx">Indicates whether the EFX extension should be initialized, if present.</param>
144
        /// <exception cref="ArgumentNullException">Occurs when the device string is invalid.</exception>
145
        /// <exception cref="ArgumentOutOfRangeException">Occurs when a specified parameter is invalid.</exception>
146
        /// <exception cref="AudioDeviceException">
147
        /// Occurs when the specified device is not available, or is in use by another program.
148
        /// </exception>
149
        /// <exception cref="AudioContextException">
150
        /// Occurs when an audio context could not be created with the specified parameters.
151
        /// </exception>
152
        /// <exception cref="NotSupportedException">
153
        /// Occurs when an AudioContext already exists.</exception>
154
        /// <remarks>
155
        /// <para>For maximum compatibility, you are strongly recommended to use the default constructor.</para>
156
        /// <para>Multiple AudioContexts are not supported at this point.</para>
157
        /// <para>
158
        /// The number of auxilliary EFX sends depends on the audio hardware and drivers. Most Realtek devices, as well
159
        /// as the Creative SB Live!, support 1 auxilliary send. Creative's Audigy and X-Fi series support 4 sends.
160
        /// Values higher than supported will be clamped by the driver.
161
        /// </para>
162
        /// </remarks>
163
        public AudioContext(string device, int freq, int refresh, bool sync, bool enableEfx)
164
        {
165
            CreateContext(device, freq, refresh, sync, enableEfx, MaxAuxiliarySends.UseDriverDefault);
166
        }
167
 
168
        #endregion
169
 
170
        #region public AudioContext(string device, int freq, int refresh, bool sync, bool enableEfx, MaxAuxiliarySends efxMaxAuxSends)
171
 
172
        /// <summary>Creates the audio context using the specified device and device parameters.</summary>
173
        /// <param name="device">The device descriptor obtained through AudioContext.AvailableDevices.</param>
174
        /// <param name="freq">Frequency for mixing output buffer, in units of Hz. Pass 0 for driver default.</param>
175
        /// <param name="refresh">Refresh intervals, in units of Hz. Pass 0 for driver default.</param>
176
        /// <param name="sync">Flag, indicating a synchronous context.</param>
177
        /// <param name="enableEfx">Indicates whether the EFX extension should be initialized, if present.</param>
178
        /// <param name="efxMaxAuxSends">Requires EFX enabled. The number of desired Auxiliary Sends per source.</param>
179
        /// <exception cref="ArgumentNullException">Occurs when the device string is invalid.</exception>
180
        /// <exception cref="ArgumentOutOfRangeException">Occurs when a specified parameter is invalid.</exception>
181
        /// <exception cref="AudioDeviceException">
182
        /// Occurs when the specified device is not available, or is in use by another program.
183
        /// </exception>
184
        /// <exception cref="AudioContextException">
185
        /// Occurs when an audio context could not be created with the specified parameters.
186
        /// </exception>
187
        /// <exception cref="NotSupportedException">
188
        /// Occurs when an AudioContext already exists.</exception>
189
        /// <remarks>
190
        /// <para>For maximum compatibility, you are strongly recommended to use the default constructor.</para>
191
        /// <para>Multiple AudioContexts are not supported at this point.</para>
192
        /// <para>
193
        /// The number of auxilliary EFX sends depends on the audio hardware and drivers. Most Realtek devices, as well
194
        /// as the Creative SB Live!, support 1 auxilliary send. Creative's Audigy and X-Fi series support 4 sends.
195
        /// Values higher than supported will be clamped by the driver.
196
        /// </para>
197
        /// </remarks>
198
        public AudioContext(string device, int freq, int refresh, bool sync, bool enableEfx, MaxAuxiliarySends efxMaxAuxSends)
199
        {
200
            CreateContext(device, freq, refresh, sync, enableEfx, efxMaxAuxSends);
201
        }
202
 
203
        #endregion
204
 
205
        #endregion --- Constructors ---
206
 
207
        #region --- Private Methods ---
208
 
209
        #region CreateContext
210
 
211
        /// <summary>May be passed at context construction time to indicate the number of desired auxiliary effect slot sends per source.</summary>
212
        public enum MaxAuxiliarySends:int
213
        {
214
            /// <summary>Will chose a reliably working parameter.</summary>
215
            UseDriverDefault = 0,
216
            /// <summary>One send per source.</summary>
217
            One = 1,
218
            /// <summary>Two sends per source.</summary>
219
            Two = 2,
220
            /// <summary>Three sends per source.</summary>
221
            Three = 3,
222
            /// <summary>Four sends per source.</summary>
223
            Four = 4,
224
        }
225
 
226
        /// \internal
227
        /// <summary>Creates the audio context using the specified device.</summary>
228
        /// <param name="device">The device descriptor obtained through AudioContext.AvailableDevices, or null for the default device.</param>
229
        /// <param name="freq">Frequency for mixing output buffer, in units of Hz. Pass 0 for driver default.</param>
230
        /// <param name="refresh">Refresh intervals, in units of Hz. Pass 0 for driver default.</param>
231
        /// <param name="sync">Flag, indicating a synchronous context.</param>
232
        /// <param name="enableEfx">Indicates whether the EFX extension should be initialized, if present.</param>
233
        /// <param name="efxAuxiliarySends">Requires EFX enabled. The number of desired Auxiliary Sends per source.</param>
234
        /// <exception cref="ArgumentOutOfRangeException">Occurs when a specified parameter is invalid.</exception>
235
        /// <exception cref="AudioDeviceException">
236
        /// Occurs when the specified device is not available, or is in use by another program.
237
        /// </exception>
238
        /// <exception cref="AudioContextException">
239
        /// Occurs when an audio context could not be created with the specified parameters.
240
        /// </exception>
241
        /// <exception cref="NotSupportedException">
242
        /// Occurs when an AudioContext already exists.</exception>
243
        /// <remarks>
244
        /// <para>For maximum compatibility, you are strongly recommended to use the default constructor.</para>
245
        /// <para>Multiple AudioContexts are not supported at this point.</para>
246
        /// <para>
247
        /// The number of auxilliary EFX sends depends on the audio hardware and drivers. Most Realtek devices, as well
248
        /// as the Creative SB Live!, support 1 auxilliary send. Creative's Audigy and X-Fi series support 4 sends.
249
        /// Values higher than supported will be clamped by the driver.
250
        /// </para>
251
        /// </remarks>
252
        void CreateContext(string device, int freq, int refresh, bool sync, bool enableEfx, MaxAuxiliarySends efxAuxiliarySends)
253
        {
254
            if (!AudioDeviceEnumerator.IsOpenALSupported)
255
                throw new DllNotFoundException("openal32.dll");
256
 
257
            if (AudioDeviceEnumerator.Version == AudioDeviceEnumerator.AlcVersion.Alc1_1 && AudioDeviceEnumerator.AvailablePlaybackDevices.Count == 0)    // Alc 1.0 does not support device enumeration.
258
                throw new NotSupportedException("No audio hardware is available.");
259
            if (context_exists) throw new NotSupportedException("Multiple AudioContexts are not supported.");
260
            if (freq < 0) throw new ArgumentOutOfRangeException("freq", freq, "Should be greater than zero.");
261
            if (refresh < 0) throw new ArgumentOutOfRangeException("refresh", refresh, "Should be greater than zero.");
262
 
263
 
264
            if (!String.IsNullOrEmpty(device))
265
            {
266
                device_name = device;
267
                device_handle = Alc.OpenDevice(device); // try to open device by name
268
            }
269
            if (device_handle == IntPtr.Zero)
270
            {
271
                device_name = "IntPtr.Zero (null string)";
272
                device_handle = Alc.OpenDevice(null); // try to open unnamed default device
273
            }
274
            if (device_handle == IntPtr.Zero)
275
            {
276
                device_name = AudioContext.DefaultDevice;
277
                device_handle = Alc.OpenDevice(AudioContext.DefaultDevice); // try to open named default device
278
            }
279
            if (device_handle == IntPtr.Zero)
280
            {
281
                device_name = "None";
282
                throw new AudioDeviceException(String.Format("Audio device '{0}' does not exist or is tied up by another application.",
283
                    String.IsNullOrEmpty(device) ? "default" : device));
284
            }
285
 
286
            CheckErrors();
287
 
288
            // Build the attribute list
289
            List<int> attributes = new List<int>();
290
 
291
            if (freq != 0)
292
            {
293
                attributes.Add((int)AlcContextAttributes.Frequency);
294
                attributes.Add(freq);
295
            }
296
 
297
            if (refresh != 0)
298
            {
299
                attributes.Add((int)AlcContextAttributes.Refresh);
300
                attributes.Add(refresh);
301
            }
302
 
303
            attributes.Add((int)AlcContextAttributes.Sync);
304
            attributes.Add(sync ? 1 : 0);
305
 
306
            if (enableEfx && Alc.IsExtensionPresent(device_handle, "ALC_EXT_EFX"))
307
            {
308
                int num_slots;
309
                switch (efxAuxiliarySends)
310
                {
311
                    case MaxAuxiliarySends.One:
312
                    case MaxAuxiliarySends.Two:
313
                    case MaxAuxiliarySends.Three:
314
                    case MaxAuxiliarySends.Four:
315
                        num_slots = (int)efxAuxiliarySends;
316
                        break;
317
                    default:
318
                    case MaxAuxiliarySends.UseDriverDefault:
319
                        Alc.GetInteger(device_handle, AlcGetInteger.EfxMaxAuxiliarySends, 1, out num_slots);
320
                        break;
321
                }
322
 
323
                attributes.Add((int)AlcContextAttributes.EfxMaxAuxiliarySends);
324
                attributes.Add(num_slots);
325
            }
326
            attributes.Add(0);
327
 
328
            context_handle = Alc.CreateContext(device_handle, attributes.ToArray());
329
 
330
            if (context_handle == ContextHandle.Zero)
331
            {
332
                Alc.CloseDevice(device_handle);
333
                throw new AudioContextException("The audio context could not be created with the specified parameters.");
334
            }
335
 
336
            CheckErrors();
337
 
338
            // HACK: OpenAL SI on Linux/ALSA crashes on MakeCurrent. This hack avoids calling MakeCurrent when
339
            // an old OpenAL version is detect - it may affect outdated OpenAL versions different than OpenAL SI,
340
            // but it looks like a good compromise for now.
341
            if (AudioDeviceEnumerator.AvailablePlaybackDevices.Count > 0)
342
                MakeCurrent();
343
 
344
            CheckErrors();
345
 
346
            device_name = Alc.GetString(device_handle, AlcGetString.DeviceSpecifier);
347
 
348
 
349
            lock (audio_context_lock)
350
            {
351
                available_contexts.Add(this.context_handle, this);
352
                context_exists = true;
353
            }
354
        }
355
 
356
        #endregion --- Private Methods ---
357
 
358
        #region static void MakeCurrent(AudioContext context)
359
 
360
        /// \internal
361
        /// <summary>Makes the specified AudioContext current in the calling thread.</summary>
362
        /// <param name="context">The OpenTK.Audio.AudioContext to make current, or null.</param>
363
        /// <exception cref="ObjectDisposedException">
364
        /// Occurs if this function is called after the AudioContext has been disposed.
365
        /// </exception>
366
        /// <exception cref="AudioContextException">
367
        /// Occurs when the AudioContext could not be made current.
368
        /// </exception>
369
        static void MakeCurrent(AudioContext context)
370
        {
371
            lock (audio_context_lock)
372
            {
373
                if (!Alc.MakeContextCurrent(context != null ? context.context_handle : ContextHandle.Zero))
374
                    throw new AudioContextException(String.Format("ALC {0} error detected at {1}.",
375
                        Alc.GetError(context != null ? (IntPtr)context.context_handle : IntPtr.Zero).ToString(),
376
                        context != null ? context.ToString() : "null"));
377
            }
378
        }
379
 
380
        #endregion
381
 
382
        #region internal bool IsCurrent
383
 
384
        /// <summary>
385
        /// Gets or sets a System.Boolean indicating whether the AudioContext
386
        /// is current.
387
        /// </summary>
388
        /// <remarks>
389
        /// Only one AudioContext can be current in the application at any time,
390
        /// <b>regardless of the number of threads</b>.
391
        /// </remarks>
392
        internal bool IsCurrent
393
        {
394
            get
395
            {
396
                lock (audio_context_lock)
397
                {
398
                    if (available_contexts.Count == 0)
399
                        return false;
400
                    else
401
                    {
402
                        return AudioContext.CurrentContext == this;
403
                    }
404
                }
405
            }
406
            set
407
            {
408
                if (value) AudioContext.MakeCurrent(this);
409
                else AudioContext.MakeCurrent(null);
410
            }
411
        }
412
 
413
        #endregion
414
 
415
        #region IntPtr Device
416
 
417
        IntPtr Device { get { return device_handle; } }
418
 
419
        #endregion
420
 
421
        #endregion
422
 
423
        #region --- Public Members ---
424
 
425
        #region CheckErrors
426
 
427
        /// <summary>
428
        /// Checks for ALC error conditions.
429
        /// </summary>
430
        /// <exception cref="OutOfMemoryException">Raised when an out of memory error is detected.</exception>
431
        /// <exception cref="AudioValueException">Raised when an invalid value is detected.</exception>
432
        /// <exception cref="AudioDeviceException">Raised when an invalid device is detected.</exception>
433
        /// <exception cref="AudioContextException">Raised when an invalid context is detected.</exception>
434
        public void CheckErrors()
435
        {
436
            if (disposed)
437
                throw new ObjectDisposedException(this.GetType().FullName);
438
 
439
            new AudioDeviceErrorChecker(device_handle).Dispose();
440
        }
441
 
442
        #endregion
443
 
444
        #region CurrentError
445
 
446
        /// <summary>
447
        /// Returns the ALC error code for this instance.
448
        /// </summary>
449
        public AlcError CurrentError
450
        {
451
            get
452
            {
453
                if (disposed)
454
                    throw new ObjectDisposedException(this.GetType().FullName);
455
 
456
                return Alc.GetError(device_handle);
457
            }
458
        }
459
 
460
        #endregion
461
 
462
        #region MakeCurrent
463
 
464
        /// <summary>Makes the AudioContext current in the calling thread.</summary>
465
        /// <exception cref="ObjectDisposedException">
466
        /// Occurs if this function is called after the AudioContext has been disposed.
467
        /// </exception>
468
        /// <exception cref="AudioContextException">
469
        /// Occurs when the AudioContext could not be made current.
470
        /// </exception>
471
        /// <remarks>
472
        /// Only one AudioContext can be current in the application at any time,
473
        /// <b>regardless of the number of threads</b>.
474
        /// </remarks>
475
        public void MakeCurrent()
476
        {
477
            if (disposed)
478
                throw new ObjectDisposedException(this.GetType().FullName);
479
 
480
            AudioContext.MakeCurrent(this);
481
        }
482
 
483
        #endregion
484
 
485
        #region IsProcessing
486
 
487
        /// <summary>
488
        /// Gets a System.Boolean indicating whether the AudioContext is
489
        /// currently processing audio events.
490
        /// </summary>
491
        /// <seealso cref="Process"/>
492
        /// <seealso cref="Suspend"/>
493
        public bool IsProcessing
494
        {
495
            get
496
            {
497
                if (disposed)
498
                    throw new ObjectDisposedException(this.GetType().FullName);
499
 
500
                return is_processing;
501
            }
502
            private set { is_processing = value; }
503
        }
504
 
505
        #endregion
506
 
507
        #region IsSynchronized
508
 
509
        /// <summary>
510
        /// Gets a System.Boolean indicating whether the AudioContext is
511
        /// synchronized.
512
        /// </summary>
513
        /// <seealso cref="Process"/>
514
        public bool IsSynchronized
515
        {
516
            get
517
            {
518
                if (disposed)
519
                    throw new ObjectDisposedException(this.GetType().FullName);
520
 
521
                return is_synchronized;
522
            }
523
            private set { is_synchronized = value; }
524
        }
525
 
526
        #endregion
527
 
528
        #region public void Process
529
 
530
        /// <summary>
531
        /// Processes queued audio events.
532
        /// </summary>
533
        /// <remarks>
534
        /// <para>
535
        /// If AudioContext.IsSynchronized is true, this function will resume
536
        /// the internal audio processing thread. If AudioContext.IsSynchronized is false,
537
        /// you will need to call this function multiple times per second to process
538
        /// audio events.
539
        /// </para>
540
        /// <para>
541
        /// In some implementations this function may have no effect.
542
        /// </para>
543
        /// </remarks>
544
        /// <exception cref="ObjectDisposedException">Occurs when this function is called after the AudioContext had been disposed.</exception>
545
        /// <seealso cref="Suspend"/>
546
        /// <seealso cref="IsProcessing"/>
547
        /// <seealso cref="IsSynchronized"/>
548
        public void Process()
549
        {
550
            if (disposed)
551
                throw new ObjectDisposedException(this.GetType().FullName);
552
 
553
            Alc.ProcessContext(this.context_handle);
554
            IsProcessing = true;
555
        }
556
 
557
        #endregion
558
 
559
        #region public void Suspend
560
 
561
        /// <summary>
562
        /// Suspends processing of audio events.
563
        /// </summary>
564
        /// <remarks>
565
        /// <para>
566
        /// To avoid audio artifacts when calling this function, set audio gain to zero before
567
        /// suspending an AudioContext.
568
        /// </para>
569
        /// <para>
570
        /// In some implementations, it can be faster to suspend processing before changing
571
        /// AudioContext state.
572
        /// </para>
573
        /// <para>
574
        /// In some implementations this function may have no effect.
575
        /// </para>
576
        /// </remarks>
577
        /// <exception cref="ObjectDisposedException">Occurs when this function is called after the AudioContext had been disposed.</exception>
578
        /// <seealso cref="Process"/>
579
        /// <seealso cref="IsProcessing"/>
580
        /// <seealso cref="IsSynchronized"/>
581
        public void Suspend()
582
        {
583
            if (disposed)
584
                throw new ObjectDisposedException(this.GetType().FullName);
585
 
586
            Alc.SuspendContext(this.context_handle);
587
            IsProcessing = false;
588
        }
589
 
590
        #endregion
591
 
592
        #region public bool SupportsExtension(string extension)
593
 
594
        /// <summary>
595
        /// Checks whether the specified OpenAL extension is supported.
596
        /// </summary>
597
        /// <param name="extension">The name of the extension to check (e.g. "ALC_EXT_EFX").</param>
598
        /// <returns>true if the extension is supported; false otherwise.</returns>
599
        public bool SupportsExtension(string extension)
600
        {
601
            if (disposed)
602
                throw new ObjectDisposedException(this.GetType().FullName);
603
 
604
            return Alc.IsExtensionPresent(this.Device, extension);
605
        }
606
 
607
        #endregion
608
 
609
        #region CurrentDevice
610
 
611
        /// <summary>
612
        /// Gets a System.String with the name of the device used in this context.
613
        /// </summary>
614
        public string CurrentDevice
615
        {
616
            get
617
            {
618
                if (disposed)
619
                    throw new ObjectDisposedException(this.GetType().FullName);
620
 
621
                return device_name;
622
            }
623
        }
624
 
625
        #endregion
626
 
627
        #endregion --- Public Members ---
628
 
629
        #region --- Static Members ---
630
 
631
        #region public static AudioContext CurrentContext
632
 
633
        /// <summary>
634
        /// Gets the OpenTK.Audio.AudioContext which is current in the application.
635
        /// </summary>
636
        /// <remarks>
637
        /// Only one AudioContext can be current in the application at any time,
638
        /// <b>regardless of the number of threads</b>.
639
        /// </remarks>
640
        public static AudioContext CurrentContext
641
        {
642
            get
643
            {
644
                lock (audio_context_lock)
645
                {
646
                    if (available_contexts.Count == 0)
647
                        return null;
648
                    else
649
                    {
650
                        AudioContext context;
651
                        AudioContext.available_contexts.TryGetValue(
652
                            (ContextHandle)Alc.GetCurrentContext(),
653
                            out context);
654
                        return context;
655
                    }
656
                }
657
            }
658
        }
659
 
660
        #endregion
661
 
662
        #region AvailableDevices
663
 
664
        /// <summary>
665
        /// Returns a list of strings containing all known playback devices.
666
        /// </summary>
667
        public static IList<string> AvailableDevices
668
        {
669
            get
670
            {
671
                return AudioDeviceEnumerator.AvailablePlaybackDevices;
672
            }
673
        }
674
        #endregion public static IList<string> AvailablePlaybackDevices
675
 
676
        #region DefaultDevice
677
 
678
        /// <summary>
679
        /// Returns the name of the device that will be used as playback default.
680
        /// </summary>
681
        public static string DefaultDevice
682
        {
683
            get
684
            {
685
                return AudioDeviceEnumerator.DefaultPlaybackDevice;
686
            }
687
        }
688
 
689
        #endregion
690
 
691
        #endregion
692
 
693
        #region --- IDisposable Members ---
694
 
695
        /// <summary>
696
        /// Disposes of the AudioContext, cleaning up all resources consumed by it.
697
        /// </summary>
698
        public void Dispose()
699
        {
700
            this.Dispose(true);
701
            GC.SuppressFinalize(this);
702
        }
703
 
704
        void Dispose(bool manual)
705
        {
706
            if (!disposed)
707
            {
708
                if (this.IsCurrent)
709
                    this.IsCurrent = false;
710
 
711
                if (context_handle != ContextHandle.Zero)
712
                {
713
                    available_contexts.Remove(context_handle);
714
                    Alc.DestroyContext(context_handle);
715
                }
716
 
717
                if (device_handle != IntPtr.Zero)
718
                    Alc.CloseDevice(device_handle);
719
 
720
                if (manual)
721
                {
722
                }
723
                disposed = true;
724
            }
725
        }
726
 
727
        /// <summary>
728
        /// Finalizes this instance.
729
        /// </summary>
730
        ~AudioContext()
731
        {
732
            this.Dispose(false);
733
        }
734
 
735
        #endregion
736
 
737
        #region --- Overrides ---
738
 
739
        /// <summary>
740
        /// Calculates the hash code for this instance.
741
        /// </summary>
742
        /// <returns></returns>
743
        public override int GetHashCode()
744
        {
745
            return base.GetHashCode();
746
        }
747
 
748
        /// <summary>
749
        /// Compares this instance with another.
750
        /// </summary>
751
        /// <param name="obj">The instance to compare to.</param>
752
        /// <returns>True, if obj refers to this instance; false otherwise.</returns>
753
        public override bool Equals(object obj)
754
        {
755
            return base.Equals(obj);
756
        }
757
 
758
        /// <summary>
759
        /// Returns a <see cref="System.String"/> that desrcibes this instance.
760
        /// </summary>
761
        /// <returns>A <see cref="System.String"/> that desrcibes this instance.</returns>
762
        public override string ToString()
763
        {
764
            return String.Format("{0} (handle: {1}, device: {2})",
765
                                 this.device_name, this.context_handle, this.device_handle);
766
        }
767
 
768
        #endregion
769
    }
770
}