dmime: Parse AudioPathConfig.
This commit is contained in:
parent
a300815c0f
commit
289dfacfd4
1 changed files with 277 additions and 4 deletions
|
@ -32,11 +32,31 @@ struct IDirectMusicAudioPathImpl {
|
|||
BOOL fActive;
|
||||
};
|
||||
|
||||
struct audio_path_pchannel_to_buffer
|
||||
{
|
||||
struct list entry;
|
||||
DMUS_IO_PCHANNELTOBUFFER_HEADER header;
|
||||
GUID guids[];
|
||||
};
|
||||
|
||||
C_ASSERT(sizeof(struct audio_path_pchannel_to_buffer) == offsetof(struct audio_path_pchannel_to_buffer, guids[0]));
|
||||
|
||||
struct audio_path_port_config
|
||||
{
|
||||
struct list entry;
|
||||
DMUS_IO_PORTCONFIG_HEADER header;
|
||||
DMUS_PORTPARAMS8 params;
|
||||
|
||||
struct list pchannel_to_buffer_entries;
|
||||
};
|
||||
|
||||
struct audio_path_config
|
||||
{
|
||||
IUnknown IUnknown_iface;
|
||||
struct dmobject dmobj;
|
||||
LONG ref;
|
||||
|
||||
struct list port_config_entries;
|
||||
};
|
||||
|
||||
static inline struct IDirectMusicAudioPathImpl *impl_from_IDirectMusicAudioPath(IDirectMusicAudioPath *iface)
|
||||
|
@ -299,15 +319,252 @@ static const IDirectMusicObjectVtbl dmobject_vtbl = {
|
|||
path_config_IDirectMusicObject_ParseDescriptor
|
||||
};
|
||||
|
||||
static HRESULT parse_pchannel_to_buffers_list(struct audio_path_port_config *This, IStream *stream, const struct chunk_entry *pchl)
|
||||
{
|
||||
struct chunk_entry chunk = { .parent = pchl };
|
||||
struct audio_path_pchannel_to_buffer *pchannel_to_buffer = NULL;
|
||||
DMUS_IO_PCHANNELTOBUFFER_HEADER header;
|
||||
SIZE_T bytes;
|
||||
ULONG i;
|
||||
HRESULT hr;
|
||||
|
||||
while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
|
||||
{
|
||||
switch (chunk.id)
|
||||
{
|
||||
case DMUS_FOURCC_PCHANNELS_ITEM:
|
||||
hr = stream_read(stream, &header, sizeof(header));
|
||||
if (FAILED(hr))
|
||||
break;
|
||||
|
||||
TRACE("Got PChannelToBuffer header:\n");
|
||||
TRACE("\tdwPChannelCount: %lu\n", header.dwPChannelCount);
|
||||
TRACE("\tdwPChannelBase: %lu\n", header.dwPChannelBase);
|
||||
TRACE("\tdwBufferCount: %lu\n", header.dwBufferCount);
|
||||
TRACE("\tdwFlags: %lx\n", header.dwFlags);
|
||||
|
||||
bytes = chunk.size - sizeof(header);
|
||||
|
||||
if (bytes != sizeof(GUID) * header.dwBufferCount)
|
||||
{
|
||||
WARN("Invalid size of GUIDs array\n");
|
||||
hr = E_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
pchannel_to_buffer = calloc(1, sizeof(*pchannel_to_buffer) + bytes);
|
||||
if (!pchannel_to_buffer)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
pchannel_to_buffer->header = header;
|
||||
TRACE("number of GUIDs: %lu\n", pchannel_to_buffer->header.dwBufferCount);
|
||||
|
||||
hr = stream_read(stream, pchannel_to_buffer->guids, bytes);
|
||||
if (FAILED(hr))
|
||||
break;
|
||||
|
||||
for (i = 0; i < pchannel_to_buffer->header.dwBufferCount; i++)
|
||||
TRACE("\tguids[%lu]: %s\n", i, debugstr_dmguid(&pchannel_to_buffer->guids[i]));
|
||||
|
||||
list_add_tail(&This->pchannel_to_buffer_entries, &pchannel_to_buffer->entry);
|
||||
pchannel_to_buffer = NULL;
|
||||
break;
|
||||
case FOURCC_LIST:
|
||||
if (chunk.type == DMUS_FOURCC_UNFO_LIST)
|
||||
TRACE("Unfo list in PChannelToBuffer is ignored\n");
|
||||
else
|
||||
WARN("Unknown %s\n", debugstr_chunk(&chunk));
|
||||
break;
|
||||
case MAKEFOURCC('p','b','g','d'):
|
||||
FIXME("Undocumented %s\n", debugstr_chunk(&chunk));
|
||||
break;
|
||||
default:
|
||||
WARN("Unknown %s\n", debugstr_chunk(&chunk));
|
||||
break;
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
break;
|
||||
}
|
||||
|
||||
if (FAILED(hr) && pchannel_to_buffer)
|
||||
free(pchannel_to_buffer);
|
||||
return hr;
|
||||
}
|
||||
|
||||
static void port_config_destroy(struct audio_path_port_config *port_config)
|
||||
{
|
||||
struct audio_path_pchannel_to_buffer *pchannel_to_buffer, *next_pchannel_to_buffer;
|
||||
LIST_FOR_EACH_ENTRY_SAFE(pchannel_to_buffer, next_pchannel_to_buffer, &port_config->pchannel_to_buffer_entries,
|
||||
struct audio_path_pchannel_to_buffer, entry)
|
||||
{
|
||||
list_remove(&pchannel_to_buffer->entry);
|
||||
free(pchannel_to_buffer);
|
||||
}
|
||||
free(port_config);
|
||||
}
|
||||
|
||||
static HRESULT parse_port_config_list(struct audio_path_config *This, IStream *stream, const struct chunk_entry *pcfl)
|
||||
{
|
||||
struct chunk_entry chunk = { .parent = pcfl };
|
||||
struct audio_path_port_config *port_config = calloc(1, sizeof(*port_config));
|
||||
HRESULT hr;
|
||||
|
||||
if (!port_config)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
list_init(&port_config->pchannel_to_buffer_entries);
|
||||
|
||||
while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
|
||||
{
|
||||
switch (chunk.id)
|
||||
{
|
||||
case DMUS_FOURCC_PORTCONFIG_ITEM:
|
||||
hr = stream_chunk_get_data(stream, &chunk, &port_config->header, sizeof(port_config->header));
|
||||
if (FAILED(hr))
|
||||
break;
|
||||
TRACE("Got PortConfig header:\n");
|
||||
TRACE("\tdwPChannelBase: %lu\n", port_config->header.dwPChannelBase);
|
||||
TRACE("\tdwPChannelCount: %lu\n", port_config->header.dwPChannelCount);
|
||||
TRACE("\tdwFlags: %lx\n", port_config->header.dwFlags);
|
||||
TRACE("\tguidPort: %s\n", debugstr_dmguid(&port_config->header.guidPort));
|
||||
break;
|
||||
case DMUS_FOURCC_PORTPARAMS_ITEM:
|
||||
hr = stream_chunk_get_data(stream, &chunk, &port_config->params, sizeof(port_config->params));
|
||||
if (FAILED(hr))
|
||||
break;
|
||||
TRACE("Got PortConfig params:\n");
|
||||
TRACE("\tdwSize: %lu\n", port_config->params.dwSize);
|
||||
TRACE("\tdwValidParams: %lx\n", port_config->params.dwValidParams);
|
||||
if (port_config->params.dwValidParams & DMUS_PORTPARAMS_VOICES)
|
||||
TRACE("\tvoices: %lu\n", port_config->params.dwVoices);
|
||||
if (port_config->params.dwValidParams & DMUS_PORTPARAMS_CHANNELGROUPS)
|
||||
TRACE("\tchannel groups: %lu\n", port_config->params.dwChannelGroups);
|
||||
if (port_config->params.dwValidParams & DMUS_PORTPARAMS_AUDIOCHANNELS)
|
||||
TRACE("\taudio channels: %lu\n", port_config->params.dwAudioChannels);
|
||||
if (port_config->params.dwValidParams & DMUS_PORTPARAMS_SAMPLERATE)
|
||||
TRACE("\tsample rate: %lu\n", port_config->params.dwSampleRate);
|
||||
if (port_config->params.dwValidParams & DMUS_PORTPARAMS_EFFECTS)
|
||||
TRACE("\teffects: %lx\n", port_config->params.dwEffectFlags);
|
||||
if (port_config->params.dwValidParams & DMUS_PORTPARAMS_SHARE)
|
||||
TRACE("\tshare: %d\n", port_config->params.fShare);
|
||||
if (port_config->params.dwValidParams & DMUS_PORTPARAMS_FEATURES)
|
||||
TRACE("\tfeatures: %lx\n", port_config->params.dwFeatures);
|
||||
break;
|
||||
case FOURCC_LIST:
|
||||
if (chunk.type == DMUS_FOURCC_DSBUFFER_LIST)
|
||||
FIXME("DirectSound buffer descriptors is not supported\n");
|
||||
else if (chunk.type == DMUS_FOURCC_PCHANNELS_LIST)
|
||||
hr = parse_pchannel_to_buffers_list(port_config, stream, &chunk);
|
||||
else if (chunk.type == DMUS_FOURCC_UNFO_LIST)
|
||||
TRACE("Unfo list in PortConfig is ignored\n");
|
||||
else
|
||||
WARN("Unknown %s\n", debugstr_chunk(&chunk));
|
||||
break;
|
||||
default:
|
||||
WARN("Unknown %s\n", debugstr_chunk(&chunk));
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
break;
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
port_config_destroy(port_config);
|
||||
else
|
||||
list_add_tail(&This->port_config_entries, &port_config->entry);
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT parse_port_configs_list(struct audio_path_config *This, IStream *stream, const struct chunk_entry *pcsl)
|
||||
{
|
||||
struct chunk_entry chunk = { .parent = pcsl };
|
||||
HRESULT hr;
|
||||
|
||||
while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
|
||||
{
|
||||
switch (MAKE_IDTYPE(chunk.id, chunk.type))
|
||||
{
|
||||
case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_PORTCONFIG_LIST):
|
||||
hr = parse_port_config_list(This, stream, &chunk);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
break;
|
||||
default:
|
||||
WARN("Unknown %s\n", debugstr_chunk(&chunk));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return SUCCEEDED(hr) ? S_OK : hr;
|
||||
}
|
||||
|
||||
/* IPersistStream */
|
||||
static HRESULT WINAPI path_config_IPersistStream_Load(IPersistStream *iface, IStream *stream)
|
||||
{
|
||||
struct audio_path_config *This = impl_from_IPersistStream(iface);
|
||||
struct chunk_entry riff = {0}, chunk = {0};
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
FIXME("(%p, %p): Loading not implemented yet\n", This, stream);
|
||||
FIXME("(%p, %p): Loading\n", This, stream);
|
||||
|
||||
return IDirectMusicObject_ParseDescriptor(&This->dmobj.IDirectMusicObject_iface, stream,
|
||||
&This->dmobj.desc);
|
||||
if (!stream)
|
||||
return E_POINTER;
|
||||
|
||||
hr = stream_get_chunk(stream, &riff);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WARN("Failed to get chunk %#lx.\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
if (MAKE_IDTYPE(riff.id, riff.type) != MAKE_IDTYPE(FOURCC_RIFF, DMUS_FOURCC_AUDIOPATH_FORM))
|
||||
{
|
||||
WARN("loading failed: unexpected %s\n", debugstr_chunk(&riff));
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (FAILED(hr = dmobj_parsedescriptor(stream, &riff, &This->dmobj.desc,
|
||||
DMUS_OBJ_OBJECT | DMUS_OBJ_VERSION | DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY))
|
||||
|| FAILED(hr = stream_reset_chunk_data(stream, &riff)))
|
||||
{
|
||||
WARN("Failed to parse descriptor %#lx.\n", hr);
|
||||
return hr;
|
||||
}
|
||||
This->dmobj.desc.guidClass = CLSID_DirectMusicAudioPathConfig;
|
||||
This->dmobj.desc.dwValidData |= DMUS_OBJ_CLASS;
|
||||
|
||||
chunk.parent = &riff;
|
||||
while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
|
||||
{
|
||||
switch (MAKE_IDTYPE(chunk.id, chunk.type))
|
||||
{
|
||||
case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_PORTCONFIGS_LIST):
|
||||
hr = parse_port_configs_list(This, stream, &chunk);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_DSBUFFER_LIST):
|
||||
FIXME("buffer attributes are not supported\n");
|
||||
break;
|
||||
case MAKE_IDTYPE(FOURCC_LIST, MAKEFOURCC('p','a','p','d')):
|
||||
FIXME("Undocumented %s\n", debugstr_chunk(&chunk));
|
||||
break;
|
||||
case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_UNFO_LIST):
|
||||
WARN("Unknown %s\n", debugstr_chunk(&chunk));
|
||||
break;
|
||||
case DMUS_FOURCC_GUID_CHUNK:
|
||||
case DMUS_FOURCC_VERSION_CHUNK:
|
||||
/* Already parsed in dmobj_parsedescriptor. */
|
||||
break;
|
||||
default:
|
||||
WARN("Unknown %s\n", debugstr_chunk(&chunk));
|
||||
break;
|
||||
}
|
||||
}
|
||||
TRACE("Finished parsing %#lx\n", hr);
|
||||
return SUCCEEDED(hr) ? S_OK : hr;
|
||||
}
|
||||
|
||||
static const IPersistStreamVtbl persiststream_vtbl = {
|
||||
|
@ -354,7 +611,11 @@ static HRESULT WINAPI path_config_IUnknown_QueryInterface(IUnknown *iface, REFII
|
|||
static ULONG WINAPI path_config_IUnknown_AddRef(IUnknown *unk)
|
||||
{
|
||||
struct audio_path_config *This = impl_from_IUnknown(unk);
|
||||
return InterlockedIncrement(&This->ref);
|
||||
ULONG ref = InterlockedIncrement(&This->ref);
|
||||
|
||||
TRACE("(%p): ref=%ld\n", This, ref);
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
static ULONG WINAPI path_config_IUnknown_Release(IUnknown *unk)
|
||||
|
@ -362,8 +623,18 @@ static ULONG WINAPI path_config_IUnknown_Release(IUnknown *unk)
|
|||
struct audio_path_config *This = impl_from_IUnknown(unk);
|
||||
ULONG ref = InterlockedDecrement(&This->ref);
|
||||
|
||||
TRACE("(%p): ref=%ld\n", This, ref);
|
||||
|
||||
if (!ref)
|
||||
{
|
||||
struct audio_path_port_config *config, *next_config;
|
||||
LIST_FOR_EACH_ENTRY_SAFE(config, next_config, &This->port_config_entries, struct audio_path_port_config, entry)
|
||||
{
|
||||
list_remove(&config->entry);
|
||||
port_config_destroy(config);
|
||||
}
|
||||
free(This);
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
|
@ -403,6 +674,8 @@ HRESULT create_dmaudiopath_config(REFIID riid, void **ppobj)
|
|||
obj->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl;
|
||||
obj->ref = 1;
|
||||
|
||||
list_init(&obj->port_config_entries);
|
||||
|
||||
hr = IUnknown_QueryInterface(&obj->IUnknown_iface, riid, ppobj);
|
||||
IUnknown_Release(&obj->IUnknown_iface);
|
||||
return hr;
|
||||
|
|
Loading…
Add table
Reference in a new issue