Evilly merge tag 'wine-1.5.11' into dsoal
[wine/multimedia.git] / dlls / dsound / dsp / 0022_dsound:_Output_openal_data_to_mmdevapi__try_2.patch
blob8e553c82cd8ba2287d708c2a3946e22ce91f02b8
1 commit c5dd3897f4e1f834402e50c068cae5fa2b82b75c
2 Author: Maarten Lankhorst <m.b.lankhorst@gmail.com>
3 Date: Fri Apr 8 21:07:28 2011 +0200
5 dsound: Output openal data to mmdevapi, try 2
7 added: Kill mmdevapi thread if dsound is dynamically unloaded
9 diff --git a/dlls/dsound/buffer.c b/dlls/dsound/buffer.c
10 index d15c8ce..efa1778 100644
11 --- a/dlls/dsound/buffer.c
12 +++ b/dlls/dsound/buffer.c
13 @@ -113,6 +113,8 @@ static void CALLBACK DS8Buffer_timer(UINT timerID, UINT msg, DWORD_PTR dwUser,
15 DS8Primary *prim = (DS8Primary*)dwUser;
16 DWORD i;
17 + UINT pad;
18 + BYTE *data;
20 EnterCriticalSection(&prim->crst);
21 setALContext(prim->ctx);
22 @@ -177,6 +179,15 @@ static void CALLBACK DS8Buffer_timer(UINT timerID, UINT msg, DWORD_PTR dwUser,
26 + IAudioClient_GetCurrentPadding(prim->dev, &pad);
27 + pad = 2048 - pad;
28 + if (pad)
29 + {
30 + IAudioRenderClient_GetBuffer(prim->render_dev, pad, &data);
31 + palcRenderSamples(prim->parent->device, data, pad);
32 + IAudioRenderClient_ReleaseBuffer(prim->render_dev, pad, 0);
33 + }
35 for (i = 0; i < prim->nnotifies ; )
37 DS8Buffer *buf = prim->notifies[i];
38 @@ -212,25 +223,26 @@ static void CALLBACK DS8Buffer_timer(UINT timerID, UINT msg, DWORD_PTR dwUser,
39 static void DS8Buffer_starttimer(DS8Primary *prim)
41 TIMECAPS time;
42 - ALint refresh = FAKE_REFRESH_COUNT;
43 DWORD triggertime, res = DS_TIME_RES;
44 + INT64 default_period, min_period;
46 if(prim->timer_id)
47 return;
49 timeGetDevCaps(&time, sizeof(TIMECAPS));
50 - palcGetIntegerv(prim->parent->device, ALC_REFRESH, 1, &refresh);
51 + IAudioClient_GetDevicePeriod(prim->dev, &default_period, &min_period);
52 + triggertime = default_period / 10000;
53 getALCError(prim->parent->device);
54 - triggertime = 1000 / refresh;
55 if(triggertime < time.wPeriodMin)
56 triggertime = time.wPeriodMin;
57 - TRACE("Calling timer every %u ms for %i refreshes per second\n", triggertime, refresh);
58 + TRACE("Calling timer every %u ms\n", triggertime);
59 if (res < time.wPeriodMin)
60 res = time.wPeriodMin;
61 if (timeBeginPeriod(res) == TIMERR_NOCANDO)
62 WARN("Could not set minimum resolution, don't expect sound\n");
63 prim->timer_res = res;
64 prim->timer_id = timeSetEvent(triggertime, res, DS8Buffer_timer, (DWORD_PTR)prim, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
65 + IAudioClient_Start(prim->dev);
68 /* Should be called with critsect held and context set.. */
69 @@ -273,7 +285,7 @@ static void DS8Buffer_removenotify(DS8Buffer *buf)
73 -static const char *get_fmtstr_PCM(WAVEFORMATEX *format, WAVEFORMATEX **out)
74 +static const char *get_fmtstr_PCM(const WAVEFORMATEX *format, WAVEFORMATEX **out)
76 *out = HeapAlloc(GetProcessHeap(), 0, sizeof(*format));
77 if(!*out) return NULL;
78 @@ -300,7 +312,7 @@ static const char *get_fmtstr_PCM(WAVEFORMATEX *format, WAVEFORMATEX **out)
79 default: break;
82 - if(format->wBitsPerSample == 16)
83 + else if(format->wBitsPerSample == 16)
85 switch(format->nChannels)
87 @@ -313,6 +325,8 @@ static const char *get_fmtstr_PCM(WAVEFORMATEX *format, WAVEFORMATEX **out)
88 default: break;
91 + else
92 + return NULL;
94 if((format->wBitsPerSample%8) == 0)
95 ERR("Could not get OpenAL format (%d-bit, %d channels)\n",
96 @@ -329,7 +343,7 @@ static const char *get_fmtstr_PCM(WAVEFORMATEX *format, WAVEFORMATEX **out)
97 #define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
98 #define X7DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
100 -static const char *get_fmtstr_EXT(WAVEFORMATEX *format, WAVEFORMATEX **out)
101 +static const char *get_fmtstr_EXT(const WAVEFORMATEX *format, WAVEFORMATEX **out)
103 WAVEFORMATEXTENSIBLE *wfe;
105 @@ -403,6 +417,23 @@ static const char *get_fmtstr_EXT(WAVEFORMATEX *format, WAVEFORMATEX **out)
106 default: break;
109 +#if 1 /* TODO: Ugly freaky hack just to pass tests */
110 + else if(wfe->Samples.wValidBitsPerSample == 24 ||
111 + wfe->Samples.wValidBitsPerSample == 32)
113 + switch(wfe->dwChannelMask)
115 + case MONO: return "AL_FORMAT_MONO_FLOAT32";
116 + case STEREO: return "AL_FORMAT_STEREO_FLOAT32";
117 + case REAR: return "AL_FORMAT_REAR32";
118 + case QUAD: return "AL_FORMAT_QUAD32";
119 + case X5DOT1: return "AL_FORMAT_51CHN32";
120 + case X6DOT1: return "AL_FORMAT_61CHN32";
121 + case X7DOT1: return "AL_FORMAT_71CHN32";
122 + default: break;
125 +#endif
126 else if((wfe->Samples.wValidBitsPerSample%8) == 0)
127 ERR("Could not get OpenAL PCM format (%d-bit, channelmask %#x)\n",
128 wfe->Samples.wValidBitsPerSample, wfe->dwChannelMask);
129 @@ -436,13 +467,82 @@ static const char *get_fmtstr_EXT(WAVEFORMATEX *format, WAVEFORMATEX **out)
130 return NULL;
133 +static const char *get_fmtstr_FLOAT(const WAVEFORMATEX *format, WAVEFORMATEX **out)
135 + if (!palIsExtensionPresent("AL_EXT_float32"))
136 + return NULL;
138 + *out = HeapAlloc(GetProcessHeap(), 0, sizeof(*format));
139 + if(!*out) return NULL;
141 + **out = *format;
142 + (*out)->cbSize = 0;
144 + switch(format->nChannels)
146 + case 1: return "AL_FORMAT_MONO_FLOAT32";
147 + case 2: return "AL_FORMAT_STEREO_FLOAT32";
148 + default:
149 + return NULL;
153 +static HRESULT openal_format(const WAVEFORMATEX *format, WAVEFORMATEX **myformat, ALenum *enumformat)
155 + const char *fmt_str;
156 + HRESULT hr = DSERR_INVALIDPARAM;
157 + *enumformat = 0;
158 + *myformat = 0;
159 + if(format->wFormatTag == WAVE_FORMAT_PCM)
160 + fmt_str = get_fmtstr_PCM(format, myformat);
161 + else if(format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
163 + WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)format;
165 + hr = DSERR_CONTROLUNAVAIL;
166 + if(format->cbSize > sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) &&
167 + format->cbSize != sizeof(WAVEFORMATEXTENSIBLE))
168 + goto fail;
170 + hr = DSERR_INVALIDPARAM;
171 + if(!IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) &&
172 + !IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
173 + goto fail;
175 + fmt_str = get_fmtstr_EXT(format, myformat);
177 + else if(format->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
179 + fmt_str = get_fmtstr_FLOAT(format, myformat);
181 + else
183 + ERR("Unhandled formattag 0x%04x\n", format->wFormatTag);
184 + return DSERR_INVALIDPARAM;
187 + if(!fmt_str)
188 + goto fail;
190 + *enumformat = palGetEnumValue(fmt_str);
191 + if(palGetError() != AL_NO_ERROR || *enumformat == 0 || *enumformat == -1)
192 + goto fail2;
193 + return S_OK;
195 +fail2:
196 + WARN("Could not get OpenAL format from %s\n", fmt_str);
197 +fail:
198 + HeapFree(GetProcessHeap(), 0, *myformat);
199 + *myformat = 0;
200 + return hr;
203 static void DS8Data_Release(DS8Data *This);
204 static HRESULT DS8Data_Create(DS8Data **ppv, const DSBUFFERDESC *desc, DS8Primary *prim)
206 HRESULT hr = DSERR_INVALIDPARAM;
207 WAVEFORMATEX *format;
208 DS8Data *pBuffer;
209 - const char *fmt_str = NULL;
211 format = desc->lpwfxFormat;
212 TRACE("Requested buffer format:\n"
213 @@ -520,37 +620,9 @@ static HRESULT DS8Data_Create(DS8Data **ppv, const DSBUFFERDESC *desc, DS8Primar
217 - if(format->wFormatTag == WAVE_FORMAT_PCM)
218 - fmt_str = get_fmtstr_PCM(format, &pBuffer->format);
219 - else if(format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
221 - WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)format;
223 - hr = DSERR_CONTROLUNAVAIL;
224 - if(format->cbSize > sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) &&
225 - format->cbSize != sizeof(WAVEFORMATEXTENSIBLE))
226 - goto fail;
228 - hr = DSERR_INVALIDCALL;
229 - if(!IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) &&
230 - !IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
231 - goto fail;
233 - fmt_str = get_fmtstr_EXT(format, &pBuffer->format);
235 - else
236 - ERR("Unhandled formattag 0x%04x\n", format->wFormatTag);
238 - if(!fmt_str)
239 - goto fail;
241 - pBuffer->buf_format = palGetEnumValue(fmt_str);
242 - if(palGetError() != AL_NO_ERROR || pBuffer->buf_format == 0 ||
243 - pBuffer->buf_format == -1)
245 - WARN("Could not get OpenAL format from %s\n", fmt_str);
246 + hr = openal_format(format, &pBuffer->format, &pBuffer->buf_format);
247 + if (FAILED(hr))
248 goto fail;
251 hr = E_OUTOFMEMORY;
252 pBuffer->buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer->buffers)*pBuffer->numsegs);
253 @@ -1305,12 +1377,8 @@ static HRESULT WINAPI DS8Buffer_Play(IDirectSoundBuffer8 *iface, DWORD res1, DWO
254 This->isplaying = TRUE;
256 if(This->nnotify)
258 DS8Buffer_addnotify(This);
259 - DS8Buffer_starttimer(This->primary);
261 - else if(This->buffer->numsegs > 1)
262 - DS8Buffer_starttimer(This->primary);
263 + DS8Buffer_starttimer(This->primary);
265 out:
266 popALContext();
267 diff --git a/dlls/dsound/dsound.c b/dlls/dsound/dsound.c
268 index 301e5fb..52e5cda 100644
269 --- a/dlls/dsound/dsound.c
270 +++ b/dlls/dsound/dsound.c
271 @@ -625,7 +625,7 @@ out:
272 static HRESULT WINAPI DS8_Initialize(IDirectSound8 *iface, const GUID *devguid)
274 DS8Impl *This = impl_from_IDirectSound8(iface);
275 - const ALCchar *drv_name = "PulseAudio Default";
276 + const ALCchar *drv_name = "loopback";
277 HRESULT hr;
278 UINT n;
280 @@ -642,6 +642,10 @@ static HRESULT WINAPI DS8_Initialize(IDirectSound8 *iface, const GUID *devguid)
281 hr = DSERR_ALREADYINITIALIZED;
282 if(This->device)
283 goto out;
284 + hr = GetDeviceID(devguid, &This->guid);
285 + if (FAILED(hr))
286 + goto out;
287 + TRACE("Resolved %s to %s\n", debugstr_guid(devguid), debugstr_guid(&This->guid));
289 for(n = 0;n < devicelistsize;n++)
291 @@ -668,7 +672,7 @@ static HRESULT WINAPI DS8_Initialize(IDirectSound8 *iface, const GUID *devguid)
292 This->deviceref[0] = 1;
295 - This->device = palcOpenDevice(drv_name);
296 + This->device = palcLoopbackOpenDevice();
297 if(!This->device)
299 getALCError(NULL);
300 diff --git a/dlls/dsound/dsound_main.c b/dlls/dsound/dsound_main.c
301 index 3ec5e1c..917da91 100644
302 --- a/dlls/dsound/dsound_main.c
303 +++ b/dlls/dsound/dsound_main.c
304 @@ -954,6 +954,8 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpvReserved)
305 if (mme)
307 IMMDeviceEnumerator_Release(mme);
308 + if (!lpvReserved)
309 + TerminateThread(DSOUND_mmdevapi_thread_handle, 0);
310 CloseHandle(DSOUND_mmdevapi_thread_handle);
312 #ifdef SONAME_LIBOPENAL
313 diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h
314 index b4337b0..d6bee6a 100644
315 --- a/dlls/dsound/dsound_private.h
316 +++ b/dlls/dsound/dsound_private.h
317 @@ -358,6 +358,9 @@ struct DS8Primary
318 } dirty;
319 ALfloat rollofffactor;
320 DS3DLISTENER listen;
322 + IAudioClient *dev;
323 + IAudioRenderClient *render_dev;
326 typedef struct DS8Data DS8Data;
327 @@ -447,6 +450,7 @@ do { \
329 /* Only restore a NULL context if using global contexts, for TLS contexts always restore */
330 #define popALContext() \
331 + do { getALError(); getALCError(NULL); } while (0); \
332 if (__old_ctx != cur_ctx && \
333 (local_contexts || __old_ctx) && \
334 set_context(__old_ctx) == ALC_FALSE) { \
335 diff --git a/dlls/dsound/primary.c b/dlls/dsound/primary.c
336 index f186705..a7b7ca5 100644
337 --- a/dlls/dsound/primary.c
338 +++ b/dlls/dsound/primary.c
339 @@ -48,13 +48,101 @@ static const IDirectSoundBufferVtbl DS8Primary_Vtbl;
340 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl;
341 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl;
343 +/* Sample types */
344 +#define AL_BYTE 0x1400
345 +#define AL_UNSIGNED_BYTE 0x1401
346 +#define AL_SHORT 0x1402
347 +#define AL_UNSIGNED_SHORT 0x1403
348 +#define AL_INT 0x1404
349 +#define AL_UNSIGNED_INT 0x1405
350 +#define AL_FLOAT 0x1406
351 +#define AL_DOUBLE 0x1407
352 +#define AL_MULAW 0x1408
353 +#define AL_IMA4 0x1409
355 +/* Channel configurations */
356 +#define AL_MONO 0x1500
357 +#define AL_STEREO 0x1501
358 +#define AL_REAR 0x1502
359 +#define AL_QUAD 0x1503
360 +#define AL_5POINT1 0x1504 /* (WFX order) */
361 +#define AL_6POINT1 0x1505 /* (WFX order) */
362 +#define AL_7POINT1 0x1506 /* (WFX order) */
364 +static HRESULT openal_type(const WAVEFORMATEX *wfx, int *channelmask, int *fmt)
366 + switch (wfx->wBitsPerSample)
368 + case 8: *fmt = AL_UNSIGNED_BYTE; break;
369 + case 16: *fmt = AL_SHORT; break;
370 + case 32:
371 + if (IsEqualGUID(&((WAVEFORMATEXTENSIBLE*)wfx)->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
372 + *fmt = AL_INT; break;
373 + if (IsEqualGUID(&((WAVEFORMATEXTENSIBLE*)wfx)->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
374 + *fmt = AL_FLOAT; break;
375 + default:
376 + return DSERR_INVALIDCALL;
378 + switch (wfx->nChannels)
380 + case 1: *channelmask = AL_MONO; break;
381 + case 2: *channelmask = AL_STEREO; break;
382 + case 4: *channelmask = AL_QUAD; break;
383 + case 6: *channelmask = AL_5POINT1; break;
384 + case 7: *channelmask = AL_6POINT1; break;
385 + case 8: *channelmask = AL_7POINT1; break;
386 + default:
387 + ERR("Unhandled channels %i\n", wfx->nChannels);
388 + return DSERR_INVALIDPARAM;
390 + return S_OK;
393 +static HRESULT WINAPI create_mmdevapi(DS8Primary *This, WAVEFORMATEX **format)
395 + HRESULT hr;
396 + IMMDevice *dev = NULL;
398 + hr = DSOUND_obtain_immdevice(eRender, &This->parent->guid, eMultimedia, &dev);
399 + if (SUCCEEDED(hr))
400 + hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&This->dev);
401 + if (SUCCEEDED(hr))
402 + hr = IAudioClient_GetMixFormat(This->dev, format);
403 + if (SUCCEEDED(hr))
404 + hr = IAudioClient_Initialize(This->dev, AUDCLNT_SHAREMODE_SHARED, 0, 5000000, 0, *format, NULL);
405 + if (SUCCEEDED(hr))
406 + hr = IAudioClient_GetService(This->dev, &IID_IAudioRenderClient, (void**)&This->render_dev);
407 + if (FAILED(hr))
409 + if (This->dev)
410 + IUnknown_Release(This->dev);
411 + This->dev = NULL;
412 + if (dev)
413 + IUnknown_Release(dev);
414 + if (hr == AUDCLNT_E_UNSUPPORTED_FORMAT)
416 + FIXME("Couldn't open device: bad format\n");
417 + return DSERR_BADFORMAT;
419 + ERR("couldn't open device %s %i: %08x\n", debugstr_guid(&This->parent->guid), (*format)->nSamplesPerSec, hr);
420 + return DSERR_NODRIVER;
422 + return S_OK;
425 HRESULT DS8Primary_Create(DS8Primary **ppv, DS8Impl *parent)
427 HRESULT hr = DSERR_OUTOFMEMORY;
428 DS8Primary *This = NULL;
429 DS3DLISTENER *listener;
430 - WAVEFORMATEX *wfx;
431 + WAVEFORMATEX *wfx, *realwfx;
432 ALuint srcs[256];
433 + ALCint attrs[] = {
434 + ALC_FORMAT_CHANNELS, AL_STEREO,
435 + ALC_FORMAT_TYPE, AL_FLOAT,
436 + ALC_FREQUENCY, 48000,
438 + };
439 DWORD nsources;
441 *ppv = NULL;
442 @@ -67,9 +155,18 @@ HRESULT DS8Primary_Create(DS8Primary **ppv, DS8Impl *parent)
443 /* Allocate enough for a WAVEFORMATEXTENSIBLE */
444 This->format = wfx = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEXTENSIBLE));
445 if(!wfx) goto fail;
446 + This->parent = parent;
448 + hr = create_mmdevapi(This, &realwfx);
449 + if (SUCCEEDED(hr))
450 + hr = openal_type(realwfx, &attrs[1], &attrs[3]);
451 + else
452 + goto fail;
453 + attrs[5] = realwfx->nSamplesPerSec;
454 + CoTaskMemFree(realwfx);
456 hr = DSERR_NODRIVER;
457 - This->ctx = palcCreateContext(parent->device, NULL);
458 + This->ctx = palcCreateContext(parent->device, attrs);
459 if(!This->ctx)
461 ALCenum err = palcGetError(parent->device);
462 @@ -127,7 +224,6 @@ HRESULT DS8Primary_Create(DS8Primary **ppv, DS8Impl *parent)
463 This->IDirectSound3DListener_iface.lpVtbl = &DS8Primary3D_Vtbl;
464 This->IKsPropertySet_iface.lpVtbl = &DS8PrimaryProp_Vtbl;
465 This->stopped = TRUE;
466 - This->parent = parent;
467 /* Apparently primary buffer size is always 32k,
468 * tested on windows with 192k 24 bits sound @ 6 channels
469 * where it will run out in 60 ms and it isn't pointer aligned
470 @@ -209,6 +305,12 @@ void DS8Primary_Destroy(DS8Primary *This)
471 ALCcontext *old_ctx;
473 EnterCriticalSection(&openal_crst);
474 + if (This->dev)
476 + IAudioClient_Stop(This->dev);
477 + IUnknown_Release(This->render_dev);
478 + IUnknown_Release(This->dev);
480 old_ctx = get_context();
481 if(old_ctx != This->ctx)
482 set_context(This->ctx);
483 @@ -586,7 +688,7 @@ static HRESULT WINAPI DS8Primary_SetCurrentPosition(IDirectSoundBuffer *iface, D
484 /* Just assume the format is crap, and clean up the damage */
485 static void copy_waveformat(WAVEFORMATEX *wfx, const WAVEFORMATEX *from)
487 - if(from->wFormatTag == WAVE_FORMAT_PCM)
488 + if(from->wFormatTag == WAVE_FORMAT_PCM || from->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
490 wfx->cbSize = 0;
491 if(from->wBitsPerSample == 8 ||