~ubuntu-branches/ubuntu/utopic/openal-soft/utopic

« back to all changes in this revision

Viewing changes to Alc/backends/dsound.c

  • Committer: Package Import Robot
  • Author(s): Michael Terry
  • Date: 2012-05-22 10:14:53 UTC
  • mfrom: (7.1.9 sid)
  • Revision ID: package-import@ubuntu.com-20120522101453-knsv1m1m8vl5ccfp
Tags: 1:1.14-3ubuntu1
* Merge from Debian testing.  Remaining changes:
  - Add a symbols file for libopenal1
* debian/libopenal1.symbols:
  - Update for 1.14

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * OpenAL cross platform audio library
 
3
 * Copyright (C) 1999-2007 by authors.
 
4
 * This library is free software; you can redistribute it and/or
 
5
 *  modify it under the terms of the GNU Library General Public
 
6
 *  License as published by the Free Software Foundation; either
 
7
 *  version 2 of the License, or (at your option) any later version.
 
8
 *
 
9
 * This library is distributed in the hope that it will be useful,
 
10
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
 *  Library General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU Library General Public
 
15
 *  License along with this library; if not, write to the
 
16
 *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
17
 *  Boston, MA  02111-1307, USA.
 
18
 * Or go to http://www.gnu.org/copyleft/lgpl.html
 
19
 */
 
20
 
 
21
#include "config.h"
 
22
 
 
23
#include <stdlib.h>
 
24
#include <stdio.h>
 
25
#include <memory.h>
 
26
 
 
27
#include <dsound.h>
 
28
#include <cguid.h>
 
29
#include <mmreg.h>
 
30
#ifndef _WAVEFORMATEXTENSIBLE_
 
31
#include <ks.h>
 
32
#include <ksmedia.h>
 
33
#endif
 
34
 
 
35
#include "alMain.h"
 
36
#include "AL/al.h"
 
37
#include "AL/alc.h"
 
38
 
 
39
#ifndef DSSPEAKER_5POINT1
 
40
#define DSSPEAKER_5POINT1       6
 
41
#endif
 
42
#ifndef DSSPEAKER_7POINT1
 
43
#define DSSPEAKER_7POINT1       7
 
44
#endif
 
45
 
 
46
DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
 
47
DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
 
48
 
 
49
 
 
50
static void *ds_handle;
 
51
static HRESULT (WINAPI *pDirectSoundCreate)(LPCGUID pcGuidDevice, IDirectSound **ppDS, IUnknown *pUnkOuter);
 
52
static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA pDSEnumCallback, void *pContext);
 
53
static HRESULT (WINAPI *pDirectSoundCaptureCreate)(LPCGUID pcGuidDevice, IDirectSoundCapture **ppDSC, IUnknown *pUnkOuter);
 
54
static HRESULT (WINAPI *pDirectSoundCaptureEnumerateA)(LPDSENUMCALLBACKA pDSEnumCallback, void *pContext);
 
55
 
 
56
#define DirectSoundCreate            pDirectSoundCreate
 
57
#define DirectSoundEnumerateA        pDirectSoundEnumerateA
 
58
#define DirectSoundCaptureCreate     pDirectSoundCaptureCreate
 
59
#define DirectSoundCaptureEnumerateA pDirectSoundCaptureEnumerateA
 
60
 
 
61
 
 
62
typedef struct {
 
63
    // DirectSound Playback Device
 
64
    IDirectSound       *lpDS;
 
65
    IDirectSoundBuffer *DSpbuffer;
 
66
    IDirectSoundBuffer *DSsbuffer;
 
67
    IDirectSoundNotify *DSnotify;
 
68
    HANDLE             hNotifyEvent;
 
69
 
 
70
    volatile int killNow;
 
71
    ALvoid *thread;
 
72
} DSoundPlaybackData;
 
73
 
 
74
typedef struct {
 
75
    // DirectSound Capture Device
 
76
    IDirectSoundCapture *lpDSC;
 
77
    IDirectSoundCaptureBuffer *DSCbuffer;
 
78
    DWORD dwBufferBytes;
 
79
    DWORD dwCursor;
 
80
    RingBuffer *pRing;
 
81
} DSoundCaptureData;
 
82
 
 
83
 
 
84
typedef struct {
 
85
    ALCchar *name;
 
86
    GUID guid;
 
87
} DevMap;
 
88
 
 
89
static DevMap *PlaybackDeviceList;
 
90
static ALuint NumPlaybackDevices;
 
91
static DevMap *CaptureDeviceList;
 
92
static ALuint NumCaptureDevices;
 
93
 
 
94
#define MAX_UPDATES 128
 
95
 
 
96
static ALCboolean DSoundLoad(void)
 
97
{
 
98
    if(!ds_handle)
 
99
    {
 
100
        ds_handle = LoadLib("dsound.dll");
 
101
        if(ds_handle == NULL)
 
102
        {
 
103
            ERR("Failed to load dsound.dll\n");
 
104
            return ALC_FALSE;
 
105
        }
 
106
 
 
107
#define LOAD_FUNC(f) do {                                                     \
 
108
    p##f = GetSymbol(ds_handle, #f);                                          \
 
109
    if(p##f == NULL) {                                                        \
 
110
        CloseLib(ds_handle);                                                  \
 
111
        ds_handle = NULL;                                                     \
 
112
        return ALC_FALSE;                                                     \
 
113
    }                                                                         \
 
114
} while(0)
 
115
        LOAD_FUNC(DirectSoundCreate);
 
116
        LOAD_FUNC(DirectSoundEnumerateA);
 
117
        LOAD_FUNC(DirectSoundCaptureCreate);
 
118
        LOAD_FUNC(DirectSoundCaptureEnumerateA);
 
119
#undef LOAD_FUNC
 
120
    }
 
121
    return ALC_TRUE;
 
122
}
 
123
 
 
124
 
 
125
static BOOL CALLBACK DSoundEnumPlaybackDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data)
 
126
{
 
127
    LPOLESTR guidstr = NULL;
 
128
    char str[1024];
 
129
    HRESULT hr;
 
130
    void *temp;
 
131
    int count;
 
132
    ALuint i;
 
133
 
 
134
    (void)data;
 
135
    (void)drvname;
 
136
 
 
137
    if(!guid)
 
138
        return TRUE;
 
139
 
 
140
    count = 0;
 
141
    do {
 
142
        if(count == 0)
 
143
            snprintf(str, sizeof(str), "%s", desc);
 
144
        else
 
145
            snprintf(str, sizeof(str), "%s #%d", desc, count+1);
 
146
        count++;
 
147
 
 
148
        for(i = 0;i < NumPlaybackDevices;i++)
 
149
        {
 
150
            if(strcmp(str, PlaybackDeviceList[i].name) == 0)
 
151
                break;
 
152
        }
 
153
    } while(i != NumPlaybackDevices);
 
154
 
 
155
    hr = StringFromCLSID(guid, &guidstr);
 
156
    if(SUCCEEDED(hr))
 
157
    {
 
158
        TRACE("Got device \"%s\", GUID \"%ls\"\n", str, guidstr);
 
159
        CoTaskMemFree(guidstr);
 
160
    }
 
161
 
 
162
    temp = realloc(PlaybackDeviceList, sizeof(DevMap) * (NumPlaybackDevices+1));
 
163
    if(temp)
 
164
    {
 
165
        PlaybackDeviceList = temp;
 
166
        PlaybackDeviceList[NumPlaybackDevices].name = strdup(str);
 
167
        PlaybackDeviceList[NumPlaybackDevices].guid = *guid;
 
168
        NumPlaybackDevices++;
 
169
    }
 
170
 
 
171
    return TRUE;
 
172
}
 
173
 
 
174
 
 
175
static BOOL CALLBACK DSoundEnumCaptureDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data)
 
176
{
 
177
    LPOLESTR guidstr = NULL;
 
178
    char str[1024];
 
179
    HRESULT hr;
 
180
    void *temp;
 
181
    int count;
 
182
    ALuint i;
 
183
 
 
184
    (void)data;
 
185
    (void)drvname;
 
186
 
 
187
    if(!guid)
 
188
        return TRUE;
 
189
 
 
190
    count = 0;
 
191
    do {
 
192
        if(count == 0)
 
193
            snprintf(str, sizeof(str), "%s", desc);
 
194
        else
 
195
            snprintf(str, sizeof(str), "%s #%d", desc, count+1);
 
196
        count++;
 
197
 
 
198
        for(i = 0;i < NumCaptureDevices;i++)
 
199
        {
 
200
            if(strcmp(str, CaptureDeviceList[i].name) == 0)
 
201
                break;
 
202
        }
 
203
    } while(i != NumCaptureDevices);
 
204
 
 
205
    hr = StringFromCLSID(guid, &guidstr);
 
206
    if(SUCCEEDED(hr))
 
207
    {
 
208
        TRACE("Got device \"%s\", GUID \"%ls\"\n", str, guidstr);
 
209
        CoTaskMemFree(guidstr);
 
210
    }
 
211
 
 
212
    temp = realloc(CaptureDeviceList, sizeof(DevMap) * (NumCaptureDevices+1));
 
213
    if(temp)
 
214
    {
 
215
        CaptureDeviceList = temp;
 
216
        CaptureDeviceList[NumCaptureDevices].name = strdup(str);
 
217
        CaptureDeviceList[NumCaptureDevices].guid = *guid;
 
218
        NumCaptureDevices++;
 
219
    }
 
220
 
 
221
    return TRUE;
 
222
}
 
223
 
 
224
 
 
225
static ALuint DSoundPlaybackProc(ALvoid *ptr)
 
226
{
 
227
    ALCdevice *pDevice = (ALCdevice*)ptr;
 
228
    DSoundPlaybackData *pData = (DSoundPlaybackData*)pDevice->ExtraData;
 
229
    DSBCAPS DSBCaps;
 
230
    DWORD LastCursor = 0;
 
231
    DWORD PlayCursor;
 
232
    VOID *WritePtr1, *WritePtr2;
 
233
    DWORD WriteCnt1,  WriteCnt2;
 
234
    BOOL Playing = FALSE;
 
235
    DWORD FrameSize;
 
236
    DWORD FragSize;
 
237
    DWORD avail;
 
238
    HRESULT err;
 
239
 
 
240
    SetRTPriority();
 
241
 
 
242
    memset(&DSBCaps, 0, sizeof(DSBCaps));
 
243
    DSBCaps.dwSize = sizeof(DSBCaps);
 
244
    err = IDirectSoundBuffer_GetCaps(pData->DSsbuffer, &DSBCaps);
 
245
    if(FAILED(err))
 
246
    {
 
247
        ERR("Failed to get buffer caps: 0x%lx\n", err);
 
248
        aluHandleDisconnect(pDevice);
 
249
        return 1;
 
250
    }
 
251
 
 
252
    FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
 
253
    FragSize = pDevice->UpdateSize * FrameSize;
 
254
 
 
255
    IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &LastCursor, NULL);
 
256
    while(!pData->killNow)
 
257
    {
 
258
        // Get current play cursor
 
259
        IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &PlayCursor, NULL);
 
260
        avail = (PlayCursor-LastCursor+DSBCaps.dwBufferBytes) % DSBCaps.dwBufferBytes;
 
261
 
 
262
        if(avail < FragSize)
 
263
        {
 
264
            if(!Playing)
 
265
            {
 
266
                err = IDirectSoundBuffer_Play(pData->DSsbuffer, 0, 0, DSBPLAY_LOOPING);
 
267
                if(FAILED(err))
 
268
                {
 
269
                    ERR("Failed to play buffer: 0x%lx\n", err);
 
270
                    aluHandleDisconnect(pDevice);
 
271
                    return 1;
 
272
                }
 
273
                Playing = TRUE;
 
274
            }
 
275
 
 
276
            avail = WaitForSingleObjectEx(pData->hNotifyEvent, 2000, FALSE);
 
277
            if(avail != WAIT_OBJECT_0)
 
278
                ERR("WaitForSingleObjectEx error: 0x%lx\n", avail);
 
279
            continue;
 
280
        }
 
281
        avail -= avail%FragSize;
 
282
 
 
283
        // Lock output buffer
 
284
        WriteCnt1 = 0;
 
285
        WriteCnt2 = 0;
 
286
        err = IDirectSoundBuffer_Lock(pData->DSsbuffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
 
287
 
 
288
        // If the buffer is lost, restore it and lock
 
289
        if(err == DSERR_BUFFERLOST)
 
290
        {
 
291
            WARN("Buffer lost, restoring...\n");
 
292
            err = IDirectSoundBuffer_Restore(pData->DSsbuffer);
 
293
            if(SUCCEEDED(err))
 
294
            {
 
295
                Playing = FALSE;
 
296
                LastCursor = 0;
 
297
                err = IDirectSoundBuffer_Lock(pData->DSsbuffer, 0, DSBCaps.dwBufferBytes, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
 
298
            }
 
299
        }
 
300
 
 
301
        // Successfully locked the output buffer
 
302
        if(SUCCEEDED(err))
 
303
        {
 
304
            // If we have an active context, mix data directly into output buffer otherwise fill with silence
 
305
            aluMixData(pDevice, WritePtr1, WriteCnt1/FrameSize);
 
306
            aluMixData(pDevice, WritePtr2, WriteCnt2/FrameSize);
 
307
 
 
308
            // Unlock output buffer only when successfully locked
 
309
            IDirectSoundBuffer_Unlock(pData->DSsbuffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2);
 
310
        }
 
311
        else
 
312
        {
 
313
            ERR("Buffer lock error: %#lx\n", err);
 
314
            aluHandleDisconnect(pDevice);
 
315
            return 1;
 
316
        }
 
317
 
 
318
        // Update old write cursor location
 
319
        LastCursor += WriteCnt1+WriteCnt2;
 
320
        LastCursor %= DSBCaps.dwBufferBytes;
 
321
    }
 
322
 
 
323
    return 0;
 
324
}
 
325
 
 
326
static ALCenum DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceName)
 
327
{
 
328
    DSoundPlaybackData *pData = NULL;
 
329
    LPGUID guid = NULL;
 
330
    HRESULT hr;
 
331
 
 
332
    if(!PlaybackDeviceList)
 
333
    {
 
334
        hr = DirectSoundEnumerateA(DSoundEnumPlaybackDevices, NULL);
 
335
        if(FAILED(hr))
 
336
            ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
 
337
    }
 
338
 
 
339
    if(!deviceName && NumPlaybackDevices > 0)
 
340
    {
 
341
        deviceName = PlaybackDeviceList[0].name;
 
342
        guid = &PlaybackDeviceList[0].guid;
 
343
    }
 
344
    else
 
345
    {
 
346
        ALuint i;
 
347
 
 
348
        for(i = 0;i < NumPlaybackDevices;i++)
 
349
        {
 
350
            if(strcmp(deviceName, PlaybackDeviceList[i].name) == 0)
 
351
            {
 
352
                guid = &PlaybackDeviceList[i].guid;
 
353
                break;
 
354
            }
 
355
        }
 
356
        if(i == NumPlaybackDevices)
 
357
            return ALC_INVALID_VALUE;
 
358
    }
 
359
 
 
360
    //Initialise requested device
 
361
    pData = calloc(1, sizeof(DSoundPlaybackData));
 
362
    if(!pData)
 
363
        return ALC_OUT_OF_MEMORY;
 
364
 
 
365
    hr = DS_OK;
 
366
    pData->hNotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
 
367
    if(pData->hNotifyEvent == NULL)
 
368
        hr = E_FAIL;
 
369
 
 
370
    //DirectSound Init code
 
371
    if(SUCCEEDED(hr))
 
372
        hr = DirectSoundCreate(guid, &pData->lpDS, NULL);
 
373
    if(SUCCEEDED(hr))
 
374
        hr = IDirectSound_SetCooperativeLevel(pData->lpDS, GetForegroundWindow(), DSSCL_PRIORITY);
 
375
    if(FAILED(hr))
 
376
    {
 
377
        if(pData->lpDS)
 
378
            IDirectSound_Release(pData->lpDS);
 
379
        if(pData->hNotifyEvent)
 
380
            CloseHandle(pData->hNotifyEvent);
 
381
        free(pData);
 
382
        ERR("Device init failed: 0x%08lx\n", hr);
 
383
        return ALC_INVALID_VALUE;
 
384
    }
 
385
 
 
386
    device->szDeviceName = strdup(deviceName);
 
387
    device->ExtraData = pData;
 
388
    return ALC_NO_ERROR;
 
389
}
 
390
 
 
391
static void DSoundClosePlayback(ALCdevice *device)
 
392
{
 
393
    DSoundPlaybackData *pData = device->ExtraData;
 
394
 
 
395
    if(pData->DSnotify)
 
396
        IDirectSoundNotify_Release(pData->DSnotify);
 
397
    pData->DSnotify = NULL;
 
398
    if(pData->DSsbuffer)
 
399
        IDirectSoundBuffer_Release(pData->DSsbuffer);
 
400
    pData->DSsbuffer = NULL;
 
401
    if(pData->DSpbuffer != NULL)
 
402
        IDirectSoundBuffer_Release(pData->DSpbuffer);
 
403
    pData->DSpbuffer = NULL;
 
404
 
 
405
    IDirectSound_Release(pData->lpDS);
 
406
    CloseHandle(pData->hNotifyEvent);
 
407
    free(pData);
 
408
    device->ExtraData = NULL;
 
409
}
 
410
 
 
411
static ALCboolean DSoundResetPlayback(ALCdevice *device)
 
412
{
 
413
    DSoundPlaybackData *pData = (DSoundPlaybackData*)device->ExtraData;
 
414
    DSBUFFERDESC DSBDescription;
 
415
    WAVEFORMATEXTENSIBLE OutputType;
 
416
    DWORD speakers;
 
417
    HRESULT hr;
 
418
 
 
419
    memset(&OutputType, 0, sizeof(OutputType));
 
420
 
 
421
    if(pData->DSnotify)
 
422
        IDirectSoundNotify_Release(pData->DSnotify);
 
423
    pData->DSnotify = NULL;
 
424
    if(pData->DSsbuffer)
 
425
        IDirectSoundBuffer_Release(pData->DSsbuffer);
 
426
    pData->DSsbuffer = NULL;
 
427
    if(pData->DSpbuffer != NULL)
 
428
        IDirectSoundBuffer_Release(pData->DSpbuffer);
 
429
    pData->DSpbuffer = NULL;
 
430
 
 
431
    switch(device->FmtType)
 
432
    {
 
433
        case DevFmtByte:
 
434
            device->FmtType = DevFmtUByte;
 
435
            break;
 
436
        case DevFmtUShort:
 
437
            device->FmtType = DevFmtShort;
 
438
            break;
 
439
        case DevFmtUInt:
 
440
            device->FmtType = DevFmtInt;
 
441
            break;
 
442
        case DevFmtUByte:
 
443
        case DevFmtShort:
 
444
        case DevFmtInt:
 
445
        case DevFmtFloat:
 
446
            break;
 
447
    }
 
448
 
 
449
    hr = IDirectSound_GetSpeakerConfig(pData->lpDS, &speakers);
 
450
    if(SUCCEEDED(hr))
 
451
    {
 
452
        if(!(device->Flags&DEVICE_CHANNELS_REQUEST))
 
453
        {
 
454
            speakers = DSSPEAKER_CONFIG(speakers);
 
455
            if(speakers == DSSPEAKER_MONO)
 
456
                device->FmtChans = DevFmtMono;
 
457
            else if(speakers == DSSPEAKER_STEREO || speakers == DSSPEAKER_HEADPHONE)
 
458
                device->FmtChans = DevFmtStereo;
 
459
            else if(speakers == DSSPEAKER_QUAD)
 
460
                device->FmtChans = DevFmtQuad;
 
461
            else if(speakers == DSSPEAKER_5POINT1)
 
462
                device->FmtChans = DevFmtX51;
 
463
            else if(speakers == DSSPEAKER_7POINT1)
 
464
                device->FmtChans = DevFmtX71;
 
465
            else
 
466
                ERR("Unknown system speaker config: 0x%lx\n", speakers);
 
467
        }
 
468
 
 
469
        switch(device->FmtChans)
 
470
        {
 
471
            case DevFmtMono:
 
472
                OutputType.dwChannelMask = SPEAKER_FRONT_CENTER;
 
473
                break;
 
474
            case DevFmtStereo:
 
475
                OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
 
476
                                           SPEAKER_FRONT_RIGHT;
 
477
                break;
 
478
            case DevFmtQuad:
 
479
                OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
 
480
                                           SPEAKER_FRONT_RIGHT |
 
481
                                           SPEAKER_BACK_LEFT |
 
482
                                           SPEAKER_BACK_RIGHT;
 
483
                break;
 
484
            case DevFmtX51:
 
485
                OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
 
486
                                           SPEAKER_FRONT_RIGHT |
 
487
                                           SPEAKER_FRONT_CENTER |
 
488
                                           SPEAKER_LOW_FREQUENCY |
 
489
                                           SPEAKER_BACK_LEFT |
 
490
                                           SPEAKER_BACK_RIGHT;
 
491
                break;
 
492
            case DevFmtX51Side:
 
493
                OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
 
494
                                           SPEAKER_FRONT_RIGHT |
 
495
                                           SPEAKER_FRONT_CENTER |
 
496
                                           SPEAKER_LOW_FREQUENCY |
 
497
                                           SPEAKER_SIDE_LEFT |
 
498
                                           SPEAKER_SIDE_RIGHT;
 
499
                break;
 
500
            case DevFmtX61:
 
501
                OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
 
502
                                           SPEAKER_FRONT_RIGHT |
 
503
                                           SPEAKER_FRONT_CENTER |
 
504
                                           SPEAKER_LOW_FREQUENCY |
 
505
                                           SPEAKER_BACK_CENTER |
 
506
                                           SPEAKER_SIDE_LEFT |
 
507
                                           SPEAKER_SIDE_RIGHT;
 
508
                break;
 
509
            case DevFmtX71:
 
510
                OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
 
511
                                           SPEAKER_FRONT_RIGHT |
 
512
                                           SPEAKER_FRONT_CENTER |
 
513
                                           SPEAKER_LOW_FREQUENCY |
 
514
                                           SPEAKER_BACK_LEFT |
 
515
                                           SPEAKER_BACK_RIGHT |
 
516
                                           SPEAKER_SIDE_LEFT |
 
517
                                           SPEAKER_SIDE_RIGHT;
 
518
                break;
 
519
        }
 
520
 
 
521
retry_open:
 
522
        hr = S_OK;
 
523
        OutputType.Format.wFormatTag = WAVE_FORMAT_PCM;
 
524
        OutputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans);
 
525
        OutputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
 
526
        OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8;
 
527
        OutputType.Format.nSamplesPerSec = device->Frequency;
 
528
        OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec*OutputType.Format.nBlockAlign;
 
529
        OutputType.Format.cbSize = 0;
 
530
    }
 
531
 
 
532
    if(OutputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat)
 
533
    {
 
534
        OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
 
535
        OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
 
536
        OutputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
 
537
        if(device->FmtType == DevFmtFloat)
 
538
            OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
 
539
        else
 
540
            OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
 
541
 
 
542
        if(pData->DSpbuffer)
 
543
            IDirectSoundBuffer_Release(pData->DSpbuffer);
 
544
        pData->DSpbuffer = NULL;
 
545
    }
 
546
    else
 
547
    {
 
548
        if(SUCCEEDED(hr))
 
549
        {
 
550
            memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
 
551
            DSBDescription.dwSize=sizeof(DSBUFFERDESC);
 
552
            DSBDescription.dwFlags=DSBCAPS_PRIMARYBUFFER;
 
553
            hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSpbuffer, NULL);
 
554
        }
 
555
        if(SUCCEEDED(hr))
 
556
            hr = IDirectSoundBuffer_SetFormat(pData->DSpbuffer,&OutputType.Format);
 
557
    }
 
558
 
 
559
    if(SUCCEEDED(hr))
 
560
    {
 
561
        if(device->NumUpdates > MAX_UPDATES)
 
562
        {
 
563
            device->UpdateSize = (device->UpdateSize*device->NumUpdates +
 
564
                                  MAX_UPDATES-1) / MAX_UPDATES;
 
565
            device->NumUpdates = MAX_UPDATES;
 
566
        }
 
567
 
 
568
        memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
 
569
        DSBDescription.dwSize=sizeof(DSBUFFERDESC);
 
570
        DSBDescription.dwFlags=DSBCAPS_CTRLPOSITIONNOTIFY|DSBCAPS_GETCURRENTPOSITION2|DSBCAPS_GLOBALFOCUS;
 
571
        DSBDescription.dwBufferBytes=device->UpdateSize * device->NumUpdates *
 
572
                                     OutputType.Format.nBlockAlign;
 
573
        DSBDescription.lpwfxFormat=&OutputType.Format;
 
574
        hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSsbuffer, NULL);
 
575
        if(FAILED(hr) && device->FmtType == DevFmtFloat)
 
576
        {
 
577
            device->FmtType = DevFmtShort;
 
578
            goto retry_open;
 
579
        }
 
580
    }
 
581
 
 
582
    if(SUCCEEDED(hr))
 
583
    {
 
584
        hr = IDirectSoundBuffer_QueryInterface(pData->DSsbuffer, &IID_IDirectSoundNotify, (LPVOID *)&pData->DSnotify);
 
585
        if(SUCCEEDED(hr))
 
586
        {
 
587
            DSBPOSITIONNOTIFY notifies[MAX_UPDATES];
 
588
            ALuint i;
 
589
 
 
590
            for(i = 0;i < device->NumUpdates;++i)
 
591
            {
 
592
                notifies[i].dwOffset = i * device->UpdateSize *
 
593
                                       OutputType.Format.nBlockAlign;
 
594
                notifies[i].hEventNotify = pData->hNotifyEvent;
 
595
            }
 
596
            if(IDirectSoundNotify_SetNotificationPositions(pData->DSnotify, device->NumUpdates, notifies) != DS_OK)
 
597
                hr = E_FAIL;
 
598
        }
 
599
    }
 
600
 
 
601
    if(FAILED(hr))
 
602
    {
 
603
        if(pData->DSnotify != NULL)
 
604
            IDirectSoundNotify_Release(pData->DSnotify);
 
605
        pData->DSnotify = NULL;
 
606
        if(pData->DSsbuffer != NULL)
 
607
            IDirectSoundBuffer_Release(pData->DSsbuffer);
 
608
        pData->DSsbuffer = NULL;
 
609
        if(pData->DSpbuffer != NULL)
 
610
            IDirectSoundBuffer_Release(pData->DSpbuffer);
 
611
        pData->DSpbuffer = NULL;
 
612
        return ALC_FALSE;
 
613
    }
 
614
 
 
615
    ResetEvent(pData->hNotifyEvent);
 
616
    SetDefaultWFXChannelOrder(device);
 
617
 
 
618
    return ALC_TRUE;
 
619
}
 
620
 
 
621
static ALCboolean DSoundStartPlayback(ALCdevice *device)
 
622
{
 
623
    DSoundPlaybackData *pData = (DSoundPlaybackData*)device->ExtraData;
 
624
 
 
625
    pData->thread = StartThread(DSoundPlaybackProc, device);
 
626
    if(pData->thread == NULL)
 
627
        return ALC_FALSE;
 
628
 
 
629
    return ALC_TRUE;
 
630
}
 
631
 
 
632
static void DSoundStopPlayback(ALCdevice *device)
 
633
{
 
634
    DSoundPlaybackData *pData = device->ExtraData;
 
635
 
 
636
    if(!pData->thread)
 
637
        return;
 
638
 
 
639
    pData->killNow = 1;
 
640
    StopThread(pData->thread);
 
641
    pData->thread = NULL;
 
642
 
 
643
    pData->killNow = 0;
 
644
    IDirectSoundBuffer_Stop(pData->DSsbuffer);
 
645
}
 
646
 
 
647
 
 
648
static ALCenum DSoundOpenCapture(ALCdevice *device, const ALCchar *deviceName)
 
649
{
 
650
    DSoundCaptureData *pData = NULL;
 
651
    WAVEFORMATEXTENSIBLE InputType;
 
652
    DSCBUFFERDESC DSCBDescription;
 
653
    LPGUID guid = NULL;
 
654
    HRESULT hr, hrcom;
 
655
    ALuint samples;
 
656
 
 
657
    if(!CaptureDeviceList)
 
658
    {
 
659
        /* Initialize COM to prevent name truncation */
 
660
        hrcom = CoInitialize(NULL);
 
661
        hr = DirectSoundCaptureEnumerateA(DSoundEnumCaptureDevices, NULL);
 
662
        if(FAILED(hr))
 
663
            ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
 
664
        if(SUCCEEDED(hrcom))
 
665
            CoUninitialize();
 
666
    }
 
667
 
 
668
    if(!deviceName && NumCaptureDevices > 0)
 
669
    {
 
670
        deviceName = CaptureDeviceList[0].name;
 
671
        guid = &CaptureDeviceList[0].guid;
 
672
    }
 
673
    else
 
674
    {
 
675
        ALuint i;
 
676
 
 
677
        for(i = 0;i < NumCaptureDevices;i++)
 
678
        {
 
679
            if(strcmp(deviceName, CaptureDeviceList[i].name) == 0)
 
680
            {
 
681
                guid = &CaptureDeviceList[i].guid;
 
682
                break;
 
683
            }
 
684
        }
 
685
        if(i == NumCaptureDevices)
 
686
            return ALC_INVALID_VALUE;
 
687
    }
 
688
 
 
689
    switch(device->FmtType)
 
690
    {
 
691
        case DevFmtByte:
 
692
        case DevFmtUShort:
 
693
        case DevFmtUInt:
 
694
            WARN("%s capture samples not supported\n", DevFmtTypeString(device->FmtType));
 
695
            return ALC_INVALID_ENUM;
 
696
 
 
697
        case DevFmtUByte:
 
698
        case DevFmtShort:
 
699
        case DevFmtInt:
 
700
        case DevFmtFloat:
 
701
            break;
 
702
    }
 
703
 
 
704
    //Initialise requested device
 
705
    pData = calloc(1, sizeof(DSoundCaptureData));
 
706
    if(!pData)
 
707
        return ALC_OUT_OF_MEMORY;
 
708
 
 
709
    hr = DS_OK;
 
710
 
 
711
    //DirectSoundCapture Init code
 
712
    if(SUCCEEDED(hr))
 
713
        hr = DirectSoundCaptureCreate(guid, &pData->lpDSC, NULL);
 
714
    if(SUCCEEDED(hr))
 
715
    {
 
716
        memset(&InputType, 0, sizeof(InputType));
 
717
 
 
718
        switch(device->FmtChans)
 
719
        {
 
720
            case DevFmtMono:
 
721
                InputType.dwChannelMask = SPEAKER_FRONT_CENTER;
 
722
                break;
 
723
            case DevFmtStereo:
 
724
                InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
 
725
                                          SPEAKER_FRONT_RIGHT;
 
726
                break;
 
727
            case DevFmtQuad:
 
728
                InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
 
729
                                          SPEAKER_FRONT_RIGHT |
 
730
                                          SPEAKER_BACK_LEFT |
 
731
                                          SPEAKER_BACK_RIGHT;
 
732
                break;
 
733
            case DevFmtX51:
 
734
                InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
 
735
                                          SPEAKER_FRONT_RIGHT |
 
736
                                          SPEAKER_FRONT_CENTER |
 
737
                                          SPEAKER_LOW_FREQUENCY |
 
738
                                          SPEAKER_BACK_LEFT |
 
739
                                          SPEAKER_BACK_RIGHT;
 
740
                break;
 
741
            case DevFmtX51Side:
 
742
                InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
 
743
                                          SPEAKER_FRONT_RIGHT |
 
744
                                          SPEAKER_FRONT_CENTER |
 
745
                                          SPEAKER_LOW_FREQUENCY |
 
746
                                          SPEAKER_SIDE_LEFT |
 
747
                                          SPEAKER_SIDE_RIGHT;
 
748
                break;
 
749
            case DevFmtX61:
 
750
                InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
 
751
                                          SPEAKER_FRONT_RIGHT |
 
752
                                          SPEAKER_FRONT_CENTER |
 
753
                                          SPEAKER_LOW_FREQUENCY |
 
754
                                          SPEAKER_BACK_CENTER |
 
755
                                          SPEAKER_SIDE_LEFT |
 
756
                                          SPEAKER_SIDE_RIGHT;
 
757
                break;
 
758
            case DevFmtX71:
 
759
                InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
 
760
                                          SPEAKER_FRONT_RIGHT |
 
761
                                          SPEAKER_FRONT_CENTER |
 
762
                                          SPEAKER_LOW_FREQUENCY |
 
763
                                          SPEAKER_BACK_LEFT |
 
764
                                          SPEAKER_BACK_RIGHT |
 
765
                                          SPEAKER_SIDE_LEFT |
 
766
                                          SPEAKER_SIDE_RIGHT;
 
767
                break;
 
768
        }
 
769
 
 
770
        InputType.Format.wFormatTag = WAVE_FORMAT_PCM;
 
771
        InputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans);
 
772
        InputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
 
773
        InputType.Format.nBlockAlign = InputType.Format.nChannels*InputType.Format.wBitsPerSample/8;
 
774
        InputType.Format.nSamplesPerSec = device->Frequency;
 
775
        InputType.Format.nAvgBytesPerSec = InputType.Format.nSamplesPerSec*InputType.Format.nBlockAlign;
 
776
        InputType.Format.cbSize = 0;
 
777
 
 
778
        if(InputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat)
 
779
        {
 
780
            InputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
 
781
            InputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
 
782
            InputType.Samples.wValidBitsPerSample = InputType.Format.wBitsPerSample;
 
783
            if(device->FmtType == DevFmtFloat)
 
784
                InputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
 
785
            else
 
786
                InputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
 
787
        }
 
788
 
 
789
        samples = device->UpdateSize * device->NumUpdates;
 
790
        samples = maxu(samples, 100 * device->Frequency / 1000);
 
791
 
 
792
        memset(&DSCBDescription, 0, sizeof(DSCBUFFERDESC));
 
793
        DSCBDescription.dwSize = sizeof(DSCBUFFERDESC);
 
794
        DSCBDescription.dwFlags = 0;
 
795
        DSCBDescription.dwBufferBytes = samples * InputType.Format.nBlockAlign;
 
796
        DSCBDescription.lpwfxFormat = &InputType.Format;
 
797
 
 
798
        hr = IDirectSoundCapture_CreateCaptureBuffer(pData->lpDSC, &DSCBDescription, &pData->DSCbuffer, NULL);
 
799
    }
 
800
    if(SUCCEEDED(hr))
 
801
    {
 
802
         pData->pRing = CreateRingBuffer(InputType.Format.nBlockAlign, device->UpdateSize * device->NumUpdates);
 
803
         if(pData->pRing == NULL)
 
804
             hr = DSERR_OUTOFMEMORY;
 
805
    }
 
806
 
 
807
    if(FAILED(hr))
 
808
    {
 
809
        ERR("Device init failed: 0x%08lx\n", hr);
 
810
 
 
811
        DestroyRingBuffer(pData->pRing);
 
812
        pData->pRing = NULL;
 
813
        if(pData->DSCbuffer != NULL)
 
814
            IDirectSoundCaptureBuffer_Release(pData->DSCbuffer);
 
815
        pData->DSCbuffer = NULL;
 
816
        if(pData->lpDSC)
 
817
            IDirectSoundCapture_Release(pData->lpDSC);
 
818
        pData->lpDSC = NULL;
 
819
 
 
820
        free(pData);
 
821
        return ALC_INVALID_VALUE;
 
822
    }
 
823
 
 
824
    pData->dwBufferBytes = DSCBDescription.dwBufferBytes;
 
825
    SetDefaultWFXChannelOrder(device);
 
826
 
 
827
    device->szDeviceName = strdup(deviceName);
 
828
    device->ExtraData = pData;
 
829
 
 
830
    return ALC_NO_ERROR;
 
831
}
 
832
 
 
833
static void DSoundCloseCapture(ALCdevice *device)
 
834
{
 
835
    DSoundCaptureData *pData = device->ExtraData;
 
836
 
 
837
    DestroyRingBuffer(pData->pRing);
 
838
    pData->pRing = NULL;
 
839
 
 
840
    if(pData->DSCbuffer != NULL)
 
841
    {
 
842
        IDirectSoundCaptureBuffer_Stop(pData->DSCbuffer);
 
843
        IDirectSoundCaptureBuffer_Release(pData->DSCbuffer);
 
844
        pData->DSCbuffer = NULL;
 
845
    }
 
846
 
 
847
    IDirectSoundCapture_Release(pData->lpDSC);
 
848
    pData->lpDSC = NULL;
 
849
 
 
850
    free(pData);
 
851
    device->ExtraData = NULL;
 
852
}
 
853
 
 
854
static void DSoundStartCapture(ALCdevice *device)
 
855
{
 
856
    DSoundCaptureData *pData = device->ExtraData;
 
857
    HRESULT hr;
 
858
 
 
859
    hr = IDirectSoundCaptureBuffer_Start(pData->DSCbuffer, DSCBSTART_LOOPING);
 
860
    if(FAILED(hr))
 
861
    {
 
862
        ERR("start failed: 0x%08lx\n", hr);
 
863
        aluHandleDisconnect(device);
 
864
    }
 
865
}
 
866
 
 
867
static void DSoundStopCapture(ALCdevice *device)
 
868
{
 
869
    DSoundCaptureData *pData = device->ExtraData;
 
870
    HRESULT hr;
 
871
 
 
872
    hr = IDirectSoundCaptureBuffer_Stop(pData->DSCbuffer);
 
873
    if(FAILED(hr))
 
874
    {
 
875
        ERR("stop failed: 0x%08lx\n", hr);
 
876
        aluHandleDisconnect(device);
 
877
    }
 
878
}
 
879
 
 
880
static ALCenum DSoundCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
 
881
{
 
882
    DSoundCaptureData *pData = pDevice->ExtraData;
 
883
    ReadRingBuffer(pData->pRing, pBuffer, lSamples);
 
884
    return ALC_NO_ERROR;
 
885
}
 
886
 
 
887
static ALCuint DSoundAvailableSamples(ALCdevice *pDevice)
 
888
{
 
889
    DSoundCaptureData *pData = pDevice->ExtraData;
 
890
    DWORD dwRead, dwCursor, dwBufferBytes, dwNumBytes;
 
891
    void *pvAudio1, *pvAudio2;
 
892
    DWORD dwAudioBytes1, dwAudioBytes2;
 
893
    DWORD FrameSize;
 
894
    HRESULT hr;
 
895
 
 
896
    if(!pDevice->Connected)
 
897
        goto done;
 
898
 
 
899
    FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
 
900
    dwBufferBytes = pData->dwBufferBytes;
 
901
    dwCursor = pData->dwCursor;
 
902
 
 
903
    hr = IDirectSoundCaptureBuffer_GetCurrentPosition(pData->DSCbuffer, NULL, &dwRead);
 
904
    if(SUCCEEDED(hr))
 
905
    {
 
906
        dwNumBytes = (dwBufferBytes + dwRead - dwCursor) % dwBufferBytes;
 
907
        if(dwNumBytes == 0)
 
908
            goto done;
 
909
        hr = IDirectSoundCaptureBuffer_Lock(pData->DSCbuffer,
 
910
                                            dwCursor, dwNumBytes,
 
911
                                            &pvAudio1, &dwAudioBytes1,
 
912
                                            &pvAudio2, &dwAudioBytes2, 0);
 
913
    }
 
914
    if(SUCCEEDED(hr))
 
915
    {
 
916
        WriteRingBuffer(pData->pRing, pvAudio1, dwAudioBytes1/FrameSize);
 
917
        if(pvAudio2 != NULL)
 
918
            WriteRingBuffer(pData->pRing, pvAudio2, dwAudioBytes2/FrameSize);
 
919
        hr = IDirectSoundCaptureBuffer_Unlock(pData->DSCbuffer,
 
920
                                              pvAudio1, dwAudioBytes1,
 
921
                                              pvAudio2, dwAudioBytes2);
 
922
        pData->dwCursor = (dwCursor + dwAudioBytes1 + dwAudioBytes2) % dwBufferBytes;
 
923
    }
 
924
 
 
925
    if(FAILED(hr))
 
926
    {
 
927
        ERR("update failed: 0x%08lx\n", hr);
 
928
        aluHandleDisconnect(pDevice);
 
929
    }
 
930
 
 
931
done:
 
932
    return RingBufferSize(pData->pRing);
 
933
}
 
934
 
 
935
static const BackendFuncs DSoundFuncs = {
 
936
    DSoundOpenPlayback,
 
937
    DSoundClosePlayback,
 
938
    DSoundResetPlayback,
 
939
    DSoundStartPlayback,
 
940
    DSoundStopPlayback,
 
941
    DSoundOpenCapture,
 
942
    DSoundCloseCapture,
 
943
    DSoundStartCapture,
 
944
    DSoundStopCapture,
 
945
    DSoundCaptureSamples,
 
946
    DSoundAvailableSamples
 
947
};
 
948
 
 
949
 
 
950
ALCboolean alcDSoundInit(BackendFuncs *FuncList)
 
951
{
 
952
    if(!DSoundLoad())
 
953
        return ALC_FALSE;
 
954
    *FuncList = DSoundFuncs;
 
955
    return ALC_TRUE;
 
956
}
 
957
 
 
958
void alcDSoundDeinit(void)
 
959
{
 
960
    ALuint i;
 
961
 
 
962
    for(i = 0;i < NumPlaybackDevices;++i)
 
963
        free(PlaybackDeviceList[i].name);
 
964
    free(PlaybackDeviceList);
 
965
    PlaybackDeviceList = NULL;
 
966
    NumPlaybackDevices = 0;
 
967
 
 
968
    for(i = 0;i < NumCaptureDevices;++i)
 
969
        free(CaptureDeviceList[i].name);
 
970
    free(CaptureDeviceList);
 
971
    CaptureDeviceList = NULL;
 
972
    NumCaptureDevices = 0;
 
973
 
 
974
    if(ds_handle)
 
975
        CloseLib(ds_handle);
 
976
    ds_handle = NULL;
 
977
}
 
978
 
 
979
void alcDSoundProbe(enum DevProbe type)
 
980
{
 
981
    HRESULT hr, hrcom;
 
982
    ALuint i;
 
983
 
 
984
    switch(type)
 
985
    {
 
986
        case ALL_DEVICE_PROBE:
 
987
            for(i = 0;i < NumPlaybackDevices;++i)
 
988
                free(PlaybackDeviceList[i].name);
 
989
            free(PlaybackDeviceList);
 
990
            PlaybackDeviceList = NULL;
 
991
            NumPlaybackDevices = 0;
 
992
 
 
993
            hr = DirectSoundEnumerateA(DSoundEnumPlaybackDevices, NULL);
 
994
            if(FAILED(hr))
 
995
                ERR("Error enumerating DirectSound playback devices (%#x)!\n", (unsigned int)hr);
 
996
            else
 
997
            {
 
998
                for(i = 0;i < NumPlaybackDevices;i++)
 
999
                    AppendAllDeviceList(PlaybackDeviceList[i].name);
 
1000
            }
 
1001
            break;
 
1002
 
 
1003
        case CAPTURE_DEVICE_PROBE:
 
1004
            for(i = 0;i < NumCaptureDevices;++i)
 
1005
                free(CaptureDeviceList[i].name);
 
1006
            free(CaptureDeviceList);
 
1007
            CaptureDeviceList = NULL;
 
1008
            NumCaptureDevices = 0;
 
1009
 
 
1010
            /* Initialize COM to prevent name truncation */
 
1011
            hrcom = CoInitialize(NULL);
 
1012
            hr = DirectSoundCaptureEnumerateA(DSoundEnumCaptureDevices, NULL);
 
1013
            if(FAILED(hr))
 
1014
                ERR("Error enumerating DirectSound capture devices (%#x)!\n", (unsigned int)hr);
 
1015
            else
 
1016
            {
 
1017
                for(i = 0;i < NumCaptureDevices;i++)
 
1018
                    AppendCaptureDeviceList(CaptureDeviceList[i].name);
 
1019
            }
 
1020
            if(SUCCEEDED(hrcom))
 
1021
                CoUninitialize();
 
1022
            break;
 
1023
    }
 
1024
}