Skip to content

Commit

Permalink
dmime: Pass the DMUS_PMSG through the performance graph.
Browse files Browse the repository at this point in the history
  • Loading branch information
rbernon authored and julliard committed Sep 18, 2023
1 parent 0a93c69 commit 5f04740
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 112 deletions.
203 changes: 114 additions & 89 deletions dlls/dmime/performance.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,10 @@ struct performance
DWORD procThreadId;
BOOL procThreadTicStarted;
CRITICAL_SECTION safe;
struct list immediate_messages;
struct list queued_messages;

IReferenceClock *master_clock;
REFERENCE_TIME init_time;
struct list messages;
};

struct message
Expand All @@ -80,99 +79,109 @@ static inline struct message *message_from_DMUS_PMSG(DMUS_PMSG *msg)
return msg ? CONTAINING_RECORD(msg, struct message, msg) : NULL;
}

static HRESULT performance_process_message(struct performance *This, DMUS_PMSG *msg, DWORD *timeout)
{
static const DWORD delivery_flags = DMUS_PMSGF_TOOL_IMMEDIATE | DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_ATTIME;
IDirectMusicPerformance *performance = (IDirectMusicPerformance *)&This->IDirectMusicPerformance8_iface;
HRESULT hr;

do
{
REFERENCE_TIME current, offset = 0;
IDirectMusicTool *tool;

if (FAILED(hr = IDirectMusicPerformance_GetTime(performance, &current, NULL))) return hr;
if (!(tool = msg->pTool)) tool = &This->IDirectMusicTool_iface;

switch (msg->dwFlags & delivery_flags)
{
default:
WARN("No delivery flag found for message %p\n", msg);
/* fallthrough */
case DMUS_PMSGF_TOOL_IMMEDIATE:
hr = IDirectMusicTool_ProcessPMsg(tool, performance, msg);
break;
case DMUS_PMSGF_TOOL_QUEUE:
offset = This->dwBumperLength * 10000;
/* fallthrough */
case DMUS_PMSGF_TOOL_ATTIME:
if (msg->rtTime >= offset && msg->rtTime - offset >= current)
{
if (timeout) *timeout = (msg->rtTime - offset - current) / 10000;
return DMUS_S_REQUEUE;
}

hr = IDirectMusicTool_ProcessPMsg(tool, performance, msg);
break;
}
} while (hr == DMUS_S_REQUEUE);

if (hr == DMUS_S_FREE) hr = IDirectMusicPerformance_FreePMsg(performance, msg);
if (FAILED(hr)) WARN("Failed to process message, hr %#lx\n", hr);
return hr;
}

#define PROCESSMSG_START (WM_APP + 0)
#define PROCESSMSG_EXIT (WM_APP + 1)
#define PROCESSMSG_REMOVE (WM_APP + 2)
#define PROCESSMSG_ADD (WM_APP + 4)

static DWORD WINAPI ProcessMsgThread(LPVOID lpParam)
{
struct performance *This = lpParam;
DWORD timeout = INFINITE;
MSG msg;
HRESULT hr;
struct message *message, *next;

static struct message *ProceedMsg(struct performance *This, struct message *cur)
{
if (cur->msg.dwType == DMUS_PMSGT_NOTIFICATION) {
SetEvent(This->hNotification);
}
list_remove(&cur->entry);
list_init(&cur->entry);
switch (cur->msg.dwType) {
case DMUS_PMSGT_WAVE:
case DMUS_PMSGT_TEMPO:
case DMUS_PMSGT_STOP:
default:
FIXME("Unhandled PMsg Type: %#lx\n", cur->msg.dwType);
break;
}
return cur;
}
while (TRUE)
{
if (timeout > 0) MsgWaitForMultipleObjects(0, NULL, FALSE, timeout, QS_POSTMESSAGE | QS_SENDMESSAGE | QS_TIMER);
timeout = INFINITE;

static DWORD WINAPI ProcessMsgThread(LPVOID lpParam) {
struct performance *This = lpParam;
DWORD timeOut = INFINITE;
MSG msg;
HRESULT hr;
REFERENCE_TIME rtCurTime;
struct message *message, *next;
struct message *cur = NULL;
EnterCriticalSection(&This->safe);

while (TRUE) {
DWORD dwDec = This->rtLatencyTime + This->dwBumperLength;
LIST_FOR_EACH_ENTRY_SAFE(message, next, &This->messages, struct message, entry)
{
list_remove(&message->entry);
list_init(&message->entry);

if (timeOut > 0) MsgWaitForMultipleObjects(0, NULL, FALSE, timeOut, QS_POSTMESSAGE|QS_SENDMESSAGE|QS_TIMER);
timeOut = INFINITE;
hr = performance_process_message(This, &message->msg, &timeout);
if (hr == DMUS_S_REQUEUE) list_add_before(&next->entry, &message->entry);
if (hr != S_OK) break;
}

EnterCriticalSection(&This->safe);
hr = IDirectMusicPerformance8_GetTime(&This->IDirectMusicPerformance8_iface, &rtCurTime, NULL);
if (FAILED(hr)) {
goto outrefresh;
}

LIST_FOR_EACH_ENTRY_SAFE(message, next, &This->immediate_messages, struct message, entry)
{
cur = ProceedMsg(This, message);
free(cur);
}
LeaveCriticalSection(&This->safe);

LIST_FOR_EACH_ENTRY_SAFE(message, next, &This->queued_messages, struct message, entry)
{
timeOut = (message->msg.rtTime - rtCurTime) + This->rtLatencyTime;
if (message->msg.rtTime >= rtCurTime + dwDec) break;
cur = ProceedMsg(This, message);
free(cur);
}
while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
{
/** if hwnd we suppose that is a windows event ... */
if (NULL != msg.hwnd)
{
TranslateMessage(&msg);
DispatchMessageA(&msg);
}
else
{
switch (msg.message)
{
case WM_QUIT:
case PROCESSMSG_EXIT: goto outofthread;
case PROCESSMSG_START: break;
case PROCESSMSG_ADD: break;
case PROCESSMSG_REMOVE: break;
default: ERR("Unhandled message %u. Critical Path\n", msg.message); break;
}
}
}

outrefresh:
LeaveCriticalSection(&This->safe);

while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) {
/** if hwnd we suppose that is a windows event ... */
if (NULL != msg.hwnd) {
TranslateMessage(&msg);
DispatchMessageA(&msg);
} else {
switch (msg.message) {
case WM_QUIT:
case PROCESSMSG_EXIT:
goto outofthread;
case PROCESSMSG_START:
break;
case PROCESSMSG_ADD:
break;
case PROCESSMSG_REMOVE:
break;
default:
ERR("Unhandled message %u. Critical Path\n", msg.message);
break;
}
}
/** here we should run a little of current AudioPath */
}

/** here we should run a little of current AudioPath */

}

outofthread:
TRACE("(%p): Exiting\n", This);
return 0;
TRACE("(%p): Exiting\n", This);

return 0;
}

static BOOL PostMessageToProcessMsgThread(struct performance *This, UINT iMsg) {
Expand Down Expand Up @@ -389,9 +398,9 @@ static HRESULT WINAPI performance_GetBumperLength(IDirectMusicPerformance8 *ifac

static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS_PMSG *msg)
{
const DWORD delivery_flags = DMUS_PMSGF_TOOL_IMMEDIATE | DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_ATTIME;
struct performance *This = impl_from_IDirectMusicPerformance8(iface);
struct message *message, *next;
struct list *queue;
HRESULT hr;

FIXME("(%p, %p): semi-stub\n", This, msg);
Expand All @@ -400,15 +409,13 @@ static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS
if (!This->dmusic) return DMUS_E_NO_MASTER_CLOCK;
if (!(msg->dwFlags & (DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_REFTIME))) return E_INVALIDARG;

if (msg->dwFlags & DMUS_PMSGF_TOOL_IMMEDIATE) queue = &This->immediate_messages;
else queue = &This->queued_messages;

EnterCriticalSection(&This->safe);

if (!list_empty(&message->entry))
hr = DMUS_E_ALREADY_SENT;
else
{
if (!(msg->dwFlags & delivery_flags)) msg->dwFlags |= DMUS_PMSGF_TOOL_IMMEDIATE;
if (!(msg->dwFlags & DMUS_PMSGF_MUSICTIME))
{
if (FAILED(hr = IDirectMusicPerformance8_ReferenceToMusicTime(iface,
Expand All @@ -424,9 +431,16 @@ static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS
msg->dwFlags |= DMUS_PMSGF_REFTIME;
}

LIST_FOR_EACH_ENTRY(next, queue, struct message, entry)
if (msg->dwFlags & DMUS_PMSGF_TOOL_IMMEDIATE)
{
hr = performance_process_message(This, &message->msg, NULL);
if (hr != DMUS_S_REQUEUE) goto done;
}

LIST_FOR_EACH_ENTRY(next, &This->messages, struct message, entry)
if (next->msg.rtTime >= message->msg.rtTime) break;
list_add_before(&next->entry, &message->entry);
PostThreadMessageW(This->procThreadId, PROCESSMSG_ADD, 0, 0);

hr = S_OK;
}
Expand Down Expand Up @@ -1440,8 +1454,20 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface,
IDirectMusicPerformance *performance, DMUS_PMSG *msg)
{
struct performance *This = impl_from_IDirectMusicTool(iface);
FIXME("(%p, %p, %p): stub\n", This, performance, msg);
return E_NOTIMPL;

FIXME("(%p, %p, %p): semi-stub\n", This, performance, msg);

switch (msg->dwType)
{
case DMUS_PMSGT_NOTIFICATION:
SetEvent(This->hNotification);
/* fallthrough */
default:
FIXME("Unhandled message type %#lx\n", msg->dwType);
break;
}

return DMUS_S_FREE;
}

static HRESULT WINAPI performance_tool_Flush(IDirectMusicTool *iface,
Expand Down Expand Up @@ -1485,8 +1511,7 @@ HRESULT create_dmperformance(REFIID iid, void **ret_iface)
obj->safe.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": performance->safe");
wine_rb_init(&obj->pchannels, pchannel_block_compare);

list_init(&obj->immediate_messages);
list_init(&obj->queued_messages);
list_init(&obj->messages);

obj->rtLatencyTime = 100; /* 100 ms TO FIX */
obj->dwBumperLength = 50; /* 50 ms default */
Expand Down
42 changes: 19 additions & 23 deletions dlls/dmime/tests/dmime.c
Original file line number Diff line number Diff line change
Expand Up @@ -1506,7 +1506,7 @@ static void test_performance_tool(void)
hr = IDirectMusicTool_GetMediaTypes(tool, (DWORD **)&types, 64);
ok(hr == E_NOTIMPL, "got %#lx\n", hr);
hr = IDirectMusicTool_ProcessPMsg(tool, performance, &msg);
todo_wine ok(hr == DMUS_S_FREE, "got %#lx\n", hr);
ok(hr == DMUS_S_FREE, "got %#lx\n", hr);
hr = IDirectMusicTool_Flush(tool, performance, &msg, 0);
todo_wine ok(hr == S_OK, "got %#lx\n", hr);

Expand Down Expand Up @@ -1859,19 +1859,18 @@ static void test_performance_pmsg(void)
ok(hr == S_OK, "got %#lx\n", hr);

ret = test_tool_wait_message(tool, 50, &msg);
todo_wine ok(!ret, "got %#lx\n", ret);
todo_wine ok(msg != NULL, "got %p\n", msg);
if (!msg) goto skip_rtime;
ok(!ret, "got %#lx\n", ret);
ok(msg != NULL, "got %p\n", msg);

time = 0xdeadbeef;
hr = IDirectMusicPerformance_MusicToReferenceTime(performance, msg->mtTime, &time);
ok(hr == S_OK, "got %#lx\n", hr);
ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize);
todo_wine ok(msg->rtTime == time, "got %I64d\n", msg->rtTime);
ok(msg->rtTime == time, "got %I64d\n", msg->rtTime);
ok(msg->mtTime == 500, "got %ld\n", msg->mtTime);
todo_wine ok(msg->dwFlags & DMUS_PMSGF_REFTIME, "got %#lx\n", msg->dwFlags);
todo_wine ok(msg->dwFlags & DMUS_PMSGF_MUSICTIME, "got %#lx\n", msg->dwFlags);
todo_wine ok(msg->dwFlags & (DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_IMMEDIATE), "got %#lx\n", msg->dwFlags);
ok(msg->dwFlags & DMUS_PMSGF_REFTIME, "got %#lx\n", msg->dwFlags);
ok(msg->dwFlags & DMUS_PMSGF_MUSICTIME, "got %#lx\n", msg->dwFlags);
ok(msg->dwFlags & (DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_IMMEDIATE), "got %#lx\n", msg->dwFlags);
ok(!msg->dwPChannel, "got %ld\n", msg->dwPChannel);
ok(!msg->dwVirtualTrackID, "got %ld\n", msg->dwVirtualTrackID);
ok(msg->pTool == tool, "got %p\n", msg->pTool);
Expand All @@ -1885,7 +1884,6 @@ static void test_performance_pmsg(void)
ok(hr == S_OK, "got %#lx\n", hr);


skip_rtime:
/* SendPMsg converts reference time to music time if it is missing */

hr = IDirectMusicPerformance_GetTime(performance, &time, &music_time);
Expand All @@ -1903,19 +1901,18 @@ static void test_performance_pmsg(void)
ok(hr == S_OK, "got %#lx\n", hr);

ret = test_tool_wait_message(tool, 50, &msg);
todo_wine ok(!ret, "got %#lx\n", ret);
todo_wine ok(msg != NULL, "got %p\n", msg);
if (!msg) goto skip_mtime;
ok(!ret, "got %#lx\n", ret);
ok(msg != NULL, "got %p\n", msg);

music_time = 0xdeadbeef;
hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, msg->rtTime, &music_time);
ok(hr == S_OK, "got %#lx\n", hr);
ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize);
todo_wine ok(msg->rtTime == time, "got %I64d\n", msg->rtTime);
todo_wine ok(msg->mtTime == music_time, "got %ld\n", msg->mtTime);
todo_wine ok(msg->dwFlags & DMUS_PMSGF_REFTIME, "got %#lx\n", msg->dwFlags);
todo_wine ok(msg->dwFlags & DMUS_PMSGF_MUSICTIME, "got %#lx\n", msg->dwFlags);
todo_wine ok(msg->dwFlags & (DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_IMMEDIATE), "got %#lx\n", msg->dwFlags);
ok(msg->rtTime == time, "got %I64d\n", msg->rtTime);
ok(msg->mtTime == music_time, "got %ld\n", msg->mtTime);
ok(msg->dwFlags & DMUS_PMSGF_REFTIME, "got %#lx\n", msg->dwFlags);
ok(msg->dwFlags & DMUS_PMSGF_MUSICTIME, "got %#lx\n", msg->dwFlags);
ok(msg->dwFlags & (DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_IMMEDIATE), "got %#lx\n", msg->dwFlags);
ok(!msg->dwPChannel, "got %ld\n", msg->dwPChannel);
ok(!msg->dwVirtualTrackID, "got %ld\n", msg->dwVirtualTrackID);
ok(msg->pTool == tool, "got %p\n", msg->pTool);
Expand All @@ -1929,7 +1926,6 @@ static void test_performance_pmsg(void)
ok(hr == S_OK, "got %#lx\n", hr);


skip_mtime:
for (i = 0; i < ARRAY_SIZE(delivery_flags); i++)
{
DWORD duration = 0;
Expand All @@ -1953,18 +1949,18 @@ static void test_performance_pmsg(void)
ok(hr == S_OK, "got %#lx\n", hr);
msg = NULL;
ret = test_tool_wait_message(tool, 1000, &msg);
todo_wine ok(!ret, "got %#lx\n", ret);
todo_wine ok(msg != NULL, "got %p\n", msg);
ok(!ret, "got %#lx\n", ret);
ok(msg != NULL, "got %p\n", msg);
duration += GetTickCount();

if (msg) hr = IDirectMusicPerformance_FreePMsg(performance, msg);
ok(hr == S_OK, "got %#lx\n", hr);

switch (delivery_flags[i])
{
case DMUS_PMSGF_TOOL_IMMEDIATE: todo_wine ok(duration <= 50, "got %lu\n", duration); break;
case DMUS_PMSGF_TOOL_QUEUE: todo_wine ok(duration >= 50 && duration <= 125, "got %lu\n", duration); break;
case DMUS_PMSGF_TOOL_ATTIME: todo_wine ok(duration >= 125 && duration <= 500, "got %lu\n", duration); break;
case DMUS_PMSGF_TOOL_IMMEDIATE: ok(duration <= 50, "got %lu\n", duration); break;
case DMUS_PMSGF_TOOL_QUEUE: ok(duration >= 50 && duration <= 125, "got %lu\n", duration); break;
case DMUS_PMSGF_TOOL_ATTIME: ok(duration >= 125 && duration <= 500, "got %lu\n", duration); break;
}
}

Expand Down

0 comments on commit 5f04740

Please sign in to comment.