1 /* IDirectMusicAudioPath Implementation
3 * Copyright (C) 2003-2004 Rok Mandeljc
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "dmime_private.h"
22 WINE_DEFAULT_DEBUG_CHANNEL(dmime
);
24 struct IDirectMusicAudioPathImpl
{
25 IDirectMusicAudioPath IDirectMusicAudioPath_iface
;
27 IDirectMusicPerformance8
* pPerf
;
28 IDirectMusicGraph
* pToolGraph
;
29 IDirectSoundBuffer
* pDSBuffer
;
30 IDirectSoundBuffer
* pPrimary
;
35 struct audio_path_pchannel_to_buffer
38 DMUS_IO_PCHANNELTOBUFFER_HEADER header
;
42 C_ASSERT(sizeof(struct audio_path_pchannel_to_buffer
) == offsetof(struct audio_path_pchannel_to_buffer
, guids
[0]));
44 struct audio_path_port_config
47 DMUS_IO_PORTCONFIG_HEADER header
;
48 DMUS_PORTPARAMS8 params
;
50 struct list pchannel_to_buffer_entries
;
53 struct audio_path_config
55 IUnknown IUnknown_iface
;
56 struct dmobject dmobj
;
59 struct list port_config_entries
;
62 static inline struct IDirectMusicAudioPathImpl
*impl_from_IDirectMusicAudioPath(IDirectMusicAudioPath
*iface
)
64 return CONTAINING_RECORD(iface
, struct IDirectMusicAudioPathImpl
, IDirectMusicAudioPath_iface
);
67 static inline struct audio_path_config
*impl_from_IPersistStream(IPersistStream
*iface
)
69 return CONTAINING_RECORD(iface
, struct audio_path_config
, dmobj
.IPersistStream_iface
);
72 void set_audiopath_perf_pointer(IDirectMusicAudioPath
*iface
, IDirectMusicPerformance8
*performance
)
74 struct IDirectMusicAudioPathImpl
*This
= impl_from_IDirectMusicAudioPath(iface
);
75 This
->pPerf
= performance
;
78 void set_audiopath_dsound_buffer(IDirectMusicAudioPath
*iface
, IDirectSoundBuffer
*buffer
)
80 struct IDirectMusicAudioPathImpl
*This
= impl_from_IDirectMusicAudioPath(iface
);
81 This
->pDSBuffer
= buffer
;
84 void set_audiopath_primary_dsound_buffer(IDirectMusicAudioPath
*iface
, IDirectSoundBuffer
*buffer
)
86 struct IDirectMusicAudioPathImpl
*This
= impl_from_IDirectMusicAudioPath(iface
);
87 This
->pPrimary
= buffer
;
90 /*****************************************************************************
91 * IDirectMusicAudioPathImpl implementation
93 static HRESULT WINAPI
IDirectMusicAudioPathImpl_QueryInterface (IDirectMusicAudioPath
*iface
, REFIID riid
, void **ppobj
)
95 struct IDirectMusicAudioPathImpl
*This
= impl_from_IDirectMusicAudioPath(iface
);
97 TRACE("(%p, %s, %p)\n", This
, debugstr_dmguid(riid
), ppobj
);
101 if (IsEqualIID (riid
, &IID_IDirectMusicAudioPath
) || IsEqualIID (riid
, &IID_IUnknown
))
102 *ppobj
= &This
->IDirectMusicAudioPath_iface
;
105 IUnknown_AddRef((IUnknown
*)*ppobj
);
109 WARN("(%p, %s, %p): not found\n", This
, debugstr_dmguid(riid
), ppobj
);
110 return E_NOINTERFACE
;
113 static ULONG WINAPI
IDirectMusicAudioPathImpl_AddRef (IDirectMusicAudioPath
*iface
)
115 struct IDirectMusicAudioPathImpl
*This
= impl_from_IDirectMusicAudioPath(iface
);
116 ULONG ref
= InterlockedIncrement(&This
->ref
);
118 TRACE("(%p): ref=%ld\n", This
, ref
);
123 static ULONG WINAPI
IDirectMusicAudioPathImpl_Release (IDirectMusicAudioPath
*iface
)
125 struct IDirectMusicAudioPathImpl
*This
= impl_from_IDirectMusicAudioPath(iface
);
126 ULONG ref
= InterlockedDecrement(&This
->ref
);
128 TRACE("(%p): ref=%ld\n", This
, ref
);
132 IDirectSoundBuffer_Release(This
->pPrimary
);
134 IDirectSoundBuffer_Release(This
->pDSBuffer
);
142 static HRESULT WINAPI
IDirectMusicAudioPathImpl_GetObjectInPath (IDirectMusicAudioPath
*iface
, DWORD dwPChannel
, DWORD dwStage
, DWORD dwBuffer
,
143 REFGUID guidObject
, DWORD dwIndex
, REFGUID iidInterface
, void** ppObject
)
145 struct IDirectMusicAudioPathImpl
*This
= impl_from_IDirectMusicAudioPath(iface
);
148 FIXME("(%p, %ld, %ld, %ld, %s, %ld, %s, %p): stub\n", This
, dwPChannel
, dwStage
, dwBuffer
, debugstr_dmguid(guidObject
),
149 dwIndex
, debugstr_dmguid(iidInterface
), ppObject
);
152 case DMUS_PATH_BUFFER
:
155 if (IsEqualIID (iidInterface
, &IID_IUnknown
) ||
156 IsEqualIID (iidInterface
, &IID_IDirectSoundBuffer
) ||
157 IsEqualIID (iidInterface
, &IID_IDirectSoundBuffer8
) ||
158 IsEqualIID (iidInterface
, &IID_IDirectSound3DBuffer
)) {
159 return IDirectSoundBuffer_QueryInterface(This
->pDSBuffer
, iidInterface
, ppObject
);
162 WARN("Unsupported interface %s\n", debugstr_dmguid(iidInterface
));
164 return E_NOINTERFACE
;
168 case DMUS_PATH_PRIMARY_BUFFER
: {
169 if (IsEqualIID (iidInterface
, &IID_IDirectSound3DListener
)) {
170 IDirectSoundBuffer_QueryInterface(This
->pPrimary
, &IID_IDirectSound3DListener
, ppObject
);
173 FIXME("bad iid...\n");
178 case DMUS_PATH_AUDIOPATH_GRAPH
:
180 if (IsEqualIID (iidInterface
, &IID_IDirectMusicGraph
)) {
181 if (NULL
== This
->pToolGraph
) {
182 IDirectMusicGraph
* pGraph
;
183 hr
= create_dmgraph(&IID_IDirectMusicGraph
, (void**)&pGraph
);
186 This
->pToolGraph
= pGraph
;
188 *ppObject
= This
->pToolGraph
;
189 IDirectMusicGraph_AddRef((LPDIRECTMUSICGRAPH
) *ppObject
);
195 case DMUS_PATH_AUDIOPATH_TOOL
:
201 case DMUS_PATH_PERFORMANCE
:
203 /* TODO check wanted GUID */
204 *ppObject
= This
->pPerf
;
205 IUnknown_AddRef((LPUNKNOWN
) *ppObject
);
210 case DMUS_PATH_PERFORMANCE_GRAPH
:
212 IDirectMusicGraph
* pPerfoGraph
= NULL
;
213 IDirectMusicPerformance8_GetGraph(This
->pPerf
, &pPerfoGraph
);
214 if (NULL
== pPerfoGraph
) {
215 IDirectMusicGraph
* pGraph
= NULL
;
216 hr
= create_dmgraph(&IID_IDirectMusicGraph
, (void**)&pGraph
);
219 IDirectMusicPerformance8_SetGraph(This
->pPerf
, pGraph
);
220 pPerfoGraph
= pGraph
;
222 *ppObject
= pPerfoGraph
;
227 case DMUS_PATH_PERFORMANCE_TOOL
:
236 static HRESULT WINAPI
IDirectMusicAudioPathImpl_Activate(IDirectMusicAudioPath
*iface
, BOOL activate
)
238 struct IDirectMusicAudioPathImpl
*This
= impl_from_IDirectMusicAudioPath(iface
);
240 FIXME("(%p, %d): semi-stub\n", This
, activate
);
242 if (!!activate
== This
->fActive
)
245 if (!activate
&& This
->pDSBuffer
) {
246 /* Path is being deactivated */
247 IDirectSoundBuffer_Stop(This
->pDSBuffer
);
250 This
->fActive
= !!activate
;
255 static HRESULT WINAPI
IDirectMusicAudioPathImpl_SetVolume (IDirectMusicAudioPath
*iface
, LONG lVolume
, DWORD dwDuration
)
257 struct IDirectMusicAudioPathImpl
*This
= impl_from_IDirectMusicAudioPath(iface
);
258 FIXME("(%p, %li, %ld): stub\n", This
, lVolume
, dwDuration
);
262 static HRESULT WINAPI
IDirectMusicAudioPathImpl_ConvertPChannel (IDirectMusicAudioPath
*iface
, DWORD dwPChannelIn
, DWORD
* pdwPChannelOut
)
264 struct IDirectMusicAudioPathImpl
*This
= impl_from_IDirectMusicAudioPath(iface
);
265 FIXME("(%p, %ld, %p): stub\n", This
, dwPChannelIn
, pdwPChannelOut
);
269 static const IDirectMusicAudioPathVtbl DirectMusicAudioPathVtbl
= {
270 IDirectMusicAudioPathImpl_QueryInterface
,
271 IDirectMusicAudioPathImpl_AddRef
,
272 IDirectMusicAudioPathImpl_Release
,
273 IDirectMusicAudioPathImpl_GetObjectInPath
,
274 IDirectMusicAudioPathImpl_Activate
,
275 IDirectMusicAudioPathImpl_SetVolume
,
276 IDirectMusicAudioPathImpl_ConvertPChannel
279 /* IDirectMusicObject */
280 static HRESULT WINAPI
path_config_IDirectMusicObject_ParseDescriptor(IDirectMusicObject
*iface
,
281 IStream
*stream
, DMUS_OBJECTDESC
*desc
)
283 struct chunk_entry riff
= {0};
286 TRACE("(%p, %p, %p)\n", iface
, stream
, desc
);
290 if (!desc
|| desc
->dwSize
!= sizeof(*desc
))
293 if ((hr
= stream_get_chunk(stream
, &riff
)) != S_OK
)
295 if (riff
.id
!= FOURCC_RIFF
|| riff
.type
!= DMUS_FOURCC_AUDIOPATH_FORM
) {
296 TRACE("loading failed: unexpected %s\n", debugstr_chunk(&riff
));
297 stream_skip_chunk(stream
, &riff
);
298 return DMUS_E_CHUNKNOTFOUND
;
301 hr
= dmobj_parsedescriptor(stream
, &riff
, desc
,
302 DMUS_OBJ_OBJECT
|DMUS_OBJ_NAME
|DMUS_OBJ_CATEGORY
|DMUS_OBJ_VERSION
);
306 desc
->guidClass
= CLSID_DirectMusicAudioPathConfig
;
307 desc
->dwValidData
|= DMUS_OBJ_CLASS
;
309 dump_DMUS_OBJECTDESC(desc
);
313 static const IDirectMusicObjectVtbl dmobject_vtbl
= {
314 dmobj_IDirectMusicObject_QueryInterface
,
315 dmobj_IDirectMusicObject_AddRef
,
316 dmobj_IDirectMusicObject_Release
,
317 dmobj_IDirectMusicObject_GetDescriptor
,
318 dmobj_IDirectMusicObject_SetDescriptor
,
319 path_config_IDirectMusicObject_ParseDescriptor
322 static HRESULT
parse_pchannel_to_buffers_list(struct audio_path_port_config
*This
, IStream
*stream
, const struct chunk_entry
*pchl
)
324 struct chunk_entry chunk
= { .parent
= pchl
};
325 struct audio_path_pchannel_to_buffer
*pchannel_to_buffer
= NULL
;
326 DMUS_IO_PCHANNELTOBUFFER_HEADER header
;
331 while ((hr
= stream_next_chunk(stream
, &chunk
)) == S_OK
)
335 case DMUS_FOURCC_PCHANNELS_ITEM
:
336 hr
= stream_read(stream
, &header
, sizeof(header
));
340 TRACE("Got PChannelToBuffer header:\n");
341 TRACE("\tdwPChannelCount: %lu\n", header
.dwPChannelCount
);
342 TRACE("\tdwPChannelBase: %lu\n", header
.dwPChannelBase
);
343 TRACE("\tdwBufferCount: %lu\n", header
.dwBufferCount
);
344 TRACE("\tdwFlags: %lx\n", header
.dwFlags
);
346 bytes
= chunk
.size
- sizeof(header
);
348 if (bytes
!= sizeof(GUID
) * header
.dwBufferCount
)
350 WARN("Invalid size of GUIDs array\n");
355 pchannel_to_buffer
= calloc(1, sizeof(*pchannel_to_buffer
) + bytes
);
356 if (!pchannel_to_buffer
)
362 pchannel_to_buffer
->header
= header
;
363 TRACE("number of GUIDs: %lu\n", pchannel_to_buffer
->header
.dwBufferCount
);
365 hr
= stream_read(stream
, pchannel_to_buffer
->guids
, bytes
);
369 for (i
= 0; i
< pchannel_to_buffer
->header
.dwBufferCount
; i
++)
370 TRACE("\tguids[%lu]: %s\n", i
, debugstr_dmguid(&pchannel_to_buffer
->guids
[i
]));
372 list_add_tail(&This
->pchannel_to_buffer_entries
, &pchannel_to_buffer
->entry
);
373 pchannel_to_buffer
= NULL
;
376 if (chunk
.type
== DMUS_FOURCC_UNFO_LIST
)
377 TRACE("Unfo list in PChannelToBuffer is ignored\n");
379 WARN("Unknown %s\n", debugstr_chunk(&chunk
));
381 case MAKEFOURCC('p','b','g','d'):
382 FIXME("Undocumented %s\n", debugstr_chunk(&chunk
));
385 WARN("Unknown %s\n", debugstr_chunk(&chunk
));
393 if (FAILED(hr
) && pchannel_to_buffer
)
394 free(pchannel_to_buffer
);
398 static void port_config_destroy(struct audio_path_port_config
*port_config
)
400 struct audio_path_pchannel_to_buffer
*pchannel_to_buffer
, *next_pchannel_to_buffer
;
401 LIST_FOR_EACH_ENTRY_SAFE(pchannel_to_buffer
, next_pchannel_to_buffer
, &port_config
->pchannel_to_buffer_entries
,
402 struct audio_path_pchannel_to_buffer
, entry
)
404 list_remove(&pchannel_to_buffer
->entry
);
405 free(pchannel_to_buffer
);
410 static HRESULT
parse_port_config_list(struct audio_path_config
*This
, IStream
*stream
, const struct chunk_entry
*pcfl
)
412 struct chunk_entry chunk
= { .parent
= pcfl
};
413 struct audio_path_port_config
*port_config
= calloc(1, sizeof(*port_config
));
417 return E_OUTOFMEMORY
;
419 list_init(&port_config
->pchannel_to_buffer_entries
);
421 while ((hr
= stream_next_chunk(stream
, &chunk
)) == S_OK
)
425 case DMUS_FOURCC_PORTCONFIG_ITEM
:
426 hr
= stream_chunk_get_data(stream
, &chunk
, &port_config
->header
, sizeof(port_config
->header
));
429 TRACE("Got PortConfig header:\n");
430 TRACE("\tdwPChannelBase: %lu\n", port_config
->header
.dwPChannelBase
);
431 TRACE("\tdwPChannelCount: %lu\n", port_config
->header
.dwPChannelCount
);
432 TRACE("\tdwFlags: %lx\n", port_config
->header
.dwFlags
);
433 TRACE("\tguidPort: %s\n", debugstr_dmguid(&port_config
->header
.guidPort
));
435 case DMUS_FOURCC_PORTPARAMS_ITEM
:
436 hr
= stream_chunk_get_data(stream
, &chunk
, &port_config
->params
, sizeof(port_config
->params
));
439 TRACE("Got PortConfig params:\n");
440 TRACE("\tdwSize: %lu\n", port_config
->params
.dwSize
);
441 TRACE("\tdwValidParams: %lx\n", port_config
->params
.dwValidParams
);
442 if (port_config
->params
.dwValidParams
& DMUS_PORTPARAMS_VOICES
)
443 TRACE("\tvoices: %lu\n", port_config
->params
.dwVoices
);
444 if (port_config
->params
.dwValidParams
& DMUS_PORTPARAMS_CHANNELGROUPS
)
445 TRACE("\tchannel groups: %lu\n", port_config
->params
.dwChannelGroups
);
446 if (port_config
->params
.dwValidParams
& DMUS_PORTPARAMS_AUDIOCHANNELS
)
447 TRACE("\taudio channels: %lu\n", port_config
->params
.dwAudioChannels
);
448 if (port_config
->params
.dwValidParams
& DMUS_PORTPARAMS_SAMPLERATE
)
449 TRACE("\tsample rate: %lu\n", port_config
->params
.dwSampleRate
);
450 if (port_config
->params
.dwValidParams
& DMUS_PORTPARAMS_EFFECTS
)
451 TRACE("\teffects: %lx\n", port_config
->params
.dwEffectFlags
);
452 if (port_config
->params
.dwValidParams
& DMUS_PORTPARAMS_SHARE
)
453 TRACE("\tshare: %d\n", port_config
->params
.fShare
);
454 if (port_config
->params
.dwValidParams
& DMUS_PORTPARAMS_FEATURES
)
455 TRACE("\tfeatures: %lx\n", port_config
->params
.dwFeatures
);
458 if (chunk
.type
== DMUS_FOURCC_DSBUFFER_LIST
)
459 FIXME("DirectSound buffer descriptors is not supported\n");
460 else if (chunk
.type
== DMUS_FOURCC_PCHANNELS_LIST
)
461 hr
= parse_pchannel_to_buffers_list(port_config
, stream
, &chunk
);
462 else if (chunk
.type
== DMUS_FOURCC_UNFO_LIST
)
463 TRACE("Unfo list in PortConfig is ignored\n");
465 WARN("Unknown %s\n", debugstr_chunk(&chunk
));
468 WARN("Unknown %s\n", debugstr_chunk(&chunk
));
476 port_config_destroy(port_config
);
478 list_add_tail(&This
->port_config_entries
, &port_config
->entry
);
482 static HRESULT
parse_port_configs_list(struct audio_path_config
*This
, IStream
*stream
, const struct chunk_entry
*pcsl
)
484 struct chunk_entry chunk
= { .parent
= pcsl
};
487 while ((hr
= stream_next_chunk(stream
, &chunk
)) == S_OK
)
489 switch (MAKE_IDTYPE(chunk
.id
, chunk
.type
))
491 case MAKE_IDTYPE(FOURCC_LIST
, DMUS_FOURCC_PORTCONFIG_LIST
):
492 hr
= parse_port_config_list(This
, stream
, &chunk
);
497 WARN("Unknown %s\n", debugstr_chunk(&chunk
));
501 return SUCCEEDED(hr
) ? S_OK
: hr
;
505 static HRESULT WINAPI
path_config_IPersistStream_Load(IPersistStream
*iface
, IStream
*stream
)
507 struct audio_path_config
*This
= impl_from_IPersistStream(iface
);
508 struct chunk_entry riff
= {0}, chunk
= {0};
511 FIXME("(%p, %p): Loading\n", This
, stream
);
516 hr
= stream_get_chunk(stream
, &riff
);
519 WARN("Failed to get chunk %#lx.\n", hr
);
523 if (MAKE_IDTYPE(riff
.id
, riff
.type
) != MAKE_IDTYPE(FOURCC_RIFF
, DMUS_FOURCC_AUDIOPATH_FORM
))
525 WARN("loading failed: unexpected %s\n", debugstr_chunk(&riff
));
529 if (FAILED(hr
= dmobj_parsedescriptor(stream
, &riff
, &This
->dmobj
.desc
,
530 DMUS_OBJ_OBJECT
| DMUS_OBJ_VERSION
| DMUS_OBJ_NAME
| DMUS_OBJ_CATEGORY
))
531 || FAILED(hr
= stream_reset_chunk_data(stream
, &riff
)))
533 WARN("Failed to parse descriptor %#lx.\n", hr
);
536 This
->dmobj
.desc
.guidClass
= CLSID_DirectMusicAudioPathConfig
;
537 This
->dmobj
.desc
.dwValidData
|= DMUS_OBJ_CLASS
;
539 chunk
.parent
= &riff
;
540 while ((hr
= stream_next_chunk(stream
, &chunk
)) == S_OK
)
542 switch (MAKE_IDTYPE(chunk
.id
, chunk
.type
))
544 case MAKE_IDTYPE(FOURCC_LIST
, DMUS_FOURCC_PORTCONFIGS_LIST
):
545 hr
= parse_port_configs_list(This
, stream
, &chunk
);
548 case MAKE_IDTYPE(FOURCC_LIST
, DMUS_FOURCC_DSBUFFER_LIST
):
549 FIXME("buffer attributes are not supported\n");
551 case MAKE_IDTYPE(FOURCC_LIST
, MAKEFOURCC('p','a','p','d')):
552 FIXME("Undocumented %s\n", debugstr_chunk(&chunk
));
554 case MAKE_IDTYPE(FOURCC_LIST
, DMUS_FOURCC_UNFO_LIST
):
555 WARN("Unknown %s\n", debugstr_chunk(&chunk
));
557 case DMUS_FOURCC_GUID_CHUNK
:
558 case DMUS_FOURCC_VERSION_CHUNK
:
559 /* Already parsed in dmobj_parsedescriptor. */
562 WARN("Unknown %s\n", debugstr_chunk(&chunk
));
566 TRACE("Finished parsing %#lx\n", hr
);
567 return SUCCEEDED(hr
) ? S_OK
: hr
;
570 static const IPersistStreamVtbl persiststream_vtbl
= {
571 dmobj_IPersistStream_QueryInterface
,
572 dmobj_IPersistStream_AddRef
,
573 dmobj_IPersistStream_Release
,
574 dmobj_IPersistStream_GetClassID
,
575 unimpl_IPersistStream_IsDirty
,
576 path_config_IPersistStream_Load
,
577 unimpl_IPersistStream_Save
,
578 unimpl_IPersistStream_GetSizeMax
581 static inline struct audio_path_config
*impl_from_IUnknown(IUnknown
*iface
)
583 return CONTAINING_RECORD(iface
, struct audio_path_config
, IUnknown_iface
);
586 static HRESULT WINAPI
path_config_IUnknown_QueryInterface(IUnknown
*iface
, REFIID riid
, void **ppobj
)
588 struct audio_path_config
*This
= impl_from_IUnknown(iface
);
590 TRACE("(%p, %s, %p)\n", This
, debugstr_dmguid(riid
), ppobj
);
594 if (IsEqualIID (riid
, &IID_IUnknown
))
595 *ppobj
= &This
->IUnknown_iface
;
596 else if (IsEqualIID (riid
, &IID_IDirectMusicObject
))
597 *ppobj
= &This
->dmobj
.IDirectMusicObject_iface
;
598 else if (IsEqualIID (riid
, &IID_IPersistStream
))
599 *ppobj
= &This
->dmobj
.IPersistStream_iface
;
603 IUnknown_AddRef((IUnknown
*)*ppobj
);
607 WARN("(%p, %s, %p): not found\n", This
, debugstr_dmguid(riid
), ppobj
);
608 return E_NOINTERFACE
;
611 static ULONG WINAPI
path_config_IUnknown_AddRef(IUnknown
*unk
)
613 struct audio_path_config
*This
= impl_from_IUnknown(unk
);
614 ULONG ref
= InterlockedIncrement(&This
->ref
);
616 TRACE("(%p): ref=%ld\n", This
, ref
);
621 static ULONG WINAPI
path_config_IUnknown_Release(IUnknown
*unk
)
623 struct audio_path_config
*This
= impl_from_IUnknown(unk
);
624 ULONG ref
= InterlockedDecrement(&This
->ref
);
626 TRACE("(%p): ref=%ld\n", This
, ref
);
630 struct audio_path_port_config
*config
, *next_config
;
631 LIST_FOR_EACH_ENTRY_SAFE(config
, next_config
, &This
->port_config_entries
, struct audio_path_port_config
, entry
)
633 list_remove(&config
->entry
);
634 port_config_destroy(config
);
641 static const IUnknownVtbl path_config_unk_vtbl
=
643 path_config_IUnknown_QueryInterface
,
644 path_config_IUnknown_AddRef
,
645 path_config_IUnknown_Release
,
648 HRESULT
path_config_get_audio_path_params(IUnknown
*iface
, WAVEFORMATEX
*format
, DSBUFFERDESC
*desc
, DMUS_PORTPARAMS
*params
)
650 struct audio_path_config
*This
= impl_from_IUnknown(iface
);
651 struct list
*first_port_config
, *first_pchannel_to_buffer
;
652 struct audio_path_port_config
*port_config
;
653 struct audio_path_pchannel_to_buffer
*pchannel_to_buffer
;
656 first_port_config
= list_head(&This
->port_config_entries
);
657 if (list_next(&This
->port_config_entries
, first_port_config
))
658 FIXME("Only one port config supported. %p -> %p\n", first_port_config
, list_next(&This
->port_config_entries
, first_port_config
));
659 port_config
= LIST_ENTRY(first_port_config
, struct audio_path_port_config
, entry
);
660 first_pchannel_to_buffer
= list_head(&port_config
->pchannel_to_buffer_entries
);
661 if (list_next(&port_config
->pchannel_to_buffer_entries
, first_pchannel_to_buffer
))
662 FIXME("Only one pchannel to buffer entry supported.\n");
663 pchannel_to_buffer
= LIST_ENTRY(first_pchannel_to_buffer
, struct audio_path_pchannel_to_buffer
, entry
);
665 /* Secondary buffer description */
666 memset(format
, 0, sizeof(*format
));
667 format
->wFormatTag
= WAVE_FORMAT_PCM
;
668 format
->nChannels
= 1;
669 format
->nSamplesPerSec
= 44000;
670 format
->nAvgBytesPerSec
= 44000 * 2;
671 format
->nBlockAlign
= 2;
672 format
->wBitsPerSample
= 16;
675 memset(desc
, 0, sizeof(*desc
));
676 desc
->dwSize
= sizeof(*desc
);
677 desc
->dwFlags
= DSBCAPS_CTRLFX
| DSBCAPS_CTRLVOLUME
| DSBCAPS_GLOBALFOCUS
;
678 desc
->dwBufferBytes
= DSBSIZE_MIN
;
679 desc
->dwReserved
= 0;
680 desc
->lpwfxFormat
= format
;
681 desc
->guid3DAlgorithm
= GUID_NULL
;
683 guids
= pchannel_to_buffer
->guids
;
684 if (pchannel_to_buffer
->header
.dwBufferCount
== 2)
686 if ((!IsEqualGUID(&guids
[0], &GUID_Buffer_Reverb
) && !IsEqualGUID(&guids
[0], &GUID_Buffer_Stereo
)) ||
687 (!IsEqualGUID(&guids
[1], &GUID_Buffer_Reverb
) && !IsEqualGUID(&guids
[1], &GUID_Buffer_Stereo
)) ||
688 IsEqualGUID(&guids
[0], &guids
[1]))
689 FIXME("Only a stereo plus reverb buffer is supported\n");
692 desc
->dwFlags
|= DSBCAPS_CTRLPAN
| DSBCAPS_CTRLFREQUENCY
;
693 format
->nChannels
= 2;
694 format
->nBlockAlign
*= 2;
695 format
->nAvgBytesPerSec
*= 2;
698 else if (pchannel_to_buffer
->header
.dwBufferCount
== 1)
700 if (IsEqualGUID(guids
, &GUID_Buffer_Stereo
))
702 desc
->dwFlags
|= DSBCAPS_CTRLPAN
| DSBCAPS_CTRLFREQUENCY
;
703 format
->nChannels
= 2;
704 format
->nBlockAlign
*= 2;
705 format
->nAvgBytesPerSec
*= 2;
707 else if (IsEqualGUID(guids
, &GUID_Buffer_3D_Dry
))
708 desc
->dwFlags
|= DSBCAPS_CTRL3D
| DSBCAPS_CTRLFREQUENCY
| DSBCAPS_MUTE3DATMAXDISTANCE
;
709 else if (IsEqualGUID(guids
, &GUID_Buffer_Mono
))
710 desc
->dwFlags
|= DSBCAPS_CTRLPAN
| DSBCAPS_CTRLFREQUENCY
;
712 FIXME("Unsupported buffer guid %s\n", debugstr_dmguid(guids
));
715 FIXME("Multiple buffers not supported\n");
717 *params
= port_config
->params
;
718 if (!(params
->dwValidParams
& DMUS_PORTPARAMS_CHANNELGROUPS
))
720 params
->dwValidParams
|= DMUS_PORTPARAMS_CHANNELGROUPS
;
721 params
->dwChannelGroups
= (port_config
->header
.dwPChannelCount
+ 15) / 16;
723 if (!(params
->dwValidParams
& DMUS_PORTPARAMS_AUDIOCHANNELS
))
725 params
->dwValidParams
|= DMUS_PORTPARAMS_AUDIOCHANNELS
;
726 params
->dwAudioChannels
= format
->nChannels
;
731 /* for ClassFactory */
732 HRESULT
create_dmaudiopath(REFIID riid
, void **ppobj
)
734 IDirectMusicAudioPathImpl
* obj
;
738 if (!(obj
= calloc(1, sizeof(*obj
)))) return E_OUTOFMEMORY
;
739 obj
->IDirectMusicAudioPath_iface
.lpVtbl
= &DirectMusicAudioPathVtbl
;
742 hr
= IDirectMusicAudioPath_QueryInterface(&obj
->IDirectMusicAudioPath_iface
, riid
, ppobj
);
743 IDirectMusicAudioPath_Release(&obj
->IDirectMusicAudioPath_iface
);
747 HRESULT
create_dmaudiopath_config(REFIID riid
, void **ppobj
)
749 struct audio_path_config
*obj
;
753 if (!(obj
= calloc(1, sizeof(*obj
)))) return E_OUTOFMEMORY
;
754 dmobject_init(&obj
->dmobj
, &CLSID_DirectMusicAudioPathConfig
, &obj
->IUnknown_iface
);
755 obj
->IUnknown_iface
.lpVtbl
= &path_config_unk_vtbl
;
756 obj
->dmobj
.IDirectMusicObject_iface
.lpVtbl
= &dmobject_vtbl
;
757 obj
->dmobj
.IPersistStream_iface
.lpVtbl
= &persiststream_vtbl
;
760 list_init(&obj
->port_config_entries
);
762 hr
= IUnknown_QueryInterface(&obj
->IUnknown_iface
, riid
, ppobj
);
763 IUnknown_Release(&obj
->IUnknown_iface
);