Signed-off-by: Anton Romanov theli.ua@gmail.com --- dlls/wmp/player.c | 89 ++++++++++++++++++++++++++++++--- 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, 215 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..3d0df96bd8 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,60 @@ 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); + } + IGraphBuilder_Release(This->filter_graph); + This->filter_graph = NULL; + This->media_control = NULL; + return hres; }
static HRESULT WINAPI WMPControls_pause(IWMPControls *iface) @@ -1741,16 +1794,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 zcmeI%f23Xo0LJlCcd=qF8IkluD<ZR5KSsq;mzGVmT``eqrkEu$6EP~1m`IVNlq5-1 zBqA}9NQp$^ij2req${`gz5Vg*;oRHE``_o9?faaU<K1!gx#zyyedmr1!}ROw{rmPU zO#Yl7hPgclj~%}8=B+z-Y~8+X+v=<T{<gBb|Ex8hyN@1zWb(@7G#8#4=H7X2n7d%( zMVsa?-h9cWmtAqymTRxOe(UxfH|@OTwq18D+;#Wfd+yzT-+}udIC$vrLr0E2`q;7K zk3VtZ$)}%r_PLYKzwpw_ue|#D8*jb+?tAZl@X^PgeEQkvr@r{|tFOQL?)x8p{Auau zUrzt}+nL}0`17y7r|)F)o*$gN=j~^|-(k!7yQZ&A-^a=|Pn}*_-h617KQjyuPmXOI zhD}!v!+DcmZ%*bUZ#Xdw8}{73cVYGKy*To<?u(0y)AL{cALk!AYYv^m`EQ-^`47za z{Ksc}{ugI_{tst-{%>b|{-u-a-~YK8N9r8zPv@VaIdbhLho(NbKCaLB-7z`p-`9pU zug&xY*T?no{mb{4wUFQgANarrKCJoq##)zV^*BHI$xnW+g#;h?zz06?!SmI~J>c{0 z_5SnF=l?#x9XvmHe(?M-^1WmAke@I3zz06?!Os^X_kf=-{CqKTTjY@E2hR_lA3Q%q zgf2etfe(CW6|(ri2R`s2B6RVA4}9Q5tB}P9KJbAL5uu9@eBc8gT7@h=@PQ9}hzMPL z-~%7{&?;o{fe(D(LqzD}10VRnhgKnr4}9PQA0k2*ANarrKC}v1eBc8g_z)4g_`nA~ z@S#=6;sYP}z=w#?#Rop{fe)=h79aS)2R=lEE<W&q4}549viQIUKJXzTbn$@?eBeW? zki`c+@PQ8zp^FcE-~%68g)Bbsfe(C$2wi;O10VR%DrE724}9Q5MCjrJANatBRw0WI zeBc8gB0?7*_`nA~v<g{#-~%7{5D~igzz06?p;gG@10VRnhltR{2R`tD53NELANarr zK175rKJbALd}tN2_`nA~@F5~}@qrI~;6tmB#Rop{fe#U(iw}I@10Pz2EI#mo4}6FS zU3}mJANbHJWbuIyeBeVw=;8w(_`ru&A&U=u-~%5bLKh$Szz06G3R!&M10VPh5xV%m z2R`tjRmkE4ANatBh|t9cKJbALtwI(b_`nA~M1(Fr@PQ9}Xce;fzz06?AtH3~fe(D( zL#vR*2R`tD4-uh@4}9PQA6kVhKJbALe255LeBc8g_|Ph3@qrI~;6p^{;sYP}z=u{L ziw}I@10Nzn7a#b*2R^h4S$yCFANUXvy7<5cKJcMc$l?PZ_`rvV(8UKn@PQAlLKYwR zzz04=gf2etfe(CW6|(ri2R`s2B6RVA4}9Q5tB}P9KJbAL5uu9@eBc8gT7@h=@PQ9} zhzMPL-~%7{&?;o{fe(D(LqzD}10VRnhgKnr4}9PQA0k2*ANarrKC}v1eBc8g_z)4g z_`nA~@S#=6;sYP}z=w#?#Rop{fe)=h79aS)2R=lEE<W&q4}549viQIUKJXzTbn$@? zeBeW?ki`c+@PQ8zp^FcE-~%68g)Bbsfe(C$2wi;O10VR%DrE724}9Q5MCjrJANatB zRw0WIeBc8gB0?7*_`nA~v<g{#-~%7{5D~igzz06?p;gG@10VRnhltR{2R`tD53NEL zANarrK175rKJbALd}tN2_`nA~@F5~}@qrI~;6tmB#Rop{fe#U(iw}I@10Pz2EI#mo z4}6FSU3}mJANbHJWbuIyeBeVw=;8w(_`ru&A&U=u-~%5bLKh$Szz06G3R!&M10VPh z5xV%m2R`tjRmkE4ANatBh|t9cKJbALtwI(b_`nA~M1(Fr@PQ9}Xce;fzz06?AtH3~ zfe(D(L#vR*2R`tD4-uh@4}9PQA6kVhKJbALe255LeBc8g_|Ph3@qrI~;6p^{;sYP} zz=u{Liw}I@10Nzn7a#b*2R^h4S$yCFANUXvy7<5cKJcMc$l?PZ_`rvV(8UKn@PQAl zLKYwRzz04=gf2etfe(CW6|(ri2R`s2B6RVA4}9Q5tB}P9KJbAL5uu9@eBc8gT7@h= z@PQ9}hzMPL-~%7{&?;o{fe(D(LqzD}10VRnhgKnr4}9PQA0k2*ANarrKC}v1eBc8g z_z)4g_`nA~@S#=6;sYP}z=w#?#Rop{fe)=h79aS)2R=lEE<W&q4}549viQIUKJXzT zbn$@?eBeW?ki`c+@PQ8zp^FcE-~%68g)Bbsfe(C$2wi;O10VR%DrE724}9Q5MCjrJ zANatBRw0WIeBc8gB0?7*_`nA~v<g{#-~%7{5D~igzz06?p;gG@10VRnhltR{2R`tD z53NELANarrK175rKJbALd}tN2_`nA~@F5~}@qrI~;6tmB#Rop{fe#U(iw}I@10Pz2 zEI#mo4}6FSU3}mJANbHJWbuIyeBeVw=;8w(_`ru&A&U=u-~%5bLKh$Szz06G3R!&M z10VPh5xV%m2R`tjRmkE4ANatBh|t9cKJbALtwI(b_`nA~M1(Fr@PQ9}Xce;fzz06? zAtH3~fe(D(L#vR*2R`tD4-uh@4}9PQA6kVhKJbALe255LeBc8g_|Ph3@qrI~;6p^{ z;sYP}z=u{Liw}I@10Nzn7a#b*2R^h4S$yCFANUXvy7<5cKJcMc$l?PZ_`rvV(8UKn z@PQAlLKYwRzz04=gf2etfe(CW6|(ri2R`s2B6RVA4}9Q5tB}P9KJbAL5uu9@eBc8g zT7@h=@PQ9}hzMPL-~%7{&?;o{fe(D(LqzD}10VRnhgKnr4}9PQA0k2*ANarrKC}v1 zeBc8g_z)4g_`nA~@S#=6;sYP}z=w#?#Rop{fe)=h79aS)2R=lEE<W&q4}549viQIU zKJXzTbn$@?eBeW?ki`c+@PQ8zp^FcE-~%68g)Bbsfe(C$2wi;O10VR%DrE725C6x9 d+)1Ogvb_1wlJk#Vo9RK<XU$8q`ogTQ&p*pvqh$a9
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 3d0df96bd8..b3da663637 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); @@ -1419,6 +1446,8 @@ static HRESULT WINAPI WMPControls_stop(IWMPControls *iface) IGraphBuilder_Release(This->filter_graph); 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; }
@@ -1827,3 +1856,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
Hi Anton,
On 03/28/2018 05:31 PM, Anton Romanov wrote:
diff --git a/dlls/wmp/player.c b/dlls/wmp/player.c index 3d0df96bd8..b3da663637 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);
How about moving implementation here to avoid forward declaration?
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);
Should we report ready state if put_currentMedia fails?
@@ -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);
It's similar, is it right in case of loading error?
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;
How about adding more specific tests? You could split CHECK_EXPECT into actual states, so it would be like CHECK_EXPECT(OpenStateChange_MediaChanging), CHECK_EXPECT(PlatStateChange_Waiting) and alike.
@@ -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");
This looks bad. If you change tests as I mentioned above, you can just add todo_wine where appropriate.
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
Where do those come from? Shouldn't you use WMPOpenState and WMPPlayState instead?
Thanks, Jacek
On Thu, Mar 29, 2018 at 7:11 AM, Jacek Caban jacek@codeweavers.com wrote:
Hi Anton,
On 03/28/2018 05:31 PM, Anton Romanov wrote:
diff --git a/dlls/wmp/player.c b/dlls/wmp/player.c index 3d0df96bd8..b3da663637 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);
How about moving implementation here to avoid forward declaration?
Sure.
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);
Should we report ready state if put_currentMedia fails?
Probably not.
@@ -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);
It's similar, is it right in case of loading error?
Probably not.
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;
How about adding more specific tests? You could split CHECK_EXPECT into actual states, so it would be like CHECK_EXPECT(OpenStateChange_MediaChanging), CHECK_EXPECT(PlatStateChange_Waiting) and alike.
Well, one call to something like put_url produces about 10 state changes, some are playlist related that is functionality we are missing. Do we need / want to test for them all? If we want to be as specific as possible - do we need to test for order of those changes as well?
@@ -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");
This looks bad. If you change tests as I mentioned above, you can just add todo_wine where appropriate.
this todo_wine is just TODO message, its not strictly required here. I am not sure what would change with tracking each individual state. I can just remove this todo.
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
Where do those come from? Shouldn't you use WMPOpenState and WMPPlayState instead?
I made those up, for w/e reason I was blind and didn't see those enums. I will change them to enums from msdn.
On 03/29/2018 05:38 PM, Anton Romanov wrote:
How about adding more specific tests? You could split CHECK_EXPECT into actual states, so it would be like CHECK_EXPECT(OpenStateChange_MediaChanging), CHECK_EXPECT(PlatStateChange_Waiting) and alike.
Well, one call to something like put_url produces about 10 state changes, some are playlist related that is functionality we are missing. Do we need / want to test for them all? If we want to be as specific as possible - do we need to test for order of those changes as well?
We don't need all of them, at least not yet. Adding ones that you implement would be nice.
Thanks,
Jacek
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 b3da663637..d40b0fe9cb 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); @@ -1443,9 +1451,18 @@ 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; + + 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; @@ -1819,6 +1836,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) @@ -1826,6 +1844,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) @@ -1873,3 +1893,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 d40b0fe9cb..7b57ec54ae 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); } @@ -1454,10 +1476,14 @@ 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); + } IGraphBuilder_Release(This->filter_graph); 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); @@ -1492,15 +1518,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) @@ -1737,9 +1781,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;
Hi Anton,
This is more of general thing with this patch set.
I would like to see more errors tested.
On 29/03/18 02:31, Anton Romanov wrote:
Signed-off-by: Anton Romanov theli.ua@gmail.com
SetEvent(This->stop_event); WaitForSingleObject(This->event_thread, INFINITE);
@@ -1492,15 +1518,33 @@ static HRESULT WINAPI WMPControls_fastReverse(IWMPControls *iface) static HRESULT WINAPI WMPControls_get_currentPosition(IWMPControls *iface, DOUBLE *pdCurrentPosition)
What happens when an NULL value is passed in?
static HRESULT WINAPI WMPControls_put_currentPosition(IWMPControls *iface, DOUBLE dCurrentPosition) {
What happens when an negative value is passed in?
Regards Alistair.
On 29/03/18 05:10, Alistair Leslie-Hughes wrote:
Hi Anton,
This is more of general thing with this patch set.
I would like to see more errors tested.
On 29/03/18 02:31, Anton Romanov wrote:
Signed-off-by: Anton Romanov theli.ua@gmail.com
SetEvent(This->stop_event); WaitForSingleObject(This->event_thread, INFINITE);
@@ -1492,15 +1518,33 @@ static HRESULT WINAPI WMPControls_fastReverse(IWMPControls *iface) static HRESULT WINAPI WMPControls_get_currentPosition(IWMPControls *iface, DOUBLE *pdCurrentPosition)
What happens when an NULL value is passed in?
static HRESULT WINAPI WMPControls_put_currentPosition(IWMPControls *iface, DOUBLE dCurrentPosition) {
What happens when an negative value is passed in?
I wouldn't be surprised if the answer is "the same thing that happens when a negative value is passed into IMediaSeeking_SetPositions()". That function (and quartz in general...) could certainly use some more tests as well.
On Thu, Mar 29, 2018 at 7:24 AM, Zebediah Figura z.figura12@gmail.com wrote:
On 29/03/18 05:10, Alistair Leslie-Hughes wrote:
Hi Anton,
This is more of general thing with this patch set.
I would like to see more errors tested.
On 29/03/18 02:31, Anton Romanov wrote:
Signed-off-by: Anton Romanov theli.ua@gmail.com
SetEvent(This->stop_event); WaitForSingleObject(This->event_thread, INFINITE);
@@ -1492,15 +1518,33 @@ static HRESULT WINAPI WMPControls_fastReverse(IWMPControls *iface) static HRESULT WINAPI WMPControls_get_currentPosition(IWMPControls *iface, DOUBLE *pdCurrentPosition)
What happens when an NULL value is passed in?
static HRESULT WINAPI WMPControls_put_currentPosition(IWMPControls *iface, DOUBLE dCurrentPosition) {
What happens when an negative value is passed in?
I wouldn't be surprised if the answer is "the same thing that happens when a negative value is passed into IMediaSeeking_SetPositions()". That function (and quartz in general...) could certainly use some more tests as well.
Well, basically yes, what Zeb said.
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 7b57ec54ae..e67f46d234 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 e67f46d234..4f6e4af9ad 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); } @@ -1498,11 +1516,15 @@ 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); + } IGraphBuilder_Release(This->filter_graph); 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;