Signed-off-by: Anton Romanov theli.ua@gmail.com --- dlls/wmp/player.c | 91 +++++++++++++++++++++++++++++++--- dlls/wmp/tests/Makefile.in | 2 +- dlls/wmp/tests/av.mp4 | Bin 1493 -> 0 bytes dlls/wmp/tests/media.c | 120 +++++++++++++++++++++++++++++++++++++++++++++ dlls/wmp/tests/oleobj.c | 6 +-- dlls/wmp/tests/rsrc.rc | 5 +- dlls/wmp/tests/test.mp3 | Bin 0 -> 240333 bytes dlls/wmp/wmp_private.h | 8 ++- 8 files changed, 217 insertions(+), 15 deletions(-) delete mode 100644 dlls/wmp/tests/av.mp4 create mode 100644 dlls/wmp/tests/media.c create mode 100644 dlls/wmp/tests/test.mp3
diff --git a/dlls/wmp/player.c b/dlls/wmp/player.c index 4a0d0742fd..b6f6b325ec 100644 --- a/dlls/wmp/player.c +++ b/dlls/wmp/player.c @@ -19,6 +19,7 @@ #include "wmp_private.h"
#include "wine/debug.h" +#include <nserror.h>
WINE_DEFAULT_DEBUG_CHANNEL(wmp);
@@ -119,12 +120,20 @@ static HRESULT WINAPI WMPPlayer4_put_URL(IWMPPlayer4 *iface, BSTR url) { WindowsMediaPlayer *This = impl_from_IWMPPlayer4(iface); IWMPMedia *media; + HRESULT hres; TRACE("(%p)->(%s)\n", This, debugstr_w(url)); if(url == NULL) { return E_POINTER; } - media = create_media_from_url(url); - return IWMPPlayer4_put_currentMedia(iface, media); + hres = create_media_from_url(url, &media); + if (SUCCEEDED(hres)) { + hres = IWMPPlayer4_put_currentMedia(iface, media); + IWMPMedia_Release(media); /* put will addref */ + } + if (SUCCEEDED(hres) && This->auto_start) { + hres = IWMPControls_play(&This->IWMPControls_iface); + } + return hres; }
static HRESULT WINAPI WMPPlayer4_get_openState(IWMPPlayer4 *iface, WMPOpenState *pwmpos) @@ -1357,16 +1366,62 @@ static HRESULT WINAPI WMPControls_get_isAvailable(IWMPControls *iface, BSTR bstr
static HRESULT WINAPI WMPControls_play(IWMPControls *iface) { + HRESULT hres = S_OK; WindowsMediaPlayer *This = impl_from_IWMPControls(iface); - FIXME("(%p)\n", This); - return E_NOTIMPL; + WMPMedia *media; + + TRACE("(%p)\n", This); + + if (!This->wmpmedia) { + return NS_S_WMPCORE_COMMAND_NOT_AVAILABLE; + } + + media = unsafe_impl_from_IWMPMedia(This->wmpmedia); + if (!media) { + FIXME("No support for non-builtin IWMPMedia implementations\n"); + return E_INVALIDARG; + } + + if (!This->filter_graph) { + hres = CoCreateInstance(&CLSID_FilterGraph, + NULL, + CLSCTX_INPROC_SERVER, + &IID_IGraphBuilder, + (void **)&This->filter_graph); + if (SUCCEEDED(hres)) + hres = IGraphBuilder_RenderFile(This->filter_graph, media->url, NULL); + if (SUCCEEDED(hres)) + hres = IGraphBuilder_QueryInterface(This->filter_graph, &IID_IMediaControl, + (void**)&This->media_control); + } + + if (SUCCEEDED(hres)) + hres = IMediaControl_Run(This->media_control); + + if (hres == S_FALSE) { + hres = S_OK; /* S_FALSE will mean that graph is transitioning and that is fine */ + } + return hres; }
static HRESULT WINAPI WMPControls_stop(IWMPControls *iface) { + HRESULT hres = S_OK; WindowsMediaPlayer *This = impl_from_IWMPControls(iface); - FIXME("(%p)\n", This); - return E_NOTIMPL; + TRACE("(%p)\n", This); + if (!This->filter_graph) { + return NS_S_WMPCORE_COMMAND_NOT_AVAILABLE; + } + if (This->media_control) { + hres = IMediaControl_Stop(This->media_control); + IMediaControl_Release(This->media_control); + } + if (This->filter_graph) { + IGraphBuilder_Release(This->filter_graph); + } + This->filter_graph = NULL; + This->media_control = NULL; + return hres; }
static HRESULT WINAPI WMPControls_pause(IWMPControls *iface) @@ -1741,16 +1796,36 @@ void init_player(WindowsMediaPlayer *wmp)
void destroy_player(WindowsMediaPlayer *wmp) { + IWMPControls_stop(&wmp->IWMPControls_iface); if(wmp->wmpmedia) IWMPMedia_Release(wmp->wmpmedia); }
-IWMPMedia* create_media_from_url(BSTR url){ +WMPMedia *unsafe_impl_from_IWMPMedia(IWMPMedia *iface) +{ + if (iface->lpVtbl == &WMPMediaVtbl) { + return CONTAINING_RECORD(iface, WMPMedia, IWMPMedia_iface); + } + return NULL; +}
+HRESULT create_media_from_url(BSTR url, IWMPMedia **ppMedia) +{ WMPMedia *media = heap_alloc_zero(sizeof(WMPMedia)); + + if (!media) { + return E_OUTOFMEMORY; + } + media->IWMPMedia_iface.lpVtbl = &WMPMediaVtbl; media->url = heap_strdupW(url); media->ref = 1;
- return &media->IWMPMedia_iface; + if (media->url) { + *ppMedia = &media->IWMPMedia_iface; + + return S_OK; + } + IWMPMedia_Release(&media->IWMPMedia_iface); + return E_OUTOFMEMORY; } diff --git a/dlls/wmp/tests/Makefile.in b/dlls/wmp/tests/Makefile.in index dded3a4a7e..b4ecf3ffda 100644 --- a/dlls/wmp/tests/Makefile.in +++ b/dlls/wmp/tests/Makefile.in @@ -1,7 +1,7 @@ TESTDLL = wmp.dll IMPORTS = ole32 oleaut32 user32 gdi32
-C_SRCS = oleobj.c +C_SRCS = oleobj.c media.c
RC_SRCS = \ rsrc.rc diff --git a/dlls/wmp/tests/av.mp4 b/dlls/wmp/tests/av.mp4 deleted file mode 100644 index 1431e98dd3f5bb28c282d3d732a3a1fc13cf3d63..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001
literal 1493 zcmeHHO-sW-5Z$D$cn}OyK`=rq^=7}c+G`IUJa`ik#7o*uZD_U$*=<2j`7uHf{1GDl z1OJ2v!Gm5r>6;{NZ56!et&eVJ_RZ{@-Py2=F|(~MeMfqNF`bdc*b#oM${1U02eu9V zMQ}^yjZE%({o@Y&97zZ2!~blBKX3W>_ST2tck=HTAD{cZ@Vo&eT`}nJY3bAx=4GZa z`b{u30X;KsOfrA+Qdsb;0;`MQx#~tW!HuCOUU|%5K~!R<&M$QfHdhiFrtM0VXpus! z8w+y59SdAe@Y%E99^ge_ClAreVu!myqQRus?~Q!2$C&d&tH)iNa<paP^xAL?DW*gV zJmyUv*c2zwHkSH<n@jvhshTeQ3#sJjGAQR1Zxn5mK=T+nGsvN>0=u^4bYPYW!*CPt zTN*aoSS3n(!+3qqfYDcs1sIL`ye3uDqbLP`;L_xqDBmInpmH=QpDe|$U`GJ2p{zzd z&Pvttk^tpyV>J6*S+Hlqjx2@qU;BwW2rS>HV~<gE;!E4QQ633y;7KMC5@ko$puM+W Ks#QwWO7#=93TT)B
diff --git a/dlls/wmp/tests/media.c b/dlls/wmp/tests/media.c new file mode 100644 index 0000000000..6e4a0c170f --- /dev/null +++ b/dlls/wmp/tests/media.c @@ -0,0 +1,120 @@ +/* + * 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 WIN32_LEAN_AND_MEAN +#define COBJMACROS +#include <wmp.h> +#include <olectl.h> +#include <nserror.h> + +#include "wine/test.h" + +static const WCHAR mp3file[] = {'t','e','s','t','.','m','p','3',0}; +static inline WCHAR *load_resource(const WCHAR *name) +{ + static WCHAR pathW[MAX_PATH]; + DWORD written; + HANDLE file; + HRSRC res; + void *ptr; + + GetTempPathW(sizeof(pathW)/sizeof(WCHAR), pathW); + lstrcatW(pathW, name); + + file = CreateFileW(pathW, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "file creation failed, at %s, error %d\n", wine_dbgstr_w(pathW), + GetLastError()); + + res = FindResourceW(NULL, name, (LPCWSTR)RT_RCDATA); + ok( res != 0, "couldn't find resource\n" ); + ptr = LockResource( LoadResource( GetModuleHandleA(NULL), res )); + WriteFile( file, ptr, SizeofResource( GetModuleHandleA(NULL), res ), &written, NULL ); + ok( written == SizeofResource( GetModuleHandleA(NULL), res ), "couldn't write resource\n" ); + CloseHandle( file ); + + return pathW; +} + +static void test_wmp(void) +{ + IWMPPlayer4 *player4; + IWMPControls *controls; + HRESULT hres; + BSTR filename; + + IOleObject *oleobj; + IWMPSettings *settings; + + 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; + } + ok(hres == S_OK, "Could not create CLSID_WindowsMediaPlayer instance: %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); + ok(settings != NULL, "settings = NULL\n"); + + hres = IWMPSettings_put_autoStart(settings, VARIANT_FALSE); + ok(hres == S_OK, "Could not put autoStart in IWMPSettings: %08x\n", hres); + IWMPSettings_Release(settings); + + controls = NULL; + hres = IWMPPlayer4_get_controls(player4, &controls); + ok(hres == S_OK, "get_controls failed: %08x\n", hres); + ok(controls != NULL, "controls = NULL\n"); + + hres = IWMPControls_play(controls); + ok(hres == NS_S_WMPCORE_COMMAND_NOT_AVAILABLE, "IWMPControls_play is available: %08x\n", hres); + + filename = SysAllocString(load_resource(mp3file)); + + hres = IWMPPlayer4_put_URL(player4, filename); + ok(hres == S_OK, "IWMPPlayer4_put_URL failed: %08x\n", hres); + + hres = IWMPControls_play(controls); + ok(hres == S_OK, "IWMPControls_play failed: %08x\n", hres); + + hres = IWMPControls_stop(controls); + ok(hres == S_OK, "IWMPControls_stop failed: %08x\n", hres); + + /* Already Stopped */ + hres = IWMPControls_stop(controls); + ok(hres == NS_S_WMPCORE_COMMAND_NOT_AVAILABLE, "IWMPControls_stop is available: %08x\n", hres); + + hres = IWMPControls_play(controls); + ok(hres == S_OK, "IWMPControls_play failed: %08x\n", hres); + + IWMPControls_Release(controls); + IWMPPlayer4_Release(player4); + IOleObject_Release(oleobj); + DeleteFileW(filename); + SysFreeString(filename); +} + +START_TEST(media) +{ + CoInitialize(NULL); + + test_wmp(); + + CoUninitialize(); +} diff --git a/dlls/wmp/tests/oleobj.c b/dlls/wmp/tests/oleobj.c index e4c2294436..41179dae5d 100644 --- a/dlls/wmp/tests/oleobj.c +++ b/dlls/wmp/tests/oleobj.c @@ -70,7 +70,7 @@ DEFINE_EXPECT(GetWindowContext); DEFINE_EXPECT(ShowObject); DEFINE_EXPECT(OnShowWindow_FALSE);
-static const WCHAR mp4file[] = {'a','v','.','m','p','4',0}; +static const WCHAR mp3file[] = {'t','e','s','t','.','m','p','3',0}; static inline WCHAR *load_resource(const WCHAR *name) { static WCHAR pathW[MAX_PATH]; @@ -942,8 +942,7 @@ static void test_wmp_ifaces(IOleObject *oleobj) ok(hres == S_FALSE, "get_currentMedia SUCCEEDED\n"); ok(media == NULL, "media != NULL\n");
- filename = SysAllocString(load_resource(mp4file)); - + filename = SysAllocString(load_resource(mp3file));
SET_EXPECT(GetContainer); SET_EXPECT(Invoke_USERMODE); @@ -1039,6 +1038,7 @@ static void test_wmp_ifaces(IOleObject *oleobj)
IWMPSettings_Release(settings); IWMPPlayer_Release(player); + DeleteFileW(filename); SysFreeString(filename); }
diff --git a/dlls/wmp/tests/rsrc.rc b/dlls/wmp/tests/rsrc.rc index fb30ae6940..f33acc1256 100644 --- a/dlls/wmp/tests/rsrc.rc +++ b/dlls/wmp/tests/rsrc.rc @@ -18,5 +18,6 @@
#include "windef.h"
-/* @makedep: av.mp4 */ -av.mp4 RCDATA "av.mp4" +/* 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" diff --git a/dlls/wmp/tests/test.mp3 b/dlls/wmp/tests/test.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..149a2cd346ee52ae179c46198ce290a5dd4d6251 GIT binary patch literal 240333 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
literal 0 HcmV?d00001
diff --git a/dlls/wmp/wmp_private.h b/dlls/wmp/wmp_private.h index e95b194d77..05ad5889e2 100644 --- a/dlls/wmp/wmp_private.h +++ b/dlls/wmp/wmp_private.h @@ -22,6 +22,7 @@ #include "wine/heap.h" #include "wine/unicode.h" #include "ole2.h" +#include "dshow.h" #include "wmp.h"
typedef struct { @@ -70,11 +71,16 @@ struct WindowsMediaPlayer { ConnectionPoint *wmpocx;
IWMPMedia *wmpmedia; + + /* DirectShow stuff */ + IGraphBuilder* filter_graph; + IMediaControl* media_control; };
void init_player(WindowsMediaPlayer*) DECLSPEC_HIDDEN; void destroy_player(WindowsMediaPlayer*) DECLSPEC_HIDDEN; -IWMPMedia* create_media_from_url(BSTR url); +WMPMedia *unsafe_impl_from_IWMPMedia(IWMPMedia *iface) DECLSPEC_HIDDEN; +HRESULT create_media_from_url(BSTR url, IWMPMedia **ppMedia) DECLSPEC_HIDDEN; void ConnectionPointContainer_Init(WindowsMediaPlayer *wmp) DECLSPEC_HIDDEN; void ConnectionPointContainer_Destroy(WindowsMediaPlayer *wmp) DECLSPEC_HIDDEN;
Signed-off-by: Anton Romanov theli.ua@gmail.com --- dlls/wmp/events.c | 11 +++ dlls/wmp/oleobj.c | 2 +- dlls/wmp/player.c | 46 ++++++++++++ dlls/wmp/tests/media.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++++- dlls/wmp/wmp_main.c | 1 + dlls/wmp/wmp_private.h | 1 + include/wmpids.h | 63 ++++++++++++++++ 7 files changed, 320 insertions(+), 2 deletions(-) create mode 100644 include/wmpids.h
diff --git a/dlls/wmp/events.c b/dlls/wmp/events.c index a908834010..412eb307d1 100644 --- a/dlls/wmp/events.c +++ b/dlls/wmp/events.c @@ -400,3 +400,14 @@ void ConnectionPointContainer_Destroy(WindowsMediaPlayer *wmp) { ConnectionPoint_Destroy(wmp->wmpocx); } + +void call_sink(ConnectionPoint *This, DISPID dispid, DISPPARAMS *dispparams) +{ + DWORD i; + + for(i=0; i<This->sinks_size; i++) { + if(This->sinks[i]) + IDispatch_Invoke(This->sinks[i], dispid, &IID_NULL, LOCALE_SYSTEM_DEFAULT, + DISPATCH_METHOD, dispparams, NULL, NULL, NULL); + } +} diff --git a/dlls/wmp/oleobj.c b/dlls/wmp/oleobj.c index cc0e9a9d98..cbf183c1f6 100644 --- a/dlls/wmp/oleobj.c +++ b/dlls/wmp/oleobj.c @@ -307,8 +307,8 @@ static ULONG WINAPI OleObject_Release(IOleObject *iface)
if(!ref) { release_client_site(This); - ConnectionPointContainer_Destroy(This); destroy_player(This); + ConnectionPointContainer_Destroy(This); heap_free(This); }
diff --git a/dlls/wmp/player.c b/dlls/wmp/player.c index b6f6b325ec..bf7885790e 100644 --- a/dlls/wmp/player.c +++ b/dlls/wmp/player.c @@ -20,9 +20,12 @@
#include "wine/debug.h" #include <nserror.h> +#include "wmpids.h"
WINE_DEFAULT_DEBUG_CHANNEL(wmp);
+static void update_state(WindowsMediaPlayer *wmp, LONG type, LONG state); + static inline WMPMedia *impl_from_IWMPMedia(IWMPMedia *iface) { return CONTAINING_RECORD(iface, WMPMedia, IWMPMedia_iface); @@ -125,14 +128,20 @@ static HRESULT WINAPI WMPPlayer4_put_URL(IWMPPlayer4 *iface, BSTR url) if(url == NULL) { return E_POINTER; } + hres = create_media_from_url(url, &media); + if (SUCCEEDED(hres)) { + update_state(This, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, WMP_PLAY_STATE_TRANSITIONING); hres = IWMPPlayer4_put_currentMedia(iface, media); IWMPMedia_Release(media); /* put will addref */ + + update_state(This, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, WMP_PLAY_STATE_READY); } if (SUCCEEDED(hres) && This->auto_start) { hres = IWMPControls_play(&This->IWMPControls_iface); } + return hres; }
@@ -191,9 +200,13 @@ static HRESULT WINAPI WMPPlayer4_put_currentMedia(IWMPPlayer4 *iface, IWMPMedia if(pMedia == NULL) { return E_POINTER; } + update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, WMP_OPEN_STATE_PLAYLIST_CHANGING); if(This->wmpmedia != NULL) { IWMPMedia_Release(This->wmpmedia); } + update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, WMP_OPEN_STATE_PLAYLIST_CHANGED); + update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, WMP_OPEN_STATE_PLAYLIST_OPEN_NO_MEDIA); + This->wmpmedia = pMedia; IWMPMedia_AddRef(This->wmpmedia); return S_OK; @@ -1388,19 +1401,31 @@ static HRESULT WINAPI WMPControls_play(IWMPControls *iface) CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (void **)&This->filter_graph); + update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, WMP_OPEN_STATE_OPENING_UNKNOWN_URL); + if (SUCCEEDED(hres)) hres = IGraphBuilder_RenderFile(This->filter_graph, media->url, NULL); if (SUCCEEDED(hres)) hres = IGraphBuilder_QueryInterface(This->filter_graph, &IID_IMediaControl, (void**)&This->media_control); + update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, WMP_OPEN_STATE_MEDIA_OPEN); }
+ update_state(This, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, WMP_PLAY_STATE_TRANSITIONING); + if (SUCCEEDED(hres)) hres = IMediaControl_Run(This->media_control);
if (hres == S_FALSE) { hres = S_OK; /* S_FALSE will mean that graph is transitioning and that is fine */ } + + if (SUCCEEDED(hres)) { + update_state(This, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, WMP_PLAY_STATE_PLAYING); + } else { + update_state(This, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, WMP_PLAY_STATE_UNDEFINED); + } + return hres; }
@@ -1412,6 +1437,8 @@ static HRESULT WINAPI WMPControls_stop(IWMPControls *iface) if (!This->filter_graph) { return NS_S_WMPCORE_COMMAND_NOT_AVAILABLE; } + update_state(This, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, WMP_PLAY_STATE_TRANSITIONING); + update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, WMP_OPEN_STATE_MEDIA_CHANGING); if (This->media_control) { hres = IMediaControl_Stop(This->media_control); IMediaControl_Release(This->media_control); @@ -1421,6 +1448,8 @@ static HRESULT WINAPI WMPControls_stop(IWMPControls *iface) } This->filter_graph = NULL; This->media_control = NULL; + update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, WMP_OPEN_STATE_PLAYLIST_OPEN_NO_MEDIA); + update_state(This, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, WMP_PLAY_STATE_STOPPED); return hres; }
@@ -1829,3 +1858,20 @@ HRESULT create_media_from_url(BSTR url, IWMPMedia **ppMedia) IWMPMedia_Release(&media->IWMPMedia_iface); return E_OUTOFMEMORY; } + +static void update_state(WindowsMediaPlayer *wmp, LONG type, LONG state) +{ + DISPPARAMS dispparams; + VARIANTARG params[1]; + + dispparams.cArgs = 1; + dispparams.cNamedArgs = 0; + dispparams.rgdispidNamedArgs = NULL; + dispparams.rgvarg = params; + + V_VT(params) = VT_UI4; + V_UI4(params) = state; + + call_sink(wmp->wmpocx, type, + &dispparams); +} diff --git a/dlls/wmp/tests/media.c b/dlls/wmp/tests/media.c index 6e4a0c170f..f98a60fbfd 100644 --- a/dlls/wmp/tests/media.c +++ b/dlls/wmp/tests/media.c @@ -19,9 +19,42 @@ #include <wmp.h> #include <olectl.h> #include <nserror.h> +#include <wmpids.h> +#include <math.h>
#include "wine/test.h"
+#define DEFINE_EXPECT(func) \ + static BOOL expect_ ## func = FALSE, called_ ## func = FALSE + +#define SET_EXPECT(func) \ + expect_ ## func = TRUE + +#define CHECK_EXPECT(func) \ + do { \ + ok(expect_ ##func, "unexpected call " #func "\n"); \ + called_ ## func = TRUE; \ + }while(0) + +#define CHECK_CALLED(func) \ + do { \ + ok(called_ ## func, "expected " #func "\n"); \ + expect_ ## func = called_ ## func = FALSE; \ + }while(0) + +#define CHECK_CALLED_OR_BROKEN(func) \ + do { \ + ok(called_ ## func || broken(TRUE), "expected " #func "\n"); \ + expect_ ## func = called_ ## func = FALSE; \ + }while(0) + +DEFINE_EXPECT(PLAYSTATE_CHANGE); +DEFINE_EXPECT(OPENSTATE_CHANGE); + +static BOOL open_state; +static BOOL play_state; +static HANDLE playing_event; + static const WCHAR mp3file[] = {'t','e','s','t','.','m','p','3',0}; static inline WCHAR *load_resource(const WCHAR *name) { @@ -48,14 +81,114 @@ static inline WCHAR *load_resource(const WCHAR *name) return pathW; }
+static ULONG WINAPI Dispatch_AddRef(IDispatch *iface) +{ + return 2; +} + +static ULONG WINAPI Dispatch_Release(IDispatch *iface) +{ + return 1; +} + +static HRESULT WINAPI Dispatch_GetTypeInfoCount(IDispatch *iface, UINT *pctinfo) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Dispatch_GetTypeInfo(IDispatch *iface, UINT iTInfo, LCID lcid, + ITypeInfo **ppTInfo) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Dispatch_GetIDsOfNames(IDispatch *iface, REFIID riid, LPOLESTR *rgszNames, + UINT cNames, LCID lcid, DISPID *rgDispId) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI WMPOCXEvents_QueryInterface(IDispatch *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + + if(IsEqualGUID(&IID__WMPOCXEvents, riid) || IsEqualGUID(&IID_IDispatch, riid)) { + *ppv = iface; + return S_OK; + } + + ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid)); + return E_NOINTERFACE; +} + +static HRESULT WINAPI WMPOCXEvents_Invoke(IDispatch *iface, DISPID dispIdMember, REFIID riid, + LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + switch(dispIdMember) { + /* Uncomment below traces to debug wmp events */ + case DISPID_WMPCOREEVENT_OPENSTATECHANGE: + CHECK_EXPECT(OPENSTATE_CHANGE); + open_state = V_UI4(pDispParams->rgvarg); + if (winetest_debug > 1) + trace("DISPID_WMPCOREEVENT_OPENSTATECHANGE, %d\n", V_UI4(pDispParams->rgvarg)); + break; + case DISPID_WMPCOREEVENT_PLAYSTATECHANGE: + CHECK_EXPECT(PLAYSTATE_CHANGE); + play_state = V_UI4(pDispParams->rgvarg); + if (play_state == WMP_PLAY_STATE_PLAYING) { + SetEvent(playing_event); + } + if (winetest_debug > 1) + trace("DISPID_WMPCOREEVENT_PLAYSTATECHANGE, %d\n", V_UI4(pDispParams->rgvarg)); + break; + case DISPID_WMPCOREEVENT_MEDIACHANGE: + if (winetest_debug > 1) + trace("DISPID_WMPCOREEVENT_MEDIACHANGE\n"); + break; + case DISPID_WMPCOREEVENT_CURRENTITEMCHANGE: + if (winetest_debug > 1) + trace("DISPID_WMPCOREEVENT_CURRENTITEMCHANGE\n"); + break; + case DISPID_WMPCOREEVENT_STATUSCHANGE: + if (winetest_debug > 1) + trace("DISPID_WMPCOREEVENT_STATUSCHANGE\n"); + break; + default: + if (winetest_debug > 1) + trace("event: %d\n", dispIdMember); + break; + } + + return E_NOTIMPL; +} + +static IDispatchVtbl WMPOcxEventsVtbl = { + WMPOCXEvents_QueryInterface, + Dispatch_AddRef, + Dispatch_Release, + Dispatch_GetTypeInfoCount, + Dispatch_GetTypeInfo, + Dispatch_GetIDsOfNames, + WMPOCXEvents_Invoke, +}; + +static IDispatch WMPOCXEvents = { &WMPOcxEventsVtbl }; + static void 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;
hres = CoCreateInstance(&CLSID_WindowsMediaPlayer, NULL, CLSCTX_INPROC_SERVER, &IID_IOleObject, (void**)&oleobj); @@ -65,6 +198,18 @@ static void test_wmp(void) } 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); + if(FAILED(hres)) + return; + + 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);
@@ -87,22 +232,70 @@ static void test_wmp(void)
filename = SysAllocString(load_resource(mp3file));
+ SET_EXPECT(OPENSTATE_CHANGE); + SET_EXPECT(PLAYSTATE_CHANGE); hres = IWMPPlayer4_put_URL(player4, filename); ok(hres == S_OK, "IWMPPlayer4_put_URL failed: %08x\n", hres); + CHECK_CALLED(OPENSTATE_CHANGE); + CHECK_CALLED(PLAYSTATE_CHANGE);
+ SET_EXPECT(PLAYSTATE_CHANGE); + SET_EXPECT(OPENSTATE_CHANGE); hres = IWMPControls_play(controls); + ok(hres == S_OK, "IWMPControls_play failed: %08x\n", hres); + { + MSG msg; + DWORD start_time = GetTickCount(); + DWORD dwTimeout = 5000; + HANDLE handles[1]; + handles[0] = playing_event; + do { + DWORD now = GetTickCount(); + res = MsgWaitForMultipleObjectsEx(1, handles, start_time + dwTimeout - now, + QS_ALLINPUT ,MWMO_ALERTABLE | MWMO_INPUTAVAILABLE); + if (res == WAIT_OBJECT_0 + 1) { + GetMessageW(&msg, 0, 0, 0); + if (winetest_debug > 1) + trace("Dispatching %d\n", msg.message); + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + } + while (res == WAIT_OBJECT_0 + 1); + ok(res == WAIT_OBJECT_0 || broken(res == WAIT_TIMEOUT), "Timed out while waiting for media to become ready\n"); + } + if (res == WAIT_TIMEOUT) { + /* 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"); + goto playback_skip; + } + CHECK_CALLED(OPENSTATE_CHANGE); + CHECK_CALLED(PLAYSTATE_CHANGE);
+ SET_EXPECT(OPENSTATE_CHANGE); todo_wine ok(FALSE || broken(TRUE), "WMP in wine changes open state when stopping\n"); + SET_EXPECT(PLAYSTATE_CHANGE); hres = IWMPControls_stop(controls); ok(hres == S_OK, "IWMPControls_stop failed: %08x\n", hres); + CHECK_CALLED(PLAYSTATE_CHANGE);
/* Already Stopped */ hres = IWMPControls_stop(controls); ok(hres == NS_S_WMPCORE_COMMAND_NOT_AVAILABLE, "IWMPControls_stop is available: %08x\n", hres);
+ SET_EXPECT(OPENSTATE_CHANGE); + SET_EXPECT(PLAYSTATE_CHANGE); hres = IWMPControls_play(controls); ok(hres == S_OK, "IWMPControls_play failed: %08x\n", hres); + CHECK_CALLED_OR_BROKEN(OPENSTATE_CHANGE); + CHECK_CALLED_OR_BROKEN(PLAYSTATE_CHANGE);
+playback_skip: + hres = IConnectionPoint_Unadvise(point, dw); + ok(hres == S_OK, "Unadvise failed: %08x\n", hres); + + IConnectionPoint_Release(point); IWMPControls_Release(controls); IWMPPlayer4_Release(player4); IOleObject_Release(oleobj); @@ -114,7 +307,10 @@ START_TEST(media) { CoInitialize(NULL);
+ playing_event = CreateEventW(NULL, FALSE, FALSE, NULL); test_wmp();
+ CloseHandle(playing_event); + CoUninitialize(); } diff --git a/dlls/wmp/wmp_main.c b/dlls/wmp/wmp_main.c index 29b096f7fd..9a33b2762b 100644 --- a/dlls/wmp/wmp_main.c +++ b/dlls/wmp/wmp_main.c @@ -25,6 +25,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(wmp);
HINSTANCE wmp_instance; +DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv) { diff --git a/dlls/wmp/wmp_private.h b/dlls/wmp/wmp_private.h index 05ad5889e2..9e84d56ea8 100644 --- a/dlls/wmp/wmp_private.h +++ b/dlls/wmp/wmp_private.h @@ -83,6 +83,7 @@ WMPMedia *unsafe_impl_from_IWMPMedia(IWMPMedia *iface) DECLSPEC_HIDDEN; HRESULT create_media_from_url(BSTR url, IWMPMedia **ppMedia) DECLSPEC_HIDDEN; void ConnectionPointContainer_Init(WindowsMediaPlayer *wmp) DECLSPEC_HIDDEN; void ConnectionPointContainer_Destroy(WindowsMediaPlayer *wmp) DECLSPEC_HIDDEN; +void call_sink(ConnectionPoint *This, DISPID dispid, DISPPARAMS *dispparams) DECLSPEC_HIDDEN;
HRESULT WINAPI WMPFactory_CreateInstance(IClassFactory*,IUnknown*,REFIID,void**) DECLSPEC_HIDDEN;
diff --git a/include/wmpids.h b/include/wmpids.h new file mode 100644 index 0000000000..2792f850fa --- /dev/null +++ b/include/wmpids.h @@ -0,0 +1,63 @@ +/* + * 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 + */ + + +/* play state */ +#define WMP_PLAY_STATE_UNDEFINED 0 +#define WMP_PLAY_STATE_STOPPED 1 +#define WMP_PLAY_STATE_PAUSED 2 +#define WMP_PLAY_STATE_PLAYING 3 +#define WMP_PLAY_STATE_SCAN_FORWARD 4 +#define WMP_PLAY_STATE_SCAN_REVERSE 5 +#define WMP_PLAY_STATE_BUFFERING 6 +#define WMP_PLAY_STATE_WAITING 7 +#define WMP_PLAY_STATE_MEDIA_ENDED 8 +#define WMP_PLAY_STATE_TRANSITIONING 9 +#define WMP_PLAY_STATE_READY 10 +#define WMP_PLAY_STATE_RECONNECTING 11 + +/* open state */ +#define WMP_OPEN_STATE_UNDEFINED 0 +#define WMP_OPEN_STATE_PLAYLIST_CHANGING 1 +#define WMP_OPEN_STATE_PLAYLIST_LOCATING 2 +#define WMP_OPEN_STATE_PLAYLIST_CONNECTING 3 +#define WMP_OPEN_STATE_PLAYLIST_LOADING 4 +#define WMP_OPEN_STATE_PLAYLIST_OPENING 5 +#define WMP_OPEN_STATE_PLAYLIST_OPEN_NO_MEDIA 6 +#define WMP_OPEN_STATE_PLAYLIST_CHANGED 7 +#define WMP_OPEN_STATE_MEDIA_CHANGING 8 +#define WMP_OPEN_STATE_MEDIA_LOCATING 9 +#define WMP_OPEN_STATE_MEDIA_CONNECTING 10 +#define WMP_OPEN_STATE_MEDIA_LOADING 11 +#define WMP_OPEN_STATE_MEDIA_OPENING 12 +#define WMP_OPEN_STATE_MEDIA_OPEN 13 +#define WMP_OPEN_STATE_BEGIN_CODEC_ACQUISITION 14 +#define WMP_OPEN_STATE_END_CODEC_ACQUISITION 15 +#define WMP_OPEN_STATE_BEGIN_LICENSE_ACQUISITION 16 +#define WMP_OPEN_STATE_END_LICENSE_ACQUISITION 17 +#define WMP_OPEN_STATE_BEGIN_INDIVIDUALIZATION 18 +#define WMP_OPEN_STATE_END_INDIVIDUALIZATION 19 +#define WMP_OPEN_STATE_MEDIA_WAITING 20 +#define WMP_OPEN_STATE_OPENING_UNKNOWN_URL 21 + +/* WMPCoreEvents */ +#define DISPID_WMPCOREEVENT_OPENSTATECHANGE 5001 +#define DISPID_WMPCOREEVENT_STATUSCHANGE 5002 + +#define DISPID_WMPCOREEVENT_PLAYSTATECHANGE 5101 + +#define DISPID_WMPCOREEVENT_MEDIACHANGE 5802 +#define DISPID_WMPCOREEVENT_CURRENTITEMCHANGE 5806
Signed-off-by: Anton Romanov theli.ua@gmail.com --- dlls/wmp/player.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++- dlls/wmp/wmp_private.h | 5 ++++ 2 files changed, 70 insertions(+), 1 deletion(-)
diff --git a/dlls/wmp/player.c b/dlls/wmp/player.c index bf7885790e..5b4bf71d78 100644 --- a/dlls/wmp/player.c +++ b/dlls/wmp/player.c @@ -25,6 +25,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(wmp);
static void update_state(WindowsMediaPlayer *wmp, LONG type, LONG state); +static DWORD CALLBACK WMP_event_thread(LPVOID parm);
static inline WMPMedia *impl_from_IWMPMedia(IWMPMedia *iface) { @@ -197,18 +198,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, WMP_OPEN_STATE_PLAYLIST_CHANGING); if(This->wmpmedia != NULL) { + IWMPControls_stop(&This->IWMPControls_iface); IWMPMedia_Release(This->wmpmedia); } update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, WMP_OPEN_STATE_PLAYLIST_CHANGED); update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, WMP_OPEN_STATE_PLAYLIST_OPEN_NO_MEDIA);
+ IWMPMedia_AddRef(pMedia); This->wmpmedia = pMedia; - IWMPMedia_AddRef(This->wmpmedia); return S_OK; }
@@ -1409,6 +1412,11 @@ static HRESULT WINAPI WMPControls_play(IWMPControls *iface) hres = IGraphBuilder_QueryInterface(This->filter_graph, &IID_IMediaControl, (void**)&This->media_control); update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, WMP_OPEN_STATE_MEDIA_OPEN); + if (SUCCEEDED(hres)) + hres = IGraphBuilder_QueryInterface(This->filter_graph, &IID_IMediaEvent, + (void**)&This->media_event); + if (SUCCEEDED(hres)) + This->event_thread = CreateThread(NULL, 0, WMP_event_thread, This, 0, NULL); }
update_state(This, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, WMP_PLAY_STATE_TRANSITIONING); @@ -1446,8 +1454,17 @@ static HRESULT WINAPI WMPControls_stop(IWMPControls *iface) if (This->filter_graph) { IGraphBuilder_Release(This->filter_graph); } + if (This->media_event) { + IMediaEvent_Release(This->media_event); + } This->filter_graph = NULL; This->media_control = NULL; + This->media_event = NULL; + + SetEvent(This->stop_event); + WaitForSingleObject(This->event_thread, INFINITE); + CloseHandle(This->event_thread); + update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, WMP_OPEN_STATE_PLAYLIST_OPEN_NO_MEDIA); update_state(This, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, WMP_PLAY_STATE_STOPPED); return hres; @@ -1821,6 +1838,7 @@ void init_player(WindowsMediaPlayer *wmp)
wmp->invoke_urls = VARIANT_TRUE; wmp->auto_start = VARIANT_TRUE; + wmp->stop_event = CreateEventW(NULL, FALSE, FALSE, NULL); }
void destroy_player(WindowsMediaPlayer *wmp) @@ -1828,6 +1846,8 @@ void destroy_player(WindowsMediaPlayer *wmp) IWMPControls_stop(&wmp->IWMPControls_iface); if(wmp->wmpmedia) IWMPMedia_Release(wmp->wmpmedia); + CloseHandle(wmp->stop_event); + }
WMPMedia *unsafe_impl_from_IWMPMedia(IWMPMedia *iface) @@ -1875,3 +1895,47 @@ static void update_state(WindowsMediaPlayer *wmp, LONG type, LONG state) call_sink(wmp->wmpocx, type, &dispparams); } + +static DWORD CALLBACK WMP_event_thread(LPVOID parm) +{ + WindowsMediaPlayer* wmp = (WindowsMediaPlayer *)parm; + HRESULT hr; + HANDLE handle[2]; + DWORD n = 0, ret = 0; + + handle[n++] = wmp->stop_event; + IMediaEvent_GetEventHandle(wmp->media_event, (OAEVENT *)&handle[n++]); + for (;;) { + DWORD r; + + r = WaitForMultipleObjects(n, handle, FALSE, INFINITE); + if (r == WAIT_OBJECT_0) { + TRACE("got stop event\n"); + break; + } + else if (r == WAIT_OBJECT_0+1) { + LONG event_code; + LONG_PTR p1, p2; + do { + hr = IMediaEvent_GetEvent(wmp->media_event, &event_code, &p1, &p2, 0); + if (SUCCEEDED(hr)) { + TRACE("got event_code = 0x%02x\n", event_code); + /* For now we only handle EC_COMPLETE */ + if (event_code == EC_COMPLETE) { + update_state(wmp, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, WMP_PLAY_STATE_MEDIA_ENDED); + update_state(wmp, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, WMP_PLAY_STATE_TRANSITIONING); + update_state(wmp, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, WMP_PLAY_STATE_STOPPED); + } + + IMediaEvent_FreeEventParams(wmp->media_event, event_code, p1, p2); + } + } while (hr == S_OK); + } + else { + ERR("Unknown error (%d)\n", (int)r); + break; + } + } + + return ret; +} diff --git a/dlls/wmp/wmp_private.h b/dlls/wmp/wmp_private.h index 9e84d56ea8..0095e4ce26 100644 --- a/dlls/wmp/wmp_private.h +++ b/dlls/wmp/wmp_private.h @@ -75,6 +75,11 @@ struct WindowsMediaPlayer { /* DirectShow stuff */ IGraphBuilder* filter_graph; IMediaControl* media_control; + IMediaEvent* media_event; + + /* Async event notification */ + HANDLE event_thread; + HANDLE stop_event; };
void init_player(WindowsMediaPlayer*) DECLSPEC_HIDDEN;
Signed-off-by: Anton Romanov theli.ua@gmail.com --- dlls/wmp/player.c | 63 +++++++++++++++++++++++++++++++++++++++++++------- dlls/wmp/tests/media.c | 33 ++++++++++++++++++++++++++ dlls/wmp/wmp_private.h | 3 +++ 3 files changed, 91 insertions(+), 8 deletions(-)
diff --git a/dlls/wmp/player.c b/dlls/wmp/player.c index 5b4bf71d78..6cb7656b97 100644 --- a/dlls/wmp/player.c +++ b/dlls/wmp/player.c @@ -1376,8 +1376,22 @@ static HRESULT WINAPI WMPControls_Invoke(IWMPControls *iface, DISPID dispIdMembe static HRESULT WINAPI WMPControls_get_isAvailable(IWMPControls *iface, BSTR bstrItem, VARIANT_BOOL *pIsAvailable) { WindowsMediaPlayer *This = impl_from_IWMPControls(iface); - FIXME("(%p)->(%s)\n", This, debugstr_w(bstrItem)); - return E_NOTIMPL; + static const WCHAR currentPosition[] = {'c','u','r','r','e','n','t','P','o','s','i','t','i','o','n',0}; + TRACE("(%p)->(%s %p)\n", This, debugstr_w(bstrItem), pIsAvailable); + *pIsAvailable = VARIANT_FALSE; + if (!This->filter_graph) { + *pIsAvailable = VARIANT_FALSE; + } else if (strcmpW(currentPosition, bstrItem) == 0) { + DWORD capabilities; + IMediaSeeking_GetCapabilities(This->media_seeking, &capabilities); + *pIsAvailable = (capabilities & AM_SEEKING_CanSeekAbsolute) ? + VARIANT_TRUE : VARIANT_FALSE; + } else { + FIXME("%s not implemented\n", debugstr_w(bstrItem)); + return E_NOTIMPL; + } + + return S_OK; }
static HRESULT WINAPI WMPControls_play(IWMPControls *iface) @@ -1411,6 +1425,11 @@ static HRESULT WINAPI WMPControls_play(IWMPControls *iface) if (SUCCEEDED(hres)) hres = IGraphBuilder_QueryInterface(This->filter_graph, &IID_IMediaControl, (void**)&This->media_control); + if (SUCCEEDED(hres)) + hres = IGraphBuilder_QueryInterface(This->filter_graph, &IID_IMediaSeeking, + (void**)&This->media_seeking); + if (SUCCEEDED(hres)) + hres = IMediaSeeking_SetTimeFormat(This->media_seeking, &TIME_FORMAT_MEDIA_TIME); update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, WMP_OPEN_STATE_MEDIA_OPEN); if (SUCCEEDED(hres)) hres = IGraphBuilder_QueryInterface(This->filter_graph, &IID_IMediaEvent, @@ -1429,7 +1448,10 @@ static HRESULT WINAPI WMPControls_play(IWMPControls *iface) }
if (SUCCEEDED(hres)) { + LONGLONG duration; update_state(This, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, WMP_PLAY_STATE_PLAYING); + if (SUCCEEDED(IMediaSeeking_GetDuration(This->media_seeking, &duration))) + media->duration = (DOUBLE)duration / 10000000.0f; } else { update_state(This, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, WMP_PLAY_STATE_UNDEFINED); } @@ -1457,9 +1479,13 @@ static HRESULT WINAPI WMPControls_stop(IWMPControls *iface) if (This->media_event) { IMediaEvent_Release(This->media_event); } + if (This->media_seeking) { + IMediaSeeking_Release(This->media_seeking); + } This->filter_graph = NULL; This->media_control = NULL; This->media_event = NULL; + This->media_seeking = NULL;
SetEvent(This->stop_event); WaitForSingleObject(This->event_thread, INFINITE); @@ -1494,15 +1520,33 @@ static HRESULT WINAPI WMPControls_fastReverse(IWMPControls *iface) static HRESULT WINAPI WMPControls_get_currentPosition(IWMPControls *iface, DOUBLE *pdCurrentPosition) { WindowsMediaPlayer *This = impl_from_IWMPControls(iface); - FIXME("(%p)->(%p)\n", This, pdCurrentPosition); - return E_NOTIMPL; + HRESULT hres; + LONGLONG currentPosition; + + TRACE("(%p)->(%p)\n", This, pdCurrentPosition); + if (!This->media_seeking) + return S_FALSE; + + hres = IMediaSeeking_GetCurrentPosition(This->media_seeking, ¤tPosition); + *pdCurrentPosition = (DOUBLE) currentPosition / 10000000.0f; + TRACE("hres: %d, pos: %f\n", hres, *pdCurrentPosition); + return hres; }
static HRESULT WINAPI WMPControls_put_currentPosition(IWMPControls *iface, DOUBLE dCurrentPosition) { + LONGLONG Current; + HRESULT hres; WindowsMediaPlayer *This = impl_from_IWMPControls(iface); - FIXME("(%p)->(%f)\n", This, dCurrentPosition); - return E_NOTIMPL; + TRACE("(%p)->(%f)\n", This, dCurrentPosition); + if (!This->media_seeking) + return S_FALSE; + + Current = 10000000 * dCurrentPosition; + hres = IMediaSeeking_SetPositions(This->media_seeking, &Current, + AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning); + + return hres; }
static HRESULT WINAPI WMPControls_get_currentPositionString(IWMPControls *iface, BSTR *pbstrCurrentPosition) @@ -1739,9 +1783,12 @@ static HRESULT WINAPI WMPMedia_getMarkerName(IWMPMedia *iface, LONG MarkerNum, B
static HRESULT WINAPI WMPMedia_get_duration(IWMPMedia *iface, DOUBLE *pDuration) { + /* MSDN: If this property is used with a media item other than the one + * specified in Player.currentMedia, it may not contain a valid value. */ WMPMedia *This = impl_from_IWMPMedia(iface); - FIXME("(%p)->(%p)\n", This, pDuration); - return E_NOTIMPL; + TRACE("(%p)->(%p)\n", This, pDuration); + *pDuration = This->duration; + return S_OK; }
static HRESULT WINAPI WMPMedia_get_durationString(IWMPMedia *iface, BSTR *pbstrDuration) diff --git a/dlls/wmp/tests/media.c b/dlls/wmp/tests/media.c index f98a60fbfd..b6849b0657 100644 --- a/dlls/wmp/tests/media.c +++ b/dlls/wmp/tests/media.c @@ -190,6 +190,11 @@ static void test_wmp(void) IOleObject *oleobj; static DWORD dw = 100; IWMPSettings *settings; + DOUBLE duration; + VARIANT_BOOL vbool; + IWMPMedia *media; + static const WCHAR currentPosition[] = {'c','u','r','r','e','n','t','P','o','s','i','t','i','o','n',0}; + BSTR bstrcurrentPosition = SysAllocString(currentPosition);
hres = CoCreateInstance(&CLSID_WindowsMediaPlayer, NULL, CLSCTX_INPROC_SERVER, &IID_IOleObject, (void**)&oleobj); if(hres == REGDB_E_CLASSNOTREG) { @@ -227,6 +232,10 @@ static void test_wmp(void) ok(hres == S_OK, "get_controls failed: %08x\n", hres); ok(controls != NULL, "controls = NULL\n");
+ hres = IWMPControls_get_isAvailable(controls, bstrcurrentPosition, &vbool); + ok(hres == S_OK, "IWMPControls_get_isAvailable failed: %08x\n", hres); + ok(vbool == VARIANT_FALSE, "unexpected value\n"); + hres = IWMPControls_play(controls); ok(hres == NS_S_WMPCORE_COMMAND_NOT_AVAILABLE, "IWMPControls_play is available: %08x\n", hres);
@@ -274,6 +283,29 @@ static void test_wmp(void) CHECK_CALLED(OPENSTATE_CHANGE); CHECK_CALLED(PLAYSTATE_CHANGE);
+ hres = IWMPControls_get_isAvailable(controls, bstrcurrentPosition, &vbool); + ok(hres == S_OK, "IWMPControls_get_isAvailable failed: %08x\n", hres); + ok(vbool == VARIANT_TRUE, "unexpected value\n"); + + duration = 0.0; + hres = IWMPControls_get_currentPosition(controls, &duration); + ok(hres == S_OK, "IWMPControls_get_currentPosition failed: %08x\n", hres); + ok((int)duration == 0, "unexpected value %f\n", duration); + + hres = IWMPControls_put_currentPosition(controls, duration); + ok(hres == S_OK, "IWMPControls_put_currentPosition failed: %08x\n", hres); + + hres = IWMPPlayer4_get_currentMedia(player4, &media); + ok(hres == S_OK, "IWMPPlayer4_get_currentMedia failed: %08x\n", hres); + hres = IWMPMedia_get_duration(media, &duration); + ok(hres == S_OK, "IWMPMedia_get_duration failed: %08x\n", hres); + ok( + round(duration) == 60 || + broken(round(duration) == 30) || + broken(round(duration) == 57) + , "unexpected value: %f\n", duration); + IWMPMedia_Release(media); + SET_EXPECT(OPENSTATE_CHANGE); todo_wine ok(FALSE || broken(TRUE), "WMP in wine changes open state when stopping\n"); SET_EXPECT(PLAYSTATE_CHANGE); hres = IWMPControls_stop(controls); @@ -301,6 +333,7 @@ playback_skip: IOleObject_Release(oleobj); DeleteFileW(filename); SysFreeString(filename); + SysFreeString(bstrcurrentPosition); }
START_TEST(media) diff --git a/dlls/wmp/wmp_private.h b/dlls/wmp/wmp_private.h index 0095e4ce26..4479f3cdb9 100644 --- a/dlls/wmp/wmp_private.h +++ b/dlls/wmp/wmp_private.h @@ -42,6 +42,8 @@ typedef struct { LONG ref;
WCHAR *url; + + DOUBLE duration; } WMPMedia;
struct WindowsMediaPlayer { @@ -76,6 +78,7 @@ struct WindowsMediaPlayer { IGraphBuilder* filter_graph; IMediaControl* media_control; IMediaEvent* media_event; + IMediaSeeking* media_seeking;
/* Async event notification */ HANDLE event_thread;
Signed-off-by: Anton Romanov theli.ua@gmail.com --- dlls/wmp/player.c | 27 +++++++++++++++++++++++---- dlls/wmp/tests/media.c | 16 ++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-)
diff --git a/dlls/wmp/player.c b/dlls/wmp/player.c index 6cb7656b97..8a0d051cc6 100644 --- a/dlls/wmp/player.c +++ b/dlls/wmp/player.c @@ -1130,8 +1130,17 @@ static HRESULT WINAPI WMPNetwork_get_bufferingCount(IWMPNetwork *iface, LONG *pl static HRESULT WINAPI WMPNetwork_get_bufferingProgress(IWMPNetwork *iface, LONG *plBufferingProgress) { WindowsMediaPlayer *This = impl_from_IWMPNetwork(iface); - FIXME("(%p)->(%p)\n", This, plBufferingProgress); - return E_NOTIMPL; + TRACE("(%p)->(%p)\n", This, plBufferingProgress); + if (!This->filter_graph) { + return S_FALSE; + } + /* Ideally we would use IAMOpenProgress for URL reader but we don't have it in wine (yet) + * For file sources FileAsyncReader->Length should work + * */ + FIXME("stub: Returning buffering progress 100\n"); + *plBufferingProgress = 100; + + return S_OK; }
static HRESULT WINAPI WMPNetwork_get_bufferingTime(IWMPNetwork *iface, LONG *plBufferingTime) @@ -1256,8 +1265,18 @@ static HRESULT WINAPI WMPNetwork_put_maxBandwidth(IWMPNetwork *iface, LONG lMaxB static HRESULT WINAPI WMPNetwork_get_downloadProgress(IWMPNetwork *iface, LONG *plDownloadProgress) { WindowsMediaPlayer *This = impl_from_IWMPNetwork(iface); - FIXME("(%p)->(%p)\n", This, plDownloadProgress); - return E_NOTIMPL; + TRACE("(%p)->(%p)\n", This, plDownloadProgress); + if (!This->filter_graph) { + return S_FALSE; + } + /* Ideally we would use IAMOpenProgress for URL reader but we don't have it in wine (yet) + * For file sources FileAsyncReader->Length could work or it should just be + * 100 + * */ + FIXME("stub: Returning download progress 100\n"); + *plDownloadProgress = 100; + + return S_OK; }
static HRESULT WINAPI WMPNetwork_get_encodedFrameRate(IWMPNetwork *iface, LONG *plFrameRate) diff --git a/dlls/wmp/tests/media.c b/dlls/wmp/tests/media.c index b6849b0657..8ac2c78f5a 100644 --- a/dlls/wmp/tests/media.c +++ b/dlls/wmp/tests/media.c @@ -190,8 +190,10 @@ static void test_wmp(void) IOleObject *oleobj; static DWORD dw = 100; IWMPSettings *settings; + IWMPNetwork *network; DOUBLE duration; VARIANT_BOOL vbool; + LONG progress; IWMPMedia *media; static const WCHAR currentPosition[] = {'c','u','r','r','e','n','t','P','o','s','i','t','i','o','n',0}; BSTR bstrcurrentPosition = SysAllocString(currentPosition); @@ -306,6 +308,20 @@ static void test_wmp(void) , "unexpected value: %f\n", duration); IWMPMedia_Release(media);
+ network = NULL; + hres = IWMPPlayer4_get_network(player4, &network); + ok(hres == S_OK, "get_network failed: %08x\n", hres); + ok(network != NULL, "network = NULL\n"); + progress = 0; + hres = IWMPNetwork_get_bufferingProgress(network, &progress); + ok(hres == S_OK || broken(hres == S_FALSE), "IWMPNetwork_get_bufferingProgress failed: %08x\n", hres); + ok(progress == 100, "unexpected value: %d\n", progress); + progress = 0; + hres = IWMPNetwork_get_downloadProgress(network, &progress); + ok(hres == S_OK, "IWMPNetwork_get_downloadProgress failed: %08x\n", hres); + ok(progress == 100, "unexpected value: %d\n", progress); + IWMPNetwork_Release(network); + SET_EXPECT(OPENSTATE_CHANGE); todo_wine ok(FALSE || broken(TRUE), "WMP in wine changes open state when stopping\n"); SET_EXPECT(PLAYSTATE_CHANGE); hres = IWMPControls_stop(controls);
Signed-off-by: Anton Romanov theli.ua@gmail.com --- dlls/wmp/player.c | 30 ++++++++++++++++++++++++++---- dlls/wmp/tests/media.c | 8 +++++++- dlls/wmp/wmp_private.h | 1 + 3 files changed, 34 insertions(+), 5 deletions(-)
diff --git a/dlls/wmp/player.c b/dlls/wmp/player.c index 8a0d051cc6..2cc0512e5c 100644 --- a/dlls/wmp/player.c +++ b/dlls/wmp/player.c @@ -937,16 +937,32 @@ static HRESULT WINAPI WMPSettings_put_balance(IWMPSettings *iface, LONG v)
static HRESULT WINAPI WMPSettings_get_volume(IWMPSettings *iface, LONG *p) { + HRESULT hres; WindowsMediaPlayer *This = impl_from_IWMPSettings(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + TRACE("(%p)->(%p)\n", This, p); + if (!This->filter_graph) { + return S_FALSE; + } + hres = IBasicAudio_get_Volume(This->basic_audio, p); + /* IBasicAudio - [-10000, 0], wmp - [0, 100] */ + if (SUCCEEDED(hres)) + *p = (*p + 10000) * 100 / 10000; + return hres; }
static HRESULT WINAPI WMPSettings_put_volume(IWMPSettings *iface, LONG v) { + HRESULT hres; WindowsMediaPlayer *This = impl_from_IWMPSettings(iface); - FIXME("(%p)->(%d)\n", This, v); - return E_NOTIMPL; + TRACE("(%p)->(%d)\n", This, v); + if (!This->filter_graph) { + return S_FALSE; + } + /* IBasicAudio - [-10000, 0], wmp - [0, 100] */ + v = 10000 * v / 100 - 10000; + hres = IBasicAudio_put_Volume(This->basic_audio, v); + TRACE("ret: %d", hres); + return hres; }
static HRESULT WINAPI WMPSettings_getMode(IWMPSettings *iface, BSTR mode, VARIANT_BOOL *p) @@ -1453,6 +1469,8 @@ static HRESULT WINAPI WMPControls_play(IWMPControls *iface) if (SUCCEEDED(hres)) hres = IGraphBuilder_QueryInterface(This->filter_graph, &IID_IMediaEvent, (void**)&This->media_event); + if (SUCCEEDED(hres)) + hres = IGraphBuilder_QueryInterface(This->filter_graph, &IID_IBasicAudio, (void**)&This->basic_audio); if (SUCCEEDED(hres)) This->event_thread = CreateThread(NULL, 0, WMP_event_thread, This, 0, NULL); } @@ -1501,10 +1519,14 @@ static HRESULT WINAPI WMPControls_stop(IWMPControls *iface) if (This->media_seeking) { IMediaSeeking_Release(This->media_seeking); } + if (This->basic_audio) { + IBasicAudio_Release(This->basic_audio); + } This->filter_graph = NULL; This->media_control = NULL; This->media_event = NULL; This->media_seeking = NULL; + This->basic_audio = NULL;
SetEvent(This->stop_event); WaitForSingleObject(This->event_thread, INFINITE); diff --git a/dlls/wmp/tests/media.c b/dlls/wmp/tests/media.c index 8ac2c78f5a..ad2d748af7 100644 --- a/dlls/wmp/tests/media.c +++ b/dlls/wmp/tests/media.c @@ -227,7 +227,6 @@ static void test_wmp(void)
hres = IWMPSettings_put_autoStart(settings, VARIANT_FALSE); ok(hres == S_OK, "Could not put autoStart in IWMPSettings: %08x\n", hres); - IWMPSettings_Release(settings);
controls = NULL; hres = IWMPPlayer4_get_controls(player4, &controls); @@ -343,7 +342,14 @@ playback_skip: hres = IConnectionPoint_Unadvise(point, dw); ok(hres == S_OK, "Unadvise failed: %08x\n", hres);
+ hres = IWMPSettings_put_volume(settings, 36); + ok(hres == S_OK, "IWMPSettings_put_volume failed: %08x\n", hres); + hres = IWMPSettings_get_volume(settings, &progress); + ok(hres == S_OK, "IWMPSettings_get_volume failed: %08x\n", hres); + ok(progress == 36, "unexpected value: %d\n", progress); + IConnectionPoint_Release(point); + IWMPSettings_Release(settings); IWMPControls_Release(controls); IWMPPlayer4_Release(player4); IOleObject_Release(oleobj); diff --git a/dlls/wmp/wmp_private.h b/dlls/wmp/wmp_private.h index 4479f3cdb9..876ba4e326 100644 --- a/dlls/wmp/wmp_private.h +++ b/dlls/wmp/wmp_private.h @@ -79,6 +79,7 @@ struct WindowsMediaPlayer { IMediaControl* media_control; IMediaEvent* media_event; IMediaSeeking* media_seeking; + IBasicAudio* basic_audio;
/* Async event notification */ HANDLE event_thread;
Hi,
While running your changed tests on Windows, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check? Full results can be found at https://testbot.winehq.org/JobDetails.pl?Key=37209
Your paranoid android.
=== w2003std (32 bit oleobj) === The task timed out
=== wvistau64 (64 bit oleobj) === 0890:oleobj: unhandled exception c0000005 at 000007FEF3C2ACA2
On Wed, Mar 28, 2018 at 8:24 AM, Marvin testbot@winehq.org wrote:
Hi,
While running your changed tests on Windows, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check? Full results can be found at https://testbot.winehq.org/JobDetails.pl?Key=37209
Your paranoid android.
=== w2003std (32 bit oleobj) === The task timed out
=== wvistau64 (64 bit oleobj) === 0890:oleobj: unhandled exception c0000005 at 000007FEF3C2ACA2
According to this https://source.winehq.org/patches/data/143968 thats a preexisting failure that that patch fixes.