unsafe protected override void PostAttachVirtualChannel()
        {
            DirectSoundWorld.criticalSection.Enter();

            int hr;

            currentSound = (DirectSound)CurrentVirtualChannel.CurrentSound;

            bool mode3d = (int)(currentSound.Mode & SoundMode.Mode3D) != 0;
            bool loop   = (int)(currentSound.Mode & SoundMode.Loop) != 0;

            //DirectSampleSound
            DirectSampleSound currentSampleSound = currentSound as DirectSampleSound;

            if (currentSampleSound != null)
            {
                int lastBufferCount = currentSound.soundBuffers.Count;

                currentSoundBuffer = currentSound.GetBuffer(currentSampleSound.soundSamples.Length);
                if (currentSoundBuffer == null)
                {
                    PreDetachVirtualChannel();
                    DirectSoundWorld.criticalSection.Leave();
                    return;
                }

                bool needFillData = false;

                if (lastBufferCount == 0)
                {
                    needFillData = true;
                }

                bool restored = false;
                if (!currentSound.RestoreSoundBuffers(out restored))
                {
                    PreDetachVirtualChannel();
                    DirectSoundWorld.criticalSection.Leave();
                    return;
                }
                if (restored)
                {
                    needFillData = true;
                }

                if (needFillData)
                {
                    if (!currentSampleSound.FillSoundBuffersWithData())
                    {
                        PreDetachVirtualChannel();
                        DirectSoundWorld.criticalSection.Leave();
                        return;
                    }
                }
            }

            //DirectFileStreamSound, DirectDataStreamSound
            DirectFileStreamSound currentFileStreamSound = currentSound as DirectFileStreamSound;
            DirectDataStreamSound currentDataStreamSound = currentSound as DirectDataStreamSound;

            if (currentFileStreamSound != null || currentDataStreamSound != null)
            {
                int needBufferSize;

                if (currentFileStreamSound != null)
                {
                    int numSamples = (int)currentFileStreamSound.vorbisFile.pcm_total(-1);
                    int channels;
                    int rate;
                    currentFileStreamSound.vorbisFile.get_info(-1, out channels, out rate);
                    int sizeInBytes = numSamples * channels * 2;

                    needBufferSize = sizeInBytes / 2;

                    if (needBufferSize > 65536 * 2)
                    {
                        needBufferSize = 65536 * 2;
                    }
                }
                else
                {
                    needBufferSize = currentDataStreamSound.creationBufferSize;
                }

                currentSoundBuffer = currentSound.GetBuffer(needBufferSize);
                if (currentSoundBuffer == null)
                {
                    PreDetachVirtualChannel();
                    DirectSoundWorld.criticalSection.Leave();
                    return;
                }

                streamBuffer = (byte *)NativeUtils.Alloc(NativeMemoryAllocationType.SoundAndVideo,
                                                         currentSound.bufferSize);
                streamBufferLength = 0;

                bool restored = false;
                if (!currentSound.RestoreSoundBuffers(out restored))
                {
                    PreDetachVirtualChannel();
                    DirectSoundWorld.criticalSection.Leave();
                    return;
                }
                if (restored)
                {
                    //buffer will be cleared in the BeginStreamPlay()
                }
            }

            //currentSound3DBuffer
            if (mode3d)
            {
                void */*IDirectSound3DBuffer8*/ sound3DBuffer;

                GUID guid = DSound.IID_IDirectSound3DBuffer8;
                hr = IDirectSoundBuffer.QueryInterface(currentSoundBuffer, ref guid, &sound3DBuffer);
                if (Wrapper.FAILED(hr))
                {
                    PreDetachVirtualChannel();
                    DirectSoundWorld.Warning("IDirectSoundBuffer.QueryInterface", hr);
                    DirectSoundWorld.criticalSection.Leave();
                    return;
                }
                currentSound3DBuffer = (IDirectSound3DBuffer8 *)sound3DBuffer;
            }

            //update parameters
            if (mode3d)
            {
                UpdatePosition2();
                UpdateVelocity2();
            }
            else
            {
                UpdatePan2();
            }
            UpdatePitch2();
            UpdateVolume2();

            UpdateTime2();

            if (currentFileStreamSound != null || currentDataStreamSound != null)
            {
                BeginStreamPlay();
            }

            uint playFlags = 0;

            if (loop || currentFileStreamSound != null || currentDataStreamSound != null)
            {
                playFlags |= DSound.DSBPLAY_LOOPING;
            }

            hr = IDirectSoundBuffer.Play(currentSoundBuffer, 0, 0, playFlags);
            if (Wrapper.FAILED(hr))
            {
                PreDetachVirtualChannel();
                DirectSoundWorld.Warning("IDirectSoundBuffer.Play", hr);
                DirectSoundWorld.criticalSection.Leave();
                return;
            }

            if (currentFileStreamSound != null)
            {
                DirectSoundWorld.Instance.fileStreamRealChannels.Add(this);
            }

            needStopVirtualChannel = false;

            DirectSoundWorld.criticalSection.Leave();
        }
        unsafe protected override bool InitLibrary(IntPtr mainWindowHandle,
                                                   int maxReal2DChannels, int maxReal3DChannels)
        {
            NativeLibraryManager.PreLoadLibrary("libogg");
            NativeLibraryManager.PreLoadLibrary("libvorbis");
            NativeLibraryManager.PreLoadLibrary("libvorbisfile");
            NativeLibraryManager.PreLoadLibrary("DirectSoundNativeWrapper");

            {
                DSoundStructureSizes sizes = new DSoundStructureSizes();
                sizes.Init();

                DSoundStructureSizes originalSizes;
                DSound.GetStructureSizes(out originalSizes);

                FieldInfo[] fields = sizes.GetType().GetFields(
                    BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);

                foreach (FieldInfo field in fields)
                {
                    int originalSize = (int)field.GetValue(originalSizes);
                    int size         = (int)field.GetValue(sizes);

                    if (originalSize != size)
                    {
                        Log.Fatal("DirectXSoundSystem: Invalid unmanaged bridge. " +
                                  "Invalid \"{0}\". Native size = \"{1}\". Managed size = \"{2}\".", field.Name,
                                  originalSize, size);
                        return(false);
                    }
                }
            }

            instance = this;

            criticalSection = CriticalSection.Create();

            DSound.CoInitialize(null);

            int hr;

            //create IDirectSound using the primary sound device
            void */*IDirectSound8*/ directSoundTemp;

            hr = DSound.DirectSoundCreate8(null, out directSoundTemp, null);
            if (Wrapper.FAILED(hr))
            {
                if (hr == DSound.Get_DSERR_NODRIVER())
                {
                    Log.InvisibleInfo("DirectXSoundSystem: No sound driver.");
                    return(false);
                }

                Error("DirectSoundCreate8", hr);
                return(false);
            }
            directSound = (IDirectSound8 *)directSoundTemp;

            //set DirectSound cooperative level
            hWnd = mainWindowHandle;
            hr   = IDirectSound8.SetCooperativeLevel(directSound, hWnd, DSound.DSSCL_PRIORITY);
            if (Wrapper.FAILED(hr))
            {
                Error("SetCooperativeLevel", hr);
                return(false);
            }

            //set primary buffer format
            {
                hr = SetPrimaryBufferFormat(2, 44100, 16, false);
                if (Wrapper.FAILED(hr))
                {
                    hr = SetPrimaryBufferFormat(2, 22050, 16, true);
                }
                if (Wrapper.FAILED(hr))
                {
                    return(false);
                }
            }

            //get listener
            {
                void */*IDirectSoundBuffer*/ primaryBuffer = null;

                // Obtain primary buffer, asking it for 3D control
                DSBUFFERDESC bufferDesc = new DSBUFFERDESC();
                //ZeroMemory( &bufferDesc, sizeof( DSBUFFERDESC ) );
                bufferDesc.dwSize  = (uint)sizeof(DSBUFFERDESC);
                bufferDesc.dwFlags = DSound.DSBCAPS_CTRL3D | DSound.DSBCAPS_PRIMARYBUFFER;

                hr = IDirectSound8.CreateSoundBuffer(directSound, ref bufferDesc,
                                                     out primaryBuffer, null);
                if (Wrapper.FAILED(hr))
                {
                    Error("CreateSoundBuffer", hr);
                    return(false);
                }

                void */*IDirectSound3DListener*/ listenerTemp = null;

                GUID guid = DSound.IID_IDirectSound3DListener;
                if (Wrapper.FAILED(hr = IDirectSoundBuffer.QueryInterface(primaryBuffer,
                                                                          ref guid, &listenerTemp)))
                {
                    IDirectSoundBuffer.Release(primaryBuffer);
                    Error("QueryInterface", hr);
                    return(false);
                }
                listener = (IDirectSound3DListener *)listenerTemp;

                IDirectSoundBuffer.Release(primaryBuffer);
            }

            //update general parameters
            {
                DS3DLISTENER parameters = new DS3DLISTENER();
                parameters.dwSize = (uint)sizeof(DS3DLISTENER);
                IDirectSound3DListener.GetAllParameters(listener, ref parameters);
                parameters.flDistanceFactor = 1;
                parameters.flRolloffFactor  = 0;
                parameters.flDopplerFactor  = DopplerScale;
                hr = IDirectSound3DListener.SetAllParameters(listener, ref parameters, DSound.DS3D_IMMEDIATE);
                if (Wrapper.FAILED(hr))
                {
                    Warning("IDirectSound3DListener.SetAllParameters", hr);
                }
            }

            GenerateRecordDriverList();

            //Channels
            realChannels = new List <DirectSoundRealChannel>();
            for (int n = 0; n < maxReal2DChannels; n++)
            {
                DirectSoundRealChannel realChannel = new DirectSoundRealChannel();
                AddRealChannel(realChannel, false);
                realChannels.Add(realChannel);
            }
            for (int n = 0; n < maxReal3DChannels; n++)
            {
                DirectSoundRealChannel realChannel = new DirectSoundRealChannel();
                AddRealChannel(realChannel, true);
                realChannels.Add(realChannel);
            }

            fileStreamRealChannels = new List <DirectSoundRealChannel>();

            thread = new Thread(new ThreadStart(ThreadFunction));
            thread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
            thread.IsBackground   = true;
            thread.Start();

            return(true);
        }