rlm@0: /** rlm@0: * OpenAL cross platform audio library rlm@0: * Copyright (C) 1999-2007 by authors. rlm@0: * This library is free software; you can redistribute it and/or rlm@0: * modify it under the terms of the GNU Library General Public rlm@0: * License as published by the Free Software Foundation; either rlm@0: * version 2 of the License, or (at your option) any later version. rlm@0: * rlm@0: * This library is distributed in the hope that it will be useful, rlm@0: * but WITHOUT ANY WARRANTY; without even the implied warranty of rlm@0: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU rlm@0: * Library General Public License for more details. rlm@0: * rlm@0: * You should have received a copy of the GNU Library General Public rlm@0: * License along with this library; if not, write to the rlm@0: * Free Software Foundation, Inc., 59 Temple Place - Suite 330, rlm@0: * Boston, MA 02111-1307, USA. rlm@0: * Or go to http://www.gnu.org/copyleft/lgpl.html rlm@0: */ rlm@0: rlm@0: #include "config.h" rlm@0: rlm@0: #define _WIN32_WINNT 0x0500 rlm@0: #include rlm@0: #include rlm@0: #include rlm@0: rlm@0: #include rlm@0: #include rlm@0: #include rlm@0: #ifndef _WAVEFORMATEXTENSIBLE_ rlm@0: #include rlm@0: #include rlm@0: #endif rlm@0: rlm@0: #include "alMain.h" rlm@0: #include "AL/al.h" rlm@0: #include "AL/alc.h" rlm@0: rlm@0: #ifndef DSSPEAKER_5POINT1 rlm@0: #define DSSPEAKER_5POINT1 6 rlm@0: #endif rlm@0: #ifndef DSSPEAKER_7POINT1 rlm@0: #define DSSPEAKER_7POINT1 7 rlm@0: #endif rlm@0: rlm@0: DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); rlm@0: DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); rlm@0: rlm@0: rlm@0: static HMODULE ds_handle; rlm@0: static HRESULT (WINAPI *pDirectSoundCreate)(LPCGUID pcGuidDevice, IDirectSound **ppDS, IUnknown *pUnkOuter); rlm@0: static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA pDSEnumCallback, void *pContext); rlm@0: rlm@0: #define DirectSoundCreate pDirectSoundCreate rlm@0: #define DirectSoundEnumerateA pDirectSoundEnumerateA rlm@0: rlm@0: rlm@0: typedef struct { rlm@0: // DirectSound Playback Device rlm@0: IDirectSound *lpDS; rlm@0: IDirectSoundBuffer *DSpbuffer; rlm@0: IDirectSoundBuffer *DSsbuffer; rlm@0: IDirectSoundNotify *DSnotify; rlm@0: HANDLE hNotifyEvent; rlm@0: rlm@0: volatile int killNow; rlm@0: ALvoid *thread; rlm@0: } DSoundData; rlm@0: rlm@0: rlm@0: typedef struct { rlm@0: ALCchar *name; rlm@0: GUID guid; rlm@0: } DevMap; rlm@0: rlm@0: static const ALCchar dsDevice[] = "DirectSound Default"; rlm@0: static DevMap *DeviceList; rlm@0: static ALuint NumDevices; rlm@0: rlm@0: #define MAX_UPDATES 128 rlm@0: rlm@0: static ALCboolean DSoundLoad(void) rlm@0: { rlm@0: ALCboolean ok = ALC_TRUE; rlm@0: if(!ds_handle) rlm@0: { rlm@0: ds_handle = LoadLibraryA("dsound.dll"); rlm@0: if(ds_handle == NULL) rlm@0: { rlm@0: ERR("Failed to load dsound.dll\n"); rlm@0: return ALC_FALSE; rlm@0: } rlm@0: rlm@0: #define LOAD_FUNC(x) do { \ rlm@0: if((p##x = (void*)GetProcAddress(ds_handle, #x)) == NULL) { \ rlm@0: ERR("Could not load %s from dsound.dll\n", #x); \ rlm@0: ok = ALC_FALSE; \ rlm@0: } \ rlm@0: } while(0) rlm@0: LOAD_FUNC(DirectSoundCreate); rlm@0: LOAD_FUNC(DirectSoundEnumerateA); rlm@0: #undef LOAD_FUNC rlm@0: rlm@0: if(!ok) rlm@0: { rlm@0: FreeLibrary(ds_handle); rlm@0: ds_handle = NULL; rlm@0: } rlm@0: } rlm@0: return ok; rlm@0: } rlm@0: rlm@0: rlm@0: static BOOL CALLBACK DSoundEnumDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data) rlm@0: { rlm@0: char str[1024]; rlm@0: void *temp; rlm@0: int count; rlm@0: ALuint i; rlm@0: rlm@0: (void)data; rlm@0: (void)drvname; rlm@0: rlm@0: if(!guid) rlm@0: return TRUE; rlm@0: rlm@0: count = 0; rlm@0: do { rlm@0: if(count == 0) rlm@0: snprintf(str, sizeof(str), "%s", desc); rlm@0: else rlm@0: snprintf(str, sizeof(str), "%s #%d", desc, count+1); rlm@0: count++; rlm@0: rlm@0: for(i = 0;i < NumDevices;i++) rlm@0: { rlm@0: if(strcmp(str, DeviceList[i].name) == 0) rlm@0: break; rlm@0: } rlm@0: } while(i != NumDevices); rlm@0: rlm@0: temp = realloc(DeviceList, sizeof(DevMap) * (NumDevices+1)); rlm@0: if(temp) rlm@0: { rlm@0: DeviceList = temp; rlm@0: DeviceList[NumDevices].name = strdup(str); rlm@0: DeviceList[NumDevices].guid = *guid; rlm@0: NumDevices++; rlm@0: } rlm@0: rlm@0: return TRUE; rlm@0: } rlm@0: rlm@0: rlm@0: static ALuint DSoundProc(ALvoid *ptr) rlm@0: { rlm@0: ALCdevice *pDevice = (ALCdevice*)ptr; rlm@0: DSoundData *pData = (DSoundData*)pDevice->ExtraData; rlm@0: DSBCAPS DSBCaps; rlm@0: DWORD LastCursor = 0; rlm@0: DWORD PlayCursor; rlm@0: VOID *WritePtr1, *WritePtr2; rlm@0: DWORD WriteCnt1, WriteCnt2; rlm@0: BOOL Playing = FALSE; rlm@0: DWORD FrameSize; rlm@0: DWORD FragSize; rlm@0: DWORD avail; rlm@0: HRESULT err; rlm@0: rlm@0: SetRTPriority(); rlm@0: rlm@0: memset(&DSBCaps, 0, sizeof(DSBCaps)); rlm@0: DSBCaps.dwSize = sizeof(DSBCaps); rlm@0: err = IDirectSoundBuffer_GetCaps(pData->DSsbuffer, &DSBCaps); rlm@0: if(FAILED(err)) rlm@0: { rlm@0: ERR("Failed to get buffer caps: 0x%lx\n", err); rlm@0: aluHandleDisconnect(pDevice); rlm@0: return 1; rlm@0: } rlm@0: rlm@0: FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType); rlm@0: FragSize = pDevice->UpdateSize * FrameSize; rlm@0: rlm@0: IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &LastCursor, NULL); rlm@0: while(!pData->killNow) rlm@0: { rlm@0: // Get current play cursor rlm@0: IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &PlayCursor, NULL); rlm@0: avail = (PlayCursor-LastCursor+DSBCaps.dwBufferBytes) % DSBCaps.dwBufferBytes; rlm@0: rlm@0: if(avail < FragSize) rlm@0: { rlm@0: if(!Playing) rlm@0: { rlm@0: err = IDirectSoundBuffer_Play(pData->DSsbuffer, 0, 0, DSBPLAY_LOOPING); rlm@0: if(FAILED(err)) rlm@0: { rlm@0: ERR("Failed to play buffer: 0x%lx\n", err); rlm@0: aluHandleDisconnect(pDevice); rlm@0: return 1; rlm@0: } rlm@0: Playing = TRUE; rlm@0: } rlm@0: rlm@0: avail = WaitForSingleObjectEx(pData->hNotifyEvent, 2000, FALSE); rlm@0: if(avail != WAIT_OBJECT_0) rlm@0: ERR("WaitForSingleObjectEx error: 0x%lx\n", avail); rlm@0: continue; rlm@0: } rlm@0: avail -= avail%FragSize; rlm@0: rlm@0: // Lock output buffer rlm@0: WriteCnt1 = 0; rlm@0: WriteCnt2 = 0; rlm@0: err = IDirectSoundBuffer_Lock(pData->DSsbuffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0); rlm@0: rlm@0: // If the buffer is lost, restore it and lock rlm@0: if(err == DSERR_BUFFERLOST) rlm@0: { rlm@0: WARN("Buffer lost, restoring...\n"); rlm@0: err = IDirectSoundBuffer_Restore(pData->DSsbuffer); rlm@0: if(SUCCEEDED(err)) rlm@0: { rlm@0: Playing = FALSE; rlm@0: LastCursor = 0; rlm@0: err = IDirectSoundBuffer_Lock(pData->DSsbuffer, 0, DSBCaps.dwBufferBytes, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0); rlm@0: } rlm@0: } rlm@0: rlm@0: // Successfully locked the output buffer rlm@0: if(SUCCEEDED(err)) rlm@0: { rlm@0: // If we have an active context, mix data directly into output buffer otherwise fill with silence rlm@0: aluMixData(pDevice, WritePtr1, WriteCnt1/FrameSize); rlm@0: aluMixData(pDevice, WritePtr2, WriteCnt2/FrameSize); rlm@0: rlm@0: // Unlock output buffer only when successfully locked rlm@0: IDirectSoundBuffer_Unlock(pData->DSsbuffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2); rlm@0: } rlm@0: else rlm@0: { rlm@0: ERR("Buffer lock error: %#lx\n", err); rlm@0: aluHandleDisconnect(pDevice); rlm@0: return 1; rlm@0: } rlm@0: rlm@0: // Update old write cursor location rlm@0: LastCursor += WriteCnt1+WriteCnt2; rlm@0: LastCursor %= DSBCaps.dwBufferBytes; rlm@0: } rlm@0: rlm@0: return 0; rlm@0: } rlm@0: rlm@0: static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceName) rlm@0: { rlm@0: DSoundData *pData = NULL; rlm@0: LPGUID guid = NULL; rlm@0: HRESULT hr; rlm@0: rlm@0: if(!deviceName) rlm@0: deviceName = dsDevice; rlm@0: else if(strcmp(deviceName, dsDevice) != 0) rlm@0: { rlm@0: ALuint i; rlm@0: rlm@0: if(!DeviceList) rlm@0: { rlm@0: hr = DirectSoundEnumerateA(DSoundEnumDevices, NULL); rlm@0: if(FAILED(hr)) rlm@0: ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr); rlm@0: } rlm@0: rlm@0: for(i = 0;i < NumDevices;i++) rlm@0: { rlm@0: if(strcmp(deviceName, DeviceList[i].name) == 0) rlm@0: { rlm@0: guid = &DeviceList[i].guid; rlm@0: break; rlm@0: } rlm@0: } rlm@0: if(i == NumDevices) rlm@0: return ALC_FALSE; rlm@0: } rlm@0: rlm@0: //Initialise requested device rlm@0: pData = calloc(1, sizeof(DSoundData)); rlm@0: if(!pData) rlm@0: { rlm@0: alcSetError(device, ALC_OUT_OF_MEMORY); rlm@0: return ALC_FALSE; rlm@0: } rlm@0: rlm@0: hr = DS_OK; rlm@0: pData->hNotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); rlm@0: if(pData->hNotifyEvent == NULL) rlm@0: hr = E_FAIL; rlm@0: rlm@0: //DirectSound Init code rlm@0: if(SUCCEEDED(hr)) rlm@0: hr = DirectSoundCreate(guid, &pData->lpDS, NULL); rlm@0: if(SUCCEEDED(hr)) rlm@0: hr = IDirectSound_SetCooperativeLevel(pData->lpDS, GetForegroundWindow(), DSSCL_PRIORITY); rlm@0: if(FAILED(hr)) rlm@0: { rlm@0: if(pData->lpDS) rlm@0: IDirectSound_Release(pData->lpDS); rlm@0: if(pData->hNotifyEvent) rlm@0: CloseHandle(pData->hNotifyEvent); rlm@0: free(pData); rlm@0: ERR("Device init failed: 0x%08lx\n", hr); rlm@0: return ALC_FALSE; rlm@0: } rlm@0: rlm@0: device->szDeviceName = strdup(deviceName); rlm@0: device->ExtraData = pData; rlm@0: return ALC_TRUE; rlm@0: } rlm@0: rlm@0: static void DSoundClosePlayback(ALCdevice *device) rlm@0: { rlm@0: DSoundData *pData = device->ExtraData; rlm@0: rlm@0: IDirectSound_Release(pData->lpDS); rlm@0: CloseHandle(pData->hNotifyEvent); rlm@0: free(pData); rlm@0: device->ExtraData = NULL; rlm@0: } rlm@0: rlm@0: static ALCboolean DSoundResetPlayback(ALCdevice *device) rlm@0: { rlm@0: DSoundData *pData = (DSoundData*)device->ExtraData; rlm@0: DSBUFFERDESC DSBDescription; rlm@0: WAVEFORMATEXTENSIBLE OutputType; rlm@0: DWORD speakers; rlm@0: HRESULT hr; rlm@0: rlm@0: memset(&OutputType, 0, sizeof(OutputType)); rlm@0: rlm@0: switch(device->FmtType) rlm@0: { rlm@0: case DevFmtByte: rlm@0: device->FmtType = DevFmtUByte; rlm@0: break; rlm@0: case DevFmtUShort: rlm@0: device->FmtType = DevFmtShort; rlm@0: break; rlm@0: case DevFmtUByte: rlm@0: case DevFmtShort: rlm@0: case DevFmtFloat: rlm@0: break; rlm@0: } rlm@0: rlm@0: hr = IDirectSound_GetSpeakerConfig(pData->lpDS, &speakers); rlm@0: if(SUCCEEDED(hr)) rlm@0: { rlm@0: if(!(device->Flags&DEVICE_CHANNELS_REQUEST)) rlm@0: { rlm@0: speakers = DSSPEAKER_CONFIG(speakers); rlm@0: if(speakers == DSSPEAKER_MONO) rlm@0: device->FmtChans = DevFmtMono; rlm@0: else if(speakers == DSSPEAKER_STEREO || speakers == DSSPEAKER_HEADPHONE) rlm@0: device->FmtChans = DevFmtStereo; rlm@0: else if(speakers == DSSPEAKER_QUAD) rlm@0: device->FmtChans = DevFmtQuad; rlm@0: else if(speakers == DSSPEAKER_5POINT1) rlm@0: device->FmtChans = DevFmtX51; rlm@0: else if(speakers == DSSPEAKER_7POINT1) rlm@0: device->FmtChans = DevFmtX71; rlm@0: else rlm@0: ERR("Unknown system speaker config: 0x%lx\n", speakers); rlm@0: } rlm@0: rlm@0: switch(device->FmtChans) rlm@0: { rlm@0: case DevFmtMono: rlm@0: OutputType.dwChannelMask = SPEAKER_FRONT_CENTER; rlm@0: break; rlm@0: case DevFmtStereo: rlm@0: OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | rlm@0: SPEAKER_FRONT_RIGHT; rlm@0: break; rlm@0: case DevFmtQuad: rlm@0: OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | rlm@0: SPEAKER_FRONT_RIGHT | rlm@0: SPEAKER_BACK_LEFT | rlm@0: SPEAKER_BACK_RIGHT; rlm@0: break; rlm@0: case DevFmtX51: rlm@0: OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | rlm@0: SPEAKER_FRONT_RIGHT | rlm@0: SPEAKER_FRONT_CENTER | rlm@0: SPEAKER_LOW_FREQUENCY | rlm@0: SPEAKER_BACK_LEFT | rlm@0: SPEAKER_BACK_RIGHT; rlm@0: break; rlm@0: case DevFmtX51Side: rlm@0: OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | rlm@0: SPEAKER_FRONT_RIGHT | rlm@0: SPEAKER_FRONT_CENTER | rlm@0: SPEAKER_LOW_FREQUENCY | rlm@0: SPEAKER_SIDE_LEFT | rlm@0: SPEAKER_SIDE_RIGHT; rlm@0: break; rlm@0: case DevFmtX61: rlm@0: OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | rlm@0: SPEAKER_FRONT_RIGHT | rlm@0: SPEAKER_FRONT_CENTER | rlm@0: SPEAKER_LOW_FREQUENCY | rlm@0: SPEAKER_BACK_CENTER | rlm@0: SPEAKER_SIDE_LEFT | rlm@0: SPEAKER_SIDE_RIGHT; rlm@0: break; rlm@0: case DevFmtX71: rlm@0: OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | rlm@0: SPEAKER_FRONT_RIGHT | rlm@0: SPEAKER_FRONT_CENTER | rlm@0: SPEAKER_LOW_FREQUENCY | rlm@0: SPEAKER_BACK_LEFT | rlm@0: SPEAKER_BACK_RIGHT | rlm@0: SPEAKER_SIDE_LEFT | rlm@0: SPEAKER_SIDE_RIGHT; rlm@0: break; rlm@0: } rlm@0: rlm@0: OutputType.Format.wFormatTag = WAVE_FORMAT_PCM; rlm@0: OutputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans); rlm@0: OutputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8; rlm@0: OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8; rlm@0: OutputType.Format.nSamplesPerSec = device->Frequency; rlm@0: OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec*OutputType.Format.nBlockAlign; rlm@0: OutputType.Format.cbSize = 0; rlm@0: } rlm@0: rlm@0: if(OutputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat) rlm@0: { rlm@0: OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; rlm@0: OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; rlm@0: OutputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); rlm@0: if(device->FmtType == DevFmtFloat) rlm@0: OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; rlm@0: else rlm@0: OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; rlm@0: } rlm@0: else rlm@0: { rlm@0: if(SUCCEEDED(hr)) rlm@0: { rlm@0: memset(&DSBDescription,0,sizeof(DSBUFFERDESC)); rlm@0: DSBDescription.dwSize=sizeof(DSBUFFERDESC); rlm@0: DSBDescription.dwFlags=DSBCAPS_PRIMARYBUFFER; rlm@0: hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSpbuffer, NULL); rlm@0: } rlm@0: if(SUCCEEDED(hr)) rlm@0: hr = IDirectSoundBuffer_SetFormat(pData->DSpbuffer,&OutputType.Format); rlm@0: } rlm@0: rlm@0: if(SUCCEEDED(hr)) rlm@0: { rlm@0: if(device->NumUpdates > MAX_UPDATES) rlm@0: { rlm@0: device->UpdateSize = (device->UpdateSize*device->NumUpdates + rlm@0: MAX_UPDATES-1) / MAX_UPDATES; rlm@0: device->NumUpdates = MAX_UPDATES; rlm@0: } rlm@0: rlm@0: memset(&DSBDescription,0,sizeof(DSBUFFERDESC)); rlm@0: DSBDescription.dwSize=sizeof(DSBUFFERDESC); rlm@0: DSBDescription.dwFlags=DSBCAPS_CTRLPOSITIONNOTIFY|DSBCAPS_GETCURRENTPOSITION2|DSBCAPS_GLOBALFOCUS; rlm@0: DSBDescription.dwBufferBytes=device->UpdateSize * device->NumUpdates * rlm@0: OutputType.Format.nBlockAlign; rlm@0: DSBDescription.lpwfxFormat=&OutputType.Format; rlm@0: hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSsbuffer, NULL); rlm@0: } rlm@0: rlm@0: if(SUCCEEDED(hr)) rlm@0: { rlm@0: hr = IDirectSoundBuffer_QueryInterface(pData->DSsbuffer, &IID_IDirectSoundNotify, (LPVOID *)&pData->DSnotify); rlm@0: if(SUCCEEDED(hr)) rlm@0: { rlm@0: DSBPOSITIONNOTIFY notifies[MAX_UPDATES]; rlm@0: ALuint i; rlm@0: rlm@0: for(i = 0;i < device->NumUpdates;++i) rlm@0: { rlm@0: notifies[i].dwOffset = i * device->UpdateSize * rlm@0: OutputType.Format.nBlockAlign; rlm@0: notifies[i].hEventNotify = pData->hNotifyEvent; rlm@0: } rlm@0: if(IDirectSoundNotify_SetNotificationPositions(pData->DSnotify, device->NumUpdates, notifies) != DS_OK) rlm@0: hr = E_FAIL; rlm@0: } rlm@0: } rlm@0: rlm@0: if(SUCCEEDED(hr)) rlm@0: { rlm@0: ResetEvent(pData->hNotifyEvent); rlm@0: SetDefaultWFXChannelOrder(device); rlm@0: pData->thread = StartThread(DSoundProc, device); rlm@0: if(pData->thread == NULL) rlm@0: hr = E_FAIL; rlm@0: } rlm@0: rlm@0: if(FAILED(hr)) rlm@0: { rlm@0: if(pData->DSnotify != NULL) rlm@0: IDirectSoundNotify_Release(pData->DSnotify); rlm@0: pData->DSnotify = NULL; rlm@0: if(pData->DSsbuffer != NULL) rlm@0: IDirectSoundBuffer_Release(pData->DSsbuffer); rlm@0: pData->DSsbuffer = NULL; rlm@0: if(pData->DSpbuffer != NULL) rlm@0: IDirectSoundBuffer_Release(pData->DSpbuffer); rlm@0: pData->DSpbuffer = NULL; rlm@0: return ALC_FALSE; rlm@0: } rlm@0: rlm@0: return ALC_TRUE; rlm@0: } rlm@0: rlm@0: static void DSoundStopPlayback(ALCdevice *device) rlm@0: { rlm@0: DSoundData *pData = device->ExtraData; rlm@0: rlm@0: if(!pData->thread) rlm@0: return; rlm@0: rlm@0: pData->killNow = 1; rlm@0: StopThread(pData->thread); rlm@0: pData->thread = NULL; rlm@0: rlm@0: pData->killNow = 0; rlm@0: rlm@0: IDirectSoundNotify_Release(pData->DSnotify); rlm@0: pData->DSnotify = NULL; rlm@0: IDirectSoundBuffer_Release(pData->DSsbuffer); rlm@0: pData->DSsbuffer = NULL; rlm@0: if(pData->DSpbuffer != NULL) rlm@0: IDirectSoundBuffer_Release(pData->DSpbuffer); rlm@0: pData->DSpbuffer = NULL; rlm@0: } rlm@0: rlm@0: rlm@0: static const BackendFuncs DSoundFuncs = { rlm@0: DSoundOpenPlayback, rlm@0: DSoundClosePlayback, rlm@0: DSoundResetPlayback, rlm@0: DSoundStopPlayback, rlm@0: NULL, rlm@0: NULL, rlm@0: NULL, rlm@0: NULL, rlm@0: NULL, rlm@0: NULL rlm@0: }; rlm@0: rlm@0: rlm@0: ALCboolean alcDSoundInit(BackendFuncs *FuncList) rlm@0: { rlm@0: if(!DSoundLoad()) rlm@0: return ALC_FALSE; rlm@0: *FuncList = DSoundFuncs; rlm@0: return ALC_TRUE; rlm@0: } rlm@0: rlm@0: void alcDSoundDeinit(void) rlm@0: { rlm@0: ALuint i; rlm@0: rlm@0: for(i = 0;i < NumDevices;++i) rlm@0: free(DeviceList[i].name); rlm@0: free(DeviceList); rlm@0: DeviceList = NULL; rlm@0: NumDevices = 0; rlm@0: rlm@0: if(ds_handle) rlm@0: FreeLibrary(ds_handle); rlm@0: ds_handle = NULL; rlm@0: } rlm@0: rlm@0: void alcDSoundProbe(enum DevProbe type) rlm@0: { rlm@0: HRESULT hr; rlm@0: ALuint i; rlm@0: rlm@0: switch(type) rlm@0: { rlm@0: case DEVICE_PROBE: rlm@0: AppendDeviceList(dsDevice); rlm@0: break; rlm@0: rlm@0: case ALL_DEVICE_PROBE: rlm@0: for(i = 0;i < NumDevices;++i) rlm@0: free(DeviceList[i].name); rlm@0: free(DeviceList); rlm@0: DeviceList = NULL; rlm@0: NumDevices = 0; rlm@0: rlm@0: hr = DirectSoundEnumerateA(DSoundEnumDevices, NULL); rlm@0: if(FAILED(hr)) rlm@0: ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr); rlm@0: else rlm@0: { rlm@0: for(i = 0;i < NumDevices;i++) rlm@0: AppendAllDeviceList(DeviceList[i].name); rlm@0: } rlm@0: break; rlm@0: rlm@0: case CAPTURE_DEVICE_PROBE: rlm@0: break; rlm@0: } rlm@0: }