Wine-Devel
Threads by month
- ----- 2026 -----
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- 5 participants
- 84534 discussions
Feb. 4, 2021
From: Andrew Eikum <aeikum(a)codeweavers.com>
This makes car radio / ambient noises audible in Cyberpunk 2077.
Signed-off-by: Arkadiusz Hiler <ahiler(a)codeweavers.com>
---
dlls/mmdevapi/Makefile.in | 3 +-
dlls/mmdevapi/audiovolume.c | 1 +
dlls/mmdevapi/devenum.c | 5 +
dlls/mmdevapi/main.c | 1 +
dlls/mmdevapi/mmdevapi.h | 1 +
dlls/mmdevapi/spatialaudio.c | 988 +++++++++++++++++++++++++++++++++
include/spatialaudioclient.idl | 121 ++++
7 files changed, 1119 insertions(+), 1 deletion(-)
create mode 100644 dlls/mmdevapi/spatialaudio.c
diff --git a/dlls/mmdevapi/Makefile.in b/dlls/mmdevapi/Makefile.in
index 5f44f7ba53b..903b14335a9 100644
--- a/dlls/mmdevapi/Makefile.in
+++ b/dlls/mmdevapi/Makefile.in
@@ -6,6 +6,7 @@ EXTRADLLFLAGS = -mno-cygwin
C_SRCS = \
audiovolume.c \
devenum.c \
- main.c
+ main.c \
+ spatialaudio.c
IDL_SRCS = mmdevapi_classes.idl
diff --git a/dlls/mmdevapi/audiovolume.c b/dlls/mmdevapi/audiovolume.c
index 9214980120e..6f403cf348a 100644
--- a/dlls/mmdevapi/audiovolume.c
+++ b/dlls/mmdevapi/audiovolume.c
@@ -33,6 +33,7 @@
#include "audioclient.h"
#include "endpointvolume.h"
#include "audiopolicy.h"
+#include "spatialaudioclient.h"
#include "mmdevapi.h"
diff --git a/dlls/mmdevapi/devenum.c b/dlls/mmdevapi/devenum.c
index 9e4a29816ce..07b4dca028b 100644
--- a/dlls/mmdevapi/devenum.c
+++ b/dlls/mmdevapi/devenum.c
@@ -35,6 +35,7 @@
#include "audioclient.h"
#include "endpointvolume.h"
#include "audiopolicy.h"
+#include "spatialaudioclient.h"
#include "mmdevapi.h"
#include "devpkey.h"
@@ -635,6 +636,10 @@ static HRESULT WINAPI MMDevice_Activate(IMMDevice *iface, REFIID riid, DWORD cls
IDirectSoundCapture_Release((IDirectSoundCapture*)*ppv);
}
}
+ else if (IsEqualIID(riid, &IID_ISpatialAudioClient))
+ {
+ hr = SpatialAudioClient_Create(iface, (ISpatialAudioClient**)ppv);
+ }
else
ERR("Invalid/unknown iid %s\n", debugstr_guid(riid));
diff --git a/dlls/mmdevapi/main.c b/dlls/mmdevapi/main.c
index 247ebc3b001..eac1da28f18 100644
--- a/dlls/mmdevapi/main.c
+++ b/dlls/mmdevapi/main.c
@@ -37,6 +37,7 @@
#include "audiopolicy.h"
#include "devpkey.h"
#include "winreg.h"
+#include "spatialaudioclient.h"
#include "mmdevapi.h"
#include "wine/debug.h"
diff --git a/dlls/mmdevapi/mmdevapi.h b/dlls/mmdevapi/mmdevapi.h
index bc9788e95c8..3bcf568cddf 100644
--- a/dlls/mmdevapi/mmdevapi.h
+++ b/dlls/mmdevapi/mmdevapi.h
@@ -71,5 +71,6 @@ typedef struct MMDevice {
extern HRESULT AudioClient_Create(MMDevice *parent, IAudioClient **ppv) DECLSPEC_HIDDEN;
extern HRESULT AudioEndpointVolume_Create(MMDevice *parent, IAudioEndpointVolumeEx **ppv) DECLSPEC_HIDDEN;
+extern HRESULT SpatialAudioClient_Create(IMMDevice *device, ISpatialAudioClient **out) DECLSPEC_HIDDEN;
extern const WCHAR drv_keyW[] DECLSPEC_HIDDEN;
diff --git a/dlls/mmdevapi/spatialaudio.c b/dlls/mmdevapi/spatialaudio.c
new file mode 100644
index 00000000000..cbca57b4890
--- /dev/null
+++ b/dlls/mmdevapi/spatialaudio.c
@@ -0,0 +1,988 @@
+/*
+ * Copyright 2020 Andrew Eikum for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define COBJMACROS
+#define NONAMELESSUNION
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winnls.h"
+#include "winreg.h"
+#include "wine/heap.h"
+#include "wine/debug.h"
+#include "wine/list.h"
+
+#include "ole2.h"
+#include "mmdeviceapi.h"
+#include "mmsystem.h"
+#include "audioclient.h"
+#include "endpointvolume.h"
+#include "audiopolicy.h"
+#include "spatialaudioclient.h"
+
+#include "mmdevapi.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi);
+
+#define MAX_PERIODS 3
+
+static UINT32 AudioObjectType_to_index(AudioObjectType type)
+{
+ UINT32 o = 0;
+ while(type){
+ type >>= 1;
+ ++o;
+ }
+ return o - 2;
+}
+
+typedef struct SpatialAudioImpl SpatialAudioImpl;
+typedef struct SpatialAudioStreamImpl SpatialAudioStreamImpl;
+typedef struct SpatialAudioObjectImpl SpatialAudioObjectImpl;
+
+struct SpatialAudioObjectImpl {
+ ISpatialAudioObject ISpatialAudioObject_iface;
+ LONG ref;
+
+ SpatialAudioStreamImpl *sa_stream;
+ AudioObjectType type;
+ UINT32 static_idx;
+
+ float *buf;
+
+ struct list entry;
+};
+
+struct SpatialAudioStreamImpl {
+ ISpatialAudioObjectRenderStream ISpatialAudioObjectRenderStream_iface;
+ LONG ref;
+ CRITICAL_SECTION lock;
+
+ SpatialAudioImpl *sa_client;
+ SpatialAudioObjectRenderStreamActivationParams params;
+
+ IAudioClient *client;
+ IAudioRenderClient *render;
+
+ UINT32 period_frames, update_frames;
+ WAVEFORMATEXTENSIBLE stream_fmtex;
+
+ float *buf;
+
+ UINT32 static_object_map[17];
+
+ struct list objects;
+};
+
+struct SpatialAudioImpl {
+ ISpatialAudioClient ISpatialAudioClient_iface;
+ IAudioFormatEnumerator IAudioFormatEnumerator_iface;
+ IMMDevice *mmdev;
+ LONG ref;
+ WAVEFORMATEXTENSIBLE object_fmtex;
+};
+
+static inline SpatialAudioObjectImpl *impl_from_ISpatialAudioObject(ISpatialAudioObject *iface)
+{
+ return CONTAINING_RECORD(iface, SpatialAudioObjectImpl, ISpatialAudioObject_iface);
+}
+
+static inline SpatialAudioStreamImpl *impl_from_ISpatialAudioObjectRenderStream(ISpatialAudioObjectRenderStream *iface)
+{
+ return CONTAINING_RECORD(iface, SpatialAudioStreamImpl, ISpatialAudioObjectRenderStream_iface);
+}
+
+static inline SpatialAudioImpl *impl_from_ISpatialAudioClient(ISpatialAudioClient *iface)
+{
+ return CONTAINING_RECORD(iface, SpatialAudioImpl, ISpatialAudioClient_iface);
+}
+
+static inline SpatialAudioImpl *impl_from_IAudioFormatEnumerator(IAudioFormatEnumerator *iface)
+{
+ return CONTAINING_RECORD(iface, SpatialAudioImpl, IAudioFormatEnumerator_iface);
+}
+
+static HRESULT WINAPI SAO_QueryInterface(ISpatialAudioObject *iface,
+ REFIID riid, void **ppv)
+{
+ SpatialAudioObjectImpl *This = impl_from_ISpatialAudioObject(iface);
+
+ TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppv);
+
+ if (!ppv)
+ return E_POINTER;
+
+ *ppv = NULL;
+
+ if (IsEqualIID(riid, &IID_IUnknown) ||
+ IsEqualIID(riid, &IID_ISpatialAudioObjectBase) ||
+ IsEqualIID(riid, &IID_ISpatialAudioObject)) {
+ *ppv = &This->ISpatialAudioObject_iface;
+ }
+ else
+ return E_NOINTERFACE;
+
+ IUnknown_AddRef((IUnknown *)*ppv);
+
+ return S_OK;
+}
+
+static ULONG WINAPI SAO_AddRef(ISpatialAudioObject *iface)
+{
+ SpatialAudioObjectImpl *This = impl_from_ISpatialAudioObject(iface);
+ ULONG ref = InterlockedIncrement(&This->ref);
+ TRACE("(%p) new ref %u\n", This, ref);
+ return ref;
+}
+
+static ULONG WINAPI SAO_Release(ISpatialAudioObject *iface)
+{
+ SpatialAudioObjectImpl *This = impl_from_ISpatialAudioObject(iface);
+ ULONG ref = InterlockedDecrement(&This->ref);
+ TRACE("(%p) new ref %u\n", This, ref);
+ if(!ref){
+ EnterCriticalSection(&This->sa_stream->lock);
+ list_remove(&This->entry);
+ LeaveCriticalSection(&This->sa_stream->lock);
+
+ ISpatialAudioObjectRenderStream_Release(&This->sa_stream->ISpatialAudioObjectRenderStream_iface);
+ heap_free(This->buf);
+ heap_free(This);
+ }
+ return ref;
+}
+
+static HRESULT WINAPI SAO_GetBuffer(ISpatialAudioObject *iface,
+ BYTE **buffer, UINT32 *bytes)
+{
+ SpatialAudioObjectImpl *This = impl_from_ISpatialAudioObject(iface);
+
+ TRACE("(%p)->(%p, %p)\n", This, buffer, bytes);
+
+ EnterCriticalSection(&This->sa_stream->lock);
+
+ if(This->sa_stream->update_frames == ~0){
+ LeaveCriticalSection(&This->sa_stream->lock);
+ return SPTLAUDCLNT_E_OUT_OF_ORDER;
+ }
+
+ *buffer = (BYTE *)This->buf;
+ *bytes = This->sa_stream->update_frames *
+ This->sa_stream->sa_client->object_fmtex.Format.nBlockAlign;
+
+ LeaveCriticalSection(&This->sa_stream->lock);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI SAO_SetEndOfStream(ISpatialAudioObject *iface, UINT32 frames)
+{
+ SpatialAudioObjectImpl *This = impl_from_ISpatialAudioObject(iface);
+ FIXME("(%p)->(%u)\n", This, frames);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI SAO_IsActive(ISpatialAudioObject *iface, BOOL *active)
+{
+ SpatialAudioObjectImpl *This = impl_from_ISpatialAudioObject(iface);
+ FIXME("(%p)->(%p)\n", This, active);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI SAO_GetAudioObjectType(ISpatialAudioObject *iface,
+ AudioObjectType *type)
+{
+ SpatialAudioObjectImpl *This = impl_from_ISpatialAudioObject(iface);
+
+ TRACE("(%p)->(%p)\n", This, type);
+
+ *type = This->type;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI SAO_SetPosition(ISpatialAudioObject *iface, float x,
+ float y, float z)
+{
+ SpatialAudioObjectImpl *This = impl_from_ISpatialAudioObject(iface);
+ FIXME("(%p)->(%f, %f, %f)\n", This, x, y, z);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI SAO_SetVolume(ISpatialAudioObject *iface, float vol)
+{
+ SpatialAudioObjectImpl *This = impl_from_ISpatialAudioObject(iface);
+ FIXME("(%p)->(%f)\n", This, vol);
+ return E_NOTIMPL;
+}
+
+static ISpatialAudioObjectVtbl ISpatialAudioObject_vtbl = {
+ SAO_QueryInterface,
+ SAO_AddRef,
+ SAO_Release,
+ SAO_GetBuffer,
+ SAO_SetEndOfStream,
+ SAO_IsActive,
+ SAO_GetAudioObjectType,
+ SAO_SetPosition,
+ SAO_SetVolume,
+};
+
+static HRESULT WINAPI SAORS_QueryInterface(ISpatialAudioObjectRenderStream *iface,
+ REFIID riid, void **ppv)
+{
+ SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface);
+
+ TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppv);
+
+ if (!ppv)
+ return E_POINTER;
+
+ *ppv = NULL;
+
+ if (IsEqualIID(riid, &IID_IUnknown) ||
+ IsEqualIID(riid, &IID_ISpatialAudioObjectRenderStreamBase) ||
+ IsEqualIID(riid, &IID_ISpatialAudioObjectRenderStream)) {
+ *ppv = &This->ISpatialAudioObjectRenderStream_iface;
+ }
+ else
+ return E_NOINTERFACE;
+
+ IUnknown_AddRef((IUnknown *)*ppv);
+
+ return S_OK;
+}
+
+static ULONG WINAPI SAORS_AddRef(ISpatialAudioObjectRenderStream *iface)
+{
+ SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface);
+ ULONG ref = InterlockedIncrement(&This->ref);
+ TRACE("(%p) new ref %u\n", This, ref);
+ return ref;
+}
+
+static ULONG WINAPI SAORS_Release(ISpatialAudioObjectRenderStream *iface)
+{
+ SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface);
+ ULONG ref = InterlockedDecrement(&This->ref);
+ TRACE("(%p) new ref %u\n", This, ref);
+ if(!ref){
+ IAudioClient_Stop(This->client);
+ if(This->update_frames != ~0 && This->update_frames > 0)
+ IAudioRenderClient_ReleaseBuffer(This->render, This->update_frames, 0);
+ IAudioRenderClient_Release(This->render);
+ IAudioClient_Release(This->client);
+ if(This->params.NotifyObject)
+ ISpatialAudioObjectRenderStreamNotify_Release(This->params.NotifyObject);
+ heap_free((void*)This->params.ObjectFormat);
+ CloseHandle(This->params.EventHandle);
+ DeleteCriticalSection(&This->lock);
+ ISpatialAudioClient_Release(&This->sa_client->ISpatialAudioClient_iface);
+ heap_free(This);
+ }
+ return ref;
+}
+
+static HRESULT WINAPI SAORS_GetAvailableDynamicObjectCount(
+ ISpatialAudioObjectRenderStream *iface, UINT32 *count)
+{
+ SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface);
+ FIXME("(%p)->(%p)\n", This, count);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI SAORS_GetService(ISpatialAudioObjectRenderStream *iface,
+ REFIID riid, void **service)
+{
+ SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface);
+ FIXME("(%p)->(%s, %p)\n", This, debugstr_guid(riid), service);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI SAORS_Start(ISpatialAudioObjectRenderStream *iface)
+{
+ SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface);
+ HRESULT hr;
+
+ TRACE("(%p)->()\n", This);
+
+ hr = IAudioClient_Start(This->client);
+ if(FAILED(hr)){
+ WARN("IAudioClient::Start failed: %08x\n", hr);
+ return hr;
+ }
+
+ return S_OK;
+}
+
+static HRESULT WINAPI SAORS_Stop(ISpatialAudioObjectRenderStream *iface)
+{
+ SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface);
+ HRESULT hr;
+
+ TRACE("(%p)->()\n", This);
+
+ hr = IAudioClient_Stop(This->client);
+ if(FAILED(hr)){
+ WARN("IAudioClient::Stop failed: %08x\n", hr);
+ return hr;
+ }
+
+ return S_OK;
+}
+
+static HRESULT WINAPI SAORS_Reset(ISpatialAudioObjectRenderStream *iface)
+{
+ SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface);
+ FIXME("(%p)->()\n", This);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI SAORS_BeginUpdatingAudioObjects(ISpatialAudioObjectRenderStream *iface,
+ UINT32 *dyn_count, UINT32 *frames)
+{
+ static BOOL fixme_once = FALSE;
+ SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface);
+ SpatialAudioObjectImpl *object;
+ UINT32 pad;
+ HRESULT hr;
+
+ TRACE("(%p)->(%p, %p)\n", This, dyn_count, frames);
+
+ EnterCriticalSection(&This->lock);
+
+ if(This->update_frames != ~0){
+ LeaveCriticalSection(&This->lock);
+ return SPTLAUDCLNT_E_OUT_OF_ORDER;
+ }
+
+ hr = IAudioClient_GetCurrentPadding(This->client, &pad);
+ if(FAILED(hr)){
+ WARN("GetCurrentPadding failed: %08x\n", hr);
+ LeaveCriticalSection(&This->lock);
+ return hr;
+ }
+
+ if(pad < This->period_frames * MAX_PERIODS){
+ This->update_frames = This->period_frames * MAX_PERIODS - pad;
+ }else{
+ This->update_frames = 0;
+ }
+
+ if(This->update_frames > 0){
+ hr = IAudioRenderClient_GetBuffer(This->render, This->update_frames, (BYTE **)&This->buf);
+ if(FAILED(hr)){
+ WARN("GetBuffer failed: %08x\n", hr);
+ This->update_frames = ~0;
+ LeaveCriticalSection(&This->lock);
+ return hr;
+ }
+
+ LIST_FOR_EACH_ENTRY(object, &This->objects, SpatialAudioObjectImpl, entry){
+ memset(object->buf, 0, This->update_frames * This->sa_client->object_fmtex.Format.nBlockAlign);
+ }
+ }else if (!fixme_once){
+ fixme_once = TRUE;
+ FIXME("Zero frame update.\n");
+ }
+
+ *dyn_count = 0;
+ *frames = This->update_frames;
+
+ LeaveCriticalSection(&This->lock);
+
+ return S_OK;
+}
+
+static void mix_static_object(SpatialAudioStreamImpl *stream, SpatialAudioObjectImpl *object)
+{
+ float *in = object->buf, *out;
+ UINT32 i;
+ if(object->static_idx == ~0 ||
+ stream->static_object_map[object->static_idx] == ~0){
+ WARN("Got unmapped static object?! Not mixing. Type: 0x%x\n", object->type);
+ return;
+ }
+ out = stream->buf + stream->static_object_map[object->static_idx];
+ for(i = 0; i < stream->update_frames; ++i){
+ *out += *in;
+ ++in;
+ out += stream->stream_fmtex.Format.nChannels;
+ }
+}
+
+static HRESULT WINAPI SAORS_EndUpdatingAudioObjects(ISpatialAudioObjectRenderStream *iface)
+{
+ SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface);
+ SpatialAudioObjectImpl *object;
+ HRESULT hr;
+
+ TRACE("(%p)->()\n", This);
+
+ EnterCriticalSection(&This->lock);
+
+ if(This->update_frames == ~0){
+ LeaveCriticalSection(&This->lock);
+ return SPTLAUDCLNT_E_OUT_OF_ORDER;
+ }
+
+ if(This->update_frames > 0){
+ LIST_FOR_EACH_ENTRY(object, &This->objects, SpatialAudioObjectImpl, entry){
+ if(object->type != AudioObjectType_Dynamic)
+ mix_static_object(This, object);
+ else
+ WARN("Don't know how to mix dynamic object yet. %p\n", object);
+ }
+
+ hr = IAudioRenderClient_ReleaseBuffer(This->render, This->update_frames, 0);
+ if(FAILED(hr))
+ WARN("ReleaseBuffer failed: %08x\n", hr);
+ }
+
+ This->update_frames = ~0;
+
+ LeaveCriticalSection(&This->lock);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI SAORS_ActivateSpatialAudioObject(ISpatialAudioObjectRenderStream *iface,
+ AudioObjectType type, ISpatialAudioObject **object)
+{
+ SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface);
+ SpatialAudioObjectImpl *obj;
+
+ TRACE("(%p)->(0x%x, %p)\n", This, type, object);
+
+ if(type == AudioObjectType_Dynamic)
+ return SPTLAUDCLNT_E_NO_MORE_OBJECTS;
+
+ if(type & ~This->params.StaticObjectTypeMask)
+ return SPTLAUDCLNT_E_STATIC_OBJECT_NOT_AVAILABLE;
+
+ LIST_FOR_EACH_ENTRY(obj, &This->objects, SpatialAudioObjectImpl, entry){
+ if(obj->static_idx == AudioObjectType_to_index(type))
+ return SPTLAUDCLNT_E_OBJECT_ALREADY_ACTIVE;
+ }
+
+ obj = heap_alloc_zero(sizeof(*obj));
+ obj->ISpatialAudioObject_iface.lpVtbl = &ISpatialAudioObject_vtbl;
+ obj->ref = 1;
+ obj->type = type;
+ if(type == AudioObjectType_None){
+ FIXME("AudioObjectType_None not implemented yet!\n");
+ obj->static_idx = ~0;
+ }else{
+ obj->static_idx = AudioObjectType_to_index(type);
+ }
+
+ obj->sa_stream = This;
+ SAORS_AddRef(&This->ISpatialAudioObjectRenderStream_iface);
+
+ obj->buf = heap_alloc_zero(This->period_frames * MAX_PERIODS * This->sa_client->object_fmtex.Format.nBlockAlign);
+
+ EnterCriticalSection(&This->lock);
+
+ list_add_tail(&This->objects, &obj->entry);
+
+ LeaveCriticalSection(&This->lock);
+
+ *object = &obj->ISpatialAudioObject_iface;
+
+ return S_OK;
+}
+
+static ISpatialAudioObjectRenderStreamVtbl ISpatialAudioObjectRenderStream_vtbl = {
+ SAORS_QueryInterface,
+ SAORS_AddRef,
+ SAORS_Release,
+ SAORS_GetAvailableDynamicObjectCount,
+ SAORS_GetService,
+ SAORS_Start,
+ SAORS_Stop,
+ SAORS_Reset,
+ SAORS_BeginUpdatingAudioObjects,
+ SAORS_EndUpdatingAudioObjects,
+ SAORS_ActivateSpatialAudioObject,
+};
+
+static HRESULT WINAPI SAC_QueryInterface(ISpatialAudioClient *iface, REFIID riid, void **ppv)
+{
+ SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface);
+
+ TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppv);
+
+ if (!ppv)
+ return E_POINTER;
+
+ *ppv = NULL;
+
+ if (IsEqualIID(riid, &IID_IUnknown) ||
+ IsEqualIID(riid, &IID_ISpatialAudioClient)) {
+ *ppv = &This->ISpatialAudioClient_iface;
+ }
+ else
+ return E_NOINTERFACE;
+
+ IUnknown_AddRef((IUnknown *)*ppv);
+
+ return S_OK;
+}
+
+static ULONG WINAPI SAC_AddRef(ISpatialAudioClient *iface)
+{
+ SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface);
+ ULONG ref = InterlockedIncrement(&This->ref);
+ TRACE("(%p) new ref %u\n", This, ref);
+ return ref;
+}
+
+static ULONG WINAPI SAC_Release(ISpatialAudioClient *iface)
+{
+ SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface);
+ ULONG ref = InterlockedDecrement(&This->ref);
+ TRACE("(%p) new ref %u\n", This, ref);
+ if (!ref) {
+ IMMDevice_Release(This->mmdev);
+ heap_free(This);
+ }
+ return ref;
+}
+
+static HRESULT WINAPI SAC_GetStaticObjectPosition(ISpatialAudioClient *iface,
+ AudioObjectType type, float *x, float *y, float *z)
+{
+ SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface);
+ FIXME("(%p)->(0x%x, %p, %p, %p)\n", This, type, x, y, z);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI SAC_GetNativeStaticObjectTypeMask(ISpatialAudioClient *iface,
+ AudioObjectType *mask)
+{
+ SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface);
+ FIXME("(%p)->(%p)\n", This, mask);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI SAC_GetMaxDynamicObjectCount(ISpatialAudioClient *iface,
+ UINT32 *value)
+{
+ SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface);
+ FIXME("(%p)->(%p)\n", This, value);
+
+ *value = 0;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI SAC_GetSupportedAudioObjectFormatEnumerator(
+ ISpatialAudioClient *iface, IAudioFormatEnumerator **enumerator)
+{
+ SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface);
+
+ TRACE("(%p)->(%p)\n", This, enumerator);
+
+ *enumerator = &This->IAudioFormatEnumerator_iface;
+ SAC_AddRef(iface);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI SAC_GetMaxFrameCount(ISpatialAudioClient *iface,
+ const WAVEFORMATEX *format, UINT32 *count)
+{
+ SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface);
+
+ /* FIXME: should get device period from the device */
+ static const REFERENCE_TIME period = 100000;
+
+ TRACE("(%p)->(%p, %p)\n", This, format, count);
+
+ *count = MulDiv(period, format->nSamplesPerSec, 10000000) * MAX_PERIODS;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI SAC_IsAudioObjectFormatSupported(ISpatialAudioClient *iface,
+ const WAVEFORMATEX *format)
+{
+ SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface);
+ FIXME("(%p)->(%p)\n", This, format);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI SAC_IsSpatialAudioStreamAvailable(ISpatialAudioClient *iface,
+ REFIID stream_uuid, const PROPVARIANT *info)
+{
+ SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface);
+ FIXME("(%p)->(%s, %p)\n", This, debugstr_guid(stream_uuid), info);
+ return E_NOTIMPL;
+}
+
+static WAVEFORMATEX *clone_fmtex(const WAVEFORMATEX *src)
+{
+ WAVEFORMATEX *r = heap_alloc(sizeof(WAVEFORMATEX) + src->cbSize);
+ memcpy(r, src, sizeof(WAVEFORMATEX) + src->cbSize);
+ return r;
+}
+
+static const char *debugstr_fmtex(const WAVEFORMATEX *fmt)
+{
+ static char buf[2048];
+ if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
+ const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt;
+ snprintf(buf, sizeof(buf), "tag: 0x%x (%s), ch: %u (mask: 0x%x), rate: %u, depth: %u",
+ fmt->wFormatTag, debugstr_guid(&fmtex->SubFormat),
+ fmt->nChannels, fmtex->dwChannelMask, fmt->nSamplesPerSec,
+ fmt->wBitsPerSample);
+ }else{
+ snprintf(buf, sizeof(buf), "tag: 0x%x, ch: %u, rate: %u, depth: %u",
+ fmt->wFormatTag, fmt->nChannels, fmt->nSamplesPerSec,
+ fmt->wBitsPerSample);
+ }
+ return buf;
+}
+
+static void static_mask_to_channels(AudioObjectType static_mask, WORD *count, DWORD *mask, UINT32 *map)
+{
+ UINT32 out_chan = 0, map_idx = 0;
+ *count = 0;
+ *mask = 0;
+#define CONVERT_MASK(f, t) \
+ if(static_mask & f){ \
+ *count += 1; \
+ *mask |= t; \
+ map[map_idx++] = out_chan++; \
+ TRACE("mapping 0x%x to %u\n", f, out_chan - 1); \
+ }else{ \
+ map[map_idx++] = ~0; \
+ }
+ CONVERT_MASK(AudioObjectType_FrontLeft, SPEAKER_FRONT_LEFT);
+ CONVERT_MASK(AudioObjectType_FrontRight, SPEAKER_FRONT_RIGHT);
+ CONVERT_MASK(AudioObjectType_FrontCenter, SPEAKER_FRONT_CENTER);
+ CONVERT_MASK(AudioObjectType_LowFrequency, SPEAKER_LOW_FREQUENCY);
+ CONVERT_MASK(AudioObjectType_SideLeft, SPEAKER_SIDE_LEFT);
+ CONVERT_MASK(AudioObjectType_SideRight, SPEAKER_SIDE_RIGHT);
+ CONVERT_MASK(AudioObjectType_BackLeft, SPEAKER_BACK_LEFT);
+ CONVERT_MASK(AudioObjectType_BackRight, SPEAKER_BACK_RIGHT);
+ CONVERT_MASK(AudioObjectType_TopFrontLeft, SPEAKER_TOP_FRONT_LEFT);
+ CONVERT_MASK(AudioObjectType_TopFrontRight, SPEAKER_TOP_FRONT_RIGHT);
+ CONVERT_MASK(AudioObjectType_TopBackLeft, SPEAKER_TOP_BACK_LEFT);
+ CONVERT_MASK(AudioObjectType_TopBackRight, SPEAKER_TOP_BACK_RIGHT);
+ CONVERT_MASK(AudioObjectType_BackCenter, SPEAKER_BACK_CENTER);
+}
+
+static HRESULT activate_stream(SpatialAudioStreamImpl *stream)
+{
+ WAVEFORMATEXTENSIBLE *object_fmtex = (WAVEFORMATEXTENSIBLE *)stream->params.ObjectFormat;
+ HRESULT hr;
+ REFERENCE_TIME period;
+
+ if(!(object_fmtex->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
+ (object_fmtex->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
+ IsEqualGUID(&object_fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))){
+ FIXME("Only float formats are supported for now\n");
+ return E_INVALIDARG;
+ }
+
+ hr = IMMDevice_Activate(stream->sa_client->mmdev, &IID_IAudioClient,
+ CLSCTX_INPROC_SERVER, NULL, (void**)&stream->client);
+ if(FAILED(hr)){
+ WARN("Activate failed: %08x\n", hr);
+ return hr;
+ }
+
+ hr = IAudioClient_GetDevicePeriod(stream->client, &period, NULL);
+ if(FAILED(hr)){
+ WARN("GetDevicePeriod failed: %08x\n", hr);
+ IAudioClient_Release(stream->client);
+ return hr;
+ }
+
+ stream->stream_fmtex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
+ static_mask_to_channels(stream->params.StaticObjectTypeMask,
+ &stream->stream_fmtex.Format.nChannels, &stream->stream_fmtex.dwChannelMask,
+ stream->static_object_map);
+ stream->stream_fmtex.Format.nSamplesPerSec = stream->params.ObjectFormat->nSamplesPerSec;
+ stream->stream_fmtex.Format.wBitsPerSample = stream->params.ObjectFormat->wBitsPerSample;
+ stream->stream_fmtex.Format.nBlockAlign = (stream->stream_fmtex.Format.nChannels * stream->stream_fmtex.Format.wBitsPerSample) / 8;
+ stream->stream_fmtex.Format.nAvgBytesPerSec = stream->stream_fmtex.Format.nSamplesPerSec * stream->stream_fmtex.Format.nBlockAlign;
+ stream->stream_fmtex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
+ stream->stream_fmtex.Samples.wValidBitsPerSample = stream->stream_fmtex.Format.wBitsPerSample;
+ stream->stream_fmtex.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
+
+ hr = IAudioClient_Initialize(stream->client, AUDCLNT_SHAREMODE_SHARED,
+ AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST,
+ period * MAX_PERIODS, 0, &stream->stream_fmtex.Format, NULL);
+ if(FAILED(hr)){
+ WARN("Initialize failed: %08x\n", hr);
+ IAudioClient_Release(stream->client);
+ return hr;
+ }
+
+ hr = IAudioClient_SetEventHandle(stream->client, stream->params.EventHandle);
+ if(FAILED(hr)){
+ WARN("SetEventHandle failed: %08x\n", hr);
+ IAudioClient_Release(stream->client);
+ return hr;
+ }
+
+ hr = IAudioClient_GetService(stream->client, &IID_IAudioRenderClient, (void**)&stream->render);
+ if(FAILED(hr)){
+ WARN("GetService(AudioRenderClient) failed: %08x\n", hr);
+ IAudioClient_Release(stream->client);
+ return hr;
+ }
+
+ stream->period_frames = MulDiv(period, stream->stream_fmtex.Format.nSamplesPerSec, 10000000);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI SAC_ActivateSpatialAudioStream(ISpatialAudioClient *iface,
+ const PROPVARIANT *prop, REFIID riid, void **stream)
+{
+ SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface);
+ SpatialAudioObjectRenderStreamActivationParams *params;
+ HRESULT hr;
+
+ TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), stream);
+
+ if(IsEqualIID(riid, &IID_ISpatialAudioObjectRenderStream)){
+ SpatialAudioStreamImpl *obj;
+
+ if(prop &&
+ (prop->vt != VT_BLOB ||
+ prop->u.blob.cbSize != sizeof(SpatialAudioObjectRenderStreamActivationParams))){
+ WARN("Got invalid params\n");
+ *stream = NULL;
+ return E_INVALIDARG;
+ }
+
+ params = (SpatialAudioObjectRenderStreamActivationParams*) prop->u.blob.pBlobData;
+
+ if(params->StaticObjectTypeMask & AudioObjectType_Dynamic){
+ *stream = NULL;
+ return E_INVALIDARG;
+ }
+
+ if(params->EventHandle == INVALID_HANDLE_VALUE ||
+ params->EventHandle == 0){
+ *stream = NULL;
+ return E_INVALIDARG;
+ }
+
+ if(!params->ObjectFormat ||
+ memcmp(params->ObjectFormat, &This->object_fmtex.Format, sizeof(*params->ObjectFormat) + params->ObjectFormat->cbSize)){
+ *stream = NULL;
+ return AUDCLNT_E_UNSUPPORTED_FORMAT;
+ }
+
+ obj = heap_alloc_zero(sizeof(SpatialAudioStreamImpl));
+
+ obj->ISpatialAudioObjectRenderStream_iface.lpVtbl = &ISpatialAudioObjectRenderStream_vtbl;
+ obj->ref = 1;
+ memcpy(&obj->params, params, sizeof(obj->params));
+
+ obj->update_frames = ~0;
+
+ InitializeCriticalSection(&obj->lock);
+ list_init(&obj->objects);
+
+ obj->sa_client = This;
+ SAC_AddRef(&This->ISpatialAudioClient_iface);
+
+ obj->params.ObjectFormat = clone_fmtex(obj->params.ObjectFormat);
+
+ DuplicateHandle(GetCurrentProcess(), obj->params.EventHandle,
+ GetCurrentProcess(), &obj->params.EventHandle, 0, FALSE,
+ DUPLICATE_SAME_ACCESS);
+
+ if(obj->params.NotifyObject)
+ ISpatialAudioObjectRenderStreamNotify_AddRef(obj->params.NotifyObject);
+
+ if(TRACE_ON(mmdevapi)){
+ TRACE("ObjectFormat: {%s}\n", debugstr_fmtex(obj->params.ObjectFormat));
+ TRACE("StaticObjectTypeMask: 0x%x\n", obj->params.StaticObjectTypeMask);
+ TRACE("MinDynamicObjectCount: 0x%x\n", obj->params.MinDynamicObjectCount);
+ TRACE("MaxDynamicObjectCount: 0x%x\n", obj->params.MaxDynamicObjectCount);
+ TRACE("Category: 0x%x\n", obj->params.Category);
+ TRACE("EventHandle: %p\n", obj->params.EventHandle);
+ TRACE("NotifyObject: %p\n", obj->params.NotifyObject);
+ }
+
+ hr = activate_stream(obj);
+ if(FAILED(hr)){
+ if(obj->params.NotifyObject)
+ ISpatialAudioObjectRenderStreamNotify_Release(obj->params.NotifyObject);
+ DeleteCriticalSection(&obj->lock);
+ heap_free((void*)obj->params.ObjectFormat);
+ CloseHandle(obj->params.EventHandle);
+ ISpatialAudioClient_Release(&obj->sa_client->ISpatialAudioClient_iface);
+ heap_free(obj);
+ *stream = NULL;
+ return hr;
+ }
+
+ *stream = &obj->ISpatialAudioObjectRenderStream_iface;
+ }else{
+ FIXME("Unsupported audio stream IID: %s\n", debugstr_guid(riid));
+ *stream = NULL;
+ return E_NOTIMPL;
+ }
+
+ return S_OK;
+}
+
+static ISpatialAudioClientVtbl ISpatialAudioClient_vtbl = {
+ SAC_QueryInterface,
+ SAC_AddRef,
+ SAC_Release,
+ SAC_GetStaticObjectPosition,
+ SAC_GetNativeStaticObjectTypeMask,
+ SAC_GetMaxDynamicObjectCount,
+ SAC_GetSupportedAudioObjectFormatEnumerator,
+ SAC_GetMaxFrameCount,
+ SAC_IsAudioObjectFormatSupported,
+ SAC_IsSpatialAudioStreamAvailable,
+ SAC_ActivateSpatialAudioStream,
+};
+
+static HRESULT WINAPI SAOFE_QueryInterface(IAudioFormatEnumerator *iface,
+ REFIID riid, void **ppvObject)
+{
+ SpatialAudioImpl *This = impl_from_IAudioFormatEnumerator(iface);
+ return SAC_QueryInterface(&This->ISpatialAudioClient_iface, riid, ppvObject);
+}
+
+static ULONG WINAPI SAOFE_AddRef(IAudioFormatEnumerator *iface)
+{
+ SpatialAudioImpl *This = impl_from_IAudioFormatEnumerator(iface);
+ return SAC_AddRef(&This->ISpatialAudioClient_iface);
+}
+
+static ULONG WINAPI SAOFE_Release(IAudioFormatEnumerator *iface)
+{
+ SpatialAudioImpl *This = impl_from_IAudioFormatEnumerator(iface);
+ return SAC_Release(&This->ISpatialAudioClient_iface);
+}
+
+static HRESULT WINAPI SAOFE_GetCount(IAudioFormatEnumerator *iface, UINT32 *count)
+{
+ SpatialAudioImpl *This = impl_from_IAudioFormatEnumerator(iface);
+
+ TRACE("(%p)->(%p)\n", This, count);
+
+ *count = 1;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI SAOFE_GetFormat(IAudioFormatEnumerator *iface,
+ UINT32 index, WAVEFORMATEX **format)
+{
+ SpatialAudioImpl *This = impl_from_IAudioFormatEnumerator(iface);
+
+ TRACE("(%p)->(%u, %p)\n", This, index, format);
+
+ if(index > 0)
+ return E_INVALIDARG;
+
+ *format = &This->object_fmtex.Format;
+
+ return S_OK;
+}
+
+static IAudioFormatEnumeratorVtbl IAudioFormatEnumerator_vtbl = {
+ SAOFE_QueryInterface,
+ SAOFE_AddRef,
+ SAOFE_Release,
+ SAOFE_GetCount,
+ SAOFE_GetFormat,
+};
+
+HRESULT SpatialAudioClient_Create(IMMDevice *mmdev, ISpatialAudioClient **out)
+{
+ SpatialAudioImpl *obj;
+ IAudioClient *aclient;
+ WAVEFORMATEX *closest;
+ HRESULT hr;
+
+ obj = heap_alloc_zero(sizeof(*obj));
+
+ obj->ref = 1;
+ obj->ISpatialAudioClient_iface.lpVtbl = &ISpatialAudioClient_vtbl;
+ obj->IAudioFormatEnumerator_iface.lpVtbl = &IAudioFormatEnumerator_vtbl;
+
+ obj->object_fmtex.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
+ obj->object_fmtex.Format.nChannels = 1;
+ obj->object_fmtex.Format.nSamplesPerSec = 48000;
+ obj->object_fmtex.Format.wBitsPerSample = sizeof(float) * 8;
+ obj->object_fmtex.Format.nBlockAlign = (obj->object_fmtex.Format.nChannels * obj->object_fmtex.Format.wBitsPerSample) / 8;
+ obj->object_fmtex.Format.nAvgBytesPerSec = obj->object_fmtex.Format.nSamplesPerSec * obj->object_fmtex.Format.nBlockAlign;
+ obj->object_fmtex.Format.cbSize = 0;
+
+ hr = IMMDevice_Activate(mmdev, &IID_IAudioClient,
+ CLSCTX_INPROC_SERVER, NULL, (void**)&aclient);
+ if(FAILED(hr)){
+ WARN("Activate failed: %08x\n", hr);
+ heap_free(obj);
+ return hr;
+ }
+
+ hr = IAudioClient_IsFormatSupported(aclient, AUDCLNT_SHAREMODE_SHARED, &obj->object_fmtex.Format, &closest);
+
+ IAudioClient_Release(aclient);
+
+ if(hr == S_FALSE){
+ if(sizeof(WAVEFORMATEX) + closest->cbSize > sizeof(obj->object_fmtex)){
+ ERR("Returned format too large: %s\n", debugstr_fmtex(closest));
+ CoTaskMemFree(closest);
+ heap_free(obj);
+ return AUDCLNT_E_UNSUPPORTED_FORMAT;
+ }else if(!((closest->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
+ (closest->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
+ IsEqualGUID(&((WAVEFORMATEXTENSIBLE *)closest)->SubFormat,
+ &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))) &&
+ closest->wBitsPerSample == 32)){
+ ERR("Returned format not 32-bit float: %s\n", debugstr_fmtex(closest));
+ CoTaskMemFree(closest);
+ heap_free(obj);
+ return AUDCLNT_E_UNSUPPORTED_FORMAT;
+ }
+ WARN("The audio stack doesn't support 48kHz 32bit float. Using the closest match. Audio may be glitchy. %s\n", debugstr_fmtex(closest));
+ memcpy(&obj->object_fmtex,
+ closest,
+ sizeof(WAVEFORMATEX) + closest->cbSize);
+ CoTaskMemFree(closest);
+ } else if(hr != S_OK){
+ WARN("Checking supported formats failed: %08x\n", hr);
+ heap_free(obj);
+ return hr;
+ }
+
+ obj->mmdev = mmdev;
+ IMMDevice_AddRef(mmdev);
+
+ *out = &obj->ISpatialAudioClient_iface;
+
+ return S_OK;
+}
diff --git a/include/spatialaudioclient.idl b/include/spatialaudioclient.idl
index 16a1541fd1d..08c84965566 100644
--- a/include/spatialaudioclient.idl
+++ b/include/spatialaudioclient.idl
@@ -43,6 +43,47 @@ typedef [v1_enum] enum AudioObjectType
AudioObjectType_BackCenter = 0x00020000,
} AudioObjectType;
+cpp_quote("#define SPTLAUDCLNT_E_DESTROYED AUDCLNT_ERR(0x100)")
+cpp_quote("#define SPTLAUDCLNT_E_OUT_OF_ORDER AUDCLNT_ERR(0x101)")
+cpp_quote("#define SPTLAUDCLNT_E_RESOURCES_INVALIDATED AUDCLNT_ERR(0x102)")
+cpp_quote("#define SPTLAUDCLNT_E_NO_MORE_OBJECTS AUDCLNT_ERR(0x103)")
+cpp_quote("#define SPTLAUDCLNT_E_PROPERTY_NOT_SUPPORTED AUDCLNT_ERR(0x104)")
+cpp_quote("#define SPTLAUDCLNT_E_ERRORS_IN_OBJECT_CALLS AUDCLNT_ERR(0x105)")
+cpp_quote("#define SPTLAUDCLNT_E_METADATA_FORMAT_NOT_SUPPORTED AUDCLNT_ERR(0x106)")
+cpp_quote("#define SPTLAUDCLNT_E_STREAM_NOT_AVAILABLE AUDCLNT_ERR(0x107)")
+cpp_quote("#define SPTLAUDCLNT_E_INVALID_LICENSE AUDCLNT_ERR(0x108)")
+cpp_quote("#define SPTLAUDCLNT_E_STREAM_NOT_STOPPED AUDCLNT_ERR(0x10a)")
+cpp_quote("#define SPTLAUDCLNT_E_STATIC_OBJECT_NOT_AVAILABLE AUDCLNT_ERR(0x10b)")
+cpp_quote("#define SPTLAUDCLNT_E_OBJECT_ALREADY_ACTIVE AUDCLNT_ERR(0x10c)")
+cpp_quote("#define SPTLAUDCLNT_E_INTERNAL AUDCLNT_ERR(0x10d)")
+
+interface ISpatialAudioObjectRenderStreamBase;
+
+[
+ object,
+ uuid(dddf83e6-68d7-4c70-883f-a1836afb4a50),
+ pointer_default(unique),
+ local
+]
+interface ISpatialAudioObjectRenderStreamNotify : IUnknown
+{
+ HRESULT OnAvailableDynamicObjectCountChange(
+ [in] ISpatialAudioObjectRenderStreamBase *stream,
+ [in] LONGLONG deadline,
+ [in] UINT32 object_count);
+}
+
+typedef struct tagSpatialAudioObjectRenderStreamActivationParams
+{
+ const WAVEFORMATEX *ObjectFormat;
+ AudioObjectType StaticObjectTypeMask;
+ UINT32 MinDynamicObjectCount;
+ UINT32 MaxDynamicObjectCount;
+ AUDIO_STREAM_CATEGORY Category;
+ HANDLE EventHandle;
+ ISpatialAudioObjectRenderStreamNotify *NotifyObject;
+} SpatialAudioObjectRenderStreamActivationParams;
+
[
object,
uuid(dcdaa858-895a-4a22-a5eb-67bda506096d),
@@ -98,3 +139,83 @@ interface ISpatialAudioClient : IUnknown
[in] REFIID riid,
[out, iid_is(riid)] void **stream);
}
+
+[
+ object,
+ uuid(cce0b8f2-8d4d-4efb-a8cf-3d6ecf1c30e0),
+ pointer_default(unique),
+ local
+]
+interface ISpatialAudioObjectBase : IUnknown
+{
+ HRESULT GetBuffer(
+ [out] BYTE **buffer,
+ [out] UINT32 *bytes);
+
+ HRESULT SetEndOfStream(
+ [in] UINT32 frames);
+
+ HRESULT IsActive(
+ [out] BOOL *active);
+
+ HRESULT GetAudioObjectType(
+ [out] AudioObjectType *type);
+}
+
+[
+ object,
+ uuid(dde28967-521b-46e5-8f00-bd6f2bc8ab1d),
+ pointer_default(unique),
+ local
+]
+interface ISpatialAudioObject : ISpatialAudioObjectBase
+{
+ HRESULT SetPosition(
+ [in] float x,
+ [in] float y,
+ [in] float z);
+
+ HRESULT SetVolume(
+ [in] float vol);
+}
+
+[
+ object,
+ uuid(feaaf403-c1d8-450d-aa05-e0ccee7502a8),
+ pointer_default(unique),
+ local
+]
+interface ISpatialAudioObjectRenderStreamBase : IUnknown
+{
+ HRESULT GetAvailableDynamicObjectCount(
+ [out] UINT32 *count);
+
+ HRESULT GetService(
+ [in] REFIID riid,
+ [out] void **service);
+
+ HRESULT Start();
+
+ HRESULT Stop();
+
+ HRESULT Reset();
+
+ HRESULT BeginUpdatingAudioObjects(
+ [out] UINT32 *count,
+ [out] UINT32 *frames);
+
+ HRESULT EndUpdatingAudioObjects();
+}
+
+[
+ object,
+ uuid(bab5f473-b423-477b-85f5-b5a332a04153),
+ pointer_default(unique),
+ local
+]
+interface ISpatialAudioObjectRenderStream : ISpatialAudioObjectRenderStreamBase
+{
+ HRESULT ActivateSpatialAudioObject(
+ [in] AudioObjectType type,
+ [out] ISpatialAudioObject **object);
+}
--
2.30.0
2
3
Feb. 4, 2021
From: Andrew Eikum <aeikum(a)codeweavers.com>
This makes car radio / ambient noises audible in Cyberpunk 2077.
Signed-off-by: Arkadiusz Hiler <ahiler(a)codeweavers.com>
---
dlls/mmdevapi/Makefile.in | 3 +-
dlls/mmdevapi/audiovolume.c | 1 +
dlls/mmdevapi/devenum.c | 5 +
dlls/mmdevapi/main.c | 1 +
dlls/mmdevapi/mmdevapi.h | 1 +
dlls/mmdevapi/spatialaudio.c | 988 +++++++++++++++++++++++++++++++++
include/spatialaudioclient.idl | 121 ++++
7 files changed, 1119 insertions(+), 1 deletion(-)
create mode 100644 dlls/mmdevapi/spatialaudio.c
diff --git a/dlls/mmdevapi/Makefile.in b/dlls/mmdevapi/Makefile.in
index 5f44f7ba53b..903b14335a9 100644
--- a/dlls/mmdevapi/Makefile.in
+++ b/dlls/mmdevapi/Makefile.in
@@ -6,6 +6,7 @@ EXTRADLLFLAGS = -mno-cygwin
C_SRCS = \
audiovolume.c \
devenum.c \
- main.c
+ main.c \
+ spatialaudio.c
IDL_SRCS = mmdevapi_classes.idl
diff --git a/dlls/mmdevapi/audiovolume.c b/dlls/mmdevapi/audiovolume.c
index 9214980120e..6f403cf348a 100644
--- a/dlls/mmdevapi/audiovolume.c
+++ b/dlls/mmdevapi/audiovolume.c
@@ -33,6 +33,7 @@
#include "audioclient.h"
#include "endpointvolume.h"
#include "audiopolicy.h"
+#include "spatialaudioclient.h"
#include "mmdevapi.h"
diff --git a/dlls/mmdevapi/devenum.c b/dlls/mmdevapi/devenum.c
index 9e4a29816ce..07b4dca028b 100644
--- a/dlls/mmdevapi/devenum.c
+++ b/dlls/mmdevapi/devenum.c
@@ -35,6 +35,7 @@
#include "audioclient.h"
#include "endpointvolume.h"
#include "audiopolicy.h"
+#include "spatialaudioclient.h"
#include "mmdevapi.h"
#include "devpkey.h"
@@ -635,6 +636,10 @@ static HRESULT WINAPI MMDevice_Activate(IMMDevice *iface, REFIID riid, DWORD cls
IDirectSoundCapture_Release((IDirectSoundCapture*)*ppv);
}
}
+ else if (IsEqualIID(riid, &IID_ISpatialAudioClient))
+ {
+ hr = SpatialAudioClient_Create(iface, (ISpatialAudioClient**)ppv);
+ }
else
ERR("Invalid/unknown iid %s\n", debugstr_guid(riid));
diff --git a/dlls/mmdevapi/main.c b/dlls/mmdevapi/main.c
index 247ebc3b001..eac1da28f18 100644
--- a/dlls/mmdevapi/main.c
+++ b/dlls/mmdevapi/main.c
@@ -37,6 +37,7 @@
#include "audiopolicy.h"
#include "devpkey.h"
#include "winreg.h"
+#include "spatialaudioclient.h"
#include "mmdevapi.h"
#include "wine/debug.h"
diff --git a/dlls/mmdevapi/mmdevapi.h b/dlls/mmdevapi/mmdevapi.h
index bc9788e95c8..3bcf568cddf 100644
--- a/dlls/mmdevapi/mmdevapi.h
+++ b/dlls/mmdevapi/mmdevapi.h
@@ -71,5 +71,6 @@ typedef struct MMDevice {
extern HRESULT AudioClient_Create(MMDevice *parent, IAudioClient **ppv) DECLSPEC_HIDDEN;
extern HRESULT AudioEndpointVolume_Create(MMDevice *parent, IAudioEndpointVolumeEx **ppv) DECLSPEC_HIDDEN;
+extern HRESULT SpatialAudioClient_Create(IMMDevice *device, ISpatialAudioClient **out) DECLSPEC_HIDDEN;
extern const WCHAR drv_keyW[] DECLSPEC_HIDDEN;
diff --git a/dlls/mmdevapi/spatialaudio.c b/dlls/mmdevapi/spatialaudio.c
new file mode 100644
index 00000000000..cbca57b4890
--- /dev/null
+++ b/dlls/mmdevapi/spatialaudio.c
@@ -0,0 +1,988 @@
+/*
+ * Copyright 2020 Andrew Eikum for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define COBJMACROS
+#define NONAMELESSUNION
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winnls.h"
+#include "winreg.h"
+#include "wine/heap.h"
+#include "wine/debug.h"
+#include "wine/list.h"
+
+#include "ole2.h"
+#include "mmdeviceapi.h"
+#include "mmsystem.h"
+#include "audioclient.h"
+#include "endpointvolume.h"
+#include "audiopolicy.h"
+#include "spatialaudioclient.h"
+
+#include "mmdevapi.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi);
+
+#define MAX_PERIODS 3
+
+static UINT32 AudioObjectType_to_index(AudioObjectType type)
+{
+ UINT32 o = 0;
+ while(type){
+ type >>= 1;
+ ++o;
+ }
+ return o - 2;
+}
+
+typedef struct SpatialAudioImpl SpatialAudioImpl;
+typedef struct SpatialAudioStreamImpl SpatialAudioStreamImpl;
+typedef struct SpatialAudioObjectImpl SpatialAudioObjectImpl;
+
+struct SpatialAudioObjectImpl {
+ ISpatialAudioObject ISpatialAudioObject_iface;
+ LONG ref;
+
+ SpatialAudioStreamImpl *sa_stream;
+ AudioObjectType type;
+ UINT32 static_idx;
+
+ float *buf;
+
+ struct list entry;
+};
+
+struct SpatialAudioStreamImpl {
+ ISpatialAudioObjectRenderStream ISpatialAudioObjectRenderStream_iface;
+ LONG ref;
+ CRITICAL_SECTION lock;
+
+ SpatialAudioImpl *sa_client;
+ SpatialAudioObjectRenderStreamActivationParams params;
+
+ IAudioClient *client;
+ IAudioRenderClient *render;
+
+ UINT32 period_frames, update_frames;
+ WAVEFORMATEXTENSIBLE stream_fmtex;
+
+ float *buf;
+
+ UINT32 static_object_map[17];
+
+ struct list objects;
+};
+
+struct SpatialAudioImpl {
+ ISpatialAudioClient ISpatialAudioClient_iface;
+ IAudioFormatEnumerator IAudioFormatEnumerator_iface;
+ IMMDevice *mmdev;
+ LONG ref;
+ WAVEFORMATEXTENSIBLE object_fmtex;
+};
+
+static inline SpatialAudioObjectImpl *impl_from_ISpatialAudioObject(ISpatialAudioObject *iface)
+{
+ return CONTAINING_RECORD(iface, SpatialAudioObjectImpl, ISpatialAudioObject_iface);
+}
+
+static inline SpatialAudioStreamImpl *impl_from_ISpatialAudioObjectRenderStream(ISpatialAudioObjectRenderStream *iface)
+{
+ return CONTAINING_RECORD(iface, SpatialAudioStreamImpl, ISpatialAudioObjectRenderStream_iface);
+}
+
+static inline SpatialAudioImpl *impl_from_ISpatialAudioClient(ISpatialAudioClient *iface)
+{
+ return CONTAINING_RECORD(iface, SpatialAudioImpl, ISpatialAudioClient_iface);
+}
+
+static inline SpatialAudioImpl *impl_from_IAudioFormatEnumerator(IAudioFormatEnumerator *iface)
+{
+ return CONTAINING_RECORD(iface, SpatialAudioImpl, IAudioFormatEnumerator_iface);
+}
+
+static HRESULT WINAPI SAO_QueryInterface(ISpatialAudioObject *iface,
+ REFIID riid, void **ppv)
+{
+ SpatialAudioObjectImpl *This = impl_from_ISpatialAudioObject(iface);
+
+ TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppv);
+
+ if (!ppv)
+ return E_POINTER;
+
+ *ppv = NULL;
+
+ if (IsEqualIID(riid, &IID_IUnknown) ||
+ IsEqualIID(riid, &IID_ISpatialAudioObjectBase) ||
+ IsEqualIID(riid, &IID_ISpatialAudioObject)) {
+ *ppv = &This->ISpatialAudioObject_iface;
+ }
+ else
+ return E_NOINTERFACE;
+
+ IUnknown_AddRef((IUnknown *)*ppv);
+
+ return S_OK;
+}
+
+static ULONG WINAPI SAO_AddRef(ISpatialAudioObject *iface)
+{
+ SpatialAudioObjectImpl *This = impl_from_ISpatialAudioObject(iface);
+ ULONG ref = InterlockedIncrement(&This->ref);
+ TRACE("(%p) new ref %u\n", This, ref);
+ return ref;
+}
+
+static ULONG WINAPI SAO_Release(ISpatialAudioObject *iface)
+{
+ SpatialAudioObjectImpl *This = impl_from_ISpatialAudioObject(iface);
+ ULONG ref = InterlockedDecrement(&This->ref);
+ TRACE("(%p) new ref %u\n", This, ref);
+ if(!ref){
+ EnterCriticalSection(&This->sa_stream->lock);
+ list_remove(&This->entry);
+ LeaveCriticalSection(&This->sa_stream->lock);
+
+ ISpatialAudioObjectRenderStream_Release(&This->sa_stream->ISpatialAudioObjectRenderStream_iface);
+ heap_free(This->buf);
+ heap_free(This);
+ }
+ return ref;
+}
+
+static HRESULT WINAPI SAO_GetBuffer(ISpatialAudioObject *iface,
+ BYTE **buffer, UINT32 *bytes)
+{
+ SpatialAudioObjectImpl *This = impl_from_ISpatialAudioObject(iface);
+
+ TRACE("(%p)->(%p, %p)\n", This, buffer, bytes);
+
+ EnterCriticalSection(&This->sa_stream->lock);
+
+ if(This->sa_stream->update_frames == ~0){
+ LeaveCriticalSection(&This->sa_stream->lock);
+ return SPTLAUDCLNT_E_OUT_OF_ORDER;
+ }
+
+ *buffer = (BYTE *)This->buf;
+ *bytes = This->sa_stream->update_frames *
+ This->sa_stream->sa_client->object_fmtex.Format.nBlockAlign;
+
+ LeaveCriticalSection(&This->sa_stream->lock);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI SAO_SetEndOfStream(ISpatialAudioObject *iface, UINT32 frames)
+{
+ SpatialAudioObjectImpl *This = impl_from_ISpatialAudioObject(iface);
+ FIXME("(%p)->(%u)\n", This, frames);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI SAO_IsActive(ISpatialAudioObject *iface, BOOL *active)
+{
+ SpatialAudioObjectImpl *This = impl_from_ISpatialAudioObject(iface);
+ FIXME("(%p)->(%p)\n", This, active);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI SAO_GetAudioObjectType(ISpatialAudioObject *iface,
+ AudioObjectType *type)
+{
+ SpatialAudioObjectImpl *This = impl_from_ISpatialAudioObject(iface);
+
+ TRACE("(%p)->(%p)\n", This, type);
+
+ *type = This->type;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI SAO_SetPosition(ISpatialAudioObject *iface, float x,
+ float y, float z)
+{
+ SpatialAudioObjectImpl *This = impl_from_ISpatialAudioObject(iface);
+ FIXME("(%p)->(%f, %f, %f)\n", This, x, y, z);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI SAO_SetVolume(ISpatialAudioObject *iface, float vol)
+{
+ SpatialAudioObjectImpl *This = impl_from_ISpatialAudioObject(iface);
+ FIXME("(%p)->(%f)\n", This, vol);
+ return E_NOTIMPL;
+}
+
+static ISpatialAudioObjectVtbl ISpatialAudioObject_vtbl = {
+ SAO_QueryInterface,
+ SAO_AddRef,
+ SAO_Release,
+ SAO_GetBuffer,
+ SAO_SetEndOfStream,
+ SAO_IsActive,
+ SAO_GetAudioObjectType,
+ SAO_SetPosition,
+ SAO_SetVolume,
+};
+
+static HRESULT WINAPI SAORS_QueryInterface(ISpatialAudioObjectRenderStream *iface,
+ REFIID riid, void **ppv)
+{
+ SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface);
+
+ TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppv);
+
+ if (!ppv)
+ return E_POINTER;
+
+ *ppv = NULL;
+
+ if (IsEqualIID(riid, &IID_IUnknown) ||
+ IsEqualIID(riid, &IID_ISpatialAudioObjectRenderStreamBase) ||
+ IsEqualIID(riid, &IID_ISpatialAudioObjectRenderStream)) {
+ *ppv = &This->ISpatialAudioObjectRenderStream_iface;
+ }
+ else
+ return E_NOINTERFACE;
+
+ IUnknown_AddRef((IUnknown *)*ppv);
+
+ return S_OK;
+}
+
+static ULONG WINAPI SAORS_AddRef(ISpatialAudioObjectRenderStream *iface)
+{
+ SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface);
+ ULONG ref = InterlockedIncrement(&This->ref);
+ TRACE("(%p) new ref %u\n", This, ref);
+ return ref;
+}
+
+static ULONG WINAPI SAORS_Release(ISpatialAudioObjectRenderStream *iface)
+{
+ SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface);
+ ULONG ref = InterlockedDecrement(&This->ref);
+ TRACE("(%p) new ref %u\n", This, ref);
+ if(!ref){
+ IAudioClient_Stop(This->client);
+ if(This->update_frames != ~0 && This->update_frames > 0)
+ IAudioRenderClient_ReleaseBuffer(This->render, This->update_frames, 0);
+ IAudioRenderClient_Release(This->render);
+ IAudioClient_Release(This->client);
+ if(This->params.NotifyObject)
+ ISpatialAudioObjectRenderStreamNotify_Release(This->params.NotifyObject);
+ heap_free((void*)This->params.ObjectFormat);
+ CloseHandle(This->params.EventHandle);
+ DeleteCriticalSection(&This->lock);
+ ISpatialAudioClient_Release(&This->sa_client->ISpatialAudioClient_iface);
+ heap_free(This);
+ }
+ return ref;
+}
+
+static HRESULT WINAPI SAORS_GetAvailableDynamicObjectCount(
+ ISpatialAudioObjectRenderStream *iface, UINT32 *count)
+{
+ SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface);
+ FIXME("(%p)->(%p)\n", This, count);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI SAORS_GetService(ISpatialAudioObjectRenderStream *iface,
+ REFIID riid, void **service)
+{
+ SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface);
+ FIXME("(%p)->(%s, %p)\n", This, debugstr_guid(riid), service);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI SAORS_Start(ISpatialAudioObjectRenderStream *iface)
+{
+ SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface);
+ HRESULT hr;
+
+ TRACE("(%p)->()\n", This);
+
+ hr = IAudioClient_Start(This->client);
+ if(FAILED(hr)){
+ WARN("IAudioClient::Start failed: %08x\n", hr);
+ return hr;
+ }
+
+ return S_OK;
+}
+
+static HRESULT WINAPI SAORS_Stop(ISpatialAudioObjectRenderStream *iface)
+{
+ SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface);
+ HRESULT hr;
+
+ TRACE("(%p)->()\n", This);
+
+ hr = IAudioClient_Stop(This->client);
+ if(FAILED(hr)){
+ WARN("IAudioClient::Stop failed: %08x\n", hr);
+ return hr;
+ }
+
+ return S_OK;
+}
+
+static HRESULT WINAPI SAORS_Reset(ISpatialAudioObjectRenderStream *iface)
+{
+ SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface);
+ FIXME("(%p)->()\n", This);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI SAORS_BeginUpdatingAudioObjects(ISpatialAudioObjectRenderStream *iface,
+ UINT32 *dyn_count, UINT32 *frames)
+{
+ static BOOL fixme_once = FALSE;
+ SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface);
+ SpatialAudioObjectImpl *object;
+ UINT32 pad;
+ HRESULT hr;
+
+ TRACE("(%p)->(%p, %p)\n", This, dyn_count, frames);
+
+ EnterCriticalSection(&This->lock);
+
+ if(This->update_frames != ~0){
+ LeaveCriticalSection(&This->lock);
+ return SPTLAUDCLNT_E_OUT_OF_ORDER;
+ }
+
+ hr = IAudioClient_GetCurrentPadding(This->client, &pad);
+ if(FAILED(hr)){
+ WARN("GetCurrentPadding failed: %08x\n", hr);
+ LeaveCriticalSection(&This->lock);
+ return hr;
+ }
+
+ if(pad < This->period_frames * MAX_PERIODS){
+ This->update_frames = This->period_frames * MAX_PERIODS - pad;
+ }else{
+ This->update_frames = 0;
+ }
+
+ if(This->update_frames > 0){
+ hr = IAudioRenderClient_GetBuffer(This->render, This->update_frames, (BYTE **)&This->buf);
+ if(FAILED(hr)){
+ WARN("GetBuffer failed: %08x\n", hr);
+ This->update_frames = ~0;
+ LeaveCriticalSection(&This->lock);
+ return hr;
+ }
+
+ LIST_FOR_EACH_ENTRY(object, &This->objects, SpatialAudioObjectImpl, entry){
+ memset(object->buf, 0, This->update_frames * This->sa_client->object_fmtex.Format.nBlockAlign);
+ }
+ }else if (!fixme_once){
+ fixme_once = TRUE;
+ FIXME("Zero frame update.\n");
+ }
+
+ *dyn_count = 0;
+ *frames = This->update_frames;
+
+ LeaveCriticalSection(&This->lock);
+
+ return S_OK;
+}
+
+static void mix_static_object(SpatialAudioStreamImpl *stream, SpatialAudioObjectImpl *object)
+{
+ float *in = object->buf, *out;
+ UINT32 i;
+ if(object->static_idx == ~0 ||
+ stream->static_object_map[object->static_idx] == ~0){
+ WARN("Got unmapped static object?! Not mixing. Type: 0x%x\n", object->type);
+ return;
+ }
+ out = stream->buf + stream->static_object_map[object->static_idx];
+ for(i = 0; i < stream->update_frames; ++i){
+ *out += *in;
+ ++in;
+ out += stream->stream_fmtex.Format.nChannels;
+ }
+}
+
+static HRESULT WINAPI SAORS_EndUpdatingAudioObjects(ISpatialAudioObjectRenderStream *iface)
+{
+ SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface);
+ SpatialAudioObjectImpl *object;
+ HRESULT hr;
+
+ TRACE("(%p)->()\n", This);
+
+ EnterCriticalSection(&This->lock);
+
+ if(This->update_frames == ~0){
+ LeaveCriticalSection(&This->lock);
+ return SPTLAUDCLNT_E_OUT_OF_ORDER;
+ }
+
+ if(This->update_frames > 0){
+ LIST_FOR_EACH_ENTRY(object, &This->objects, SpatialAudioObjectImpl, entry){
+ if(object->type != AudioObjectType_Dynamic)
+ mix_static_object(This, object);
+ else
+ WARN("Don't know how to mix dynamic object yet. %p\n", object);
+ }
+
+ hr = IAudioRenderClient_ReleaseBuffer(This->render, This->update_frames, 0);
+ if(FAILED(hr))
+ WARN("ReleaseBuffer failed: %08x\n", hr);
+ }
+
+ This->update_frames = ~0;
+
+ LeaveCriticalSection(&This->lock);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI SAORS_ActivateSpatialAudioObject(ISpatialAudioObjectRenderStream *iface,
+ AudioObjectType type, ISpatialAudioObject **object)
+{
+ SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface);
+ SpatialAudioObjectImpl *obj;
+
+ TRACE("(%p)->(0x%x, %p)\n", This, type, object);
+
+ if(type == AudioObjectType_Dynamic)
+ return SPTLAUDCLNT_E_NO_MORE_OBJECTS;
+
+ if(type & ~This->params.StaticObjectTypeMask)
+ return SPTLAUDCLNT_E_STATIC_OBJECT_NOT_AVAILABLE;
+
+ LIST_FOR_EACH_ENTRY(obj, &This->objects, SpatialAudioObjectImpl, entry){
+ if(obj->static_idx == AudioObjectType_to_index(type))
+ return SPTLAUDCLNT_E_OBJECT_ALREADY_ACTIVE;
+ }
+
+ obj = heap_alloc_zero(sizeof(*obj));
+ obj->ISpatialAudioObject_iface.lpVtbl = &ISpatialAudioObject_vtbl;
+ obj->ref = 1;
+ obj->type = type;
+ if(type == AudioObjectType_None){
+ FIXME("AudioObjectType_None not implemented yet!\n");
+ obj->static_idx = ~0;
+ }else{
+ obj->static_idx = AudioObjectType_to_index(type);
+ }
+
+ obj->sa_stream = This;
+ SAORS_AddRef(&This->ISpatialAudioObjectRenderStream_iface);
+
+ obj->buf = heap_alloc_zero(This->period_frames * MAX_PERIODS * This->sa_client->object_fmtex.Format.nBlockAlign);
+
+ EnterCriticalSection(&This->lock);
+
+ list_add_tail(&This->objects, &obj->entry);
+
+ LeaveCriticalSection(&This->lock);
+
+ *object = &obj->ISpatialAudioObject_iface;
+
+ return S_OK;
+}
+
+static ISpatialAudioObjectRenderStreamVtbl ISpatialAudioObjectRenderStream_vtbl = {
+ SAORS_QueryInterface,
+ SAORS_AddRef,
+ SAORS_Release,
+ SAORS_GetAvailableDynamicObjectCount,
+ SAORS_GetService,
+ SAORS_Start,
+ SAORS_Stop,
+ SAORS_Reset,
+ SAORS_BeginUpdatingAudioObjects,
+ SAORS_EndUpdatingAudioObjects,
+ SAORS_ActivateSpatialAudioObject,
+};
+
+static HRESULT WINAPI SAC_QueryInterface(ISpatialAudioClient *iface, REFIID riid, void **ppv)
+{
+ SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface);
+
+ TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppv);
+
+ if (!ppv)
+ return E_POINTER;
+
+ *ppv = NULL;
+
+ if (IsEqualIID(riid, &IID_IUnknown) ||
+ IsEqualIID(riid, &IID_ISpatialAudioClient)) {
+ *ppv = &This->ISpatialAudioClient_iface;
+ }
+ else
+ return E_NOINTERFACE;
+
+ IUnknown_AddRef((IUnknown *)*ppv);
+
+ return S_OK;
+}
+
+static ULONG WINAPI SAC_AddRef(ISpatialAudioClient *iface)
+{
+ SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface);
+ ULONG ref = InterlockedIncrement(&This->ref);
+ TRACE("(%p) new ref %u\n", This, ref);
+ return ref;
+}
+
+static ULONG WINAPI SAC_Release(ISpatialAudioClient *iface)
+{
+ SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface);
+ ULONG ref = InterlockedDecrement(&This->ref);
+ TRACE("(%p) new ref %u\n", This, ref);
+ if (!ref) {
+ IMMDevice_Release(This->mmdev);
+ heap_free(This);
+ }
+ return ref;
+}
+
+static HRESULT WINAPI SAC_GetStaticObjectPosition(ISpatialAudioClient *iface,
+ AudioObjectType type, float *x, float *y, float *z)
+{
+ SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface);
+ FIXME("(%p)->(0x%x, %p, %p, %p)\n", This, type, x, y, z);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI SAC_GetNativeStaticObjectTypeMask(ISpatialAudioClient *iface,
+ AudioObjectType *mask)
+{
+ SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface);
+ FIXME("(%p)->(%p)\n", This, mask);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI SAC_GetMaxDynamicObjectCount(ISpatialAudioClient *iface,
+ UINT32 *value)
+{
+ SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface);
+ FIXME("(%p)->(%p)\n", This, value);
+
+ *value = 0;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI SAC_GetSupportedAudioObjectFormatEnumerator(
+ ISpatialAudioClient *iface, IAudioFormatEnumerator **enumerator)
+{
+ SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface);
+
+ TRACE("(%p)->(%p)\n", This, enumerator);
+
+ *enumerator = &This->IAudioFormatEnumerator_iface;
+ SAC_AddRef(iface);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI SAC_GetMaxFrameCount(ISpatialAudioClient *iface,
+ const WAVEFORMATEX *format, UINT32 *count)
+{
+ SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface);
+
+ /* FIXME: should get device period from the device */
+ static const REFERENCE_TIME period = 100000;
+
+ TRACE("(%p)->(%p, %p)\n", This, format, count);
+
+ *count = MulDiv(period, format->nSamplesPerSec, 10000000) * MAX_PERIODS;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI SAC_IsAudioObjectFormatSupported(ISpatialAudioClient *iface,
+ const WAVEFORMATEX *format)
+{
+ SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface);
+ FIXME("(%p)->(%p)\n", This, format);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI SAC_IsSpatialAudioStreamAvailable(ISpatialAudioClient *iface,
+ REFIID stream_uuid, const PROPVARIANT *info)
+{
+ SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface);
+ FIXME("(%p)->(%s, %p)\n", This, debugstr_guid(stream_uuid), info);
+ return E_NOTIMPL;
+}
+
+static WAVEFORMATEX *clone_fmtex(const WAVEFORMATEX *src)
+{
+ WAVEFORMATEX *r = heap_alloc(sizeof(WAVEFORMATEX) + src->cbSize);
+ memcpy(r, src, sizeof(WAVEFORMATEX) + src->cbSize);
+ return r;
+}
+
+static const char *debugstr_fmtex(const WAVEFORMATEX *fmt)
+{
+ static char buf[2048];
+ if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
+ const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt;
+ snprintf(buf, sizeof(buf), "tag: 0x%x (%s), ch: %u (mask: 0x%x), rate: %u, depth: %u",
+ fmt->wFormatTag, debugstr_guid(&fmtex->SubFormat),
+ fmt->nChannels, fmtex->dwChannelMask, fmt->nSamplesPerSec,
+ fmt->wBitsPerSample);
+ }else{
+ snprintf(buf, sizeof(buf), "tag: 0x%x, ch: %u, rate: %u, depth: %u",
+ fmt->wFormatTag, fmt->nChannels, fmt->nSamplesPerSec,
+ fmt->wBitsPerSample);
+ }
+ return buf;
+}
+
+static void static_mask_to_channels(AudioObjectType static_mask, WORD *count, DWORD *mask, UINT32 *map)
+{
+ UINT32 out_chan = 0, map_idx = 0;
+ *count = 0;
+ *mask = 0;
+#define CONVERT_MASK(f, t) \
+ if(static_mask & f){ \
+ *count += 1; \
+ *mask |= t; \
+ map[map_idx++] = out_chan++; \
+ TRACE("mapping 0x%x to %u\n", f, out_chan - 1); \
+ }else{ \
+ map[map_idx++] = ~0; \
+ }
+ CONVERT_MASK(AudioObjectType_FrontLeft, SPEAKER_FRONT_LEFT);
+ CONVERT_MASK(AudioObjectType_FrontRight, SPEAKER_FRONT_RIGHT);
+ CONVERT_MASK(AudioObjectType_FrontCenter, SPEAKER_FRONT_CENTER);
+ CONVERT_MASK(AudioObjectType_LowFrequency, SPEAKER_LOW_FREQUENCY);
+ CONVERT_MASK(AudioObjectType_SideLeft, SPEAKER_SIDE_LEFT);
+ CONVERT_MASK(AudioObjectType_SideRight, SPEAKER_SIDE_RIGHT);
+ CONVERT_MASK(AudioObjectType_BackLeft, SPEAKER_BACK_LEFT);
+ CONVERT_MASK(AudioObjectType_BackRight, SPEAKER_BACK_RIGHT);
+ CONVERT_MASK(AudioObjectType_TopFrontLeft, SPEAKER_TOP_FRONT_LEFT);
+ CONVERT_MASK(AudioObjectType_TopFrontRight, SPEAKER_TOP_FRONT_RIGHT);
+ CONVERT_MASK(AudioObjectType_TopBackLeft, SPEAKER_TOP_BACK_LEFT);
+ CONVERT_MASK(AudioObjectType_TopBackRight, SPEAKER_TOP_BACK_RIGHT);
+ CONVERT_MASK(AudioObjectType_BackCenter, SPEAKER_BACK_CENTER);
+}
+
+static HRESULT activate_stream(SpatialAudioStreamImpl *stream)
+{
+ WAVEFORMATEXTENSIBLE *object_fmtex = (WAVEFORMATEXTENSIBLE *)stream->params.ObjectFormat;
+ HRESULT hr;
+ REFERENCE_TIME period;
+
+ if(!(object_fmtex->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
+ (object_fmtex->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
+ IsEqualGUID(&object_fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))){
+ FIXME("Only float formats are supported for now\n");
+ return E_INVALIDARG;
+ }
+
+ hr = IMMDevice_Activate(stream->sa_client->mmdev, &IID_IAudioClient,
+ CLSCTX_INPROC_SERVER, NULL, (void**)&stream->client);
+ if(FAILED(hr)){
+ WARN("Activate failed: %08x\n", hr);
+ return hr;
+ }
+
+ hr = IAudioClient_GetDevicePeriod(stream->client, &period, NULL);
+ if(FAILED(hr)){
+ WARN("GetDevicePeriod failed: %08x\n", hr);
+ IAudioClient_Release(stream->client);
+ return hr;
+ }
+
+ stream->stream_fmtex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
+ static_mask_to_channels(stream->params.StaticObjectTypeMask,
+ &stream->stream_fmtex.Format.nChannels, &stream->stream_fmtex.dwChannelMask,
+ stream->static_object_map);
+ stream->stream_fmtex.Format.nSamplesPerSec = stream->params.ObjectFormat->nSamplesPerSec;
+ stream->stream_fmtex.Format.wBitsPerSample = stream->params.ObjectFormat->wBitsPerSample;
+ stream->stream_fmtex.Format.nBlockAlign = (stream->stream_fmtex.Format.nChannels * stream->stream_fmtex.Format.wBitsPerSample) / 8;
+ stream->stream_fmtex.Format.nAvgBytesPerSec = stream->stream_fmtex.Format.nSamplesPerSec * stream->stream_fmtex.Format.nBlockAlign;
+ stream->stream_fmtex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
+ stream->stream_fmtex.Samples.wValidBitsPerSample = stream->stream_fmtex.Format.wBitsPerSample;
+ stream->stream_fmtex.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
+
+ hr = IAudioClient_Initialize(stream->client, AUDCLNT_SHAREMODE_SHARED,
+ AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST,
+ period * MAX_PERIODS, 0, &stream->stream_fmtex.Format, NULL);
+ if(FAILED(hr)){
+ WARN("Initialize failed: %08x\n", hr);
+ IAudioClient_Release(stream->client);
+ return hr;
+ }
+
+ hr = IAudioClient_SetEventHandle(stream->client, stream->params.EventHandle);
+ if(FAILED(hr)){
+ WARN("SetEventHandle failed: %08x\n", hr);
+ IAudioClient_Release(stream->client);
+ return hr;
+ }
+
+ hr = IAudioClient_GetService(stream->client, &IID_IAudioRenderClient, (void**)&stream->render);
+ if(FAILED(hr)){
+ WARN("GetService(AudioRenderClient) failed: %08x\n", hr);
+ IAudioClient_Release(stream->client);
+ return hr;
+ }
+
+ stream->period_frames = MulDiv(period, stream->stream_fmtex.Format.nSamplesPerSec, 10000000);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI SAC_ActivateSpatialAudioStream(ISpatialAudioClient *iface,
+ const PROPVARIANT *prop, REFIID riid, void **stream)
+{
+ SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface);
+ SpatialAudioObjectRenderStreamActivationParams *params;
+ HRESULT hr;
+
+ TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), stream);
+
+ if(IsEqualIID(riid, &IID_ISpatialAudioObjectRenderStream)){
+ SpatialAudioStreamImpl *obj;
+
+ if(prop &&
+ (prop->vt != VT_BLOB ||
+ prop->u.blob.cbSize != sizeof(SpatialAudioObjectRenderStreamActivationParams))){
+ WARN("Got invalid params\n");
+ *stream = NULL;
+ return E_INVALIDARG;
+ }
+
+ params = (SpatialAudioObjectRenderStreamActivationParams*) prop->u.blob.pBlobData;
+
+ if(params->StaticObjectTypeMask & AudioObjectType_Dynamic){
+ *stream = NULL;
+ return E_INVALIDARG;
+ }
+
+ if(params->EventHandle == INVALID_HANDLE_VALUE ||
+ params->EventHandle == 0){
+ *stream = NULL;
+ return E_INVALIDARG;
+ }
+
+ if(!params->ObjectFormat ||
+ memcmp(params->ObjectFormat, &This->object_fmtex.Format, sizeof(*params->ObjectFormat) + params->ObjectFormat->cbSize)){
+ *stream = NULL;
+ return AUDCLNT_E_UNSUPPORTED_FORMAT;
+ }
+
+ obj = heap_alloc_zero(sizeof(SpatialAudioStreamImpl));
+
+ obj->ISpatialAudioObjectRenderStream_iface.lpVtbl = &ISpatialAudioObjectRenderStream_vtbl;
+ obj->ref = 1;
+ memcpy(&obj->params, params, sizeof(obj->params));
+
+ obj->update_frames = ~0;
+
+ InitializeCriticalSection(&obj->lock);
+ list_init(&obj->objects);
+
+ obj->sa_client = This;
+ SAC_AddRef(&This->ISpatialAudioClient_iface);
+
+ obj->params.ObjectFormat = clone_fmtex(obj->params.ObjectFormat);
+
+ DuplicateHandle(GetCurrentProcess(), obj->params.EventHandle,
+ GetCurrentProcess(), &obj->params.EventHandle, 0, FALSE,
+ DUPLICATE_SAME_ACCESS);
+
+ if(obj->params.NotifyObject)
+ ISpatialAudioObjectRenderStreamNotify_AddRef(obj->params.NotifyObject);
+
+ if(TRACE_ON(mmdevapi)){
+ TRACE("ObjectFormat: {%s}\n", debugstr_fmtex(obj->params.ObjectFormat));
+ TRACE("StaticObjectTypeMask: 0x%x\n", obj->params.StaticObjectTypeMask);
+ TRACE("MinDynamicObjectCount: 0x%x\n", obj->params.MinDynamicObjectCount);
+ TRACE("MaxDynamicObjectCount: 0x%x\n", obj->params.MaxDynamicObjectCount);
+ TRACE("Category: 0x%x\n", obj->params.Category);
+ TRACE("EventHandle: %p\n", obj->params.EventHandle);
+ TRACE("NotifyObject: %p\n", obj->params.NotifyObject);
+ }
+
+ hr = activate_stream(obj);
+ if(FAILED(hr)){
+ if(obj->params.NotifyObject)
+ ISpatialAudioObjectRenderStreamNotify_Release(obj->params.NotifyObject);
+ DeleteCriticalSection(&obj->lock);
+ heap_free((void*)obj->params.ObjectFormat);
+ CloseHandle(obj->params.EventHandle);
+ ISpatialAudioClient_Release(&obj->sa_client->ISpatialAudioClient_iface);
+ heap_free(obj);
+ *stream = NULL;
+ return hr;
+ }
+
+ *stream = &obj->ISpatialAudioObjectRenderStream_iface;
+ }else{
+ FIXME("Unsupported audio stream IID: %s\n", debugstr_guid(riid));
+ *stream = NULL;
+ return E_NOTIMPL;
+ }
+
+ return S_OK;
+}
+
+static ISpatialAudioClientVtbl ISpatialAudioClient_vtbl = {
+ SAC_QueryInterface,
+ SAC_AddRef,
+ SAC_Release,
+ SAC_GetStaticObjectPosition,
+ SAC_GetNativeStaticObjectTypeMask,
+ SAC_GetMaxDynamicObjectCount,
+ SAC_GetSupportedAudioObjectFormatEnumerator,
+ SAC_GetMaxFrameCount,
+ SAC_IsAudioObjectFormatSupported,
+ SAC_IsSpatialAudioStreamAvailable,
+ SAC_ActivateSpatialAudioStream,
+};
+
+static HRESULT WINAPI SAOFE_QueryInterface(IAudioFormatEnumerator *iface,
+ REFIID riid, void **ppvObject)
+{
+ SpatialAudioImpl *This = impl_from_IAudioFormatEnumerator(iface);
+ return SAC_QueryInterface(&This->ISpatialAudioClient_iface, riid, ppvObject);
+}
+
+static ULONG WINAPI SAOFE_AddRef(IAudioFormatEnumerator *iface)
+{
+ SpatialAudioImpl *This = impl_from_IAudioFormatEnumerator(iface);
+ return SAC_AddRef(&This->ISpatialAudioClient_iface);
+}
+
+static ULONG WINAPI SAOFE_Release(IAudioFormatEnumerator *iface)
+{
+ SpatialAudioImpl *This = impl_from_IAudioFormatEnumerator(iface);
+ return SAC_Release(&This->ISpatialAudioClient_iface);
+}
+
+static HRESULT WINAPI SAOFE_GetCount(IAudioFormatEnumerator *iface, UINT32 *count)
+{
+ SpatialAudioImpl *This = impl_from_IAudioFormatEnumerator(iface);
+
+ TRACE("(%p)->(%p)\n", This, count);
+
+ *count = 1;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI SAOFE_GetFormat(IAudioFormatEnumerator *iface,
+ UINT32 index, WAVEFORMATEX **format)
+{
+ SpatialAudioImpl *This = impl_from_IAudioFormatEnumerator(iface);
+
+ TRACE("(%p)->(%u, %p)\n", This, index, format);
+
+ if(index > 0)
+ return E_INVALIDARG;
+
+ *format = &This->object_fmtex.Format;
+
+ return S_OK;
+}
+
+static IAudioFormatEnumeratorVtbl IAudioFormatEnumerator_vtbl = {
+ SAOFE_QueryInterface,
+ SAOFE_AddRef,
+ SAOFE_Release,
+ SAOFE_GetCount,
+ SAOFE_GetFormat,
+};
+
+HRESULT SpatialAudioClient_Create(IMMDevice *mmdev, ISpatialAudioClient **out)
+{
+ SpatialAudioImpl *obj;
+ IAudioClient *aclient;
+ WAVEFORMATEX *closest;
+ HRESULT hr;
+
+ obj = heap_alloc_zero(sizeof(*obj));
+
+ obj->ref = 1;
+ obj->ISpatialAudioClient_iface.lpVtbl = &ISpatialAudioClient_vtbl;
+ obj->IAudioFormatEnumerator_iface.lpVtbl = &IAudioFormatEnumerator_vtbl;
+
+ obj->object_fmtex.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
+ obj->object_fmtex.Format.nChannels = 1;
+ obj->object_fmtex.Format.nSamplesPerSec = 48000;
+ obj->object_fmtex.Format.wBitsPerSample = sizeof(float) * 8;
+ obj->object_fmtex.Format.nBlockAlign = (obj->object_fmtex.Format.nChannels * obj->object_fmtex.Format.wBitsPerSample) / 8;
+ obj->object_fmtex.Format.nAvgBytesPerSec = obj->object_fmtex.Format.nSamplesPerSec * obj->object_fmtex.Format.nBlockAlign;
+ obj->object_fmtex.Format.cbSize = 0;
+
+ hr = IMMDevice_Activate(mmdev, &IID_IAudioClient,
+ CLSCTX_INPROC_SERVER, NULL, (void**)&aclient);
+ if(FAILED(hr)){
+ WARN("Activate failed: %08x\n", hr);
+ heap_free(obj);
+ return hr;
+ }
+
+ hr = IAudioClient_IsFormatSupported(aclient, AUDCLNT_SHAREMODE_SHARED, &obj->object_fmtex.Format, &closest);
+
+ IAudioClient_Release(aclient);
+
+ if(hr == S_FALSE){
+ if(sizeof(WAVEFORMATEX) + closest->cbSize > sizeof(obj->object_fmtex)){
+ ERR("Returned format too large: %s\n", debugstr_fmtex(closest));
+ CoTaskMemFree(closest);
+ heap_free(obj);
+ return AUDCLNT_E_UNSUPPORTED_FORMAT;
+ }else if(!((closest->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
+ (closest->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
+ IsEqualGUID(&((WAVEFORMATEXTENSIBLE *)closest)->SubFormat,
+ &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))) &&
+ closest->wBitsPerSample == 32)){
+ ERR("Returned format not 32-bit float: %s\n", debugstr_fmtex(closest));
+ CoTaskMemFree(closest);
+ heap_free(obj);
+ return AUDCLNT_E_UNSUPPORTED_FORMAT;
+ }
+ WARN("The audio stack doesn't support 48kHz 32bit float. Using the closest match. Audio may be glitchy. %s\n", debugstr_fmtex(closest));
+ memcpy(&obj->object_fmtex,
+ closest,
+ sizeof(WAVEFORMATEX) + closest->cbSize);
+ CoTaskMemFree(closest);
+ } else if(hr != S_OK){
+ WARN("Checking supported formats failed: %08x\n", hr);
+ heap_free(obj);
+ return hr;
+ }
+
+ obj->mmdev = mmdev;
+ IMMDevice_AddRef(mmdev);
+
+ *out = &obj->ISpatialAudioClient_iface;
+
+ return S_OK;
+}
diff --git a/include/spatialaudioclient.idl b/include/spatialaudioclient.idl
index 16a1541fd1d..08c84965566 100644
--- a/include/spatialaudioclient.idl
+++ b/include/spatialaudioclient.idl
@@ -43,6 +43,47 @@ typedef [v1_enum] enum AudioObjectType
AudioObjectType_BackCenter = 0x00020000,
} AudioObjectType;
+cpp_quote("#define SPTLAUDCLNT_E_DESTROYED AUDCLNT_ERR(0x100)")
+cpp_quote("#define SPTLAUDCLNT_E_OUT_OF_ORDER AUDCLNT_ERR(0x101)")
+cpp_quote("#define SPTLAUDCLNT_E_RESOURCES_INVALIDATED AUDCLNT_ERR(0x102)")
+cpp_quote("#define SPTLAUDCLNT_E_NO_MORE_OBJECTS AUDCLNT_ERR(0x103)")
+cpp_quote("#define SPTLAUDCLNT_E_PROPERTY_NOT_SUPPORTED AUDCLNT_ERR(0x104)")
+cpp_quote("#define SPTLAUDCLNT_E_ERRORS_IN_OBJECT_CALLS AUDCLNT_ERR(0x105)")
+cpp_quote("#define SPTLAUDCLNT_E_METADATA_FORMAT_NOT_SUPPORTED AUDCLNT_ERR(0x106)")
+cpp_quote("#define SPTLAUDCLNT_E_STREAM_NOT_AVAILABLE AUDCLNT_ERR(0x107)")
+cpp_quote("#define SPTLAUDCLNT_E_INVALID_LICENSE AUDCLNT_ERR(0x108)")
+cpp_quote("#define SPTLAUDCLNT_E_STREAM_NOT_STOPPED AUDCLNT_ERR(0x10a)")
+cpp_quote("#define SPTLAUDCLNT_E_STATIC_OBJECT_NOT_AVAILABLE AUDCLNT_ERR(0x10b)")
+cpp_quote("#define SPTLAUDCLNT_E_OBJECT_ALREADY_ACTIVE AUDCLNT_ERR(0x10c)")
+cpp_quote("#define SPTLAUDCLNT_E_INTERNAL AUDCLNT_ERR(0x10d)")
+
+interface ISpatialAudioObjectRenderStreamBase;
+
+[
+ object,
+ uuid(dddf83e6-68d7-4c70-883f-a1836afb4a50),
+ pointer_default(unique),
+ local
+]
+interface ISpatialAudioObjectRenderStreamNotify : IUnknown
+{
+ HRESULT OnAvailableDynamicObjectCountChange(
+ [in] ISpatialAudioObjectRenderStreamBase *stream,
+ [in] LONGLONG deadline,
+ [in] UINT32 object_count);
+}
+
+typedef struct tagSpatialAudioObjectRenderStreamActivationParams
+{
+ const WAVEFORMATEX *ObjectFormat;
+ AudioObjectType StaticObjectTypeMask;
+ UINT32 MinDynamicObjectCount;
+ UINT32 MaxDynamicObjectCount;
+ AUDIO_STREAM_CATEGORY Category;
+ HANDLE EventHandle;
+ ISpatialAudioObjectRenderStreamNotify *NotifyObject;
+} SpatialAudioObjectRenderStreamActivationParams;
+
[
object,
uuid(dcdaa858-895a-4a22-a5eb-67bda506096d),
@@ -98,3 +139,83 @@ interface ISpatialAudioClient : IUnknown
[in] REFIID riid,
[out, iid_is(riid)] void **stream);
}
+
+[
+ object,
+ uuid(cce0b8f2-8d4d-4efb-a8cf-3d6ecf1c30e0),
+ pointer_default(unique),
+ local
+]
+interface ISpatialAudioObjectBase : IUnknown
+{
+ HRESULT GetBuffer(
+ [out] BYTE **buffer,
+ [out] UINT32 *bytes);
+
+ HRESULT SetEndOfStream(
+ [in] UINT32 frames);
+
+ HRESULT IsActive(
+ [out] BOOL *active);
+
+ HRESULT GetAudioObjectType(
+ [out] AudioObjectType *type);
+}
+
+[
+ object,
+ uuid(dde28967-521b-46e5-8f00-bd6f2bc8ab1d),
+ pointer_default(unique),
+ local
+]
+interface ISpatialAudioObject : ISpatialAudioObjectBase
+{
+ HRESULT SetPosition(
+ [in] float x,
+ [in] float y,
+ [in] float z);
+
+ HRESULT SetVolume(
+ [in] float vol);
+}
+
+[
+ object,
+ uuid(feaaf403-c1d8-450d-aa05-e0ccee7502a8),
+ pointer_default(unique),
+ local
+]
+interface ISpatialAudioObjectRenderStreamBase : IUnknown
+{
+ HRESULT GetAvailableDynamicObjectCount(
+ [out] UINT32 *count);
+
+ HRESULT GetService(
+ [in] REFIID riid,
+ [out] void **service);
+
+ HRESULT Start();
+
+ HRESULT Stop();
+
+ HRESULT Reset();
+
+ HRESULT BeginUpdatingAudioObjects(
+ [out] UINT32 *count,
+ [out] UINT32 *frames);
+
+ HRESULT EndUpdatingAudioObjects();
+}
+
+[
+ object,
+ uuid(bab5f473-b423-477b-85f5-b5a332a04153),
+ pointer_default(unique),
+ local
+]
+interface ISpatialAudioObjectRenderStream : ISpatialAudioObjectRenderStreamBase
+{
+ HRESULT ActivateSpatialAudioObject(
+ [in] AudioObjectType type,
+ [out] ISpatialAudioObject **object);
+}
--
2.30.0
1
1
Feb. 4, 2021
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
Updating this patch with the suggested change, and adding a few more.
tools/widl/header.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/tools/widl/header.c b/tools/widl/header.c
index 63389440c94..e6394991317 100644
--- a/tools/widl/header.c
+++ b/tools/widl/header.c
@@ -1702,6 +1702,7 @@ static void write_runtimeclass(FILE *header, type_t *runtimeclass)
{
expr_t *contract = get_attrp(runtimeclass->attrs, ATTR_CONTRACT);
char *name, *c_name;
+ size_t i, len;
name = format_namespace(runtimeclass->namespace, "", ".", runtimeclass->name, NULL);
c_name = format_namespace(runtimeclass->namespace, "", "_", runtimeclass->name, NULL);
fprintf(header, "/*\n");
@@ -1710,6 +1711,14 @@ static void write_runtimeclass(FILE *header, type_t *runtimeclass)
if (contract) write_apicontract_guard_start(header, contract);
fprintf(header, "#ifndef RUNTIMECLASS_%s_DEFINED\n", c_name);
fprintf(header, "#define RUNTIMECLASS_%s_DEFINED\n", c_name);
+ fprintf(header, "#if defined(_MSC_VER) || defined(__MINGW32__)\n");
+ /* FIXME: MIDL generates extern const here but GCC warns if extern is initialized */
+ fprintf(header, "const DECLSPEC_SELECTANY WCHAR RuntimeClass_%s[] = L\"%s\";\n", c_name, name);
+ fprintf(header, "#else\n");
+ fprintf(header, "static const WCHAR RuntimeClass_%s[] = {", c_name);
+ for (i = 0, len = strlen(name); i < len; ++i) fprintf(header, "'%c',", name[i]);
+ fprintf(header, "0};\n");
+ fprintf(header, "#endif\n");
fprintf(header, "#endif /* RUNTIMECLASS_%s_DEFINED */\n", c_name);
free(c_name);
free(name);
--
2.30.0
2
13
Since quite some time I keep splitting/cleaning up/rebasing and fixing the 2 year old PowerPC64le
patchset from 2019 (done by Timothy Pearson): [1]
The goal is to have a winelib base for Hangover [2] on PowerPC64 and there's also interest in having
winelib for crosscompiling [3].
This rebase meanwhile matured, especially end of last year, and I hope it can get upstreamed now
that wine-6.0 is out and the patch flood after it calmed down a bit.
[1] https://github.com/madscientist159/wine/commits/master
[2] https://github.com/AndreRH/hangover
[3] https://wiki.raptorcs.com/wiki/Porting/Wine
4
27
[PATCH 1/2] dwrite: Change remaining traces to have consistent format.
by Nikolay Sivov Feb. 4, 2021
by Nikolay Sivov Feb. 4, 2021
Feb. 4, 2021
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/dwrite/analyzer.c | 50 +++++++++++++++++++-----------------
dlls/dwrite/font.c | 58 ++++++++++++++++++++----------------------
dlls/dwrite/layout.c | 4 +--
dlls/dwrite/main.c | 2 +-
dlls/dwrite/opentype.c | 2 +-
5 files changed, 58 insertions(+), 58 deletions(-)
diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c
index 8d573ed530d..f717bb47c80 100644
--- a/dlls/dwrite/analyzer.c
+++ b/dlls/dwrite/analyzer.c
@@ -820,7 +820,7 @@ static HRESULT analyze_linebreaks(const WCHAR *text, UINT32 count, DWRITE_LINE_B
static HRESULT WINAPI dwritetextanalyzer_QueryInterface(IDWriteTextAnalyzer2 *iface, REFIID riid, void **obj)
{
- TRACE("(%s %p)\n", debugstr_guid(riid), obj);
+ TRACE("%s, %p.\n", debugstr_guid(riid), obj);
if (IsEqualIID(riid, &IID_IDWriteTextAnalyzer2) ||
IsEqualIID(riid, &IID_IDWriteTextAnalyzer1) ||
@@ -894,7 +894,7 @@ static HRESULT WINAPI dwritetextanalyzer_AnalyzeScript(IDWriteTextAnalyzer2 *ifa
const WCHAR *text;
HRESULT hr;
- TRACE("(%p %u %u %p)\n", source, position, length, sink);
+ TRACE("%p, %u, %u, %p.\n", source, position, length, sink);
if (length == 0)
return S_OK;
@@ -919,7 +919,7 @@ static HRESULT WINAPI dwritetextanalyzer_AnalyzeBidi(IDWriteTextAnalyzer2 *iface
const WCHAR *text;
HRESULT hr;
- TRACE("(%p %u %u %p)\n", source, position, length, sink);
+ TRACE("%p, %u, %u, %p.\n", source, position, length, sink);
if (!length)
return S_OK;
@@ -990,7 +990,7 @@ static HRESULT WINAPI dwritetextanalyzer_AnalyzeLineBreakpoints(IDWriteTextAnaly
HRESULT hr;
UINT32 len;
- TRACE("(%p %u %u %p)\n", source, position, length, sink);
+ TRACE("%p, %u, %u, %p.\n", source, position, length, sink);
if (length == 0)
return S_OK;
@@ -1156,7 +1156,7 @@ static HRESULT WINAPI dwritetextanalyzer_GetGlyphs(IDWriteTextAnalyzer2 *iface,
WCHAR digits[NATIVE_DIGITS_LEN];
HRESULT hr;
- TRACE("(%s:%u %p %d %d %s %s %p %p %p %u %u %p %p %p %p %p)\n", debugstr_wn(text, length),
+ TRACE("%s:%u, %p, %d, %d, %s, %s, %p, %p, %p, %u, %u, %p, %p, %p, %p, %p.\n", debugstr_wn(text, length),
length, fontface, is_sideways, is_rtl, debugstr_sa_script(analysis->script), debugstr_w(locale), substitution,
features, feature_range_lengths, feature_ranges, max_glyph_count, clustermap, text_props, glyphs,
glyph_props, actual_glyph_count);
@@ -1512,7 +1512,7 @@ static HRESULT WINAPI dwritetextanalyzer1_ApplyCharacterSpacing(IDWriteTextAnaly
{
unsigned int i;
- TRACE("(%.2f %.2f %.2f %u %u %p %p %p %p %p %p)\n", leading_spacing, trailing_spacing, min_advance_width,
+ TRACE("%.2f, %.2f, %.2f, %u, %u, %p, %p, %p, %p, %p, %p.\n", leading_spacing, trailing_spacing, min_advance_width,
len, glyph_count, clustermap, advances, offsets, props, modified_advances, modified_offsets);
if (min_advance_width < 0.0f) {
@@ -1607,14 +1607,15 @@ static HRESULT WINAPI dwritetextanalyzer1_AnalyzeVerticalGlyphOrientation(IDWrit
static HRESULT WINAPI dwritetextanalyzer1_GetGlyphOrientationTransform(IDWriteTextAnalyzer2 *iface,
DWRITE_GLYPH_ORIENTATION_ANGLE angle, BOOL is_sideways, DWRITE_MATRIX *transform)
{
- TRACE("(%d %d %p)\n", angle, is_sideways, transform);
+ TRACE("%d, %d, %p.\n", angle, is_sideways, transform);
+
return IDWriteTextAnalyzer2_GetGlyphOrientationTransform(iface, angle, is_sideways, 0.0, 0.0, transform);
}
static HRESULT WINAPI dwritetextanalyzer1_GetScriptProperties(IDWriteTextAnalyzer2 *iface, DWRITE_SCRIPT_ANALYSIS sa,
DWRITE_SCRIPT_PROPERTIES *props)
{
- TRACE("(%u %p)\n", sa.script, props);
+ TRACE("%u, %p.\n", sa.script, props);
if (sa.script > Script_LastId)
return E_INVALIDARG;
@@ -1641,7 +1642,7 @@ static HRESULT WINAPI dwritetextanalyzer1_GetTextComplexity(IDWriteTextAnalyzer2
HRESULT hr = S_OK;
int i;
- TRACE("(%s:%u %p %p %p %p)\n", debugstr_wn(text, len), len, face, is_simple, len_read, indices);
+ TRACE("%s:%u, %p, %p, %p, %p.\n", debugstr_wn(text, len), len, face, is_simple, len_read, indices);
*is_simple = FALSE;
*len_read = 0;
@@ -1723,7 +1724,7 @@ static HRESULT WINAPI dwritetextanalyzer2_GetGlyphOrientationTransform(IDWriteTe
{ 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f }
};
- TRACE("(%d %d %.2f %.2f %p)\n", angle, is_sideways, originX, originY, m);
+ TRACE("%d, %d, %.2f, %.2f, %p.\n", angle, is_sideways, originX, originY, m);
if ((UINT32)angle > DWRITE_GLYPH_ORIENTATION_ANGLE_270_DEGREES) {
memset(m, 0, sizeof(*m));
@@ -1850,9 +1851,7 @@ IDWriteTextAnalyzer *get_text_analyzer(void)
static HRESULT WINAPI dwritenumbersubstitution_QueryInterface(IDWriteNumberSubstitution *iface, REFIID riid, void **obj)
{
- struct dwrite_numbersubstitution *This = impl_from_IDWriteNumberSubstitution(iface);
-
- TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
if (IsEqualIID(riid, &IID_IDWriteNumberSubstitution) ||
IsEqualIID(riid, &IID_IUnknown))
@@ -1871,25 +1870,28 @@ static HRESULT WINAPI dwritenumbersubstitution_QueryInterface(IDWriteNumberSubst
static ULONG WINAPI dwritenumbersubstitution_AddRef(IDWriteNumberSubstitution *iface)
{
- struct dwrite_numbersubstitution *This = impl_from_IDWriteNumberSubstitution(iface);
- ULONG ref = InterlockedIncrement(&This->ref);
- TRACE("(%p)->(%d)\n", This, ref);
- return ref;
+ struct dwrite_numbersubstitution *object = impl_from_IDWriteNumberSubstitution(iface);
+ ULONG refcount = InterlockedIncrement(&object->ref);
+
+ TRACE("%p, refcount %d.\n", iface, refcount);
+
+ return refcount;
}
static ULONG WINAPI dwritenumbersubstitution_Release(IDWriteNumberSubstitution *iface)
{
- struct dwrite_numbersubstitution *This = impl_from_IDWriteNumberSubstitution(iface);
- ULONG ref = InterlockedDecrement(&This->ref);
+ struct dwrite_numbersubstitution *object = impl_from_IDWriteNumberSubstitution(iface);
+ ULONG refcount = InterlockedDecrement(&object->ref);
- TRACE("(%p)->(%d)\n", This, ref);
+ TRACE("%p, refcount %d.\n", iface, refcount);
- if (!ref) {
- heap_free(This->locale);
- heap_free(This);
+ if (!refcount)
+ {
+ heap_free(object->locale);
+ heap_free(object);
}
- return ref;
+ return refcount;
}
static const IDWriteNumberSubstitutionVtbl numbersubstitutionvtbl =
diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c
index f1db6dd732b..e22e4abf271 100644
--- a/dlls/dwrite/font.c
+++ b/dlls/dwrite/font.c
@@ -6662,9 +6662,7 @@ HRESULT create_fontfacereference(IDWriteFactory7 *factory, IDWriteFontFile *file
static HRESULT WINAPI inmemoryfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
{
- struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
-
- TRACE_(dwrite_file)("(%p)->(%s, %p)\n", stream, debugstr_guid(riid), obj);
+ TRACE_(dwrite_file)("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
if (IsEqualIID(riid, &IID_IDWriteFontFileStream) || IsEqualIID(riid, &IID_IUnknown)) {
*obj = iface;
@@ -6681,24 +6679,27 @@ static HRESULT WINAPI inmemoryfilestream_QueryInterface(IDWriteFontFileStream *i
static ULONG WINAPI inmemoryfilestream_AddRef(IDWriteFontFileStream *iface)
{
struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
- ULONG ref = InterlockedIncrement(&stream->ref);
- TRACE_(dwrite_file)("(%p)->(%u)\n", stream, ref);
- return ref;
+ ULONG refcount = InterlockedIncrement(&stream->ref);
+
+ TRACE_(dwrite_file)("%p, refcount %u.\n", iface, refcount);
+
+ return refcount;
}
static ULONG WINAPI inmemoryfilestream_Release(IDWriteFontFileStream *iface)
{
struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
- ULONG ref = InterlockedDecrement(&stream->ref);
+ ULONG refcount = InterlockedDecrement(&stream->ref);
- TRACE_(dwrite_file)("(%p)->(%u)\n", stream, ref);
+ TRACE_(dwrite_file)("%p, refcount %u.\n", iface, refcount);
- if (!ref) {
+ if (!refcount)
+ {
release_inmemory_stream(stream->data);
heap_free(stream);
}
- return ref;
+ return refcount;
}
static HRESULT WINAPI inmemoryfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
@@ -6706,7 +6707,7 @@ static HRESULT WINAPI inmemoryfilestream_ReadFileFragment(IDWriteFontFileStream
{
struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
- TRACE_(dwrite_file)("(%p)->(%p, 0x%s, 0x%s, %p)\n", stream, fragment_start,
+ TRACE_(dwrite_file)("%p, %p, 0x%s, 0x%s, %p.\n", iface, fragment_start,
wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
*fragment_context = NULL;
@@ -6722,16 +6723,14 @@ static HRESULT WINAPI inmemoryfilestream_ReadFileFragment(IDWriteFontFileStream
static void WINAPI inmemoryfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
{
- struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
-
- TRACE_(dwrite_file)("(%p)->(%p)\n", stream, fragment_context);
+ TRACE_(dwrite_file)("%p, %p.\n", iface, fragment_context);
}
static HRESULT WINAPI inmemoryfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
{
struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
- TRACE_(dwrite_file)("(%p)->(%p)\n", stream, size);
+ TRACE_(dwrite_file)("%p, %p.\n", iface, size);
*size = stream->data->size;
@@ -6740,9 +6739,7 @@ static HRESULT WINAPI inmemoryfilestream_GetFileSize(IDWriteFontFileStream *ifac
static HRESULT WINAPI inmemoryfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
{
- struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
-
- TRACE_(dwrite_file)("(%p)->(%p)\n", stream, last_writetime);
+ TRACE_(dwrite_file)("%p, %p.\n", iface, last_writetime);
*last_writetime = 0;
@@ -6762,9 +6759,7 @@ static const IDWriteFontFileStreamVtbl inmemoryfilestreamvtbl = {
static HRESULT WINAPI inmemoryfontfileloader_QueryInterface(IDWriteInMemoryFontFileLoader *iface,
REFIID riid, void **obj)
{
- struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
-
- TRACE("(%p)->(%s, %p)\n", loader, debugstr_guid(riid), obj);
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
if (IsEqualIID(riid, &IID_IDWriteInMemoryFontFileLoader) ||
IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
@@ -6785,27 +6780,30 @@ static HRESULT WINAPI inmemoryfontfileloader_QueryInterface(IDWriteInMemoryFontF
static ULONG WINAPI inmemoryfontfileloader_AddRef(IDWriteInMemoryFontFileLoader *iface)
{
struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
- ULONG ref = InterlockedIncrement(&loader->ref);
- TRACE("(%p)->(%u)\n", loader, ref);
- return ref;
+ ULONG refcount = InterlockedIncrement(&loader->ref);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ return refcount;
}
static ULONG WINAPI inmemoryfontfileloader_Release(IDWriteInMemoryFontFileLoader *iface)
{
struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
- ULONG ref = InterlockedDecrement(&loader->ref);
+ ULONG refcount = InterlockedDecrement(&loader->ref);
size_t i;
- TRACE("(%p)->(%u)\n", loader, ref);
+ TRACE("%p, refcount %u.\n", iface, refcount);
- if (!ref) {
+ if (!refcount)
+ {
for (i = 0; i < loader->count; ++i)
release_inmemory_stream(loader->streams[i]);
heap_free(loader->streams);
heap_free(loader);
}
- return ref;
+ return refcount;
}
static HRESULT WINAPI inmemoryfontfileloader_CreateStreamFromKey(IDWriteInMemoryFontFileLoader *iface,
@@ -6815,7 +6813,7 @@ static HRESULT WINAPI inmemoryfontfileloader_CreateStreamFromKey(IDWriteInMemory
struct dwrite_inmemory_filestream *stream;
DWORD index;
- TRACE("(%p)->(%p, %u, %p)\n", loader, key, key_size, ret);
+ TRACE("%p, %p, %u, %p.\n", iface, key, key_size, ret);
*ret = NULL;
@@ -6847,7 +6845,7 @@ static HRESULT WINAPI inmemoryfontfileloader_CreateInMemoryFontFileReference(IDW
struct dwrite_inmemory_stream_data *stream;
DWORD key;
- TRACE("(%p)->(%p, %p, %u, %p, %p)\n", loader, factory, data, data_size, owner, fontfile);
+ TRACE("%p, %p, %p, %u, %p, %p.\n", iface, factory, data, data_size, owner, fontfile);
*fontfile = NULL;
diff --git a/dlls/dwrite/layout.c b/dlls/dwrite/layout.c
index 0b5bad80339..b68daf0345b 100644
--- a/dlls/dwrite/layout.c
+++ b/dlls/dwrite/layout.c
@@ -4935,7 +4935,7 @@ static HRESULT WINAPI dwritetextlayout_source_GetTextAtPosition(IDWriteTextAnaly
{
struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
- TRACE("(%p)->(%u %p %p)\n", layout, position, text, text_len);
+ TRACE("%p, %u, %p, %p.\n", iface, position, text, text_len);
if (position < layout->len) {
*text = &layout->str[position];
@@ -4954,7 +4954,7 @@ static HRESULT WINAPI dwritetextlayout_source_GetTextBeforePosition(IDWriteTextA
{
struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
- TRACE("(%p)->(%u %p %p)\n", layout, position, text, text_len);
+ TRACE("%p, %u, %p, %p.\n", iface, position, text, text_len);
if (position > 0 && position < layout->len) {
*text = layout->str;
diff --git a/dlls/dwrite/main.c b/dlls/dwrite/main.c
index f550c204b6d..40c82b6cd05 100644
--- a/dlls/dwrite/main.c
+++ b/dlls/dwrite/main.c
@@ -1931,7 +1931,7 @@ HRESULT WINAPI DWriteCreateFactory(DWRITE_FACTORY_TYPE type, REFIID riid, IUnkno
struct dwritefactory *factory;
HRESULT hr;
- TRACE("(%d, %s, %p)\n", type, debugstr_guid(riid), ret);
+ TRACE("%d, %s, %p.\n", type, debugstr_guid(riid), ret);
*ret = NULL;
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c
index ae9a88a876c..0e5b8c75f62 100644
--- a/dlls/dwrite/opentype.c
+++ b/dlls/dwrite/opentype.c
@@ -2159,7 +2159,7 @@ void opentype_get_font_properties(struct file_stream_desc *stream_desc, struct d
IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, colr.context);
}
- TRACE("stretch=%d, weight=%d, style %d\n", props->stretch, props->weight, props->style);
+ TRACE("stretch %d, weight %d, style %d\n", props->stretch, props->weight, props->style);
if (os2.data)
IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, os2.context);
--
2.30.0
1
1
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mfplat/tests/mfplat.c | 36 +++++++++++++++++++++---------------
1 file changed, 21 insertions(+), 15 deletions(-)
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c
index deb9e78efba..0464293b37f 100644
--- a/dlls/mfplat/tests/mfplat.c
+++ b/dlls/mfplat/tests/mfplat.c
@@ -136,6 +136,7 @@ static DXGI_FORMAT (WINAPI *pMFMapDX9FormatToDXGIFormat)(DWORD format);
static HRESULT (WINAPI *pMFCreateVideoSampleAllocatorEx)(REFIID riid, void **allocator);
static HRESULT (WINAPI *pMFCreateDXGISurfaceBuffer)(REFIID riid, IUnknown *surface, UINT subresource, BOOL bottomup,
IMFMediaBuffer **buffer);
+static HRESULT (WINAPI *pMFCreateVideoMediaTypeFromSubtype)(const GUID *subtype, IMFVideoMediaType **media_type);
static HWND create_window(void)
{
@@ -799,6 +800,7 @@ static void init_functions(void)
X(MFCreateMFByteStreamOnStream);
X(MFCreateTrackedSample);
X(MFCreateTransformActivate);
+ X(MFCreateVideoMediaTypeFromSubtype);
X(MFCreateVideoSampleAllocatorEx);
X(MFGetPlaneSize);
X(MFGetStrideForBitmapInfoHeader);
@@ -965,28 +967,32 @@ if(0)
IUnknown_Release(unk2);
IUnknown_Release(unk);
+ IMFMediaType_Release(mediatype);
- hr = MFCreateVideoMediaTypeFromSubtype(&MFVideoFormat_RGB555, &video_type);
- ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
-
- check_interface(video_type, &IID_IMFMediaType, TRUE);
- check_interface(video_type, &IID_IMFVideoMediaType, TRUE);
+ if (pMFCreateVideoMediaTypeFromSubtype)
+ {
+ hr = pMFCreateVideoMediaTypeFromSubtype(&MFVideoFormat_RGB555, &video_type);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
- /* Major and subtype are set on creation. */
- hr = IMFVideoMediaType_GetCount(video_type, &count);
- ok(count == 2, "Unexpected attribute count %#x.\n", hr);
+ check_interface(video_type, &IID_IMFMediaType, TRUE);
+ check_interface(video_type, &IID_IMFVideoMediaType, TRUE);
- hr = IMFVideoMediaType_DeleteAllItems(video_type);
- ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ /* Major and subtype are set on creation. */
+ hr = IMFVideoMediaType_GetCount(video_type, &count);
+ ok(count == 2, "Unexpected attribute count %#x.\n", hr);
- hr = IMFVideoMediaType_GetCount(video_type, &count);
- ok(!count, "Unexpected attribute count %#x.\n", hr);
+ hr = IMFVideoMediaType_DeleteAllItems(video_type);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
- check_interface(video_type, &IID_IMFVideoMediaType, FALSE);
+ hr = IMFVideoMediaType_GetCount(video_type, &count);
+ ok(!count, "Unexpected attribute count %#x.\n", hr);
- IMFVideoMediaType_Release(video_type);
+ check_interface(video_type, &IID_IMFVideoMediaType, FALSE);
- IMFMediaType_Release(mediatype);
+ IMFVideoMediaType_Release(video_type);
+ }
+ else
+ win_skip("MFCreateVideoMediaTypeFromSubtype() is not available.\n");
/* IMFAudioMediaType */
hr = MFCreateMediaType(&mediatype);
--
2.30.0
1
0
Signed-off-by: Byeongsik Jeon <bsjeon(a)hanmail.net>
---
po/ko.po | 252 +++++++++++++++++++++++++++----------------------------
1 file changed, 126 insertions(+), 126 deletions(-)
diff --git a/po/ko.po b/po/ko.po
index 40962ead745..8cc8c6d5099 100644
--- a/po/ko.po
+++ b/po/ko.po
@@ -5,7 +5,7 @@ msgstr ""
"Project-Id-Version: Wine\n"
"Report-Msgid-Bugs-To: https://bugs.winehq.org\n"
"POT-Creation-Date: N/A\n"
-"PO-Revision-Date: 2020-12-29 16:25+0900\n"
+"PO-Revision-Date: 2021-02-04 15:08+0900\n"
"Last-Translator: Byeongsik Jeon <bsjeon(a)hanmail.net>\n"
"Language-Team: Korean\n"
"Language: ko\n"
@@ -6709,7 +6709,7 @@ msgstr "RPC 호출이 취소되었습니다.\n"
#: dlls/kernel32/winerror.mc:3508
msgid "Binding incomplete.\n"
-msgstr "Binding incomplete.\n"
+msgstr "바인딩이 완료되지 않았습니다.\n"
#: dlls/kernel32/winerror.mc:3513
msgid "RPC comm failure.\n"
@@ -7807,7 +7807,7 @@ msgstr "서비스: [1]"
#: dlls/msi/msi.rc:167 dlls/msi/msi.rc:170 dlls/msi/msi.rc:174
msgid "File: [1], Directory: [9], Size: [6]"
-msgstr "파일: [1], 디렉터리: [9], 크기: [6]"
+msgstr "파일: [1], 디렉터리: [9], 크기: [6]"
#: dlls/msi/msi.rc:168
msgid "Found application: [1]"
@@ -7823,7 +7823,7 @@ msgstr "서비스: [2]"
#: dlls/msi/msi.rc:172
msgid "File: [1], Dependencies: [2]"
-msgstr "파일: [1], 종속성: [2]"
+msgstr "파일: [1], 종속성: [2]"
#: dlls/msi/msi.rc:173
msgid "Application: [1]"
@@ -7835,7 +7835,7 @@ msgstr "프로그램 컨텍스트: [1], 어셈블리 이름 : [2]"
#: dlls/msi/msi.rc:177
msgid "File: [1], Directory: [2], Size: [3]"
-msgstr "파일: [1], 디렉터리: [2], 크기: [3]"
+msgstr "파일: [1], 디렉터리: [2], 크기: [3]"
#: dlls/msi/msi.rc:178 dlls/msi/msi.rc:199
msgid "Component ID: [1], Qualifier: [2]"
@@ -7887,7 +7887,7 @@ msgstr "프로그램: [1], 명령줄: [2]"
#: dlls/msi/msi.rc:192 dlls/msi/msi.rc:209
msgid "File: [1], Section: [2], Key: [3], Value: [4]"
-msgstr "파일: [1], 부분: [2], 키: [3], 값: [4]"
+msgstr "파일: [1], 부분: [2], 키: [3], 값: [4]"
#: dlls/msi/msi.rc:193
msgid "Key: [1], Name: [2]"
@@ -9156,7 +9156,7 @@ msgstr "오른쪽으로 스크롤"
#: dlls/shdoclc/shdoclc.rc:28
msgid "Wine Internet Explorer"
-msgstr "Wine 인터넷 익스폴로어"
+msgstr "Wine 인터넷 익스플로러"
#: dlls/shdoclc/shdoclc.rc:33
msgid "&w&bPage &p"
@@ -11728,7 +11728,7 @@ msgstr "기밀성이 요구됩니다"
#: dlls/wldap32/wldap32.rc:46
msgid "SASL Bind in Progress"
-msgstr "SASL 바인딩 진행 중"
+msgstr "SASL 바인딩 중입니다"
#: dlls/wldap32/wldap32.rc:48
msgid "No Such Attribute"
@@ -11752,7 +11752,7 @@ msgstr "특성 또는 값이 있습니다"
#: dlls/wldap32/wldap32.rc:53
msgid "Invalid Syntax"
-msgstr "잘못된 구문"
+msgstr "잘못된 구문입니다"
#: dlls/wldap32/wldap32.rc:64
msgid "No Such Object"
@@ -11768,7 +11768,7 @@ msgstr "잘못된 DN 구문입니다"
#: dlls/wldap32/wldap32.rc:67
msgid "Is Leaf"
-msgstr "잎 노드임"
+msgstr "잎 노드입니다"
#: dlls/wldap32/wldap32.rc:68
msgid "Alias Dereference Problem"
@@ -11788,11 +11788,11 @@ msgstr "권한이 부족합니다"
#: dlls/wldap32/wldap32.rc:83
msgid "Busy"
-msgstr "바쁨"
+msgstr "사용 중입니다"
#: dlls/wldap32/wldap32.rc:84
msgid "Unavailable"
-msgstr "사용할 수 없음"
+msgstr "사용할 수 없습니다"
#: dlls/wldap32/wldap32.rc:85
msgid "Unwilling To Perform"
@@ -11920,7 +11920,7 @@ msgstr ""
#: programs/attrib/attrib.rc:31 programs/cmd/cmd.rc:376
msgid "%1: File Not Found\n"
-msgstr "%1:파일을 찾을 수 없습니다\n"
+msgstr "%1: 파일을 찾을 수 없습니다\n"
#: programs/attrib/attrib.rc:50
msgid ""
@@ -11943,24 +11943,25 @@ msgid ""
" /S Processes matching files in the current folder and all subfolders.\n"
" /D Processes folders as well.\n"
msgstr ""
-"ATTRIB - 파일 속성을 바꾸거나 표시합니다.\n"
+"ATTRIB - 파일 특성을 화면에 표시하거나 변경합니다.\n"
"\n"
-"문법:\n"
-"ATTRIB [+R | -R] [+A | -A ] [+S | -S] [+H | -H] [drive:][path][filename]\n"
+"구문:\n"
+"ATTRIB [+R | -R] [+A | -A ] [+S | -S] [+H | -H] [드라이브:][경로][파일 이"
+"름]\n"
" [/S [/D]]\n"
"\n"
"옵션:\n"
"\n"
-" + 속성을 설정합니다.\n"
-" - 속성을 제거합니다.\n"
-" R 읽기 전용 속성를 설정합니다.\n"
-" A 압축 파일 속성을 설정합니다.\n"
-" S 시스템 파일 속성을 설정합니다.\n"
-" H 숨은 파일 속성을 설정합니다.\n"
-" [drive:][path][filename]\n"
-" 속성 작업을 할 하나 또는 복수의 파일을 지정합니다.\n"
+" + 특성을 설정합니다.\n"
+" - 특성을 지웁니다.\n"
+" R 읽기 전용 파일 특성을 설정합니다.\n"
+" A 보관 파일 특성을 설정합니다.\n"
+" S 시스템 파일 특성을 설정합니다.\n"
+" H 숨김 파일 특성을 설정합니다.\n"
+" [드라이브:][경로][파일 이름]\n"
+" ATTRIB 명령을 수행할 파일을 지정합니다.\n"
" /S 현재 폴더와 모든 하위 폴더에서 일치하는 파일을 처리합니다.\n"
-" /D 폴더를 함께 처리합니다.\n"
+" /D 폴더를 처리합니다.\n"
#: programs/clock/clock.rc:32
msgid "Ana&log"
@@ -12011,13 +12012,13 @@ msgid ""
"Changes to default directory, environment variables etc made within a\n"
"called procedure are inherited by the caller.\n"
msgstr ""
-"<배치파일 이름>을 호출하는 것은 배치 파일 안에서 다른 배치 파일의\n"
-"명령을 실행하는 것입니다. 배치 파일이 끝나면, 제어권은 배치 파일을\n"
-"호출한 배치 파일로 돌아갑니다.\n"
-"CALL 명령은 매개변수를 지원합니다.\n"
+"CALL <배치파일 이름>은 배치 파일 내에서 다른 배치 파일의 명령을\n"
+"실행하는 데 사용됩니다. 배치 파일이 끝나면 제어권은 배치 파일을\n"
+"호출한 배치 파일로 돌아갑니다. CALL 명령은 호출된 프로시저에\n"
+"매개변수를 제공할 수 있습니다.\n"
"\n"
-"호출된 프로시저 안에서 기본 디렉터리, 환경 변수 등을 바꾸는 것은\n"
-"호출자에게 상속됩니다.\n"
+"호출된 프로시저 내에서 작성된 기본 디렉터리, 환경 변수 등의\n"
+"변경사항은 발신자가 상속합니다.\n"
#: programs/cmd/cmd.rc:44
msgid ""
@@ -12025,15 +12026,15 @@ msgid ""
"default directory.\n"
msgstr ""
"CD <디렉터리> 는 CHDIR의 단축 버전입니다.\n"
-"현재 작업 디렉터리를 바꿉니다.\n"
+"현재 기본 디렉터리를 바꿉니다.\n"
#: programs/cmd/cmd.rc:47
msgid "CHDIR <directory> changes the current default directory.\n"
-msgstr "CHDIR <디렉터리> 는 현재 작업 디렉터리를 바꿉니다.\n"
+msgstr "CHDIR <디렉터리> 는 현재 기본 디렉터리를 바꿉니다.\n"
#: programs/cmd/cmd.rc:50
msgid "CLS clears the console screen.\n"
-msgstr "CLS는 콘솔 화면을 깨끗하게 합니다.\n"
+msgstr "CLS는 콘솔 화면을 지웁니다.\n"
#: programs/cmd/cmd.rc:53
msgid "COPY <filename> copies a file.\n"
@@ -12049,7 +12050,7 @@ msgstr "DATE는 시스템 날짜를 보여주거나 바꿉니다.\n"
#: programs/cmd/cmd.rc:62
msgid "DEL <filename> deletes a file or set of files.\n"
-msgstr "DEL <파일 이름>은 하나의 파일이나 여러 파일을 지웁니다.\n"
+msgstr "DEL <파일 이름>은 하나 또는 여러개의 파일을 지웁니다.\n"
#: programs/cmd/cmd.rc:65
msgid "DIR lists the contents of a directory.\n"
@@ -12068,16 +12069,17 @@ msgid ""
msgstr ""
"ECHO <문자열>은 <문자열>을 현재 터미널 장치에 표시합니다.\n"
"\n"
-"ECHO ON는 배치파일 안의 모든 이후 명령어를 터미널 장치에 실행하기 전에\n"
-"표시합니다.\n"
+"ECHO ON는 배치파일 안의 모든 이후 명령어가 실행 전에 터미널 장치에\n"
+"표시되도록 합니다.\n"
"\n"
"ECHO OFF는 ECHO ON과 반대 효과가 있습니다(기본값은 ECHO OFF입니다).\n"
-"ECHO OFF 명령은 @ 부호처럼 처리 중 명령어가 표시되는 것을 막습니다\n"
-"(@ 부호가 첫번째 문자인 라인은 ECHO OFF인 효과가 있습니다).\n"
+"ECHO OFF 앞에 @ 기호룰 두어서 ECHO OFF 명령어 자체가 화면에\n"
+"표시되는 것을 막을 수 있습니다.\n"
+"\n"
#: programs/cmd/cmd.rc:78
msgid "ERASE <filename> deletes a file or set of files.\n"
-msgstr "ERASE <파일 이름>은 하나의 파일이냐 여러 파일을 지웁니다.\n"
+msgstr "ERASE <파일 이름>은 하나 이상의 파일을 지웁니다.\n"
#: programs/cmd/cmd.rc:85
msgid ""
@@ -12087,11 +12089,11 @@ msgid ""
"\n"
"The % sign must be doubled when using FOR in a batch file.\n"
msgstr ""
-"FOR는 파일 집합에 포함된 각각의 파일에 대해 명령어를 실행할 때 쓰입니다.\n"
+"FOR는 파일 모음에 포함된 각각의 파일에 대해 명령어를 실행할 때 쓰입니다.\n"
"\n"
-"사용법: FOR %변수 IN (set) DO 명령\n"
+"사용법: FOR %변수 IN (파일 모음) DO 명령\n"
"\n"
-"% 부호는 배치 파일 안에서 FOR를 사용할 때는 중첩(%%)되어야 합니다.\n"
+"배치 파일 안에서 FOR를 사용할 때는 '%변수' 대신 '%%변수'를 사용해야 합니다.\n"
#: programs/cmd/cmd.rc:97
msgid ""
@@ -12109,10 +12111,10 @@ msgstr ""
"GOTO 명령은 배치 파일 안에서 다른 구문으로 실행을\n"
"전환합니다.\n"
"\n"
-"GOTO의 타겟인 레이블은 255자까지 가능합니다만, 공백은 포함하지 않을 수도\n"
-"있습니다(운영체제에 따라서 다를 수도 있습니다).\n"
-"만약 배치 파일 안에 2개나 그 이상의 동일한 레이블이 존재할 경우 첫번째\n"
-"것이 실행됩니다. 파일에 없는 레이블로 GOTO를 시도한다면 배치파일 실행은\n"
+"GOTO의 타겟인 레이블은 255자까지 가능합니다. 단, 공백은 포함하지 않을\n"
+"수도 있습니다 (운영 체제에 따라서 다를 수도 있습니다). 만약 배치 파일\n"
+"안에 둘 이상의 동일한 레이블이 존재할 경우 항상 첫 번째 레이블이\n"
+"실행됩니다. GOTO를 시도하려는 레이블이 없다면 배치 파일 실행은\n"
"중단됩니다.\n"
"\n"
"GOTO는 대화식으로 사용할 경우 어떤 효과도 없습니다.\n"
@@ -12122,8 +12124,8 @@ msgid ""
"HELP <command> shows brief help details on a topic.\n"
"HELP without an argument shows all CMD built-in commands.\n"
msgstr ""
-"HELP <명령>은 주제의 간단한 도움말 정보를 보여줍니 다.\n"
-"아무 매개변수가 없는 HELP눈 CMD의 모든 내장 명령을 표시합니다.\n"
+"HELP <명령어>은 해당 명령어에 대한 간단한 도움말을 보여줍니다.\n"
+"매개 변수 없이 HELP를 실행하면 모든 CMD 내장 명령을 표시합니다.\n"
#: programs/cmd/cmd.rc:111
msgid ""
@@ -12136,14 +12138,14 @@ msgid ""
"In the second form of the command, string1 and string2 must be in double\n"
"quotes. The comparison is not case-sensitive.\n"
msgstr ""
-"IF는 명령을 선택적으로 실행 할 때 사용한다.\n"
+"IF는 명령을 조건부로 실행하는 데 사용됩니다.\n"
"\n"
-"문법: IF [NOT] EXIST 파일 이름 명령\n"
-" IF [NOT] string1==string2 명령\n"
-" IF [NOT] ERRORLEVEL 숫자 명령\n"
+"구문: IF [NOT] EXIST 파일_이름 명령어\n"
+" IF [NOT] 문자열1==문자열2 명령어\n"
+" IF [NOT] ERRORLEVEL 숫자 명령어\n"
"\n"
-"명령의 두번째 형식에서, string1과 string2는 반드시 2개의 따옴표로\n"
-"둘려놓아야 합니다.이 비교는 대소문자를 구분하지 않습니다.\n"
+"명령어의 두번째 형식에서, 문자열1과 문자열2는 반드시 2개의 따옴표로\n"
+"둘러싸야 합니다. 대소문자를 구분하지 않고 비교합니다.\n"
#: programs/cmd/cmd.rc:118
msgid ""
@@ -12162,11 +12164,11 @@ msgstr ""
#: programs/cmd/cmd.rc:121
msgid "MD <name> is the short version of MKDIR. It creates a subdirectory.\n"
msgstr ""
-"MD <아름> 운 MKDIR의 단축 버전입니다. 이것은 하위 디렉터리를 만듭니다 .\n"
+"MD <이름>은 MKDIR의 단축 버전입니다. 서브디렉터리를 만듭니다.\n"
#: programs/cmd/cmd.rc:123
msgid "MKDIR <name> creates a subdirectory.\n"
-msgstr "MKDIR <명령> 운 하위 디렉터리를 만듭니다.\n"
+msgstr "MKDIR <이름>은 서브디렉터리를 만듭니다.\n"
#: programs/cmd/cmd.rc:131
msgid ""
@@ -12182,8 +12184,7 @@ msgstr ""
"만약 옮겨지는 항목이 하나의 디렉터리라면 디렉터리 아래 모든 파일과\n"
"서브디렉터리도 이동합니다.\n"
"\n"
-"MOVE는 원본과 대상의 위치가 다른 DOS 드라이브 문자를 가지고 있다면 실패합니"
-"다.\n"
+"MOVE는 원본과 대상이 다른 DOS 드라이브에 위치하면 실패합니다.\n"
#: programs/cmd/cmd.rc:142
msgid ""
@@ -12271,21 +12272,19 @@ msgstr ""
#: programs/cmd/cmd.rc:176
msgid "REN <filename> is the short version of RENAME. It renames a file.\n"
-msgstr ""
-"REN <파일 이름> 은 REANME의 단축 버전입니다.이것은 파일 이름을 바꿉니다.\n"
+msgstr "REN <파일 이름>은 REANME의 단축 버전입니다. 파일 이름을 바꿉니다.\n"
#: programs/cmd/cmd.rc:178
msgid "RENAME <filename> renames a file.\n"
-msgstr "RENAME <파일 이름> 은 파일의 이름을 바꿈.\n"
+msgstr "RENAME <파일 이름>은 파일 이름을 바꿈니다.\n"
#: programs/cmd/cmd.rc:181
msgid "RD <directory> is the short version of RMDIR. It deletes a directory.\n"
-msgstr ""
-"RD <디렉터리> 는 RMDIR의 단축 버전입니다. 이것은 디렉터리를 제거합니다.\n"
+msgstr "RD <디렉터리>는 RMDIR의 단축 버전입니다. 디렉터리를 지웁니다.\n"
#: programs/cmd/cmd.rc:183
msgid "RMDIR <directory> deletes a directory.\n"
-msgstr "RMDIR <디렉터리>는 디렉터리를 제거합니다.\n"
+msgstr "RMDIR <디렉터리>는 디렉터리를 지웁니다.\n"
#: programs/cmd/cmd.rc:229
msgid ""
@@ -12309,7 +12308,7 @@ msgstr ""
"\n"
"매개변수가 없는 SET은 현재 환경변수를 모두 표시합니다.\n"
"\n"
-"환경 변수를 만들거나 수정할 때 사용하는 문법:\n"
+"환경 변수를 만들거나 수정할 때 사용하는 구문:\n"
"\n"
"SET <변수>=<값>\n"
"\n"
@@ -12364,8 +12363,8 @@ msgstr ""
"프로그램을 시작하거나, 파일 확장자와 연관된 프로그램으로\n"
"문서를 엽니다.\n"
"사용법:\n"
-"start [옵션] 프로그램_파일 이름 [...]\n"
-"start [옵션] 문서_파일 이름\n"
+"start [옵션] 프로그램_파일_이름 [...]\n"
+"start [옵션] 문서_파일_이름\n"
"\n"
"옵션:\n"
"\"제목\" 자식 창 표시줄에 나타날 제목을 지정합니다.\n"
@@ -12382,8 +12381,8 @@ msgstr ""
"/belownormal 프로그램을 BELOWNORMAL 우선 순위 클래스에서 시작합니다.\n"
"/node n 지정한 NUMA 노드에서 프로그램을 시작합니다.\n"
"/affinity mask 지정한 프로세서 친화도 마스크에서 프로그램을 시작합니다.\n"
-"/wait 시작한 프로그램이 끝날 때까지 기다립니다.\n"
-" 이 명령의 반환값은 실행했던 프로그램의 반환 코드입니다.\n"
+"/wait 시작한 프로그램이 끝날 때까지 기다립니다. 이 명령의 반환값은\n"
+" 실행했던 프로그램의 반환 코드입니다.\n"
"/unix 유닉스 파일 이름을 사용하고, Windows 탐색기처럼 파일을\n"
" 시작합니다.\n"
"/ProgIDOpen 지정한 progID를 사용해서 문서를 엽니다.\n"
@@ -12391,19 +12390,21 @@ msgstr ""
#: programs/cmd/cmd.rc:237
msgid "TIME sets or shows the current system time.\n"
-msgstr "TIME - 현재 시스템 시간을 보여 줍니다.\n"
+msgstr "TIME - 현재 시스템 시간을 설정하거나 보여줍니다.\n"
#: programs/cmd/cmd.rc:240
msgid "TITLE <string> sets the window title for the cmd window.\n"
-msgstr "TITLE <문자열> - cmd 창의 창 제목을 설정합니다.\n"
+msgstr ""
+"TITLE <문자열>은 CMD 창의 창 제목을 설정합니다.\n"
#: programs/cmd/cmd.rc:244
msgid ""
"TYPE <filename> copies <filename> to the console device (or elsewhere if\n"
"redirected). No check is made that the file is readable text.\n"
msgstr ""
-"TYPE <filename> <filename>을 콘솔 장치로 복사합니다(또는 어디에나\n"
-"다이렉트). 파일이 읽기 가능한 텍스트인지 체크하지 않습니다.\n"
+"TYPE <파일 이름>은 <파일 이름>을 콘솔 장치( 또는 방향 전환된 어딘가)로 복사합니"
+"다.\n"
+"파일 내용이 읽기 가능한 텍스트인지는 체크하지 않습니다.\n"
#: programs/cmd/cmd.rc:253
msgid ""
@@ -12415,14 +12416,13 @@ msgid ""
"\n"
"The verify flag has no function in Wine.\n"
msgstr ""
-"VERIFY는 검증 플래그를 설정하고 제거하거나 테스트하는데 사용됩니다. 올바른 형"
-"식은:\n"
+"VERIFY는 검증 플래그의 설정, 제거 및 테스트 용도로 사용됩니다.\n"
"\n"
"VERIFY ON\t플래그 설정.\n"
"VERIFY OFF\t플래그 제거.\n"
-"VERIFY\t\tON 이나 OFF 같이 적절하게 보여줌.\n"
+"VERIFY\t\t현재 플래그 상태를 표시합니다.\n"
"\n"
-"이 검증 플래그는 Wine에서는 아무 기능을 안함.\n"
+"이 검증 플래그는 Wine에서는 아무 기능도 하지 않습니다.\n"
#: programs/cmd/cmd.rc:256
msgid "VER displays the version of cmd you are running.\n"
@@ -12994,7 +12994,7 @@ msgstr "DirectX 진단 도구"
#: programs/dxdiag/dxdiag.rc:31
msgid "Usage: dxdiag [/whql:off | /whql:on] [/t filename | /x filename]"
-msgstr "사용법: dxdiag [/whql:off | /whql:on] [/t 파일 이름 | /x 파일 이름]"
+msgstr "사용법: dxdiag [/whql:off | /whql:on] [/t 파일_이름 | /x 파일_이름]"
#: programs/explorer/explorer.rc:31
msgid "Wine Explorer"
@@ -13133,13 +13133,13 @@ msgid ""
"\n"
"Where 'command' is one of HELP, START, STOP or USE.\n"
msgstr ""
-"이 명령어의 문법은:\n"
+"구문:\n"
"\n"
"NET 명령어[매개변수]\n"
-" -나-\n"
+"\n"
"NET 명령어 /HELP\n"
"\n"
-"명령어에 들어갈 수 있는 것은 HELP, START, STOP이나 USE중의 하나임.\n"
+"<명령어>는 HELP, START, STOP, USE 중 하나입니다.\n"
#: programs/net/net.rc:31
msgid ""
@@ -13150,12 +13150,12 @@ msgid ""
"Displays the list of running services if 'service' is omitted. Otherwise "
"'service' is the name of the service to start.\n"
msgstr ""
-"명령어의 문법:\n"
+"구문:\n"
"\n"
"NET START [서비스]\n"
"\n"
-"'서비스'가 생략하는 경우 실행 중인 서비스 목록을 표시합니다. 그렇지 않으면 "
-"'서비스'는 시작할 서비스의 이름입니다.\n"
+"<서비스>를 생략하면 실행 중인 서비스 목록을 표시합니다."
+"<서비스>는 시작하려는 서비스 이름입니다.\n"
#: programs/net/net.rc:32
msgid ""
@@ -13165,23 +13165,23 @@ msgid ""
"\n"
"Where 'service' is the name of the service to stop.\n"
msgstr ""
-"명령어의 문법:\n"
+"구문:\n"
"\n"
"NET STOP 서비스\n"
"\n"
-"'서비스'는 정지할 서비스의 이름입니다.\n"
+"<서비스>는 중지하려는 서비스 이름입니다.\n"
#: programs/net/net.rc:33
msgid "Stopping dependent service: %1\n"
-msgstr "종속된 서비스 중지 중: %1\n"
+msgstr "종속 서비스를 중지하고 있습니다: %1\n"
#: programs/net/net.rc:34
msgid "Could not stop service %1\n"
-msgstr "%1 서비스를 중지할 수 없음\n"
+msgstr "%1 서비스를 중지하지 못했습니다\n"
#: programs/net/net.rc:35
msgid "Could not get handle to service control manager.\n"
-msgstr "서비스 제어 관리자를 다룰 수 없습니다.\n"
+msgstr "서비스 제어 관리자 핸들을 얻을 수 없습니다.\n"
#: programs/net/net.rc:36
msgid "Could not get handle to service.\n"
@@ -13189,31 +13189,31 @@ msgstr "서비스 핸들을 얻을 수 없습니다.\n"
#: programs/net/net.rc:37
msgid "The %1 service is starting.\n"
-msgstr "%1 서비스는 시작중입니다.\n"
+msgstr "%1 서비스를 시작하고 있습니다.\n"
#: programs/net/net.rc:38
msgid "The %1 service was started successfully.\n"
-msgstr "%1 서비스 시작 성공했습니다.\n"
+msgstr "%1 서비스를 시작했습니다.\n"
#: programs/net/net.rc:39
msgid "The %1 service failed to start.\n"
-msgstr "%1 서비스 시작 실패했습니다.\n"
+msgstr "%1 서비스를 시작하지 못했습니다.\n"
#: programs/net/net.rc:40
msgid "The %1 service is stopping.\n"
-msgstr "%1 서비스는 정지하는 중입니다.\n"
+msgstr "%1 서비스를 중지하고 있습니다.\n"
#: programs/net/net.rc:41
msgid "The %1 service was stopped successfully.\n"
-msgstr "%1 서비스 정지 성공했습니다.\n"
+msgstr "%1 서비스를 중지했습니다.\n"
#: programs/net/net.rc:42
msgid "The %1 service failed to stop.\n"
-msgstr "%1 서비스 정지 실패했습니다.\n"
+msgstr "%1 서비스를 중지하지 못했습니다.\n"
#: programs/net/net.rc:44
msgid "There are no entries in the list.\n"
-msgstr "리스트가 비어 있습니다.\n"
+msgstr "목록에 항목이 없습니다.\n"
#: programs/net/net.rc:45
msgid ""
@@ -13222,7 +13222,7 @@ msgid ""
"---------------------------------------------------------------\n"
msgstr ""
"\n"
-"상태 로컬 원격\n"
+"상태 로컬 원격\n"
"---------------------------------------------------------------\n"
#: programs/net/net.rc:46
@@ -13231,35 +13231,35 @@ msgstr "%1 %2 %3 열린 리소스: %4!u!\n"
#: programs/net/net.rc:48
msgid "Paused"
-msgstr "정지됨"
+msgstr "일지 중지"
#: programs/net/net.rc:49
msgid "Disconnected"
-msgstr "연결이 끊어짐"
+msgstr "연결 끊김"
#: programs/net/net.rc:50
msgid "A network error occurred"
-msgstr "네트워크 오류가 발생함"
+msgstr "네트워크 오류 발생"
#: programs/net/net.rc:51
msgid "Connection is being made"
-msgstr "연결이 만들어짐"
+msgstr "연결 중"
#: programs/net/net.rc:52
msgid "Reconnecting"
-msgstr "다시 연결중"
+msgstr "다시 연결 중"
#: programs/net/net.rc:43
msgid "The following services are running:\n"
-msgstr "다음 서비스가 실행중임:\n"
+msgstr "실행 중인 서비스:\n"
#: programs/netstat/netstat.rc:30
msgid "Active Connections"
-msgstr "활성화된 연결"
+msgstr "활성 연결"
#: programs/netstat/netstat.rc:31
msgid "Proto"
-msgstr "프로토"
+msgstr "프로토콜"
#: programs/netstat/netstat.rc:32
msgid "Local Address"
@@ -13283,7 +13283,7 @@ msgstr "보냄"
#: programs/netstat/netstat.rc:37
msgid "Received"
-msgstr "응답받음"
+msgstr "받음"
#: programs/netstat/netstat.rc:38
msgid "Bytes"
@@ -13295,11 +13295,11 @@ msgstr "유니캐스트 패킷"
#: programs/netstat/netstat.rc:40
msgid "Non-unicast packets"
-msgstr "유니캐스트가 아닌 패킷"
+msgstr "비유니캐스트 패킷"
#: programs/netstat/netstat.rc:41
msgid "Discards"
-msgstr "폐기"
+msgstr "버림"
#: programs/netstat/netstat.rc:42
msgid "Errors"
@@ -13311,23 +13311,23 @@ msgstr "알 수 없는 프로토콜"
#: programs/netstat/netstat.rc:44
msgid "TCP Statistics for IPv4"
-msgstr "IPv4의 TCP 상태"
+msgstr "IPv4 TCP 통계"
#: programs/netstat/netstat.rc:45
msgid "Active Opens"
-msgstr "활성화된 열림"
+msgstr "활성 열기"
#: programs/netstat/netstat.rc:46
msgid "Passive Opens"
-msgstr "수동적인 열림"
+msgstr "수동 열기"
#: programs/netstat/netstat.rc:47
msgid "Failed Connection Attempts"
-msgstr "연결 시도 실패"
+msgstr "실패한 연결 시도"
#: programs/netstat/netstat.rc:48
msgid "Reset Connections"
-msgstr "연결 재설정"
+msgstr "재설정된 연결"
#: programs/netstat/netstat.rc:49
msgid "Current Connections"
@@ -13335,35 +13335,35 @@ msgstr "현재 연결"
#: programs/netstat/netstat.rc:50
msgid "Segments Received"
-msgstr "세그멘트가 응답함"
+msgstr "받은 세그멘트"
#: programs/netstat/netstat.rc:51
msgid "Segments Sent"
-msgstr "세그멘트가 보내짐"
+msgstr "보낸 세그멘트"
#: programs/netstat/netstat.rc:52
msgid "Segments Retransmitted"
-msgstr "세그멘트가 다시 보내짐"
+msgstr "재전송된 세그멘트"
#: programs/netstat/netstat.rc:53
msgid "UDP Statistics for IPv4"
-msgstr "IPv4의 UDP 상태"
+msgstr "IPv4 UDP 통계"
#: programs/netstat/netstat.rc:54
msgid "Datagrams Received"
-msgstr "데이터그램을 받음"
+msgstr "받은 데이터그램"
#: programs/netstat/netstat.rc:55
msgid "No Ports"
-msgstr "포트가 없음"
+msgstr "포트 없음"
#: programs/netstat/netstat.rc:56
msgid "Receive Errors"
-msgstr "받는 중에 오류 발생"
+msgstr "받기 오류"
#: programs/netstat/netstat.rc:57
msgid "Datagrams Sent"
-msgstr "데이터그램을 보냄"
+msgstr "보낸 데이터그램"
#: programs/notepad/notepad.rc:30
msgid "&New\tCtrl+N"
@@ -14167,7 +14167,7 @@ msgid ""
" REG [operation] /?\n"
"\n"
msgstr ""
-"문법:\n"
+"구문:\n"
" REG [명령] [매개변수]\n"
"\n"
"지원하는 명령:\n"
@@ -15058,11 +15058,11 @@ msgstr "오류: \"%1\" 프로세스를 중단시킬 수 없습니다.\n"
#: programs/taskkill/taskkill.rc:43
msgid "Error: Process self-termination is not permitted.\n"
-msgstr "오류: 프로세스 자가 종료는 허용되지 않습니다.\n"
+msgstr "오류: 프로세스 자체 종료는 허용되지 않습니다.\n"
#: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108
msgid "&New Task (Run...)"
-msgstr "새 작업(실행...)(&N)"
+msgstr "새 작업 (실행...)(&N)"
#: programs/taskmgr/taskmgr.rc:39
msgid "E&xit Task Manager"
@@ -15295,7 +15295,7 @@ msgstr "프로세서 선호도"
msgid ""
"The Processor Affinity setting controls which CPUs the process will be "
"allowed to execute on."
-msgstr "프로세서 선호도 설정은 어떤 CPU가 프로세스를 실행시킬 지를 제어한다."
+msgstr "프로세서 선호도 설정은 프로세스가 실행될 수 있는 CPU를 지정합니다."
#: programs/taskmgr/taskmgr.rc:446
msgid "CPU 0"
--
2.30.0
1
0
[PATCH v4 1/2] windowscodecs: Use IWICImagingFactory_CreatePalette in write_source.
by Rémi Bernon Feb. 4, 2021
by Rémi Bernon Feb. 4, 2021
Feb. 4, 2021
Instead of PaletteImpl_Create.
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
v4: As an alternative to v3, with unix_lib.c copied to wmphoto instead,
as it seems to be preferred it over the #ifdef. I don't mind either.
dlls/windowscodecs/wincodecs_common.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/dlls/windowscodecs/wincodecs_common.c b/dlls/windowscodecs/wincodecs_common.c
index 37ad7128f10..1b146908be9 100644
--- a/dlls/windowscodecs/wincodecs_common.c
+++ b/dlls/windowscodecs/wincodecs_common.c
@@ -121,9 +121,17 @@ HRESULT write_source(IWICBitmapFrameEncode *iface,
if (need_palette)
{
+ IWICImagingFactory *factory;
IWICPalette *palette;
- hr = PaletteImpl_Create(&palette);
+ hr = create_instance(&CLSID_WICImagingFactory, &IID_IWICImagingFactory, (void**)&factory);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = IWICImagingFactory_CreatePalette(factory, &palette);
+ IWICImagingFactory_Release(factory);
+ }
+
if (SUCCEEDED(hr))
{
hr = IWICBitmapSource_CopyPalette(converted_source, palette);
--
2.30.0
2
4
Feb. 3, 2021
From: Michael Müller <michael(a)fds-team.de>
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/kernel32/locale_rc.rc | 1 +
dlls/kernel32/nls/srm.nls | 174 +++++++++++++++++++++++++++++++++++++
2 files changed, 175 insertions(+)
create mode 100644 dlls/kernel32/nls/srm.nls
diff --git a/dlls/kernel32/locale_rc.rc b/dlls/kernel32/locale_rc.rc
index c6bb407b1c5..86ababd0900 100644
--- a/dlls/kernel32/locale_rc.rc
+++ b/dlls/kernel32/locale_rc.rc
@@ -143,6 +143,7 @@
#include "nls/hrv.nls" /* 0x041a LANG_SERBIAN, SUBLANG_DEFAULT */
#include "nls/srl.nls" /* 0x081a LANG_SERBIAN, SUBLANG_SERBIAN_LATIN */
#include "nls/srb.nls" /* 0x0c1a LANG_SERBIAN, SUBLANG_SERBIAN_CYRILLIC */
+#include "nls/srm.nls" /* 0x241a LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN */
#include "nls/sky.nls" /* 0x041b LANG_SLOVAK, SUBLANG_DEFAULT */
diff --git a/dlls/kernel32/nls/srm.nls b/dlls/kernel32/nls/srm.nls
new file mode 100644
index 00000000000..f4b1169943a
--- /dev/null
+++ b/dlls/kernel32/nls/srm.nls
@@ -0,0 +1,174 @@
+/*
+ * Locale definitions for Serbian (Serbia, Latin)
+ *
+ * Copyright 2016 Michael Müller
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#pragma code_page(65001) /* UTF-8 */
+
+STRINGTABLE LANGUAGE LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN
+{
+ LOCALE_FONTSIGNATURE L"\x0027\x8000\x3808\x0000\x0000\x0000\x0000\x0000\x0002\x0000\x0000\x0400\x0012\x0000\x0000\xc5d4"
+ LOCALE_ICALENDARTYPE "1"
+ LOCALE_ICENTURY "1"
+ LOCALE_ICOUNTRY "381"
+ LOCALE_ICURRDIGITS "2"
+ LOCALE_ICURRENCY "3"
+ LOCALE_IDATE "1"
+ LOCALE_IDAYLZERO "0"
+ LOCALE_IDEFAULTANSICODEPAGE "1250"
+ LOCALE_IDEFAULTCODEPAGE "852"
+ LOCALE_IDEFAULTCOUNTRY "381"
+ LOCALE_IDEFAULTEBCDICCODEPAGE "500"
+ LOCALE_IDEFAULTLANGUAGE "241a"
+ LOCALE_IDEFAULTMACCODEPAGE "10029"
+ LOCALE_IDIGITS "2"
+ LOCALE_IDIGITSUBSTITUTION "1"
+ LOCALE_IFIRSTDAYOFWEEK "0"
+ LOCALE_IFIRSTWEEKOFYEAR "0"
+ LOCALE_IGEOID "271"
+ LOCALE_IINTLCURRDIGITS "2"
+ LOCALE_ILANGUAGE "241a"
+ LOCALE_ILDATE "1"
+ LOCALE_ILZERO "1"
+ LOCALE_IMEASURE "0"
+ LOCALE_IMONLZERO "0"
+ LOCALE_INEGATIVEPERCENT "1"
+ LOCALE_INEGCURR "8"
+ LOCALE_INEGNUMBER "1"
+ LOCALE_INEGSEPBYSPACE "1"
+ LOCALE_INEGSIGNPOSN "1"
+ LOCALE_INEGSYMPRECEDES "0"
+ LOCALE_INEUTRAL "0"
+ LOCALE_IOPTIONALCALENDAR "0"
+ LOCALE_IPAPERSIZE "9"
+ LOCALE_IPOSSEPBYSPACE "1"
+ LOCALE_IPOSSIGNPOSN "1"
+ LOCALE_IPOSSYMPRECEDES "0"
+ LOCALE_IREADINGLAYOUT "0"
+ LOCALE_ITIME "1"
+ LOCALE_ITIMEMARKPOSN "0"
+ LOCALE_ITLZERO "1"
+ LOCALE_S1159 "pre podne"
+ LOCALE_S2359 "po podne"
+ LOCALE_SABBREVCTRYNAME "SRB"
+ LOCALE_SABBREVDAYNAME1 "pon"
+ LOCALE_SABBREVDAYNAME2 "uto"
+ LOCALE_SABBREVDAYNAME3 "sre"
+ LOCALE_SABBREVDAYNAME4 "čet"
+ LOCALE_SABBREVDAYNAME5 "pet"
+ LOCALE_SABBREVDAYNAME6 "sub"
+ LOCALE_SABBREVDAYNAME7 "ned"
+ LOCALE_SABBREVLANGNAME "SRM"
+ LOCALE_SABBREVMONTHNAME1 "jan"
+ LOCALE_SABBREVMONTHNAME2 "feb"
+ LOCALE_SABBREVMONTHNAME3 "mar"
+ LOCALE_SABBREVMONTHNAME4 "apr"
+ LOCALE_SABBREVMONTHNAME5 "maj"
+ LOCALE_SABBREVMONTHNAME6 "jun"
+ LOCALE_SABBREVMONTHNAME7 "jul"
+ LOCALE_SABBREVMONTHNAME8 "avg"
+ LOCALE_SABBREVMONTHNAME9 "sep"
+ LOCALE_SABBREVMONTHNAME10 "okt"
+ LOCALE_SABBREVMONTHNAME11 "nov"
+ LOCALE_SABBREVMONTHNAME12 "dec"
+ LOCALE_SABBREVMONTHNAME13 ""
+ LOCALE_SCOUNTRY "Serbia"
+ LOCALE_SCURRENCY "Din."
+ LOCALE_SDATE "."
+ LOCALE_SDAYNAME1 "ponedeljak"
+ LOCALE_SDAYNAME2 "utorak"
+ LOCALE_SDAYNAME3 "sreda"
+ LOCALE_SDAYNAME4 "četvrtak"
+ LOCALE_SDAYNAME5 "petak"
+ LOCALE_SDAYNAME6 "subota"
+ LOCALE_SDAYNAME7 "nedelja"
+ LOCALE_SDECIMAL ","
+ LOCALE_SENGCOUNTRY "Serbia"
+ LOCALE_SENGCURRNAME "Serbian Dinar"
+ LOCALE_SENGLANGUAGE "Serbian (Latin)"
+ LOCALE_SGROUPING "3;0"
+ LOCALE_SINTLSYMBOL "RSD"
+ LOCALE_SISO3166CTRYNAME "RS"
+ LOCALE_SISO639LANGNAME "sr"
+ LOCALE_SLANGUAGE "Serbian (Latin, Serbia)"
+ LOCALE_SLIST ";"
+ LOCALE_SLONGDATE "dddd, dd. MMMM yyyy"
+ LOCALE_SMONDECIMALSEP ","
+ LOCALE_SMONGROUPING "3;0"
+ LOCALE_SMONTHDAY "d. MMMM"
+ LOCALE_SMONTHNAME1 "januar"
+ LOCALE_SMONTHNAME2 "februar"
+ LOCALE_SMONTHNAME3 "mart"
+ LOCALE_SMONTHNAME4 "april"
+ LOCALE_SMONTHNAME5 "maj"
+ LOCALE_SMONTHNAME6 "jun"
+ LOCALE_SMONTHNAME7 "jul"
+ LOCALE_SMONTHNAME8 "avgust"
+ LOCALE_SMONTHNAME9 "septembar"
+ LOCALE_SMONTHNAME10 "oktobar"
+ LOCALE_SMONTHNAME11 "novembar"
+ LOCALE_SMONTHNAME12 "decembar"
+ LOCALE_SMONTHNAME13 ""
+ LOCALE_SMONTHOUSANDSEP "."
+ LOCALE_SNAME "sr-Latn-RS"
+ LOCALE_SNAN "NaN"
+ LOCALE_SNATIVECTRYNAME "Srbija"
+ LOCALE_SNATIVECURRNAME "Srpski dinar"
+ LOCALE_SNATIVEDIGITS "0123456789"
+ LOCALE_SNATIVEDISPLAYNAME "srpski (Srbija)"
+ LOCALE_SNATIVELANGNAME "srpski"
+ LOCALE_SNEGATIVESIGN "-"
+ LOCALE_SNEGINFINITY L"-\x221e"
+ LOCALE_SOPENTYPELANGUAGETAG "SRB "
+ LOCALE_SPARENT "sr-Latn"
+ LOCALE_SPOSINFINITY L"\x221e"
+ LOCALE_SPOSITIVESIGN "+"
+ LOCALE_SSCRIPTS "Latn;"
+ LOCALE_SSHORTDATE "d.M.yyyy"
+ LOCALE_SSHORTESTDAYNAME1 "pon"
+ LOCALE_SSHORTESTDAYNAME2 "uto"
+ LOCALE_SSHORTESTDAYNAME3 "sre"
+ LOCALE_SSHORTESTDAYNAME4 "čet"
+ LOCALE_SSHORTESTDAYNAME5 "pet"
+ LOCALE_SSHORTESTDAYNAME6 "sub"
+ LOCALE_SSHORTESTDAYNAME7 "ned"
+ LOCALE_SSHORTTIME "H:mm"
+ LOCALE_SSORTNAME "Default"
+ LOCALE_STHOUSAND "."
+ LOCALE_STIME ":"
+ LOCALE_STIMEFORMAT "H:mm:ss"
+ LOCALE_SYEARMONTH "MMMM yyyy"
+
+ LGRPID_WESTERN_EUROPE+LGRPID_RES_BASE "Western Europe and United States"
+ LGRPID_CENTRAL_EUROPE+LGRPID_RES_BASE "Central Europe"
+ LGRPID_BALTIC+LGRPID_RES_BASE "Baltic"
+ LGRPID_GREEK+LGRPID_RES_BASE "Greek"
+ LGRPID_CYRILLIC+LGRPID_RES_BASE "Cyrillic"
+ LGRPID_TURKISH+LGRPID_RES_BASE "Turkic"
+ LGRPID_JAPANESE+LGRPID_RES_BASE "Japanese"
+ LGRPID_KOREAN+LGRPID_RES_BASE "Korean"
+ LGRPID_TRADITIONAL_CHINESE+LGRPID_RES_BASE "Traditional Chinese"
+ LGRPID_SIMPLIFIED_CHINESE+LGRPID_RES_BASE "Simplified Chinese"
+ LGRPID_THAI+LGRPID_RES_BASE "Thai"
+ LGRPID_HEBREW+LGRPID_RES_BASE "Hebrew"
+ LGRPID_ARABIC+LGRPID_RES_BASE "Arabic"
+ LGRPID_VIETNAMESE+LGRPID_RES_BASE "Vietnamese"
+ LGRPID_INDIC+LGRPID_RES_BASE "Indic"
+ LGRPID_GEORGIAN+LGRPID_RES_BASE "Georgian"
+ LGRPID_ARMENIAN+LGRPID_RES_BASE "Armenian"
+}
--
2.20.1
1
3
[PATCH 1/5] winegstreamer: Move the stream event fields to struct wg_parser_stream.
by Zebediah Figura Feb. 3, 2021
by Zebediah Figura Feb. 3, 2021
Feb. 3, 2021
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/winegstreamer/gstdemux.c | 125 +++++++++++++++++-----------------
1 file changed, 64 insertions(+), 61 deletions(-)
diff --git a/dlls/winegstreamer/gstdemux.c b/dlls/winegstreamer/gstdemux.c
index 8d08ff370f4..eaad0f56133 100644
--- a/dlls/winegstreamer/gstdemux.c
+++ b/dlls/winegstreamer/gstdemux.c
@@ -74,12 +74,37 @@ struct wg_parser
bool flushing, sink_connected;
};
+enum wg_parser_event_type
+{
+ WG_PARSER_EVENT_NONE = 0,
+ WG_PARSER_EVENT_BUFFER,
+ WG_PARSER_EVENT_EOS,
+ WG_PARSER_EVENT_SEGMENT,
+};
+
+struct wg_parser_event
+{
+ enum wg_parser_event_type type;
+ union
+ {
+ GstBuffer *buffer;
+ struct
+ {
+ uint64_t position, stop;
+ double rate;
+ } segment;
+ } u;
+};
+
struct wg_parser_stream
{
GstPad *their_src, *post_sink, *post_src, *my_sink;
GstElement *flip;
GstSegment *segment;
GstCaps *caps;
+
+ pthread_cond_t event_cond, event_empty_cond;
+ struct wg_parser_event event;
};
struct parser
@@ -112,28 +137,6 @@ struct parser
HRESULT (*source_get_media_type)(struct parser_source *pin, unsigned int index, AM_MEDIA_TYPE *mt);
};
-enum parser_event_type
-{
- PARSER_EVENT_NONE = 0,
- PARSER_EVENT_BUFFER,
- PARSER_EVENT_EOS,
- PARSER_EVENT_SEGMENT,
-};
-
-struct parser_event
-{
- enum parser_event_type type;
- union
- {
- GstBuffer *buffer;
- struct
- {
- uint64_t position, stop;
- double rate;
- } segment;
- } u;
-};
-
struct parser_source
{
struct strmbase_source pin;
@@ -144,9 +147,7 @@ struct parser_source
SourceSeeking seek;
CRITICAL_SECTION flushing_cs;
- pthread_cond_t event_cond, event_empty_cond;
bool flushing, eos;
- struct parser_event event;
HANDLE thread;
};
@@ -710,9 +711,10 @@ static gboolean event_src(GstPad *pad, GstObject *parent, GstEvent *event)
return ret;
}
-static GstFlowReturn queue_stream_event(struct parser_source *pin, const struct parser_event *event)
+static GstFlowReturn queue_stream_event(struct parser_source *pin, const struct wg_parser_event *event)
{
struct wg_parser *parser = impl_from_strmbase_filter(pin->pin.pin.filter)->wg_parser;
+ struct wg_parser_stream *stream = pin->wg_stream;
/* Unlike request_buffer_src() [q.v.], we need to watch for GStreamer
* flushes here. The difference is that we can be blocked by the streaming
@@ -721,17 +723,17 @@ static GstFlowReturn queue_stream_event(struct parser_source *pin, const struct
* is solved by flushing the upstream source. */
pthread_mutex_lock(&parser->mutex);
- while (!pin->flushing && pin->event.type != PARSER_EVENT_NONE)
- pthread_cond_wait(&pin->event_empty_cond, &parser->mutex);
+ while (!pin->flushing && stream->event.type != WG_PARSER_EVENT_NONE)
+ pthread_cond_wait(&stream->event_empty_cond, &parser->mutex);
if (pin->flushing)
{
pthread_mutex_unlock(&parser->mutex);
GST_DEBUG("Filter is flushing; discarding event.");
return GST_FLOW_FLUSHING;
}
- pin->event = *event;
+ stream->event = *event;
pthread_mutex_unlock(&parser->mutex);
- pthread_cond_signal(&pin->event_cond);
+ pthread_cond_signal(&stream->event_cond);
GST_LOG("Event queued.");
return GST_FLOW_OK;
}
@@ -750,7 +752,7 @@ static gboolean event_sink(GstPad *pad, GstObject *parent, GstEvent *event)
case GST_EVENT_SEGMENT:
if (pin->pin.pin.peer)
{
- struct parser_event stream_event;
+ struct wg_parser_event stream_event;
const GstSegment *segment;
gst_event_parse_segment(event, &segment);
@@ -763,7 +765,7 @@ static gboolean event_sink(GstPad *pad, GstObject *parent, GstEvent *event)
gst_segment_copy_into(segment, stream->segment);
- stream_event.type = PARSER_EVENT_SEGMENT;
+ stream_event.type = WG_PARSER_EVENT_SEGMENT;
stream_event.u.segment.position = segment->position / 100;
stream_event.u.segment.stop = segment->stop / 100;
stream_event.u.segment.rate = segment->rate * segment->applied_rate;
@@ -774,9 +776,9 @@ static gboolean event_sink(GstPad *pad, GstObject *parent, GstEvent *event)
case GST_EVENT_EOS:
if (pin->pin.pin.peer)
{
- struct parser_event stream_event;
+ struct wg_parser_event stream_event;
- stream_event.type = PARSER_EVENT_EOS;
+ stream_event.type = WG_PARSER_EVENT_EOS;
queue_stream_event(pin, &stream_event);
}
else
@@ -794,20 +796,20 @@ static gboolean event_sink(GstPad *pad, GstObject *parent, GstEvent *event)
pthread_mutex_lock(&parser->mutex);
pin->flushing = true;
- pthread_cond_signal(&pin->event_empty_cond);
+ pthread_cond_signal(&stream->event_empty_cond);
- switch (pin->event.type)
+ switch (stream->event.type)
{
- case PARSER_EVENT_NONE:
- case PARSER_EVENT_EOS:
- case PARSER_EVENT_SEGMENT:
+ case WG_PARSER_EVENT_NONE:
+ case WG_PARSER_EVENT_EOS:
+ case WG_PARSER_EVENT_SEGMENT:
break;
- case PARSER_EVENT_BUFFER:
- gst_buffer_unref(pin->event.u.buffer);
+ case WG_PARSER_EVENT_BUFFER:
+ gst_buffer_unref(stream->event.u.buffer);
break;
}
- pin->event.type = PARSER_EVENT_NONE;
+ stream->event.type = WG_PARSER_EVENT_NONE;
pthread_mutex_unlock(&parser->mutex);
}
@@ -897,7 +899,7 @@ static void *push_data(void *iface)
static GstFlowReturn got_data_sink(GstPad *pad, GstObject *parent, GstBuffer *buffer)
{
struct parser_source *pin = gst_pad_get_element_private(pad);
- struct parser_event stream_event;
+ struct wg_parser_event stream_event;
GstFlowReturn ret;
GST_LOG("pin %p, buffer %p.", pin, buffer);
@@ -908,7 +910,7 @@ static GstFlowReturn got_data_sink(GstPad *pad, GstObject *parent, GstBuffer *bu
return GST_FLOW_OK;
}
- stream_event.type = PARSER_EVENT_BUFFER;
+ stream_event.type = WG_PARSER_EVENT_BUFFER;
stream_event.u.buffer = buffer;
/* Transfer our reference to the buffer to the thread. */
if ((ret = queue_stream_event(pin, &stream_event)) != GST_FLOW_OK)
@@ -1044,15 +1046,16 @@ static void send_buffer(struct parser_source *pin, GstBuffer *buf)
gst_buffer_unref(buf);
}
-static bool get_stream_event(struct parser_source *pin, struct parser_event *event)
+static bool get_stream_event(struct parser_source *pin, struct wg_parser_event *event)
{
struct parser *filter = impl_from_strmbase_filter(pin->pin.pin.filter);
+ struct wg_parser_stream *stream = pin->wg_stream;
struct wg_parser *parser = filter->wg_parser;
pthread_mutex_lock(&parser->mutex);
- while (!parser->flushing && pin->event.type == PARSER_EVENT_NONE)
- pthread_cond_wait(&pin->event_cond, &parser->mutex);
+ while (!parser->flushing && stream->event.type == WG_PARSER_EVENT_NONE)
+ pthread_cond_wait(&stream->event_cond, &parser->mutex);
if (parser->flushing)
{
@@ -1061,11 +1064,11 @@ static bool get_stream_event(struct parser_source *pin, struct parser_event *eve
return false;
}
- *event = pin->event;
- pin->event.type = PARSER_EVENT_NONE;
+ *event = stream->event;
+ stream->event.type = WG_PARSER_EVENT_NONE;
pthread_mutex_unlock(&parser->mutex);
- pthread_cond_signal(&pin->event_empty_cond);
+ pthread_cond_signal(&stream->event_empty_cond);
return true;
}
@@ -1079,7 +1082,7 @@ static DWORD CALLBACK stream_thread(void *arg)
while (filter->streaming)
{
- struct parser_event event;
+ struct wg_parser_event event;
EnterCriticalSection(&pin->flushing_cs);
@@ -1093,20 +1096,20 @@ static DWORD CALLBACK stream_thread(void *arg)
switch (event.type)
{
- case PARSER_EVENT_BUFFER:
+ case WG_PARSER_EVENT_BUFFER:
send_buffer(pin, event.u.buffer);
break;
- case PARSER_EVENT_EOS:
+ case WG_PARSER_EVENT_EOS:
IPin_EndOfStream(pin->pin.pin.peer);
break;
- case PARSER_EVENT_SEGMENT:
+ case WG_PARSER_EVENT_SEGMENT:
IPin_NewSegment(pin->pin.pin.peer, event.u.segment.position,
event.u.segment.stop, event.u.segment.rate);
break;
- case PARSER_EVENT_NONE:
+ case WG_PARSER_EVENT_NONE:
assert(0);
}
@@ -1785,7 +1788,7 @@ static HRESULT parser_cleanup_stream(struct strmbase_filter *iface)
if (!pin->pin.pin.peer)
continue;
- pthread_cond_signal(&pin->event_cond);
+ pthread_cond_signal(&pin->wg_stream->event_cond);
}
for (i = 0; i < filter->source_count; ++i)
@@ -2187,7 +2190,7 @@ static HRESULT WINAPI GST_Seeking_SetPositions(IMediaSeeking *iface,
{
if (filter->sources[i]->pin.pin.peer)
{
- pthread_cond_signal(&pin->event_cond);
+ pthread_cond_signal(&stream->event_cond);
IPin_BeginFlush(filter->sources[i]->pin.pin.peer);
}
}
@@ -2468,8 +2471,8 @@ static void free_source_pin(struct parser_source *pin)
gst_object_unref(stream->my_sink);
gst_segment_free(stream->segment);
- pthread_cond_destroy(&pin->event_cond);
- pthread_cond_destroy(&pin->event_empty_cond);
+ pthread_cond_destroy(&stream->event_cond);
+ pthread_cond_destroy(&stream->event_empty_cond);
free(stream);
@@ -2517,8 +2520,8 @@ static struct parser_source *create_pin(struct parser *filter, const WCHAR *name
pin->IQualityControl_iface.lpVtbl = &GSTOutPin_QualityControl_Vtbl;
strmbase_seeking_init(&pin->seek, &GST_Seeking_Vtbl, GST_ChangeStop,
GST_ChangeCurrent, GST_ChangeRate);
- pthread_cond_init(&pin->event_cond, NULL);
- pthread_cond_init(&pin->event_empty_cond, NULL);
+ pthread_cond_init(&stream->event_cond, NULL);
+ pthread_cond_init(&stream->event_empty_cond, NULL);
BaseFilterImpl_IncrementPinVersion(&filter->filter);
InitializeCriticalSection(&pin->flushing_cs);
@@ -2551,7 +2554,7 @@ static HRESULT GST_RemoveOutputPins(struct parser *This)
for (i = 0; i < This->source_count; ++i)
{
This->sources[i]->flushing = true;
- pthread_cond_signal(&This->sources[i]->event_empty_cond);
+ pthread_cond_signal(&This->sources[i]->wg_stream->event_empty_cond);
}
pthread_mutex_unlock(&parser->mutex);
--
2.30.0
1
4