blob: 491d87379ba0e01fc5cd5878f8bde814d2ab52f7 [file] [log] [blame]
Robert Reif0e3c5242004-10-26 22:04:55 +00001/*
2 * Direct Sound Capture driver
3 *
4 * Copyright 2004 Robert Reif
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
Jonathan Ernst360a3f92006-05-18 14:49:52 +020018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Robert Reif0e3c5242004-10-26 22:04:55 +000019 */
20
21#include "config.h"
22#include "wine/port.h"
23
24#include <stdlib.h>
25#include <stdarg.h>
26#include <stdio.h>
27#include <string.h>
28#ifdef HAVE_UNISTD_H
29# include <unistd.h>
30#endif
31#include <errno.h>
32#include <fcntl.h>
33#ifdef HAVE_SYS_IOCTL_H
34# include <sys/ioctl.h>
35#endif
36#ifdef HAVE_SYS_MMAN_H
37# include <sys/mman.h>
38#endif
Steven Edwards57279182005-03-04 12:38:36 +000039#ifdef HAVE_POLL_H
40#include <poll.h>
41#endif
Robert Reif0e3c5242004-10-26 22:04:55 +000042#ifdef HAVE_SYS_POLL_H
43# include <sys/poll.h>
44#endif
45
46#include "windef.h"
47#include "winbase.h"
48#include "wingdi.h"
Alexandre Julliardb4e49552004-12-06 20:55:25 +000049#include "winuser.h"
Robert Reif0e3c5242004-10-26 22:04:55 +000050#include "winerror.h"
Robert Reif0e3c5242004-10-26 22:04:55 +000051#include "mmddk.h"
52#include "mmreg.h"
53#include "dsound.h"
54#include "dsdriver.h"
55#include "oss.h"
56#include "wine/debug.h"
57
58#include "audio.h"
59
Robert Reif24da7562004-11-19 18:25:03 +000060WINE_DEFAULT_DEBUG_CHANNEL(dscapture);
Robert Reif0e3c5242004-10-26 22:04:55 +000061
62#ifdef HAVE_OSS
63
64/*======================================================================*
65 * Low level DSOUND capture definitions *
66 *======================================================================*/
67
68typedef struct IDsCaptureDriverPropertySetImpl IDsCaptureDriverPropertySetImpl;
69typedef struct IDsCaptureDriverNotifyImpl IDsCaptureDriverNotifyImpl;
70typedef struct IDsCaptureDriverImpl IDsCaptureDriverImpl;
71typedef struct IDsCaptureDriverBufferImpl IDsCaptureDriverBufferImpl;
72
73struct IDsCaptureDriverPropertySetImpl
74{
75 /* IUnknown fields */
Dmitry Timoshkoveba47f12005-06-06 19:50:35 +000076 const IDsDriverPropertySetVtbl *lpVtbl;
Mike McCormackbda7ace2005-07-13 11:59:15 +000077 LONG ref;
Robert Reif0e3c5242004-10-26 22:04:55 +000078
79 IDsCaptureDriverBufferImpl* capture_buffer;
80};
81
82struct IDsCaptureDriverNotifyImpl
83{
84 /* IUnknown fields */
Dmitry Timoshkoveba47f12005-06-06 19:50:35 +000085 const IDsDriverNotifyVtbl *lpVtbl;
Mike McCormackbda7ace2005-07-13 11:59:15 +000086 LONG ref;
Robert Reif0e3c5242004-10-26 22:04:55 +000087
88 IDsCaptureDriverBufferImpl* capture_buffer;
89};
90
91struct IDsCaptureDriverImpl
92{
93 /* IUnknown fields */
Dmitry Timoshkoveba47f12005-06-06 19:50:35 +000094 const IDsCaptureDriverVtbl *lpVtbl;
Mike McCormackbda7ace2005-07-13 11:59:15 +000095 LONG ref;
Robert Reif0e3c5242004-10-26 22:04:55 +000096
97 /* IDsCaptureDriverImpl fields */
98 UINT wDevID;
99 IDsCaptureDriverBufferImpl* capture_buffer;
100};
101
102struct IDsCaptureDriverBufferImpl
103{
104 /* IUnknown fields */
Dmitry Timoshkoveba47f12005-06-06 19:50:35 +0000105 const IDsCaptureDriverBufferVtbl *lpVtbl;
Mike McCormackbda7ace2005-07-13 11:59:15 +0000106 LONG ref;
Robert Reif0e3c5242004-10-26 22:04:55 +0000107
108 /* IDsCaptureDriverBufferImpl fields */
109 IDsCaptureDriverImpl* drv;
Robert Reif24da7562004-11-19 18:25:03 +0000110 LPBYTE buffer; /* user buffer */
111 DWORD buflen; /* user buffer length */
112 LPBYTE mapping; /* DMA buffer */
113 DWORD maplen; /* DMA buffer length */
114 BOOL is_direct_map; /* DMA == user ? */
115 DWORD fragsize;
116 DWORD map_writepos; /* DMA write offset */
117 DWORD map_readpos; /* DMA read offset */
118 DWORD writeptr; /* user write offset */
119 DWORD readptr; /* user read offset */
Robert Reif0e3c5242004-10-26 22:04:55 +0000120
121 /* IDsDriverNotifyImpl fields */
122 IDsCaptureDriverNotifyImpl* notify;
123 int notify_index;
124 LPDSBPOSITIONNOTIFY notifies;
125 int nrofnotifies;
126
127 /* IDsDriverPropertySetImpl fields */
128 IDsCaptureDriverPropertySetImpl* property_set;
129
130 BOOL is_capturing;
131 BOOL is_looping;
Robert Reif24da7562004-11-19 18:25:03 +0000132 WAVEFORMATEX wfx;
133 HANDLE hThread;
134 DWORD dwThreadID;
135 HANDLE hStartUpEvent;
136 HANDLE hExitEvent;
137 int pipe_fd[2];
138 int fd;
Robert Reif0e3c5242004-10-26 22:04:55 +0000139};
140
Francois Gougetec6f88b2008-11-24 17:24:29 +0100141static HRESULT IDsCaptureDriverPropertySetImpl_Create(
Robert Reif0e3c5242004-10-26 22:04:55 +0000142 IDsCaptureDriverBufferImpl * dscdb,
143 IDsCaptureDriverPropertySetImpl **pdscdps);
144
Francois Gougetec6f88b2008-11-24 17:24:29 +0100145static HRESULT IDsCaptureDriverNotifyImpl_Create(
Robert Reif0e3c5242004-10-26 22:04:55 +0000146 IDsCaptureDriverBufferImpl * dsdcb,
147 IDsCaptureDriverNotifyImpl **pdscdn);
148
149/*======================================================================*
150 * Low level DSOUND capture property set implementation *
151 *======================================================================*/
152
153static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_QueryInterface(
154 PIDSDRIVERPROPERTYSET iface,
155 REFIID riid,
156 LPVOID *ppobj)
157{
158 IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
159 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
160
161 if ( IsEqualGUID(riid, &IID_IUnknown) ||
162 IsEqualGUID(riid, &IID_IDsDriverPropertySet) ) {
163 IDsDriverPropertySet_AddRef(iface);
Michael Stefaniucc0a92812009-01-22 09:52:59 +0100164 *ppobj = This;
Robert Reif0e3c5242004-10-26 22:04:55 +0000165 return DS_OK;
166 }
167
168 FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
169
170 *ppobj = 0;
171 return E_NOINTERFACE;
172}
173
174static ULONG WINAPI IDsCaptureDriverPropertySetImpl_AddRef(
175 PIDSDRIVERPROPERTYSET iface)
176{
177 IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
James Hawkinsed12a3d2005-01-12 19:55:24 +0000178 ULONG refCount = InterlockedIncrement(&This->ref);
Robert Reif0e3c5242004-10-26 22:04:55 +0000179
Michael Stefaniuc10ee3302006-10-06 22:59:51 +0200180 TRACE("(%p) ref was %d\n", This, refCount - 1);
James Hawkinsed12a3d2005-01-12 19:55:24 +0000181
182 return refCount;
Robert Reif0e3c5242004-10-26 22:04:55 +0000183}
184
185static ULONG WINAPI IDsCaptureDriverPropertySetImpl_Release(
186 PIDSDRIVERPROPERTYSET iface)
187{
188 IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
James Hawkinsed12a3d2005-01-12 19:55:24 +0000189 ULONG refCount = InterlockedDecrement(&This->ref);
Robert Reif0e3c5242004-10-26 22:04:55 +0000190
Michael Stefaniuc10ee3302006-10-06 22:59:51 +0200191 TRACE("(%p) ref was %d\n", This, refCount + 1);
James Hawkinsed12a3d2005-01-12 19:55:24 +0000192
193 if (!refCount) {
Robert Reif0e3c5242004-10-26 22:04:55 +0000194 IDsCaptureDriverBuffer_Release((PIDSCDRIVERBUFFER)This->capture_buffer);
195 This->capture_buffer->property_set = NULL;
196 HeapFree(GetProcessHeap(),0,This);
197 TRACE("(%p) released\n",This);
198 }
James Hawkinsed12a3d2005-01-12 19:55:24 +0000199 return refCount;
Robert Reif0e3c5242004-10-26 22:04:55 +0000200}
201
202static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_Get(
203 PIDSDRIVERPROPERTYSET iface,
204 PDSPROPERTY pDsProperty,
205 LPVOID pPropertyParams,
206 ULONG cbPropertyParams,
207 LPVOID pPropertyData,
208 ULONG cbPropertyData,
209 PULONG pcbReturnedData )
210{
211 IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
Michael Stefaniuc10ee3302006-10-06 22:59:51 +0200212 FIXME("(%p,%p,%p,%x,%p,%x,%p)\n",This,pDsProperty,pPropertyParams,
Robert Reif0e3c5242004-10-26 22:04:55 +0000213 cbPropertyParams,pPropertyData,cbPropertyData,pcbReturnedData);
214 return DSERR_UNSUPPORTED;
215}
216
217static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_Set(
218 PIDSDRIVERPROPERTYSET iface,
219 PDSPROPERTY pDsProperty,
220 LPVOID pPropertyParams,
221 ULONG cbPropertyParams,
222 LPVOID pPropertyData,
223 ULONG cbPropertyData )
224{
225 IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
Michael Stefaniuc10ee3302006-10-06 22:59:51 +0200226 FIXME("(%p,%p,%p,%x,%p,%x)\n",This,pDsProperty,pPropertyParams,
Robert Reif0e3c5242004-10-26 22:04:55 +0000227 cbPropertyParams,pPropertyData,cbPropertyData);
228 return DSERR_UNSUPPORTED;
229}
230
231static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_QuerySupport(
232 PIDSDRIVERPROPERTYSET iface,
233 REFGUID PropertySetId,
234 ULONG PropertyId,
235 PULONG pSupport )
236{
237 IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
Michael Stefaniuc10ee3302006-10-06 22:59:51 +0200238 FIXME("(%p,%s,%x,%p)\n",This,debugstr_guid(PropertySetId),PropertyId,
Robert Reif0e3c5242004-10-26 22:04:55 +0000239 pSupport);
240 return DSERR_UNSUPPORTED;
241}
242
Dmitry Timoshkoveba47f12005-06-06 19:50:35 +0000243static const IDsDriverPropertySetVtbl dscdpsvt =
Robert Reif0e3c5242004-10-26 22:04:55 +0000244{
245 IDsCaptureDriverPropertySetImpl_QueryInterface,
246 IDsCaptureDriverPropertySetImpl_AddRef,
247 IDsCaptureDriverPropertySetImpl_Release,
248 IDsCaptureDriverPropertySetImpl_Get,
249 IDsCaptureDriverPropertySetImpl_Set,
250 IDsCaptureDriverPropertySetImpl_QuerySupport,
251};
252
253/*======================================================================*
254 * Low level DSOUND capture notify implementation *
255 *======================================================================*/
256
257static HRESULT WINAPI IDsCaptureDriverNotifyImpl_QueryInterface(
258 PIDSDRIVERNOTIFY iface,
259 REFIID riid,
260 LPVOID *ppobj)
261{
262 IDsCaptureDriverNotifyImpl *This = (IDsCaptureDriverNotifyImpl *)iface;
263 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
264
265 if ( IsEqualGUID(riid, &IID_IUnknown) ||
266 IsEqualGUID(riid, &IID_IDsDriverNotify) ) {
267 IDsDriverNotify_AddRef(iface);
268 *ppobj = This;
269 return DS_OK;
270 }
271
272 FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
273
274 *ppobj = 0;
275 return E_NOINTERFACE;
276}
277
278static ULONG WINAPI IDsCaptureDriverNotifyImpl_AddRef(
279 PIDSDRIVERNOTIFY iface)
280{
281 IDsCaptureDriverNotifyImpl *This = (IDsCaptureDriverNotifyImpl *)iface;
James Hawkinsed12a3d2005-01-12 19:55:24 +0000282 ULONG refCount = InterlockedIncrement(&This->ref);
Robert Reif0e3c5242004-10-26 22:04:55 +0000283
Michael Stefaniuc10ee3302006-10-06 22:59:51 +0200284 TRACE("(%p) ref was %d\n", This, refCount - 1);
James Hawkinsed12a3d2005-01-12 19:55:24 +0000285
286 return refCount;
Robert Reif0e3c5242004-10-26 22:04:55 +0000287}
288
289static ULONG WINAPI IDsCaptureDriverNotifyImpl_Release(
290 PIDSDRIVERNOTIFY iface)
291{
292 IDsCaptureDriverNotifyImpl *This = (IDsCaptureDriverNotifyImpl *)iface;
James Hawkinsed12a3d2005-01-12 19:55:24 +0000293 ULONG refCount = InterlockedDecrement(&This->ref);
Robert Reif0e3c5242004-10-26 22:04:55 +0000294
Michael Stefaniuc10ee3302006-10-06 22:59:51 +0200295 TRACE("(%p) ref was %d\n", This, refCount + 1);
James Hawkinsed12a3d2005-01-12 19:55:24 +0000296
297 if (!refCount) {
Robert Reif0e3c5242004-10-26 22:04:55 +0000298 IDsCaptureDriverBuffer_Release((PIDSCDRIVERBUFFER)This->capture_buffer);
299 This->capture_buffer->notify = NULL;
300 HeapFree(GetProcessHeap(),0,This);
301 TRACE("(%p) released\n",This);
302 }
James Hawkinsed12a3d2005-01-12 19:55:24 +0000303 return refCount;
Robert Reif0e3c5242004-10-26 22:04:55 +0000304}
305
306static HRESULT WINAPI IDsCaptureDriverNotifyImpl_SetNotificationPositions(
307 PIDSDRIVERNOTIFY iface,
308 DWORD howmuch,
309 LPCDSBPOSITIONNOTIFY notify)
310{
311 IDsCaptureDriverNotifyImpl *This = (IDsCaptureDriverNotifyImpl *)iface;
Michael Stefaniuc10ee3302006-10-06 22:59:51 +0200312 TRACE("(%p,0x%08x,%p)\n",This,howmuch,notify);
Robert Reif0e3c5242004-10-26 22:04:55 +0000313
314 if (!notify) {
315 WARN("invalid parameter\n");
316 return DSERR_INVALIDPARAM;
317 }
318
Robert Reif24da7562004-11-19 18:25:03 +0000319 if (TRACE_ON(dscapture)) {
Andrew Talbot209fe1e2008-12-03 17:42:10 +0000320 DWORD i;
Robert Reif0e3c5242004-10-26 22:04:55 +0000321 for (i=0;i<howmuch;i++)
Maarten Lankhorstc4b52332008-12-02 15:40:52 +0100322 TRACE("notify at %d to 0x%08lx\n",
323 notify[i].dwOffset,(DWORD_PTR)notify[i].hEventNotify);
Robert Reif0e3c5242004-10-26 22:04:55 +0000324 }
325
326 /* Make an internal copy of the caller-supplied array.
327 * Replace the existing copy if one is already present. */
328 if (This->capture_buffer->notifies)
329 This->capture_buffer->notifies = HeapReAlloc(GetProcessHeap(),
330 HEAP_ZERO_MEMORY, This->capture_buffer->notifies,
331 howmuch * sizeof(DSBPOSITIONNOTIFY));
332 else
333 This->capture_buffer->notifies = HeapAlloc(GetProcessHeap(),
334 HEAP_ZERO_MEMORY, howmuch * sizeof(DSBPOSITIONNOTIFY));
335
336 memcpy(This->capture_buffer->notifies, notify,
337 howmuch * sizeof(DSBPOSITIONNOTIFY));
338 This->capture_buffer->nrofnotifies = howmuch;
339
340 return S_OK;
341}
342
Dmitry Timoshkoveba47f12005-06-06 19:50:35 +0000343static const IDsDriverNotifyVtbl dscdnvt =
Robert Reif0e3c5242004-10-26 22:04:55 +0000344{
345 IDsCaptureDriverNotifyImpl_QueryInterface,
346 IDsCaptureDriverNotifyImpl_AddRef,
347 IDsCaptureDriverNotifyImpl_Release,
348 IDsCaptureDriverNotifyImpl_SetNotificationPositions,
349};
350
351/*======================================================================*
352 * Low level DSOUND capture implementation *
353 *======================================================================*/
354
355static HRESULT DSCDB_MapBuffer(IDsCaptureDriverBufferImpl *dscdb)
356{
357 if (!dscdb->mapping) {
358 dscdb->mapping = mmap(NULL, dscdb->maplen, PROT_READ, MAP_SHARED,
Maarten Lankhorst58e26452007-10-01 09:16:59 +0200359 WInDev[dscdb->drv->wDevID].ossdev.fd, 0);
Robert Reif0e3c5242004-10-26 22:04:55 +0000360 if (dscdb->mapping == (LPBYTE)-1) {
361 TRACE("(%p): Could not map sound device for direct access (%s)\n",
362 dscdb, strerror(errno));
363 return DSERR_GENERIC;
364 }
Robert Reif24da7562004-11-19 18:25:03 +0000365 TRACE("(%p): sound device has been mapped for direct access at %p, "
Michael Stefaniuc10ee3302006-10-06 22:59:51 +0200366 "size=%d\n", dscdb, dscdb->mapping, dscdb->maplen);
Robert Reif0e3c5242004-10-26 22:04:55 +0000367 }
368 return DS_OK;
369}
370
371static HRESULT DSCDB_UnmapBuffer(IDsCaptureDriverBufferImpl *dscdb)
372{
373 if (dscdb->mapping) {
374 if (munmap(dscdb->mapping, dscdb->maplen) < 0) {
375 ERR("(%p): Could not unmap sound device (%s)\n",
376 dscdb, strerror(errno));
377 return DSERR_GENERIC;
378 }
379 dscdb->mapping = NULL;
380 TRACE("(%p): sound device unmapped\n", dscdb);
381 }
382 return DS_OK;
383}
384
385static HRESULT WINAPI IDsCaptureDriverBufferImpl_QueryInterface(
386 PIDSCDRIVERBUFFER iface,
387 REFIID riid,
388 LPVOID *ppobj)
389{
390 IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
391 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
392
393 *ppobj = 0;
394
395 if ( IsEqualGUID(riid, &IID_IUnknown) ||
396 IsEqualGUID(riid, &IID_IDsCaptureDriverBuffer) ) {
397 IDsCaptureDriverBuffer_AddRef(iface);
Michael Stefaniucc0a92812009-01-22 09:52:59 +0100398 *ppobj = This;
Robert Reif0e3c5242004-10-26 22:04:55 +0000399 return DS_OK;
400 }
401
402 if ( IsEqualGUID( &IID_IDsDriverNotify, riid ) ) {
403 if (!This->notify)
404 IDsCaptureDriverNotifyImpl_Create(This, &(This->notify));
405 if (This->notify) {
406 IDsDriverNotify_AddRef((PIDSDRIVERNOTIFY)This->notify);
Michael Stefaniucc0a92812009-01-22 09:52:59 +0100407 *ppobj = This->notify;
Robert Reif0e3c5242004-10-26 22:04:55 +0000408 return DS_OK;
409 }
410 return E_FAIL;
411 }
412
413 if ( IsEqualGUID( &IID_IDsDriverPropertySet, riid ) ) {
414 if (!This->property_set)
415 IDsCaptureDriverPropertySetImpl_Create(This, &(This->property_set));
416 if (This->property_set) {
417 IDsDriverPropertySet_AddRef((PIDSDRIVERPROPERTYSET)This->property_set);
Michael Stefaniucc0a92812009-01-22 09:52:59 +0100418 *ppobj = This->property_set;
Robert Reif0e3c5242004-10-26 22:04:55 +0000419 return DS_OK;
420 }
421 return E_FAIL;
422 }
423
424 FIXME("(%p,%s,%p) unsupported GUID\n", This, debugstr_guid(riid), ppobj);
425 return DSERR_UNSUPPORTED;
426}
427
428static ULONG WINAPI IDsCaptureDriverBufferImpl_AddRef(PIDSCDRIVERBUFFER iface)
429{
430 IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
James Hawkinsed12a3d2005-01-12 19:55:24 +0000431 ULONG refCount = InterlockedIncrement(&This->ref);
Robert Reif0e3c5242004-10-26 22:04:55 +0000432
Michael Stefaniuc10ee3302006-10-06 22:59:51 +0200433 TRACE("(%p) ref was %d\n", This, refCount - 1);
James Hawkinsed12a3d2005-01-12 19:55:24 +0000434
435 return refCount;
Robert Reif0e3c5242004-10-26 22:04:55 +0000436}
437
438static ULONG WINAPI IDsCaptureDriverBufferImpl_Release(PIDSCDRIVERBUFFER iface)
439{
440 IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
James Hawkinsed12a3d2005-01-12 19:55:24 +0000441 ULONG refCount = InterlockedDecrement(&This->ref);
Michael Stefaniuc10ee3302006-10-06 22:59:51 +0200442 TRACE("(%p) ref was %d\n", This, refCount + 1);
Robert Reif0e3c5242004-10-26 22:04:55 +0000443
James Hawkinsed12a3d2005-01-12 19:55:24 +0000444 if (!refCount) {
Robert Reif24da7562004-11-19 18:25:03 +0000445 WINE_WAVEIN* wwi;
446
447 wwi = &WInDev[This->drv->wDevID];
448
449 if (This->hThread) {
450 int x = 0;
451
452 /* request thread termination */
453 write(This->pipe_fd[1], &x, sizeof(x));
454
455 /* wait for reply */
456 WaitForSingleObject(This->hExitEvent, INFINITE);
457 CloseHandle(This->hExitEvent);
458 }
459
460 close(This->pipe_fd[0]);
461 close(This->pipe_fd[1]);
462
Robert Reif0e3c5242004-10-26 22:04:55 +0000463 DSCDB_UnmapBuffer(This);
Robert Reif24da7562004-11-19 18:25:03 +0000464
Maarten Lankhorst58e26452007-10-01 09:16:59 +0200465 OSS_CloseDevice(&wwi->ossdev);
Robert Reif24da7562004-11-19 18:25:03 +0000466 wwi->state = WINE_WS_CLOSED;
467 wwi->dwFragmentSize = 0;
468 This->drv->capture_buffer = NULL;
469
Michael Stefaniuc5ad7d852004-12-23 17:06:43 +0000470 HeapFree(GetProcessHeap(), 0, This->notifies);
Robert Reif0e3c5242004-10-26 22:04:55 +0000471 HeapFree(GetProcessHeap(),0,This);
472 TRACE("(%p) released\n",This);
473 }
James Hawkinsed12a3d2005-01-12 19:55:24 +0000474 return refCount;
Robert Reif0e3c5242004-10-26 22:04:55 +0000475}
476
477static HRESULT WINAPI IDsCaptureDriverBufferImpl_Lock(
478 PIDSCDRIVERBUFFER iface,
479 LPVOID* ppvAudio1,
480 LPDWORD pdwLen1,
481 LPVOID* ppvAudio2,
482 LPDWORD pdwLen2,
483 DWORD dwWritePosition,
484 DWORD dwWriteLen,
485 DWORD dwFlags)
486{
487 IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
Michael Stefaniuc10ee3302006-10-06 22:59:51 +0200488 TRACE("(%p,%p,%p,%p,%p,%d,%d,0x%08x)\n",This,ppvAudio1,pdwLen1,
Robert Reif0e3c5242004-10-26 22:04:55 +0000489 ppvAudio2,pdwLen2,dwWritePosition,dwWriteLen,dwFlags);
Robert Reif24da7562004-11-19 18:25:03 +0000490
491 if (This->is_direct_map) {
492 if (ppvAudio1)
493 *ppvAudio1 = This->mapping + dwWritePosition;
494
495 if (dwWritePosition + dwWriteLen < This->maplen) {
496 if (pdwLen1)
497 *pdwLen1 = dwWriteLen;
498 if (ppvAudio2)
499 *ppvAudio2 = 0;
500 if (pdwLen2)
501 *pdwLen2 = 0;
502 } else {
503 if (pdwLen1)
504 *pdwLen1 = This->maplen - dwWritePosition;
505 if (ppvAudio2)
506 *ppvAudio2 = 0;
507 if (pdwLen2)
508 *pdwLen2 = dwWriteLen - (This->maplen - dwWritePosition);
509 }
510 } else {
511 if (ppvAudio1)
512 *ppvAudio1 = This->buffer + dwWritePosition;
513
514 if (dwWritePosition + dwWriteLen < This->buflen) {
515 if (pdwLen1)
516 *pdwLen1 = dwWriteLen;
517 if (ppvAudio2)
518 *ppvAudio2 = 0;
519 if (pdwLen2)
520 *pdwLen2 = 0;
521 } else {
522 if (pdwLen1)
523 *pdwLen1 = This->buflen - dwWritePosition;
524 if (ppvAudio2)
525 *ppvAudio2 = 0;
526 if (pdwLen2)
527 *pdwLen2 = dwWriteLen - (This->buflen - dwWritePosition);
528 }
529 }
530
Robert Reif0e3c5242004-10-26 22:04:55 +0000531 return DS_OK;
532}
533
534static HRESULT WINAPI IDsCaptureDriverBufferImpl_Unlock(
535 PIDSCDRIVERBUFFER iface,
536 LPVOID pvAudio1,
537 DWORD dwLen1,
538 LPVOID pvAudio2,
539 DWORD dwLen2)
540{
541 IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
Michael Stefaniuc10ee3302006-10-06 22:59:51 +0200542 TRACE("(%p,%p,%d,%p,%d)\n",This,pvAudio1,dwLen1,pvAudio2,dwLen2);
Robert Reif24da7562004-11-19 18:25:03 +0000543
544 if (This->is_direct_map)
545 This->map_readpos = (This->map_readpos + dwLen1 + dwLen2) % This->maplen;
546 else
547 This->readptr = (This->readptr + dwLen1 + dwLen2) % This->buflen;
548
Robert Reif0e3c5242004-10-26 22:04:55 +0000549 return DS_OK;
550}
551
552static HRESULT WINAPI IDsCaptureDriverBufferImpl_GetPosition(
553 PIDSCDRIVERBUFFER iface,
554 LPDWORD lpdwCapture,
555 LPDWORD lpdwRead)
556{
557 IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
Robert Reif0e3c5242004-10-26 22:04:55 +0000558 TRACE("(%p,%p,%p)\n",This,lpdwCapture,lpdwRead);
559
560 if (WInDev[This->drv->wDevID].state == WINE_WS_CLOSED) {
561 ERR("device not open, but accessing?\n");
562 return DSERR_UNINITIALIZED;
563 }
564
565 if (!This->is_capturing) {
566 if (lpdwCapture)
567 *lpdwCapture = 0;
568 if (lpdwRead)
569 *lpdwRead = 0;
570 }
571
Robert Reif24da7562004-11-19 18:25:03 +0000572 if (This->is_direct_map) {
573 if (lpdwCapture)
574 *lpdwCapture = This->map_writepos;
575 if (lpdwRead) {
576 *lpdwRead = This->map_readpos;
577 }
578 } else {
579 if (lpdwCapture)
580 *lpdwCapture = This->writeptr;
581 if (lpdwRead)
582 *lpdwRead = This->readptr;
Robert Reif0e3c5242004-10-26 22:04:55 +0000583 }
Robert Reif24da7562004-11-19 18:25:03 +0000584
Michael Stefaniuc10ee3302006-10-06 22:59:51 +0200585 TRACE("capturepos=%d, readpos=%d\n", lpdwCapture?*lpdwCapture:0,
Robert Reif24da7562004-11-19 18:25:03 +0000586 lpdwRead?*lpdwRead:0);
Robert Reif0e3c5242004-10-26 22:04:55 +0000587 return DS_OK;
588}
589
590static HRESULT WINAPI IDsCaptureDriverBufferImpl_GetStatus(
591 PIDSCDRIVERBUFFER iface,
592 LPDWORD lpdwStatus)
593{
594 IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
595 TRACE("(%p,%p)\n",This,lpdwStatus);
596
597 if (This->is_capturing) {
598 if (This->is_looping)
599 *lpdwStatus = DSCBSTATUS_CAPTURING | DSCBSTATUS_LOOPING;
600 else
601 *lpdwStatus = DSCBSTATUS_CAPTURING;
602 } else
603 *lpdwStatus = 0;
604
605 return DS_OK;
606}
607
608static HRESULT WINAPI IDsCaptureDriverBufferImpl_Start(
609 PIDSCDRIVERBUFFER iface,
610 DWORD dwFlags)
611{
612 IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
613 int enable;
Michael Stefaniuc10ee3302006-10-06 22:59:51 +0200614 TRACE("(%p,%x)\n",This,dwFlags);
Robert Reif0e3c5242004-10-26 22:04:55 +0000615
616 if (This->is_capturing)
617 return DS_OK;
618
619 if (dwFlags & DSCBSTART_LOOPING)
620 This->is_looping = TRUE;
621
Maarten Lankhorst58e26452007-10-01 09:16:59 +0200622 WInDev[This->drv->wDevID].ossdev.bInputEnabled = TRUE;
623 enable = getEnables(&WInDev[This->drv->wDevID].ossdev);
624 if (ioctl(WInDev[This->drv->wDevID].ossdev.fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
Robert Reif0e3c5242004-10-26 22:04:55 +0000625 if (errno == EINVAL) {
626 /* Don't give up yet. OSS trigger support is inconsistent. */
Maarten Lankhorst58e26452007-10-01 09:16:59 +0200627 if (WInDev[This->drv->wDevID].ossdev.open_count == 1) {
Robert Reif0e3c5242004-10-26 22:04:55 +0000628 /* try the opposite output enable */
Maarten Lankhorst58e26452007-10-01 09:16:59 +0200629 if (WInDev[This->drv->wDevID].ossdev.bOutputEnabled == FALSE)
630 WInDev[This->drv->wDevID].ossdev.bOutputEnabled = TRUE;
Robert Reif0e3c5242004-10-26 22:04:55 +0000631 else
Maarten Lankhorst58e26452007-10-01 09:16:59 +0200632 WInDev[This->drv->wDevID].ossdev.bOutputEnabled = FALSE;
Robert Reif0e3c5242004-10-26 22:04:55 +0000633 /* try it again */
Maarten Lankhorst58e26452007-10-01 09:16:59 +0200634 enable = getEnables(&WInDev[This->drv->wDevID].ossdev);
635 if (ioctl(WInDev[This->drv->wDevID].ossdev.fd, SNDCTL_DSP_SETTRIGGER, &enable) >= 0) {
Robert Reif0e3c5242004-10-26 22:04:55 +0000636 This->is_capturing = TRUE;
637 return DS_OK;
638 }
639 }
640 }
641 ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
Maarten Lankhorst58e26452007-10-01 09:16:59 +0200642 WInDev[This->drv->wDevID].ossdev.dev_name, strerror(errno));
643 WInDev[This->drv->wDevID].ossdev.bInputEnabled = FALSE;
Robert Reif0e3c5242004-10-26 22:04:55 +0000644 return DSERR_GENERIC;
645 }
646
647 This->is_capturing = TRUE;
648 return DS_OK;
649}
650
651static HRESULT WINAPI IDsCaptureDriverBufferImpl_Stop(PIDSCDRIVERBUFFER iface)
652{
653 IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
654 int enable;
655 TRACE("(%p)\n",This);
656
657 if (!This->is_capturing)
658 return DS_OK;
659
Francois Gouget1ccf9442006-11-12 19:51:37 +0100660 /* no more capturing */
Maarten Lankhorst58e26452007-10-01 09:16:59 +0200661 WInDev[This->drv->wDevID].ossdev.bInputEnabled = FALSE;
662 enable = getEnables(&WInDev[This->drv->wDevID].ossdev);
663 if (ioctl(WInDev[This->drv->wDevID].ossdev.fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
Robert Reif0e3c5242004-10-26 22:04:55 +0000664 ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
Maarten Lankhorst58e26452007-10-01 09:16:59 +0200665 WInDev[This->drv->wDevID].ossdev.dev_name, strerror(errno));
Robert Reif0e3c5242004-10-26 22:04:55 +0000666 return DSERR_GENERIC;
667 }
668
669 /* send a final event if necessary */
670 if (This->nrofnotifies > 0) {
671 if (This->notifies[This->nrofnotifies - 1].dwOffset == DSBPN_OFFSETSTOP)
672 SetEvent(This->notifies[This->nrofnotifies - 1].hEventNotify);
673 }
674
675 This->is_capturing = FALSE;
676 This->is_looping = FALSE;
677
Robert Reif24da7562004-11-19 18:25:03 +0000678 if (This->hThread) {
679 int x = 0;
680 write(This->pipe_fd[1], &x, sizeof(x));
681 WaitForSingleObject(This->hExitEvent, INFINITE);
682 CloseHandle(This->hExitEvent);
683 This->hExitEvent = INVALID_HANDLE_VALUE;
684 This->hThread = 0;
685 }
686
687 return DS_OK;
Robert Reif0e3c5242004-10-26 22:04:55 +0000688}
689
690static HRESULT WINAPI IDsCaptureDriverBufferImpl_SetFormat(
691 PIDSCDRIVERBUFFER iface,
692 LPWAVEFORMATEX pwfx)
693{
694 IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
695 FIXME("(%p): stub!\n",This);
696 return DSERR_UNSUPPORTED;
697}
698
Dmitry Timoshkoveba47f12005-06-06 19:50:35 +0000699static const IDsCaptureDriverBufferVtbl dscdbvt =
Robert Reif0e3c5242004-10-26 22:04:55 +0000700{
701 IDsCaptureDriverBufferImpl_QueryInterface,
702 IDsCaptureDriverBufferImpl_AddRef,
703 IDsCaptureDriverBufferImpl_Release,
704 IDsCaptureDriverBufferImpl_Lock,
705 IDsCaptureDriverBufferImpl_Unlock,
706 IDsCaptureDriverBufferImpl_SetFormat,
707 IDsCaptureDriverBufferImpl_GetPosition,
708 IDsCaptureDriverBufferImpl_GetStatus,
709 IDsCaptureDriverBufferImpl_Start,
710 IDsCaptureDriverBufferImpl_Stop
711};
712
713static HRESULT WINAPI IDsCaptureDriverImpl_QueryInterface(
714 PIDSCDRIVER iface,
715 REFIID riid,
716 LPVOID *ppobj)
717{
718 IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
719 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
720
721 if ( IsEqualGUID(riid, &IID_IUnknown) ||
722 IsEqualGUID(riid, &IID_IDsCaptureDriver) ) {
723 IDsCaptureDriver_AddRef(iface);
Michael Stefaniucc0a92812009-01-22 09:52:59 +0100724 *ppobj = This;
Robert Reif0e3c5242004-10-26 22:04:55 +0000725 return DS_OK;
726 }
727
728 FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
729
730 *ppobj = 0;
731
732 return E_NOINTERFACE;
733}
734
735static ULONG WINAPI IDsCaptureDriverImpl_AddRef(PIDSCDRIVER iface)
736{
737 IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
James Hawkinsed12a3d2005-01-12 19:55:24 +0000738 ULONG refCount = InterlockedIncrement(&This->ref);
Robert Reif0e3c5242004-10-26 22:04:55 +0000739
Michael Stefaniuc10ee3302006-10-06 22:59:51 +0200740 TRACE("(%p) ref was %d\n", This, refCount - 1);
James Hawkinsed12a3d2005-01-12 19:55:24 +0000741
742 return refCount;
Robert Reif0e3c5242004-10-26 22:04:55 +0000743}
744
745static ULONG WINAPI IDsCaptureDriverImpl_Release(PIDSCDRIVER iface)
746{
747 IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
James Hawkinsed12a3d2005-01-12 19:55:24 +0000748 ULONG refCount = InterlockedDecrement(&This->ref);
Robert Reif0e3c5242004-10-26 22:04:55 +0000749
Michael Stefaniuc10ee3302006-10-06 22:59:51 +0200750 TRACE("(%p) ref was %d\n", This, refCount + 1);
James Hawkinsed12a3d2005-01-12 19:55:24 +0000751
752 if (!refCount) {
Robert Reif0e3c5242004-10-26 22:04:55 +0000753 HeapFree(GetProcessHeap(),0,This);
754 TRACE("(%p) released\n",This);
755 }
James Hawkinsed12a3d2005-01-12 19:55:24 +0000756 return refCount;
Robert Reif0e3c5242004-10-26 22:04:55 +0000757}
758
759static HRESULT WINAPI IDsCaptureDriverImpl_GetDriverDesc(
760 PIDSCDRIVER iface,
761 PDSDRIVERDESC pDesc)
762{
763 IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
764 TRACE("(%p,%p)\n",This,pDesc);
765
766 if (!pDesc) {
767 TRACE("invalid parameter\n");
768 return DSERR_INVALIDPARAM;
769 }
770
771 /* copy version from driver */
Andrew Talbotd2c602b2008-03-26 21:56:41 +0000772 *pDesc = WInDev[This->wDevID].ossdev.ds_desc;
Robert Reif0e3c5242004-10-26 22:04:55 +0000773
Robert Reif0e3c5242004-10-26 22:04:55 +0000774 pDesc->dnDevNode = WInDev[This->wDevID].waveDesc.dnDevNode;
775 pDesc->wVxdId = 0;
776 pDesc->wReserved = 0;
777 pDesc->ulDeviceNum = This->wDevID;
778 pDesc->dwHeapType = DSDHEAP_NOHEAP;
779 pDesc->pvDirectDrawHeap = NULL;
780 pDesc->dwMemStartAddress = 0;
781 pDesc->dwMemEndAddress = 0;
782 pDesc->dwMemAllocExtra = 0;
783 pDesc->pvReserved1 = NULL;
784 pDesc->pvReserved2 = NULL;
785 return DS_OK;
786}
787
788static HRESULT WINAPI IDsCaptureDriverImpl_Open(PIDSCDRIVER iface)
789{
790 IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
791 TRACE("(%p)\n",This);
792 return DS_OK;
793}
794
795static HRESULT WINAPI IDsCaptureDriverImpl_Close(PIDSCDRIVER iface)
796{
797 IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
798 TRACE("(%p)\n",This);
799 if (This->capture_buffer) {
800 ERR("problem with DirectSound: capture buffer not released\n");
801 return DSERR_GENERIC;
802 }
803 return DS_OK;
804}
805
806static HRESULT WINAPI IDsCaptureDriverImpl_GetCaps(
807 PIDSCDRIVER iface,
808 PDSCDRIVERCAPS pCaps)
809{
810 IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
811 TRACE("(%p,%p)\n",This,pCaps);
Andrew Talbotd2c602b2008-03-26 21:56:41 +0000812 *pCaps = WInDev[This->wDevID].ossdev.dsc_caps;
Robert Reif0e3c5242004-10-26 22:04:55 +0000813 return DS_OK;
814}
815
Robert Reif24da7562004-11-19 18:25:03 +0000816static void DSCDB_CheckEvent(
817 IDsCaptureDriverBufferImpl *dscb,
818 DWORD writepos,
819 DWORD len,
820 DWORD buflen)
821{
822 LPDSBPOSITIONNOTIFY event = dscb->notifies + dscb->notify_index;
823 DWORD offset = event->dwOffset;
Michael Stefaniuc10ee3302006-10-06 22:59:51 +0200824 TRACE("(%p,%d,%d,%d)\n", dscb, writepos, len, buflen);
Robert Reif24da7562004-11-19 18:25:03 +0000825
Michael Stefaniuc10ee3302006-10-06 22:59:51 +0200826 TRACE("(%p) buflen = %d, writeptr = %d\n",
Robert Reif24da7562004-11-19 18:25:03 +0000827 dscb, dscb->buflen, dscb->writeptr);
Michael Stefaniuc10ee3302006-10-06 22:59:51 +0200828 TRACE("checking %d, position %d, event = %p\n",
Robert Reif24da7562004-11-19 18:25:03 +0000829 dscb->notify_index, offset, event->hEventNotify);
830
831 if ((writepos + len) > offset) {
Michael Stefaniuc10ee3302006-10-06 22:59:51 +0200832 TRACE("signalled event %p (%d) %d\n",
Robert Reif24da7562004-11-19 18:25:03 +0000833 event->hEventNotify, dscb->notify_index, offset);
834 SetEvent(event->hEventNotify);
835 dscb->notify_index = (dscb->notify_index + 1) % dscb->nrofnotifies;
836 return;
837 } else if ((writepos + len) > buflen) {
838 writepos = writepos + len - buflen;
839 if ((writepos + len) > offset) {
Michael Stefaniuc10ee3302006-10-06 22:59:51 +0200840 TRACE("signalled event %p (%d) %d\n",
Robert Reif24da7562004-11-19 18:25:03 +0000841 event->hEventNotify, dscb->notify_index, offset);
842 SetEvent(event->hEventNotify);
843 dscb->notify_index = (dscb->notify_index + 1) % dscb->nrofnotifies;
844 return;
845 }
846 }
847
848 return;
849}
850
851/* FIXME: using memcpy can cause strange crashes so use this fake one */
852static void * my_memcpy(void * dst, const void * src, int length)
853{
854 int i;
855 for (i = 0; i < length; i++)
Andrew Talbot89bb5462006-11-23 20:29:00 +0000856 ((char *)dst)[i] = ((const char *)src)[i];
Robert Reif24da7562004-11-19 18:25:03 +0000857 return dst;
858}
859
860static DWORD CALLBACK DSCDB_Thread(LPVOID lpParameter)
861{
Michael Stefaniucc0a92812009-01-22 09:52:59 +0100862 IDsCaptureDriverBufferImpl *This = lpParameter;
Robert Reif24da7562004-11-19 18:25:03 +0000863 struct pollfd poll_list[2];
864 int retval;
865 DWORD offset = 0;
866 DWORD map_offset = 0;
867 TRACE("(%p)\n", lpParameter);
868
869 poll_list[0].fd = This->fd; /* data available */
870 poll_list[1].fd = This->pipe_fd[0]; /* message from parent process */
871 poll_list[0].events = POLLIN;
872 poll_list[1].events = POLLIN;
873
874 /* let other process know we are running */
875 SetEvent(This->hStartUpEvent);
876
877 while (1) {
878 /* wait for something to happen */
879 retval = poll(poll_list,(unsigned long)2,-1);
880 /* Retval will always be greater than 0 or -1 in this case.
881 * Since we're doing it while blocking
882 */
883 if (retval < 0) {
884 ERR("Error while polling: %s\n",strerror(errno));
885 continue;
886 }
887
888 /* check for exit command */
889 if ((poll_list[1].revents & POLLIN) == POLLIN) {
890 TRACE("(%p) done\n", lpParameter);
891 /* acknowledge command and exit */
892 SetEvent(This->hExitEvent);
893 ExitThread(0);
894 return 0;
895 }
896
897 /* check for data */
898 if ((poll_list[0].revents & POLLIN) == POLLIN) {
899 count_info info;
900 int fragsize, first, second;
901
902 /* get the current DMA position */
903 if (ioctl(This->fd, SNDCTL_DSP_GETIPTR, &info) < 0) {
904 ERR("ioctl(%s, SNDCTL_DSP_GETIPTR) failed (%s)\n",
Maarten Lankhorst58e26452007-10-01 09:16:59 +0200905 WInDev[This->drv->wDevID].ossdev.dev_name, strerror(errno));
Robert Reif24da7562004-11-19 18:25:03 +0000906 return DSERR_GENERIC;
907 }
908
909 if (This->is_direct_map) {
910 offset = This->map_writepos;
911 This->map_writepos = info.ptr;
912
913 if (info.ptr < offset)
914 fragsize = info.ptr + This->maplen - offset;
915 else
916 fragsize = info.ptr - offset;
917
918 DSCDB_CheckEvent(This, offset, fragsize, This->maplen);
919 } else {
920 map_offset = This->map_writepos;
921 offset = This->writeptr;
922
923 /* test for mmap buffer wrap */
924 if (info.ptr < map_offset) {
925 /* mmap buffer wrapped */
926 fragsize = info.ptr + This->maplen - map_offset;
927
928 /* check for user buffer wrap */
929 if ((offset + fragsize) > This->buflen) {
930 /* both buffers wrapped
931 * figure out which wrapped first
932 */
933 if ((This->maplen - map_offset) > (This->buflen - offset)) {
934 /* user buffer wrapped first */
935 first = This->buflen - offset;
936 second = (This->maplen - map_offset) - first;
937 my_memcpy(This->buffer + offset, This->mapping + map_offset, first);
938 my_memcpy(This->buffer, This->mapping + map_offset + first, second);
939 my_memcpy(This->buffer + second, This->mapping, fragsize - (first + second));
940 } else {
941 /* mmap buffer wrapped first */
942 first = This->maplen - map_offset;
943 second = (This->buflen - offset) - first;
944 my_memcpy(This->buffer + offset, This->mapping + map_offset, first);
945 my_memcpy(This->buffer + offset + first, This->mapping, second);
946 my_memcpy(This->buffer, This->mapping + second, fragsize - (first + second));
947 }
948 } else {
949 /* only mmap buffer wrapped */
950 first = This->maplen - map_offset;
951 my_memcpy(This->buffer + offset, This->mapping + map_offset, first);
952 my_memcpy(This->buffer + offset + first, This->mapping, fragsize - first);
953 }
954 } else {
955 /* mmap buffer didn't wrap */
956 fragsize = info.ptr - map_offset;
957
958 /* check for user buffer wrap */
959 if ((offset + fragsize) > This->buflen) {
960 first = This->buflen - offset;
961 my_memcpy(This->buffer + offset, This->mapping + map_offset, first);
962 my_memcpy(This->buffer, This->mapping + map_offset + first, fragsize - first);
963 } else
964 my_memcpy(This->buffer + offset, This->mapping + map_offset, fragsize);
965 }
966
967 This->map_writepos = info.ptr;
968 This->writeptr = (This->writeptr + fragsize) % This->buflen;
969 DSCDB_CheckEvent(This, offset, fragsize, This->buflen);
970 }
971 }
972 }
Robert Reif24da7562004-11-19 18:25:03 +0000973}
974
Robert Reif0e3c5242004-10-26 22:04:55 +0000975static HRESULT WINAPI IDsCaptureDriverImpl_CreateCaptureBuffer(
976 PIDSCDRIVER iface,
977 LPWAVEFORMATEX pwfx,
978 DWORD dwFlags,
979 DWORD dwCardAddress,
980 LPDWORD pdwcbBufferSize,
981 LPBYTE *ppbBuffer,
982 LPVOID *ppvObj)
983{
984 IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
985 IDsCaptureDriverBufferImpl** ippdscdb = (IDsCaptureDriverBufferImpl**)ppvObj;
986 HRESULT err;
987 audio_buf_info info;
Robert Reif24da7562004-11-19 18:25:03 +0000988 int audio_fragment, fsize, shift, ret;
989 BOOL bNewBuffer = FALSE;
990 WINE_WAVEIN* wwi;
Michael Stefaniuc10ee3302006-10-06 22:59:51 +0200991 TRACE("(%p,%p,%x,%x,%p,%p,%p)\n",This,pwfx,dwFlags,dwCardAddress,
Robert Reif0e3c5242004-10-26 22:04:55 +0000992 pdwcbBufferSize,ppbBuffer,ppvObj);
993
994 if (This->capture_buffer) {
995 TRACE("already allocated\n");
996 return DSERR_ALLOCATED;
997 }
998
Robert Reif24da7562004-11-19 18:25:03 +0000999 /* must be given a buffer size */
1000 if (pdwcbBufferSize == NULL || *pdwcbBufferSize == 0) {
1001 TRACE("invalid parameter: pdwcbBufferSize\n");
1002 return DSERR_INVALIDPARAM;
1003 }
1004
1005 /* must be given a buffer pointer */
1006 if (ppbBuffer == NULL) {
1007 TRACE("invalid parameter: ppbBuffer\n");
1008 return DSERR_INVALIDPARAM;
1009 }
1010
1011 /* may or may not be given a buffer */
1012 if (*ppbBuffer == NULL) {
1013 TRACE("creating buffer\n");
1014 bNewBuffer = TRUE; /* not given a buffer so create one */
1015 } else
1016 TRACE("using supplied buffer\n");
1017
1018 *ippdscdb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsCaptureDriverBufferImpl));
Robert Reif0e3c5242004-10-26 22:04:55 +00001019 if (*ippdscdb == NULL) {
1020 TRACE("out of memory\n");
1021 return DSERR_OUTOFMEMORY;
1022 }
1023
Robert Reif24da7562004-11-19 18:25:03 +00001024 (*ippdscdb)->lpVtbl = &dscdbvt;
Robert Reif0e3c5242004-10-26 22:04:55 +00001025 (*ippdscdb)->ref = 1;
1026 (*ippdscdb)->drv = This;
1027 (*ippdscdb)->notify = NULL;
1028 (*ippdscdb)->notify_index = 0;
1029 (*ippdscdb)->notifies = NULL;
1030 (*ippdscdb)->nrofnotifies = 0;
1031 (*ippdscdb)->property_set = NULL;
1032 (*ippdscdb)->is_capturing = FALSE;
1033 (*ippdscdb)->is_looping = FALSE;
Robert Reif24da7562004-11-19 18:25:03 +00001034 (*ippdscdb)->wfx = *pwfx;
1035 (*ippdscdb)->buflen = *pdwcbBufferSize;
Robert Reif0e3c5242004-10-26 22:04:55 +00001036
Robert Reif24da7562004-11-19 18:25:03 +00001037 if (bNewBuffer)
1038 (*ippdscdb)->buffer = NULL;
1039 else
1040 (*ippdscdb)->buffer = *ppbBuffer;
1041
1042 wwi = &WInDev[This->wDevID];
1043
1044 if (wwi->state == WINE_WS_CLOSED) {
1045 unsigned int frag_size;
1046
Maarten Lankhorst58e26452007-10-01 09:16:59 +02001047 if (wwi->ossdev.open_count > 0) {
Robert Reif24da7562004-11-19 18:25:03 +00001048 /* opened already so use existing fragment size */
Maarten Lankhorst58e26452007-10-01 09:16:59 +02001049 audio_fragment = wwi->ossdev.audio_fragment;
Robert Reif24da7562004-11-19 18:25:03 +00001050 } else {
1051 /* calculate a fragment size */
1052 unsigned int mask = 0xffffffff;
1053
1054 /* calculate largest fragment size less than 10 ms. */
1055 fsize = pwfx->nAvgBytesPerSec / 100; /* 10 ms chunk */
1056 shift = 0;
1057 while ((1 << shift) <= fsize)
1058 shift++;
1059 shift--;
1060 fsize = 1 << shift;
1061 TRACE("shift = %d, fragment size = %d\n", shift, fsize);
Michael Stefaniuc10ee3302006-10-06 22:59:51 +02001062 TRACE("BufferSize=%d(%08x)\n", *pdwcbBufferSize, *pdwcbBufferSize);
Robert Reif24da7562004-11-19 18:25:03 +00001063
1064 /* See if we can directly map the buffer first.
1065 * (buffer length is multiple of a power of 2)
1066 */
1067 mask = (mask >> (32 - shift));
1068 TRACE("mask=%08x\n", mask);
1069 if (*pdwcbBufferSize & mask) {
1070 /* no so try a smaller fragment size greater than 1 ms */
1071 int new_shift = shift - 1;
1072 int min_shift = 0;
1073 int min_fsize = pwfx->nAvgBytesPerSec / 1000;
1074 BOOL found_one = FALSE;
1075 while ((1 << min_shift) <= min_fsize)
1076 min_shift++;
1077 min_shift--;
1078 while (new_shift > min_shift) {
1079 if (*pdwcbBufferSize & (-1 >> (32 - new_shift))) {
1080 new_shift--;
1081 continue;
1082 } else {
1083 found_one = TRUE;
1084 break;
1085 }
1086 }
1087 if (found_one) {
1088 /* found a smaller one that will work */
1089 audio_fragment = ((*pdwcbBufferSize >> new_shift) << 16) | new_shift;
1090 (*ippdscdb)->is_direct_map = TRUE;
1091 TRACE("new shift = %d, fragment size = %d\n",
1092 new_shift, 1 << (audio_fragment & 0xffff));
1093 } else {
1094 /* buffer can't be direct mapped */
1095 audio_fragment = 0x00100000 + shift; /* 16 fragments of 2^shift */
1096 (*ippdscdb)->is_direct_map = FALSE;
1097 }
1098 } else {
1099 /* good fragment size */
1100 audio_fragment = ((*pdwcbBufferSize >> shift) << 16) | shift;
1101 (*ippdscdb)->is_direct_map = TRUE;
1102 }
1103 }
1104 frag_size = 1 << (audio_fragment & 0xffff);
1105 TRACE("is_direct_map = %s\n", (*ippdscdb)->is_direct_map ? "TRUE" : "FALSE");
Michael Stefaniuc10ee3302006-10-06 22:59:51 +02001106 TRACE("requesting %d %d byte fragments (%d bytes) (%d ms/fragment)\n",
Robert Reif24da7562004-11-19 18:25:03 +00001107 audio_fragment >> 16, frag_size, frag_size * (audio_fragment >> 16),
1108 (frag_size * 1000) / pwfx->nAvgBytesPerSec);
1109
Maarten Lankhorst58e26452007-10-01 09:16:59 +02001110 ret = OSS_OpenDevice(&wwi->ossdev, O_RDWR, &audio_fragment, 1,
Robert Reif24da7562004-11-19 18:25:03 +00001111 pwfx->nSamplesPerSec,
1112 (pwfx->nChannels > 1) ? 1 : 0,
1113 (pwfx->wBitsPerSample == 16)
1114 ? AFMT_S16_LE : AFMT_U8);
1115
1116 if (ret != 0) {
1117 WARN("OSS_OpenDevice failed\n");
1118 HeapFree(GetProcessHeap(),0,*ippdscdb);
1119 *ippdscdb = NULL;
1120 return DSERR_GENERIC;
1121 }
1122
1123 wwi->state = WINE_WS_STOPPED;
1124
1125 /* find out what fragment and buffer sizes OSS gave us */
Maarten Lankhorst58e26452007-10-01 09:16:59 +02001126 if (ioctl(wwi->ossdev.fd, SNDCTL_DSP_GETISPACE, &info) < 0) {
Robert Reif24da7562004-11-19 18:25:03 +00001127 ERR("ioctl(%s, SNDCTL_DSP_GETISPACE) failed (%s)\n",
Maarten Lankhorst58e26452007-10-01 09:16:59 +02001128 wwi->ossdev.dev_name, strerror(errno));
1129 OSS_CloseDevice(&wwi->ossdev);
Robert Reif24da7562004-11-19 18:25:03 +00001130 wwi->state = WINE_WS_CLOSED;
1131 HeapFree(GetProcessHeap(),0,*ippdscdb);
1132 *ippdscdb = NULL;
1133 return DSERR_GENERIC;
1134 }
1135
Michael Stefaniuc10ee3302006-10-06 22:59:51 +02001136 TRACE("got %d %d byte fragments (%d bytes) (%d ms/fragment)\n",
Robert Reif24da7562004-11-19 18:25:03 +00001137 info.fragstotal, info.fragsize, info.fragstotal * info.fragsize,
1138 info.fragsize * 1000 / pwfx->nAvgBytesPerSec);
1139
1140 wwi->dwTotalRecorded = 0;
1141 memcpy(&wwi->waveFormat, pwfx, sizeof(PCMWAVEFORMAT));
1142 wwi->dwFragmentSize = info.fragsize;
1143
1144 /* make sure we got what we asked for */
1145 if ((*ippdscdb)->buflen != info.fragstotal * info.fragsize) {
1146 TRACE("Couldn't create requested buffer\n");
1147 if ((*ippdscdb)->is_direct_map) {
1148 (*ippdscdb)->is_direct_map = FALSE;
1149 TRACE("is_direct_map = FALSE\n");
1150 }
1151 } else if (info.fragsize != frag_size) {
1152 TRACE("same buffer length but different fragment size\n");
Robert Reif0e3c5242004-10-26 22:04:55 +00001153 }
1154 }
Maarten Lankhorst58e26452007-10-01 09:16:59 +02001155 (*ippdscdb)->fd = WInDev[This->wDevID].ossdev.fd;
Robert Reif0e3c5242004-10-26 22:04:55 +00001156
Robert Reif24da7562004-11-19 18:25:03 +00001157 if (pipe((*ippdscdb)->pipe_fd) < 0) {
1158 TRACE("pipe() failed (%s)\n", strerror(errno));
Maarten Lankhorst58e26452007-10-01 09:16:59 +02001159 OSS_CloseDevice(&wwi->ossdev);
Robert Reif24da7562004-11-19 18:25:03 +00001160 wwi->state = WINE_WS_CLOSED;
Robert Reif0e3c5242004-10-26 22:04:55 +00001161 HeapFree(GetProcessHeap(),0,*ippdscdb);
1162 *ippdscdb = NULL;
1163 return DSERR_GENERIC;
1164 }
Robert Reif24da7562004-11-19 18:25:03 +00001165
1166 /* check how big the DMA buffer is now */
Maarten Lankhorst58e26452007-10-01 09:16:59 +02001167 if (ioctl(wwi->ossdev.fd, SNDCTL_DSP_GETISPACE, &info) < 0) {
Robert Reif24da7562004-11-19 18:25:03 +00001168 ERR("ioctl(%s, SNDCTL_DSP_GETISPACE) failed (%s)\n",
Maarten Lankhorst58e26452007-10-01 09:16:59 +02001169 wwi->ossdev.dev_name, strerror(errno));
1170 OSS_CloseDevice(&wwi->ossdev);
Robert Reif24da7562004-11-19 18:25:03 +00001171 wwi->state = WINE_WS_CLOSED;
1172 close((*ippdscdb)->pipe_fd[0]);
1173 close((*ippdscdb)->pipe_fd[1]);
1174 HeapFree(GetProcessHeap(),0,*ippdscdb);
1175 *ippdscdb = NULL;
1176 return DSERR_GENERIC;
1177 }
1178
1179 (*ippdscdb)->maplen = info.fragstotal * info.fragsize;
1180 (*ippdscdb)->fragsize = info.fragsize;
1181 (*ippdscdb)->map_writepos = 0;
1182 (*ippdscdb)->map_readpos = 0;
Robert Reif0e3c5242004-10-26 22:04:55 +00001183
1184 /* map the DMA buffer */
1185 err = DSCDB_MapBuffer(*ippdscdb);
1186 if (err != DS_OK) {
Maarten Lankhorst58e26452007-10-01 09:16:59 +02001187 OSS_CloseDevice(&wwi->ossdev);
Robert Reif24da7562004-11-19 18:25:03 +00001188 wwi->state = WINE_WS_CLOSED;
1189 close((*ippdscdb)->pipe_fd[0]);
1190 close((*ippdscdb)->pipe_fd[1]);
Robert Reif0e3c5242004-10-26 22:04:55 +00001191 HeapFree(GetProcessHeap(),0,*ippdscdb);
1192 *ippdscdb = NULL;
1193 return err;
1194 }
1195
Robert Reif24da7562004-11-19 18:25:03 +00001196 /* create the buffer if necessary */
1197 if (!(*ippdscdb)->buffer)
1198 (*ippdscdb)->buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,(*ippdscdb)->buflen);
Robert Reif0e3c5242004-10-26 22:04:55 +00001199
Robert Reif24da7562004-11-19 18:25:03 +00001200 if ((*ippdscdb)->buffer == NULL) {
Maarten Lankhorst58e26452007-10-01 09:16:59 +02001201 OSS_CloseDevice(&wwi->ossdev);
Robert Reif24da7562004-11-19 18:25:03 +00001202 wwi->state = WINE_WS_CLOSED;
1203 close((*ippdscdb)->pipe_fd[0]);
1204 close((*ippdscdb)->pipe_fd[1]);
1205 HeapFree(GetProcessHeap(),0,*ippdscdb);
1206 *ippdscdb = NULL;
1207 return DSERR_OUTOFMEMORY;
Robert Reif0e3c5242004-10-26 22:04:55 +00001208 }
1209
1210 This->capture_buffer = *ippdscdb;
1211
Alexandre Julliardb4e49552004-12-06 20:55:25 +00001212 (*ippdscdb)->hStartUpEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
1213 (*ippdscdb)->hExitEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
Robert Reif24da7562004-11-19 18:25:03 +00001214
Michael Stefaniucc0a92812009-01-22 09:52:59 +01001215 (*ippdscdb)->hThread = CreateThread(NULL, 0, DSCDB_Thread, *ippdscdb, 0, &((*ippdscdb)->dwThreadID));
Robert Reif24da7562004-11-19 18:25:03 +00001216 WaitForSingleObject((*ippdscdb)->hStartUpEvent, INFINITE);
1217 CloseHandle((*ippdscdb)->hStartUpEvent);
1218 (*ippdscdb)->hStartUpEvent = INVALID_HANDLE_VALUE;
1219
Robert Reif0e3c5242004-10-26 22:04:55 +00001220 return DS_OK;
1221}
1222
Dmitry Timoshkoveba47f12005-06-06 19:50:35 +00001223static const IDsCaptureDriverVtbl dscdvt =
Robert Reif0e3c5242004-10-26 22:04:55 +00001224{
1225 IDsCaptureDriverImpl_QueryInterface,
1226 IDsCaptureDriverImpl_AddRef,
1227 IDsCaptureDriverImpl_Release,
1228 IDsCaptureDriverImpl_GetDriverDesc,
1229 IDsCaptureDriverImpl_Open,
1230 IDsCaptureDriverImpl_Close,
1231 IDsCaptureDriverImpl_GetCaps,
1232 IDsCaptureDriverImpl_CreateCaptureBuffer
1233};
1234
Francois Gougetec6f88b2008-11-24 17:24:29 +01001235static HRESULT IDsCaptureDriverPropertySetImpl_Create(
Robert Reif0e3c5242004-10-26 22:04:55 +00001236 IDsCaptureDriverBufferImpl * dscdb,
1237 IDsCaptureDriverPropertySetImpl **pdscdps)
1238{
1239 IDsCaptureDriverPropertySetImpl * dscdps;
1240 TRACE("(%p,%p)\n",dscdb,pdscdps);
1241
Andrew Talbotddfbe4e2008-05-10 16:25:33 +01001242 dscdps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dscdps));
Robert Reif0e3c5242004-10-26 22:04:55 +00001243 if (dscdps == NULL) {
1244 WARN("out of memory\n");
1245 return DSERR_OUTOFMEMORY;
1246 }
1247
1248 dscdps->ref = 0;
1249 dscdps->lpVtbl = &dscdpsvt;
1250 dscdps->capture_buffer = dscdb;
1251 dscdb->property_set = dscdps;
1252 IDsCaptureDriverBuffer_AddRef((PIDSCDRIVER)dscdb);
1253
1254 *pdscdps = dscdps;
1255 return DS_OK;
1256}
1257
Francois Gougetec6f88b2008-11-24 17:24:29 +01001258static HRESULT IDsCaptureDriverNotifyImpl_Create(
Robert Reif0e3c5242004-10-26 22:04:55 +00001259 IDsCaptureDriverBufferImpl * dscdb,
1260 IDsCaptureDriverNotifyImpl **pdscdn)
1261{
1262 IDsCaptureDriverNotifyImpl * dscdn;
1263 TRACE("(%p,%p)\n",dscdb,pdscdn);
1264
Andrew Talbotddfbe4e2008-05-10 16:25:33 +01001265 dscdn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dscdn));
Robert Reif0e3c5242004-10-26 22:04:55 +00001266 if (dscdn == NULL) {
1267 WARN("out of memory\n");
1268 return DSERR_OUTOFMEMORY;
1269 }
1270
1271 dscdn->ref = 0;
1272 dscdn->lpVtbl = &dscdnvt;
1273 dscdn->capture_buffer = dscdb;
1274 dscdb->notify = dscdn;
1275 IDsCaptureDriverBuffer_AddRef((PIDSCDRIVER)dscdb);
1276
1277 *pdscdn = dscdn;
1278 return DS_OK;
1279}
1280
1281DWORD widDsCreate(UINT wDevID, PIDSCDRIVER* drv)
1282{
1283 IDsCaptureDriverImpl** idrv = (IDsCaptureDriverImpl**)drv;
1284 TRACE("(%d,%p)\n",wDevID,drv);
1285
1286 /* the HAL isn't much better than the HEL if we can't do mmap() */
Maarten Lankhorst58e26452007-10-01 09:16:59 +02001287 if (!(WInDev[wDevID].ossdev.in_caps_support & WAVECAPS_DIRECTSOUND)) {
Robert Reif0e3c5242004-10-26 22:04:55 +00001288 ERR("DirectSoundCapture flag not set\n");
1289 MESSAGE("This sound card's driver does not support direct access\n");
1290 MESSAGE("The (slower) DirectSound HEL mode will be used instead.\n");
1291 return MMSYSERR_NOTSUPPORTED;
1292 }
1293
Jakob Eriksson9ed61de2005-03-24 21:01:35 +00001294 *idrv = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsCaptureDriverImpl));
Robert Reif0e3c5242004-10-26 22:04:55 +00001295 if (!*idrv)
1296 return MMSYSERR_NOMEM;
1297 (*idrv)->lpVtbl = &dscdvt;
1298 (*idrv)->ref = 1;
1299
1300 (*idrv)->wDevID = wDevID;
1301 (*idrv)->capture_buffer = NULL;
1302 return MMSYSERR_NOERROR;
1303}
1304
1305DWORD widDsDesc(UINT wDevID, PDSDRIVERDESC desc)
1306{
Maarten Lankhorst58e26452007-10-01 09:16:59 +02001307 memcpy(desc, &(WInDev[wDevID].ossdev.ds_desc), sizeof(DSDRIVERDESC));
Robert Reif0e3c5242004-10-26 22:04:55 +00001308 return MMSYSERR_NOERROR;
1309}
1310
1311#endif /* HAVE_OSS */