From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmime/dmime_private.h | 4 +- dlls/dmime/performance.c | 21 +++++++- dlls/dmime/segmentstate.c | 98 +++++++++++++++++++++++++++++++++++++- dlls/dmime/tests/dmime.c | 14 +++--- 4 files changed, 125 insertions(+), 12 deletions(-)
diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h index c35c52eb066..e67797def30 100644 --- a/dlls/dmime/dmime_private.h +++ b/dlls/dmime/dmime_private.h @@ -71,7 +71,9 @@ extern void set_audiopath_dsound_buffer(IDirectMusicAudioPath*,IDirectSoundBuffe extern void set_audiopath_primary_dsound_buffer(IDirectMusicAudioPath*,IDirectSoundBuffer*);
extern HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time, - IDirectMusicSegmentState **ret_iface); + IDirectMusicPerformance *performance, IDirectMusicSegmentState **ret_iface); +extern HRESULT segment_state_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance *performance); +extern HRESULT segment_state_end_play(IDirectMusicSegmentState *iface);
/***************************************************************************** * Auxiliary definitions diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 3d53d754d11..7d077db16cb 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1052,7 +1052,14 @@ static HRESULT WINAPI performance_CloseDown(IDirectMusicPerformance8 *iface) list_remove(&message->entry); list_init(&message->entry);
- if (FAILED(hr = IDirectMusicPerformance8_FreePMsg(iface, &message->msg))) + /* process notifications to end any pending segment states */ + if (message->msg.dwType == DMUS_PMSGT_NOTIFICATION) + hr = IDirectMusicTool_ProcessPMsg(&This->IDirectMusicTool_iface, + (IDirectMusicPerformance *)iface, &message->msg); + else + hr = DMUS_S_FREE; + + if (hr == DMUS_S_FREE && FAILED(hr = IDirectMusicPerformance8_FreePMsg(iface, &message->msg))) WARN("Failed to free message %p, hr %#lx\n", message, hr); }
@@ -1191,7 +1198,7 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface,
if (FAILED(hr = IUnknown_QueryInterface(source, &IID_IDirectMusicSegment, (void **)&segment))) return hr; - if (FAILED(hr = segment_state_create(segment, start_time, &state))) + if (FAILED(hr = segment_state_create(segment, start_time, (IDirectMusicPerformance *)iface, &state))) { IDirectMusicSegment_Release(segment); return hr; @@ -1207,6 +1214,9 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, if (SUCCEEDED(hr)) hr = performance_send_dirty_pmsg(This, start_time);
+ if (SUCCEEDED(hr)) + hr = segment_state_play(state, (IDirectMusicPerformance *)iface); + if (SUCCEEDED(hr)) hr = performance_send_notification_pmsg(This, start_time + length, This->notification_segment, GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGEND, (IUnknown *)state); @@ -1634,6 +1644,13 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, BOOL enabled = FALSE; HRESULT hr;
+ if (IsEqualGUID(¬if->guidNotificationType, &GUID_NOTIFICATION_SEGMENT) + && notif->dwNotificationOption == DMUS_NOTIFICATION_SEGEND) + { + if (FAILED(hr = segment_state_end_play((IDirectMusicSegmentState *)notif->punkUser))) + WARN("Failed to end segment state %p, hr %#lx\n", notif->punkUser, hr); + } + if (IsEqualGUID(¬if->guidNotificationType, &GUID_NOTIFICATION_PERFORMANCE)) enabled = This->notification_performance; if (IsEqualGUID(¬if->guidNotificationType, &GUID_NOTIFICATION_SEGMENT)) diff --git a/dlls/dmime/segmentstate.c b/dlls/dmime/segmentstate.c index 1a09bed5dd3..de47d85e9b8 100644 --- a/dlls/dmime/segmentstate.c +++ b/dlls/dmime/segmentstate.c @@ -21,14 +21,39 @@
WINE_DEFAULT_DEBUG_CHANNEL(dmime);
+static DWORD next_track_id; + +struct track_entry +{ + struct list entry; + + IDirectMusicTrack *track; + void *state_data; + DWORD track_id; +}; + +static void track_entry_destroy(struct track_entry *entry) +{ + HRESULT hr; + + if (FAILED(hr = IDirectMusicTrack_EndPlay(entry->track, entry->state_data))) + WARN("track %p EndPlay failed, hr %#lx\n", entry->track, hr); + + IDirectMusicTrack_Release(entry->track); + free(entry); +} + struct segment_state { IDirectMusicSegmentState8 IDirectMusicSegmentState8_iface; LONG ref;
IDirectMusicSegment *segment; - MUSIC_TIME start_point; MUSIC_TIME start_time; + MUSIC_TIME start_point; + MUSIC_TIME end_point; + + struct list tracks; };
static inline struct segment_state *impl_from_IDirectMusicSegmentState8(IDirectMusicSegmentState8 *iface) @@ -79,6 +104,7 @@ static ULONG WINAPI segment_state_Release(IDirectMusicSegmentState8 *iface)
if (!ref) { + segment_state_end_play((IDirectMusicSegmentState *)iface); if (This->segment) IDirectMusicSegment_Release(This->segment); free(This); } @@ -174,6 +200,7 @@ HRESULT create_dmsegmentstate(REFIID riid, void **ret_iface) obj->IDirectMusicSegmentState8_iface.lpVtbl = &segment_state_vtbl; obj->ref = 1; obj->start_time = -1; + list_init(&obj->tracks);
TRACE("Created IDirectMusicSegmentState %p\n", obj); hr = IDirectMusicSegmentState8_QueryInterface(&obj->IDirectMusicSegmentState8_iface, riid, ret_iface); @@ -182,11 +209,13 @@ HRESULT create_dmsegmentstate(REFIID riid, void **ret_iface) }
HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time, - IDirectMusicSegmentState **ret_iface) + IDirectMusicPerformance *performance, IDirectMusicSegmentState **ret_iface) { IDirectMusicSegmentState *iface; struct segment_state *This; + IDirectMusicTrack *track; HRESULT hr; + UINT i;
TRACE("(%p, %lu, %p)\n", segment, start_time, ret_iface);
@@ -198,8 +227,73 @@ HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time
This->start_time = start_time; hr = IDirectMusicSegment_GetStartPoint(segment, &This->start_point); + if (SUCCEEDED(hr)) hr = IDirectMusicSegment_GetLength(segment, &This->end_point); + + for (i = 0; SUCCEEDED(hr); i++) + { + DWORD track_id = ++next_track_id; + struct track_entry *entry; + + if ((hr = IDirectMusicSegment_GetTrack(segment, &GUID_NULL, -1, i, &track)) != S_OK) + { + if (hr == DMUS_E_NOT_FOUND) hr = S_OK; + break; + } + + if (!(entry = malloc(sizeof(*entry)))) + hr = E_OUTOFMEMORY; + else if (SUCCEEDED(hr = IDirectMusicTrack_InitPlay(track, iface, performance, + &entry->state_data, track_id, 0))) + { + entry->track = track; + entry->track_id = track_id; + list_add_tail(&This->tracks, &entry->entry); + } + + if (FAILED(hr)) + { + WARN("Failed to initialize track %p, hr %#lx\n", track, hr); + IDirectMusicTrack_Release(track); + free(entry); + } + }
if (SUCCEEDED(hr)) *ret_iface = iface; else IDirectMusicSegmentState_Release(iface); return hr; } + +HRESULT segment_state_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance *performance) +{ + struct segment_state *This = impl_from_IDirectMusicSegmentState8((IDirectMusicSegmentState8 *)iface); + DWORD track_flags = DMUS_TRACKF_DIRTY | DMUS_TRACKF_START | DMUS_TRACKF_SEEK; + MUSIC_TIME start_time = This->start_point, end_time = This->end_point; + struct track_entry *entry; + HRESULT hr = S_OK; + + LIST_FOR_EACH_ENTRY(entry, &This->tracks, struct track_entry, entry) + { + if (FAILED(hr = IDirectMusicTrack_Play(entry->track, entry->state_data, start_time, + end_time, 0, track_flags, performance, iface, entry->track_id))) + { + WARN("Failed to play track %p, hr %#lx\n", entry->track, hr); + break; + } + } + + return hr; +} + +HRESULT segment_state_end_play(IDirectMusicSegmentState *iface) +{ + struct segment_state *This = impl_from_IDirectMusicSegmentState8((IDirectMusicSegmentState8 *)iface); + struct track_entry *entry, *next; + + LIST_FOR_EACH_ENTRY_SAFE(entry, next, &This->tracks, struct track_entry, entry) + { + list_remove(&entry->entry); + track_entry_destroy(entry); + } + + return S_OK; +} diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index f9143176594..cb35ef64ead 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -662,7 +662,7 @@ static HRESULT WINAPI test_track_Play(IDirectMusicTrack *iface, void *state_data ok(state_data == &This->data, "got %p\n", state_data); ok(start_time == 50, "got %lu\n", start_time); ok(end_time == 100, "got %lu\n", end_time); - ok(time_offset < 0, "got %lu\n", time_offset); + todo_wine ok(time_offset < 0, "got %lu\n", time_offset); ok(segment_flags == (DMUS_TRACKF_DIRTY|DMUS_TRACKF_START|DMUS_TRACKF_SEEK), "got %#lx\n", segment_flags); ok(!!performance, "got %p\n", performance); @@ -3990,7 +3990,7 @@ static void test_segment_state(void) IDirectMusicSegmentState_Release(tmp_state);
check_track_state(track, downloaded, FALSE); - todo_wine check_track_state(track, initialized, TRUE); + check_track_state(track, initialized, TRUE);
/* The track can be removed from the segment */ @@ -4001,10 +4001,10 @@ static void test_segment_state(void) /* This might be timing dependent and if PlaySegment is already * late, the tracks are played synchronously and right away. */ - check_track_state(track, playing, FALSE); + todo_wine check_track_state(track, playing, FALSE);
ret = test_track_wait_playing(track, 50); - todo_wine ok(ret == 0, "got %#lx\n", ret); + ok(ret == 0, "got %#lx\n", ret);
tmp_segment = (void *)0xdeadbeef; @@ -4064,14 +4064,14 @@ static void test_segment_state(void)
check_track_state(track, downloaded, FALSE); - todo_wine check_track_state(track, initialized, TRUE); - todo_wine check_track_state(track, playing, TRUE); + check_track_state(track, initialized, TRUE); + check_track_state(track, playing, TRUE);
hr = IDirectMusicPerformance_CloseDown(performance); ok(hr == S_OK, "got %#lx\n", hr);
check_track_state(track, downloaded, FALSE); - todo_wine check_track_state(track, initialized, TRUE); + check_track_state(track, initialized, TRUE); check_track_state(track, playing, FALSE);