Module: wine Branch: master Commit: 56043971350831234a7a6306d2d5f9fbd0ff63bc URL: https://gitlab.winehq.org/wine/wine/-/commit/56043971350831234a7a6306d2d5f9f...
Author: Rémi Bernon rbernon@codeweavers.com Date: Wed Oct 25 09:37:24 2023 +0200
dmime: Implement segment state chunked playback.
---
dlls/dmime/dmime_private.h | 3 +++ dlls/dmime/performance.c | 66 ++++++++++++++++++++++++++++++++++++++++------ dlls/dmime/segmentstate.c | 53 ++++++++++++++++++++++++++++++++----- 3 files changed, 107 insertions(+), 15 deletions(-)
diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h index 28836694ed9..212ee254192 100644 --- a/dlls/dmime/dmime_private.h +++ b/dlls/dmime/dmime_private.h @@ -75,12 +75,15 @@ extern void set_audiopath_primary_dsound_buffer(IDirectMusicAudioPath*,IDirectSo extern HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time, IDirectMusicPerformance8 *performance, IDirectMusicSegmentState **ret_iface); extern HRESULT segment_state_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance); +extern HRESULT segment_state_tick(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance); extern HRESULT segment_state_end_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance);
extern HRESULT wave_track_create_from_chunk(IStream *stream, struct chunk_entry *parent, IDirectMusicTrack8 **ret_iface);
extern HRESULT performance_get_dsound(IDirectMusicPerformance8 *iface, IDirectSound **dsound); +extern HRESULT performance_send_segment_tick(IDirectMusicPerformance8 *iface, MUSIC_TIME music_time, + IDirectMusicSegmentState *state); extern HRESULT performance_send_segment_end(IDirectMusicPerformance8 *iface, MUSIC_TIME music_time, IDirectMusicSegmentState *state);
diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 7ab11773314..6f77f8677ba 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -28,6 +28,7 @@ enum dmus_internal_message_type { DMUS_PMSGT_INTERNAL_FIRST = 0x10, DMUS_PMSGT_INTERNAL_SEGMENT_END = DMUS_PMSGT_INTERNAL_FIRST, + DMUS_PMSGT_INTERNAL_SEGMENT_TICK, };
struct pchannel_block { @@ -275,6 +276,43 @@ static inline struct performance *impl_from_IDirectMusicPerformance8(IDirectMusi return CONTAINING_RECORD(iface, struct performance, IDirectMusicPerformance8_iface); }
+static HRESULT performance_send_segment_start(IDirectMusicPerformance8 *iface, MUSIC_TIME music_time, + IDirectMusicSegmentState *state) +{ + struct performance *This = impl_from_IDirectMusicPerformance8(iface); + HRESULT hr; + + if (FAILED(hr = performance_send_notification_pmsg(This, music_time, This->notification_performance, + GUID_NOTIFICATION_PERFORMANCE, DMUS_NOTIFICATION_MUSICSTARTED, NULL))) + return hr; + if (FAILED(hr = performance_send_notification_pmsg(This, music_time, This->notification_segment, + GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGSTART, (IUnknown *)state))) + return hr; + if (FAILED(hr = performance_send_pmsg(This, music_time, DMUS_PMSGF_TOOL_IMMEDIATE, + DMUS_PMSGT_DIRTY, NULL))) + return hr; + + return S_OK; +} + +HRESULT performance_send_segment_tick(IDirectMusicPerformance8 *iface, MUSIC_TIME music_time, + IDirectMusicSegmentState *state) +{ + struct performance *This = impl_from_IDirectMusicPerformance8(iface); + REFERENCE_TIME time; + HRESULT hr; + + if (FAILED(hr = IDirectMusicPerformance8_MusicToReferenceTime(iface, music_time, &time))) + return hr; + if (FAILED(hr = IDirectMusicPerformance8_ReferenceToMusicTime(iface, time + 2000000, &music_time))) + return hr; + if (FAILED(hr = performance_send_pmsg(This, music_time, DMUS_PMSGF_TOOL_QUEUE, + DMUS_PMSGT_INTERNAL_SEGMENT_TICK, (IUnknown *)state))) + return hr; + + return S_OK; +} + HRESULT performance_send_segment_end(IDirectMusicPerformance8 *iface, MUSIC_TIME music_time, IDirectMusicSegmentState *state) { @@ -1235,16 +1273,11 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, return hr; }
+ EnterCriticalSection(&This->safe); + hr = IDirectMusicSegment_GetLength(segment, &length); if (SUCCEEDED(hr)) - hr = performance_send_notification_pmsg(This, music_time, This->notification_performance, - GUID_NOTIFICATION_PERFORMANCE, DMUS_NOTIFICATION_MUSICSTARTED, NULL); - if (SUCCEEDED(hr)) - hr = performance_send_notification_pmsg(This, music_time, This->notification_segment, - GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGSTART, (IUnknown *)state); - if (SUCCEEDED(hr)) - hr = performance_send_pmsg(This, music_time, DMUS_PMSGF_TOOL_IMMEDIATE, DMUS_PMSGT_DIRTY, NULL); - + hr = performance_send_segment_start(iface, music_time, state); if (SUCCEEDED(hr)) hr = segment_state_play(state, iface);
@@ -1266,6 +1299,8 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, IDirectMusicSegmentState_AddRef(state); }
+ LeaveCriticalSection(&This->safe); + IDirectMusicSegmentState_Release(state); IDirectMusicSegment_Release(segment); return hr; @@ -1839,6 +1874,21 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, WARN("Failed to play wave buffer, hr %#lx\n", hr); break;
+ case DMUS_PMSGT_INTERNAL_SEGMENT_TICK: + msg->rtTime += 10000000; + msg->dwFlags &= ~DMUS_PMSGF_MUSICTIME; + + /* re-send the tick message until segment_state_tick returns S_FALSE */ + if (FAILED(hr = segment_state_tick((IDirectMusicSegmentState *)msg->punkUser, + (IDirectMusicPerformance8 *)performance))) + ERR("Failed to tick segment state %p, hr %#lx\n", msg->punkUser, hr); + else if (hr == S_FALSE) + return DMUS_S_FREE; /* done ticking */ + else if (FAILED(hr = IDirectMusicPerformance_SendPMsg(performance, msg))) + ERR("Failed to queue tick for segment state %p, hr %#lx\n", msg->punkUser, hr); + + return S_OK; + case DMUS_PMSGT_INTERNAL_SEGMENT_END: if (FAILED(hr = segment_state_end_play((IDirectMusicSegmentState *)msg->punkUser, (IDirectMusicPerformance8 *)performance))) diff --git a/dlls/dmime/segmentstate.c b/dlls/dmime/segmentstate.c index 21b98ccc14c..fa49d06836b 100644 --- a/dlls/dmime/segmentstate.c +++ b/dlls/dmime/segmentstate.c @@ -51,6 +51,7 @@ struct segment_state MUSIC_TIME start_time; MUSIC_TIME start_point; MUSIC_TIME end_point; + MUSIC_TIME played; BOOL auto_download;
struct list tracks; @@ -271,25 +272,63 @@ HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time return hr; }
-HRESULT segment_state_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance) +static HRESULT segment_state_play_chunk(struct segment_state *This, IDirectMusicPerformance8 *performance, + REFERENCE_TIME duration, DWORD track_flags) { - 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; + IDirectMusicSegmentState *iface = (IDirectMusicSegmentState *)&This->IDirectMusicSegmentState8_iface; + MUSIC_TIME next_time, played; struct track_entry *entry; + REFERENCE_TIME time; HRESULT hr = S_OK;
+ if (FAILED(hr = IDirectMusicPerformance8_MusicToReferenceTime(performance, + This->start_time + This->played, &time))) + return hr; + if (FAILED(hr = IDirectMusicPerformance8_ReferenceToMusicTime(performance, + time + duration, &next_time))) + return hr; + played = min(next_time - This->start_time, This->end_point - This->start_point); + 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, - This->start_time, track_flags, (IDirectMusicPerformance *)performance, iface, entry->track_id))) + if (FAILED(hr = IDirectMusicTrack_Play(entry->track, entry->state_data, + This->start_point + This->played, This->start_point + played, + This->start_time, track_flags, (IDirectMusicPerformance *)performance, + iface, entry->track_id))) { WARN("Failed to play track %p, hr %#lx\n", entry->track, hr); break; } }
- return hr; + This->played = played; + if (This->start_point + This->played >= This->end_point) + return S_FALSE; + return S_OK; +} + +HRESULT segment_state_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance) +{ + struct segment_state *This = impl_from_IDirectMusicSegmentState8((IDirectMusicSegmentState8 *)iface); + HRESULT hr; + + TRACE("%p %p\n", iface, performance); + + if (FAILED(hr = segment_state_play_chunk(This, performance, 10000000, + DMUS_TRACKF_START | DMUS_TRACKF_SEEK | DMUS_TRACKF_DIRTY))) + return hr; + + if (hr == S_FALSE) return S_OK; + return performance_send_segment_tick(performance, This->start_time, iface); +} + +HRESULT segment_state_tick(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance) +{ + struct segment_state *This = impl_from_IDirectMusicSegmentState8((IDirectMusicSegmentState8 *)iface); + + TRACE("%p %p\n", iface, performance); + + return segment_state_play_chunk(This, performance, 10000000, 0); }
HRESULT segment_state_end_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance)