Beispiel #1
0
        /// <summary>
        /// Initializes the direct sound.
        /// </summary>
        private void InitializeDirectSound()
        {
            // We will have 2 buffers: one for immediate audio out rendering, and another where we will
            // feed the samples. We will copy audio data from the back buffer into the immediate render
            // buffer. We first open the DirectSound driver, create the buffers and start the playback!
            // Open DirectSound
            DirectSoundDriver = null;
            var createDriverResult = NativeMethods.DirectSoundCreate(ref DeviceId, out DirectSoundDriver, IntPtr.Zero);

            if (DirectSoundDriver == null || createDriverResult != 0)
            {
                return;
            }

            // Set Cooperative Level to PRIORITY (priority level can call the SetFormat and Compact methods)
            DirectSoundDriver.SetCooperativeLevel(NativeMethods.GetDesktopWindow(),
                                                  DirectSound.DirectSoundCooperativeLevel.Normal);

            // Fill BufferDescription for immediate, rendering buffer
            var renderBuffer = new DirectSound.BufferDescription
            {
                Size         = Marshal.SizeOf <DirectSound.BufferDescription>(),
                BufferBytes  = 0,
                Flags        = DirectSound.DirectSoundBufferCaps.PrimaryBuffer,
                Reserved     = 0,
                FormatHandle = IntPtr.Zero,
                AlgorithmId  = Guid.Empty
            };

            // Create the Render Buffer (Immediate audio out)
            DirectSoundDriver.CreateSoundBuffer(renderBuffer, out var audioRenderBuffer, IntPtr.Zero);
            AudioRenderBuffer = audioRenderBuffer as DirectSound.IDirectSoundBuffer;

            // Play & Loop on the render buffer
            AudioRenderBuffer?.Play(0, 0, DirectSound.DirectSoundPlayFlags.Looping);

            // A frame of samples equals to Desired Latency
            SamplesFrameSize = MillisToBytes(DesiredLatency);
            var waveFormatHandle = GCHandle.Alloc(WaveFormat, GCHandleType.Pinned);

            // Fill BufferDescription for sample-receiving back buffer
            var backBuffer = new DirectSound.BufferDescription
            {
                Size        = Marshal.SizeOf <DirectSound.BufferDescription>(),
                BufferBytes = (uint)(SamplesFrameSize * 2),
                Flags       = DirectSound.DirectSoundBufferCaps.GetCurrentPosition2
                              | DirectSound.DirectSoundBufferCaps.ControlNotifyPosition
                              | DirectSound.DirectSoundBufferCaps.GlobalFocus
                              | DirectSound.DirectSoundBufferCaps.ControlVolume
                              | DirectSound.DirectSoundBufferCaps.StickyFocus
                              | DirectSound.DirectSoundBufferCaps.GetCurrentPosition2,
                Reserved     = 0,
                FormatHandle = waveFormatHandle.AddrOfPinnedObject(),
                AlgorithmId  = Guid.Empty
            };

            // Create back buffer where samples will be fed
            DirectSoundDriver.CreateSoundBuffer(backBuffer, out audioRenderBuffer, IntPtr.Zero);
            AudioBackBuffer = audioRenderBuffer as DirectSound.IDirectSoundBuffer;
            waveFormatHandle.Free();

            // Get effective SecondaryBuffer size
            var bufferCapabilities = new DirectSound.BufferCaps {
                Size = Marshal.SizeOf <DirectSound.BufferCaps>()
            };

            AudioBackBuffer?.GetCaps(bufferCapabilities);

            NextSamplesWriteIndex = 0;
            SamplesTotalSize      = bufferCapabilities.BufferBytes;
            Samples = new byte[SamplesTotalSize];
            Debug.Assert(SamplesTotalSize == (2 * SamplesFrameSize), "Invalid SamplesTotalSize vs SamplesFrameSize");

            // Create double buffering notifications.
            // Use DirectSoundNotify at Position [0, 1/2] and Stop Position (0xFFFFFFFF)
            var notifier = audioRenderBuffer as DirectSound.IDirectSoundNotify;

            FrameStartEventWaitHandle    = new EventWaitHandle(false, EventResetMode.AutoReset);
            FrameEndEventWaitHandle      = new EventWaitHandle(false, EventResetMode.AutoReset);
            PlaybackEndedEventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
            PlaybackWaitHandles          = new WaitHandle[] { FrameStartEventWaitHandle, FrameEndEventWaitHandle, PlaybackEndedEventWaitHandle, CancelEvent };

            var notificationEvents = new[]
            {
                CreatePositionNotification(FrameStartEventWaitHandle, 0),
                CreatePositionNotification(FrameEndEventWaitHandle, (uint)SamplesFrameSize),
                CreatePositionNotification(PlaybackEndedEventWaitHandle, 0xFFFFFFFF)
            };

            notifier?.SetNotificationPositions((uint)notificationEvents.Length, notificationEvents);
        }
Beispiel #2
0
        /// <summary>
        /// Initializes the direct sound.
        /// </summary>
        private void InitializeDirectSound()
        {
            // Open DirectSound
            DirectSoundDriver = null;
            NativeMethods.DirectSoundCreate(ref DeviceId, out DirectSoundDriver, IntPtr.Zero);

            if (DirectSoundDriver == null)
            {
                return;
            }

            // Set Cooperative Level to PRIORITY (priority level can call the SetFormat and Compact methods)
            DirectSoundDriver.SetCooperativeLevel(NativeMethods.GetDesktopWindow(),
                                                  DirectSound.DirectSoundCooperativeLevel.DSSCL_PRIORITY);

            // -------------------------------------------------------------------------------------
            // Create PrimaryBuffer
            // -------------------------------------------------------------------------------------

            // Fill BufferDescription for PrimaryBuffer
            var bufferDesc = new DirectSound.BufferDescription();

            bufferDesc.Size         = Marshal.SizeOf(bufferDesc);
            bufferDesc.BufferBytes  = 0;
            bufferDesc.Flags        = DirectSound.DirectSoundBufferCaps.DSBCAPS_PRIMARYBUFFER;
            bufferDesc.Reserved     = 0;
            bufferDesc.FormatHandle = IntPtr.Zero;
            bufferDesc.AlgorithmId  = Guid.Empty;

            // Create PrimaryBuffer
            DirectSoundDriver.CreateSoundBuffer(bufferDesc, out object soundBufferObj, IntPtr.Zero);
            AudioPlaybackBuffer = soundBufferObj as DirectSound.IDirectSoundBuffer;

            // Play & Loop on the PrimarySound Buffer
            AudioPlaybackBuffer.Play(0, 0, DirectSound.DirectSoundPlayFlags.DSBPLAY_LOOPING);

            // -------------------------------------------------------------------------------------
            // Create SecondaryBuffer
            // -------------------------------------------------------------------------------------

            // A frame of samples equals to Desired Latency
            SamplesFrameSize = MillisToBytes(DesiredLatency);

            // Fill BufferDescription for SecondaryBuffer
            var bufferDesc2 = new DirectSound.BufferDescription();

            bufferDesc2.Size        = Marshal.SizeOf(bufferDesc2);
            bufferDesc2.BufferBytes = (uint)(SamplesFrameSize * 2);
            bufferDesc2.Flags       = DirectSound.DirectSoundBufferCaps.DSBCAPS_GETCURRENTPOSITION2
                                      | DirectSound.DirectSoundBufferCaps.DSBCAPS_CTRLPOSITIONNOTIFY
                                      | DirectSound.DirectSoundBufferCaps.DSBCAPS_GLOBALFOCUS
                                      | DirectSound.DirectSoundBufferCaps.DSBCAPS_CTRLVOLUME
                                      | DirectSound.DirectSoundBufferCaps.DSBCAPS_STICKYFOCUS
                                      | DirectSound.DirectSoundBufferCaps.DSBCAPS_GETCURRENTPOSITION2;

            bufferDesc2.Reserved = 0;
            var handleOnWaveFormat = GCHandle.Alloc(WaveFormat, GCHandleType.Pinned); // Ptr to waveFormat

            bufferDesc2.FormatHandle = handleOnWaveFormat.AddrOfPinnedObject();       // set Ptr to waveFormat
            bufferDesc2.AlgorithmId  = Guid.Empty;

            // Create SecondaryBuffer
            DirectSoundDriver.CreateSoundBuffer(bufferDesc2, out soundBufferObj, IntPtr.Zero);
            AudioBackBuffer = soundBufferObj as DirectSound.IDirectSoundBuffer;
            handleOnWaveFormat.Free();

            // Get effective SecondaryBuffer size
            var dsbCaps = new DirectSound.BufferCaps();

            dsbCaps.Size = Marshal.SizeOf(dsbCaps);
            AudioBackBuffer.GetCaps(dsbCaps);

            NextSamplesWriteIndex = 0;
            SamplesTotalSize      = dsbCaps.BufferBytes;
            Samples = new byte[SamplesTotalSize];
            Debug.Assert(SamplesTotalSize == (2 * SamplesFrameSize), "Invalid SamplesTotalSize vs SamplesFrameSize");

            // -------------------------------------------------------------------------------------
            // Create double buffering notification.
            // Use DirectSoundNotify at Position [0, 1/2] and Stop Position (0xFFFFFFFF)
            // -------------------------------------------------------------------------------------
            var notify = soundBufferObj as DirectSound.IDirectSoundNotify;

            FrameEventWaitHandle1 = new EventWaitHandle(false, EventResetMode.AutoReset);
            FrameEventWaitHandle2 = new EventWaitHandle(false, EventResetMode.AutoReset);
            EndEventWaitHandle    = new EventWaitHandle(false, EventResetMode.AutoReset);

            var notifies = new DirectSound.DirectSoundBufferPositionNotify[3];

            notifies[0] = new DirectSound.DirectSoundBufferPositionNotify
            {
                Offset       = 0,
                NotifyHandle = FrameEventWaitHandle1.SafeWaitHandle.DangerousGetHandle()
            };

            notifies[1] = new DirectSound.DirectSoundBufferPositionNotify
            {
                Offset       = (uint)SamplesFrameSize,
                NotifyHandle = FrameEventWaitHandle2.SafeWaitHandle.DangerousGetHandle()
            };

            notifies[2] = new DirectSound.DirectSoundBufferPositionNotify
            {
                Offset       = 0xFFFFFFFF,
                NotifyHandle = EndEventWaitHandle.SafeWaitHandle.DangerousGetHandle()
            };

            notify.SetNotificationPositions(3, notifies);
        }