wmp: Add media completion notifications.

Signed-off-by: Anton Romanov <theli.ua@gmail.com>
Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Anton Romanov 2018-04-12 22:55:00 -07:00 committed by Alexandre Julliard
parent a56e57b3ec
commit a072899794
7 changed files with 214 additions and 24 deletions

View File

@ -899,18 +899,20 @@ HRESULT WINAPI WMPFactory_CreateInstance(IClassFactory *iface, IUnknown *outer,
wmp->ref = 1;
init_player(wmp);
if (init_player(wmp)) {
ConnectionPointContainer_Init(wmp);
hdc = GetDC(0);
dpi_x = GetDeviceCaps(hdc, LOGPIXELSX);
dpi_y = GetDeviceCaps(hdc, LOGPIXELSY);
ReleaseDC(0, hdc);
ConnectionPointContainer_Init(wmp);
hdc = GetDC(0);
dpi_x = GetDeviceCaps(hdc, LOGPIXELSX);
dpi_y = GetDeviceCaps(hdc, LOGPIXELSY);
ReleaseDC(0, hdc);
wmp->extent.cx = MulDiv(192, 2540, dpi_x);
wmp->extent.cy = MulDiv(192, 2540, dpi_y);
wmp->extent.cx = MulDiv(192, 2540, dpi_x);
wmp->extent.cy = MulDiv(192, 2540, dpi_y);
hres = IOleObject_QueryInterface(&wmp->IOleObject_iface, riid, ppv);
hres = IOleObject_QueryInterface(&wmp->IOleObject_iface, riid, ppv);
} else {
hres = E_FAIL;
}
IOleObject_Release(&wmp->IOleObject_iface);
return hres;
}

View File

@ -24,6 +24,12 @@
WINE_DEFAULT_DEBUG_CHANNEL(wmp);
static ATOM player_msg_class;
static INIT_ONCE class_init_once;
static UINT WM_WMPEVENT;
static const WCHAR WMPmessageW[] = {'_', 'W', 'M', 'P', 'M','e','s','s','a','g','e',0};
static void update_state(WindowsMediaPlayer *wmp, LONG type, LONG state)
{
DISPPARAMS dispparams;
@ -212,18 +218,20 @@ static HRESULT WINAPI WMPPlayer4_put_currentMedia(IWMPPlayer4 *iface, IWMPMedia
{
WindowsMediaPlayer *This = impl_from_IWMPPlayer4(iface);
TRACE("(%p)->(%p)\n", This, pMedia);
if(pMedia == NULL) {
return E_POINTER;
}
update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, wmposPlaylistChanging);
if(This->wmpmedia != NULL) {
IWMPControls_stop(&This->IWMPControls_iface);
IWMPMedia_Release(This->wmpmedia);
}
update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, wmposPlaylistChanged);
update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, wmposPlaylistOpenNoMedia);
IWMPMedia_AddRef(pMedia);
This->wmpmedia = pMedia;
IWMPMedia_AddRef(This->wmpmedia);
return S_OK;
}
@ -1425,6 +1433,20 @@ static HRESULT WINAPI WMPControls_play(IWMPControls *iface)
(void**)&This->media_control);
if (SUCCEEDED(hres))
update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, wmposMediaOpen);
if (SUCCEEDED(hres))
hres = IGraphBuilder_QueryInterface(This->filter_graph, &IID_IMediaEvent,
(void**)&This->media_event);
if (SUCCEEDED(hres))
{
IMediaEventEx *media_event_ex = NULL;
hres = IGraphBuilder_QueryInterface(This->filter_graph, &IID_IMediaEventEx,
(void**)&media_event_ex);
if (SUCCEEDED(hres)) {
hres = IMediaEventEx_SetNotifyWindow(media_event_ex, (OAHWND)This->msg_window,
WM_WMPEVENT, (LONG_PTR)This);
IMediaEventEx_Release(media_event_ex);
}
}
}
update_state(This, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, wmppsTransitioning);
@ -1457,9 +1479,15 @@ static HRESULT WINAPI WMPControls_stop(IWMPControls *iface)
hres = IMediaControl_Stop(This->media_control);
IMediaControl_Release(This->media_control);
}
if (This->media_event) {
IMediaEvent_Release(This->media_event);
}
IGraphBuilder_Release(This->filter_graph);
This->filter_graph = NULL;
This->media_control = NULL;
This->media_event = NULL;
update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, wmposPlaylistOpenNoMedia);
update_state(This, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, wmppsStopped);
return hres;
@ -1823,8 +1851,66 @@ static const IWMPMediaVtbl WMPMediaVtbl = {
WMPMedia_isReadOnlyItem
};
void init_player(WindowsMediaPlayer *wmp)
static LRESULT WINAPI player_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (msg == WM_WMPEVENT && wParam == 0) {
WindowsMediaPlayer *wmp = (WindowsMediaPlayer*)lParam;
LONG event_code;
LONG_PTR p1, p2;
HRESULT hr;
if (wmp->media_event) {
do {
hr = IMediaEvent_GetEvent(wmp->media_event, &event_code, &p1, &p2, 0);
if (SUCCEEDED(hr)) {
TRACE("got event_code = 0x%02x\n", event_code);
IMediaEvent_FreeEventParams(wmp->media_event, event_code, p1, p2);
/* For now we only handle EC_COMPLETE */
if (event_code == EC_COMPLETE) {
update_state(wmp, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, wmppsMediaEnded);
update_state(wmp, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, wmppsTransitioning);
update_state(wmp, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, wmppsStopped);
}
}
} while (hr == S_OK);
} else {
FIXME("Got event from quartz when interfaces are already released\n");
}
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
static BOOL WINAPI register_player_msg_class(INIT_ONCE *once, void *param, void **context) {
static WNDCLASSEXW wndclass = {
sizeof(wndclass), CS_DBLCLKS, player_wnd_proc, 0, 0,
NULL, NULL, NULL, NULL, NULL,
WMPmessageW, NULL
};
wndclass.hInstance = wmp_instance;
player_msg_class = RegisterClassExW(&wndclass);
WM_WMPEVENT= RegisterWindowMessageW(WMPmessageW);
return TRUE;
}
void unregister_player_msg_class(void) {
if(player_msg_class)
UnregisterClassW(MAKEINTRESOURCEW(player_msg_class), wmp_instance);
}
BOOL init_player(WindowsMediaPlayer *wmp)
{
InitOnceExecuteOnce(&class_init_once, register_player_msg_class, NULL, NULL);
wmp->msg_window = CreateWindowW( MAKEINTRESOURCEW(player_msg_class), NULL, 0, 0,
0, 0, 0, HWND_MESSAGE, 0, wmp_instance, wmp );
if (!wmp->msg_window) {
ERR("Failed to create message window, GetLastError: %d\n", GetLastError());
return FALSE;
}
if (!WM_WMPEVENT) {
ERR("Failed to register window message, GetLastError: %d\n", GetLastError());
return FALSE;
}
wmp->IWMPPlayer4_iface.lpVtbl = &WMPPlayer4Vtbl;
wmp->IWMPPlayer_iface.lpVtbl = &WMPPlayerVtbl;
wmp->IWMPSettings_iface.lpVtbl = &WMPSettingsVtbl;
@ -1833,6 +1919,7 @@ void init_player(WindowsMediaPlayer *wmp)
wmp->invoke_urls = VARIANT_TRUE;
wmp->auto_start = VARIANT_TRUE;
return TRUE;
}
void destroy_player(WindowsMediaPlayer *wmp)
@ -1840,6 +1927,7 @@ void destroy_player(WindowsMediaPlayer *wmp)
IWMPControls_stop(&wmp->IWMPControls_iface);
if(wmp->wmpmedia)
IWMPMedia_Release(wmp->wmpmedia);
DestroyWindow(wmp->msg_window);
}
WMPMedia *unsafe_impl_from_IWMPMedia(IWMPMedia *iface)

View File

@ -40,16 +40,15 @@
called_ ## kind |= (1 << index); \
}while(0)
#define CHECK_CALLED(kind, index) \
#define CLEAR_CALLED(kind, index) \
do { \
ok(called_ ## kind & (1 << index), "expected " #kind ", %d\n", index); \
expect_ ## kind &= ~(1 << index); \
called_ ## kind &= ~(1 << index); \
}while(0)
#define CHECK_CALLED_OR_BROKEN(kind, index) \
#define CHECK_CALLED(kind, index) \
do { \
ok(called_ ## kind & (1 << index) || broken(1), "expected " #kind ", %d\n", index); \
ok(called_ ## kind & (1 << index), "expected " #kind ", %d\n", index); \
expect_ ## kind &= ~(1 << index); \
called_ ## kind &= ~(1 << index); \
}while(0)
@ -65,9 +64,11 @@ DEFINE_EXPECT(PLAYSTATE);
DEFINE_EXPECT(OPENSTATE);
static HANDLE playing_event;
static HANDLE completed_event;
static DWORD main_thread_id;
static const WCHAR mp3file[] = {'t','e','s','t','.','m','p','3',0};
static const WCHAR mp3file1s[] = {'t','e','s','t','1','s','.','m','p','3',0};
static inline WCHAR *load_resource(const WCHAR *name)
{
static WCHAR pathW[MAX_PATH];
@ -151,6 +152,8 @@ static HRESULT WINAPI WMPOCXEvents_Invoke(IDispatch *iface, DISPID dispIdMember,
CHECK_EXPECT(PLAYSTATE, V_UI4(pDispParams->rgvarg));
if (V_UI4(pDispParams->rgvarg) == wmppsPlaying) {
SetEvent(playing_event);
} else if (V_UI4(pDispParams->rgvarg) == wmppsMediaEnded) {
SetEvent(completed_event);
}
if (winetest_debug > 1)
trace("DISPID_WMPCOREEVENT_PLAYSTATECHANGE, %d\n", V_UI4(pDispParams->rgvarg));
@ -208,18 +211,16 @@ static HRESULT pump_messages(DWORD timeout, DWORD count, const HANDLE *handles)
return res;
}
static void test_wmp(void)
static void test_completion_event(void)
{
DWORD res = 0;
IWMPPlayer4 *player4;
IWMPControls *controls;
HRESULT hres;
BSTR filename;
IConnectionPointContainer *container;
IConnectionPoint *point;
IOleObject *oleobj;
static DWORD dw = 100;
IWMPSettings *settings;
hres = CoCreateInstance(&CLSID_WindowsMediaPlayer, NULL, CLSCTX_INPROC_SERVER, &IID_IOleObject, (void**)&oleobj);
if(hres == REGDB_E_CLASSNOTREG) {
@ -243,6 +244,86 @@ static void test_wmp(void)
hres = IOleObject_QueryInterface(oleobj, &IID_IWMPPlayer4, (void**)&player4);
ok(hres == S_OK, "Could not get IWMPPlayer4 iface: %08x\n", hres);
filename = SysAllocString(load_resource(mp3file1s));
SET_EXPECT(OPENSTATE, wmposPlaylistChanging);
SET_EXPECT(OPENSTATE, wmposPlaylistOpenNoMedia);
SET_EXPECT(OPENSTATE, wmposPlaylistChanged);
SET_EXPECT(OPENSTATE, wmposOpeningUnknownURL);
SET_EXPECT(OPENSTATE, wmposMediaOpen);
SET_EXPECT(OPENSTATE, wmposMediaOpening);
SET_EXPECT(PLAYSTATE, wmppsPlaying);
SET_EXPECT(PLAYSTATE, wmppsMediaEnded);
SET_EXPECT(PLAYSTATE, wmppsStopped);
SET_EXPECT(PLAYSTATE, wmppsTransitioning);
/* following two are sent on vistau64 vms only */
SET_EXPECT(OPENSTATE, wmposMediaChanging);
SET_EXPECT(PLAYSTATE, wmppsReady);
hres = IWMPPlayer4_put_URL(player4, filename);
ok(hres == S_OK, "IWMPPlayer4_put_URL failed: %08x\n", hres);
res = pump_messages(3000, 1, &completed_event);
ok(res == WAIT_OBJECT_0, "Timed out while waiting for media to complete\n");
/* following two are sent on vistau64 vms only */
CLEAR_CALLED(OPENSTATE, wmposMediaChanging);
CLEAR_CALLED(PLAYSTATE, wmppsReady);
CHECK_CALLED(OPENSTATE, wmposPlaylistChanging);
CHECK_CALLED(OPENSTATE, wmposPlaylistChanged);
CHECK_CALLED(OPENSTATE, wmposPlaylistOpenNoMedia);
CHECK_CALLED(PLAYSTATE, wmppsTransitioning);
CHECK_CALLED(OPENSTATE, wmposOpeningUnknownURL);
CHECK_CALLED(OPENSTATE, wmposMediaOpen);
CHECK_CALLED(PLAYSTATE, wmppsPlaying);
CHECK_CALLED(PLAYSTATE, wmppsMediaEnded);
CHECK_CALLED(PLAYSTATE, wmppsStopped);
/* MediaOpening happens only on xp, 2003 */
CLEAR_CALLED(OPENSTATE, wmposMediaOpening);
hres = IConnectionPoint_Unadvise(point, dw);
ok(hres == S_OK, "Unadvise failed: %08x\n", hres);
IConnectionPoint_Release(point);
IWMPPlayer4_Release(player4);
IOleObject_Release(oleobj);
DeleteFileW(filename);
SysFreeString(filename);
}
static BOOL test_wmp(void)
{
DWORD res = 0;
IWMPPlayer4 *player4;
IWMPControls *controls;
HRESULT hres;
BSTR filename;
IConnectionPointContainer *container;
IConnectionPoint *point;
IOleObject *oleobj;
static DWORD dw = 100;
IWMPSettings *settings;
BOOL test_ran = TRUE;
hres = CoCreateInstance(&CLSID_WindowsMediaPlayer, NULL, CLSCTX_INPROC_SERVER, &IID_IOleObject, (void**)&oleobj);
if(hres == REGDB_E_CLASSNOTREG) {
win_skip("CLSID_WindowsMediaPlayer not registered\n");
return FALSE;
}
ok(hres == S_OK, "Could not create CLSID_WindowsMediaPlayer instance: %08x\n", hres);
hres = IOleObject_QueryInterface(oleobj, &IID_IConnectionPointContainer, (void**)&container);
ok(hres == S_OK, "QueryInterface(IID_IConnectionPointContainer) failed: %08x\n", hres);
hres = IConnectionPointContainer_FindConnectionPoint(container, &IID__WMPOCXEvents, &point);
IConnectionPointContainer_Release(container);
ok(hres == S_OK, "FindConnectionPoint failed: %08x\n", hres);
hres = IConnectionPoint_Advise(point, (IUnknown*)&WMPOCXEvents, &dw);
ok(hres == S_OK, "Advise failed: %08x\n", hres);
hres = IOleObject_QueryInterface(oleobj, &IID_IWMPPlayer4, (void**)&player4);
ok(hres == S_OK, "Could not get IWMPPlayer4 iface: %08x\n", hres);
settings = NULL;
hres = IWMPPlayer4_get_settings(player4, &settings);
ok(hres == S_OK, "get_settings failed: %08x\n", hres);
@ -277,9 +358,10 @@ static void test_wmp(void)
SET_EXPECT(OPENSTATE, wmposOpeningUnknownURL);
SET_EXPECT(OPENSTATE, wmposMediaOpen);
SET_EXPECT(OPENSTATE, wmposMediaOpening);
SET_EXPECT(PLAYSTATE, wmppsPlaying);
SET_EXPECT(PLAYSTATE, wmppsTransitioning);
/* MediaOpening happens only on xp, 2003 */
SET_EXPECT(OPENSTATE, wmposMediaOpening);
hres = IWMPControls_play(controls);
ok(hres == S_OK, "IWMPControls_play failed: %08x\n", hres);
res = pump_messages(5000, 1, &playing_event);
@ -288,14 +370,15 @@ static void test_wmp(void)
/* This happens on Vista Ultimate 64 vms
* I have been unable to find out source of this behaviour */
win_skip("Failed to transition media to playing state.\n");
test_ran = FALSE;
goto playback_skip;
}
CHECK_CALLED(OPENSTATE, wmposOpeningUnknownURL);
CHECK_CALLED(OPENSTATE, wmposMediaOpen);
/* MediaOpening happens only on xp, 2003 */
todo_wine CHECK_CALLED_OR_BROKEN(OPENSTATE, wmposMediaOpening);
CHECK_CALLED(PLAYSTATE, wmppsPlaying);
CHECK_CALLED(PLAYSTATE, wmppsTransitioning);
/* MediaOpening happens only on xp, 2003 */
CLEAR_CALLED(OPENSTATE, wmposMediaOpening);
SET_EXPECT(PLAYSTATE, wmppsStopped);
/* The following happens on wine only since we close media on stop */
@ -331,6 +414,8 @@ playback_skip:
IOleObject_Release(oleobj);
DeleteFileW(filename);
SysFreeString(filename);
return test_ran;
}
START_TEST(media)
@ -339,9 +424,15 @@ START_TEST(media)
main_thread_id = GetCurrentThreadId();
playing_event = CreateEventW(NULL, FALSE, FALSE, NULL);
test_wmp();
completed_event = CreateEventW(NULL, FALSE, FALSE, NULL);
if (test_wmp()) {
test_completion_event();
} else {
win_skip("Failed to play media\n");
}
CloseHandle(playing_event);
CloseHandle(completed_event);
CoUninitialize();
}

View File

@ -21,3 +21,6 @@
/* ffmpeg -ar 48000 -t 60 -f s16le -acodec pcm_s16le -ac 2 -i /dev/zero -acodec libmp3lame -aq 4 output.mp3 */
/* @makedep: test.mp3 */
test.mp3 RCDATA "test.mp3"
/* ffmpeg -ar 48000 -t 1 -f s16le -acodec pcm_s16le -ac 2 -i /dev/zero -acodec libmp3lame -aq 4 test1s.mp3 */
/* @makedep: test1s.mp3 */
test1s.mp3 RCDATA "test1s.mp3"

BIN
dlls/wmp/tests/test1s.mp3 Normal file

Binary file not shown.

View File

@ -92,6 +92,7 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
break;
case DLL_PROCESS_DETACH:
unregister_wmp_class();
unregister_player_msg_class();
break;
}

View File

@ -75,9 +75,13 @@ struct WindowsMediaPlayer {
/* DirectShow stuff */
IGraphBuilder* filter_graph;
IMediaControl* media_control;
IMediaEvent* media_event;
/* Async event notification */
HWND msg_window;
};
void init_player(WindowsMediaPlayer*) DECLSPEC_HIDDEN;
BOOL init_player(WindowsMediaPlayer*) DECLSPEC_HIDDEN;
void destroy_player(WindowsMediaPlayer*) DECLSPEC_HIDDEN;
WMPMedia *unsafe_impl_from_IWMPMedia(IWMPMedia *iface) DECLSPEC_HIDDEN;
HRESULT create_media_from_url(BSTR url, IWMPMedia **ppMedia) DECLSPEC_HIDDEN;
@ -88,6 +92,7 @@ void call_sink(ConnectionPoint *This, DISPID dispid, DISPPARAMS *dispparams) DEC
HRESULT WINAPI WMPFactory_CreateInstance(IClassFactory*,IUnknown*,REFIID,void**) DECLSPEC_HIDDEN;
void unregister_wmp_class(void) DECLSPEC_HIDDEN;
void unregister_player_msg_class(void) DECLSPEC_HIDDEN;
extern HINSTANCE wmp_instance DECLSPEC_HIDDEN;