~ubuntu-branches/ubuntu/precise/wine1.3/precise

« back to all changes in this revision

Viewing changes to dlls/winecoreaudio.drv/audio.c

  • Committer: Package Import Robot
  • Author(s): Scott Ritchie
  • Date: 2012-01-17 09:00:34 UTC
  • mfrom: (1.1.2)
  • Revision ID: package-import@ubuntu.com-20120117090034-eyhpp02jawlvrrkc
Tags: 1.3.37-0ubuntu1
* New upstream release
  - Many changes
* Convert to 3.0 source format
* debian/control:
  - Remove pre-multiarch amd64 build depends
  - Remove quilt build depends
  - Recommend proper gecko versions
* debian/rules:
  - Remove manual dh_quilt patch and unpatch
  - No need to uuencode/uudecode anymore with new source format

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Wine Driver for CoreAudio based on Jack Driver
3
 
 *
4
 
 * Copyright 1994 Martin Ayotte
5
 
 * Copyright 1999 Eric Pouech (async playing in waveOut/waveIn)
6
 
 * Copyright 2000 Eric Pouech (loops in waveOut)
7
 
 * Copyright 2002 Chris Morgan (jack version of this file)
8
 
 * Copyright 2005, 2006 Emmanuel Maillard
9
 
 *
10
 
 * This library is free software; you can redistribute it and/or
11
 
 * modify it under the terms of the GNU Lesser General Public
12
 
 * License as published by the Free Software Foundation; either
13
 
 * version 2.1 of the License, or (at your option) any later version.
14
 
 *
15
 
 * This library is distributed in the hope that it will be useful,
16
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18
 
 * Lesser General Public License for more details.
19
 
 *
20
 
 * You should have received a copy of the GNU Lesser General Public
21
 
 * License along with this library; if not, write to the Free Software
22
 
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23
 
 */
24
 
 
25
 
#include "config.h"
26
 
 
27
 
#include <stdlib.h>
28
 
#include <stdarg.h>
29
 
#include <stdio.h>
30
 
#include <string.h>
31
 
#ifdef HAVE_UNISTD_H
32
 
# include <unistd.h>
33
 
#endif
34
 
#include <fcntl.h>
35
 
#include <assert.h>
36
 
 
37
 
#ifdef HAVE_COREAUDIO_COREAUDIO_H
38
 
#include <CoreAudio/CoreAudio.h>
39
 
#include <CoreFoundation/CoreFoundation.h>
40
 
#include <libkern/OSAtomic.h>
41
 
#endif
42
 
 
43
 
#include "windef.h"
44
 
#include "winbase.h"
45
 
#include "winnls.h"
46
 
#include "wingdi.h"
47
 
#include "winerror.h"
48
 
#include "mmddk.h"
49
 
#include "mmreg.h"
50
 
#include "dsound.h"
51
 
#include "dsdriver.h"
52
 
#include "ks.h"
53
 
#include "coreaudio.h"
54
 
#include "wine/unicode.h"
55
 
#include "wine/library.h"
56
 
#include "wine/debug.h"
57
 
#include "wine/list.h"
58
 
 
59
 
#include "initguid.h"
60
 
#include "ksmedia.h"
61
 
 
62
 
WINE_DEFAULT_DEBUG_CHANNEL(wave);
63
 
WINE_DECLARE_DEBUG_CHANNEL(coreaudio);
64
 
 
65
 
/*
66
 
    Due to AudioUnit headers conflict define some needed types.
67
 
*/
68
 
 
69
 
typedef void *AudioUnit;
70
 
 
71
 
/* From AudioUnit/AUComponents.h */
72
 
enum
73
 
{
74
 
    kAudioUnitRenderAction_OutputIsSilence  = (1 << 4),
75
 
        /* provides hint on return from Render(): if set the buffer contains all zeroes */
76
 
};
77
 
typedef UInt32 AudioUnitRenderActionFlags;
78
 
 
79
 
typedef long ComponentResult;
80
 
extern ComponentResult
81
 
AudioUnitRender(                    AudioUnit                       ci,
82
 
                                    AudioUnitRenderActionFlags *    ioActionFlags,
83
 
                                    const AudioTimeStamp *          inTimeStamp,
84
 
                                    UInt32                          inOutputBusNumber,
85
 
                                    UInt32                          inNumberFrames,
86
 
                                    AudioBufferList *               ioData)         AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER;
87
 
 
88
 
/* only allow 10 output devices through this driver, this ought to be adequate */
89
 
#define MAX_WAVEOUTDRV  (1)
90
 
#define MAX_WAVEINDRV   (1)
91
 
 
92
 
/* state diagram for waveOut writing:
93
 
*
94
 
* +---------+-------------+---------------+---------------------------------+
95
 
* |  state  |  function   |     event     |            new state             |
96
 
* +---------+-------------+---------------+---------------------------------+
97
 
* |         | open()       |               | PLAYING                         |
98
 
* | PAUSED  | write()      |               | PAUSED                          |
99
 
* | PLAYING | write()      | HEADER        | PLAYING                         |
100
 
* | (other) | write()      | <error>       |                                 |
101
 
* | (any)   | pause()      | PAUSING       | PAUSED                          |
102
 
* | PAUSED  | restart()    | RESTARTING    | PLAYING                         |
103
 
* | (any)   | reset()      | RESETTING     | PLAYING                         |
104
 
* | (any)   | close()      | CLOSING       | <deallocated>                   |
105
 
* +---------+-------------+---------------+---------------------------------+
106
 
*/
107
 
 
108
 
/* states of the playing device */
109
 
#define WINE_WS_PLAYING   0 /* for waveOut: lpPlayPtr == NULL -> stopped */
110
 
#define WINE_WS_PAUSED    1
111
 
#define WINE_WS_STOPPED   2 /* Not used for waveOut */
112
 
#define WINE_WS_CLOSED    3 /* Not used for waveOut */
113
 
#define WINE_WS_OPENING   4
114
 
#define WINE_WS_CLOSING   5
115
 
 
116
 
typedef struct tagCoreAudio_Device {
117
 
    char                        dev_name[32];
118
 
    char                        mixer_name[32];
119
 
    unsigned                    open_count;
120
 
    char*                       interface_name;
121
 
    
122
 
    WAVEOUTCAPSW                out_caps;
123
 
    WAVEINCAPSW                 in_caps;
124
 
    DWORD                       in_caps_support;
125
 
    int                         sample_rate;
126
 
    int                         stereo;
127
 
    int                         format;
128
 
    unsigned                    audio_fragment;
129
 
    BOOL                        full_duplex;
130
 
    BOOL                        bTriggerSupport;
131
 
    BOOL                        bOutputEnabled;
132
 
    BOOL                        bInputEnabled;
133
 
    DSDRIVERDESC                ds_desc;
134
 
    DSDRIVERCAPS                ds_caps;
135
 
    DSCDRIVERCAPS               dsc_caps;
136
 
    GUID                        ds_guid;
137
 
    GUID                        dsc_guid;
138
 
    
139
 
    AudioDeviceID outputDeviceID;
140
 
    AudioDeviceID inputDeviceID;
141
 
    AudioStreamBasicDescription streamDescription;
142
 
} CoreAudio_Device;
143
 
 
144
 
/* for now use the default device */
145
 
static CoreAudio_Device CoreAudio_DefaultDevice;
146
 
 
147
 
typedef struct {
148
 
    struct list                 entry;
149
 
 
150
 
    volatile int                state;      /* one of the WINE_WS_ manifest constants */
151
 
    WAVEOPENDESC                waveDesc;
152
 
    WORD                        wFlags;
153
 
    PCMWAVEFORMAT               format;
154
 
    DWORD                       woID;
155
 
    AudioUnit                   audioUnit;
156
 
    AudioStreamBasicDescription streamDescription;
157
 
 
158
 
    LPWAVEHDR                   lpQueuePtr;             /* start of queued WAVEHDRs (waiting to be notified) */
159
 
    LPWAVEHDR                   lpPlayPtr;              /* start of not yet fully played buffers */
160
 
    DWORD                       dwPartialOffset;        /* Offset of not yet written bytes in lpPlayPtr */
161
 
 
162
 
    LPWAVEHDR                   lpLoopPtr;              /* pointer of first buffer in loop, if any */
163
 
    DWORD                       dwLoops;                /* private copy of loop counter */
164
 
 
165
 
    DWORD                       dwPlayedTotal;          /* number of bytes actually played since opening */
166
 
 
167
 
    OSSpinLock                  lock;         /* synchronization stuff */
168
 
} WINE_WAVEOUT_INSTANCE;
169
 
 
170
 
typedef struct {
171
 
    CoreAudio_Device            *cadev;
172
 
    WAVEOUTCAPSW                caps;
173
 
    char                        interface_name[32];
174
 
    DWORD                       device_volume;
175
 
 
176
 
    BOOL trace_on;
177
 
    BOOL warn_on;
178
 
    BOOL err_on;
179
 
 
180
 
    struct list                 instances;
181
 
    OSSpinLock                  lock;         /* guards the instances list */
182
 
} WINE_WAVEOUT;
183
 
 
184
 
typedef struct {
185
 
    /* This device's device number */
186
 
    DWORD           wiID;
187
 
 
188
 
    /* Access to the following fields is synchronized across threads. */
189
 
    volatile int    state;
190
 
    LPWAVEHDR       lpQueuePtr;
191
 
    DWORD           dwTotalRecorded;
192
 
 
193
 
    /* Synchronization mechanism to protect above fields */
194
 
    OSSpinLock      lock;
195
 
 
196
 
    /* Capabilities description */
197
 
    WAVEINCAPSW     caps;
198
 
    char            interface_name[32];
199
 
 
200
 
    /* Record the arguments used when opening the device. */
201
 
    WAVEOPENDESC    waveDesc;
202
 
    WORD            wFlags;
203
 
    PCMWAVEFORMAT   format;
204
 
 
205
 
    AudioUnit       audioUnit;
206
 
    AudioBufferList*bufferList;
207
 
    AudioBufferList*bufferListCopy;
208
 
 
209
 
    /* Record state of debug channels at open.  Used to control fprintf's since
210
 
     * we can't use Wine debug channel calls in non-Wine AudioUnit threads. */
211
 
    BOOL            trace_on;
212
 
    BOOL            warn_on;
213
 
    BOOL            err_on;
214
 
 
215
 
/* These fields aren't used. */
216
 
#if 0
217
 
    CoreAudio_Device *cadev;
218
 
 
219
 
    AudioStreamBasicDescription streamDescription;
220
 
#endif
221
 
} WINE_WAVEIN;
222
 
 
223
 
static WINE_WAVEOUT WOutDev   [MAX_WAVEOUTDRV];
224
 
static WINE_WAVEIN  WInDev    [MAX_WAVEINDRV];
225
 
 
226
 
static HANDLE hThread = NULL; /* Track the thread we create so we can clean it up later */
227
 
static CFMessagePortRef Port_SendToMessageThread;
228
 
 
229
 
static void wodHelper_PlayPtrNext(WINE_WAVEOUT_INSTANCE* wwo);
230
 
static void wodHelper_NotifyDoneForList(WINE_WAVEOUT_INSTANCE* wwo, LPWAVEHDR lpWaveHdr);
231
 
static void wodHelper_NotifyCompletions(WINE_WAVEOUT_INSTANCE* wwo, BOOL force);
232
 
static void widHelper_NotifyCompletions(WINE_WAVEIN* wwi);
233
 
 
234
 
extern int AudioUnit_CreateDefaultAudioUnit(void *wwo, AudioUnit *au);
235
 
extern int AudioUnit_CloseAudioUnit(AudioUnit au);
236
 
extern int AudioUnit_InitializeWithStreamDescription(AudioUnit au, AudioStreamBasicDescription *streamFormat);
237
 
 
238
 
extern OSStatus AudioOutputUnitStart(AudioUnit au);
239
 
extern OSStatus AudioOutputUnitStop(AudioUnit au);
240
 
extern OSStatus AudioUnitUninitialize(AudioUnit au);
241
 
 
242
 
extern int AudioUnit_SetVolume(AudioUnit au, float left, float right);
243
 
extern int AudioUnit_GetVolume(AudioUnit au, float *left, float *right);
244
 
 
245
 
extern int AudioUnit_GetInputDeviceSampleRate(void);
246
 
 
247
 
extern int AudioUnit_CreateInputUnit(void* wwi, AudioUnit* out_au,
248
 
        WORD nChannels, DWORD nSamplesPerSec, WORD wBitsPerSample,
249
 
        UInt32* outFrameCount);
250
 
 
251
 
OSStatus CoreAudio_woAudioUnitIOProc(void *inRefCon, 
252
 
                                     AudioUnitRenderActionFlags *ioActionFlags, 
253
 
                                     const AudioTimeStamp *inTimeStamp, 
254
 
                                     UInt32 inBusNumber, 
255
 
                                     UInt32 inNumberFrames, 
256
 
                                     AudioBufferList *ioData);
257
 
OSStatus CoreAudio_wiAudioUnitIOProc(void *inRefCon,
258
 
                                     AudioUnitRenderActionFlags *ioActionFlags,
259
 
                                     const AudioTimeStamp *inTimeStamp,
260
 
                                     UInt32 inBusNumber,
261
 
                                     UInt32 inNumberFrames,
262
 
                                     AudioBufferList *ioData);
263
 
 
264
 
/* These strings used only for tracing */
265
 
 
266
 
static const char * getMessage(UINT msg)
267
 
{
268
 
#define MSG_TO_STR(x) case x: return #x
269
 
    switch(msg) {
270
 
        MSG_TO_STR(DRVM_INIT);
271
 
        MSG_TO_STR(DRVM_EXIT);
272
 
        MSG_TO_STR(DRVM_ENABLE);
273
 
        MSG_TO_STR(DRVM_DISABLE);
274
 
        MSG_TO_STR(WIDM_OPEN);
275
 
        MSG_TO_STR(WIDM_CLOSE);
276
 
        MSG_TO_STR(WIDM_ADDBUFFER);
277
 
        MSG_TO_STR(WIDM_PREPARE);
278
 
        MSG_TO_STR(WIDM_UNPREPARE);
279
 
        MSG_TO_STR(WIDM_GETDEVCAPS);
280
 
        MSG_TO_STR(WIDM_GETNUMDEVS);
281
 
        MSG_TO_STR(WIDM_GETPOS);
282
 
        MSG_TO_STR(WIDM_RESET);
283
 
        MSG_TO_STR(WIDM_START);
284
 
        MSG_TO_STR(WIDM_STOP);
285
 
        MSG_TO_STR(WODM_OPEN);
286
 
        MSG_TO_STR(WODM_CLOSE);
287
 
        MSG_TO_STR(WODM_WRITE);
288
 
        MSG_TO_STR(WODM_PAUSE);
289
 
        MSG_TO_STR(WODM_GETPOS);
290
 
        MSG_TO_STR(WODM_BREAKLOOP);
291
 
        MSG_TO_STR(WODM_PREPARE);
292
 
        MSG_TO_STR(WODM_UNPREPARE);
293
 
        MSG_TO_STR(WODM_GETDEVCAPS);
294
 
        MSG_TO_STR(WODM_GETNUMDEVS);
295
 
        MSG_TO_STR(WODM_GETPITCH);
296
 
        MSG_TO_STR(WODM_SETPITCH);
297
 
        MSG_TO_STR(WODM_GETPLAYBACKRATE);
298
 
        MSG_TO_STR(WODM_SETPLAYBACKRATE);
299
 
        MSG_TO_STR(WODM_GETVOLUME);
300
 
        MSG_TO_STR(WODM_SETVOLUME);
301
 
        MSG_TO_STR(WODM_RESTART);
302
 
        MSG_TO_STR(WODM_RESET);
303
 
        MSG_TO_STR(DRV_QUERYDEVICEINTERFACESIZE);
304
 
        MSG_TO_STR(DRV_QUERYDEVICEINTERFACE);
305
 
        MSG_TO_STR(DRV_QUERYDSOUNDIFACE);
306
 
        MSG_TO_STR(DRV_QUERYDSOUNDDESC);
307
 
    }
308
 
#undef MSG_TO_STR
309
 
    return wine_dbg_sprintf("UNKNOWN(0x%04x)", msg);
310
 
}
311
 
 
312
 
#define kStopLoopMessage 0
313
 
#define kWaveOutNotifyCompletionsMessage 1
314
 
#define kWaveInNotifyCompletionsMessage 2
315
 
 
316
 
/* Mach Message Handling */
317
 
static CFDataRef wodMessageHandler(CFMessagePortRef port_ReceiveInMessageThread, SInt32 msgid, CFDataRef data, void *info)
318
 
{
319
 
    UInt32 *buffer = NULL;
320
 
 
321
 
    switch (msgid)
322
 
    {
323
 
        case kWaveOutNotifyCompletionsMessage:
324
 
            wodHelper_NotifyCompletions(*(WINE_WAVEOUT_INSTANCE**)CFDataGetBytePtr(data), FALSE);
325
 
            break;
326
 
        case kWaveInNotifyCompletionsMessage:
327
 
            buffer = (UInt32 *) CFDataGetBytePtr(data);
328
 
            widHelper_NotifyCompletions(&WInDev[buffer[0]]);
329
 
            break;
330
 
        default:
331
 
            CFRunLoopStop(CFRunLoopGetCurrent());
332
 
            break;
333
 
    }
334
 
    
335
 
    return NULL;
336
 
}
337
 
 
338
 
static DWORD WINAPI messageThread(LPVOID p)
339
 
{
340
 
    CFMessagePortRef port_ReceiveInMessageThread = (CFMessagePortRef) p;
341
 
    CFRunLoopSourceRef source;
342
 
 
343
 
    source = CFMessagePortCreateRunLoopSource(kCFAllocatorDefault, port_ReceiveInMessageThread, 0);
344
 
    CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
345
 
 
346
 
    CFRunLoopRun();
347
 
 
348
 
    CFRunLoopSourceInvalidate(source);
349
 
    CFRelease(source);
350
 
    CFRelease(port_ReceiveInMessageThread);
351
 
 
352
 
    return 0;
353
 
}
354
 
 
355
 
/**************************************************************************
356
 
*                       wodSendNotifyCompletionsMessage                 [internal]
357
 
*   Call from AudioUnit IO thread can't use Wine debug channels.
358
 
*/
359
 
static void wodSendNotifyCompletionsMessage(WINE_WAVEOUT_INSTANCE* wwo)
360
 
{
361
 
    CFDataRef data;
362
 
 
363
 
    if (!Port_SendToMessageThread)
364
 
        return;
365
 
 
366
 
    data = CFDataCreate(kCFAllocatorDefault, (UInt8 *)&wwo, sizeof(wwo));
367
 
    if (!data)
368
 
        return;
369
 
 
370
 
    CFMessagePortSendRequest(Port_SendToMessageThread, kWaveOutNotifyCompletionsMessage, data, 0.0, 0.0, NULL, NULL);
371
 
    CFRelease(data);
372
 
}
373
 
 
374
 
/**************************************************************************
375
 
*                       wodSendNotifyInputCompletionsMessage     [internal]
376
 
*   Call from AudioUnit IO thread can't use Wine debug channels.
377
 
*/
378
 
static void wodSendNotifyInputCompletionsMessage(WINE_WAVEIN* wwi)
379
 
{
380
 
    CFDataRef data;
381
 
    UInt32 buffer;
382
 
 
383
 
    if (!Port_SendToMessageThread)
384
 
        return;
385
 
 
386
 
    buffer = (UInt32) wwi->wiID;
387
 
 
388
 
    data = CFDataCreate(kCFAllocatorDefault, (UInt8 *)&buffer, sizeof(buffer));
389
 
    if (!data)
390
 
        return;
391
 
 
392
 
    CFMessagePortSendRequest(Port_SendToMessageThread, kWaveInNotifyCompletionsMessage, data, 0.0, 0.0, NULL, NULL);
393
 
    CFRelease(data);
394
 
}
395
 
 
396
 
static DWORD bytes_to_mmtime(LPMMTIME lpTime, DWORD position,
397
 
                             PCMWAVEFORMAT* format)
398
 
{
399
 
    TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%u nChannels=%u nAvgBytesPerSec=%u\n",
400
 
          lpTime->wType, format->wBitsPerSample, format->wf.nSamplesPerSec,
401
 
          format->wf.nChannels, format->wf.nAvgBytesPerSec);
402
 
    TRACE("Position in bytes=%u\n", position);
403
 
 
404
 
    switch (lpTime->wType) {
405
 
    case TIME_SAMPLES:
406
 
        lpTime->u.sample = position / (format->wBitsPerSample / 8 * format->wf.nChannels);
407
 
        TRACE("TIME_SAMPLES=%u\n", lpTime->u.sample);
408
 
        break;
409
 
    case TIME_MS:
410
 
        lpTime->u.ms = 1000.0 * position / (format->wBitsPerSample / 8 * format->wf.nChannels * format->wf.nSamplesPerSec);
411
 
        TRACE("TIME_MS=%u\n", lpTime->u.ms);
412
 
        break;
413
 
    case TIME_SMPTE:
414
 
        lpTime->u.smpte.fps = 30;
415
 
        position = position / (format->wBitsPerSample / 8 * format->wf.nChannels);
416
 
        position += (format->wf.nSamplesPerSec / lpTime->u.smpte.fps) - 1; /* round up */
417
 
        lpTime->u.smpte.sec = position / format->wf.nSamplesPerSec;
418
 
        position -= lpTime->u.smpte.sec * format->wf.nSamplesPerSec;
419
 
        lpTime->u.smpte.min = lpTime->u.smpte.sec / 60;
420
 
        lpTime->u.smpte.sec -= 60 * lpTime->u.smpte.min;
421
 
        lpTime->u.smpte.hour = lpTime->u.smpte.min / 60;
422
 
        lpTime->u.smpte.min -= 60 * lpTime->u.smpte.hour;
423
 
        lpTime->u.smpte.fps = 30;
424
 
        lpTime->u.smpte.frame = position * lpTime->u.smpte.fps / format->wf.nSamplesPerSec;
425
 
        TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
426
 
              lpTime->u.smpte.hour, lpTime->u.smpte.min,
427
 
              lpTime->u.smpte.sec, lpTime->u.smpte.frame);
428
 
        break;
429
 
    default:
430
 
        WARN("Format %d not supported, using TIME_BYTES !\n", lpTime->wType);
431
 
        lpTime->wType = TIME_BYTES;
432
 
        /* fall through */
433
 
    case TIME_BYTES:
434
 
        lpTime->u.cb = position;
435
 
        TRACE("TIME_BYTES=%u\n", lpTime->u.cb);
436
 
        break;
437
 
    }
438
 
    return MMSYSERR_NOERROR;
439
 
}
440
 
 
441
 
static BOOL supportedFormat(LPWAVEFORMATEX wf)
442
 
{
443
 
    if (wf->nSamplesPerSec < DSBFREQUENCY_MIN || wf->nSamplesPerSec > DSBFREQUENCY_MAX)
444
 
        return FALSE;
445
 
 
446
 
    if (wf->wFormatTag == WAVE_FORMAT_PCM) {
447
 
        if (wf->nChannels >= 1 && wf->nChannels <= 2) {
448
 
            if (wf->wBitsPerSample==8||wf->wBitsPerSample==16)
449
 
                return TRUE;
450
 
        }
451
 
    } else if (wf->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
452
 
        WAVEFORMATEXTENSIBLE * wfex = (WAVEFORMATEXTENSIBLE *)wf;
453
 
 
454
 
        if (wf->cbSize == 22 && IsEqualGUID(&wfex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) {
455
 
            if (wf->nChannels >=1 && wf->nChannels <= 8) {
456
 
                if (wf->wBitsPerSample==wfex->Samples.wValidBitsPerSample) {
457
 
                    if (wf->wBitsPerSample==8||wf->wBitsPerSample==16)
458
 
                        return TRUE;
459
 
                } else
460
 
                    WARN("wBitsPerSample != wValidBitsPerSample not supported yet\n");
461
 
            }
462
 
        } else
463
 
            WARN("only KSDATAFORMAT_SUBTYPE_PCM supported\n");
464
 
    } else
465
 
        WARN("only WAVE_FORMAT_PCM and WAVE_FORMAT_EXTENSIBLE supported\n");
466
 
 
467
 
    return FALSE;
468
 
}
469
 
 
470
 
void copyFormat(LPWAVEFORMATEX wf1, LPPCMWAVEFORMAT wf2)
471
 
{
472
 
    memcpy(wf2, wf1, sizeof(PCMWAVEFORMAT));
473
 
    /* Downgrade WAVE_FORMAT_EXTENSIBLE KSDATAFORMAT_SUBTYPE_PCM
474
 
     * to smaller yet compatible WAVE_FORMAT_PCM structure */
475
 
    if (wf2->wf.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
476
 
        wf2->wf.wFormatTag = WAVE_FORMAT_PCM;
477
 
}
478
 
 
479
 
/**************************************************************************
480
 
*                       CoreAudio_GetDevCaps            [internal]
481
 
*/
482
 
BOOL CoreAudio_GetDevCaps (void)
483
 
{
484
 
    OSStatus status;
485
 
    UInt32 propertySize;
486
 
    AudioDeviceID devId = CoreAudio_DefaultDevice.outputDeviceID;
487
 
    AudioObjectPropertyAddress propertyAddress;
488
 
    
489
 
    CFStringRef name;
490
 
    CFRange range;
491
 
    
492
 
    propertySize = sizeof(name);
493
 
    propertyAddress.mSelector = kAudioObjectPropertyName;
494
 
    propertyAddress.mScope = kAudioDevicePropertyScopeOutput;
495
 
    propertyAddress.mElement = kAudioObjectPropertyElementMaster;
496
 
    status = AudioObjectGetPropertyData(devId, &propertyAddress, 0, NULL, &propertySize, &name);
497
 
    if (status) {
498
 
        ERR("AudioObjectGetPropertyData for kAudioObjectPropertyName return %s\n", wine_dbgstr_fourcc(status));
499
 
        return FALSE;
500
 
    }
501
 
    
502
 
    CFStringGetCString(name, CoreAudio_DefaultDevice.ds_desc.szDesc,
503
 
                       sizeof(CoreAudio_DefaultDevice.ds_desc.szDesc),
504
 
                       kCFStringEncodingUTF8);
505
 
    strcpy(CoreAudio_DefaultDevice.ds_desc.szDrvname, "winecoreaudio.drv");
506
 
    range = CFRangeMake(0, min(sizeof(CoreAudio_DefaultDevice.out_caps.szPname) / sizeof(WCHAR) - 1, CFStringGetLength(name)));
507
 
    CFStringGetCharacters(name, range, CoreAudio_DefaultDevice.out_caps.szPname);
508
 
    CoreAudio_DefaultDevice.out_caps.szPname[range.length] = 0;
509
 
    CFStringGetCString(name, CoreAudio_DefaultDevice.dev_name, 32, kCFStringEncodingUTF8);
510
 
    CFRelease(name);
511
 
    
512
 
    propertySize = sizeof(CoreAudio_DefaultDevice.streamDescription);
513
 
    /* FIXME: kAudioDevicePropertyStreamFormat is deprecated. We're
514
 
     * "supposed" to get an AudioStream object from the AudioDevice,
515
 
     * then query it for the format with kAudioStreamPropertyVirtualFormat.
516
 
     * Apple says that this is for our own good, because this property
517
 
     * "has been shown to lead to programming mistakes by clients when
518
 
     * working with devices with multiple streams." Only one problem:
519
 
     * which stream? For now, just query the device.
520
 
     */
521
 
    propertyAddress.mSelector = kAudioDevicePropertyStreamFormat;
522
 
    status = AudioObjectGetPropertyData(devId, &propertyAddress, 0, NULL, &propertySize, &CoreAudio_DefaultDevice.streamDescription);
523
 
    if (status != noErr) {
524
 
        ERR("AudioObjectGetPropertyData for kAudioDevicePropertyStreamFormat return %s\n", wine_dbgstr_fourcc(status));
525
 
        return FALSE;
526
 
    }
527
 
    
528
 
    TRACE("Device Stream Description mSampleRate : %f\n mFormatID : %s\n"
529
 
            "mFormatFlags : %lX\n mBytesPerPacket : %lu\n mFramesPerPacket : %lu\n"
530
 
            "mBytesPerFrame : %lu\n mChannelsPerFrame : %lu\n mBitsPerChannel : %lu\n",
531
 
                               CoreAudio_DefaultDevice.streamDescription.mSampleRate,
532
 
                               wine_dbgstr_fourcc(CoreAudio_DefaultDevice.streamDescription.mFormatID),
533
 
                               CoreAudio_DefaultDevice.streamDescription.mFormatFlags,
534
 
                               CoreAudio_DefaultDevice.streamDescription.mBytesPerPacket,
535
 
                               CoreAudio_DefaultDevice.streamDescription.mFramesPerPacket,
536
 
                               CoreAudio_DefaultDevice.streamDescription.mBytesPerFrame,
537
 
                               CoreAudio_DefaultDevice.streamDescription.mChannelsPerFrame,
538
 
                               CoreAudio_DefaultDevice.streamDescription.mBitsPerChannel);
539
 
    
540
 
    CoreAudio_DefaultDevice.out_caps.wMid = 0xcafe;
541
 
    CoreAudio_DefaultDevice.out_caps.wPid = 0x0001;
542
 
    
543
 
    CoreAudio_DefaultDevice.out_caps.vDriverVersion = 0x0001;
544
 
    CoreAudio_DefaultDevice.out_caps.dwFormats = 0x00000000;
545
 
    CoreAudio_DefaultDevice.out_caps.wReserved1 = 0;
546
 
    CoreAudio_DefaultDevice.out_caps.dwSupport = WAVECAPS_VOLUME;
547
 
    CoreAudio_DefaultDevice.out_caps.dwSupport |= WAVECAPS_LRVOLUME;
548
 
    
549
 
    CoreAudio_DefaultDevice.out_caps.wChannels = 2;
550
 
    CoreAudio_DefaultDevice.out_caps.dwFormats|= WAVE_FORMAT_4S16;
551
 
 
552
 
    TRACE_(coreaudio)("out dwFormats = %08x, dwSupport = %08x\n",
553
 
           CoreAudio_DefaultDevice.out_caps.dwFormats, CoreAudio_DefaultDevice.out_caps.dwSupport);
554
 
    
555
 
    return TRUE;
556
 
}
557
 
 
558
 
/******************************************************************
559
 
*               CoreAudio_WaveInit
560
 
*
561
 
* Initialize CoreAudio_DefaultDevice
562
 
*/
563
 
LONG CoreAudio_WaveInit(void)
564
 
{
565
 
    OSStatus status;
566
 
    UInt32 propertySize;
567
 
    AudioObjectPropertyAddress propertyAddress;
568
 
    int i;
569
 
    CFStringRef  messageThreadPortName;
570
 
    CFMessagePortRef port_ReceiveInMessageThread;
571
 
    int inputSampleRate;
572
 
 
573
 
    TRACE("()\n");
574
 
    
575
 
    /* number of sound cards */
576
 
    propertyAddress.mSelector = kAudioHardwarePropertyDevices;
577
 
    propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
578
 
    propertyAddress.mElement = kAudioObjectPropertyElementMaster;
579
 
    AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize);
580
 
    propertySize /= sizeof(AudioDeviceID);
581
 
    TRACE("sound cards : %lu\n", propertySize);
582
 
    
583
 
    /* Get the output device */
584
 
    propertySize = sizeof(CoreAudio_DefaultDevice.outputDeviceID);
585
 
    propertyAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
586
 
    status = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize, &CoreAudio_DefaultDevice.outputDeviceID);
587
 
    if (status) {
588
 
        ERR("AudioObjectGetPropertyData return %s for kAudioHardwarePropertyDefaultOutputDevice\n", wine_dbgstr_fourcc(status));
589
 
        return DRV_FAILURE;
590
 
    }
591
 
    if (CoreAudio_DefaultDevice.outputDeviceID == kAudioDeviceUnknown) {
592
 
        ERR("AudioObjectGetPropertyData: CoreAudio_DefaultDevice.outputDeviceID == kAudioDeviceUnknown\n");
593
 
        return DRV_FAILURE;
594
 
    }
595
 
    
596
 
    if ( ! CoreAudio_GetDevCaps() )
597
 
        return DRV_FAILURE;
598
 
    
599
 
    CoreAudio_DefaultDevice.interface_name=HeapAlloc(GetProcessHeap(),0,strlen(CoreAudio_DefaultDevice.dev_name)+1);
600
 
    strcpy(CoreAudio_DefaultDevice.interface_name, CoreAudio_DefaultDevice.dev_name);
601
 
    
602
 
    for (i = 0; i < MAX_WAVEOUTDRV; ++i)
603
 
    {
604
 
        static const WCHAR wszWaveOutFormat[] =
605
 
            {'C','o','r','e','A','u','d','i','o',' ','W','a','v','e','O','u','t',' ','%','d',0};
606
 
 
607
 
        list_init(&WOutDev[i].instances);
608
 
        WOutDev[i].cadev = &CoreAudio_DefaultDevice; 
609
 
        
610
 
        memset(&WOutDev[i].caps, 0, sizeof(WOutDev[i].caps));
611
 
        
612
 
        WOutDev[i].caps.wMid = 0xcafe;  /* Manufac ID */
613
 
        WOutDev[i].caps.wPid = 0x0001;  /* Product ID */
614
 
        snprintfW(WOutDev[i].caps.szPname, sizeof(WOutDev[i].caps.szPname)/sizeof(WCHAR), wszWaveOutFormat, i);
615
 
        snprintf(WOutDev[i].interface_name, sizeof(WOutDev[i].interface_name), "winecoreaudio: %d", i);
616
 
        
617
 
        WOutDev[i].caps.vDriverVersion = 0x0001;
618
 
        WOutDev[i].caps.dwFormats = 0x00000000;
619
 
        WOutDev[i].caps.dwSupport = WAVECAPS_VOLUME;
620
 
        
621
 
        WOutDev[i].caps.wChannels = 2;
622
 
      /*  WOutDev[i].caps.dwSupport |= WAVECAPS_LRVOLUME; */ /* FIXME */
623
 
        
624
 
        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_96M08;
625
 
        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_96S08;
626
 
        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_96M16;
627
 
        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_96S16;
628
 
        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_48M08;
629
 
        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_48S08;
630
 
        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_48M16;
631
 
        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_48S16;
632
 
        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4M08;
633
 
        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4S08; 
634
 
        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4S16;
635
 
        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4M16;
636
 
        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2M08;
637
 
        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2S08; 
638
 
        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2M16;
639
 
        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2S16;
640
 
        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1M08;
641
 
        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1S08;
642
 
        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1M16;
643
 
        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1S16;
644
 
 
645
 
        WOutDev[i].device_volume = 0xffffffff;
646
 
 
647
 
        WOutDev[i].lock = 0; /* initialize the mutex */
648
 
    }
649
 
 
650
 
    /* FIXME: implement sample rate conversion on input */
651
 
    inputSampleRate = AudioUnit_GetInputDeviceSampleRate();
652
 
 
653
 
    for (i = 0; i < MAX_WAVEINDRV; ++i)
654
 
    {
655
 
        static const WCHAR wszWaveInFormat[] =
656
 
            {'C','o','r','e','A','u','d','i','o',' ','W','a','v','e','I','n',' ','%','d',0};
657
 
 
658
 
        memset(&WInDev[i], 0, sizeof(WInDev[i]));
659
 
        WInDev[i].wiID = i;
660
 
 
661
 
        /* Establish preconditions for widOpen */
662
 
        WInDev[i].state = WINE_WS_CLOSED;
663
 
        WInDev[i].lock = 0; /* initialize the mutex */
664
 
 
665
 
        /* Fill in capabilities.  widGetDevCaps can be called at any time. */
666
 
        WInDev[i].caps.wMid = 0xcafe;   /* Manufac ID */
667
 
        WInDev[i].caps.wPid = 0x0001;   /* Product ID */
668
 
        WInDev[i].caps.vDriverVersion = 0x0001;
669
 
 
670
 
        snprintfW(WInDev[i].caps.szPname, sizeof(WInDev[i].caps.szPname)/sizeof(WCHAR), wszWaveInFormat, i);
671
 
        snprintf(WInDev[i].interface_name, sizeof(WInDev[i].interface_name), "winecoreaudio in: %d", i);
672
 
 
673
 
        if (inputSampleRate == 96000)
674
 
        {
675
 
            WInDev[i].caps.dwFormats |= WAVE_FORMAT_96M08;
676
 
            WInDev[i].caps.dwFormats |= WAVE_FORMAT_96S08;
677
 
            WInDev[i].caps.dwFormats |= WAVE_FORMAT_96M16;
678
 
            WInDev[i].caps.dwFormats |= WAVE_FORMAT_96S16;
679
 
        }
680
 
        if (inputSampleRate == 48000)
681
 
        {
682
 
            WInDev[i].caps.dwFormats |= WAVE_FORMAT_48M08;
683
 
            WInDev[i].caps.dwFormats |= WAVE_FORMAT_48S08;
684
 
            WInDev[i].caps.dwFormats |= WAVE_FORMAT_48M16;
685
 
            WInDev[i].caps.dwFormats |= WAVE_FORMAT_48S16;
686
 
        }
687
 
        if (inputSampleRate == 44100)
688
 
        {
689
 
            WInDev[i].caps.dwFormats |= WAVE_FORMAT_4M08;
690
 
            WInDev[i].caps.dwFormats |= WAVE_FORMAT_4S08;
691
 
            WInDev[i].caps.dwFormats |= WAVE_FORMAT_4M16;
692
 
            WInDev[i].caps.dwFormats |= WAVE_FORMAT_4S16;
693
 
        }
694
 
        if (inputSampleRate == 22050)
695
 
        {
696
 
            WInDev[i].caps.dwFormats |= WAVE_FORMAT_2M08;
697
 
            WInDev[i].caps.dwFormats |= WAVE_FORMAT_2S08;
698
 
            WInDev[i].caps.dwFormats |= WAVE_FORMAT_2M16;
699
 
            WInDev[i].caps.dwFormats |= WAVE_FORMAT_2S16;
700
 
        }
701
 
        if (inputSampleRate == 11025)
702
 
        {
703
 
            WInDev[i].caps.dwFormats |= WAVE_FORMAT_1M08;
704
 
            WInDev[i].caps.dwFormats |= WAVE_FORMAT_1S08;
705
 
            WInDev[i].caps.dwFormats |= WAVE_FORMAT_1M16;
706
 
            WInDev[i].caps.dwFormats |= WAVE_FORMAT_1S16;
707
 
        }
708
 
 
709
 
        WInDev[i].caps.wChannels = 2;
710
 
    }
711
 
 
712
 
    /* create mach messages handler */
713
 
    srandomdev();
714
 
    messageThreadPortName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
715
 
        CFSTR("WaveMessagePort.%d.%lu"), getpid(), (unsigned long)random());
716
 
    if (!messageThreadPortName)
717
 
    {
718
 
        ERR("Can't create message thread port name\n");
719
 
        return DRV_FAILURE;
720
 
    }
721
 
 
722
 
    port_ReceiveInMessageThread = CFMessagePortCreateLocal(kCFAllocatorDefault, messageThreadPortName,
723
 
                                        &wodMessageHandler, NULL, NULL);
724
 
    if (!port_ReceiveInMessageThread)
725
 
    {
726
 
        ERR("Can't create message thread local port\n");
727
 
        CFRelease(messageThreadPortName);
728
 
        return DRV_FAILURE;
729
 
    }
730
 
 
731
 
    Port_SendToMessageThread = CFMessagePortCreateRemote(kCFAllocatorDefault, messageThreadPortName);
732
 
    CFRelease(messageThreadPortName);
733
 
    if (!Port_SendToMessageThread)
734
 
    {
735
 
        ERR("Can't create port for sending to message thread\n");
736
 
        CFRelease(port_ReceiveInMessageThread);
737
 
        return DRV_FAILURE;
738
 
    }
739
 
 
740
 
    /* Cannot WAIT for any events because we are called from the loader (which has a lock on loading stuff) */
741
 
    /* We might want to wait for this thread to be created -- but we cannot -- not here at least */
742
 
    /* Instead track the thread so we can clean it up later */
743
 
    if ( hThread )
744
 
    {
745
 
        ERR("Message thread already started -- expect problems\n");
746
 
    }
747
 
    hThread = CreateThread(NULL, 0, messageThread, (LPVOID)port_ReceiveInMessageThread, 0, NULL);
748
 
    if ( !hThread )
749
 
    {
750
 
        ERR("Can't create message thread\n");
751
 
        CFRelease(port_ReceiveInMessageThread);
752
 
        CFRelease(Port_SendToMessageThread);
753
 
        Port_SendToMessageThread = NULL;
754
 
        return DRV_FAILURE;
755
 
    }
756
 
 
757
 
    /* The message thread is responsible for releasing port_ReceiveInMessageThread. */
758
 
 
759
 
    return DRV_SUCCESS;
760
 
}
761
 
 
762
 
void CoreAudio_WaveRelease(void)
763
 
{
764
 
    /* Stop CFRunLoop in messageThread */
765
 
    TRACE("()\n");
766
 
 
767
 
    if (!Port_SendToMessageThread)
768
 
        return;
769
 
 
770
 
    CFMessagePortSendRequest(Port_SendToMessageThread, kStopLoopMessage, NULL, 0.0, 0.0, NULL, NULL);
771
 
    CFRelease(Port_SendToMessageThread);
772
 
    Port_SendToMessageThread = NULL;
773
 
 
774
 
    /* Wait for the thread to finish and clean it up */
775
 
    /* This rids us of any quick start/shutdown driver crashes */
776
 
    WaitForSingleObject(hThread, INFINITE);
777
 
    CloseHandle(hThread);
778
 
    hThread = NULL;
779
 
}
780
 
 
781
 
/*======================================================================*
782
 
*                  Low level WAVE OUT implementation                    *
783
 
*======================================================================*/
784
 
 
785
 
/**************************************************************************
786
 
*                       wodNotifyClient                 [internal]
787
 
*/
788
 
static void wodNotifyClient(WINE_WAVEOUT_INSTANCE* wwo, WORD wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
789
 
{
790
 
    TRACE("wMsg = 0x%04x dwParm1 = %04lx dwParam2 = %04lx\n", wMsg, dwParam1, dwParam2);
791
 
 
792
 
    switch (wMsg) {
793
 
        case WOM_OPEN:
794
 
        case WOM_CLOSE:
795
 
        case WOM_DONE:
796
 
            DriverCallback(wwo->waveDesc.dwCallback, wwo->wFlags,
797
 
                           (HDRVR)wwo->waveDesc.hWave, wMsg, wwo->waveDesc.dwInstance,
798
 
                           dwParam1, dwParam2);
799
 
            break;
800
 
        default:
801
 
            FIXME("Unknown callback message %u\n", wMsg);
802
 
    }
803
 
}
804
 
 
805
 
 
806
 
/**************************************************************************
807
 
*                       wodGetDevCaps               [internal]
808
 
*/
809
 
static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPSW lpCaps, DWORD dwSize)
810
 
{
811
 
    TRACE("(%u, %p, %u);\n", wDevID, lpCaps, dwSize);
812
 
    
813
 
    if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
814
 
    
815
 
    if (wDevID >= MAX_WAVEOUTDRV)
816
 
    {
817
 
        TRACE("MAX_WAVOUTDRV reached !\n");
818
 
        return MMSYSERR_BADDEVICEID;
819
 
    }
820
 
    
821
 
    TRACE("dwSupport=(0x%x), dwFormats=(0x%x)\n", WOutDev[wDevID].caps.dwSupport, WOutDev[wDevID].caps.dwFormats);
822
 
    memcpy(lpCaps, &WOutDev[wDevID].caps, min(dwSize, sizeof(*lpCaps)));
823
 
    return MMSYSERR_NOERROR;
824
 
}
825
 
 
826
 
/**************************************************************************
827
 
*                               wodOpen                         [internal]
828
 
*/
829
 
static DWORD wodOpen(WORD wDevID, WINE_WAVEOUT_INSTANCE** pInstance, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
830
 
{
831
 
    WINE_WAVEOUT_INSTANCE*      wwo;
832
 
    DWORD               ret;
833
 
    AudioStreamBasicDescription streamFormat;
834
 
    AudioUnit           audioUnit = NULL;
835
 
    BOOL                auInited  = FALSE;
836
 
 
837
 
    TRACE("(%u, %p, %p, %08x);\n", wDevID, pInstance, lpDesc, dwFlags);
838
 
    if (lpDesc == NULL)
839
 
    {
840
 
        WARN("Invalid Parameter !\n");
841
 
        return MMSYSERR_INVALPARAM;
842
 
    }
843
 
    if (wDevID >= MAX_WAVEOUTDRV) {
844
 
        TRACE("MAX_WAVOUTDRV reached !\n");
845
 
        return MMSYSERR_BADDEVICEID;
846
 
    }
847
 
    
848
 
    TRACE("Format: tag=%04X nChannels=%d nSamplesPerSec=%d wBitsPerSample=%d !\n",
849
 
          lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
850
 
          lpDesc->lpFormat->nSamplesPerSec, lpDesc->lpFormat->wBitsPerSample);
851
 
    
852
 
    if (!supportedFormat(lpDesc->lpFormat))
853
 
    {
854
 
        WARN("Bad format: tag=%04X nChannels=%d nSamplesPerSec=%d wBitsPerSample=%d !\n",
855
 
             lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
856
 
             lpDesc->lpFormat->nSamplesPerSec, lpDesc->lpFormat->wBitsPerSample);
857
 
        return WAVERR_BADFORMAT;
858
 
    }
859
 
    
860
 
    if (dwFlags & WAVE_FORMAT_QUERY)
861
 
    {
862
 
        TRACE("Query format: tag=%04X nChannels=%d nSamplesPerSec=%d !\n",
863
 
              lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
864
 
              lpDesc->lpFormat->nSamplesPerSec);
865
 
        return MMSYSERR_NOERROR;
866
 
    }
867
 
 
868
 
    /* nBlockAlign and nAvgBytesPerSec are output variables for dsound */
869
 
    if (lpDesc->lpFormat->nBlockAlign != lpDesc->lpFormat->nChannels*lpDesc->lpFormat->wBitsPerSample/8) {
870
 
        lpDesc->lpFormat->nBlockAlign  = lpDesc->lpFormat->nChannels*lpDesc->lpFormat->wBitsPerSample/8;
871
 
        WARN("Fixing nBlockAlign\n");
872
 
    }
873
 
    if (lpDesc->lpFormat->nAvgBytesPerSec!= lpDesc->lpFormat->nSamplesPerSec*lpDesc->lpFormat->nBlockAlign) {
874
 
        lpDesc->lpFormat->nAvgBytesPerSec = lpDesc->lpFormat->nSamplesPerSec*lpDesc->lpFormat->nBlockAlign;
875
 
        WARN("Fixing nAvgBytesPerSec\n");
876
 
    }
877
 
 
878
 
    /* We proceed in three phases:
879
 
     * o Allocate the device instance, marking it as opening
880
 
     * o Create, configure, and start the Audio Unit.  To avoid deadlock,
881
 
     *   this has to be done without holding wwo->lock.
882
 
     * o If that was successful, finish setting up our instance and add it
883
 
     *   to the device's list.
884
 
     *   Otherwise, clean up and deallocate the instance.
885
 
     */
886
 
    wwo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wwo));
887
 
    if (!wwo)
888
 
        return MMSYSERR_NOMEM;
889
 
 
890
 
    wwo->woID = wDevID;
891
 
    wwo->state = WINE_WS_OPENING;
892
 
 
893
 
    if (!AudioUnit_CreateDefaultAudioUnit((void *) wwo, &audioUnit))
894
 
    {
895
 
        ERR("CoreAudio_CreateDefaultAudioUnit(0x%04x) failed\n", wDevID);
896
 
        ret = MMSYSERR_ERROR;
897
 
        goto error;
898
 
    }
899
 
 
900
 
    streamFormat.mFormatID = kAudioFormatLinearPCM;
901
 
    streamFormat.mFormatFlags = kLinearPCMFormatFlagIsPacked;
902
 
    /* FIXME check for 32bits float -> kLinearPCMFormatFlagIsFloat */
903
 
    if (lpDesc->lpFormat->wBitsPerSample != 8)
904
 
        streamFormat.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
905
 
# ifdef WORDS_BIGENDIAN
906
 
    streamFormat.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; /* FIXME Wave format is little endian */
907
 
# endif
908
 
 
909
 
    streamFormat.mSampleRate = lpDesc->lpFormat->nSamplesPerSec;
910
 
    streamFormat.mChannelsPerFrame = lpDesc->lpFormat->nChannels;       
911
 
    streamFormat.mFramesPerPacket = 1;  
912
 
    streamFormat.mBitsPerChannel = lpDesc->lpFormat->wBitsPerSample;
913
 
    streamFormat.mBytesPerFrame = streamFormat.mBitsPerChannel * streamFormat.mChannelsPerFrame / 8;    
914
 
    streamFormat.mBytesPerPacket = streamFormat.mBytesPerFrame * streamFormat.mFramesPerPacket;         
915
 
 
916
 
    ret = AudioUnit_InitializeWithStreamDescription(audioUnit, &streamFormat);
917
 
    if (!ret) 
918
 
    {
919
 
        ret = WAVERR_BADFORMAT; /* FIXME return an error based on the OSStatus */
920
 
        goto error;
921
 
    }
922
 
    auInited = TRUE;
923
 
 
924
 
    AudioUnit_SetVolume(audioUnit, LOWORD(WOutDev[wDevID].device_volume) / 65535.0f,
925
 
                        HIWORD(WOutDev[wDevID].device_volume) / 65535.0f);
926
 
 
927
 
    /* Our render callback CoreAudio_woAudioUnitIOProc may be called before
928
 
     * AudioOutputUnitStart returns.  Core Audio will grab its own internal
929
 
     * lock before calling it and the callback grabs wwo->lock.  This would
930
 
     * deadlock if we were holding wwo->lock.
931
 
     * Also, the callback has to safely do nothing in that case, because
932
 
     * wwo hasn't been completely filled out, yet. This is assured by state
933
 
     * being WINE_WS_OPENING. */
934
 
    ret = AudioOutputUnitStart(audioUnit);
935
 
    if (ret)
936
 
    {
937
 
        ERR("AudioOutputUnitStart failed: %08x\n", ret);
938
 
        ret = MMSYSERR_ERROR; /* FIXME return an error based on the OSStatus */
939
 
        goto error;
940
 
    }
941
 
 
942
 
 
943
 
    OSSpinLockLock(&wwo->lock);
944
 
    assert(wwo->state == WINE_WS_OPENING);
945
 
 
946
 
    wwo->audioUnit = audioUnit;
947
 
    wwo->streamDescription = streamFormat;
948
 
 
949
 
    wwo->state = WINE_WS_PLAYING;
950
 
 
951
 
    wwo->wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
952
 
 
953
 
    wwo->waveDesc = *lpDesc;
954
 
    copyFormat(lpDesc->lpFormat, &wwo->format);
955
 
 
956
 
    WOutDev[wDevID].trace_on = TRACE_ON(wave);
957
 
    WOutDev[wDevID].warn_on  = WARN_ON(wave);
958
 
    WOutDev[wDevID].err_on   = ERR_ON(wave);
959
 
 
960
 
    OSSpinLockUnlock(&wwo->lock);
961
 
 
962
 
    OSSpinLockLock(&WOutDev[wDevID].lock);
963
 
    list_add_head(&WOutDev[wDevID].instances, &wwo->entry);
964
 
    OSSpinLockUnlock(&WOutDev[wDevID].lock);
965
 
 
966
 
    *pInstance = wwo;
967
 
    TRACE("opened instance %p\n", wwo);
968
 
 
969
 
    wodNotifyClient(wwo, WOM_OPEN, 0L, 0L);
970
 
    
971
 
    return MMSYSERR_NOERROR;
972
 
 
973
 
error:
974
 
    if (audioUnit)
975
 
    {
976
 
        if (auInited)
977
 
            AudioUnitUninitialize(audioUnit);
978
 
        AudioUnit_CloseAudioUnit(audioUnit);
979
 
    }
980
 
 
981
 
    OSSpinLockLock(&wwo->lock);
982
 
    assert(wwo->state == WINE_WS_OPENING);
983
 
    /* OSSpinLockUnlock(&wwo->lock); *//* No need, about to free */
984
 
    HeapFree(GetProcessHeap(), 0, wwo);
985
 
 
986
 
    return ret;
987
 
}
988
 
 
989
 
/**************************************************************************
990
 
*                               wodClose                        [internal]
991
 
*/
992
 
static DWORD wodClose(WORD wDevID, WINE_WAVEOUT_INSTANCE* wwo)
993
 
{
994
 
    DWORD               ret = MMSYSERR_NOERROR;
995
 
    
996
 
    TRACE("(%u, %p);\n", wDevID, wwo);
997
 
    
998
 
    if (wDevID >= MAX_WAVEOUTDRV)
999
 
    {
1000
 
        WARN("bad device ID !\n");
1001
 
        return MMSYSERR_BADDEVICEID;
1002
 
    }
1003
 
    
1004
 
    OSSpinLockLock(&wwo->lock);
1005
 
    if (wwo->lpQueuePtr)
1006
 
    {
1007
 
        OSSpinLockUnlock(&wwo->lock);
1008
 
        WARN("buffers still playing !\n");
1009
 
        return WAVERR_STILLPLAYING;
1010
 
    } else
1011
 
    {
1012
 
        OSStatus err;
1013
 
        AudioUnit audioUnit = wwo->audioUnit;
1014
 
 
1015
 
        /* sanity check: this should not happen since the device must have been reset before */
1016
 
        if (wwo->lpQueuePtr || wwo->lpPlayPtr) ERR("out of sync\n");
1017
 
        
1018
 
        wwo->state = WINE_WS_CLOSING; /* mark the device as closing */
1019
 
        wwo->audioUnit = NULL;
1020
 
        
1021
 
        OSSpinLockUnlock(&wwo->lock);
1022
 
 
1023
 
        err = AudioUnitUninitialize(audioUnit);
1024
 
        if (err) {
1025
 
            ERR("AudioUnitUninitialize return %s\n", wine_dbgstr_fourcc(err));
1026
 
            return MMSYSERR_ERROR; /* FIXME return an error based on the OSStatus */
1027
 
        }
1028
 
        
1029
 
        if ( !AudioUnit_CloseAudioUnit(audioUnit) )
1030
 
        {
1031
 
            ERR("Can't close AudioUnit\n");
1032
 
            return MMSYSERR_ERROR; /* FIXME return an error based on the OSStatus */
1033
 
        }  
1034
 
        
1035
 
        OSSpinLockLock(&WOutDev[wDevID].lock);
1036
 
        list_remove(&wwo->entry);
1037
 
        OSSpinLockUnlock(&WOutDev[wDevID].lock);
1038
 
 
1039
 
        wodNotifyClient(wwo, WOM_CLOSE, 0L, 0L);
1040
 
 
1041
 
        HeapFree(GetProcessHeap(), 0, wwo);
1042
 
    }
1043
 
    
1044
 
    return ret;
1045
 
}
1046
 
 
1047
 
/**************************************************************************
1048
 
*                               wodPrepare                      [internal]
1049
 
*/
1050
 
static DWORD wodPrepare(WORD wDevID, WINE_WAVEOUT_INSTANCE* wwo, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1051
 
{
1052
 
    TRACE("(%u, %p, %p, %08x);\n", wDevID, wwo, lpWaveHdr, dwSize);
1053
 
    
1054
 
    if (wDevID >= MAX_WAVEOUTDRV) {
1055
 
        WARN("bad device ID !\n");
1056
 
        return MMSYSERR_BADDEVICEID;
1057
 
    }
1058
 
    
1059
 
    if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
1060
 
        return WAVERR_STILLPLAYING;
1061
 
    
1062
 
    lpWaveHdr->dwFlags |= WHDR_PREPARED;
1063
 
    lpWaveHdr->dwFlags &= ~WHDR_DONE;
1064
 
 
1065
 
    return MMSYSERR_NOERROR;
1066
 
}
1067
 
 
1068
 
/**************************************************************************
1069
 
*                               wodUnprepare                    [internal]
1070
 
*/
1071
 
static DWORD wodUnprepare(WORD wDevID, WINE_WAVEOUT_INSTANCE* wwo, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1072
 
{
1073
 
    TRACE("(%u, %p, %p, %08x);\n", wDevID, wwo, lpWaveHdr, dwSize);
1074
 
    
1075
 
    if (wDevID >= MAX_WAVEOUTDRV) {
1076
 
        WARN("bad device ID !\n");
1077
 
        return MMSYSERR_BADDEVICEID;
1078
 
    }
1079
 
    
1080
 
    if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
1081
 
        return WAVERR_STILLPLAYING;
1082
 
    
1083
 
    lpWaveHdr->dwFlags &= ~WHDR_PREPARED;
1084
 
    lpWaveHdr->dwFlags |= WHDR_DONE;
1085
 
   
1086
 
    return MMSYSERR_NOERROR;
1087
 
}
1088
 
 
1089
 
 
1090
 
/**************************************************************************
1091
 
*                               wodHelper_CheckForLoopBegin             [internal]
1092
 
*
1093
 
* Check if the new waveheader is the beginning of a loop, and set up
1094
 
* state if so.
1095
 
* This is called with the WAVEOUT_INSTANCE lock held.
1096
 
* Call from AudioUnit IO thread can't use Wine debug channels.
1097
 
*/
1098
 
static void wodHelper_CheckForLoopBegin(WINE_WAVEOUT_INSTANCE* wwo)
1099
 
{
1100
 
    LPWAVEHDR lpWaveHdr = wwo->lpPlayPtr;
1101
 
 
1102
 
    if (lpWaveHdr->dwFlags & WHDR_BEGINLOOP)
1103
 
    {
1104
 
        if (wwo->lpLoopPtr)
1105
 
        {
1106
 
            if (WOutDev[wwo->woID].warn_on)
1107
 
                fprintf(stderr, "warn:winecoreaudio:wodHelper_CheckForLoopBegin Already in a loop. Discarding loop on this header (%p)\n", lpWaveHdr);
1108
 
        }
1109
 
        else
1110
 
        {
1111
 
            if (WOutDev[wwo->woID].trace_on)
1112
 
                fprintf(stderr, "trace:winecoreaudio:wodHelper_CheckForLoopBegin Starting loop (%dx) with %p\n", lpWaveHdr->dwLoops, lpWaveHdr);
1113
 
 
1114
 
            wwo->lpLoopPtr = lpWaveHdr;
1115
 
            /* Windows does not touch WAVEHDR.dwLoops,
1116
 
                * so we need to make an internal copy */
1117
 
            wwo->dwLoops = lpWaveHdr->dwLoops;
1118
 
        }
1119
 
    }
1120
 
}
1121
 
 
1122
 
 
1123
 
/**************************************************************************
1124
 
*                               wodHelper_PlayPtrNext           [internal]
1125
 
*
1126
 
* Advance the play pointer to the next waveheader, looping if required.
1127
 
* This is called with the WAVEOUT_INSTANCE lock held.
1128
 
* Call from AudioUnit IO thread can't use Wine debug channels.
1129
 
*/
1130
 
static void wodHelper_PlayPtrNext(WINE_WAVEOUT_INSTANCE* wwo)
1131
 
{
1132
 
    BOOL didLoopBack = FALSE;
1133
 
 
1134
 
    wwo->dwPartialOffset = 0;
1135
 
    if ((wwo->lpPlayPtr->dwFlags & WHDR_ENDLOOP) && wwo->lpLoopPtr)
1136
 
    {
1137
 
        /* We're at the end of a loop, loop if required */
1138
 
        if (wwo->dwLoops > 1)
1139
 
        {
1140
 
            wwo->dwLoops--;
1141
 
            wwo->lpPlayPtr = wwo->lpLoopPtr;
1142
 
            didLoopBack = TRUE;
1143
 
        }
1144
 
        else
1145
 
        {
1146
 
            wwo->lpLoopPtr = NULL;
1147
 
        }
1148
 
    }
1149
 
    if (!didLoopBack)
1150
 
    {
1151
 
        /* We didn't loop back.  Advance to the next wave header */
1152
 
        wwo->lpPlayPtr = wwo->lpPlayPtr->lpNext;
1153
 
 
1154
 
        if (wwo->lpPlayPtr)
1155
 
            wodHelper_CheckForLoopBegin(wwo);
1156
 
    }
1157
 
}
1158
 
 
1159
 
/* Send the "done" notification for each WAVEHDR in a list.  The list must be
1160
 
 * free-standing.  It should not be part of a device instance's queue.
1161
 
 * This function must be called with the WAVEOUT_INSTANCE lock *not* held.
1162
 
 * Furthermore, it does not lock it, itself.  That's because the callback to the
1163
 
 * application may prompt the application to operate on the device, and we don't
1164
 
 * want to deadlock.
1165
 
 */
1166
 
static void wodHelper_NotifyDoneForList(WINE_WAVEOUT_INSTANCE* wwo, LPWAVEHDR lpWaveHdr)
1167
 
{
1168
 
    while (lpWaveHdr)
1169
 
    {
1170
 
        LPWAVEHDR lpNext = lpWaveHdr->lpNext;
1171
 
 
1172
 
        lpWaveHdr->lpNext = NULL;
1173
 
        lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
1174
 
        lpWaveHdr->dwFlags |= WHDR_DONE;
1175
 
        wodNotifyClient(wwo, WOM_DONE, (DWORD_PTR)lpWaveHdr, 0);
1176
 
 
1177
 
        lpWaveHdr = lpNext;
1178
 
    }
1179
 
}
1180
 
 
1181
 
/* if force is TRUE then notify the client that all the headers were completed
1182
 
 */
1183
 
static void wodHelper_NotifyCompletions(WINE_WAVEOUT_INSTANCE* wwo, BOOL force)
1184
 
{
1185
 
    LPWAVEHDR lpFirstDoneWaveHdr = NULL;
1186
 
 
1187
 
    OSSpinLockLock(&wwo->lock);
1188
 
 
1189
 
    /* First, excise all of the done headers from the queue into
1190
 
     * a free-standing list. */
1191
 
    if (force)
1192
 
    {
1193
 
        lpFirstDoneWaveHdr = wwo->lpQueuePtr;
1194
 
        wwo->lpQueuePtr = NULL;
1195
 
    }
1196
 
    else
1197
 
    {
1198
 
        LPWAVEHDR lpWaveHdr;
1199
 
        LPWAVEHDR lpLastDoneWaveHdr = NULL;
1200
 
 
1201
 
        /* Start from lpQueuePtr and keep notifying until:
1202
 
            * - we hit an unwritten wavehdr
1203
 
            * - we hit the beginning of a running loop
1204
 
            * - we hit a wavehdr which hasn't finished playing
1205
 
            */
1206
 
        for (
1207
 
            lpWaveHdr = wwo->lpQueuePtr;
1208
 
            lpWaveHdr &&
1209
 
                lpWaveHdr != wwo->lpPlayPtr &&
1210
 
                lpWaveHdr != wwo->lpLoopPtr;
1211
 
            lpWaveHdr = lpWaveHdr->lpNext
1212
 
            )
1213
 
        {
1214
 
            if (!lpFirstDoneWaveHdr)
1215
 
                lpFirstDoneWaveHdr = lpWaveHdr;
1216
 
            lpLastDoneWaveHdr = lpWaveHdr;
1217
 
        }
1218
 
 
1219
 
        if (lpLastDoneWaveHdr)
1220
 
        {
1221
 
            wwo->lpQueuePtr = lpLastDoneWaveHdr->lpNext;
1222
 
            lpLastDoneWaveHdr->lpNext = NULL;
1223
 
        }
1224
 
    }
1225
 
    
1226
 
    OSSpinLockUnlock(&wwo->lock);
1227
 
 
1228
 
    /* Now, send the "done" notification for each header in our list. */
1229
 
    wodHelper_NotifyDoneForList(wwo, lpFirstDoneWaveHdr);
1230
 
}
1231
 
 
1232
 
 
1233
 
/**************************************************************************
1234
 
*                               wodWrite                        [internal]
1235
 
1236
 
*/
1237
 
static DWORD wodWrite(WORD wDevID, WINE_WAVEOUT_INSTANCE* wwo, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1238
 
{
1239
 
    LPWAVEHDR*wh;
1240
 
    
1241
 
    TRACE("(%u, %p, %p, %lu, %08X);\n", wDevID, wwo, lpWaveHdr, (unsigned long)lpWaveHdr->dwBufferLength, dwSize);
1242
 
    
1243
 
    /* first, do the sanity checks... */
1244
 
    if (wDevID >= MAX_WAVEOUTDRV)
1245
 
    {
1246
 
        WARN("bad dev ID !\n");
1247
 
        return MMSYSERR_BADDEVICEID;
1248
 
    }
1249
 
    
1250
 
    if (lpWaveHdr->lpData == NULL || !(lpWaveHdr->dwFlags & WHDR_PREPARED))
1251
 
    {
1252
 
        TRACE("unprepared\n");
1253
 
        return WAVERR_UNPREPARED;
1254
 
    }
1255
 
    
1256
 
    if (lpWaveHdr->dwFlags & WHDR_INQUEUE) 
1257
 
    {
1258
 
        TRACE("still playing\n");
1259
 
        return WAVERR_STILLPLAYING;
1260
 
    }
1261
 
    
1262
 
    lpWaveHdr->dwFlags &= ~WHDR_DONE;
1263
 
    lpWaveHdr->dwFlags |= WHDR_INQUEUE;
1264
 
    lpWaveHdr->lpNext = 0;
1265
 
 
1266
 
    OSSpinLockLock(&wwo->lock);
1267
 
    /* insert buffer at the end of queue */
1268
 
    for (wh = &(wwo->lpQueuePtr); *wh; wh = &((*wh)->lpNext))
1269
 
        /* Do nothing */;
1270
 
    *wh = lpWaveHdr;
1271
 
    
1272
 
    if (!wwo->lpPlayPtr)
1273
 
    {
1274
 
        wwo->lpPlayPtr = lpWaveHdr;
1275
 
 
1276
 
        wodHelper_CheckForLoopBegin(wwo);
1277
 
 
1278
 
        wwo->dwPartialOffset = 0;
1279
 
    }
1280
 
    OSSpinLockUnlock(&wwo->lock);
1281
 
 
1282
 
    return MMSYSERR_NOERROR;
1283
 
}
1284
 
 
1285
 
/**************************************************************************
1286
 
*                       wodPause                                [internal]
1287
 
*/
1288
 
static DWORD wodPause(WORD wDevID, WINE_WAVEOUT_INSTANCE* wwo)
1289
 
{
1290
 
    OSStatus status;
1291
 
 
1292
 
    TRACE("(%u, %p);!\n", wDevID, wwo);
1293
 
    
1294
 
    if (wDevID >= MAX_WAVEOUTDRV)
1295
 
    {
1296
 
        WARN("bad device ID !\n");
1297
 
        return MMSYSERR_BADDEVICEID;
1298
 
    }
1299
 
 
1300
 
    /* The order of the following operations is important since we can't hold
1301
 
     * the mutex while we make an Audio Unit call.  Stop the Audio Unit before
1302
 
     * setting the PAUSED state.  In wodRestart, the order is reversed.  This
1303
 
     * guarantees that we can't get into a situation where the state is
1304
 
     * PLAYING but the Audio Unit isn't running.  Although we can be in PAUSED
1305
 
     * state with the Audio Unit still running, that's harmless because the
1306
 
     * render callback will just produce silence.
1307
 
     */
1308
 
    status = AudioOutputUnitStop(wwo->audioUnit);
1309
 
    if (status)
1310
 
        WARN("AudioOutputUnitStop return %s\n", wine_dbgstr_fourcc(status));
1311
 
 
1312
 
    OSSpinLockLock(&wwo->lock);
1313
 
    if (wwo->state == WINE_WS_PLAYING)
1314
 
        wwo->state = WINE_WS_PAUSED;
1315
 
    OSSpinLockUnlock(&wwo->lock);
1316
 
 
1317
 
    return MMSYSERR_NOERROR;
1318
 
}
1319
 
 
1320
 
/**************************************************************************
1321
 
*                       wodRestart                              [internal]
1322
 
*/
1323
 
static DWORD wodRestart(WORD wDevID, WINE_WAVEOUT_INSTANCE* wwo)
1324
 
{
1325
 
    OSStatus status;
1326
 
 
1327
 
    TRACE("(%u, %p);\n", wDevID, wwo);
1328
 
    
1329
 
    if (wDevID >= MAX_WAVEOUTDRV )
1330
 
    {
1331
 
        WARN("bad device ID !\n");
1332
 
        return MMSYSERR_BADDEVICEID;
1333
 
    }
1334
 
 
1335
 
    /* The order of the following operations is important since we can't hold
1336
 
     * the mutex while we make an Audio Unit call.  Set the PLAYING
1337
 
     * state before starting the Audio Unit.  In wodPause, the order is
1338
 
     * reversed.  This guarantees that we can't get into a situation where
1339
 
     * the state is PLAYING but the Audio Unit isn't running.
1340
 
     * Although we can be in PAUSED state with the Audio Unit still running,
1341
 
     * that's harmless because the render callback will just produce silence.
1342
 
     */
1343
 
    OSSpinLockLock(&wwo->lock);
1344
 
    if (wwo->state == WINE_WS_PAUSED)
1345
 
        wwo->state = WINE_WS_PLAYING;
1346
 
    OSSpinLockUnlock(&wwo->lock);
1347
 
 
1348
 
    status = AudioOutputUnitStart(wwo->audioUnit);
1349
 
    if (status) {
1350
 
        ERR("AudioOutputUnitStart return %s\n", wine_dbgstr_fourcc(status));
1351
 
        return MMSYSERR_ERROR; /* FIXME return an error based on the OSStatus */
1352
 
    }
1353
 
 
1354
 
    return MMSYSERR_NOERROR;
1355
 
}
1356
 
 
1357
 
/**************************************************************************
1358
 
*                       wodReset                                [internal]
1359
 
*/
1360
 
static DWORD wodReset(WORD wDevID, WINE_WAVEOUT_INSTANCE* wwo)
1361
 
{
1362
 
    OSStatus status;
1363
 
    LPWAVEHDR lpSavedQueuePtr;
1364
 
 
1365
 
    TRACE("(%u, %p);\n", wDevID, wwo);
1366
 
 
1367
 
    if (wDevID >= MAX_WAVEOUTDRV)
1368
 
    {
1369
 
        WARN("bad device ID !\n");
1370
 
        return MMSYSERR_BADDEVICEID;
1371
 
    }
1372
 
 
1373
 
    OSSpinLockLock(&wwo->lock);
1374
 
 
1375
 
    if (wwo->state == WINE_WS_CLOSING || wwo->state == WINE_WS_OPENING)
1376
 
    {
1377
 
        OSSpinLockUnlock(&wwo->lock);
1378
 
        WARN("resetting a closed device\n");
1379
 
        return MMSYSERR_INVALHANDLE;
1380
 
    }
1381
 
 
1382
 
    lpSavedQueuePtr = wwo->lpQueuePtr;
1383
 
    wwo->lpPlayPtr = wwo->lpQueuePtr = wwo->lpLoopPtr = NULL;
1384
 
    wwo->state = WINE_WS_PLAYING;
1385
 
    wwo->dwPlayedTotal = 0;
1386
 
 
1387
 
    wwo->dwPartialOffset = 0;        /* Clear partial wavehdr */
1388
 
 
1389
 
    OSSpinLockUnlock(&wwo->lock);
1390
 
 
1391
 
    status = AudioOutputUnitStart(wwo->audioUnit);
1392
 
 
1393
 
    if (status) {
1394
 
        ERR( "AudioOutputUnitStart return %s\n", wine_dbgstr_fourcc(status));
1395
 
        return MMSYSERR_ERROR; /* FIXME return an error based on the OSStatus */
1396
 
    }
1397
 
 
1398
 
    /* Now, send the "done" notification for each header in our list. */
1399
 
    /* Do this last so the reset operation is effectively complete before the
1400
 
     * app does whatever it's going to do in response to these notifications. */
1401
 
    wodHelper_NotifyDoneForList(wwo, lpSavedQueuePtr);
1402
 
 
1403
 
    return MMSYSERR_NOERROR;
1404
 
}
1405
 
 
1406
 
/**************************************************************************
1407
 
*           wodBreakLoop                [internal]
1408
 
*/
1409
 
static DWORD wodBreakLoop(WORD wDevID, WINE_WAVEOUT_INSTANCE* wwo)
1410
 
{
1411
 
    TRACE("(%u, %p);\n", wDevID, wwo);
1412
 
 
1413
 
    if (wDevID >= MAX_WAVEOUTDRV)
1414
 
    {
1415
 
        WARN("bad device ID !\n");
1416
 
        return MMSYSERR_BADDEVICEID;
1417
 
    }
1418
 
 
1419
 
    OSSpinLockLock(&wwo->lock);
1420
 
 
1421
 
    if (wwo->lpLoopPtr != NULL)
1422
 
    {
1423
 
        /* ensure exit at end of current loop */
1424
 
        wwo->dwLoops = 1;
1425
 
    }
1426
 
 
1427
 
    OSSpinLockUnlock(&wwo->lock);
1428
 
 
1429
 
    return MMSYSERR_NOERROR;
1430
 
}
1431
 
 
1432
 
/**************************************************************************
1433
 
*                               wodGetPosition                  [internal]
1434
 
*/
1435
 
static DWORD wodGetPosition(WORD wDevID, WINE_WAVEOUT_INSTANCE* wwo, LPMMTIME lpTime, DWORD uSize)
1436
 
{
1437
 
    DWORD               val;
1438
 
 
1439
 
    TRACE("(%u, %p, %p, %u);\n", wDevID, wwo, lpTime, uSize);
1440
 
    
1441
 
    if (wDevID >= MAX_WAVEOUTDRV)
1442
 
    {
1443
 
        WARN("bad device ID !\n");
1444
 
        return MMSYSERR_BADDEVICEID;
1445
 
    }
1446
 
    
1447
 
    /* if null pointer to time structure return error */
1448
 
    if (lpTime == NULL) return MMSYSERR_INVALPARAM;
1449
 
    
1450
 
    OSSpinLockLock(&wwo->lock);
1451
 
    val = wwo->dwPlayedTotal;
1452
 
    OSSpinLockUnlock(&wwo->lock);
1453
 
    
1454
 
    return bytes_to_mmtime(lpTime, val, &wwo->format);
1455
 
}
1456
 
 
1457
 
/**************************************************************************
1458
 
*                               wodGetVolume                    [internal]
1459
 
*/
1460
 
static DWORD wodGetVolume(WORD wDevID, WINE_WAVEOUT_INSTANCE* wwo, LPDWORD lpdwVol)
1461
 
{
1462
 
    if (wDevID >= MAX_WAVEOUTDRV)
1463
 
    {
1464
 
        WARN("bad device ID !\n");
1465
 
        return MMSYSERR_BADDEVICEID;
1466
 
    }    
1467
 
    
1468
 
    TRACE("(%u, %p, %p);\n", wDevID, wwo, lpdwVol);
1469
 
 
1470
 
    if (wwo)
1471
 
    {
1472
 
        float left;
1473
 
        float right;
1474
 
 
1475
 
        AudioUnit_GetVolume(wwo->audioUnit, &left, &right);
1476
 
        *lpdwVol = (WORD)(left * 0xFFFFl) + ((WORD)(right * 0xFFFFl) << 16);
1477
 
    }
1478
 
    else
1479
 
        *lpdwVol = WOutDev[wDevID].device_volume;
1480
 
 
1481
 
    return MMSYSERR_NOERROR;
1482
 
}
1483
 
 
1484
 
/**************************************************************************
1485
 
*                               wodSetVolume                    [internal]
1486
 
*/
1487
 
static DWORD wodSetVolume(WORD wDevID, WINE_WAVEOUT_INSTANCE* wwo, DWORD dwParam)
1488
 
{
1489
 
    float left;
1490
 
    float right;
1491
 
    
1492
 
    if (wDevID >= MAX_WAVEOUTDRV)
1493
 
    {
1494
 
        WARN("bad device ID !\n");
1495
 
        return MMSYSERR_BADDEVICEID;
1496
 
    }
1497
 
 
1498
 
    left  = LOWORD(dwParam) / 65535.0f;
1499
 
    right = HIWORD(dwParam) / 65535.0f;
1500
 
    
1501
 
    TRACE("(%u, %p, %08x);\n", wDevID, wwo, dwParam);
1502
 
 
1503
 
    if (wwo)
1504
 
        AudioUnit_SetVolume(wwo->audioUnit, left, right);
1505
 
    else
1506
 
    {
1507
 
        OSSpinLockLock(&WOutDev[wDevID].lock);
1508
 
        LIST_FOR_EACH_ENTRY(wwo, &WOutDev[wDevID].instances, WINE_WAVEOUT_INSTANCE, entry)
1509
 
            AudioUnit_SetVolume(wwo->audioUnit, left, right);
1510
 
        OSSpinLockUnlock(&WOutDev[wDevID].lock);
1511
 
 
1512
 
        WOutDev[wDevID].device_volume = dwParam;
1513
 
    }
1514
 
 
1515
 
    return MMSYSERR_NOERROR;
1516
 
}
1517
 
 
1518
 
/**************************************************************************
1519
 
*                               wodGetNumDevs                   [internal]
1520
 
*/
1521
 
static DWORD wodGetNumDevs(void)
1522
 
{
1523
 
    TRACE("\n");
1524
 
    return MAX_WAVEOUTDRV;
1525
 
}
1526
 
 
1527
 
/**************************************************************************
1528
 
*                              wodDevInterfaceSize             [internal]
1529
 
*/
1530
 
static DWORD wodDevInterfaceSize(UINT wDevID, LPDWORD dwParam1)
1531
 
{
1532
 
    TRACE("(%u, %p)\n", wDevID, dwParam1);
1533
 
    
1534
 
    *dwParam1 = MultiByteToWideChar(CP_UNIXCP, 0, WOutDev[wDevID].cadev->interface_name, -1,
1535
 
                                    NULL, 0 ) * sizeof(WCHAR);
1536
 
    return MMSYSERR_NOERROR;
1537
 
}
1538
 
 
1539
 
/**************************************************************************
1540
 
*                              wodDevInterface                 [internal]
1541
 
*/
1542
 
static DWORD wodDevInterface(UINT wDevID, PWCHAR dwParam1, DWORD dwParam2)
1543
 
{
1544
 
    TRACE("\n");
1545
 
    if (dwParam2 >= MultiByteToWideChar(CP_UNIXCP, 0, WOutDev[wDevID].cadev->interface_name, -1,
1546
 
                                        NULL, 0 ) * sizeof(WCHAR))
1547
 
    {
1548
 
        MultiByteToWideChar(CP_UNIXCP, 0, WOutDev[wDevID].cadev->interface_name, -1,
1549
 
                            dwParam1, dwParam2 / sizeof(WCHAR));
1550
 
        return MMSYSERR_NOERROR;
1551
 
    }
1552
 
    return MMSYSERR_INVALPARAM;
1553
 
}
1554
 
 
1555
 
/**************************************************************************
1556
 
 *                              widDsCreate                     [internal]
1557
 
 */
1558
 
static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv)
1559
 
{
1560
 
    TRACE("(%d,%p)\n",wDevID,drv);
1561
 
 
1562
 
    FIXME("DirectSound not implemented\n");
1563
 
    FIXME("The (slower) DirectSound HEL mode will be used instead.\n");
1564
 
    return MMSYSERR_NOTSUPPORTED;
1565
 
}
1566
 
 
1567
 
/**************************************************************************
1568
 
*                              wodDsDesc                 [internal]
1569
 
*/
1570
 
static DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc)
1571
 
{
1572
 
    /* The DirectSound HEL will automatically wrap a non-DirectSound-capable
1573
 
     * driver in a DirectSound adaptor, thus allowing the driver to be used by
1574
 
     * DirectSound clients.  However, it only does this if we respond
1575
 
     * successfully to the DRV_QUERYDSOUNDDESC message.  It's enough to fill in
1576
 
     * the driver and device names of the description output parameter. */
1577
 
    *desc = WOutDev[wDevID].cadev->ds_desc;
1578
 
    return MMSYSERR_NOERROR;
1579
 
}
1580
 
 
1581
 
/**************************************************************************
1582
 
*                               wodMessage (WINECOREAUDIO.7)
1583
 
*/
1584
 
DWORD WINAPI CoreAudio_wodMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser,
1585
 
                                  DWORD_PTR dwParam1, DWORD_PTR dwParam2)
1586
 
{
1587
 
    WINE_WAVEOUT_INSTANCE* wwo = (WINE_WAVEOUT_INSTANCE*)dwUser;
1588
 
 
1589
 
    TRACE("(%u, %s, %p, %p, %p);\n",
1590
 
          wDevID, getMessage(wMsg), (void*)dwUser, (void*)dwParam1, (void*)dwParam2);
1591
 
    
1592
 
    switch (wMsg) {
1593
 
        case DRVM_INIT:
1594
 
        case DRVM_EXIT:
1595
 
        case DRVM_ENABLE:
1596
 
        case DRVM_DISABLE:
1597
 
            
1598
 
            /* FIXME: Pretend this is supported */
1599
 
            return 0;
1600
 
        case WODM_OPEN:         return wodOpen(wDevID, (WINE_WAVEOUT_INSTANCE**)dwUser, (LPWAVEOPENDESC) dwParam1, dwParam2);
1601
 
        case WODM_CLOSE:        return wodClose(wDevID, wwo);
1602
 
        case WODM_WRITE:        return wodWrite(wDevID, wwo, (LPWAVEHDR) dwParam1, dwParam2);
1603
 
        case WODM_PAUSE:        return wodPause(wDevID, wwo);
1604
 
        case WODM_GETPOS:       return wodGetPosition(wDevID, wwo, (LPMMTIME) dwParam1, dwParam2);
1605
 
        case WODM_BREAKLOOP:    return wodBreakLoop(wDevID, wwo);
1606
 
        case WODM_PREPARE:      return wodPrepare(wDevID, wwo, (LPWAVEHDR)dwParam1, dwParam2);
1607
 
        case WODM_UNPREPARE:    return wodUnprepare(wDevID, wwo, (LPWAVEHDR)dwParam1, dwParam2);
1608
 
            
1609
 
        case WODM_GETDEVCAPS:   return wodGetDevCaps(wDevID, (LPWAVEOUTCAPSW) dwParam1, dwParam2);
1610
 
        case WODM_GETNUMDEVS:   return wodGetNumDevs();  
1611
 
            
1612
 
        case WODM_GETPITCH:         
1613
 
        case WODM_SETPITCH:        
1614
 
        case WODM_GETPLAYBACKRATE:      
1615
 
        case WODM_SETPLAYBACKRATE:      return MMSYSERR_NOTSUPPORTED;
1616
 
        case WODM_GETVOLUME:    return wodGetVolume(wDevID, wwo, (LPDWORD)dwParam1);
1617
 
        case WODM_SETVOLUME:    return wodSetVolume(wDevID, wwo, dwParam1);
1618
 
        case WODM_RESTART:      return wodRestart(wDevID, wwo);
1619
 
        case WODM_RESET:        return wodReset(wDevID, wwo);
1620
 
            
1621
 
        case DRV_QUERYDEVICEINTERFACESIZE:  return wodDevInterfaceSize (wDevID, (LPDWORD)dwParam1);
1622
 
        case DRV_QUERYDEVICEINTERFACE:      return wodDevInterface (wDevID, (PWCHAR)dwParam1, dwParam2);
1623
 
        case DRV_QUERYDSOUNDIFACE:  return wodDsCreate  (wDevID, (PIDSDRIVER*)dwParam1);
1624
 
        case DRV_QUERYDSOUNDDESC:   return wodDsDesc    (wDevID, (PDSDRIVERDESC)dwParam1);
1625
 
            
1626
 
        default:
1627
 
            FIXME("unknown message %d!\n", wMsg);
1628
 
    }
1629
 
    
1630
 
    return MMSYSERR_NOTSUPPORTED;
1631
 
}
1632
 
 
1633
 
/*======================================================================*
1634
 
*                  Low level DSOUND implementation                      *
1635
 
*======================================================================*/
1636
 
 
1637
 
typedef struct IDsDriverImpl IDsDriverImpl;
1638
 
typedef struct IDsDriverBufferImpl IDsDriverBufferImpl;
1639
 
 
1640
 
struct IDsDriverImpl
1641
 
{
1642
 
    /* IUnknown fields */
1643
 
    const IDsDriverVtbl *lpVtbl;
1644
 
    DWORD               ref;
1645
 
    /* IDsDriverImpl fields */
1646
 
    UINT                wDevID;
1647
 
    IDsDriverBufferImpl*primary;
1648
 
};
1649
 
 
1650
 
struct IDsDriverBufferImpl
1651
 
{
1652
 
    /* IUnknown fields */
1653
 
    const IDsDriverBufferVtbl *lpVtbl;
1654
 
    DWORD ref;
1655
 
    /* IDsDriverBufferImpl fields */
1656
 
    IDsDriverImpl* drv;
1657
 
    DWORD buflen;
1658
 
};
1659
 
 
1660
 
 
1661
 
/*
1662
 
    CoreAudio IO threaded callback,
1663
 
    we can't call Wine debug channels, critical section or anything using NtCurrentTeb here.
1664
 
*/
1665
 
OSStatus CoreAudio_woAudioUnitIOProc(void *inRefCon, 
1666
 
                                     AudioUnitRenderActionFlags *ioActionFlags, 
1667
 
                                     const AudioTimeStamp *inTimeStamp, 
1668
 
                                     UInt32 inBusNumber, 
1669
 
                                     UInt32 inNumberFrames, 
1670
 
                                     AudioBufferList *ioData)
1671
 
{
1672
 
    UInt32 buffer;
1673
 
    WINE_WAVEOUT_INSTANCE* wwo = (WINE_WAVEOUT_INSTANCE*)inRefCon;
1674
 
    int needNotify = 0;
1675
 
 
1676
 
    unsigned int dataNeeded = ioData->mBuffers[0].mDataByteSize;
1677
 
    unsigned int dataProvided = 0;
1678
 
 
1679
 
    OSSpinLockLock(&wwo->lock);
1680
 
 
1681
 
    /* We might have been called before wwo has been completely filled out by
1682
 
     * wodOpen, or while it's being closed in wodClose.  We have to do nothing
1683
 
     * in that case.  The check of wwo->state below ensures that. */
1684
 
    while (dataNeeded > 0 && wwo->state == WINE_WS_PLAYING && wwo->lpPlayPtr)
1685
 
    {
1686
 
        unsigned int available = wwo->lpPlayPtr->dwBufferLength - wwo->dwPartialOffset;
1687
 
        unsigned int toCopy;
1688
 
 
1689
 
        if (available >= dataNeeded)
1690
 
            toCopy = dataNeeded;
1691
 
        else
1692
 
            toCopy = available;
1693
 
 
1694
 
        if (toCopy > 0)
1695
 
        {
1696
 
            memcpy((char*)ioData->mBuffers[0].mData + dataProvided,
1697
 
                wwo->lpPlayPtr->lpData + wwo->dwPartialOffset, toCopy);
1698
 
            wwo->dwPartialOffset += toCopy;
1699
 
            wwo->dwPlayedTotal += toCopy;
1700
 
            dataProvided += toCopy;
1701
 
            dataNeeded -= toCopy;
1702
 
            available -= toCopy;
1703
 
        }
1704
 
 
1705
 
        if (available == 0)
1706
 
        {
1707
 
            wodHelper_PlayPtrNext(wwo);
1708
 
            needNotify = 1;
1709
 
        }
1710
 
    }
1711
 
    ioData->mBuffers[0].mDataByteSize = dataProvided;
1712
 
 
1713
 
    OSSpinLockUnlock(&wwo->lock);
1714
 
 
1715
 
    /* We can't provide any more wave data.  Fill the rest with silence. */
1716
 
    if (dataNeeded > 0)
1717
 
    {
1718
 
        if (!dataProvided)
1719
 
            *ioActionFlags |= kAudioUnitRenderAction_OutputIsSilence;
1720
 
        memset((char*)ioData->mBuffers[0].mData + dataProvided, 0, dataNeeded);
1721
 
        dataProvided += dataNeeded;
1722
 
        dataNeeded = 0;
1723
 
    }
1724
 
 
1725
 
    /* We only fill buffer 0.  Set any others that might be requested to 0. */
1726
 
    for (buffer = 1; buffer < ioData->mNumberBuffers; buffer++)
1727
 
    {
1728
 
        memset(ioData->mBuffers[buffer].mData, 0, ioData->mBuffers[buffer].mDataByteSize);
1729
 
    }
1730
 
 
1731
 
    if (needNotify) wodSendNotifyCompletionsMessage(wwo);
1732
 
    return noErr;
1733
 
}
1734
 
 
1735
 
 
1736
 
/*======================================================================*
1737
 
 *                  Low level WAVE IN implementation                    *
1738
 
 *======================================================================*/
1739
 
 
1740
 
/**************************************************************************
1741
 
 *                      widNotifyClient                 [internal]
1742
 
 */
1743
 
static void widNotifyClient(WINE_WAVEIN* wwi, WORD wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
1744
 
{
1745
 
    TRACE("wMsg = 0x%04x dwParm1 = %04lX dwParam2 = %04lX\n", wMsg, dwParam1, dwParam2);
1746
 
 
1747
 
    switch (wMsg)
1748
 
    {
1749
 
        case WIM_OPEN:
1750
 
        case WIM_CLOSE:
1751
 
        case WIM_DATA:
1752
 
            DriverCallback(wwi->waveDesc.dwCallback, wwi->wFlags,
1753
 
                           (HDRVR)wwi->waveDesc.hWave, wMsg, wwi->waveDesc.dwInstance,
1754
 
                           dwParam1, dwParam2);
1755
 
            break;
1756
 
        default:
1757
 
            FIXME("Unknown callback message %u\n", wMsg);
1758
 
    }
1759
 
}
1760
 
 
1761
 
 
1762
 
/**************************************************************************
1763
 
 *                      widHelper_NotifyCompletions              [internal]
1764
 
 */
1765
 
static void widHelper_NotifyCompletions(WINE_WAVEIN* wwi)
1766
 
{
1767
 
    LPWAVEHDR       lpWaveHdr;
1768
 
    LPWAVEHDR       lpFirstDoneWaveHdr = NULL;
1769
 
    LPWAVEHDR       lpLastDoneWaveHdr = NULL;
1770
 
 
1771
 
    OSSpinLockLock(&wwi->lock);
1772
 
 
1773
 
    /* First, excise all of the done headers from the queue into
1774
 
     * a free-standing list. */
1775
 
 
1776
 
    /* Start from lpQueuePtr and keep notifying until:
1777
 
        * - we hit an unfilled wavehdr
1778
 
        * - we hit the end of the list
1779
 
        */
1780
 
    for (
1781
 
        lpWaveHdr = wwi->lpQueuePtr;
1782
 
        lpWaveHdr &&
1783
 
            lpWaveHdr->dwBytesRecorded >= lpWaveHdr->dwBufferLength;
1784
 
        lpWaveHdr = lpWaveHdr->lpNext
1785
 
        )
1786
 
    {
1787
 
        if (!lpFirstDoneWaveHdr)
1788
 
            lpFirstDoneWaveHdr = lpWaveHdr;
1789
 
        lpLastDoneWaveHdr = lpWaveHdr;
1790
 
    }
1791
 
 
1792
 
    if (lpLastDoneWaveHdr)
1793
 
    {
1794
 
        wwi->lpQueuePtr = lpLastDoneWaveHdr->lpNext;
1795
 
        lpLastDoneWaveHdr->lpNext = NULL;
1796
 
    }
1797
 
 
1798
 
    OSSpinLockUnlock(&wwi->lock);
1799
 
 
1800
 
    /* Now, send the "done" notification for each header in our list. */
1801
 
    lpWaveHdr = lpFirstDoneWaveHdr;
1802
 
    while (lpWaveHdr)
1803
 
    {
1804
 
        LPWAVEHDR lpNext = lpWaveHdr->lpNext;
1805
 
 
1806
 
        lpWaveHdr->lpNext = NULL;
1807
 
        lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
1808
 
        lpWaveHdr->dwFlags |= WHDR_DONE;
1809
 
        widNotifyClient(wwi, WIM_DATA, (DWORD_PTR)lpWaveHdr, 0);
1810
 
 
1811
 
        lpWaveHdr = lpNext;
1812
 
    }
1813
 
}
1814
 
 
1815
 
 
1816
 
/**************************************************************************
1817
 
 *                      widGetDevCaps                           [internal]
1818
 
 */
1819
 
static DWORD widGetDevCaps(WORD wDevID, LPWAVEINCAPSW lpCaps, DWORD dwSize)
1820
 
{
1821
 
    TRACE("(%u, %p, %u);\n", wDevID, lpCaps, dwSize);
1822
 
 
1823
 
    if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
1824
 
 
1825
 
    if (wDevID >= MAX_WAVEINDRV)
1826
 
    {
1827
 
        TRACE("MAX_WAVEINDRV reached !\n");
1828
 
        return MMSYSERR_BADDEVICEID;
1829
 
    }
1830
 
 
1831
 
    memcpy(lpCaps, &WInDev[wDevID].caps, min(dwSize, sizeof(*lpCaps)));
1832
 
    return MMSYSERR_NOERROR;
1833
 
}
1834
 
 
1835
 
 
1836
 
/**************************************************************************
1837
 
 *                    widHelper_DestroyAudioBufferList           [internal]
1838
 
 * Convenience function to dispose of our audio buffers
1839
 
 */
1840
 
static void widHelper_DestroyAudioBufferList(AudioBufferList* list)
1841
 
{
1842
 
    if (list)
1843
 
    {
1844
 
        UInt32 i;
1845
 
        for (i = 0; i < list->mNumberBuffers; i++)
1846
 
        {
1847
 
            if (list->mBuffers[i].mData)
1848
 
                HeapFree(GetProcessHeap(), 0, list->mBuffers[i].mData);
1849
 
        }
1850
 
        HeapFree(GetProcessHeap(), 0, list);
1851
 
    }
1852
 
}
1853
 
 
1854
 
 
1855
 
#define AUDIOBUFFERLISTSIZE(numBuffers) (offsetof(AudioBufferList, mBuffers) + (numBuffers) * sizeof(AudioBuffer))
1856
 
 
1857
 
/**************************************************************************
1858
 
 *                    widHelper_AllocateAudioBufferList          [internal]
1859
 
 * Convenience function to allocate our audio buffers
1860
 
 */
1861
 
static AudioBufferList* widHelper_AllocateAudioBufferList(UInt32 numChannels, UInt32 bitsPerChannel, UInt32 bufferFrames, BOOL interleaved)
1862
 
{
1863
 
    UInt32                      numBuffers;
1864
 
    UInt32                      channelsPerFrame;
1865
 
    UInt32                      bytesPerFrame;
1866
 
    UInt32                      bytesPerBuffer;
1867
 
    AudioBufferList*            list;
1868
 
    UInt32                      i;
1869
 
 
1870
 
    if (interleaved)
1871
 
    {
1872
 
        /* For interleaved audio, we allocate one buffer for all channels. */
1873
 
        numBuffers = 1;
1874
 
        channelsPerFrame = numChannels;
1875
 
    }
1876
 
    else
1877
 
    {
1878
 
        numBuffers = numChannels;
1879
 
        channelsPerFrame = 1;
1880
 
    }
1881
 
 
1882
 
    bytesPerFrame = bitsPerChannel * channelsPerFrame / 8;
1883
 
    bytesPerBuffer = bytesPerFrame * bufferFrames;
1884
 
 
1885
 
    list = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, AUDIOBUFFERLISTSIZE(numBuffers));
1886
 
    if (list == NULL)
1887
 
        return NULL;
1888
 
 
1889
 
    list->mNumberBuffers = numBuffers;
1890
 
    for (i = 0; i < numBuffers; ++i)
1891
 
    {
1892
 
        list->mBuffers[i].mNumberChannels = channelsPerFrame;
1893
 
        list->mBuffers[i].mDataByteSize = bytesPerBuffer;
1894
 
        list->mBuffers[i].mData = HeapAlloc(GetProcessHeap(), 0, bytesPerBuffer);
1895
 
        if (list->mBuffers[i].mData == NULL)
1896
 
        {
1897
 
            widHelper_DestroyAudioBufferList(list);
1898
 
            return NULL;
1899
 
        }
1900
 
    }
1901
 
    return list;
1902
 
}
1903
 
 
1904
 
 
1905
 
/**************************************************************************
1906
 
 *                              widOpen                         [internal]
1907
 
 */
1908
 
static DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
1909
 
{
1910
 
    WINE_WAVEIN*    wwi;
1911
 
    UInt32          frameCount;
1912
 
 
1913
 
    TRACE("(%u, %p, %08X);\n", wDevID, lpDesc, dwFlags);
1914
 
    if (lpDesc == NULL)
1915
 
    {
1916
 
        WARN("Invalid Parameter !\n");
1917
 
        return MMSYSERR_INVALPARAM;
1918
 
    }
1919
 
    if (wDevID >= MAX_WAVEINDRV)
1920
 
    {
1921
 
        TRACE ("MAX_WAVEINDRV reached !\n");
1922
 
        return MMSYSERR_BADDEVICEID;
1923
 
    }
1924
 
 
1925
 
    TRACE("Format: tag=%04X nChannels=%d nSamplesPerSec=%d wBitsPerSample=%d !\n",
1926
 
          lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
1927
 
          lpDesc->lpFormat->nSamplesPerSec, lpDesc->lpFormat->wBitsPerSample);
1928
 
 
1929
 
    if (!supportedFormat(lpDesc->lpFormat) ||
1930
 
        lpDesc->lpFormat->nSamplesPerSec != AudioUnit_GetInputDeviceSampleRate()
1931
 
        )
1932
 
    {
1933
 
        WARN("Bad format: tag=%04X nChannels=%d nSamplesPerSec=%d wBitsPerSample=%d !\n",
1934
 
             lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
1935
 
             lpDesc->lpFormat->nSamplesPerSec, lpDesc->lpFormat->wBitsPerSample);
1936
 
        return WAVERR_BADFORMAT;
1937
 
    }
1938
 
 
1939
 
    if (dwFlags & WAVE_FORMAT_QUERY)
1940
 
    {
1941
 
        TRACE("Query format: tag=%04X nChannels=%d nSamplesPerSec=%d !\n",
1942
 
              lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
1943
 
              lpDesc->lpFormat->nSamplesPerSec);
1944
 
        return MMSYSERR_NOERROR;
1945
 
    }
1946
 
 
1947
 
    /* nBlockAlign and nAvgBytesPerSec are output variables for dsound */
1948
 
    if (lpDesc->lpFormat->nBlockAlign != lpDesc->lpFormat->nChannels*lpDesc->lpFormat->wBitsPerSample/8) {
1949
 
        lpDesc->lpFormat->nBlockAlign  = lpDesc->lpFormat->nChannels*lpDesc->lpFormat->wBitsPerSample/8;
1950
 
        WARN("Fixing nBlockAlign\n");
1951
 
    }
1952
 
    if (lpDesc->lpFormat->nAvgBytesPerSec!= lpDesc->lpFormat->nSamplesPerSec*lpDesc->lpFormat->nBlockAlign) {
1953
 
        lpDesc->lpFormat->nAvgBytesPerSec = lpDesc->lpFormat->nSamplesPerSec*lpDesc->lpFormat->nBlockAlign;
1954
 
        WARN("Fixing nAvgBytesPerSec\n");
1955
 
    }
1956
 
 
1957
 
    wwi = &WInDev[wDevID];
1958
 
    if (!OSSpinLockTry(&wwi->lock))
1959
 
        return MMSYSERR_ALLOCATED;
1960
 
 
1961
 
    if (wwi->state != WINE_WS_CLOSED)
1962
 
    {
1963
 
        OSSpinLockUnlock(&wwi->lock);
1964
 
        return MMSYSERR_ALLOCATED;
1965
 
    }
1966
 
 
1967
 
    wwi->state = WINE_WS_STOPPED;
1968
 
    wwi->wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
1969
 
 
1970
 
    wwi->waveDesc = *lpDesc;
1971
 
    copyFormat(lpDesc->lpFormat, &wwi->format);
1972
 
 
1973
 
    wwi->dwTotalRecorded = 0;
1974
 
 
1975
 
    wwi->trace_on = TRACE_ON(wave);
1976
 
    wwi->warn_on  = WARN_ON(wave);
1977
 
    wwi->err_on   = ERR_ON(wave);
1978
 
 
1979
 
    if (!AudioUnit_CreateInputUnit(wwi, &wwi->audioUnit,
1980
 
        wwi->format.wf.nChannels, wwi->format.wf.nSamplesPerSec,
1981
 
        wwi->format.wBitsPerSample, &frameCount))
1982
 
    {
1983
 
        OSSpinLockUnlock(&wwi->lock);
1984
 
        ERR("AudioUnit_CreateInputUnit failed\n");
1985
 
        return MMSYSERR_ERROR;
1986
 
    }
1987
 
 
1988
 
    /* Allocate our audio buffers */
1989
 
    wwi->bufferList = widHelper_AllocateAudioBufferList(wwi->format.wf.nChannels,
1990
 
        wwi->format.wBitsPerSample, frameCount, TRUE);
1991
 
    if (wwi->bufferList == NULL)
1992
 
    {
1993
 
        AudioUnitUninitialize(wwi->audioUnit);
1994
 
        AudioUnit_CloseAudioUnit(wwi->audioUnit);
1995
 
        OSSpinLockUnlock(&wwi->lock);
1996
 
        ERR("Failed to allocate buffer list\n");
1997
 
        return MMSYSERR_NOMEM;
1998
 
    }
1999
 
 
2000
 
    /* Keep a copy of the buffer list structure (but not the buffers themselves)
2001
 
     * in case AudioUnitRender clobbers the original, as it tends to do. */
2002
 
    wwi->bufferListCopy = HeapAlloc(GetProcessHeap(), 0, AUDIOBUFFERLISTSIZE(wwi->bufferList->mNumberBuffers));
2003
 
    if (wwi->bufferListCopy == NULL)
2004
 
    {
2005
 
        widHelper_DestroyAudioBufferList(wwi->bufferList);
2006
 
        AudioUnitUninitialize(wwi->audioUnit);
2007
 
        AudioUnit_CloseAudioUnit(wwi->audioUnit);
2008
 
        OSSpinLockUnlock(&wwi->lock);
2009
 
        ERR("Failed to allocate buffer list copy\n");
2010
 
        return MMSYSERR_NOMEM;
2011
 
    }
2012
 
    memcpy(wwi->bufferListCopy, wwi->bufferList, AUDIOBUFFERLISTSIZE(wwi->bufferList->mNumberBuffers));
2013
 
 
2014
 
    OSSpinLockUnlock(&wwi->lock);
2015
 
 
2016
 
    widNotifyClient(wwi, WIM_OPEN, 0L, 0L);
2017
 
 
2018
 
    return MMSYSERR_NOERROR;
2019
 
}
2020
 
 
2021
 
 
2022
 
/**************************************************************************
2023
 
 *                              widClose                        [internal]
2024
 
 */
2025
 
static DWORD widClose(WORD wDevID)
2026
 
{
2027
 
    DWORD           ret = MMSYSERR_NOERROR;
2028
 
    WINE_WAVEIN*    wwi;
2029
 
    OSStatus        err;
2030
 
 
2031
 
    TRACE("(%u);\n", wDevID);
2032
 
 
2033
 
    if (wDevID >= MAX_WAVEINDRV)
2034
 
    {
2035
 
        WARN("bad device ID !\n");
2036
 
        return MMSYSERR_BADDEVICEID;
2037
 
    }
2038
 
 
2039
 
    wwi = &WInDev[wDevID];
2040
 
    OSSpinLockLock(&wwi->lock);
2041
 
    if (wwi->state == WINE_WS_CLOSED || wwi->state == WINE_WS_CLOSING)
2042
 
    {
2043
 
        WARN("Device already closed.\n");
2044
 
        ret = MMSYSERR_INVALHANDLE;
2045
 
    }
2046
 
    else if (wwi->lpQueuePtr)
2047
 
    {
2048
 
        WARN("Buffers in queue.\n");
2049
 
        ret = WAVERR_STILLPLAYING;
2050
 
    }
2051
 
    else
2052
 
    {
2053
 
        wwi->state = WINE_WS_CLOSING;
2054
 
    }
2055
 
 
2056
 
    OSSpinLockUnlock(&wwi->lock);
2057
 
 
2058
 
    if (ret != MMSYSERR_NOERROR)
2059
 
        return ret;
2060
 
 
2061
 
 
2062
 
    /* Clean up and close the audio unit.  This has to be done without
2063
 
     * wwi->lock being held to avoid deadlock.  AudioUnitUninitialize will
2064
 
     * grab an internal Core Audio lock while waiting for the device work
2065
 
     * thread to exit.  Meanwhile the device work thread may be holding
2066
 
     * that lock and trying to grab the wwi->lock in the callback. */
2067
 
    err = AudioUnitUninitialize(wwi->audioUnit);
2068
 
    if (err)
2069
 
        ERR("AudioUnitUninitialize return %s\n", wine_dbgstr_fourcc(err));
2070
 
 
2071
 
    if (!AudioUnit_CloseAudioUnit(wwi->audioUnit))
2072
 
        ERR("Can't close AudioUnit\n");
2073
 
 
2074
 
 
2075
 
    OSSpinLockLock(&wwi->lock);
2076
 
    assert(wwi->state == WINE_WS_CLOSING);
2077
 
 
2078
 
    /* Dellocate our audio buffers */
2079
 
    widHelper_DestroyAudioBufferList(wwi->bufferList);
2080
 
    wwi->bufferList = NULL;
2081
 
    HeapFree(GetProcessHeap(), 0, wwi->bufferListCopy);
2082
 
    wwi->bufferListCopy = NULL;
2083
 
 
2084
 
    wwi->audioUnit = NULL;
2085
 
    wwi->state = WINE_WS_CLOSED;
2086
 
    OSSpinLockUnlock(&wwi->lock);
2087
 
 
2088
 
    widNotifyClient(wwi, WIM_CLOSE, 0L, 0L);
2089
 
 
2090
 
    return ret;
2091
 
}
2092
 
 
2093
 
 
2094
 
/**************************************************************************
2095
 
 *                              widAddBuffer            [internal]
2096
 
 */
2097
 
static DWORD widAddBuffer(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
2098
 
{
2099
 
    DWORD           ret = MMSYSERR_NOERROR;
2100
 
    WINE_WAVEIN*    wwi;
2101
 
 
2102
 
    TRACE("(%u, %p, %08X);\n", wDevID, lpWaveHdr, dwSize);
2103
 
 
2104
 
    if (wDevID >= MAX_WAVEINDRV)
2105
 
    {
2106
 
        WARN("invalid device ID\n");
2107
 
        return MMSYSERR_INVALHANDLE;
2108
 
    }
2109
 
    if (!(lpWaveHdr->dwFlags & WHDR_PREPARED))
2110
 
    {
2111
 
        TRACE("never been prepared !\n");
2112
 
        return WAVERR_UNPREPARED;
2113
 
    }
2114
 
    if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
2115
 
    {
2116
 
        TRACE("header already in use !\n");
2117
 
        return WAVERR_STILLPLAYING;
2118
 
    }
2119
 
 
2120
 
    wwi = &WInDev[wDevID];
2121
 
    OSSpinLockLock(&wwi->lock);
2122
 
 
2123
 
    if (wwi->state == WINE_WS_CLOSED || wwi->state == WINE_WS_CLOSING)
2124
 
    {
2125
 
        WARN("Trying to add buffer to closed device.\n");
2126
 
        ret = MMSYSERR_INVALHANDLE;
2127
 
    }
2128
 
    else
2129
 
    {
2130
 
        LPWAVEHDR* wh;
2131
 
 
2132
 
        lpWaveHdr->dwFlags |= WHDR_INQUEUE;
2133
 
        lpWaveHdr->dwFlags &= ~WHDR_DONE;
2134
 
        lpWaveHdr->dwBytesRecorded = 0;
2135
 
        lpWaveHdr->lpNext = NULL;
2136
 
 
2137
 
        /* insert buffer at end of queue */
2138
 
        for (wh = &(wwi->lpQueuePtr); *wh; wh = &((*wh)->lpNext))
2139
 
            /* Do nothing */;
2140
 
        *wh = lpWaveHdr;
2141
 
    }
2142
 
 
2143
 
    OSSpinLockUnlock(&wwi->lock);
2144
 
 
2145
 
    return ret;
2146
 
}
2147
 
 
2148
 
 
2149
 
/**************************************************************************
2150
 
 *                      widStart                                [internal]
2151
 
 */
2152
 
static DWORD widStart(WORD wDevID)
2153
 
{
2154
 
    DWORD           ret = MMSYSERR_NOERROR;
2155
 
    WINE_WAVEIN*    wwi;
2156
 
 
2157
 
    TRACE("(%u);\n", wDevID);
2158
 
    if (wDevID >= MAX_WAVEINDRV)
2159
 
    {
2160
 
        WARN("invalid device ID\n");
2161
 
        return MMSYSERR_INVALHANDLE;
2162
 
    }
2163
 
 
2164
 
    /* The order of the following operations is important since we can't hold
2165
 
     * the mutex while we make an Audio Unit call.  Set the PLAYING state
2166
 
     * before starting the Audio Unit.  In widStop, the order is reversed.
2167
 
     * This guarantees that we can't get into a situation where the state is
2168
 
     * PLAYING but the Audio Unit isn't running.  Although we can be in STOPPED
2169
 
     * state with the Audio Unit still running, that's harmless because the
2170
 
     * input callback will just throw away the sound data.
2171
 
     */
2172
 
    wwi = &WInDev[wDevID];
2173
 
    OSSpinLockLock(&wwi->lock);
2174
 
 
2175
 
    if (wwi->state == WINE_WS_CLOSED || wwi->state == WINE_WS_CLOSING)
2176
 
    {
2177
 
        WARN("Trying to start closed device.\n");
2178
 
        ret = MMSYSERR_INVALHANDLE;
2179
 
    }
2180
 
    else
2181
 
        wwi->state = WINE_WS_PLAYING;
2182
 
 
2183
 
    OSSpinLockUnlock(&wwi->lock);
2184
 
 
2185
 
    if (ret == MMSYSERR_NOERROR)
2186
 
    {
2187
 
        /* Start pulling for audio data */
2188
 
        OSStatus err = AudioOutputUnitStart(wwi->audioUnit);
2189
 
        if (err != noErr)
2190
 
            ERR("Failed to start AU: %08lx\n", err);
2191
 
 
2192
 
        TRACE("Recording started...\n");
2193
 
    }
2194
 
 
2195
 
    return ret;
2196
 
}
2197
 
 
2198
 
 
2199
 
/**************************************************************************
2200
 
 *                      widStop                                 [internal]
2201
 
 */
2202
 
static DWORD widStop(WORD wDevID)
2203
 
{
2204
 
    DWORD           ret = MMSYSERR_NOERROR;
2205
 
    WINE_WAVEIN*    wwi;
2206
 
    WAVEHDR*        lpWaveHdr = NULL;
2207
 
    OSStatus        err;
2208
 
 
2209
 
    TRACE("(%u);\n", wDevID);
2210
 
    if (wDevID >= MAX_WAVEINDRV)
2211
 
    {
2212
 
        WARN("invalid device ID\n");
2213
 
        return MMSYSERR_INVALHANDLE;
2214
 
    }
2215
 
 
2216
 
    wwi = &WInDev[wDevID];
2217
 
 
2218
 
    /* The order of the following operations is important since we can't hold
2219
 
     * the mutex while we make an Audio Unit call.  Stop the Audio Unit before
2220
 
     * setting the STOPPED state.  In widStart, the order is reversed.  This
2221
 
     * guarantees that we can't get into a situation where the state is
2222
 
     * PLAYING but the Audio Unit isn't running.  Although we can be in STOPPED
2223
 
     * state with the Audio Unit still running, that's harmless because the
2224
 
     * input callback will just throw away the sound data.
2225
 
     */
2226
 
    err = AudioOutputUnitStop(wwi->audioUnit);
2227
 
    if (err != noErr)
2228
 
        WARN("Failed to stop AU: %08lx\n", err);
2229
 
 
2230
 
    TRACE("Recording stopped.\n");
2231
 
 
2232
 
    OSSpinLockLock(&wwi->lock);
2233
 
 
2234
 
    if (wwi->state == WINE_WS_CLOSED || wwi->state == WINE_WS_CLOSING)
2235
 
    {
2236
 
        WARN("Trying to stop closed device.\n");
2237
 
        ret = MMSYSERR_INVALHANDLE;
2238
 
    }
2239
 
    else if (wwi->state != WINE_WS_STOPPED)
2240
 
    {
2241
 
        wwi->state = WINE_WS_STOPPED;
2242
 
        /* If there's a buffer in progress, it's done.  Remove it from the
2243
 
         * queue so that we can return it to the app, below. */
2244
 
        if (wwi->lpQueuePtr)
2245
 
        {
2246
 
            lpWaveHdr = wwi->lpQueuePtr;
2247
 
            wwi->lpQueuePtr = lpWaveHdr->lpNext;
2248
 
        }
2249
 
    }
2250
 
 
2251
 
    OSSpinLockUnlock(&wwi->lock);
2252
 
 
2253
 
    if (lpWaveHdr)
2254
 
    {
2255
 
        lpWaveHdr->lpNext = NULL;
2256
 
        lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
2257
 
        lpWaveHdr->dwFlags |= WHDR_DONE;
2258
 
        widNotifyClient(wwi, WIM_DATA, (DWORD_PTR)lpWaveHdr, 0);
2259
 
    }
2260
 
 
2261
 
    return ret;
2262
 
}
2263
 
 
2264
 
/**************************************************************************
2265
 
 *                      widGetPos                                 [internal]
2266
 
 */
2267
 
static DWORD widGetPos(WORD wDevID, LPMMTIME lpTime, UINT size)
2268
 
{
2269
 
    DWORD                   val;
2270
 
    WINE_WAVEIN*    wwi;
2271
 
 
2272
 
    TRACE("(%u);\n", wDevID);
2273
 
    if (wDevID >= MAX_WAVEINDRV)
2274
 
    {
2275
 
        WARN("invalid device ID\n");
2276
 
        return MMSYSERR_INVALHANDLE;
2277
 
    }
2278
 
 
2279
 
    wwi = &WInDev[wDevID];
2280
 
 
2281
 
    OSSpinLockLock(&WInDev[wDevID].lock);
2282
 
    val = wwi->dwTotalRecorded;
2283
 
    OSSpinLockUnlock(&WInDev[wDevID].lock);
2284
 
 
2285
 
    return bytes_to_mmtime(lpTime, val, &wwi->format);
2286
 
}
2287
 
 
2288
 
/**************************************************************************
2289
 
 *                      widReset                                [internal]
2290
 
 */
2291
 
static DWORD widReset(WORD wDevID)
2292
 
{
2293
 
    DWORD           ret = MMSYSERR_NOERROR;
2294
 
    WINE_WAVEIN*    wwi;
2295
 
    WAVEHDR*        lpWaveHdr = NULL;
2296
 
 
2297
 
    TRACE("(%u);\n", wDevID);
2298
 
    if (wDevID >= MAX_WAVEINDRV)
2299
 
    {
2300
 
        WARN("invalid device ID\n");
2301
 
        return MMSYSERR_INVALHANDLE;
2302
 
    }
2303
 
 
2304
 
    wwi = &WInDev[wDevID];
2305
 
    OSSpinLockLock(&wwi->lock);
2306
 
 
2307
 
    if (wwi->state == WINE_WS_CLOSED || wwi->state == WINE_WS_CLOSING)
2308
 
    {
2309
 
        WARN("Trying to reset a closed device.\n");
2310
 
        ret = MMSYSERR_INVALHANDLE;
2311
 
    }
2312
 
    else
2313
 
    {
2314
 
        lpWaveHdr               = wwi->lpQueuePtr;
2315
 
        wwi->lpQueuePtr         = NULL;
2316
 
        wwi->state              = WINE_WS_STOPPED;
2317
 
        wwi->dwTotalRecorded    = 0;
2318
 
    }
2319
 
 
2320
 
    OSSpinLockUnlock(&wwi->lock);
2321
 
 
2322
 
    if (ret == MMSYSERR_NOERROR)
2323
 
    {
2324
 
        OSStatus err = AudioOutputUnitStop(wwi->audioUnit);
2325
 
        if (err != noErr)
2326
 
            WARN("Failed to stop AU: %08lx\n", err);
2327
 
 
2328
 
        TRACE("Recording stopped.\n");
2329
 
    }
2330
 
 
2331
 
    while (lpWaveHdr)
2332
 
    {
2333
 
        WAVEHDR* lpNext = lpWaveHdr->lpNext;
2334
 
 
2335
 
        lpWaveHdr->lpNext = NULL;
2336
 
        lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
2337
 
        lpWaveHdr->dwFlags |= WHDR_DONE;
2338
 
        widNotifyClient(wwi, WIM_DATA, (DWORD_PTR)lpWaveHdr, 0);
2339
 
 
2340
 
        lpWaveHdr = lpNext;
2341
 
    }
2342
 
 
2343
 
    return ret;
2344
 
}
2345
 
 
2346
 
 
2347
 
/**************************************************************************
2348
 
 *                              widGetNumDevs                   [internal]
2349
 
 */
2350
 
static DWORD widGetNumDevs(void)
2351
 
{
2352
 
    return MAX_WAVEINDRV;
2353
 
}
2354
 
 
2355
 
 
2356
 
/**************************************************************************
2357
 
 *                              widDevInterfaceSize             [internal]
2358
 
 */
2359
 
static DWORD widDevInterfaceSize(UINT wDevID, LPDWORD dwParam1)
2360
 
{
2361
 
    TRACE("(%u, %p)\n", wDevID, dwParam1);
2362
 
 
2363
 
    *dwParam1 = MultiByteToWideChar(CP_UNIXCP, 0, WInDev[wDevID].interface_name, -1,
2364
 
                                    NULL, 0 ) * sizeof(WCHAR);
2365
 
    return MMSYSERR_NOERROR;
2366
 
}
2367
 
 
2368
 
 
2369
 
/**************************************************************************
2370
 
 *                              widDevInterface                 [internal]
2371
 
 */
2372
 
static DWORD widDevInterface(UINT wDevID, PWCHAR dwParam1, DWORD dwParam2)
2373
 
{
2374
 
    if (dwParam2 >= MultiByteToWideChar(CP_UNIXCP, 0, WInDev[wDevID].interface_name, -1,
2375
 
                                        NULL, 0 ) * sizeof(WCHAR))
2376
 
    {
2377
 
        MultiByteToWideChar(CP_UNIXCP, 0, WInDev[wDevID].interface_name, -1,
2378
 
                            dwParam1, dwParam2 / sizeof(WCHAR));
2379
 
        return MMSYSERR_NOERROR;
2380
 
    }
2381
 
    return MMSYSERR_INVALPARAM;
2382
 
}
2383
 
 
2384
 
 
2385
 
/**************************************************************************
2386
 
 *                              widDsCreate                     [internal]
2387
 
 */
2388
 
static DWORD widDsCreate(UINT wDevID, PIDSCDRIVER* drv)
2389
 
{
2390
 
    TRACE("(%d,%p)\n",wDevID,drv);
2391
 
 
2392
 
    FIXME("DirectSoundCapture not implemented\n");
2393
 
    FIXME("The (slower) DirectSound HEL mode will be used instead.\n");
2394
 
    return MMSYSERR_NOTSUPPORTED;
2395
 
}
2396
 
 
2397
 
/**************************************************************************
2398
 
 *                              widDsDesc                       [internal]
2399
 
 */
2400
 
static DWORD widDsDesc(UINT wDevID, PDSDRIVERDESC desc)
2401
 
{
2402
 
    /* The DirectSound HEL will automatically wrap a non-DirectSound-capable
2403
 
     * driver in a DirectSound adaptor, thus allowing the driver to be used by
2404
 
     * DirectSound clients.  However, it only does this if we respond
2405
 
     * successfully to the DRV_QUERYDSOUNDDESC message.  It's enough to fill in
2406
 
     * the driver and device names of the description output parameter. */
2407
 
    memset(desc, 0, sizeof(*desc));
2408
 
    lstrcpynA(desc->szDrvname, "winecoreaudio.drv", sizeof(desc->szDrvname) - 1);
2409
 
    lstrcpynA(desc->szDesc, WInDev[wDevID].interface_name, sizeof(desc->szDesc) - 1);
2410
 
    return MMSYSERR_NOERROR;
2411
 
}
2412
 
 
2413
 
 
2414
 
/**************************************************************************
2415
 
 *                              widMessage (WINECOREAUDIO.6)
2416
 
 */
2417
 
DWORD WINAPI CoreAudio_widMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
2418
 
                            DWORD dwParam1, DWORD dwParam2)
2419
 
{
2420
 
    TRACE("(%u, %04X, %08X, %08X, %08X);\n",
2421
 
            wDevID, wMsg, dwUser, dwParam1, dwParam2);
2422
 
 
2423
 
    switch (wMsg)
2424
 
    {
2425
 
        case DRVM_INIT:
2426
 
        case DRVM_EXIT:
2427
 
        case DRVM_ENABLE:
2428
 
        case DRVM_DISABLE:
2429
 
            /* FIXME: Pretend this is supported */
2430
 
            return 0;
2431
 
        case WIDM_OPEN:             return widOpen          (wDevID, (LPWAVEOPENDESC)dwParam1,  dwParam2);
2432
 
        case WIDM_CLOSE:            return widClose         (wDevID);
2433
 
        case WIDM_ADDBUFFER:        return widAddBuffer     (wDevID, (LPWAVEHDR)dwParam1,       dwParam2);
2434
 
        case WIDM_PREPARE:          return MMSYSERR_NOTSUPPORTED;
2435
 
        case WIDM_UNPREPARE:        return MMSYSERR_NOTSUPPORTED;
2436
 
        case WIDM_GETDEVCAPS:       return widGetDevCaps    (wDevID, (LPWAVEINCAPSW)dwParam1,   dwParam2);
2437
 
        case WIDM_GETNUMDEVS:       return widGetNumDevs    ();
2438
 
        case WIDM_RESET:            return widReset         (wDevID);
2439
 
        case WIDM_START:            return widStart         (wDevID);
2440
 
        case WIDM_STOP:             return widStop          (wDevID);
2441
 
        case WIDM_GETPOS:           return widGetPos        (wDevID, (LPMMTIME)dwParam1, (UINT)dwParam2  );
2442
 
        case DRV_QUERYDEVICEINTERFACESIZE: return widDevInterfaceSize       (wDevID, (LPDWORD)dwParam1);
2443
 
        case DRV_QUERYDEVICEINTERFACE:     return widDevInterface           (wDevID, (PWCHAR)dwParam1, dwParam2);
2444
 
        case DRV_QUERYDSOUNDIFACE:  return widDsCreate   (wDevID, (PIDSCDRIVER*)dwParam1);
2445
 
        case DRV_QUERYDSOUNDDESC:   return widDsDesc     (wDevID, (PDSDRIVERDESC)dwParam1);
2446
 
        default:
2447
 
            FIXME("unknown message %d!\n", wMsg);
2448
 
    }
2449
 
 
2450
 
    return MMSYSERR_NOTSUPPORTED;
2451
 
}
2452
 
 
2453
 
 
2454
 
OSStatus CoreAudio_wiAudioUnitIOProc(void *inRefCon,
2455
 
                                     AudioUnitRenderActionFlags *ioActionFlags,
2456
 
                                     const AudioTimeStamp *inTimeStamp,
2457
 
                                     UInt32 inBusNumber,
2458
 
                                     UInt32 inNumberFrames,
2459
 
                                     AudioBufferList *ioData)
2460
 
{
2461
 
    WINE_WAVEIN*    wwi = (WINE_WAVEIN*)inRefCon;
2462
 
    OSStatus        err = noErr;
2463
 
    BOOL            needNotify = FALSE;
2464
 
    WAVEHDR*        lpStorePtr;
2465
 
    unsigned int    dataToStore;
2466
 
    unsigned int    dataStored = 0;
2467
 
 
2468
 
 
2469
 
    if (wwi->trace_on)
2470
 
        fprintf(stderr, "trace:wave:CoreAudio_wiAudioUnitIOProc (ioActionFlags = %08lx, "
2471
 
            "inTimeStamp = { %f, %x%08x, %f, %x%08x, %08lx }, inBusNumber = %lu, inNumberFrames = %lu)\n",
2472
 
            *ioActionFlags, inTimeStamp->mSampleTime, (DWORD)(inTimeStamp->mHostTime >>32),
2473
 
            (DWORD)inTimeStamp->mHostTime, inTimeStamp->mRateScalar, (DWORD)(inTimeStamp->mWordClockTime >> 32),
2474
 
            (DWORD)inTimeStamp->mWordClockTime, inTimeStamp->mFlags, inBusNumber, inNumberFrames);
2475
 
 
2476
 
    /* Render into audio buffer */
2477
 
    /* FIXME: implement sample rate conversion on input.  This will require
2478
 
     * a different render strategy.  We'll need to buffer the sound data
2479
 
     * received here and pass it off to an AUConverter in another thread. */
2480
 
    err = AudioUnitRender(wwi->audioUnit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, wwi->bufferList);
2481
 
    if (err)
2482
 
    {
2483
 
        if (wwi->err_on)
2484
 
            fprintf(stderr, "err:wave:CoreAudio_wiAudioUnitIOProc AudioUnitRender failed with error %li\n", err);
2485
 
        return err;
2486
 
    }
2487
 
 
2488
 
    /* Copy from audio buffer to the wavehdrs */
2489
 
    dataToStore = wwi->bufferList->mBuffers[0].mDataByteSize;
2490
 
 
2491
 
    OSSpinLockLock(&wwi->lock);
2492
 
 
2493
 
    lpStorePtr = wwi->lpQueuePtr;
2494
 
 
2495
 
    /* We might have been called while the waveIn device is being closed in
2496
 
     * widClose.  We have to do nothing in that case.  The check of wwi->state
2497
 
     * below ensures that. */
2498
 
    while (dataToStore > 0 && wwi->state == WINE_WS_PLAYING && lpStorePtr)
2499
 
    {
2500
 
        unsigned int room = lpStorePtr->dwBufferLength - lpStorePtr->dwBytesRecorded;
2501
 
        unsigned int toCopy;
2502
 
 
2503
 
        if (wwi->trace_on)
2504
 
            fprintf(stderr, "trace:wave:CoreAudio_wiAudioUnitIOProc Looking to store %u bytes to wavehdr %p, which has room for %u\n",
2505
 
                dataToStore, lpStorePtr, room);
2506
 
 
2507
 
        if (room >= dataToStore)
2508
 
            toCopy = dataToStore;
2509
 
        else
2510
 
            toCopy = room;
2511
 
 
2512
 
        if (toCopy > 0)
2513
 
        {
2514
 
            memcpy(lpStorePtr->lpData + lpStorePtr->dwBytesRecorded,
2515
 
                (char*)wwi->bufferList->mBuffers[0].mData + dataStored, toCopy);
2516
 
            lpStorePtr->dwBytesRecorded += toCopy;
2517
 
            wwi->dwTotalRecorded += toCopy;
2518
 
            dataStored += toCopy;
2519
 
            dataToStore -= toCopy;
2520
 
            room -= toCopy;
2521
 
        }
2522
 
 
2523
 
        if (room == 0)
2524
 
        {
2525
 
            lpStorePtr = lpStorePtr->lpNext;
2526
 
            needNotify = TRUE;
2527
 
        }
2528
 
    }
2529
 
 
2530
 
    OSSpinLockUnlock(&wwi->lock);
2531
 
 
2532
 
    /* Restore the audio buffer list structure from backup, in case
2533
 
     * AudioUnitRender clobbered it.  (It modifies mDataByteSize and may even
2534
 
     * give us a different mData buffer to avoid a copy.) */
2535
 
    memcpy(wwi->bufferList, wwi->bufferListCopy, AUDIOBUFFERLISTSIZE(wwi->bufferList->mNumberBuffers));
2536
 
 
2537
 
    if (needNotify) wodSendNotifyInputCompletionsMessage(wwi);
2538
 
    return err;
2539
 
}